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   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     return GetVisitResult().type();
152   }
153 
GetVisitResult()154   const VisitResult& GetVisitResult() const {
155     if (IsVariableAccess()) return variable();
156     if (IsHeapSlice()) return heap_slice();
157     DCHECK(IsTemporary());
158     return temporary();
159   }
160 
161   // For error reporting.
temporary_description()162   const std::string& temporary_description() const {
163     DCHECK(IsTemporary());
164     return *temporary_description_;
165   }
166 
IsCallAccess()167   bool IsCallAccess() const {
168     bool is_call_access = eval_function_.has_value();
169     DCHECK_EQ(is_call_access, assign_function_.has_value());
170     return is_call_access;
171   }
call_arguments()172   const VisitResultVector& call_arguments() const {
173     DCHECK(IsCallAccess());
174     return call_arguments_;
175   }
eval_function()176   const std::string& eval_function() const {
177     DCHECK(IsCallAccess());
178     return *eval_function_;
179   }
assign_function()180   const std::string& assign_function() const {
181     DCHECK(IsCallAccess());
182     return *assign_function_;
183   }
binding()184   base::Optional<Binding<LocalValue>*> binding() const {
185     DCHECK(IsVariableAccess());
186     return binding_;
187   }
188 
189  private:
190   base::Optional<VisitResult> variable_;
191   base::Optional<VisitResult> temporary_;
192   base::Optional<std::string> temporary_description_;
193   base::Optional<VisitResult> heap_reference_;
194   base::Optional<VisitResult> heap_slice_;
195   base::Optional<std::string> eval_function_;
196   base::Optional<std::string> assign_function_;
197   VisitResultVector call_arguments_;
198   base::Optional<Binding<LocalValue>*> binding_;
199 
200   // The location of the bitfield struct that contains this bitfield, if this
201   // reference is a bitfield access. Uses a shared_ptr so that LocationReference
202   // is copyable, allowing us to set this field equal to a copy of a
203   // stack-allocated LocationReference.
204   std::shared_ptr<const LocationReference> bit_field_struct_;
205   base::Optional<BitField> bit_field_;
206 
207   LocationReference() = default;
208 };
209 
210 struct InitializerResults {
211   std::vector<Identifier*> names;
212   std::map<std::string, VisitResult> field_value_map;
213 };
214 
215 struct LayoutForInitialization {
216   std::map<std::string, VisitResult> array_lengths;
217   std::map<std::string, VisitResult> offsets;
218   VisitResult size;
219 };
220 
221 template <class T>
222 class Binding;
223 
224 template <class T>
225 class BindingsManager {
226  public:
TryLookup(const std::string & name)227   base::Optional<Binding<T>*> TryLookup(const std::string& name) {
228     if (name.length() >= 2 && name[0] == '_' && name[1] != '_') {
229       Error("Trying to reference '", name, "' which is marked as unused.")
230           .Throw();
231     }
232     auto binding = current_bindings_[name];
233     if (binding) {
234       (*binding)->SetUsed();
235     }
236     return binding;
237   }
238 
239  private:
240   friend class Binding<T>;
241   std::unordered_map<std::string, base::Optional<Binding<T>*>>
242       current_bindings_;
243 };
244 
245 template <class T>
246 class Binding : public T {
247  public:
248   template <class... Args>
Binding(BindingsManager<T> * manager,const std::string & name,Args &&...args)249   Binding(BindingsManager<T>* manager, const std::string& name, Args&&... args)
250       : T(std::forward<Args>(args)...),
251         manager_(manager),
252         name_(name),
253         previous_binding_(this),
254         used_(false),
255         written_(false) {
256     std::swap(previous_binding_, manager_->current_bindings_[name]);
257   }
258   template <class... Args>
Binding(BindingsManager<T> * manager,const Identifier * name,Args &&...args)259   Binding(BindingsManager<T>* manager, const Identifier* name, Args&&... args)
260       : Binding(manager, name->value, std::forward<Args>(args)...) {
261     declaration_position_ = name->pos;
262   }
~Binding()263   ~Binding() {
264     if (!used_ && !SkipLintCheck()) {
265       Lint(BindingTypeString(), "'", name_,
266            "' is never used. Prefix with '_' if this is intentional.")
267           .Position(declaration_position_);
268     }
269 
270     if (CheckWritten() && !written_ && !SkipLintCheck()) {
271       Lint(BindingTypeString(), "'", name_,
272            "' is never assigned to. Use 'const' instead of 'let'.")
273           .Position(declaration_position_);
274     }
275 
276     manager_->current_bindings_[name_] = previous_binding_;
277   }
278 
279   std::string BindingTypeString() const;
280   bool CheckWritten() const;
281 
name()282   const std::string& name() const { return name_; }
declaration_position()283   SourcePosition declaration_position() const { return declaration_position_; }
284 
Used()285   bool Used() const { return used_; }
SetUsed()286   void SetUsed() { used_ = true; }
287 
Written()288   bool Written() const { return written_; }
SetWritten()289   void SetWritten() { written_ = true; }
290 
291  private:
SkipLintCheck()292   bool SkipLintCheck() const { return name_.length() > 0 && name_[0] == '_'; }
293 
294   BindingsManager<T>* manager_;
295   const std::string name_;
296   base::Optional<Binding*> previous_binding_;
297   SourcePosition declaration_position_ = CurrentSourcePosition::Get();
298   bool used_;
299   bool written_;
300   DISALLOW_COPY_AND_ASSIGN(Binding);
301 };
302 
303 template <class T>
304 class BlockBindings {
305  public:
BlockBindings(BindingsManager<T> * manager)306   explicit BlockBindings(BindingsManager<T>* manager) : manager_(manager) {}
307   void Add(std::string name, T value, bool mark_as_used = false) {
308     ReportErrorIfAlreadyBound(name);
309     auto binding =
310         std::make_unique<Binding<T>>(manager_, name, std::move(value));
311     if (mark_as_used) binding->SetUsed();
312     bindings_.push_back(std::move(binding));
313   }
314 
315   void Add(const Identifier* name, T value, bool mark_as_used = false) {
316     ReportErrorIfAlreadyBound(name->value);
317     auto binding =
318         std::make_unique<Binding<T>>(manager_, name, std::move(value));
319     if (mark_as_used) binding->SetUsed();
320     bindings_.push_back(std::move(binding));
321   }
322 
bindings()323   std::vector<Binding<T>*> bindings() const {
324     std::vector<Binding<T>*> result;
325     result.reserve(bindings_.size());
326     for (auto& b : bindings_) {
327       result.push_back(b.get());
328     }
329     return result;
330   }
331 
332  private:
ReportErrorIfAlreadyBound(const std::string & name)333   void ReportErrorIfAlreadyBound(const std::string& name) {
334     for (const auto& binding : bindings_) {
335       if (binding->name() == name) {
336         ReportError(
337             "redeclaration of name \"", name,
338             "\" in the same block is illegal, previous declaration at: ",
339             binding->declaration_position());
340       }
341     }
342   }
343 
344   BindingsManager<T>* manager_;
345   std::vector<std::unique_ptr<Binding<T>>> bindings_;
346 };
347 
348 class LocalValue {
349  public:
LocalValue(LocationReference reference)350   explicit LocalValue(LocationReference reference)
351       : value(std::move(reference)) {}
LocalValue(std::string inaccessible_explanation)352   explicit LocalValue(std::string inaccessible_explanation)
353       : inaccessible_explanation(std::move(inaccessible_explanation)) {}
354 
GetLocationReference(Binding<LocalValue> * binding)355   LocationReference GetLocationReference(Binding<LocalValue>* binding) {
356     if (value) {
357       const LocationReference& ref = *value;
358       if (ref.IsVariableAccess()) {
359         // Attach the binding to enable the never-assigned-to lint check.
360         return LocationReference::VariableAccess(ref.GetVisitResult(), binding);
361       }
362       return ref;
363     } else {
364       Error("Cannot access ", binding->name(), ": ", inaccessible_explanation)
365           .Throw();
366     }
367   }
368 
IsAccessible()369   bool IsAccessible() const { return value.has_value(); }
370 
371  private:
372   base::Optional<LocationReference> value;
373   std::string inaccessible_explanation;
374 };
375 
376 struct LocalLabel {
377   Block* block;
378   std::vector<const Type*> parameter_types;
379 
380   explicit LocalLabel(Block* block,
381                       std::vector<const Type*> parameter_types = {})
blockLocalLabel382       : block(block), parameter_types(std::move(parameter_types)) {}
383 };
384 
385 template <>
BindingTypeString()386 inline std::string Binding<LocalValue>::BindingTypeString() const {
387   return "Variable ";
388 }
389 template <>
CheckWritten()390 inline bool Binding<LocalValue>::CheckWritten() const {
391   // Do the check only for non-const variables and non struct types.
392   auto binding = *manager_->current_bindings_[name_];
393   if (!binding->IsAccessible()) return false;
394   const LocationReference& ref = binding->GetLocationReference(binding);
395   if (!ref.IsVariableAccess()) return false;
396   return !ref.GetVisitResult().type()->StructSupertype();
397 }
398 template <>
BindingTypeString()399 inline std::string Binding<LocalLabel>::BindingTypeString() const {
400   return "Label ";
401 }
402 template <>
CheckWritten()403 inline bool Binding<LocalLabel>::CheckWritten() const {
404   return false;
405 }
406 
407 struct Arguments {
408   VisitResultVector parameters;
409   std::vector<Binding<LocalLabel>*> labels;
410 };
411 
412 // Determine if a callable should be considered as an overload.
413 bool IsCompatibleSignature(const Signature& sig, const TypeVector& types,
414                            size_t label_count);
415 
416 class ImplementationVisitor {
417  public:
418   void GenerateBuiltinDefinitionsAndInterfaceDescriptors(
419       const std::string& output_directory);
420   void GenerateClassFieldOffsets(const std::string& output_directory);
421   void GenerateBitFields(const std::string& output_directory);
422   void GeneratePrintDefinitions(const std::string& output_directory);
423   void GenerateClassDefinitions(const std::string& output_directory);
424   void GenerateBodyDescriptors(const std::string& output_directory);
425   void GenerateInstanceTypes(const std::string& output_directory);
426   void GenerateClassVerifiers(const std::string& output_directory);
427   void GenerateEnumVerifiers(const std::string& output_directory);
428   void GenerateClassDebugReaders(const std::string& output_directory);
429   void GenerateExportedMacrosAssembler(const std::string& output_directory);
430   void GenerateCSATypes(const std::string& output_directory);
431 
432   VisitResult Visit(Expression* expr);
433   const Type* Visit(Statement* stmt);
434 
435   void CheckInitializersWellformed(
436       const std::string& aggregate_name,
437       const std::vector<Field>& aggregate_fields,
438       const std::vector<NameAndExpression>& initializers,
439       bool ignore_first_field = false);
440 
441   InitializerResults VisitInitializerResults(
442       const ClassType* class_type,
443       const std::vector<NameAndExpression>& expressions);
444   LocationReference GenerateFieldReference(VisitResult object,
445                                            const Field& field,
446                                            const ClassType* class_type);
447   LocationReference GenerateFieldReferenceForInit(
448       VisitResult object, const Field& field,
449       const LayoutForInitialization& layout);
450   VisitResult GenerateArrayLength(
451       Expression* array_length, Namespace* nspace,
452       const std::map<std::string, LocalValue>& bindings);
453   VisitResult GenerateArrayLength(VisitResult object, const Field& field);
454   VisitResult GenerateArrayLength(const ClassType* class_type,
455                                   const InitializerResults& initializer_results,
456                                   const Field& field);
457   LayoutForInitialization GenerateLayoutForInitialization(
458       const ClassType* class_type,
459       const InitializerResults& initializer_results);
460 
461   void InitializeClass(const ClassType* class_type, VisitResult allocate_result,
462                        const InitializerResults& initializer_results,
463                        const LayoutForInitialization& layout);
464 
465   VisitResult Visit(StructExpression* decl);
466 
467   LocationReference GetLocationReference(Expression* location);
468   LocationReference LookupLocalValue(const std::string& name);
469   LocationReference GetLocationReference(IdentifierExpression* expr);
470   LocationReference GetLocationReference(DereferenceExpression* expr);
471   LocationReference GetLocationReference(FieldAccessExpression* expr);
472   LocationReference GenerateFieldAccess(
473       LocationReference reference, const std::string& fieldname,
474       bool ignore_stuct_field_constness = false,
475       base::Optional<SourcePosition> pos = {});
476   LocationReference GetLocationReference(ElementAccessExpression* expr);
477 
478   VisitResult GenerateFetchFromLocation(const LocationReference& reference);
479 
480   VisitResult GetBuiltinCode(Builtin* builtin);
481 
482   VisitResult Visit(LocationExpression* expr);
483 
484   void VisitAllDeclarables();
485   void Visit(Declarable* delarable);
486   void Visit(TypeAlias* decl);
487   VisitResult InlineMacro(Macro* macro,
488                           base::Optional<LocationReference> this_reference,
489                           const std::vector<VisitResult>& arguments,
490                           const std::vector<Block*> label_blocks);
491   void VisitMacroCommon(Macro* macro);
Visit(ExternMacro * macro)492   void Visit(ExternMacro* macro) {}
493   void Visit(TorqueMacro* macro);
494   void Visit(Method* macro);
495   void Visit(Builtin* builtin);
496   void Visit(NamespaceConstant* decl);
497 
498   VisitResult Visit(CallExpression* expr, bool is_tail = false);
499   VisitResult Visit(CallMethodExpression* expr);
500   VisitResult Visit(IntrinsicCallExpression* intrinsic);
501   const Type* Visit(TailCallStatement* stmt);
502 
503   VisitResult Visit(ConditionalExpression* expr);
504 
505   VisitResult Visit(LogicalOrExpression* expr);
506   VisitResult Visit(LogicalAndExpression* expr);
507 
508   VisitResult Visit(IncrementDecrementExpression* expr);
509   VisitResult Visit(AssignmentExpression* expr);
510   VisitResult Visit(StringLiteralExpression* expr);
511   VisitResult Visit(NumberLiteralExpression* expr);
512   VisitResult Visit(AssumeTypeImpossibleExpression* expr);
513   VisitResult Visit(TryLabelExpression* expr);
514   VisitResult Visit(StatementExpression* expr);
515   VisitResult Visit(NewExpression* expr);
516   VisitResult Visit(SpreadExpression* expr);
517 
518   const Type* Visit(ReturnStatement* stmt);
519   const Type* Visit(GotoStatement* stmt);
520   const Type* Visit(IfStatement* stmt);
521   const Type* Visit(WhileStatement* stmt);
522   const Type* Visit(BreakStatement* stmt);
523   const Type* Visit(ContinueStatement* stmt);
524   const Type* Visit(ForLoopStatement* stmt);
525   const Type* Visit(VarDeclarationStatement* stmt);
526   const Type* Visit(VarDeclarationStatement* stmt,
527                     BlockBindings<LocalValue>* block_bindings);
528   const Type* Visit(BlockStatement* block);
529   const Type* Visit(ExpressionStatement* stmt);
530   const Type* Visit(DebugStatement* stmt);
531   const Type* Visit(AssertStatement* stmt);
532 
533   void BeginCSAFiles();
534   void EndCSAFiles();
535 
536   void GenerateImplementation(const std::string& dir);
537 
538   DECLARE_CONTEXTUAL_VARIABLE(ValueBindingsManager,
539                               BindingsManager<LocalValue>);
540   DECLARE_CONTEXTUAL_VARIABLE(LabelBindingsManager,
541                               BindingsManager<LocalLabel>);
542   DECLARE_CONTEXTUAL_VARIABLE(CurrentCallable, Callable*);
543   DECLARE_CONTEXTUAL_VARIABLE(CurrentFileStreams,
544                               GlobalContext::PerFileStreams*);
545   DECLARE_CONTEXTUAL_VARIABLE(CurrentReturnValue, base::Optional<VisitResult>);
546 
547   // A BindingsManagersScope has to be active for local bindings to be created.
548   // Shadowing an existing BindingsManagersScope by creating a new one hides all
549   // existing bindings while the additional BindingsManagersScope is active.
550   struct BindingsManagersScope {
551     ValueBindingsManager::Scope value_bindings_manager;
552     LabelBindingsManager::Scope label_bindings_manager;
553   };
554 
SetDryRun(bool is_dry_run)555   void SetDryRun(bool is_dry_run) { is_dry_run_ = is_dry_run; }
556 
557  private:
558   base::Optional<Block*> GetCatchBlock();
559   void GenerateCatchBlock(base::Optional<Block*> catch_block);
560 
561   // {StackScope} records the stack height at creation time and reconstructs it
562   // when being destructed by emitting a {DeleteRangeInstruction}, except for
563   // the slots protected by {StackScope::Yield}. Calling {Yield(v)} deletes all
564   // slots above the initial stack height except for the slots of {v}, which are
565   // moved to form the only slots above the initial height and marks them to
566   // survive destruction of the {StackScope}. A typical pattern is the
567   // following:
568   //
569   // VisitResult result;
570   // {
571   //   StackScope stack_scope(this);
572   //   // ... create temporary slots ...
573   //   result = stack_scope.Yield(surviving_slots);
574   // }
575   class StackScope {
576    public:
StackScope(ImplementationVisitor * visitor)577     explicit StackScope(ImplementationVisitor* visitor) : visitor_(visitor) {
578       base_ = visitor_->assembler().CurrentStack().AboveTop();
579     }
Yield(VisitResult result)580     VisitResult Yield(VisitResult result) {
581       DCHECK(!closed_);
582       closed_ = true;
583       if (!result.IsOnStack()) {
584         if (!visitor_->assembler().CurrentBlockIsComplete()) {
585           visitor_->assembler().DropTo(base_);
586         }
587         return result;
588       }
589       DCHECK_LE(base_, result.stack_range().begin());
590       DCHECK_LE(result.stack_range().end(),
591                 visitor_->assembler().CurrentStack().AboveTop());
592       visitor_->assembler().DropTo(result.stack_range().end());
593       visitor_->assembler().DeleteRange(
594           StackRange{base_, result.stack_range().begin()});
595       base_ = visitor_->assembler().CurrentStack().AboveTop();
596       return VisitResult(result.type(), visitor_->assembler().TopRange(
597                                             result.stack_range().Size()));
598     }
599 
Close()600     void Close() {
601       DCHECK(!closed_);
602       closed_ = true;
603       if (!visitor_->assembler().CurrentBlockIsComplete()) {
604         visitor_->assembler().DropTo(base_);
605       }
606     }
607 
~StackScope()608     ~StackScope() {
609       if (closed_) {
610         DCHECK_IMPLIES(
611             !visitor_->assembler().CurrentBlockIsComplete(),
612             base_ == visitor_->assembler().CurrentStack().AboveTop());
613       } else {
614         Close();
615       }
616     }
617 
618    private:
619     ImplementationVisitor* visitor_;
620     BottomOffset base_;
621     bool closed_ = false;
622   };
623 
624   class BreakContinueActivator {
625    public:
BreakContinueActivator(Block * break_block,Block * continue_block)626     BreakContinueActivator(Block* break_block, Block* continue_block)
627         : break_binding_{&LabelBindingsManager::Get(), kBreakLabelName,
628                          LocalLabel{break_block}},
Get()629           continue_binding_{&LabelBindingsManager::Get(), kContinueLabelName,
630                             LocalLabel{continue_block}} {}
631 
632    private:
633     Binding<LocalLabel> break_binding_;
634     Binding<LocalLabel> continue_binding_;
635   };
636 
637   base::Optional<Binding<LocalValue>*> TryLookupLocalValue(
638       const std::string& name);
639   base::Optional<Binding<LocalLabel>*> TryLookupLabel(const std::string& name);
640   Binding<LocalLabel>* LookupLabel(const std::string& name);
641   Block* LookupSimpleLabel(const std::string& name);
642   template <class Container>
643   Callable* LookupCallable(const QualifiedName& name,
644                            const Container& declaration_container,
645                            const TypeVector& types,
646                            const std::vector<Binding<LocalLabel>*>& labels,
647                            const TypeVector& specialization_types,
648                            bool silence_errors = false);
649   bool TestLookupCallable(const QualifiedName& name,
650                           const TypeVector& parameter_types);
651 
652   template <class Container>
653   Callable* LookupCallable(const QualifiedName& name,
654                            const Container& declaration_container,
655                            const Arguments& arguments,
656                            const TypeVector& specialization_types);
657 
658   Method* LookupMethod(const std::string& name,
659                        const AggregateType* receiver_type,
660                        const Arguments& arguments,
661                        const TypeVector& specialization_types);
662 
663   const Type* GetCommonType(const Type* left, const Type* right);
664 
665   VisitResult GenerateCopy(const VisitResult& to_copy);
666 
667   void GenerateAssignToLocation(const LocationReference& reference,
668                                 const VisitResult& assignment_value);
669 
670   void AddCallParameter(Callable* callable, VisitResult parameter,
671                         const Type* parameter_type,
672                         std::vector<VisitResult>* converted_arguments,
673                         StackRange* argument_range,
674                         std::vector<std::string>* constexpr_arguments);
675 
676   VisitResult GenerateCall(Callable* callable,
677                            base::Optional<LocationReference> this_parameter,
678                            Arguments parameters,
679                            const TypeVector& specialization_types = {},
680                            bool tail_call = false);
681   VisitResult GenerateCall(const QualifiedName& callable_name,
682                            Arguments parameters,
683                            const TypeVector& specialization_types = {},
684                            bool tail_call = false);
685   VisitResult GenerateCall(std::string callable_name, Arguments parameters,
686                            const TypeVector& specialization_types = {},
687                            bool tail_call = false) {
688     return GenerateCall(QualifiedName(std::move(callable_name)),
689                         std::move(parameters), specialization_types, tail_call);
690   }
691   VisitResult GeneratePointerCall(Expression* callee,
692                                   const Arguments& parameters, bool tail_call);
693 
694   void GenerateBranch(const VisitResult& condition, Block* true_block,
695                       Block* false_block);
696 
697   VisitResult GenerateBoolConstant(bool constant);
698 
699   void GenerateExpressionBranch(Expression* expression, Block* true_block,
700                                 Block* false_block);
701 
702   void GenerateMacroFunctionDeclaration(std::ostream& o,
703                                         const std::string& macro_prefix,
704                                         Macro* macro);
705   std::vector<std::string> GenerateFunctionDeclaration(
706       std::ostream& o, const std::string& macro_prefix, const std::string& name,
707       const Signature& signature, const NameVector& parameter_names,
708       bool pass_code_assembler_state = true);
709 
710   VisitResult GenerateImplicitConvert(const Type* destination_type,
711                                       VisitResult source);
712 
713   StackRange GenerateLabelGoto(LocalLabel* label,
714                                base::Optional<StackRange> arguments = {});
715 
716   std::vector<Binding<LocalLabel>*> LabelsFromIdentifiers(
717       const std::vector<Identifier*>& names);
718 
719   StackRange LowerParameter(const Type* type, const std::string& parameter_name,
720                             Stack<std::string>* lowered_parameters);
721 
722   void LowerLabelParameter(const Type* type, const std::string& parameter_name,
723                            std::vector<std::string>* lowered_parameters);
724 
725   std::string ExternalLabelName(const std::string& label_name);
726   std::string ExternalLabelParameterName(const std::string& label_name,
727                                          size_t i);
728   std::string ExternalParameterName(const std::string& name);
729 
source_out()730   std::ostream& source_out() {
731     if (auto* streams = CurrentFileStreams::Get()) {
732       return streams->csa_ccfile;
733     }
734     return null_stream_;
735   }
header_out()736   std::ostream& header_out() {
737     if (auto* streams = CurrentFileStreams::Get()) {
738       return streams->csa_headerfile;
739     }
740     return null_stream_;
741   }
assembler()742   CfgAssembler& assembler() { return *assembler_; }
743 
SetReturnValue(VisitResult return_value)744   void SetReturnValue(VisitResult return_value) {
745     base::Optional<VisitResult>& current_return_value =
746         CurrentReturnValue::Get();
747     DCHECK_IMPLIES(current_return_value, *current_return_value == return_value);
748     current_return_value = std::move(return_value);
749   }
750 
GetAndClearReturnValue()751   VisitResult GetAndClearReturnValue() {
752     VisitResult return_value = *CurrentReturnValue::Get();
753     CurrentReturnValue::Get() = base::nullopt;
754     return return_value;
755   }
756 
WriteFile(const std::string & file,const std::string & content)757   void WriteFile(const std::string& file, const std::string& content) {
758     if (is_dry_run_) return;
759     ReplaceFileContentsIfDifferent(file, content);
760   }
761 
762   base::Optional<CfgAssembler> assembler_;
763   NullOStream null_stream_;
764   bool is_dry_run_;
765 };
766 
767 void ReportAllUnusedMacros();
768 
769 }  // namespace torque
770 }  // namespace internal
771 }  // namespace v8
772 
773 #endif  // V8_TORQUE_IMPLEMENTATION_VISITOR_H_
774