• 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 #include <algorithm>
6 
7 #include "src/torque/implementation-visitor.h"
8 #include "src/torque/parameter-difference.h"
9 
10 namespace v8 {
11 namespace internal {
12 namespace torque {
13 
Visit(Expression * expr)14 VisitResult ImplementationVisitor::Visit(Expression* expr) {
15   CurrentSourcePosition::Scope scope(expr->pos);
16   switch (expr->kind) {
17 #define ENUM_ITEM(name)        \
18   case AstNode::Kind::k##name: \
19     return Visit(name::cast(expr));
20     AST_EXPRESSION_NODE_KIND_LIST(ENUM_ITEM)
21 #undef ENUM_ITEM
22     default:
23       UNREACHABLE();
24   }
25 }
26 
Visit(Statement * stmt)27 const Type* ImplementationVisitor::Visit(Statement* stmt) {
28   CurrentSourcePosition::Scope scope(stmt->pos);
29   GenerateIndent();
30   source_out() << "// " << CurrentPositionAsString() << "\n";
31   switch (stmt->kind) {
32 #define ENUM_ITEM(name)        \
33   case AstNode::Kind::k##name: \
34     return Visit(name::cast(stmt));
35     AST_STATEMENT_NODE_KIND_LIST(ENUM_ITEM)
36 #undef ENUM_ITEM
37     default:
38       UNIMPLEMENTED();
39   }
40   UNREACHABLE();
41   return nullptr;
42 }
43 
Visit(Declaration * decl)44 void ImplementationVisitor::Visit(Declaration* decl) {
45   CurrentSourcePosition::Scope scope(decl->pos);
46   switch (decl->kind) {
47 #define ENUM_ITEM(name)        \
48   case AstNode::Kind::k##name: \
49     return Visit(name::cast(decl));
50     AST_DECLARATION_NODE_KIND_LIST(ENUM_ITEM)
51 #undef ENUM_ITEM
52     default:
53       UNIMPLEMENTED();
54   }
55 }
56 
Visit(CallableNode * decl,const Signature & signature,Statement * body)57 void ImplementationVisitor::Visit(CallableNode* decl,
58                                   const Signature& signature, Statement* body) {
59   switch (decl->kind) {
60 #define ENUM_ITEM(name)        \
61   case AstNode::Kind::k##name: \
62     return Visit(name::cast(decl), signature, body);
63     AST_CALLABLE_NODE_KIND_LIST(ENUM_ITEM)
64 #undef ENUM_ITEM
65     default:
66       UNIMPLEMENTED();
67   }
68 }
69 
BeginModuleFile(Module * module)70 void ImplementationVisitor::BeginModuleFile(Module* module) {
71   std::ostream& source = module->source_stream();
72   std::ostream& header = module->header_stream();
73 
74   if (module->IsDefault()) {
75     source << "#include \"src/code-stub-assembler.h\"";
76   } else {
77     source << "#include \"src/builtins/builtins-" +
78                   DashifyString(module->name()) + "-gen.h\"";
79   }
80   source << "\n";
81   source << "#include \"src/builtins/builtins-utils-gen.h\"\n";
82   source << "#include \"src/builtins/builtins.h\"\n";
83   source << "#include \"src/code-factory.h\"\n";
84   source << "#include \"src/elements-kind.h\"\n";
85   source << "#include \"src/heap/factory-inl.h\"\n";
86   source << "#include \"src/objects.h\"\n";
87   source << "#include \"src/objects/bigint.h\"\n";
88 
89   source << "#include \"builtins-" + DashifyString(module->name()) +
90                 "-from-dsl-gen.h\"\n\n";
91 
92   source << "namespace v8 {\n"
93          << "namespace internal {\n"
94          << "\n"
95          << "using Node = compiler::Node;\n"
96          << "\n";
97 
98   std::string upper_name(module->name());
99   transform(upper_name.begin(), upper_name.end(), upper_name.begin(),
100             ::toupper);
101   std::string headerDefine =
102       std::string("V8_TORQUE_") + upper_name + "_FROM_DSL_BASE_H__";
103   header << "#ifndef " << headerDefine << "\n";
104   header << "#define " << headerDefine << "\n\n";
105   if (module->IsDefault()) {
106     header << "#include \"src/code-stub-assembler.h\"";
107   } else {
108     header << "#include \"src/builtins/builtins-" +
109                   DashifyString(module->name()) + "-gen.h\"\n";
110   }
111   header << "\n\n ";
112 
113   header << "namespace v8 {\n"
114          << "namespace internal {\n"
115          << "\n";
116 
117   header << "class " << GetDSLAssemblerName(module) << ": public "
118          << GetBaseAssemblerName(module) << " {\n";
119   header << " public:\n";
120   header << "  explicit " << GetDSLAssemblerName(module)
121          << "(compiler::CodeAssemblerState* state) : "
122          << GetBaseAssemblerName(module) << "(state) {}\n";
123 
124   header << "\n";
125   header << "  using Node = compiler::Node;\n";
126   header << "  template <class T>\n";
127   header << "  using TNode = compiler::TNode<T>;\n";
128   header << "  template <class T>\n";
129   header << "  using SloppyTNode = compiler::SloppyTNode<T>;\n\n";
130 }
131 
EndModuleFile(Module * module)132 void ImplementationVisitor::EndModuleFile(Module* module) {
133   std::ostream& source = module->source_stream();
134   std::ostream& header = module->header_stream();
135 
136   DrainSpecializationQueue();
137 
138   std::string upper_name(module->name());
139   transform(upper_name.begin(), upper_name.end(), upper_name.begin(),
140             ::toupper);
141   std::string headerDefine =
142       std::string("V8_TORQUE_") + upper_name + "_FROM_DSL_BASE_H__";
143 
144   source << "}  // namespace internal\n"
145          << "}  // namespace v8\n"
146          << "\n";
147 
148   header << "};\n\n";
149   header << "}  // namespace internal\n"
150          << "}  // namespace v8\n"
151          << "\n";
152   header << "#endif  // " << headerDefine << "\n";
153 }
154 
Visit(ModuleDeclaration * decl)155 void ImplementationVisitor::Visit(ModuleDeclaration* decl) {
156   Module* module = decl->GetModule();
157   Module* saved_module = module_;
158   module_ = module;
159   Declarations::ModuleScopeActivator scope(declarations(), decl->GetModule());
160   for (auto& child : decl->declarations) Visit(child);
161   module_ = saved_module;
162 }
163 
Visit(ConstDeclaration * decl)164 void ImplementationVisitor::Visit(ConstDeclaration* decl) {
165   Signature signature = MakeSignatureFromReturnType(decl->type);
166   std::string name = decl->name;
167 
168   header_out() << "  ";
169   GenerateFunctionDeclaration(header_out(), "", name, signature, {});
170   header_out() << ";\n";
171 
172   GenerateFunctionDeclaration(source_out(),
173                               GetDSLAssemblerName(CurrentModule()) + "::", name,
174                               signature, {});
175   source_out() << " {\n";
176 
177   DCHECK(!signature.return_type->IsVoidOrNever());
178 
179   VisitResult expression_result = Visit(decl->expression);
180   VisitResult return_result =
181       GenerateImplicitConvert(signature.return_type, expression_result);
182 
183   GenerateIndent();
184   source_out() << "return " << return_result.RValue() << ";\n";
185   source_out() << "}\n\n";
186 }
187 
Visit(StructDeclaration * decl)188 void ImplementationVisitor::Visit(StructDeclaration* decl) {
189   header_out() << "  struct " << decl->name << " {\n";
190   const StructType* struct_type =
191       static_cast<const StructType*>(declarations()->LookupType(decl->name));
192   for (auto& field : struct_type->fields()) {
193     header_out() << "    " << field.type->GetGeneratedTypeName();
194     header_out() << " " << field.name << ";\n";
195   }
196   header_out() << "  } "
197                << ";\n";
198 }
199 
Visit(TorqueMacroDeclaration * decl,const Signature & sig,Statement * body)200 void ImplementationVisitor::Visit(TorqueMacroDeclaration* decl,
201                                   const Signature& sig, Statement* body) {
202   Signature signature = MakeSignature(decl->signature.get());
203   std::string name = GetGeneratedCallableName(
204       decl->name, declarations()->GetCurrentSpecializationTypeNamesVector());
205   const TypeVector& list = signature.types();
206   Macro* macro = declarations()->LookupMacro(name, list);
207 
208   CurrentCallableActivator activator(global_context_, macro, decl);
209 
210   if (body != nullptr) {
211     header_out() << "  ";
212     GenerateMacroFunctionDeclaration(header_out(), "", macro);
213     header_out() << ";\n";
214 
215     GenerateMacroFunctionDeclaration(
216         source_out(), GetDSLAssemblerName(CurrentModule()) + "::", macro);
217     source_out() << " {\n";
218 
219     const Variable* result_var = nullptr;
220     if (macro->HasReturnValue()) {
221       result_var =
222           GeneratePredeclaredVariableDeclaration(kReturnValueVariable, {});
223     }
224     Label* macro_end = declarations()->DeclareLabel("macro_end");
225     GenerateLabelDefinition(macro_end, decl);
226 
227     const Type* result = Visit(body);
228     if (result->IsNever()) {
229       if (!macro->signature().return_type->IsNever() && !macro->HasReturns()) {
230         std::stringstream s;
231         s << "macro " << decl->name
232           << " that never returns must have return type never";
233         ReportError(s.str());
234       }
235     } else {
236       if (macro->signature().return_type->IsNever()) {
237         std::stringstream s;
238         s << "macro " << decl->name
239           << " has implicit return at end of its declartion but return type "
240              "never";
241         ReportError(s.str());
242       } else if (!macro->signature().return_type->IsVoid()) {
243         std::stringstream s;
244         s << "macro " << decl->name
245           << " expects to return a value but doesn't on all paths";
246         ReportError(s.str());
247       }
248     }
249     if (macro->HasReturns()) {
250       if (!result->IsNever()) {
251         GenerateLabelGoto(macro_end);
252       }
253       GenerateLabelBind(macro_end);
254     }
255     if (result_var != nullptr) {
256       GenerateIndent();
257       source_out() << "return "
258                    << RValueFlattenStructs(
259                           VisitResult(result_var->type(), result_var))
260                    << ";\n";
261     }
262     source_out() << "}\n\n";
263   }
264 }
265 
Visit(TorqueBuiltinDeclaration * decl,const Signature & signature,Statement * body)266 void ImplementationVisitor::Visit(TorqueBuiltinDeclaration* decl,
267                                   const Signature& signature, Statement* body) {
268   std::string name = GetGeneratedCallableName(
269       decl->name, declarations()->GetCurrentSpecializationTypeNamesVector());
270   source_out() << "TF_BUILTIN(" << name << ", "
271                << GetDSLAssemblerName(CurrentModule()) << ") {\n";
272   Builtin* builtin = declarations()->LookupBuiltin(name);
273   CurrentCallableActivator activator(global_context_, builtin, decl);
274 
275   // Context
276   const Value* val =
277       declarations()->LookupValue(decl->signature->parameters.names[0]);
278   GenerateIndent();
279   source_out() << "TNode<Context> " << val->value()
280                << " = UncheckedCast<Context>(Parameter("
281                << "Descriptor::kContext));\n";
282   GenerateIndent();
283   source_out() << "USE(" << val->value() << ");\n";
284 
285   size_t first = 1;
286   if (builtin->IsVarArgsJavaScript()) {
287     assert(decl->signature->parameters.has_varargs);
288     ExternConstant* arguments =
289         ExternConstant::cast(declarations()->LookupValue(
290             decl->signature->parameters.arguments_variable));
291     std::string arguments_name = arguments->value();
292     GenerateIndent();
293     source_out()
294         << "Node* argc = Parameter(Descriptor::kJSActualArgumentsCount);\n";
295     GenerateIndent();
296     source_out() << "CodeStubArguments arguments_impl(this, "
297                     "ChangeInt32ToIntPtr(argc));\n";
298     const Value* receiver =
299         declarations()->LookupValue(decl->signature->parameters.names[1]);
300     GenerateIndent();
301     source_out() << "TNode<Object> " << receiver->value()
302                  << " = arguments_impl.GetReceiver();\n";
303     GenerateIndent();
304     source_out() << "auto arguments = &arguments_impl;\n";
305     GenerateIndent();
306     source_out() << "USE(arguments);\n";
307     GenerateIndent();
308     source_out() << "USE(" << receiver->value() << ");\n";
309     first = 2;
310   }
311 
312   GenerateParameterList(decl->signature->parameters.names, first);
313   Visit(body);
314   source_out() << "}\n\n";
315 }
316 
Visit(VarDeclarationStatement * stmt)317 const Type* ImplementationVisitor::Visit(VarDeclarationStatement* stmt) {
318   base::Optional<VisitResult> init_result;
319   if (stmt->initializer) {
320     init_result = Visit(*stmt->initializer);
321   }
322   base::Optional<const Type*> type;
323   if (stmt->type) type = declarations()->GetType(*stmt->type);
324   GenerateVariableDeclaration(stmt, stmt->name, stmt->const_qualified, type,
325                               init_result);
326   return TypeOracle::GetVoidType();
327 }
328 
Visit(TailCallStatement * stmt)329 const Type* ImplementationVisitor::Visit(TailCallStatement* stmt) {
330   return Visit(stmt->call, true).type();
331 }
332 
Visit(ConditionalExpression * expr)333 VisitResult ImplementationVisitor::Visit(ConditionalExpression* expr) {
334   std::string f1 = NewTempVariable();
335   std::string f2 = NewTempVariable();
336 
337   // The code for both paths of the conditional need to be generated first in
338   // lambdas before evaluating the conditional expression because the common
339   // type of the result of both the true and false of the condition needs to be
340   // known when declaring the variable to hold the result of the conditional.
341   VisitResult left, right;
342   GenerateIndent();
343   source_out() << "auto " << f1 << " = [=]() ";
344   {
345     ScopedIndent indent(this, false);
346     source_out() << "\n";
347     left = Visit(expr->if_true);
348     GenerateIndent();
349     source_out() << "return " << RValueFlattenStructs(left) << ";\n";
350   }
351   source_out() << ";\n";
352   GenerateIndent();
353   source_out() << "auto " << f2 << " = [=]() ";
354   {
355     ScopedIndent indent(this, false);
356     source_out() << "\n";
357     right = Visit(expr->if_false);
358     GenerateIndent();
359     source_out() << "return " << RValueFlattenStructs(right) << ";\n";
360   }
361   source_out() << ";\n";
362 
363   const Type* common_type = GetCommonType(left.type(), right.type());
364   std::string result_var = NewTempVariable();
365   Variable* result =
366       GenerateVariableDeclaration(expr, result_var, false, common_type);
367 
368   {
369     ScopedIndent indent(this);
370     Declarations::NodeScopeActivator scope(declarations(), expr->condition);
371 
372     Label* true_label = declarations()->LookupLabel(kTrueLabelName);
373     GenerateLabelDefinition(true_label);
374     Label* false_label = declarations()->LookupLabel(kFalseLabelName);
375     GenerateLabelDefinition(false_label);
376     Label* done_label = declarations()->DeclarePrivateLabel(kDoneLabelName);
377     GenerateLabelDefinition(done_label, expr);
378 
379     VisitResult condition_result = Visit(expr->condition);
380     if (!condition_result.type()->IsNever()) {
381       condition_result =
382           GenerateImplicitConvert(TypeOracle::GetBoolType(), condition_result);
383       GenerateBranch(condition_result, true_label, false_label);
384     }
385     GenerateLabelBind(true_label);
386     GenerateIndent();
387     VisitResult left_result = {right.type(), f1 + "()"};
388     GenerateAssignToVariable(result, left_result);
389     GenerateLabelGoto(done_label);
390 
391     GenerateLabelBind(false_label);
392     GenerateIndent();
393     VisitResult right_result = {right.type(), f2 + "()"};
394     GenerateAssignToVariable(result, right_result);
395     GenerateLabelGoto(done_label);
396 
397     GenerateLabelBind(done_label);
398   }
399   return VisitResult(common_type, result);
400 }
401 
Visit(LogicalOrExpression * expr)402 VisitResult ImplementationVisitor::Visit(LogicalOrExpression* expr) {
403   VisitResult left_result;
404   {
405     Declarations::NodeScopeActivator scope(declarations(), expr->left);
406     Label* false_label = declarations()->LookupLabel(kFalseLabelName);
407     GenerateLabelDefinition(false_label);
408     left_result = Visit(expr->left);
409     if (left_result.type()->IsBool()) {
410       Label* true_label = declarations()->LookupLabel(kTrueLabelName);
411       GenerateIndent();
412       source_out() << "GotoIf(" << RValueFlattenStructs(left_result) << ", "
413                    << true_label->generated() << ");\n";
414     } else if (!left_result.type()->IsConstexprBool()) {
415       GenerateLabelBind(false_label);
416     }
417   }
418   VisitResult right_result = Visit(expr->right);
419   if (right_result.type() != left_result.type()) {
420     std::stringstream stream;
421     stream << "types of left and right expression of logical OR don't match (\""
422            << *left_result.type() << "\" vs. \"" << *right_result.type()
423            << "\")";
424     ReportError(stream.str());
425   }
426   if (left_result.type()->IsConstexprBool()) {
427     return VisitResult(left_result.type(),
428                        std::string("(") + RValueFlattenStructs(left_result) +
429                            " || " + RValueFlattenStructs(right_result) + ")");
430   } else {
431     return right_result;
432   }
433 }
434 
Visit(LogicalAndExpression * expr)435 VisitResult ImplementationVisitor::Visit(LogicalAndExpression* expr) {
436   VisitResult left_result;
437   {
438     Declarations::NodeScopeActivator scope(declarations(), expr->left);
439     Label* true_label = declarations()->LookupLabel(kTrueLabelName);
440     GenerateLabelDefinition(true_label);
441     left_result = Visit(expr->left);
442     if (left_result.type()->IsBool()) {
443       Label* false_label = declarations()->LookupLabel(kFalseLabelName);
444       GenerateIndent();
445       source_out() << "GotoIfNot(" << RValueFlattenStructs(left_result) << ", "
446                    << false_label->generated() << ");\n";
447     } else if (!left_result.type()->IsConstexprBool()) {
448       GenerateLabelBind(true_label);
449     }
450   }
451   VisitResult right_result = Visit(expr->right);
452   if (right_result.type() != left_result.type()) {
453     std::stringstream stream;
454     stream
455         << "types of left and right expression of logical AND don't match (\""
456         << *left_result.type() << "\" vs. \"" << *right_result.type() << "\")";
457     ReportError(stream.str());
458   }
459   if (left_result.type()->IsConstexprBool()) {
460     return VisitResult(left_result.type(),
461                        std::string("(") + RValueFlattenStructs(left_result) +
462                            " && " + RValueFlattenStructs(right_result) + ")");
463   } else {
464     return right_result;
465   }
466 }
467 
Visit(IncrementDecrementExpression * expr)468 VisitResult ImplementationVisitor::Visit(IncrementDecrementExpression* expr) {
469   VisitResult value_copy;
470   auto location_ref = GetLocationReference(expr->location);
471   VisitResult current_value =
472       GenerateFetchFromLocation(expr->location, location_ref);
473   if (expr->postfix) {
474     value_copy = GenerateCopy(current_value);
475   }
476   VisitResult one = {TypeOracle::GetConstInt31Type(), "1"};
477   Arguments args;
478   args.parameters = {current_value, one};
479   VisitResult assignment_value = GenerateCall(
480       expr->op == IncrementDecrementOperator::kIncrement ? "+" : "-", args);
481   GenerateAssignToLocation(expr->location, location_ref, assignment_value);
482   return expr->postfix ? value_copy : assignment_value;
483 }
484 
Visit(AssignmentExpression * expr)485 VisitResult ImplementationVisitor::Visit(AssignmentExpression* expr) {
486   LocationReference location_ref = GetLocationReference(expr->location);
487   VisitResult assignment_value;
488   if (expr->op) {
489     VisitResult location_value =
490         GenerateFetchFromLocation(expr->location, location_ref);
491     assignment_value = Visit(expr->value);
492     Arguments args;
493     args.parameters = {location_value, assignment_value};
494     assignment_value = GenerateCall(*expr->op, args);
495     GenerateAssignToLocation(expr->location, location_ref, assignment_value);
496   } else {
497     assignment_value = Visit(expr->value);
498     GenerateAssignToLocation(expr->location, location_ref, assignment_value);
499   }
500   return assignment_value;
501 }
502 
Visit(NumberLiteralExpression * expr)503 VisitResult ImplementationVisitor::Visit(NumberLiteralExpression* expr) {
504   // TODO(tebbi): Do not silently loose precision; support 64bit literals.
505   double d = std::stod(expr->number.c_str());
506   int32_t i = static_cast<int32_t>(d);
507   const Type* result_type =
508       declarations()->LookupType(CONST_FLOAT64_TYPE_STRING);
509   if (i == d) {
510     if ((i >> 30) == (i >> 31)) {
511       result_type = declarations()->LookupType(CONST_INT31_TYPE_STRING);
512     } else {
513       result_type = declarations()->LookupType(CONST_INT32_TYPE_STRING);
514     }
515   }
516   std::string temp = GenerateNewTempVariable(result_type);
517   source_out() << expr->number << ";\n";
518   return VisitResult{result_type, temp};
519 }
520 
Visit(AssumeTypeImpossibleExpression * expr)521 VisitResult ImplementationVisitor::Visit(AssumeTypeImpossibleExpression* expr) {
522   VisitResult result = Visit(expr->expression);
523   const Type* result_type =
524       SubtractType(result.type(), declarations()->GetType(expr->excluded_type));
525   if (result_type->IsNever()) {
526     ReportError("unreachable code");
527   }
528   return VisitResult{result_type, "UncheckedCast<" +
529                                       result_type->GetGeneratedTNodeTypeName() +
530                                       ">(" + result.RValue() + ")"};
531 }
532 
Visit(StringLiteralExpression * expr)533 VisitResult ImplementationVisitor::Visit(StringLiteralExpression* expr) {
534   std::string temp = GenerateNewTempVariable(TypeOracle::GetConstStringType());
535   source_out() << "\"" << expr->literal.substr(1, expr->literal.size() - 2)
536                << "\";\n";
537   return VisitResult{TypeOracle::GetConstStringType(), temp};
538 }
539 
GetBuiltinCode(Builtin * builtin)540 VisitResult ImplementationVisitor::GetBuiltinCode(Builtin* builtin) {
541   if (builtin->IsExternal() || builtin->kind() != Builtin::kStub) {
542     ReportError(
543         "creating function pointers is only allowed for internal builtins with "
544         "stub linkage");
545   }
546   const Type* type = TypeOracle::GetFunctionPointerType(
547       builtin->signature().parameter_types.types,
548       builtin->signature().return_type);
549   std::string code =
550       "HeapConstant(Builtins::CallableFor(isolate(), Builtins::k" +
551       builtin->name() + ").code())";
552   return VisitResult(type, code);
553 }
554 
Visit(IdentifierExpression * expr)555 VisitResult ImplementationVisitor::Visit(IdentifierExpression* expr) {
556   std::string name = expr->name;
557   if (expr->generic_arguments.size() != 0) {
558     GenericList* generic_list = declarations()->LookupGeneric(expr->name);
559     for (Generic* generic : generic_list->list()) {
560       TypeVector specialization_types = GetTypeVector(expr->generic_arguments);
561       name = GetGeneratedCallableName(name, specialization_types);
562       CallableNode* callable = generic->declaration()->callable;
563       QueueGenericSpecialization({generic, specialization_types}, callable,
564                                  callable->signature.get(),
565                                  generic->declaration()->body);
566     }
567   }
568 
569   if (Builtin* builtin = Builtin::DynamicCast(declarations()->Lookup(name))) {
570     return GetBuiltinCode(builtin);
571   }
572 
573   return GenerateFetchFromLocation(expr, GetLocationReference(expr));
574 }
575 
Visit(GotoStatement * stmt)576 const Type* ImplementationVisitor::Visit(GotoStatement* stmt) {
577   Label* label = declarations()->LookupLabel(stmt->label);
578 
579   if (stmt->arguments.size() != label->GetParameterCount()) {
580     std::stringstream stream;
581     stream << "goto to label has incorrect number of parameters (expected "
582            << std::to_string(label->GetParameterCount()) << " found "
583            << std::to_string(stmt->arguments.size()) << ")";
584     ReportError(stream.str());
585   }
586 
587   size_t i = 0;
588   for (Expression* e : stmt->arguments) {
589     VisitResult result = Visit(e);
590     Variable* var = label->GetParameter(i++);
591     GenerateAssignToVariable(var, result);
592   }
593 
594   GenerateLabelGoto(label);
595   label->MarkUsed();
596   return TypeOracle::GetNeverType();
597 }
598 
Visit(IfStatement * stmt)599 const Type* ImplementationVisitor::Visit(IfStatement* stmt) {
600   ScopedIndent indent(this);
601 
602   bool has_else = stmt->if_false.has_value();
603 
604   if (stmt->is_constexpr) {
605     VisitResult expression_result = Visit(stmt->condition);
606 
607     if (!(expression_result.type() == TypeOracle::GetConstexprBoolType())) {
608       std::stringstream stream;
609       stream << "expression should return type constexpr bool "
610              << "but returns type " << *expression_result.type();
611       ReportError(stream.str());
612     }
613 
614     const Type* left_result;
615     const Type* right_result = TypeOracle::GetVoidType();
616     {
617       GenerateIndent();
618       source_out() << "if ((" << RValueFlattenStructs(expression_result)
619                    << ")) ";
620       ScopedIndent indent(this, false);
621       source_out() << "\n";
622       left_result = Visit(stmt->if_true);
623     }
624 
625     if (has_else) {
626       source_out() << " else ";
627       ScopedIndent indent(this, false);
628       source_out() << "\n";
629       right_result = Visit(*stmt->if_false);
630     }
631     if (left_result->IsNever() != right_result->IsNever()) {
632       std::stringstream stream;
633       stream << "either both or neither branches in a constexpr if statement "
634                 "must reach their end at"
635              << PositionAsString(stmt->pos);
636       ReportError(stream.str());
637     }
638 
639     source_out() << "\n";
640 
641     return left_result;
642   } else {
643     Label* true_label = nullptr;
644     Label* false_label = nullptr;
645     {
646       Declarations::NodeScopeActivator scope(declarations(), &*stmt->condition);
647       true_label = declarations()->LookupLabel(kTrueLabelName);
648       GenerateLabelDefinition(true_label);
649       false_label = declarations()->LookupLabel(kFalseLabelName);
650       GenerateLabelDefinition(false_label, !has_else ? stmt : nullptr);
651     }
652 
653     Label* done_label = nullptr;
654     bool live = false;
655     if (has_else) {
656       done_label = declarations()->DeclarePrivateLabel("if_done_label");
657       GenerateLabelDefinition(done_label, stmt);
658     } else {
659       done_label = false_label;
660       live = true;
661     }
662     std::vector<Statement*> blocks = {stmt->if_true};
663     std::vector<Label*> labels = {true_label, false_label};
664     if (has_else) blocks.push_back(*stmt->if_false);
665     if (GenerateExpressionBranch(stmt->condition, labels, blocks, done_label)) {
666       live = true;
667     }
668     if (live) {
669       GenerateLabelBind(done_label);
670     }
671     return live ? TypeOracle::GetVoidType() : TypeOracle::GetNeverType();
672   }
673 }
674 
Visit(WhileStatement * stmt)675 const Type* ImplementationVisitor::Visit(WhileStatement* stmt) {
676   ScopedIndent indent(this);
677 
678   Label* body_label = nullptr;
679   Label* exit_label = nullptr;
680   {
681     Declarations::NodeScopeActivator scope(declarations(), stmt->condition);
682     body_label = declarations()->LookupLabel(kTrueLabelName);
683     GenerateLabelDefinition(body_label);
684     exit_label = declarations()->LookupLabel(kFalseLabelName);
685     GenerateLabelDefinition(exit_label);
686   }
687 
688   Label* header_label = declarations()->DeclarePrivateLabel("header");
689   GenerateLabelDefinition(header_label, stmt);
690   GenerateLabelGoto(header_label);
691   GenerateLabelBind(header_label);
692 
693   Declarations::NodeScopeActivator scope(declarations(), stmt->body);
694   BreakContinueActivator activator(global_context_, exit_label, header_label);
695 
696   GenerateExpressionBranch(stmt->condition, {body_label, exit_label},
697                            {stmt->body}, header_label);
698 
699   GenerateLabelBind(exit_label);
700   return TypeOracle::GetVoidType();
701 }
702 
Visit(BlockStatement * block)703 const Type* ImplementationVisitor::Visit(BlockStatement* block) {
704   Declarations::NodeScopeActivator scope(declarations(), block);
705   ScopedIndent indent(this);
706   const Type* type = TypeOracle::GetVoidType();
707   for (Statement* s : block->statements) {
708     if (type->IsNever()) {
709       std::stringstream stream;
710       stream << "statement after non-returning statement";
711       ReportError(stream.str());
712     }
713     type = Visit(s);
714   }
715   return type;
716 }
717 
Visit(DebugStatement * stmt)718 const Type* ImplementationVisitor::Visit(DebugStatement* stmt) {
719 #if defined(DEBUG)
720   GenerateIndent();
721   source_out() << "Print(\""
722                << "halting because of '" << stmt->reason << "' at "
723                << PositionAsString(stmt->pos) << "\");\n";
724 #endif
725   GenerateIndent();
726   if (stmt->never_continues) {
727     source_out() << "Unreachable();\n";
728     return TypeOracle::GetNeverType();
729   } else {
730     source_out() << "DebugBreak();\n";
731     return TypeOracle::GetVoidType();
732   }
733 }
734 
735 namespace {
736 
FormatAssertSource(const std::string & str)737 std::string FormatAssertSource(const std::string& str) {
738   // Replace all whitespace characters with a space character.
739   std::string str_no_newlines = str;
740   std::replace_if(str_no_newlines.begin(), str_no_newlines.end(),
741                   [](unsigned char c) { return isspace(c); }, ' ');
742 
743   // str might include indentation, squash multiple space characters into one.
744   std::string result;
745   std::unique_copy(str_no_newlines.begin(), str_no_newlines.end(),
746                    std::back_inserter(result),
747                    [](char a, char b) { return a == ' ' && b == ' '; });
748   return result;
749 }
750 
751 }  // namespace
752 
Visit(AssertStatement * stmt)753 const Type* ImplementationVisitor::Visit(AssertStatement* stmt) {
754   bool do_check = !stmt->debug_only;
755 #if defined(DEBUG)
756   do_check = true;
757 #endif
758   if (do_check) {
759     // CSA_ASSERT & co. are not used here on purpose for two reasons. First,
760     // Torque allows and handles two types of expressions in the if protocol
761     // automagically, ones that return TNode<BoolT> and those that use the
762     // BranchIf(..., Label* true, Label* false) idiom. Because the machinery to
763     // handle this is embedded in the expression handling and to it's not
764     // possible to make the decision to use CSA_ASSERT or CSA_ASSERT_BRANCH
765     // isn't trivial up-front. Secondly, on failure, the assert text should be
766     // the corresponding Torque code, not the -gen.cc code, which would be the
767     // case when using CSA_ASSERT_XXX.
768     Label* true_label = nullptr;
769     Label* false_label = nullptr;
770     Declarations::NodeScopeActivator scope(declarations(), stmt->expression);
771     true_label = declarations()->LookupLabel(kTrueLabelName);
772     GenerateLabelDefinition(true_label);
773     false_label = declarations()->LookupLabel(kFalseLabelName);
774     GenerateLabelDefinition(false_label);
775 
776     VisitResult expression_result = Visit(stmt->expression);
777     if (expression_result.type() == TypeOracle::GetBoolType()) {
778       GenerateBranch(expression_result, true_label, false_label);
779     } else {
780       if (expression_result.type() != TypeOracle::GetNeverType()) {
781         std::stringstream s;
782         s << "unexpected return type " << *expression_result.type()
783           << " for branch expression";
784         ReportError(s.str());
785       }
786     }
787 
788     GenerateLabelBind(false_label);
789     GenerateIndent();
790     source_out() << "Print(\""
791                  << "assert '" << FormatAssertSource(stmt->source)
792                  << "' failed at " << PositionAsString(stmt->pos) << "\");\n";
793     GenerateIndent();
794     source_out() << "Unreachable();\n";
795 
796     GenerateLabelBind(true_label);
797   }
798   return TypeOracle::GetVoidType();
799 }
800 
Visit(ExpressionStatement * stmt)801 const Type* ImplementationVisitor::Visit(ExpressionStatement* stmt) {
802   const Type* type = Visit(stmt->expression).type();
803   return type->IsNever() ? type : TypeOracle::GetVoidType();
804 }
805 
Visit(ReturnStatement * stmt)806 const Type* ImplementationVisitor::Visit(ReturnStatement* stmt) {
807   Callable* current_callable = global_context_.GetCurrentCallable();
808   if (current_callable->signature().return_type->IsNever()) {
809     std::stringstream s;
810     s << "cannot return from a function with return type never";
811     ReportError(s.str());
812   }
813   Label* end = current_callable->IsMacro()
814                    ? declarations()->LookupLabel("macro_end")
815                    : nullptr;
816   if (current_callable->HasReturnValue()) {
817     if (!stmt->value) {
818       std::stringstream s;
819       s << "return expression needs to be specified for a return type of "
820         << *current_callable->signature().return_type;
821       ReportError(s.str());
822     }
823     VisitResult expression_result = Visit(*stmt->value);
824     VisitResult return_result = GenerateImplicitConvert(
825         current_callable->signature().return_type, expression_result);
826     if (current_callable->IsMacro()) {
827       Variable* var =
828           Variable::cast(declarations()->LookupValue(kReturnValueVariable));
829       GenerateAssignToVariable(var, return_result);
830       GenerateLabelGoto(end);
831     } else if (current_callable->IsBuiltin()) {
832       if (Builtin::cast(current_callable)->IsVarArgsJavaScript()) {
833         GenerateIndent();
834         source_out() << "arguments->PopAndReturn("
835                      << RValueFlattenStructs(return_result) << ");\n";
836       } else {
837         GenerateIndent();
838         source_out() << "Return(" << RValueFlattenStructs(return_result)
839                      << ");\n";
840       }
841     } else {
842       UNREACHABLE();
843     }
844   } else {
845     if (stmt->value) {
846       std::stringstream s;
847       s << "return expression can't be specified for a void or never return "
848            "type";
849       ReportError(s.str());
850     }
851     GenerateLabelGoto(end);
852   }
853   current_callable->IncrementReturns();
854   return TypeOracle::GetNeverType();
855 }
856 
Visit(ForOfLoopStatement * stmt)857 const Type* ImplementationVisitor::Visit(ForOfLoopStatement* stmt) {
858   Declarations::NodeScopeActivator scope(declarations(), stmt);
859 
860   VisitResult expression_result = Visit(stmt->iterable);
861   VisitResult begin = stmt->begin
862                           ? Visit(*stmt->begin)
863                           : VisitResult(TypeOracle::GetConstInt31Type(), "0");
864 
865   VisitResult end = stmt->end
866                         ? Visit(*stmt->end)
867                         : GenerateCall(".length", {{expression_result}, {}});
868 
869   Label* body_label = declarations()->DeclarePrivateLabel("body");
870   GenerateLabelDefinition(body_label);
871   Label* increment_label = declarations()->DeclarePrivateLabel("increment");
872   GenerateLabelDefinition(increment_label);
873   Label* exit_label = declarations()->DeclarePrivateLabel("exit");
874   GenerateLabelDefinition(exit_label);
875 
876   const Type* common_type = GetCommonType(begin.type(), end.type());
877   Variable* index_var = GenerateVariableDeclaration(
878       stmt, std::string(kForIndexValueVariable) + "_" + NewTempVariable(),
879       false, common_type, begin);
880 
881   VisitResult index_for_read = {index_var->type(), index_var};
882 
883   Label* header_label = declarations()->DeclarePrivateLabel("header");
884   GenerateLabelDefinition(header_label, stmt);
885 
886   GenerateLabelGoto(header_label);
887 
888   GenerateLabelBind(header_label);
889 
890   BreakContinueActivator activator(global_context_, exit_label,
891                                    increment_label);
892 
893   VisitResult result = GenerateCall("<", {{index_for_read, end}, {}});
894   GenerateBranch(result, body_label, exit_label);
895 
896   GenerateLabelBind(body_label);
897   VisitResult element_result =
898       GenerateCall("[]", {{expression_result, index_for_read}, {}});
899   base::Optional<const Type*> declared_type;
900   if (stmt->var_declaration->type)
901     declared_type = declarations()->GetType(*stmt->var_declaration->type);
902   GenerateVariableDeclaration(
903       stmt->var_declaration, stmt->var_declaration->name,
904       stmt->var_declaration->const_qualified, declared_type, element_result);
905   Visit(stmt->body);
906   GenerateLabelGoto(increment_label);
907 
908   GenerateLabelBind(increment_label);
909   Arguments increment_args;
910   increment_args.parameters = {index_for_read,
911                                {TypeOracle::GetConstInt31Type(), "1"}};
912   VisitResult increment_result = GenerateCall("+", increment_args);
913 
914   GenerateAssignToVariable(index_var, increment_result);
915 
916   GenerateLabelGoto(header_label);
917 
918   GenerateLabelBind(exit_label);
919   return TypeOracle::GetVoidType();
920 }
921 
Visit(TryLabelStatement * stmt)922 const Type* ImplementationVisitor::Visit(TryLabelStatement* stmt) {
923   ScopedIndent indent(this);
924   Label* try_done = declarations()->DeclarePrivateLabel("try_done");
925   GenerateLabelDefinition(try_done);
926   const Type* try_result = TypeOracle::GetNeverType();
927   std::vector<Label*> labels;
928 
929   // Output labels for the goto handlers and for the merge after the try.
930   {
931     // Activate a new scope to see handler labels
932     Declarations::NodeScopeActivator scope(declarations(), stmt);
933     for (LabelBlock* block : stmt->label_blocks) {
934       CurrentSourcePosition::Scope scope(block->pos);
935       Label* label = declarations()->LookupLabel(block->label);
936       labels.push_back(label);
937       GenerateLabelDefinition(label);
938     }
939 
940     size_t i = 0;
941     for (auto label : labels) {
942       Declarations::NodeScopeActivator scope(declarations(),
943                                              stmt->label_blocks[i]->body);
944       for (auto& v : label->GetParameters()) {
945         GenerateVariableDeclaration(stmt, v->name(), false, v->type());
946         v->Define();
947       }
948       ++i;
949     }
950 
951     Label* try_begin_label = declarations()->DeclarePrivateLabel("try_begin");
952     GenerateLabelDefinition(try_begin_label);
953     GenerateLabelGoto(try_begin_label);
954 
955     // Visit try
956     if (GenerateLabeledStatementBlocks({stmt->try_block},
957                                        std::vector<Label*>({try_begin_label}),
958                                        try_done)) {
959       try_result = TypeOracle::GetVoidType();
960     }
961   }
962 
963   // Make sure that each label clause is actually used. It's not just a friendly
964   // thing to do, it will cause problems downstream in the compiler if there are
965   // bound labels that are never jumped to.
966   auto label_iterator = stmt->label_blocks.begin();
967   for (auto label : labels) {
968     CurrentSourcePosition::Scope scope((*label_iterator)->pos);
969     if (!label->IsUsed()) {
970       std::stringstream s;
971       s << "label ";
972       s << (*label_iterator)->label;
973       s << " has a handler block but is never referred to in try block";
974       ReportError(s.str());
975     }
976     label_iterator++;
977   }
978 
979   // Visit and output the code for each catch block, one-by-one.
980   std::vector<Statement*> bodies;
981   for (LabelBlock* block : stmt->label_blocks) bodies.push_back(block->body);
982   if (GenerateLabeledStatementBlocks(bodies, labels, try_done)) {
983     try_result = TypeOracle::GetVoidType();
984   }
985 
986   if (!try_result->IsNever()) {
987     GenerateLabelBind(try_done);
988   }
989   return try_result;
990 }
991 
Visit(BreakStatement * stmt)992 const Type* ImplementationVisitor::Visit(BreakStatement* stmt) {
993   Label* break_label = global_context_.GetCurrentBreak();
994   if (break_label == nullptr) {
995     ReportError("break used outside of loop");
996   }
997   GenerateLabelGoto(break_label);
998   return TypeOracle::GetNeverType();
999 }
1000 
Visit(ContinueStatement * stmt)1001 const Type* ImplementationVisitor::Visit(ContinueStatement* stmt) {
1002   Label* continue_label = global_context_.GetCurrentContinue();
1003   if (continue_label == nullptr) {
1004     ReportError("continue used outside of loop");
1005   }
1006   GenerateLabelGoto(continue_label);
1007   return TypeOracle::GetNeverType();
1008 }
1009 
Visit(ForLoopStatement * stmt)1010 const Type* ImplementationVisitor::Visit(ForLoopStatement* stmt) {
1011   Declarations::NodeScopeActivator scope(declarations(), stmt);
1012 
1013   if (stmt->var_declaration) Visit(*stmt->var_declaration);
1014 
1015   Label* body_label = declarations()->LookupLabel(kTrueLabelName);
1016   GenerateLabelDefinition(body_label);
1017   Label* exit_label = declarations()->LookupLabel(kFalseLabelName);
1018   GenerateLabelDefinition(exit_label);
1019 
1020   Label* header_label = declarations()->DeclarePrivateLabel("header");
1021   GenerateLabelDefinition(header_label, stmt);
1022   GenerateLabelGoto(header_label);
1023   GenerateLabelBind(header_label);
1024 
1025   // The continue label is where "continue" statements jump to. If no action
1026   // expression is provided, we jump directly to the header.
1027   Label* continue_label = header_label;
1028 
1029   // The action label is only needed when an action expression was provided.
1030   Label* action_label = nullptr;
1031   if (stmt->action) {
1032     action_label = declarations()->DeclarePrivateLabel("action");
1033     GenerateLabelDefinition(action_label);
1034 
1035     // The action expression needs to be executed on a continue.
1036     continue_label = action_label;
1037   }
1038 
1039   BreakContinueActivator activator(global_context_, exit_label, continue_label);
1040 
1041   std::vector<Label*> labels = {body_label, exit_label};
1042   bool generate_action = true;
1043   if (stmt->test) {
1044     generate_action = GenerateExpressionBranch(*stmt->test, labels,
1045                                                {stmt->body}, continue_label);
1046   } else {
1047     GenerateLabelGoto(body_label);
1048     generate_action =
1049         GenerateLabeledStatementBlocks({stmt->body}, labels, continue_label);
1050   }
1051 
1052   if (generate_action && stmt->action) {
1053     ScopedIndent indent(this);
1054     GenerateLabelBind(action_label);
1055     Visit(*stmt->action);
1056     GenerateLabelGoto(header_label);
1057   }
1058 
1059   GenerateLabelBind(exit_label);
1060   return TypeOracle::GetVoidType();
1061 }
1062 
GenerateImplementation(const std::string & dir,Module * module)1063 void ImplementationVisitor::GenerateImplementation(const std::string& dir,
1064                                                    Module* module) {
1065   std::string new_source(module->source());
1066   std::string base_file_name =
1067       "builtins-" + DashifyString(module->name()) + "-from-dsl-gen";
1068 
1069   std::string source_file_name = dir + "/" + base_file_name + ".cc";
1070   ReplaceFileContentsIfDifferent(source_file_name, new_source);
1071   std::string new_header(module->header());
1072   std::string header_file_name = dir + "/" + base_file_name + ".h";
1073   ReplaceFileContentsIfDifferent(header_file_name, new_header);
1074 }
1075 
GetBaseAssemblerName(Module * module)1076 std::string ImplementationVisitor::GetBaseAssemblerName(Module* module) {
1077   if (module == global_context_.GetDefaultModule()) {
1078     return "CodeStubAssembler";
1079   } else {
1080     std::string assembler_name(CamelifyString(module->name()) +
1081                                "BuiltinsAssembler");
1082     return assembler_name;
1083   }
1084 }
1085 
GetDSLAssemblerName(Module * module)1086 std::string ImplementationVisitor::GetDSLAssemblerName(Module* module) {
1087   std::string assembler_name(CamelifyString(module->name()) +
1088                              "BuiltinsFromDSLAssembler");
1089   return assembler_name;
1090 }
1091 
GenerateIndent()1092 void ImplementationVisitor::GenerateIndent() {
1093   for (size_t i = 0; i <= indent_; ++i) {
1094     source_out() << "  ";
1095   }
1096 }
1097 
GenerateMacroFunctionDeclaration(std::ostream & o,const std::string & macro_prefix,Macro * macro)1098 void ImplementationVisitor::GenerateMacroFunctionDeclaration(
1099     std::ostream& o, const std::string& macro_prefix, Macro* macro) {
1100   GenerateFunctionDeclaration(o, macro_prefix, macro->name(),
1101                               macro->signature(), macro->parameter_names());
1102 }
1103 
GenerateFunctionDeclaration(std::ostream & o,const std::string & macro_prefix,const std::string & name,const Signature & signature,const NameVector & parameter_names)1104 void ImplementationVisitor::GenerateFunctionDeclaration(
1105     std::ostream& o, const std::string& macro_prefix, const std::string& name,
1106     const Signature& signature, const NameVector& parameter_names) {
1107   if (global_context_.verbose()) {
1108     std::cout << "generating source for declaration " << name << "\n";
1109   }
1110 
1111   // Quite a hack here. Make sure that TNode is namespace qualified if the
1112   // macro/constant name is also qualified.
1113   std::string return_type_name(signature.return_type->GetGeneratedTypeName());
1114   if (const StructType* struct_type =
1115           StructType::DynamicCast(signature.return_type)) {
1116     o << GetDSLAssemblerName(struct_type->module()) << "::";
1117   } else if (macro_prefix != "" && (return_type_name.length() > 5) &&
1118              (return_type_name.substr(0, 5) == "TNode")) {
1119     o << "compiler::";
1120   }
1121   o << return_type_name;
1122   o << " " << macro_prefix << name << "(";
1123 
1124   DCHECK_EQ(signature.types().size(), parameter_names.size());
1125   auto type_iterator = signature.types().begin();
1126   bool first = true;
1127   for (const std::string& name : parameter_names) {
1128     if (!first) {
1129       o << ", ";
1130     }
1131     const Value* parameter = declarations()->LookupValue(name);
1132     const Type* parameter_type = *type_iterator;
1133     const std::string& generated_type_name =
1134         parameter_type->GetGeneratedTypeName();
1135     o << generated_type_name << " " << parameter->value();
1136     type_iterator++;
1137     first = false;
1138   }
1139 
1140   for (const LabelDeclaration& label_info : signature.labels) {
1141     Label* label = declarations()->LookupLabel(label_info.name);
1142     if (!first) {
1143       o << ", ";
1144     }
1145     o << "Label* " << label->generated();
1146     for (Variable* var : label->GetParameters()) {
1147       std::string generated_type_name("TVariable<");
1148       generated_type_name += var->type()->GetGeneratedTNodeTypeName();
1149       generated_type_name += ">*";
1150       o << ", ";
1151       o << generated_type_name << " " << var->value();
1152     }
1153   }
1154 
1155   o << ")";
1156 }
1157 
1158 namespace {
1159 
PrintMacroSignatures(std::stringstream & s,const std::string & name,const std::vector<Macro * > & macros)1160 void PrintMacroSignatures(std::stringstream& s, const std::string& name,
1161                           const std::vector<Macro*>& macros) {
1162   for (Macro* m : macros) {
1163     s << "\n  " << name;
1164     PrintSignature(s, m->signature(), false);
1165   }
1166 }
1167 
FailMacroLookup(const std::string & reason,const std::string & name,const Arguments & arguments,const std::vector<Macro * > & candidates)1168 void FailMacroLookup(const std::string& reason, const std::string& name,
1169                      const Arguments& arguments,
1170                      const std::vector<Macro*>& candidates) {
1171   std::stringstream stream;
1172   stream << "\n"
1173          << reason << ": \n  " << name << "("
1174          << arguments.parameters.GetTypeVector() << ")";
1175   if (arguments.labels.size() != 0) {
1176     stream << " labels ";
1177     for (auto l : arguments.labels) {
1178       PrintLabel(stream, *l, false);
1179     }
1180   }
1181   stream << "\ncandidates are:";
1182   PrintMacroSignatures(stream, name, candidates);
1183   ReportError(stream.str());
1184 }
1185 
1186 }  // namespace
1187 
LookupCall(const std::string & name,const Arguments & arguments,const TypeVector & specialization_types)1188 Callable* ImplementationVisitor::LookupCall(
1189     const std::string& name, const Arguments& arguments,
1190     const TypeVector& specialization_types) {
1191   Callable* result = nullptr;
1192   TypeVector parameter_types(arguments.parameters.GetTypeVector());
1193   bool has_template_arguments = !specialization_types.empty();
1194   std::string mangled_name = name;
1195   if (has_template_arguments) {
1196     mangled_name = GetGeneratedCallableName(name, specialization_types);
1197   }
1198   Declarable* declarable = declarations()->Lookup(mangled_name);
1199   if (declarable->IsBuiltin()) {
1200     result = Builtin::cast(declarable);
1201   } else if (declarable->IsRuntimeFunction()) {
1202     result = RuntimeFunction::cast(declarable);
1203   } else if (declarable->IsMacroList()) {
1204     std::vector<Macro*> candidates;
1205     std::vector<Macro*> macros_with_same_name;
1206     for (Macro* m : MacroList::cast(declarable)->list()) {
1207       bool try_bool_context =
1208           arguments.labels.size() == 0 &&
1209           m->signature().return_type == TypeOracle::GetNeverType();
1210       Label* true_label = nullptr;
1211       Label* false_label = nullptr;
1212       if (try_bool_context) {
1213         true_label = declarations()->TryLookupLabel(kTrueLabelName);
1214         false_label = declarations()->TryLookupLabel(kFalseLabelName);
1215       }
1216       if (IsCompatibleSignature(m->signature(), parameter_types,
1217                                 arguments.labels) ||
1218           (true_label && false_label &&
1219            IsCompatibleSignature(m->signature(), parameter_types,
1220                                  {true_label, false_label}))) {
1221         candidates.push_back(m);
1222       } else {
1223         macros_with_same_name.push_back(m);
1224       }
1225     }
1226 
1227     if (candidates.empty() && macros_with_same_name.empty()) {
1228       std::stringstream stream;
1229       stream << "no matching declaration found for " << name;
1230       ReportError(stream.str());
1231     } else if (candidates.empty()) {
1232       FailMacroLookup("cannot find macro with name", name, arguments,
1233                       macros_with_same_name);
1234     }
1235 
1236     auto is_better_candidate = [&](Macro* a, Macro* b) {
1237       return ParameterDifference(a->signature().parameter_types.types,
1238                                  parameter_types)
1239           .StrictlyBetterThan(ParameterDifference(
1240               b->signature().parameter_types.types, parameter_types));
1241     };
1242 
1243     Macro* best = *std::min_element(candidates.begin(), candidates.end(),
1244                                     is_better_candidate);
1245     for (Macro* candidate : candidates) {
1246       if (candidate != best && !is_better_candidate(best, candidate)) {
1247         FailMacroLookup("ambiguous macro", name, arguments, candidates);
1248       }
1249     }
1250     result = best;
1251   } else {
1252     std::stringstream stream;
1253     stream << "can't call " << declarable->type_name() << " " << name
1254            << " because it's not callable"
1255            << ": call parameters were (" << parameter_types << ")";
1256     ReportError(stream.str());
1257   }
1258 
1259   size_t caller_size = parameter_types.size();
1260   size_t callee_size = result->signature().types().size();
1261   if (caller_size != callee_size &&
1262       !result->signature().parameter_types.var_args) {
1263     std::stringstream stream;
1264     stream << "parameter count mismatch calling " << *result << " - expected "
1265            << std::to_string(callee_size) << ", found "
1266            << std::to_string(caller_size);
1267     ReportError(stream.str());
1268   }
1269 
1270   if (has_template_arguments) {
1271     Generic* generic = *result->generic();
1272     CallableNode* callable = generic->declaration()->callable;
1273     if (generic->declaration()->body) {
1274       QueueGenericSpecialization({generic, specialization_types}, callable,
1275                                  callable->signature.get(),
1276                                  generic->declaration()->body);
1277     }
1278   }
1279 
1280   return result;
1281 }
1282 
GetFlattenedStructsVars(const Variable * base,std::set<const Variable * > * vars)1283 void ImplementationVisitor::GetFlattenedStructsVars(
1284     const Variable* base, std::set<const Variable*>* vars) {
1285   const Type* type = base->type();
1286   if (base->IsConst()) return;
1287   if (type->IsStructType()) {
1288     const StructType* struct_type = StructType::cast(type);
1289     for (auto& field : struct_type->fields()) {
1290       std::string field_var_name = base->name() + "." + field.name;
1291       GetFlattenedStructsVars(
1292           Variable::cast(declarations()->LookupValue(field_var_name)), vars);
1293     }
1294   } else {
1295     vars->insert(base);
1296   }
1297 }
1298 
GenerateChangedVarsFromControlSplit(AstNode * node)1299 void ImplementationVisitor::GenerateChangedVarsFromControlSplit(AstNode* node) {
1300   const std::set<const Variable*>& changed_vars =
1301       global_context_.GetControlSplitChangedVariables(
1302           node, declarations()->GetCurrentSpecializationTypeNamesVector());
1303   std::set<const Variable*> flattened_vars;
1304   for (auto v : changed_vars) {
1305     GetFlattenedStructsVars(v, &flattened_vars);
1306   }
1307   std::vector<const Variable*> flattened_vars_sorted(flattened_vars.begin(),
1308                                                      flattened_vars.end());
1309   auto compare_variables = [](const Variable* a, const Variable* b) {
1310     return a->value() < b->value();
1311   };
1312   std::sort(flattened_vars_sorted.begin(), flattened_vars_sorted.end(),
1313             compare_variables);
1314   source_out() << "{";
1315   PrintCommaSeparatedList(source_out(), flattened_vars_sorted,
1316                           [](const Variable* v) { return v->value(); });
1317   source_out() << "}";
1318 }
1319 
GetCommonType(const Type * left,const Type * right)1320 const Type* ImplementationVisitor::GetCommonType(const Type* left,
1321                                                  const Type* right) {
1322   const Type* common_type;
1323   if (IsAssignableFrom(left, right)) {
1324     common_type = left;
1325   } else if (IsAssignableFrom(right, left)) {
1326     common_type = right;
1327   } else {
1328     common_type = TypeOracle::GetUnionType(left, right);
1329   }
1330   common_type = common_type->NonConstexprVersion();
1331   return common_type;
1332 }
1333 
GenerateCopy(const VisitResult & to_copy)1334 VisitResult ImplementationVisitor::GenerateCopy(const VisitResult& to_copy) {
1335   std::string temp = GenerateNewTempVariable(to_copy.type());
1336   source_out() << RValueFlattenStructs(to_copy) << ";\n";
1337   GenerateIndent();
1338   source_out() << "USE(" << temp << ");\n";
1339   return VisitResult(to_copy.type(), temp);
1340 }
1341 
Visit(StructExpression * decl)1342 VisitResult ImplementationVisitor::Visit(StructExpression* decl) {
1343   const Type* raw_type = declarations()->LookupType(decl->name);
1344   if (!raw_type->IsStructType()) {
1345     std::stringstream s;
1346     s << decl->name << " is not a struct but used like one ";
1347     ReportError(s.str());
1348   }
1349   const StructType* struct_type = StructType::cast(raw_type);
1350   if (struct_type->fields().size() != decl->expressions.size()) {
1351     std::stringstream s;
1352     s << "initializer count mismatch for struct " << decl->name << " (expected "
1353       << struct_type->fields().size() << ", found " << decl->expressions.size()
1354       << ")";
1355     ReportError(s.str());
1356   }
1357   std::vector<VisitResult> expression_results;
1358   for (auto& field : struct_type->fields()) {
1359     VisitResult value = Visit(decl->expressions[expression_results.size()]);
1360     value = GenerateImplicitConvert(field.type, value);
1361     expression_results.push_back(value);
1362   }
1363   std::string result_var_name = GenerateNewTempVariable(struct_type);
1364   source_out() << "{";
1365   PrintCommaSeparatedList(
1366       source_out(), expression_results,
1367       [&](const VisitResult& result) { return RValueFlattenStructs(result); });
1368   source_out() << "};\n";
1369   return VisitResult(struct_type, result_var_name);
1370 }
1371 
GetLocationReference(LocationExpression * location)1372 LocationReference ImplementationVisitor::GetLocationReference(
1373     LocationExpression* location) {
1374   switch (location->kind) {
1375     case AstNode::Kind::kIdentifierExpression:
1376       return GetLocationReference(static_cast<IdentifierExpression*>(location));
1377     case AstNode::Kind::kFieldAccessExpression:
1378       return GetLocationReference(
1379           static_cast<FieldAccessExpression*>(location));
1380     case AstNode::Kind::kElementAccessExpression:
1381       return GetLocationReference(
1382           static_cast<ElementAccessExpression*>(location));
1383     default:
1384       UNREACHABLE();
1385   }
1386 }
1387 
GetLocationReference(FieldAccessExpression * expr)1388 LocationReference ImplementationVisitor::GetLocationReference(
1389     FieldAccessExpression* expr) {
1390   VisitResult result = Visit(expr->object);
1391   if (result.type()->IsStructType()) {
1392     if (result.declarable()) {
1393       return LocationReference(
1394           declarations()->LookupValue((*result.declarable())->name() + "." +
1395                                       expr->field),
1396           {}, {});
1397     }
1398   }
1399   return LocationReference(nullptr, result, {});
1400 }
1401 
RValueFlattenStructs(VisitResult result)1402 std::string ImplementationVisitor::RValueFlattenStructs(VisitResult result) {
1403   if (result.declarable()) {
1404     const Value* value = *result.declarable();
1405     const Type* type = value->type();
1406     if (const StructType* struct_type = StructType::DynamicCast(type)) {
1407       std::stringstream s;
1408       s << struct_type->name() << "{";
1409       PrintCommaSeparatedList(
1410           s, struct_type->fields(), [&](const NameAndType& field) {
1411             std::string field_declaration = value->name() + "." + field.name;
1412             Variable* field_variable =
1413                 Variable::cast(declarations()->LookupValue(field_declaration));
1414             return RValueFlattenStructs(
1415                 VisitResult(field_variable->type(), field_variable));
1416           });
1417       s << "}";
1418       return s.str();
1419     }
1420   }
1421   return result.RValue();
1422 }
1423 
GenerateFetchFromLocation(LocationExpression * location,LocationReference reference)1424 VisitResult ImplementationVisitor::GenerateFetchFromLocation(
1425     LocationExpression* location, LocationReference reference) {
1426   switch (location->kind) {
1427     case AstNode::Kind::kIdentifierExpression:
1428       return GenerateFetchFromLocation(
1429           static_cast<IdentifierExpression*>(location), reference);
1430     case AstNode::Kind::kFieldAccessExpression:
1431       return GenerateFetchFromLocation(
1432           static_cast<FieldAccessExpression*>(location), reference);
1433     case AstNode::Kind::kElementAccessExpression:
1434       return GenerateFetchFromLocation(
1435           static_cast<ElementAccessExpression*>(location), reference);
1436     default:
1437       UNREACHABLE();
1438   }
1439 }
1440 
GenerateFetchFromLocation(FieldAccessExpression * expr,LocationReference reference)1441 VisitResult ImplementationVisitor::GenerateFetchFromLocation(
1442     FieldAccessExpression* expr, LocationReference reference) {
1443   if (reference.value != nullptr) {
1444     return GenerateFetchFromLocation(reference);
1445   }
1446   const Type* type = reference.base.type();
1447   if (const StructType* struct_type = StructType::DynamicCast(type)) {
1448     return VisitResult(struct_type->GetFieldType(expr->field),
1449                        reference.base.RValue() + "." + expr->field);
1450   } else {
1451     Arguments arguments;
1452     arguments.parameters = {reference.base};
1453     return GenerateCall(std::string(".") + expr->field, arguments);
1454   }
1455 }
1456 
GenerateAssignToVariable(Variable * var,VisitResult value)1457 void ImplementationVisitor::GenerateAssignToVariable(Variable* var,
1458                                                      VisitResult value) {
1459   if (var->type()->IsStructType()) {
1460     if (value.type() != var->type()) {
1461       std::stringstream s;
1462       s << "incompatable assignment from type " << *value.type() << " to "
1463         << *var->type();
1464       ReportError(s.str());
1465     }
1466     const StructType* struct_type = StructType::cast(var->type());
1467     for (auto& field : struct_type->fields()) {
1468       std::string field_declaration = var->name() + "." + field.name;
1469       Variable* field_variable =
1470           Variable::cast(declarations()->LookupValue(field_declaration));
1471       if (value.declarable() && (*value.declarable())->IsVariable()) {
1472         Variable* source_field = Variable::cast(declarations()->LookupValue(
1473             Variable::cast((*value.declarable()))->name() + "." + field.name));
1474         GenerateAssignToVariable(
1475             field_variable, VisitResult{source_field->type(), source_field});
1476       } else {
1477         GenerateAssignToVariable(
1478             field_variable, VisitResult{field_variable->type(),
1479                                         value.RValue() + "." + field.name});
1480       }
1481     }
1482   } else {
1483     VisitResult casted_value = GenerateImplicitConvert(var->type(), value);
1484     GenerateIndent();
1485     VisitResult var_value = {var->type(), var};
1486     source_out() << var_value.LValue() << " = "
1487                  << RValueFlattenStructs(casted_value) << ";\n";
1488   }
1489   var->Define();
1490 }
1491 
GenerateAssignToLocation(LocationExpression * location,const LocationReference & reference,VisitResult assignment_value)1492 void ImplementationVisitor::GenerateAssignToLocation(
1493     LocationExpression* location, const LocationReference& reference,
1494     VisitResult assignment_value) {
1495   if (reference.value != nullptr) {
1496     Value* value = reference.value;
1497     Variable* var = Variable::cast(value);
1498     if (var->IsConst()) {
1499       std::stringstream s;
1500       s << "\"" << var->name()
1501         << "\" is declared const (maybe implicitly) and cannot be assigned to";
1502       ReportError(s.str());
1503     }
1504     GenerateAssignToVariable(var, assignment_value);
1505   } else if (auto access = FieldAccessExpression::DynamicCast(location)) {
1506     GenerateCall(std::string(".") + access->field + "=",
1507                  {{reference.base, assignment_value}, {}});
1508   } else {
1509     DCHECK_NOT_NULL(ElementAccessExpression::cast(location));
1510     GenerateCall("[]=",
1511                  {{reference.base, reference.index, assignment_value}, {}});
1512   }
1513 }
1514 
GenerateVariableDeclaration(const Variable * var)1515 void ImplementationVisitor::GenerateVariableDeclaration(const Variable* var) {
1516   const Type* var_type = var->type();
1517   if (var_type->IsStructType()) {
1518     const StructType* struct_type = StructType::cast(var_type);
1519     for (auto& field : struct_type->fields()) {
1520       GenerateVariableDeclaration(Variable::cast(
1521           declarations()->LookupValue(var->name() + "." + field.name)));
1522     }
1523   } else {
1524     std::string value = var->value();
1525     GenerateIndent();
1526     if (var_type->IsConstexpr()) {
1527       source_out() << var_type->GetGeneratedTypeName();
1528       source_out() << " " << value << "_impl;\n";
1529     } else if (var->IsConst()) {
1530       source_out() << "TNode<" << var->type()->GetGeneratedTNodeTypeName();
1531       source_out() << "> " << var->value() << "_impl;\n";
1532     } else {
1533       source_out() << "TVARIABLE(";
1534       source_out() << var_type->GetGeneratedTNodeTypeName();
1535       source_out() << ", " << value << "_impl);\n";
1536     }
1537     GenerateIndent();
1538     source_out() << "auto " << value << " = &" << value << "_impl;\n";
1539     GenerateIndent();
1540     source_out() << "USE(" << value << ");\n";
1541   }
1542 }
1543 
GeneratePredeclaredVariableDeclaration(const std::string & name,const base::Optional<VisitResult> & initialization)1544 Variable* ImplementationVisitor::GeneratePredeclaredVariableDeclaration(
1545     const std::string& name,
1546     const base::Optional<VisitResult>& initialization) {
1547   Variable* variable = Variable::cast(declarations()->LookupValue(name));
1548   GenerateVariableDeclaration(variable);
1549   if (initialization) {
1550     GenerateAssignToVariable(variable, *initialization);
1551   }
1552   return variable;
1553 }
1554 
GenerateVariableDeclaration(AstNode * node,const std::string & name,bool is_const,const base::Optional<const Type * > & type,const base::Optional<VisitResult> & initialization)1555 Variable* ImplementationVisitor::GenerateVariableDeclaration(
1556     AstNode* node, const std::string& name, bool is_const,
1557     const base::Optional<const Type*>& type,
1558     const base::Optional<VisitResult>& initialization) {
1559   Variable* variable = nullptr;
1560   if (declarations()->IsDeclaredInCurrentScope(name)) {
1561     variable = Variable::cast(declarations()->LookupValue(name));
1562   } else {
1563     variable = declarations()->DeclareVariable(
1564         name, type ? *type : initialization->type(), is_const);
1565     if (!is_const) {
1566       // Because the variable is being defined during code generation, it must
1567       // be assumed that it changes along all control split paths because it's
1568       // no longer possible to run the control-flow anlaysis in the declaration
1569       // pass over the variable.
1570       global_context_.MarkVariableChanged(
1571           node, declarations()->GetCurrentSpecializationTypeNamesVector(),
1572           variable);
1573     }
1574   }
1575   GenerateVariableDeclaration(variable);
1576   if (initialization) {
1577     GenerateAssignToVariable(variable, *initialization);
1578   }
1579   return variable;
1580 }
1581 
GenerateParameter(const std::string & parameter_name)1582 void ImplementationVisitor::GenerateParameter(
1583     const std::string& parameter_name) {
1584   const Value* val = declarations()->LookupValue(parameter_name);
1585   std::string var = val->value();
1586   GenerateIndent();
1587   source_out() << val->type()->GetGeneratedTypeName() << " " << var << " = ";
1588 
1589   source_out() << "UncheckedCast<" << val->type()->GetGeneratedTNodeTypeName()
1590                << ">(Parameter(Descriptor::k" << CamelifyString(parameter_name)
1591                << "));\n";
1592   GenerateIndent();
1593   source_out() << "USE(" << var << ");\n";
1594 }
1595 
GenerateParameterList(const NameVector & list,size_t first)1596 void ImplementationVisitor::GenerateParameterList(const NameVector& list,
1597                                                   size_t first) {
1598   for (auto p : list) {
1599     if (first == 0) {
1600       GenerateParameter(p);
1601     } else {
1602       first--;
1603     }
1604   }
1605 }
1606 
GeneratePointerCall(Expression * callee,const Arguments & arguments,bool is_tailcall)1607 VisitResult ImplementationVisitor::GeneratePointerCall(
1608     Expression* callee, const Arguments& arguments, bool is_tailcall) {
1609   TypeVector parameter_types(arguments.parameters.GetTypeVector());
1610   VisitResult callee_result = Visit(callee);
1611   if (!callee_result.type()->IsFunctionPointerType()) {
1612     std::stringstream stream;
1613     stream << "Expected a function pointer type but found "
1614            << *callee_result.type();
1615     ReportError(stream.str());
1616   }
1617   const FunctionPointerType* type =
1618       FunctionPointerType::cast(callee_result.type());
1619 
1620   if (type->parameter_types().size() != parameter_types.size()) {
1621     std::stringstream stream;
1622     stream << "parameter count mismatch calling function pointer with Type: "
1623            << *type << " - expected "
1624            << std::to_string(type->parameter_types().size()) << ", found "
1625            << std::to_string(parameter_types.size());
1626     ReportError(stream.str());
1627   }
1628 
1629   ParameterTypes types{type->parameter_types(), false};
1630   Signature sig;
1631   sig.parameter_types = types;
1632   if (!IsCompatibleSignature(sig, parameter_types, {})) {
1633     std::stringstream stream;
1634     stream << "parameters do not match function pointer signature. Expected: ("
1635            << type->parameter_types() << ") but got: (" << parameter_types
1636            << ")";
1637     ReportError(stream.str());
1638   }
1639 
1640   std::vector<std::string> variables;
1641   for (size_t current = 0; current < arguments.parameters.size(); ++current) {
1642     const Type* to_type = type->parameter_types()[current];
1643     VisitResult result =
1644         GenerateImplicitConvert(to_type, arguments.parameters[current]);
1645     variables.push_back(RValueFlattenStructs(result));
1646   }
1647 
1648   std::string result_variable_name;
1649   bool no_result = type->return_type()->IsVoidOrNever() || is_tailcall;
1650   if (no_result) {
1651     GenerateIndent();
1652   } else {
1653     const Type* return_type = type->return_type();
1654     result_variable_name = GenerateNewTempVariable(return_type);
1655     if (return_type->IsStructType()) {
1656       source_out() << "(";
1657     } else {
1658       source_out() << "UncheckedCast<";
1659       source_out() << type->return_type()->GetGeneratedTNodeTypeName();
1660       source_out() << ">(";
1661     }
1662   }
1663 
1664   Builtin* example_builtin =
1665       declarations()->FindSomeInternalBuiltinWithType(type);
1666   if (!example_builtin) {
1667     std::stringstream stream;
1668     stream << "unable to find any builtin with type \"" << *type << "\"";
1669     ReportError(stream.str());
1670   }
1671 
1672   if (is_tailcall) {
1673     source_out() << "TailCallStub(";
1674   } else {
1675     source_out() << "CallStub(";
1676   }
1677   source_out() << "Builtins::CallableFor(isolate(), Builtins::k"
1678                << example_builtin->name() << ").descriptor(), "
1679                << RValueFlattenStructs(callee_result) << ", ";
1680 
1681   size_t total_parameters = 0;
1682   for (size_t i = 0; i < arguments.parameters.size(); ++i) {
1683     if (total_parameters++ != 0) {
1684       source_out() << ", ";
1685     }
1686     source_out() << variables[i];
1687   }
1688   if (!no_result) {
1689     source_out() << ")";
1690   }
1691   source_out() << ");\n";
1692   return VisitResult(type->return_type(), result_variable_name);
1693 }
1694 
GenerateCall(const std::string & callable_name,Arguments arguments,const TypeVector & specialization_types,bool is_tailcall)1695 VisitResult ImplementationVisitor::GenerateCall(
1696     const std::string& callable_name, Arguments arguments,
1697     const TypeVector& specialization_types, bool is_tailcall) {
1698   Callable* callable =
1699       LookupCall(callable_name, arguments, specialization_types);
1700 
1701   // Operators used in a branching context can also be function calls that never
1702   // return but have a True and False label
1703   if (arguments.labels.size() == 0 &&
1704       callable->signature().labels.size() == 2) {
1705     Label* true_label = declarations()->LookupLabel(kTrueLabelName);
1706     arguments.labels.push_back(true_label);
1707     Label* false_label = declarations()->LookupLabel(kFalseLabelName);
1708     arguments.labels.push_back(false_label);
1709   }
1710 
1711   const Type* result_type = callable->signature().return_type;
1712 
1713   std::vector<std::string> variables;
1714   for (size_t current = 0; current < arguments.parameters.size(); ++current) {
1715     const Type* to_type = (current >= callable->signature().types().size())
1716                               ? TypeOracle::GetObjectType()
1717                               : callable->signature().types()[current];
1718     VisitResult result =
1719         GenerateImplicitConvert(to_type, arguments.parameters[current]);
1720     variables.push_back(RValueFlattenStructs(result));
1721   }
1722 
1723   std::string result_variable_name;
1724   if (result_type->IsVoidOrNever() || is_tailcall) {
1725     GenerateIndent();
1726   } else {
1727     result_variable_name = GenerateNewTempVariable(result_type);
1728     if (!result_type->IsConstexpr()) {
1729       if (result_type->IsStructType()) {
1730         source_out() << "(";
1731       } else {
1732         source_out() << "UncheckedCast<";
1733         source_out() << result_type->GetGeneratedTNodeTypeName();
1734         source_out() << ">(";
1735       }
1736     }
1737   }
1738   if (callable->IsBuiltin()) {
1739     if (is_tailcall) {
1740       source_out() << "TailCallBuiltin(Builtins::k" << callable->name() << ", ";
1741     } else {
1742       source_out() << "CallBuiltin(Builtins::k" << callable->name() << ", ";
1743     }
1744   } else if (callable->IsMacro()) {
1745     if (is_tailcall) {
1746       std::stringstream stream;
1747       stream << "can't tail call a macro";
1748       ReportError(stream.str());
1749     }
1750     source_out() << callable->name() << "(";
1751   } else if (callable->IsRuntimeFunction()) {
1752     if (is_tailcall) {
1753       source_out() << "TailCallRuntime(Runtime::k" << callable->name() << ", ";
1754     } else {
1755       source_out() << "CallRuntime(Runtime::k" << callable->name() << ", ";
1756     }
1757   } else {
1758     UNREACHABLE();
1759   }
1760   if (global_context_.verbose()) {
1761     std::cout << "generating code for call to " << callable_name << "\n";
1762   }
1763 
1764   size_t total_parameters = 0;
1765   for (size_t i = 0; i < arguments.parameters.size(); ++i) {
1766     if (total_parameters++ != 0) {
1767       source_out() << ", ";
1768     }
1769     source_out() << variables[i];
1770   }
1771 
1772   size_t label_count = callable->signature().labels.size();
1773   if (label_count != arguments.labels.size()) {
1774     std::stringstream s;
1775     s << "unexpected number of otherwise labels for " << callable->name()
1776       << " (expected " << std::to_string(label_count) << " found "
1777       << std::to_string(arguments.labels.size()) << ")";
1778     ReportError(s.str());
1779   }
1780   for (size_t i = 0; i < label_count; ++i) {
1781     if (total_parameters++ != 0) {
1782       source_out() << ", ";
1783     }
1784     Label* label = arguments.labels[i];
1785     size_t callee_label_parameters =
1786         callable->signature().labels[i].types.size();
1787     if (label->GetParameterCount() != callee_label_parameters) {
1788       std::stringstream s;
1789       s << "label " << label->name()
1790         << " doesn't have the right number of parameters (found "
1791         << std::to_string(label->GetParameterCount()) << " expected "
1792         << std::to_string(callee_label_parameters) << ")";
1793       ReportError(s.str());
1794     }
1795     source_out() << label->generated();
1796     size_t j = 0;
1797     for (auto t : callable->signature().labels[i].types) {
1798       source_out() << ", ";
1799       Variable* variable = label->GetParameter(j);
1800       if (!(variable->type() == t)) {
1801         std::stringstream s;
1802         s << "mismatch of label parameters (expected " << *t << " got "
1803           << *label->GetParameter(j)->type() << " for parameter "
1804           << std::to_string(i + 1) << ")";
1805         ReportError(s.str());
1806       }
1807       j++;
1808       source_out() << variable->value();
1809     }
1810     label->MarkUsed();
1811   }
1812 
1813   if (global_context_.verbose()) {
1814     std::cout << "finished generating code for call to " << callable_name
1815               << "\n";
1816   }
1817   if (!result_type->IsVoidOrNever() && !is_tailcall &&
1818       !result_type->IsConstexpr()) {
1819     source_out() << ")";
1820   }
1821   source_out() << ");\n";
1822   return VisitResult(result_type, result_variable_name);
1823 }
1824 
Visit(StandardDeclaration * decl)1825 void ImplementationVisitor::Visit(StandardDeclaration* decl) {
1826   Signature signature = MakeSignature(decl->callable->signature.get());
1827   Visit(decl->callable, signature, decl->body);
1828 }
1829 
Visit(SpecializationDeclaration * decl)1830 void ImplementationVisitor::Visit(SpecializationDeclaration* decl) {
1831   Signature signature_with_types = MakeSignature(decl->signature.get());
1832   Declarations::NodeScopeActivator specialization_activator(declarations(),
1833                                                             decl);
1834   GenericList* generic_list = declarations()->LookupGeneric(decl->name);
1835   for (Generic* generic : generic_list->list()) {
1836     CallableNode* callable = generic->declaration()->callable;
1837     Signature generic_signature_with_types =
1838         MakeSignature(callable->signature.get());
1839     if (signature_with_types.HasSameTypesAs(generic_signature_with_types)) {
1840       TypeVector specialization_types = GetTypeVector(decl->generic_parameters);
1841       SpecializeGeneric({{generic, specialization_types},
1842                          callable,
1843                          decl->signature.get(),
1844                          decl->body,
1845                          decl->pos});
1846       return;
1847     }
1848   }
1849   // Because the DeclarationVisitor already performed the same lookup
1850   // as above to find aspecialization match and already threw if it didn't
1851   // find one, failure to find a match here should never happen.
1852   // TODO(danno): Remember the specialization found in the declaration visitor
1853   //              so that the lookup doesn't have to be repeated here.
1854   UNREACHABLE();
1855 }
1856 
Visit(CallExpression * expr,bool is_tailcall)1857 VisitResult ImplementationVisitor::Visit(CallExpression* expr,
1858                                          bool is_tailcall) {
1859   Arguments arguments;
1860   std::string name = expr->callee.name;
1861     TypeVector specialization_types =
1862         GetTypeVector(expr->callee.generic_arguments);
1863     bool has_template_arguments = !specialization_types.empty();
1864     for (Expression* arg : expr->arguments)
1865       arguments.parameters.push_back(Visit(arg));
1866     arguments.labels = LabelsFromIdentifiers(expr->labels);
1867     VisitResult result;
1868     if (!has_template_arguments &&
1869         declarations()->Lookup(expr->callee.name)->IsValue()) {
1870       result = GeneratePointerCall(&expr->callee, arguments, is_tailcall);
1871   } else {
1872     result = GenerateCall(name, arguments, specialization_types, is_tailcall);
1873   }
1874   if (!result.type()->IsVoidOrNever()) {
1875     GenerateIndent();
1876     source_out() << "USE(" << RValueFlattenStructs(result) << ");\n";
1877   }
1878   if (is_tailcall) {
1879     result = {TypeOracle::GetNeverType(), ""};
1880   }
1881   return result;
1882 }
1883 
GenerateLabeledStatementBlocks(const std::vector<Statement * > & blocks,const std::vector<Label * > & statement_labels,Label * merge_label)1884 bool ImplementationVisitor::GenerateLabeledStatementBlocks(
1885     const std::vector<Statement*>& blocks,
1886     const std::vector<Label*>& statement_labels, Label* merge_label) {
1887   bool live = false;
1888   auto label_iterator = statement_labels.begin();
1889   for (Statement* block : blocks) {
1890     GenerateIndent();
1891     source_out() << "if (" << (*label_iterator)->generated()
1892                  << "->is_used())\n";
1893     ScopedIndent indent(this);
1894 
1895     GenerateLabelBind(*label_iterator++);
1896     if (!Visit(block)->IsNever()) {
1897       GenerateLabelGoto(merge_label);
1898       live = true;
1899     }
1900   }
1901   return live;
1902 }
1903 
GenerateBranch(const VisitResult & condition,Label * true_label,Label * false_label)1904 void ImplementationVisitor::GenerateBranch(const VisitResult& condition,
1905                                            Label* true_label,
1906                                            Label* false_label) {
1907   GenerateIndent();
1908   source_out() << "Branch(" << RValueFlattenStructs(condition) << ", "
1909                << true_label->generated() << ", " << false_label->generated()
1910                << ");\n";
1911 }
1912 
GenerateExpressionBranch(Expression * expression,const std::vector<Label * > & statement_labels,const std::vector<Statement * > & statement_blocks,Label * merge_label)1913 bool ImplementationVisitor::GenerateExpressionBranch(
1914     Expression* expression, const std::vector<Label*>& statement_labels,
1915     const std::vector<Statement*>& statement_blocks, Label* merge_label) {
1916   // Activate a new scope to define True/False catch labels
1917   Declarations::NodeScopeActivator scope(declarations(), expression);
1918 
1919   VisitResult expression_result = Visit(expression);
1920   if (expression_result.type() == TypeOracle::GetBoolType()) {
1921     GenerateBranch(expression_result, statement_labels[0], statement_labels[1]);
1922   } else {
1923     if (expression_result.type() != TypeOracle::GetNeverType()) {
1924       std::stringstream s;
1925       s << "unexpected return type " << *expression_result.type()
1926         << " for branch expression";
1927       ReportError(s.str());
1928     }
1929   }
1930 
1931   return GenerateLabeledStatementBlocks(statement_blocks, statement_labels,
1932                                         merge_label);
1933 }
1934 
GenerateImplicitConvert(const Type * destination_type,VisitResult source)1935 VisitResult ImplementationVisitor::GenerateImplicitConvert(
1936     const Type* destination_type, VisitResult source) {
1937   if (destination_type == source.type()) {
1938     return source;
1939   }
1940 
1941   if (TypeOracle::IsImplicitlyConvertableFrom(destination_type,
1942                                               source.type())) {
1943     std::string name =
1944         GetGeneratedCallableName(kFromConstexprMacroName, {destination_type});
1945     return GenerateCall(name, {{source}, {}}, {}, false);
1946   } else if (IsAssignableFrom(destination_type, source.type())) {
1947     source.SetType(destination_type);
1948     return source;
1949   } else {
1950     std::stringstream s;
1951     s << "cannot use expression of type " << *source.type()
1952       << " as a value of type " << *destination_type;
1953     ReportError(s.str());
1954   }
1955 }
1956 
NewTempVariable()1957 std::string ImplementationVisitor::NewTempVariable() {
1958   std::string name("t");
1959   name += std::to_string(next_temp_++);
1960   return name;
1961 }
1962 
GenerateNewTempVariable(const Type * type)1963 std::string ImplementationVisitor::GenerateNewTempVariable(const Type* type) {
1964   std::string temp = NewTempVariable();
1965   GenerateIndent();
1966   source_out() << type->GetGeneratedTypeName() << " " << temp << " = ";
1967   return temp;
1968 }
1969 
GenerateLabelDefinition(Label * label,AstNode * node)1970 void ImplementationVisitor::GenerateLabelDefinition(Label* label,
1971                                                     AstNode* node) {
1972   std::string label_string = label->generated();
1973   std::string label_string_impl = label_string + "_impl";
1974   GenerateIndent();
1975   source_out() << "Label " + label_string_impl + "(this";
1976   if (node != nullptr) {
1977     source_out() << ", ";
1978     GenerateChangedVarsFromControlSplit(node);
1979   }
1980   source_out() << ");\n";
1981   GenerateIndent();
1982   source_out() << "Label* " + label_string + " = &" << label_string_impl
1983                << ";\n";
1984   GenerateIndent();
1985   source_out() << "USE(" << label_string << ");\n";
1986 }
1987 
GenerateLabelBind(Label * label)1988 void ImplementationVisitor::GenerateLabelBind(Label* label) {
1989   GenerateIndent();
1990   source_out() << "BIND(" << label->generated() << ");\n";
1991 }
1992 
GenerateLabelGoto(Label * label)1993 void ImplementationVisitor::GenerateLabelGoto(Label* label) {
1994   GenerateIndent();
1995   source_out() << "Goto(" << label->generated() << ");\n";
1996 }
1997 
LabelsFromIdentifiers(const std::vector<std::string> & names)1998 std::vector<Label*> ImplementationVisitor::LabelsFromIdentifiers(
1999     const std::vector<std::string>& names) {
2000   std::vector<Label*> result;
2001   for (auto name : names) {
2002     result.push_back(declarations()->LookupLabel(name));
2003   }
2004   return result;
2005 }
2006 
2007 }  // namespace torque
2008 }  // namespace internal
2009 }  // namespace v8
2010