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