• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef V8_TORQUE_IMPLEMENTATION_VISITOR_H_
6 #define V8_TORQUE_IMPLEMENTATION_VISITOR_H_
7 
8 #include <memory>
9 #include <string>
10 
11 #include "src/base/macros.h"
12 #include "src/torque/ast.h"
13 #include "src/torque/cfg.h"
14 #include "src/torque/declarations.h"
15 #include "src/torque/global-context.h"
16 #include "src/torque/type-oracle.h"
17 #include "src/torque/types.h"
18 #include "src/torque/utils.h"
19 
20 namespace v8 {
21 namespace internal {
22 namespace torque {
23 
24 template <typename T>
25 class Binding;
26 class LocalValue;
27 class ImplementationVisitor;
28 
29 // LocationReference is the representation of an l-value, so a value that might
30 // allow for assignment. For uniformity, this class can also represent
31 // unassignable temporaries. Assignable values fall in two categories:
32 //   - stack ranges that represent mutable variables, including structs.
33 //   - field or element access expressions that generate operator calls.
34 class LocationReference {
35  public:
36   // An assignable stack range.
37   static LocationReference VariableAccess(
38       VisitResult variable,
39       base::Optional<Binding<LocalValue>*> binding = base::nullopt) {
40     DCHECK(variable.IsOnStack());
41     LocationReference result;
42     result.variable_ = std::move(variable);
43     result.binding_ = binding;
44     return result;
45   }
46   // An unassignable value. {description} is only used for error messages.
Temporary(VisitResult temporary,std::string description)47   static LocationReference Temporary(VisitResult temporary,
48                                      std::string description) {
49     LocationReference result;
50     result.temporary_ = std::move(temporary);
51     result.temporary_description_ = std::move(description);
52     return result;
53   }
54   // A heap reference, that is, a tagged value and an offset to encode an inner
55   // pointer.
HeapReference(VisitResult heap_reference)56   static LocationReference HeapReference(VisitResult heap_reference) {
57     LocationReference result;
58     DCHECK(TypeOracle::MatchReferenceGeneric(heap_reference.type()));
59     result.heap_reference_ = std::move(heap_reference);
60     return result;
61   }
62   // A reference to an array on the heap. That is, a tagged value, an offset to
63   // encode an inner pointer, and the number of elements.
HeapSlice(VisitResult heap_slice)64   static LocationReference HeapSlice(VisitResult heap_slice) {
65     LocationReference result;
66     DCHECK(Type::MatchUnaryGeneric(heap_slice.type(),
67                                    TypeOracle::GetSliceGeneric()));
68     result.heap_slice_ = std::move(heap_slice);
69     return result;
70   }
ArrayAccess(VisitResult base,VisitResult offset)71   static LocationReference ArrayAccess(VisitResult base, VisitResult offset) {
72     LocationReference result;
73     result.eval_function_ = std::string{"[]"};
74     result.assign_function_ = std::string{"[]="};
75     result.call_arguments_ = {base, offset};
76     return result;
77   }
FieldAccess(VisitResult object,std::string fieldname)78   static LocationReference FieldAccess(VisitResult object,
79                                        std::string fieldname) {
80     LocationReference result;
81     result.eval_function_ = "." + fieldname;
82     result.assign_function_ = "." + fieldname + "=";
83     result.call_arguments_ = {object};
84     return result;
85   }
BitFieldAccess(const LocationReference & object,BitField field)86   static LocationReference BitFieldAccess(const LocationReference& object,
87                                           BitField field) {
88     LocationReference result;
89     result.bit_field_struct_ = std::make_shared<LocationReference>(object);
90     result.bit_field_ = std::move(field);
91     return result;
92   }
93 
IsConst()94   bool IsConst() const {
95     if (IsHeapReference()) {
96       bool is_const;
97       bool success =
98           TypeOracle::MatchReferenceGeneric(heap_reference().type(), &is_const)
99               .has_value();
100       CHECK(success);
101       return is_const;
102     }
103     return IsTemporary();
104   }
105 
IsVariableAccess()106   bool IsVariableAccess() const { return variable_.has_value(); }
variable()107   const VisitResult& variable() const {
108     DCHECK(IsVariableAccess());
109     return *variable_;
110   }
IsTemporary()111   bool IsTemporary() const { return temporary_.has_value(); }
temporary()112   const VisitResult& temporary() const {
113     DCHECK(IsTemporary());
114     return *temporary_;
115   }
IsHeapReference()116   bool IsHeapReference() const { return heap_reference_.has_value(); }
heap_reference()117   const VisitResult& heap_reference() const {
118     DCHECK(IsHeapReference());
119     return *heap_reference_;
120   }
IsHeapSlice()121   bool IsHeapSlice() const { return heap_slice_.has_value(); }
heap_slice()122   const VisitResult& heap_slice() const {
123     DCHECK(IsHeapSlice());
124     return *heap_slice_;
125   }
IsBitFieldAccess()126   bool IsBitFieldAccess() const {
127     bool is_bitfield_access = bit_field_struct_ != nullptr;
128     DCHECK_EQ(is_bitfield_access, bit_field_.has_value());
129     return is_bitfield_access;
130   }
bit_field_struct_location()131   const LocationReference& bit_field_struct_location() const {
132     DCHECK(IsBitFieldAccess());
133     return *bit_field_struct_;
134   }
bit_field()135   const BitField& bit_field() const {
136     DCHECK(IsBitFieldAccess());
137     return *bit_field_;
138   }
139 
ReferencedType()140   base::Optional<const Type*> ReferencedType() const {
141     if (IsHeapReference()) {
142       return *TypeOracle::MatchReferenceGeneric(heap_reference().type());
143     }
144     if (IsHeapSlice()) {
145       return *Type::MatchUnaryGeneric(heap_slice().type(),
146                                       TypeOracle::GetSliceGeneric());
147     }
148     if (IsBitFieldAccess()) {
149       return bit_field_->name_and_type.type;
150     }
151     if (IsVariableAccess() || IsHeapSlice() || IsTemporary()) {
152       return GetVisitResult().type();
153     }
154     return base::nullopt;
155   }
156 
GetVisitResult()157   const VisitResult& GetVisitResult() const {
158     if (IsVariableAccess()) return variable();
159     if (IsHeapSlice()) return heap_slice();
160     DCHECK(IsTemporary());
161     return temporary();
162   }
163 
164   // For error reporting.
temporary_description()165   const std::string& temporary_description() const {
166     DCHECK(IsTemporary());
167     return *temporary_description_;
168   }
169 
IsCallAccess()170   bool IsCallAccess() const {
171     bool is_call_access = eval_function_.has_value();
172     DCHECK_EQ(is_call_access, assign_function_.has_value());
173     return is_call_access;
174   }
call_arguments()175   const VisitResultVector& call_arguments() const {
176     DCHECK(IsCallAccess());
177     return call_arguments_;
178   }
eval_function()179   const std::string& eval_function() const {
180     DCHECK(IsCallAccess());
181     return *eval_function_;
182   }
assign_function()183   const std::string& assign_function() const {
184     DCHECK(IsCallAccess());
185     return *assign_function_;
186   }
binding()187   base::Optional<Binding<LocalValue>*> binding() const {
188     DCHECK(IsVariableAccess());
189     return binding_;
190   }
191 
192  private:
193   base::Optional<VisitResult> variable_;
194   base::Optional<VisitResult> temporary_;
195   base::Optional<std::string> temporary_description_;
196   base::Optional<VisitResult> heap_reference_;
197   base::Optional<VisitResult> heap_slice_;
198   base::Optional<std::string> eval_function_;
199   base::Optional<std::string> assign_function_;
200   VisitResultVector call_arguments_;
201   base::Optional<Binding<LocalValue>*> binding_;
202 
203   // The location of the bitfield struct that contains this bitfield, if this
204   // reference is a bitfield access. Uses a shared_ptr so that LocationReference
205   // is copyable, allowing us to set this field equal to a copy of a
206   // stack-allocated LocationReference.
207   std::shared_ptr<const LocationReference> bit_field_struct_;
208   base::Optional<BitField> bit_field_;
209 
210   LocationReference() = default;
211 };
212 
213 struct InitializerResults {
214   std::vector<Identifier*> names;
215   std::map<std::string, VisitResult> field_value_map;
216 };
217 
218 struct LayoutForInitialization {
219   std::map<std::string, VisitResult> array_lengths;
220   std::map<std::string, VisitResult> offsets;
221   VisitResult size;
222 };
223 
224 template <class T>
225 class Binding;
226 
227 template <class T>
228 class BindingsManager {
229  public:
TryLookup(const std::string & name)230   base::Optional<Binding<T>*> TryLookup(const std::string& name) {
231     if (name.length() >= 2 && name[0] == '_' && name[1] != '_') {
232       Error("Trying to reference '", name, "' which is marked as unused.")
233           .Throw();
234     }
235     auto binding = current_bindings_[name];
236     if (binding) {
237       (*binding)->SetUsed();
238     }
239     return binding;
240   }
241 
242  private:
243   friend class Binding<T>;
244   std::unordered_map<std::string, base::Optional<Binding<T>*>>
245       current_bindings_;
246 };
247 
248 template <class T>
249 class Binding : public T {
250  public:
251   template <class... Args>
Binding(BindingsManager<T> * manager,const std::string & name,Args &&...args)252   Binding(BindingsManager<T>* manager, const std::string& name, Args&&... args)
253       : T(std::forward<Args>(args)...),
254         manager_(manager),
255         name_(name),
256         previous_binding_(this),
257         used_(false),
258         written_(false) {
259     std::swap(previous_binding_, manager_->current_bindings_[name]);
260   }
261   template <class... Args>
Binding(BindingsManager<T> * manager,const Identifier * name,Args &&...args)262   Binding(BindingsManager<T>* manager, const Identifier* name, Args&&... args)
263       : Binding(manager, name->value, std::forward<Args>(args)...) {
264     declaration_position_ = name->pos;
265   }
~Binding()266   ~Binding() {
267     if (!used_ && !SkipLintCheck()) {
268       Lint(BindingTypeString(), "'", name_,
269            "' is never used. Prefix with '_' if this is intentional.")
270           .Position(declaration_position_);
271     }
272 
273     if (CheckWritten() && !written_ && !SkipLintCheck()) {
274       Lint(BindingTypeString(), "'", name_,
275            "' is never assigned to. Use 'const' instead of 'let'.")
276           .Position(declaration_position_);
277     }
278 
279     manager_->current_bindings_[name_] = previous_binding_;
280   }
281 
282   std::string BindingTypeString() const;
283   bool CheckWritten() const;
284 
name()285   const std::string& name() const { return name_; }
declaration_position()286   SourcePosition declaration_position() const { return declaration_position_; }
287 
Used()288   bool Used() const { return used_; }
SetUsed()289   void SetUsed() { used_ = true; }
290 
Written()291   bool Written() const { return written_; }
SetWritten()292   void SetWritten() { written_ = true; }
293 
294  private:
SkipLintCheck()295   bool SkipLintCheck() const { return name_.length() > 0 && name_[0] == '_'; }
296 
297   BindingsManager<T>* manager_;
298   const std::string name_;
299   base::Optional<Binding*> previous_binding_;
300   SourcePosition declaration_position_ = CurrentSourcePosition::Get();
301   bool used_;
302   bool written_;
303   DISALLOW_COPY_AND_ASSIGN(Binding);
304 };
305 
306 template <class T>
307 class BlockBindings {
308  public:
BlockBindings(BindingsManager<T> * manager)309   explicit BlockBindings(BindingsManager<T>* manager) : manager_(manager) {}
310   void Add(std::string name, T value, bool mark_as_used = false) {
311     ReportErrorIfAlreadyBound(name);
312     auto binding =
313         std::make_unique<Binding<T>>(manager_, name, std::move(value));
314     if (mark_as_used) binding->SetUsed();
315     bindings_.push_back(std::move(binding));
316   }
317 
318   void Add(const Identifier* name, T value, bool mark_as_used = false) {
319     ReportErrorIfAlreadyBound(name->value);
320     auto binding =
321         std::make_unique<Binding<T>>(manager_, name, std::move(value));
322     if (mark_as_used) binding->SetUsed();
323     bindings_.push_back(std::move(binding));
324   }
325 
bindings()326   std::vector<Binding<T>*> bindings() const {
327     std::vector<Binding<T>*> result;
328     result.reserve(bindings_.size());
329     for (auto& b : bindings_) {
330       result.push_back(b.get());
331     }
332     return result;
333   }
334 
335  private:
ReportErrorIfAlreadyBound(const std::string & name)336   void ReportErrorIfAlreadyBound(const std::string& name) {
337     for (const auto& binding : bindings_) {
338       if (binding->name() == name) {
339         ReportError(
340             "redeclaration of name \"", name,
341             "\" in the same block is illegal, previous declaration at: ",
342             binding->declaration_position());
343       }
344     }
345   }
346 
347   BindingsManager<T>* manager_;
348   std::vector<std::unique_ptr<Binding<T>>> bindings_;
349 };
350 
351 class LocalValue {
352  public:
LocalValue(LocationReference reference)353   explicit LocalValue(LocationReference reference)
354       : value(std::move(reference)) {}
LocalValue(std::string inaccessible_explanation)355   explicit LocalValue(std::string inaccessible_explanation)
356       : inaccessible_explanation(std::move(inaccessible_explanation)) {}
357 
GetLocationReference(Binding<LocalValue> * binding)358   LocationReference GetLocationReference(Binding<LocalValue>* binding) {
359     if (value) {
360       const LocationReference& ref = *value;
361       if (ref.IsVariableAccess()) {
362         // Attach the binding to enable the never-assigned-to lint check.
363         return LocationReference::VariableAccess(ref.GetVisitResult(), binding);
364       }
365       return ref;
366     } else {
367       Error("Cannot access ", binding->name(), ": ", inaccessible_explanation)
368           .Throw();
369     }
370   }
371 
IsAccessible()372   bool IsAccessible() const { return value.has_value(); }
373 
374  private:
375   base::Optional<LocationReference> value;
376   std::string inaccessible_explanation;
377 };
378 
379 struct LocalLabel {
380   Block* block;
381   std::vector<const Type*> parameter_types;
382 
383   explicit LocalLabel(Block* block,
384                       std::vector<const Type*> parameter_types = {})
blockLocalLabel385       : block(block), parameter_types(std::move(parameter_types)) {}
386 };
387 
388 template <>
BindingTypeString()389 inline std::string Binding<LocalValue>::BindingTypeString() const {
390   return "Variable ";
391 }
392 template <>
CheckWritten()393 inline bool Binding<LocalValue>::CheckWritten() const {
394   // Do the check only for non-const variables and non struct types.
395   auto binding = *manager_->current_bindings_[name_];
396   if (!binding->IsAccessible()) return false;
397   const LocationReference& ref = binding->GetLocationReference(binding);
398   if (!ref.IsVariableAccess()) return false;
399   return !ref.GetVisitResult().type()->StructSupertype();
400 }
401 template <>
BindingTypeString()402 inline std::string Binding<LocalLabel>::BindingTypeString() const {
403   return "Label ";
404 }
405 template <>
CheckWritten()406 inline bool Binding<LocalLabel>::CheckWritten() const {
407   return false;
408 }
409 
410 struct Arguments {
411   VisitResultVector parameters;
412   std::vector<Binding<LocalLabel>*> labels;
413 };
414 
415 // Determine if a callable should be considered as an overload.
416 bool IsCompatibleSignature(const Signature& sig, const TypeVector& types,
417                            size_t label_count);
418 
419 class ImplementationVisitor {
420  public:
421   void GenerateBuiltinDefinitionsAndInterfaceDescriptors(
422       const std::string& output_directory);
423   void GenerateClassFieldOffsets(const std::string& output_directory);
424   void GenerateBitFields(const std::string& output_directory);
425   void GeneratePrintDefinitions(const std::string& output_directory);
426   void GenerateClassDefinitions(const std::string& output_directory);
427   void GenerateBodyDescriptors(const std::string& output_directory);
428   void GenerateInstanceTypes(const std::string& output_directory);
429   void GenerateClassVerifiers(const std::string& output_directory);
430   void GenerateEnumVerifiers(const std::string& output_directory);
431   void GenerateClassDebugReaders(const std::string& output_directory);
432   void GenerateExportedMacrosAssembler(const std::string& output_directory);
433   void GenerateCSATypes(const std::string& output_directory);
434 
435   VisitResult Visit(Expression* expr);
436   const Type* Visit(Statement* stmt);
437 
438   template <typename T>
439   void CheckInitializersWellformed(
440       const std::string& aggregate_name, const std::vector<T>& aggregate_fields,
441       const std::vector<NameAndExpression>& initializers,
442       bool ignore_first_field = false) {
443     size_t fields_offset = ignore_first_field ? 1 : 0;
444     size_t fields_size = aggregate_fields.size() - fields_offset;
445     for (size_t i = 0; i < std::min(fields_size, initializers.size()); i++) {
446       const std::string& field_name =
447           aggregate_fields[i + fields_offset].name_and_type.name;
448       Identifier* found_name = initializers[i].name;
449       if (field_name != found_name->value) {
450         Error("Expected field name \"", field_name, "\" instead of \"",
451               found_name->value, "\"")
452             .Position(found_name->pos)
453             .Throw();
454       }
455     }
456     if (fields_size != initializers.size()) {
457       ReportError("expected ", fields_size, " initializers for ",
458                   aggregate_name, " found ", initializers.size());
459     }
460   }
461 
462   InitializerResults VisitInitializerResults(
463       const ClassType* class_type,
464       const std::vector<NameAndExpression>& expressions);
465   LocationReference GenerateFieldReference(VisitResult object,
466                                            const Field& field,
467                                            const ClassType* class_type);
468   LocationReference GenerateFieldReferenceForInit(
469       VisitResult object, const Field& field,
470       const LayoutForInitialization& layout);
471   VisitResult GenerateArrayLength(
472       Expression* array_length, Namespace* nspace,
473       const std::map<std::string, LocalValue>& bindings);
474   VisitResult GenerateArrayLength(VisitResult object, const Field& field);
475   VisitResult GenerateArrayLength(const ClassType* class_type,
476                                   const InitializerResults& initializer_results,
477                                   const Field& field);
478   LayoutForInitialization GenerateLayoutForInitialization(
479       const ClassType* class_type,
480       const InitializerResults& initializer_results);
481 
482   void InitializeClass(const ClassType* class_type, VisitResult allocate_result,
483                        const InitializerResults& initializer_results,
484                        const LayoutForInitialization& layout);
485 
486   VisitResult Visit(StructExpression* decl);
487 
488   LocationReference GetLocationReference(Expression* location);
489   LocationReference LookupLocalValue(const std::string& name);
490   LocationReference GetLocationReference(IdentifierExpression* expr);
491   LocationReference GetLocationReference(DereferenceExpression* expr);
492   LocationReference GetLocationReference(FieldAccessExpression* expr);
493   LocationReference GenerateFieldAccess(
494       LocationReference reference, const std::string& fieldname,
495       bool ignore_stuct_field_constness = false,
496       base::Optional<SourcePosition> pos = {});
497   LocationReference GetLocationReference(ElementAccessExpression* expr);
498 
499   VisitResult GenerateFetchFromLocation(const LocationReference& reference);
500 
501   VisitResult GetBuiltinCode(Builtin* builtin);
502 
503   VisitResult Visit(LocationExpression* expr);
504   VisitResult Visit(FieldAccessExpression* expr);
505 
506   void VisitAllDeclarables();
507   void Visit(Declarable* delarable);
508   void Visit(TypeAlias* decl);
509   VisitResult InlineMacro(Macro* macro,
510                           base::Optional<LocationReference> this_reference,
511                           const std::vector<VisitResult>& arguments,
512                           const std::vector<Block*> label_blocks);
513   void VisitMacroCommon(Macro* macro);
Visit(ExternMacro * macro)514   void Visit(ExternMacro* macro) {}
515   void Visit(TorqueMacro* macro);
516   void Visit(Method* macro);
517   void Visit(Builtin* builtin);
518   void Visit(NamespaceConstant* decl);
519 
520   VisitResult Visit(CallExpression* expr, bool is_tail = false);
521   VisitResult Visit(CallMethodExpression* expr);
522   VisitResult Visit(IntrinsicCallExpression* intrinsic);
523   const Type* Visit(TailCallStatement* stmt);
524 
525   VisitResult Visit(ConditionalExpression* expr);
526 
527   VisitResult Visit(LogicalOrExpression* expr);
528   VisitResult Visit(LogicalAndExpression* expr);
529 
530   VisitResult Visit(IncrementDecrementExpression* expr);
531   VisitResult Visit(AssignmentExpression* expr);
532   VisitResult Visit(StringLiteralExpression* expr);
533   VisitResult Visit(NumberLiteralExpression* expr);
534   VisitResult Visit(AssumeTypeImpossibleExpression* expr);
535   VisitResult Visit(TryLabelExpression* expr);
536   VisitResult Visit(StatementExpression* expr);
537   VisitResult Visit(NewExpression* expr);
538   VisitResult Visit(SpreadExpression* expr);
539 
540   const Type* Visit(ReturnStatement* stmt);
541   const Type* Visit(GotoStatement* stmt);
542   const Type* Visit(IfStatement* stmt);
543   const Type* Visit(WhileStatement* stmt);
544   const Type* Visit(BreakStatement* stmt);
545   const Type* Visit(ContinueStatement* stmt);
546   const Type* Visit(ForLoopStatement* stmt);
547   const Type* Visit(VarDeclarationStatement* stmt);
548   const Type* Visit(VarDeclarationStatement* stmt,
549                     BlockBindings<LocalValue>* block_bindings);
550   const Type* Visit(BlockStatement* block);
551   const Type* Visit(ExpressionStatement* stmt);
552   const Type* Visit(DebugStatement* stmt);
553   const Type* Visit(AssertStatement* stmt);
554 
555   void BeginGeneratedFiles();
556   void EndGeneratedFiles();
557   // TODO(tebbi): Switch to per-file generation for runtime macros and merge
558   // these functions into {Begin,End}GeneratedFiles().
559   void BeginRuntimeMacrosFile();
560   void EndRuntimeMacrosFile();
561 
562   void GenerateImplementation(const std::string& dir);
563 
564   DECLARE_CONTEXTUAL_VARIABLE(ValueBindingsManager,
565                               BindingsManager<LocalValue>);
566   DECLARE_CONTEXTUAL_VARIABLE(LabelBindingsManager,
567                               BindingsManager<LocalLabel>);
568   DECLARE_CONTEXTUAL_VARIABLE(CurrentCallable, Callable*);
569   DECLARE_CONTEXTUAL_VARIABLE(CurrentFileStreams,
570                               GlobalContext::PerFileStreams*);
571   DECLARE_CONTEXTUAL_VARIABLE(CurrentReturnValue, base::Optional<VisitResult>);
572 
573   // A BindingsManagersScope has to be active for local bindings to be created.
574   // Shadowing an existing BindingsManagersScope by creating a new one hides all
575   // existing bindings while the additional BindingsManagersScope is active.
576   struct BindingsManagersScope {
577     ValueBindingsManager::Scope value_bindings_manager;
578     LabelBindingsManager::Scope label_bindings_manager;
579   };
580 
SetDryRun(bool is_dry_run)581   void SetDryRun(bool is_dry_run) { is_dry_run_ = is_dry_run; }
582 
583  private:
584   base::Optional<Block*> GetCatchBlock();
585   void GenerateCatchBlock(base::Optional<Block*> catch_block);
586 
587   // {StackScope} records the stack height at creation time and reconstructs it
588   // when being destructed by emitting a {DeleteRangeInstruction}, except for
589   // the slots protected by {StackScope::Yield}. Calling {Yield(v)} deletes all
590   // slots above the initial stack height except for the slots of {v}, which are
591   // moved to form the only slots above the initial height and marks them to
592   // survive destruction of the {StackScope}. A typical pattern is the
593   // following:
594   //
595   // VisitResult result;
596   // {
597   //   StackScope stack_scope(this);
598   //   // ... create temporary slots ...
599   //   result = stack_scope.Yield(surviving_slots);
600   // }
601   class StackScope {
602    public:
StackScope(ImplementationVisitor * visitor)603     explicit StackScope(ImplementationVisitor* visitor) : visitor_(visitor) {
604       base_ = visitor_->assembler().CurrentStack().AboveTop();
605     }
Yield(VisitResult result)606     VisitResult Yield(VisitResult result) {
607       DCHECK(!closed_);
608       closed_ = true;
609       if (!result.IsOnStack()) {
610         if (!visitor_->assembler().CurrentBlockIsComplete()) {
611           visitor_->assembler().DropTo(base_);
612         }
613         return result;
614       }
615       DCHECK_LE(base_, result.stack_range().begin());
616       DCHECK_LE(result.stack_range().end(),
617                 visitor_->assembler().CurrentStack().AboveTop());
618       visitor_->assembler().DropTo(result.stack_range().end());
619       visitor_->assembler().DeleteRange(
620           StackRange{base_, result.stack_range().begin()});
621       base_ = visitor_->assembler().CurrentStack().AboveTop();
622       return VisitResult(result.type(), visitor_->assembler().TopRange(
623                                             result.stack_range().Size()));
624     }
625 
Close()626     void Close() {
627       DCHECK(!closed_);
628       closed_ = true;
629       if (!visitor_->assembler().CurrentBlockIsComplete()) {
630         visitor_->assembler().DropTo(base_);
631       }
632     }
633 
~StackScope()634     ~StackScope() {
635       if (closed_) {
636         DCHECK_IMPLIES(
637             !visitor_->assembler().CurrentBlockIsComplete(),
638             base_ == visitor_->assembler().CurrentStack().AboveTop());
639       } else {
640         Close();
641       }
642     }
643 
644    private:
645     ImplementationVisitor* visitor_;
646     BottomOffset base_;
647     bool closed_ = false;
648   };
649 
650   class BreakContinueActivator {
651    public:
BreakContinueActivator(Block * break_block,Block * continue_block)652     BreakContinueActivator(Block* break_block, Block* continue_block)
653         : break_binding_{&LabelBindingsManager::Get(), kBreakLabelName,
654                          LocalLabel{break_block}},
Get()655           continue_binding_{&LabelBindingsManager::Get(), kContinueLabelName,
656                             LocalLabel{continue_block}} {}
657 
658    private:
659     Binding<LocalLabel> break_binding_;
660     Binding<LocalLabel> continue_binding_;
661   };
662 
663   base::Optional<Binding<LocalValue>*> TryLookupLocalValue(
664       const std::string& name);
665   base::Optional<Binding<LocalLabel>*> TryLookupLabel(const std::string& name);
666   Binding<LocalLabel>* LookupLabel(const std::string& name);
667   Block* LookupSimpleLabel(const std::string& name);
668   template <class Container>
669   Callable* LookupCallable(const QualifiedName& name,
670                            const Container& declaration_container,
671                            const TypeVector& types,
672                            const std::vector<Binding<LocalLabel>*>& labels,
673                            const TypeVector& specialization_types,
674                            bool silence_errors = false);
675   bool TestLookupCallable(const QualifiedName& name,
676                           const TypeVector& parameter_types);
677 
678   template <class Container>
679   Callable* LookupCallable(const QualifiedName& name,
680                            const Container& declaration_container,
681                            const Arguments& arguments,
682                            const TypeVector& specialization_types);
683 
684   Method* LookupMethod(const std::string& name,
685                        const AggregateType* receiver_type,
686                        const Arguments& arguments,
687                        const TypeVector& specialization_types);
688 
689   TypeArgumentInference InferSpecializationTypes(
690       GenericCallable* generic, const TypeVector& explicit_specialization_types,
691       const TypeVector& explicit_arguments);
692 
693   const Type* GetCommonType(const Type* left, const Type* right);
694 
695   VisitResult GenerateCopy(const VisitResult& to_copy);
696 
697   void GenerateAssignToLocation(const LocationReference& reference,
698                                 const VisitResult& assignment_value);
699 
700   void AddCallParameter(Callable* callable, VisitResult parameter,
701                         const Type* parameter_type,
702                         std::vector<VisitResult>* converted_arguments,
703                         StackRange* argument_range,
704                         std::vector<std::string>* constexpr_arguments,
705                         bool inline_macro);
706 
707   VisitResult GenerateCall(Callable* callable,
708                            base::Optional<LocationReference> this_parameter,
709                            Arguments parameters,
710                            const TypeVector& specialization_types = {},
711                            bool tail_call = false);
712   VisitResult GenerateCall(const QualifiedName& callable_name,
713                            Arguments parameters,
714                            const TypeVector& specialization_types = {},
715                            bool tail_call = false);
716   VisitResult GenerateCall(std::string callable_name, Arguments parameters,
717                            const TypeVector& specialization_types = {},
718                            bool tail_call = false) {
719     return GenerateCall(QualifiedName(std::move(callable_name)),
720                         std::move(parameters), specialization_types, tail_call);
721   }
722   VisitResult GeneratePointerCall(Expression* callee,
723                                   const Arguments& parameters, bool tail_call);
724 
725   void GenerateBranch(const VisitResult& condition, Block* true_block,
726                       Block* false_block);
727 
728   VisitResult GenerateBoolConstant(bool constant);
729 
730   void GenerateExpressionBranch(Expression* expression, Block* true_block,
731                                 Block* false_block);
732 
733   void GenerateMacroFunctionDeclaration(std::ostream& o,
734                                         Macro* macro);
735   std::vector<std::string> GenerateFunctionDeclaration(
736       std::ostream& o, const std::string& macro_prefix, const std::string& name,
737       const Signature& signature, const NameVector& parameter_names,
738       bool pass_code_assembler_state = true);
739 
740   VisitResult GenerateImplicitConvert(const Type* destination_type,
741                                       VisitResult source);
742 
743   StackRange GenerateLabelGoto(LocalLabel* label,
744                                base::Optional<StackRange> arguments = {});
745 
746   VisitResult GenerateSetBitField(const Type* bitfield_struct_type,
747                                   const BitField& bitfield,
748                                   VisitResult bitfield_struct,
749                                   VisitResult value,
750                                   bool starts_as_zero = false);
751 
752   std::vector<Binding<LocalLabel>*> LabelsFromIdentifiers(
753       const std::vector<Identifier*>& names);
754 
755   StackRange LowerParameter(const Type* type, const std::string& parameter_name,
756                             Stack<std::string>* lowered_parameters);
757 
758   void LowerLabelParameter(const Type* type, const std::string& parameter_name,
759                            std::vector<std::string>* lowered_parameters);
760 
761   std::string ExternalLabelName(const std::string& label_name);
762   std::string ExternalLabelParameterName(const std::string& label_name,
763                                          size_t i);
764   std::string ExternalParameterName(const std::string& name);
765 
csa_ccfile()766   std::ostream& csa_ccfile() {
767     if (auto* streams = CurrentFileStreams::Get()) {
768       return output_type_ == OutputType::kCSA ? streams->csa_ccfile
769                                               : runtime_macros_cc_;
770     }
771     return null_stream_;
772   }
csa_headerfile()773   std::ostream& csa_headerfile() {
774     if (auto* streams = CurrentFileStreams::Get()) {
775       return output_type_ == OutputType::kCSA ? streams->csa_headerfile
776                                               : runtime_macros_h_;
777     }
778     return null_stream_;
779   }
class_definition_headerfile()780   std::ostream& class_definition_headerfile() {
781     if (auto* streams = CurrentFileStreams::Get()) {
782       return streams->class_definition_headerfile;
783     }
784     return null_stream_;
785   }
class_definition_inline_headerfile()786   std::ostream& class_definition_inline_headerfile() {
787     if (auto* streams = CurrentFileStreams::Get()) {
788       return streams->class_definition_inline_headerfile;
789     }
790     return null_stream_;
791   }
class_definition_ccfile()792   std::ostream& class_definition_ccfile() {
793     if (auto* streams = CurrentFileStreams::Get()) {
794       return streams->class_definition_ccfile;
795     }
796     return null_stream_;
797   }
798 
assembler()799   CfgAssembler& assembler() { return *assembler_; }
800 
SetReturnValue(VisitResult return_value)801   void SetReturnValue(VisitResult return_value) {
802     base::Optional<VisitResult>& current_return_value =
803         CurrentReturnValue::Get();
804     DCHECK_IMPLIES(current_return_value, *current_return_value == return_value);
805     current_return_value = std::move(return_value);
806   }
807 
GetAndClearReturnValue()808   VisitResult GetAndClearReturnValue() {
809     VisitResult return_value = *CurrentReturnValue::Get();
810     CurrentReturnValue::Get() = base::nullopt;
811     return return_value;
812   }
813 
WriteFile(const std::string & file,const std::string & content)814   void WriteFile(const std::string& file, const std::string& content) {
815     if (is_dry_run_) return;
816     ReplaceFileContentsIfDifferent(file, content);
817   }
818 
TryGetSourceForBitfieldExpression(const Expression * expr)819   const Identifier* TryGetSourceForBitfieldExpression(
820       const Expression* expr) const {
821     auto it = bitfield_expressions_.find(expr);
822     if (it == bitfield_expressions_.end()) return nullptr;
823     return it->second;
824   }
825 
PropagateBitfieldMark(const Expression * original,const Expression * derived)826   void PropagateBitfieldMark(const Expression* original,
827                              const Expression* derived) {
828     if (const Identifier* source =
829             TryGetSourceForBitfieldExpression(original)) {
830       bitfield_expressions_[derived] = source;
831     }
832   }
833 
834   base::Optional<CfgAssembler> assembler_;
835   NullOStream null_stream_;
836   bool is_dry_run_;
837 
838   // Just for allowing us to emit warnings. After visiting an Expression, if
839   // that Expression is a bitfield load, plus an optional inversion or an
840   // equality check with a constant, then that Expression will be present in
841   // this map. The Identifier associated is the bitfield struct that contains
842   // the value to load.
843   std::unordered_map<const Expression*, const Identifier*>
844       bitfield_expressions_;
845 
846   // The contents of the runtime macros output files. These contain all Torque
847   // macros that have been generated using the C++ backend. They're not yet
848   // split per source file like CSA macros, but eventually we should change them
849   // to generate -inl.inc files so that callers can easily inline their
850   // contents.
851   std::stringstream runtime_macros_cc_;
852   std::stringstream runtime_macros_h_;
853 
854   OutputType output_type_ = OutputType::kCSA;
855 };
856 
857 void ReportAllUnusedMacros();
858 
859 }  // namespace torque
860 }  // namespace internal
861 }  // namespace v8
862 
863 #endif  // V8_TORQUE_IMPLEMENTATION_VISITOR_H_
864