LCOV - code coverage report
Current view: top level - src/torque - implementation-visitor.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 1118 1307 85.5 %
Date: 2019-01-20 Functions: 80 95 84.2 %

          Line data    Source code
       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/csa-generator.h"
       8             : #include "src/torque/declaration-visitor.h"
       9             : #include "src/torque/implementation-visitor.h"
      10             : #include "src/torque/parameter-difference.h"
      11             : 
      12             : namespace v8 {
      13             : namespace internal {
      14             : namespace torque {
      15             : 
      16        9692 : VisitResult ImplementationVisitor::Visit(Expression* expr) {
      17        9692 :   CurrentSourcePosition::Scope scope(expr->pos);
      18        9692 :   switch (expr->kind) {
      19             : #define ENUM_ITEM(name)        \
      20             :   case AstNode::Kind::k##name: \
      21             :     return Visit(name::cast(expr));
      22        9557 :     AST_EXPRESSION_NODE_KIND_LIST(ENUM_ITEM)
      23             : #undef ENUM_ITEM
      24             :     default:
      25           0 :       UNREACHABLE();
      26             :   }
      27             : }
      28             : 
      29        3672 : const Type* ImplementationVisitor::Visit(Statement* stmt) {
      30        3672 :   CurrentSourcePosition::Scope scope(stmt->pos);
      31             :   StackScope stack_scope(this);
      32             :   const Type* result;
      33        3672 :   switch (stmt->kind) {
      34             : #define ENUM_ITEM(name)               \
      35             :   case AstNode::Kind::k##name:        \
      36             :     result = Visit(name::cast(stmt)); \
      37             :     break;
      38        3672 :     AST_STATEMENT_NODE_KIND_LIST(ENUM_ITEM)
      39             : #undef ENUM_ITEM
      40             :     default:
      41           0 :       UNREACHABLE();
      42             :   }
      43             :   DCHECK_EQ(result == TypeOracle::GetNeverType(),
      44             :             assembler().CurrentBlockIsComplete());
      45        3672 :   return result;
      46             : }
      47             : 
      48          10 : void ImplementationVisitor::BeginNamespaceFile(Namespace* nspace) {
      49          10 :   std::ostream& source = nspace->source_stream();
      50          10 :   std::ostream& header = nspace->header_stream();
      51             : 
      52         150 :   for (const std::string& include_path : GlobalContext::CppIncludes()) {
      53         390 :     source << "#include " << StringLiteralQuote(include_path) << "\n";
      54             :   }
      55             : 
      56         120 :   for (Namespace* n : GlobalContext::Get().GetNamespaces()) {
      57         300 :     source << "#include \"torque-generated/builtins-" +
      58         100 :                   DashifyString(n->name()) + "-from-dsl-gen.h\"\n";
      59             :   }
      60          10 :   source << "\n";
      61             : 
      62          10 :   source << "namespace v8 {\n"
      63          10 :          << "namespace internal {\n"
      64          10 :          << "\n";
      65             : 
      66          10 :   std::string upper_name(nspace->name());
      67             :   transform(upper_name.begin(), upper_name.end(), upper_name.begin(),
      68          10 :             ::toupper);
      69             :   std::string headerDefine =
      70          30 :       std::string("V8_TORQUE_") + upper_name + "_FROM_DSL_BASE_H__";
      71          20 :   header << "#ifndef " << headerDefine << "\n";
      72          20 :   header << "#define " << headerDefine << "\n\n";
      73          10 :   header << "#include \"src/compiler/code-assembler.h\"\n";
      74          10 :   if (nspace != GlobalContext::GetDefaultNamespace()) {
      75           9 :     header << "#include \"src/code-stub-assembler.h\"\n";
      76             :   }
      77          10 :   header << "\n";
      78             : 
      79          10 :   header << "namespace v8 {\n"
      80          10 :          << "namespace internal {\n"
      81          10 :          << "\n";
      82             : 
      83          30 :   header << "class " << nspace->ExternalName() << " {\n";
      84          10 :   header << " public:\n";
      85          20 :   header << "  explicit " << nspace->ExternalName()
      86             :          << "(compiler::CodeAssemblerState* state) : state_(state), ca_(state) "
      87          10 :             "{ USE(state_, ca_); }\n";
      88          10 : }
      89             : 
      90          10 : void ImplementationVisitor::EndNamespaceFile(Namespace* nspace) {
      91          10 :   std::ostream& source = nspace->source_stream();
      92          10 :   std::ostream& header = nspace->header_stream();
      93             : 
      94          10 :   std::string upper_name(nspace->name());
      95             :   transform(upper_name.begin(), upper_name.end(), upper_name.begin(),
      96          10 :             ::toupper);
      97             :   std::string headerDefine =
      98          30 :       std::string("V8_TORQUE_") + upper_name + "_FROM_DSL_BASE_H__";
      99             : 
     100          10 :   source << "}  // namespace internal\n"
     101          10 :          << "}  // namespace v8\n"
     102          10 :          << "\n";
     103             : 
     104          10 :   header << " private:\n"
     105          10 :          << "  compiler::CodeAssemblerState* const state_;\n"
     106          10 :          << "  compiler::CodeAssembler ca_;"
     107          10 :          << "}; \n\n";
     108          10 :   header << "}  // namespace internal\n"
     109          10 :          << "}  // namespace v8\n"
     110          10 :          << "\n";
     111          20 :   header << "#endif  // " << headerDefine << "\n";
     112          10 : }
     113             : 
     114          80 : void ImplementationVisitor::Visit(NamespaceConstant* decl) {
     115         200 :   Signature signature{{}, base::nullopt, {{}, false}, 0, decl->type(), {}};
     116          40 :   const std::string& name = decl->name();
     117             : 
     118             :   BindingsManagersScope bindings_managers_scope;
     119             : 
     120          40 :   header_out() << "  ";
     121         120 :   GenerateFunctionDeclaration(header_out(), "", name, signature, {});
     122          40 :   header_out() << ";\n";
     123             : 
     124          40 :   GenerateFunctionDeclaration(source_out(),
     125         120 :                               CurrentNamespace()->ExternalName() + "::", name,
     126          80 :                               signature, {});
     127          40 :   source_out() << " {\n";
     128             : 
     129             :   DCHECK(!signature.return_type->IsVoidOrNever());
     130             : 
     131         120 :   assembler_ = CfgAssembler(Stack<const Type*>{});
     132             : 
     133          40 :   VisitResult expression_result = Visit(decl->body());
     134             :   VisitResult return_result =
     135          80 :       GenerateImplicitConvert(signature.return_type, expression_result);
     136             : 
     137          40 :   CSAGenerator csa_generator{assembler().Result(), source_out()};
     138         120 :   Stack<std::string> values = *csa_generator.EmitGraph(Stack<std::string>{});
     139             : 
     140             :   assembler_ = base::nullopt;
     141             : 
     142          40 :   source_out() << "return ";
     143          80 :   CSAGenerator::EmitCSAValue(return_result, values, source_out());
     144          40 :   source_out() << ";\n";
     145          80 :   source_out() << "}\n\n";
     146          40 : }
     147             : 
     148        3977 : void ImplementationVisitor::Visit(TypeAlias* alias) {
     149        3845 :   if (alias->IsRedeclaration()) return;
     150             :   const StructType* struct_type = StructType::DynamicCast(alias->type());
     151         132 :   if (!struct_type) return;
     152             :   const std::string& name = struct_type->name();
     153          20 :   header_out() << "  struct " << name << " {\n";
     154          45 :   for (auto& field : struct_type->fields()) {
     155          75 :     header_out() << "    " << field.name_and_type.type->GetGeneratedTypeName();
     156          50 :     header_out() << " " << field.name_and_type.name << ";\n";
     157             :   }
     158          10 :   header_out() << "\n    std::tuple<";
     159             :   bool first = true;
     160          62 :   for (const Type* type : LowerType(struct_type)) {
     161          32 :     if (!first) {
     162          22 :       header_out() << ", ";
     163             :     }
     164             :     first = false;
     165          96 :     header_out() << type->GetGeneratedTypeName();
     166             :   }
     167          10 :   header_out() << "> Flatten() const {\n"
     168          10 :                << "      return std::tuple_cat(";
     169             :   first = true;
     170          45 :   for (auto& field : struct_type->fields()) {
     171          25 :     if (!first) {
     172          15 :       header_out() << ", ";
     173             :     }
     174             :     first = false;
     175          50 :     if (field.name_and_type.type->IsStructType()) {
     176           8 :       header_out() << field.name_and_type.name << ".Flatten()";
     177             :     } else {
     178          42 :       header_out() << "std::make_tuple(" << field.name_and_type.name << ")";
     179             :     }
     180             :   }
     181          10 :   header_out() << ");\n";
     182          10 :   header_out() << "    }\n";
     183          10 :   header_out() << "  };\n";
     184             : }
     185             : 
     186         452 : VisitResult ImplementationVisitor::InlineMacro(
     187         452 :     Macro* macro, base::Optional<LocationReference> this_reference,
     188             :     const std::vector<VisitResult>& arguments,
     189         130 :     const std::vector<Block*> label_blocks) {
     190         452 :   CurrentScope::Scope current_scope(macro);
     191             :   BindingsManagersScope bindings_managers_scope;
     192             :   CurrentCallable::Scope current_callable(macro);
     193         452 :   CurrentReturnValue::Scope current_return_value;
     194        1230 :   const Signature& signature = macro->signature();
     195         452 :   const Type* return_type = macro->signature().return_type;
     196         452 :   bool can_return = return_type != TypeOracle::GetNeverType();
     197             : 
     198             :   BlockBindings<LocalValue> parameter_bindings(&ValueBindingsManager::Get());
     199             :   BlockBindings<LocalLabel> label_bindings(&LabelBindingsManager::Get());
     200             :   DCHECK_EQ(macro->signature().parameter_names.size(),
     201             :             arguments.size() + (this_reference ? 1 : 0));
     202             :   DCHECK_EQ(this_reference.has_value(), macro->IsMethod());
     203             : 
     204             :   {
     205             :     size_t i = 0;
     206             :     // Bind the this for methods. Methods that modify a struct-type "this" must
     207             :     // only be called if the this is in a variable, in which case the
     208             :     // LocalValue is non-const. Otherwise, the LocalValue used for the parameter
     209             :     // binding is const, and thus read-only, which will cause errors if
     210             :     // modified, e.g. when called by a struct method that sets the structs
     211             :     // fields. This prevents using temporary struct values for anything other
     212             :     // than read operations.
     213         452 :     if (this_reference) {
     214             :       DCHECK(macro->IsMethod());
     215          25 :       LocalValue this_value = LocalValue{!this_reference->IsVariableAccess(),
     216          50 :                                          this_reference->GetVisitResult()};
     217          75 :       parameter_bindings.Add(kThisParameterName, this_value);
     218             :       i++;
     219             :     }
     220             : 
     221        1904 :     for (auto arg : arguments) {
     222        1000 :       const std::string& name = macro->parameter_names()[i++];
     223        3000 :       parameter_bindings.Add(name, LocalValue{true, arg});
     224             :     }
     225             :   }
     226             : 
     227             :   DCHECK_EQ(label_blocks.size(), signature.labels.size());
     228        1164 :   for (size_t i = 0; i < signature.labels.size(); ++i) {
     229         582 :     const LabelDeclaration& label_info = signature.labels[i];
     230             :     label_bindings.Add(label_info.name,
     231         780 :                        LocalLabel{label_blocks[i], label_info.types});
     232             :   }
     233             : 
     234             :   Block* macro_end;
     235         452 :   base::Optional<Binding<LocalLabel>> macro_end_binding;
     236         452 :   if (can_return) {
     237             :     Stack<const Type*> stack = assembler().CurrentStack();
     238         432 :     std::vector<const Type*> lowered_return_types = LowerType(return_type);
     239         432 :     stack.PushMany(lowered_return_types);
     240         432 :     if (!return_type->IsConstexpr()) {
     241             :       SetReturnValue(VisitResult(return_type,
     242         840 :                                  stack.TopRange(lowered_return_types.size())));
     243             :     }
     244         864 :     macro_end = assembler().NewBlock(std::move(stack));
     245             :     macro_end_binding.emplace(&LabelBindingsManager::Get(), "_macro_end",
     246        1728 :                               LocalLabel{macro_end, {return_type}});
     247             :   } else {
     248          40 :     SetReturnValue(VisitResult::NeverResult());
     249             :   }
     250             : 
     251         904 :   const Type* result = Visit(*macro->body());
     252             : 
     253         452 :   if (result->IsNever()) {
     254         672 :     if (!return_type->IsNever() && !macro->HasReturns()) {
     255           0 :       std::stringstream s;
     256           0 :       s << "macro " << macro->ReadableName()
     257           0 :         << " that never returns must have return type never";
     258           0 :       ReportError(s.str());
     259             :     }
     260             :   } else {
     261         106 :     if (return_type->IsNever()) {
     262           0 :       std::stringstream s;
     263           0 :       s << "macro " << macro->ReadableName()
     264             :         << " has implicit return at end of its declartion but return type "
     265           0 :            "never";
     266           0 :       ReportError(s.str());
     267         106 :     } else if (!macro->signature().return_type->IsVoid()) {
     268           0 :       std::stringstream s;
     269           0 :       s << "macro " << macro->ReadableName()
     270           0 :         << " expects to return a value but doesn't on all paths";
     271           0 :       ReportError(s.str());
     272             :     }
     273             :   }
     274         452 :   if (!result->IsNever()) {
     275         106 :     assembler().Goto(macro_end);
     276             :   }
     277             : 
     278         904 :   if (macro->HasReturns() || !result->IsNever()) {
     279         432 :     assembler().Bind(macro_end);
     280             :   }
     281             : 
     282         452 :   return GetAndClearReturnValue();
     283             : }
     284             : 
     285         434 : void ImplementationVisitor::VisitMacroCommon(Macro* macro) {
     286             :   CurrentCallable::Scope current_callable(macro);
     287             :   const Signature& signature = macro->signature();
     288         434 :   const Type* return_type = macro->signature().return_type;
     289         434 :   bool can_return = return_type != TypeOracle::GetNeverType();
     290             :   bool has_return_value =
     291         434 :       can_return && return_type != TypeOracle::GetVoidType();
     292             : 
     293             :   // Struct methods should never generate code, they should always be inlined
     294             :   DCHECK(!macro->IsMethod() ||
     295             :          Method::cast(macro)->aggregate_type()->IsClassType());
     296             : 
     297         434 :   header_out() << "  ";
     298        1302 :   GenerateMacroFunctionDeclaration(header_out(), "", macro);
     299         434 :   header_out() << ";\n";
     300             : 
     301             :   GenerateMacroFunctionDeclaration(
     302        1736 :       source_out(), CurrentNamespace()->ExternalName() + "::", macro);
     303         434 :   source_out() << " {\n";
     304             : 
     305             :   Stack<std::string> lowered_parameters;
     306             :   Stack<const Type*> lowered_parameter_types;
     307             : 
     308         434 :   std::vector<VisitResult> arguments;
     309             : 
     310             :   size_t i = 0;
     311         434 :   base::Optional<LocationReference> this_reference;
     312         434 :   if (Method* method = Method::DynamicCast(macro)) {
     313             :     const Type* this_type = method->aggregate_type();
     314             :     DCHECK(this_type->IsClassType());
     315             :     lowered_parameter_types.Push(this_type);
     316          24 :     lowered_parameters.Push(ExternalParameterName(kThisParameterName));
     317             :     VisitResult this_result =
     318             :         VisitResult(this_type, lowered_parameters.TopRange(1));
     319             :     // Mark the this as a temporary to prevent assignment to it.
     320          32 :     this_reference =
     321             :         LocationReference::Temporary(this_result, "this parameter");
     322             :     ++i;
     323             :   }
     324             : 
     325        2342 :   for (; i < macro->signature().parameter_names.size(); ++i) {
     326             :     const std::string& name = macro->parameter_names()[i];
     327         954 :     std::string external_name = ExternalParameterName(name);
     328        1908 :     const Type* type = macro->signature().types()[i];
     329             : 
     330         954 :     if (type->IsConstexpr()) {
     331          63 :       arguments.push_back(VisitResult(type, external_name));
     332             :     } else {
     333         891 :       LowerParameter(type, external_name, &lowered_parameters);
     334        1782 :       StackRange range = lowered_parameter_types.PushMany(LowerType(type));
     335         891 :       arguments.push_back(VisitResult(type, range));
     336             :     }
     337             :   }
     338             : 
     339             :   DCHECK_EQ(lowered_parameters.Size(), lowered_parameter_types.Size());
     340        1302 :   assembler_ = CfgAssembler(lowered_parameter_types);
     341             : 
     342             :   std::vector<Block*> label_blocks;
     343         997 :   for (const LabelDeclaration& label_info : signature.labels) {
     344             :     Stack<const Type*> label_input_stack;
     345         270 :     for (const Type* type : label_info.types) {
     346          24 :       label_input_stack.PushMany(LowerType(type));
     347             :     }
     348         258 :     Block* block = assembler().NewBlock(std::move(label_input_stack));
     349         129 :     label_blocks.push_back(block);
     350             :   }
     351             : 
     352             :   VisitResult return_value =
     353        1736 :       InlineMacro(macro, this_reference, arguments, label_blocks);
     354         868 :   Block* end = assembler().NewBlock();
     355         434 :   if (return_type != TypeOracle::GetNeverType()) {
     356         415 :     assembler().Goto(end);
     357             :   }
     358             : 
     359         692 :   for (size_t i = 0; i < label_blocks.size(); ++i) {
     360         129 :     Block* label_block = label_blocks[i];
     361         129 :     const LabelDeclaration& label_info = signature.labels[i];
     362         129 :     assembler().Bind(label_block);
     363             :     std::vector<std::string> label_parameter_variables;
     364         282 :     for (size_t i = 0; i < label_info.types.size(); ++i) {
     365             :       label_parameter_variables.push_back(
     366          24 :           ExternalLabelParameterName(label_info.name, i));
     367             :     }
     368             :     assembler().Emit(GotoExternalInstruction{ExternalLabelName(label_info.name),
     369         516 :                                              label_parameter_variables});
     370         129 :   }
     371             : 
     372         434 :   if (return_type != TypeOracle::GetNeverType()) {
     373         415 :     assembler().Bind(end);
     374             :   }
     375             : 
     376         434 :   CSAGenerator csa_generator{assembler().Result(), source_out()};
     377             :   base::Optional<Stack<std::string>> values =
     378         868 :       csa_generator.EmitGraph(lowered_parameters);
     379             : 
     380             :   assembler_ = base::nullopt;
     381             : 
     382         434 :   if (has_return_value) {
     383         310 :     source_out() << "  return ";
     384         620 :     CSAGenerator::EmitCSAValue(return_value, *values, source_out());
     385         310 :     source_out() << ";\n";
     386             :   }
     387         434 :   source_out() << "}\n\n";
     388         434 : }
     389             : 
     390         783 : void ImplementationVisitor::Visit(Macro* macro) {
     391         783 :   if (macro->IsExternal()) return;
     392             :   // Do not generate code for inlined macros.
     393         427 :   if (macro->ShouldBeInlined()) return;
     394         426 :   VisitMacroCommon(macro);
     395             : }
     396             : 
     397          20 : void ImplementationVisitor::Visit(Method* method) {
     398             :   DCHECK(!method->IsExternal());
     399             :   // Do not generate code for inlined methods, they have to be inlined in order
     400             :   // to get reference semantics for the 'this' argument.
     401          32 :   if (method->ShouldBeInlined()) return;
     402             :   CurrentConstructorInfo::Scope current_constructor;
     403           8 :   if (method->IsConstructor())
     404             :     CurrentConstructorInfo::Get() = ConstructorInfo{0, false};
     405           8 :   VisitMacroCommon(method);
     406             : }
     407             : 
     408             : namespace {
     409             : 
     410         404 : std::string AddParameter(size_t i, Builtin* builtin,
     411             :                          Stack<std::string>* parameters,
     412             :                          Stack<const Type*>* parameter_types,
     413             :                          BlockBindings<LocalValue>* parameter_bindings) {
     414         404 :   const std::string& name = builtin->signature().parameter_names[i];
     415         808 :   const Type* type = builtin->signature().types()[i];
     416         404 :   std::string external_name = "parameter" + std::to_string(i);
     417         808 :   parameters->Push(external_name);
     418         808 :   StackRange range = parameter_types->PushMany(LowerType(type));
     419        1616 :   parameter_bindings->Add(name, LocalValue{true, VisitResult(type, range)});
     420         404 :   return external_name;
     421             : }
     422             : 
     423             : }  // namespace
     424             : 
     425         134 : void ImplementationVisitor::Visit(Builtin* builtin) {
     426         522 :   if (builtin->IsExternal()) return;
     427         120 :   CurrentScope::Scope current_scope(builtin);
     428         120 :   const std::string& name = builtin->ExternalName();
     429             :   const Signature& signature = builtin->signature();
     430         240 :   source_out() << "TF_BUILTIN(" << name << ", CodeStubAssembler) {\n"
     431         120 :                << "  compiler::CodeAssemblerState* state_ = state();"
     432         120 :                << "  compiler::CodeAssembler ca_(state());\n";
     433             : 
     434             :   CurrentCallable::Scope current_callable(builtin);
     435         120 :   CurrentReturnValue::Scope current_return_value;
     436             : 
     437             :   Stack<const Type*> parameter_types;
     438             :   Stack<std::string> parameters;
     439             : 
     440             :   BindingsManagersScope bindings_managers_scope;
     441             : 
     442             :   BlockBindings<LocalValue> parameter_bindings(&ValueBindingsManager::Get());
     443             : 
     444             :   // Context
     445             :   std::string parameter0 = AddParameter(0, builtin, &parameters,
     446         120 :                                         &parameter_types, &parameter_bindings);
     447         120 :   source_out() << "  TNode<Context> " << parameter0
     448         120 :                << " = UncheckedCast<Context>(Parameter("
     449         120 :                << "Descriptor::kContext));\n";
     450         240 :   source_out() << "  USE(" << parameter0 << ");\n";
     451             : 
     452             :   size_t first = 1;
     453         240 :   if (builtin->IsVarArgsJavaScript()) {
     454             :     DCHECK(signature.parameter_types.var_args);
     455          43 :     source_out()
     456          43 :         << "  Node* argc = Parameter(Descriptor::kJSActualArgumentsCount);\n";
     457          43 :     source_out() << "  CodeStubArguments arguments_impl(this, "
     458          43 :                     "ChangeInt32ToIntPtr(argc));\n";
     459             :     std::string parameter1 = AddParameter(
     460          43 :         1, builtin, &parameters, &parameter_types, &parameter_bindings);
     461             : 
     462          43 :     source_out() << "  TNode<Object> " << parameter1
     463          43 :                  << " = arguments_impl.GetReceiver();\n";
     464          43 :     source_out() << "auto " << CSAGenerator::ARGUMENTS_VARIABLE_STRING
     465          43 :                  << " = &arguments_impl;\n";
     466          43 :     source_out() << "USE(arguments);\n";
     467          86 :     source_out() << "USE(" << parameter1 << ");\n";
     468             :     parameter_bindings.Add(
     469          43 :         *signature.arguments_variable,
     470             :         LocalValue{true,
     471         215 :                    VisitResult(TypeOracle::GetArgumentsType(), "arguments")});
     472             :     first = 2;
     473             :   }
     474             : 
     475        1048 :   for (size_t i = 0; i < signature.parameter_names.size(); ++i) {
     476         567 :     if (i < first) continue;
     477         524 :     const std::string& parameter_name = signature.parameter_names[i];
     478         482 :     const Type* type = signature.types()[i];
     479             :     std::string var = AddParameter(i, builtin, &parameters, &parameter_types,
     480         241 :                                    &parameter_bindings);
     481        1205 :     source_out() << "  " << type->GetGeneratedTypeName() << " " << var << " = "
     482         723 :                  << "UncheckedCast<" << type->GetGeneratedTNodeTypeName()
     483         241 :                  << ">(Parameter(Descriptor::k"
     484         723 :                  << CamelifyString(parameter_name) << "));\n";
     485         482 :     source_out() << "  USE(" << var << ");\n";
     486             :   }
     487             : 
     488         360 :   assembler_ = CfgAssembler(parameter_types);
     489         240 :   const Type* body_result = Visit(*builtin->body());
     490         120 :   if (body_result != TypeOracle::GetNeverType()) {
     491           0 :     ReportError("control reaches end of builtin, expected return of a value");
     492             :   }
     493         120 :   CSAGenerator csa_generator{assembler().Result(), source_out(),
     494         120 :                              builtin->kind()};
     495         360 :   csa_generator.EmitGraph(parameters);
     496             :   assembler_ = base::nullopt;
     497         120 :   source_out() << "}\n\n";
     498             : }
     499             : 
     500           0 : const Type* ImplementationVisitor::Visit(VarDeclarationStatement* stmt) {
     501             :   BlockBindings<LocalValue> block_bindings(&ValueBindingsManager::Get());
     502           0 :   return Visit(stmt, &block_bindings);
     503             : }
     504             : 
     505         918 : const Type* ImplementationVisitor::Visit(
     506             :     VarDeclarationStatement* stmt, BlockBindings<LocalValue>* block_bindings) {
     507        1836 :   if (!stmt->const_qualified && !stmt->type) {
     508             :     ReportError(
     509             :         "variable declaration is missing type. Only 'const' bindings can "
     510           0 :         "infer the type.");
     511             :   }
     512             :   // const qualified variables are required to be initialized properly.
     513        1836 :   if (stmt->const_qualified && !stmt->initializer) {
     514           0 :     ReportError("local constant \"", stmt->name, "\" is not initialized.");
     515             :   }
     516             : 
     517             :   base::Optional<const Type*> type;
     518         918 :   if (stmt->type) {
     519         901 :     type = Declarations::GetType(*stmt->type);
     520         901 :     if ((*type)->IsConstexpr() && !stmt->const_qualified) {
     521             :       ReportError(
     522           0 :           "cannot declare variable with constexpr type. Use 'const' instead.");
     523             :     }
     524             :   }
     525         918 :   base::Optional<VisitResult> init_result;
     526         918 :   if (stmt->initializer) {
     527             :     StackScope scope(this);
     528        1790 :     init_result = Visit(*stmt->initializer);
     529         895 :     if (type) {
     530        2634 :       init_result = GenerateImplicitConvert(*type, *init_result);
     531             :     }
     532        2685 :     init_result = scope.Yield(*init_result);
     533             :   } else {
     534             :     DCHECK(type.has_value());
     535          23 :     if ((*type)->IsConstexpr()) {
     536           0 :       ReportError("constexpr variables need an initializer");
     537             :     }
     538          23 :     TypeVector lowered_types = LowerType(*type);
     539          72 :     for (const Type* type : lowered_types) {
     540          26 :       assembler().Emit(PushUninitializedInstruction{TypeOracle::GetTopType(
     541         156 :           "unitialized variable '" + stmt->name + "' of type " +
     542         130 :               type->ToString() + " originally defined at " +
     543             :               PositionAsString(stmt->pos),
     544         130 :           type)});
     545             :     }
     546          46 :     init_result =
     547             :         VisitResult(*type, assembler().TopRange(lowered_types.size()));
     548             :   }
     549             :   block_bindings->Add(stmt->name,
     550        2754 :                       LocalValue{stmt->const_qualified, *init_result});
     551        1836 :   return TypeOracle::GetVoidType();
     552             : }
     553             : 
     554           1 : const Type* ImplementationVisitor::Visit(TailCallStatement* stmt) {
     555           2 :   return Visit(stmt->call, true).type();
     556             : }
     557             : 
     558         172 : VisitResult ImplementationVisitor::Visit(ConditionalExpression* expr) {
     559         172 :   Block* true_block = assembler().NewBlock(assembler().CurrentStack());
     560         172 :   Block* false_block = assembler().NewBlock(assembler().CurrentStack());
     561         172 :   Block* done_block = assembler().NewBlock();
     562         172 :   Block* true_conversion_block = assembler().NewBlock();
     563          86 :   GenerateExpressionBranch(expr->condition, true_block, false_block);
     564             : 
     565          86 :   VisitResult left;
     566          86 :   VisitResult right;
     567             : 
     568             :   {
     569             :     // The code for both paths of the conditional need to be generated first
     570             :     // before evaluating the conditional expression because the common type of
     571             :     // the result of both the true and false of the condition needs to be known
     572             :     // to convert both branches to a common type.
     573          86 :     assembler().Bind(true_block);
     574             :     StackScope left_scope(this);
     575         172 :     left = Visit(expr->if_true);
     576          86 :     assembler().Goto(true_conversion_block);
     577             : 
     578             :     const Type* common_type;
     579             :     {
     580          86 :       assembler().Bind(false_block);
     581             :       StackScope right_scope(this);
     582         172 :       right = Visit(expr->if_false);
     583         172 :       common_type = GetCommonType(left.type(), right.type());
     584         344 :       right = right_scope.Yield(GenerateImplicitConvert(common_type, right));
     585          86 :       assembler().Goto(done_block);
     586             :     }
     587             : 
     588          86 :     assembler().Bind(true_conversion_block);
     589         344 :     left = left_scope.Yield(GenerateImplicitConvert(common_type, left));
     590          86 :     assembler().Goto(done_block);
     591             :   }
     592             : 
     593          86 :   assembler().Bind(done_block);
     594          86 :   CHECK_EQ(left, right);
     595          86 :   return left;
     596             : }
     597             : 
     598          21 : VisitResult ImplementationVisitor::Visit(LogicalOrExpression* expr) {
     599          21 :   VisitResult left_result;
     600             :   {
     601          42 :     Block* false_block = assembler().NewBlock(assembler().CurrentStack());
     602             :     Binding<LocalLabel> false_binding{&LabelBindingsManager::Get(),
     603          84 :                                       kFalseLabelName, LocalLabel{false_block}};
     604          42 :     left_result = Visit(expr->left);
     605          21 :     if (left_result.type()->IsBool()) {
     606          14 :       Block* true_block = LookupSimpleLabel(kTrueLabelName);
     607           7 :       assembler().Branch(true_block, false_block);
     608           7 :       assembler().Bind(false_block);
     609          14 :     } else if (left_result.type()->IsNever()) {
     610           7 :       assembler().Bind(false_block);
     611           7 :     } else if (!left_result.type()->IsConstexprBool()) {
     612             :       ReportError(
     613             :           "expected type bool, constexpr bool, or never on left-hand side of "
     614           0 :           "operator ||");
     615          21 :     }
     616             :   }
     617             : 
     618          21 :   if (left_result.type()->IsConstexprBool()) {
     619           7 :     VisitResult right_result = Visit(expr->right);
     620           7 :     if (!right_result.type()->IsConstexprBool()) {
     621             :       ReportError(
     622             :           "expected type constexpr bool on right-hand side of operator "
     623           0 :           "||");
     624             :     }
     625             :     return VisitResult(TypeOracle::GetConstexprBoolType(),
     626          28 :                        std::string("(") + left_result.constexpr_value() +
     627          21 :                            " || " + right_result.constexpr_value() + ")");
     628             :   }
     629             : 
     630          14 :   VisitResult right_result = Visit(expr->right);
     631          14 :   if (right_result.type()->IsBool()) {
     632          18 :     Block* true_block = LookupSimpleLabel(kTrueLabelName);
     633          18 :     Block* false_block = LookupSimpleLabel(kFalseLabelName);
     634           9 :     assembler().Branch(true_block, false_block);
     635           9 :     return VisitResult::NeverResult();
     636           5 :   } else if (!right_result.type()->IsNever()) {
     637             :     ReportError(
     638           0 :         "expected type bool or never on right-hand side of operator ||");
     639             :   }
     640           5 :   return right_result;
     641             : }
     642             : 
     643          24 : VisitResult ImplementationVisitor::Visit(LogicalAndExpression* expr) {
     644          24 :   VisitResult left_result;
     645             :   {
     646          48 :     Block* true_block = assembler().NewBlock(assembler().CurrentStack());
     647             :     Binding<LocalLabel> false_binding{&LabelBindingsManager::Get(),
     648          96 :                                       kTrueLabelName, LocalLabel{true_block}};
     649          48 :     left_result = Visit(expr->left);
     650          24 :     if (left_result.type()->IsBool()) {
     651          36 :       Block* false_block = LookupSimpleLabel(kFalseLabelName);
     652          18 :       assembler().Branch(true_block, false_block);
     653          18 :       assembler().Bind(true_block);
     654           6 :     } else if (left_result.type()->IsNever()) {
     655           6 :       assembler().Bind(true_block);
     656           0 :     } else if (!left_result.type()->IsConstexprBool()) {
     657             :       ReportError(
     658             :           "expected type bool, constexpr bool, or never on left-hand side of "
     659           0 :           "operator &&");
     660          24 :     }
     661             :   }
     662             : 
     663          24 :   if (left_result.type()->IsConstexprBool()) {
     664           0 :     VisitResult right_result = Visit(expr->right);
     665           0 :     if (!right_result.type()->IsConstexprBool()) {
     666             :       ReportError(
     667             :           "expected type constexpr bool on right-hand side of operator "
     668           0 :           "&&");
     669             :     }
     670             :     return VisitResult(TypeOracle::GetConstexprBoolType(),
     671           0 :                        std::string("(") + left_result.constexpr_value() +
     672           0 :                            " && " + right_result.constexpr_value() + ")");
     673             :   }
     674             : 
     675          24 :   VisitResult right_result = Visit(expr->right);
     676          24 :   if (right_result.type()->IsBool()) {
     677          38 :     Block* true_block = LookupSimpleLabel(kTrueLabelName);
     678          38 :     Block* false_block = LookupSimpleLabel(kFalseLabelName);
     679          19 :     assembler().Branch(true_block, false_block);
     680          19 :     return VisitResult::NeverResult();
     681           5 :   } else if (!right_result.type()->IsNever()) {
     682             :     ReportError(
     683           0 :         "expected type bool or never on right-hand side of operator &&");
     684             :   }
     685           5 :   return right_result;
     686             : }
     687             : 
     688         118 : VisitResult ImplementationVisitor::Visit(IncrementDecrementExpression* expr) {
     689             :   StackScope scope(this);
     690         236 :   LocationReference location_ref = GetLocationReference(expr->location);
     691         118 :   VisitResult current_value = GenerateFetchFromLocation(location_ref);
     692         236 :   VisitResult one = {TypeOracle::GetConstInt31Type(), "1"};
     693         118 :   Arguments args;
     694         354 :   args.parameters = {current_value, one};
     695             :   VisitResult assignment_value = GenerateCall(
     696         354 :       expr->op == IncrementDecrementOperator::kIncrement ? "+" : "-", args);
     697         118 :   GenerateAssignToLocation(location_ref, assignment_value);
     698         354 :   return scope.Yield(expr->postfix ? current_value : assignment_value);
     699             : }
     700             : 
     701         388 : VisitResult ImplementationVisitor::Visit(AssignmentExpression* expr) {
     702             :   StackScope scope(this);
     703         776 :   LocationReference location_ref = GetLocationReference(expr->location);
     704         388 :   VisitResult assignment_value;
     705         388 :   if (expr->op) {
     706          11 :     VisitResult location_value = GenerateFetchFromLocation(location_ref);
     707          22 :     assignment_value = Visit(expr->value);
     708          11 :     Arguments args;
     709          33 :     args.parameters = {location_value, assignment_value};
     710          44 :     assignment_value = GenerateCall(*expr->op, args);
     711          11 :     GenerateAssignToLocation(location_ref, assignment_value);
     712             :   } else {
     713         754 :     assignment_value = Visit(expr->value);
     714         377 :     GenerateAssignToLocation(location_ref, assignment_value);
     715             :   }
     716        1164 :   return scope.Yield(assignment_value);
     717             : }
     718             : 
     719         747 : VisitResult ImplementationVisitor::Visit(NumberLiteralExpression* expr) {
     720             :   // TODO(tebbi): Do not silently loose precision; support 64bit literals.
     721        1494 :   double d = std::stod(expr->number.c_str());
     722         747 :   int32_t i = static_cast<int32_t>(d);
     723        1494 :   const Type* result_type = Declarations::LookupType(CONST_FLOAT64_TYPE_STRING);
     724         747 :   if (i == d) {
     725         746 :     if ((i >> 30) == (i >> 31)) {
     726        1488 :       result_type = Declarations::LookupType(CONST_INT31_TYPE_STRING);
     727             :     } else {
     728           4 :       result_type = Declarations::LookupType(CONST_INT32_TYPE_STRING);
     729             :     }
     730             :   }
     731        1494 :   return VisitResult{result_type, expr->number};
     732             : }
     733             : 
     734          58 : VisitResult ImplementationVisitor::Visit(AssumeTypeImpossibleExpression* expr) {
     735          29 :   VisitResult result = Visit(expr->expression);
     736             :   const Type* result_type =
     737          58 :       SubtractType(result.type(), Declarations::GetType(expr->excluded_type));
     738          29 :   if (result_type->IsNever()) {
     739           0 :     ReportError("unreachable code");
     740             :   }
     741         116 :   CHECK_EQ(LowerType(result_type), TypeVector{result_type});
     742          58 :   assembler().Emit(UnsafeCastInstruction{result_type});
     743             :   result.SetType(result_type);
     744          29 :   return result;
     745             : }
     746             : 
     747          38 : VisitResult ImplementationVisitor::Visit(StringLiteralExpression* expr) {
     748             :   return VisitResult{
     749             :       TypeOracle::GetConstStringType(),
     750         190 :       "\"" + expr->literal.substr(1, expr->literal.size() - 2) + "\""};
     751             : }
     752             : 
     753         126 : VisitResult ImplementationVisitor::GetBuiltinCode(Builtin* builtin) {
     754         126 :   if (builtin->IsExternal() || builtin->kind() != Builtin::kStub) {
     755             :     ReportError(
     756             :         "creating function pointers is only allowed for internal builtins with "
     757           0 :         "stub linkage");
     758             :   }
     759             :   const Type* type = TypeOracle::GetBuiltinPointerType(
     760             :       builtin->signature().parameter_types.types,
     761         126 :       builtin->signature().return_type);
     762          63 :   assembler().Emit(
     763         378 :       PushBuiltinPointerInstruction{builtin->ExternalName(), type});
     764          63 :   return VisitResult(type, assembler().TopRange(1));
     765             : }
     766             : 
     767        4934 : VisitResult ImplementationVisitor::Visit(IdentifierExpression* expr) {
     768             :   StackScope scope(this);
     769       14802 :   return scope.Yield(GenerateFetchFromLocation(GetLocationReference(expr)));
     770             : }
     771             : 
     772         131 : const Type* ImplementationVisitor::Visit(GotoStatement* stmt) {
     773         131 :   LocalLabel* label = LookupLabel(stmt->label);
     774         302 :   size_t parameter_count = label->parameter_types.size();
     775         262 :   if (stmt->arguments.size() != parameter_count) {
     776             :     ReportError("goto to label has incorrect number of parameters (expected ",
     777           0 :                 parameter_count, " found ", stmt->arguments.size(), ")");
     778             :   }
     779             : 
     780             :   size_t i = 0;
     781             :   StackRange arguments = assembler().TopRange(0);
     782         302 :   for (Expression* e : stmt->arguments) {
     783             :     StackScope scope(this);
     784          40 :     VisitResult result = Visit(e);
     785          80 :     const Type* parameter_type = label->parameter_types[i++];
     786         120 :     result = GenerateImplicitConvert(parameter_type, result);
     787         120 :     arguments.Extend(scope.Yield(result).stack_range());
     788             :   }
     789             : 
     790         131 :   assembler().Goto(label->block, arguments.Size());
     791         131 :   return TypeOracle::GetNeverType();
     792             : }
     793             : 
     794         391 : const Type* ImplementationVisitor::Visit(IfStatement* stmt) {
     795         733 :   bool has_else = stmt->if_false.has_value();
     796             : 
     797         391 :   if (stmt->is_constexpr) {
     798          49 :     VisitResult expression_result = Visit(stmt->condition);
     799             : 
     800          49 :     if (!(expression_result.type() == TypeOracle::GetConstexprBoolType())) {
     801           0 :       std::stringstream stream;
     802           0 :       stream << "expression should return type constexpr bool "
     803           0 :              << "but returns type " << *expression_result.type();
     804           0 :       ReportError(stream.str());
     805             :     }
     806             : 
     807          98 :     Block* true_block = assembler().NewBlock();
     808          98 :     Block* false_block = assembler().NewBlock();
     809          98 :     Block* done_block = assembler().NewBlock();
     810             : 
     811             :     assembler().Emit(ConstexprBranchInstruction{
     812         245 :         expression_result.constexpr_value(), true_block, false_block});
     813             : 
     814          49 :     assembler().Bind(true_block);
     815          49 :     const Type* left_result = Visit(stmt->if_true);
     816          49 :     if (left_result == TypeOracle::GetVoidType()) {
     817          11 :       assembler().Goto(done_block);
     818             :     }
     819             : 
     820          49 :     assembler().Bind(false_block);
     821          49 :     const Type* right_result = TypeOracle::GetVoidType();
     822          49 :     if (has_else) {
     823          47 :       right_result = Visit(*stmt->if_false);
     824             :     }
     825          49 :     if (right_result == TypeOracle::GetVoidType()) {
     826          11 :       assembler().Goto(done_block);
     827             :     }
     828             : 
     829          49 :     if (left_result->IsNever() != right_result->IsNever()) {
     830           0 :       std::stringstream stream;
     831             :       stream << "either both or neither branches in a constexpr if statement "
     832           0 :                 "must reach their end at"
     833           0 :              << PositionAsString(stmt->pos);
     834           0 :       ReportError(stream.str());
     835             :     }
     836             : 
     837          49 :     if (left_result != TypeOracle::GetNeverType()) {
     838          11 :       assembler().Bind(done_block);
     839             :     }
     840             :     return left_result;
     841             :   } else {
     842         342 :     Block* true_block = assembler().NewBlock(assembler().CurrentStack(),
     843        1026 :                                              IsDeferred(stmt->if_true));
     844             :     Block* false_block =
     845             :         assembler().NewBlock(assembler().CurrentStack(),
     846        1026 :                              stmt->if_false && IsDeferred(*stmt->if_false));
     847         342 :     GenerateExpressionBranch(stmt->condition, true_block, false_block);
     848             : 
     849             :     Block* done_block;
     850             :     bool live = false;
     851         342 :     if (has_else) {
     852         194 :       done_block = assembler().NewBlock();
     853             :     } else {
     854             :       done_block = false_block;
     855             :       live = true;
     856             :     }
     857             : 
     858         342 :     assembler().Bind(true_block);
     859             :     {
     860         342 :       const Type* result = Visit(stmt->if_true);
     861         342 :       if (result == TypeOracle::GetVoidType()) {
     862             :         live = true;
     863         152 :         assembler().Goto(done_block);
     864             :       }
     865             :     }
     866             : 
     867         342 :     if (has_else) {
     868          97 :       assembler().Bind(false_block);
     869          97 :       const Type* result = Visit(*stmt->if_false);
     870          97 :       if (result == TypeOracle::GetVoidType()) {
     871             :         live = true;
     872          81 :         assembler().Goto(done_block);
     873             :       }
     874             :     }
     875             : 
     876         342 :     if (live) {
     877         334 :       assembler().Bind(done_block);
     878             :     }
     879         342 :     return live ? TypeOracle::GetVoidType() : TypeOracle::GetNeverType();
     880             :   }
     881             : }
     882             : 
     883          43 : const Type* ImplementationVisitor::Visit(WhileStatement* stmt) {
     884          86 :   Block* body_block = assembler().NewBlock(assembler().CurrentStack());
     885          86 :   Block* exit_block = assembler().NewBlock(assembler().CurrentStack());
     886             : 
     887          86 :   Block* header_block = assembler().NewBlock();
     888          43 :   assembler().Goto(header_block);
     889             : 
     890          43 :   assembler().Bind(header_block);
     891          43 :   GenerateExpressionBranch(stmt->condition, body_block, exit_block);
     892             : 
     893          43 :   assembler().Bind(body_block);
     894             :   {
     895          43 :     BreakContinueActivator activator{exit_block, header_block};
     896          43 :     const Type* body_result = Visit(stmt->body);
     897          43 :     if (body_result != TypeOracle::GetNeverType()) {
     898          43 :       assembler().Goto(header_block);
     899             :     }
     900             :   }
     901             : 
     902          43 :   assembler().Bind(exit_block);
     903          43 :   return TypeOracle::GetVoidType();
     904             : }
     905             : 
     906        1226 : const Type* ImplementationVisitor::Visit(BlockStatement* block) {
     907             :   BlockBindings<LocalValue> block_bindings(&ValueBindingsManager::Get());
     908        1226 :   const Type* type = TypeOracle::GetVoidType();
     909        5497 :   for (Statement* s : block->statements) {
     910        3045 :     CurrentSourcePosition::Scope source_position(s->pos);
     911        3045 :     if (type->IsNever()) {
     912           0 :       ReportError("statement after non-returning statement");
     913             :     }
     914        3045 :     if (auto* var_declaration = VarDeclarationStatement::DynamicCast(s)) {
     915         900 :       type = Visit(var_declaration, &block_bindings);
     916             :     } else {
     917        2145 :       type = Visit(s);
     918             :     }
     919             :   }
     920        1226 :   return type;
     921             : }
     922             : 
     923          67 : const Type* ImplementationVisitor::Visit(DebugStatement* stmt) {
     924             : #if defined(DEBUG)
     925             :   assembler().Emit(PrintConstantStringInstruction{"halting because of '" +
     926             :                                                   stmt->reason + "' at " +
     927             :                                                   PositionAsString(stmt->pos)});
     928             : #endif
     929          67 :   assembler().Emit(AbortInstruction{stmt->never_continues
     930             :                                         ? AbortInstruction::Kind::kUnreachable
     931         402 :                                         : AbortInstruction::Kind::kDebugBreak});
     932          67 :   if (stmt->never_continues) {
     933          67 :     return TypeOracle::GetNeverType();
     934             :   } else {
     935           0 :     return TypeOracle::GetVoidType();
     936             :   }
     937             : }
     938             : 
     939             : namespace {
     940             : 
     941         106 : std::string FormatAssertSource(const std::string& str) {
     942             :   // Replace all whitespace characters with a space character.
     943         106 :   std::string str_no_newlines = str;
     944             :   std::replace_if(str_no_newlines.begin(), str_no_newlines.end(),
     945        3477 :                   [](unsigned char c) { return isspace(c); }, ' ');
     946             : 
     947             :   // str might include indentation, squash multiple space characters into one.
     948             :   std::string result;
     949             :   std::unique_copy(str_no_newlines.begin(), str_no_newlines.end(),
     950             :                    std::back_inserter(result),
     951        3265 :                    [](char a, char b) { return a == ' ' && b == ' '; });
     952         106 :   return result;
     953             : }
     954             : 
     955             : }  // namespace
     956             : 
     957         237 : const Type* ImplementationVisitor::Visit(AssertStatement* stmt) {
     958         237 :   bool do_check = !stmt->debug_only;
     959             : #if defined(DEBUG)
     960             :   do_check = true;
     961             : #endif
     962         237 :   if (do_check) {
     963             :     // CSA_ASSERT & co. are not used here on purpose for two reasons. First,
     964             :     // Torque allows and handles two types of expressions in the if protocol
     965             :     // automagically, ones that return TNode<BoolT> and those that use the
     966             :     // BranchIf(..., Label* true, Label* false) idiom. Because the machinery to
     967             :     // handle this is embedded in the expression handling and to it's not
     968             :     // possible to make the decision to use CSA_ASSERT or CSA_ASSERT_BRANCH
     969             :     // isn't trivial up-front. Secondly, on failure, the assert text should be
     970             :     // the corresponding Torque code, not the -gen.cc code, which would be the
     971             :     // case when using CSA_ASSERT_XXX.
     972         212 :     Block* true_block = assembler().NewBlock(assembler().CurrentStack());
     973         212 :     Block* false_block = assembler().NewBlock(assembler().CurrentStack(), true);
     974         106 :     GenerateExpressionBranch(stmt->expression, true_block, false_block);
     975             : 
     976         106 :     assembler().Bind(false_block);
     977             : 
     978             :     assembler().Emit(AbortInstruction{
     979             :         AbortInstruction::Kind::kAssertionFailure,
     980         742 :         "Torque assert '" + FormatAssertSource(stmt->source) + "' failed"});
     981             : 
     982         106 :     assembler().Bind(true_block);
     983             :   }
     984         237 :   return TypeOracle::GetVoidType();
     985             : }
     986             : 
     987         935 : const Type* ImplementationVisitor::Visit(ExpressionStatement* stmt) {
     988        1870 :   const Type* type = Visit(stmt->expression).type();
     989         935 :   return type->IsNever() ? type : TypeOracle::GetVoidType();
     990             : }
     991             : 
     992         574 : const Type* ImplementationVisitor::Visit(ReturnStatement* stmt) {
     993        1148 :   Callable* current_callable = CurrentCallable::Get();
     994         574 :   if (current_callable->signature().return_type->IsNever()) {
     995           0 :     std::stringstream s;
     996           0 :     s << "cannot return from a function with return type never";
     997           0 :     ReportError(s.str());
     998             :   }
     999             :   LocalLabel* end =
    1000         985 :       current_callable->IsMacro() ? LookupLabel("_macro_end") : nullptr;
    1001         574 :   if (current_callable->HasReturnValue()) {
    1002         574 :     if (!stmt->value) {
    1003           0 :       std::stringstream s;
    1004           0 :       s << "return expression needs to be specified for a return type of "
    1005           0 :         << *current_callable->signature().return_type;
    1006           0 :       ReportError(s.str());
    1007             :     }
    1008         572 :     VisitResult expression_result = Visit(*stmt->value);
    1009             :     VisitResult return_result = GenerateImplicitConvert(
    1010        1144 :         current_callable->signature().return_type, expression_result);
    1011         572 :     if (current_callable->IsMacro()) {
    1012         409 :       if (return_result.IsOnStack()) {
    1013             :         StackRange return_value_range =
    1014             :             GenerateLabelGoto(end, return_result.stack_range());
    1015         794 :         SetReturnValue(VisitResult(return_result.type(), return_value_range));
    1016             :       } else {
    1017             :         GenerateLabelGoto(end);
    1018          24 :         SetReturnValue(return_result);
    1019             :       }
    1020         163 :     } else if (current_callable->IsBuiltin()) {
    1021         652 :       assembler().Emit(ReturnInstruction{});
    1022             :     } else {
    1023           0 :       UNREACHABLE();
    1024             :     }
    1025             :   } else {
    1026           2 :     if (stmt->value) {
    1027           0 :       std::stringstream s;
    1028             :       s << "return expression can't be specified for a void or never return "
    1029           0 :            "type";
    1030           0 :       ReportError(s.str());
    1031             :     }
    1032             :     GenerateLabelGoto(end);
    1033             :   }
    1034             :   current_callable->IncrementReturns();
    1035         574 :   return TypeOracle::GetNeverType();
    1036             : }
    1037             : 
    1038           4 : const Type* ImplementationVisitor::Visit(ForOfLoopStatement* stmt) {
    1039           4 :   VisitResult expression_result = Visit(stmt->iterable);
    1040             :   VisitResult begin = stmt->begin
    1041             :                           ? Visit(*stmt->begin)
    1042           8 :                           : VisitResult(TypeOracle::GetConstInt31Type(), "0");
    1043             : 
    1044             :   VisitResult end = stmt->end
    1045             :                         ? Visit(*stmt->end)
    1046          24 :                         : GenerateCall(".length", {{expression_result}, {}});
    1047             : 
    1048           4 :   const Type* common_type = GetCommonType(begin.type(), end.type());
    1049           8 :   VisitResult index = GenerateImplicitConvert(common_type, begin);
    1050             : 
    1051           8 :   Block* body_block = assembler().NewBlock();
    1052           8 :   Block* increment_block = assembler().NewBlock(assembler().CurrentStack());
    1053           8 :   Block* exit_block = assembler().NewBlock(assembler().CurrentStack());
    1054             : 
    1055           8 :   Block* header_block = assembler().NewBlock();
    1056             : 
    1057           4 :   assembler().Goto(header_block);
    1058             : 
    1059           4 :   assembler().Bind(header_block);
    1060             : 
    1061           4 :   BreakContinueActivator activator(exit_block, increment_block);
    1062             : 
    1063             :   {
    1064             :     StackScope comparison_scope(this);
    1065          20 :     VisitResult result = GenerateCall("<", {{index, end}, {}});
    1066           4 :     if (result.type() != TypeOracle::GetBoolType()) {
    1067           0 :       ReportError("operator < with arguments(", *index.type(), ", ",
    1068           0 :                   *end.type(),
    1069             :                   ")  used in for-of loop has to return type bool, but "
    1070             :                   "returned type ",
    1071           0 :                   *result.type());
    1072             :     }
    1073          12 :     comparison_scope.Yield(result);
    1074             :   }
    1075           4 :   assembler().Branch(body_block, exit_block);
    1076             : 
    1077           4 :   assembler().Bind(body_block);
    1078             :   {
    1079           4 :     VisitResult element_result;
    1080             :     {
    1081             :       StackScope element_scope(this);
    1082          20 :       VisitResult result = GenerateCall("[]", {{expression_result, index}, {}});
    1083           4 :       if (stmt->var_declaration->type) {
    1084             :         const Type* declared_type =
    1085           4 :             Declarations::GetType(*stmt->var_declaration->type);
    1086          12 :         result = GenerateImplicitConvert(declared_type, result);
    1087             :       }
    1088          12 :       element_result = element_scope.Yield(result);
    1089             :     }
    1090             :     Binding<LocalValue> element_var_binding{&ValueBindingsManager::Get(),
    1091             :                                             stmt->var_declaration->name,
    1092          16 :                                             LocalValue{true, element_result}};
    1093           4 :     Visit(stmt->body);
    1094             :   }
    1095           4 :   assembler().Goto(increment_block);
    1096             : 
    1097           4 :   assembler().Bind(increment_block);
    1098             :   {
    1099             :     Arguments increment_args;
    1100          16 :     increment_args.parameters = {index, {TypeOracle::GetConstInt31Type(), "1"}};
    1101          12 :     VisitResult increment_result = GenerateCall("+", increment_args);
    1102             : 
    1103             :     GenerateAssignToLocation(LocationReference::VariableAccess(index),
    1104          16 :                              increment_result);
    1105             :   }
    1106             : 
    1107           4 :   assembler().Goto(header_block);
    1108             : 
    1109           4 :   assembler().Bind(exit_block);
    1110           8 :   return TypeOracle::GetVoidType();
    1111             : }
    1112             : 
    1113         768 : VisitResult ImplementationVisitor::Visit(TryLabelExpression* expr) {
    1114         197 :   size_t parameter_count = expr->label_block->parameters.names.size();
    1115             :   std::vector<VisitResult> parameters;
    1116             : 
    1117             :   Block* label_block = nullptr;
    1118         362 :   Block* done_block = assembler().NewBlock();
    1119         181 :   VisitResult try_result;
    1120             : 
    1121             :   {
    1122         181 :     CurrentSourcePosition::Scope source_position(expr->label_block->pos);
    1123         181 :     if (expr->label_block->parameters.has_varargs) {
    1124           0 :       ReportError("cannot use ... for label parameters");
    1125             :     }
    1126             :     Stack<const Type*> label_input_stack = assembler().CurrentStack();
    1127             :     TypeVector parameter_types;
    1128         197 :     for (size_t i = 0; i < parameter_count; ++i) {
    1129             :       const Type* type =
    1130          32 :           Declarations::GetType(expr->label_block->parameters.types[i]);
    1131          16 :       parameter_types.push_back(type);
    1132          16 :       if (type->IsConstexpr()) {
    1133           0 :         ReportError("no constexpr type allowed for label arguments");
    1134             :       }
    1135          32 :       StackRange range = label_input_stack.PushMany(LowerType(type));
    1136          32 :       parameters.push_back(VisitResult(type, range));
    1137             :     }
    1138             :     label_block = assembler().NewBlock(label_input_stack,
    1139         543 :                                        IsDeferred(expr->label_block->body));
    1140             : 
    1141             :     Binding<LocalLabel> label_binding{&LabelBindingsManager::Get(),
    1142             :                                       expr->label_block->label,
    1143        1086 :                                       LocalLabel{label_block, parameter_types}};
    1144             : 
    1145             :     // Visit try
    1146             :     StackScope stack_scope(this);
    1147         362 :     try_result = Visit(expr->try_expression);
    1148         181 :     if (try_result.type() != TypeOracle::GetNeverType()) {
    1149         255 :       try_result = stack_scope.Yield(try_result);
    1150          85 :       assembler().Goto(done_block);
    1151             :     }
    1152             :   }
    1153             : 
    1154             :   // Visit and output the code for the label block. If the label block falls
    1155             :   // through, then the try must not return a value. Also, if the try doesn't
    1156             :   // fall through, but the label does, then overall the try-label block
    1157             :   // returns type void.
    1158         181 :   assembler().Bind(label_block);
    1159             :   const Type* label_result;
    1160             :   {
    1161             :     BlockBindings<LocalValue> parameter_bindings(&ValueBindingsManager::Get());
    1162         197 :     for (size_t i = 0; i < parameter_count; ++i) {
    1163          16 :       parameter_bindings.Add(expr->label_block->parameters.names[i],
    1164          80 :                              LocalValue{true, parameters[i]});
    1165             :     }
    1166             : 
    1167         181 :     label_result = Visit(expr->label_block->body);
    1168             :   }
    1169         181 :   if (!try_result.type()->IsVoidOrNever() && label_result->IsVoid()) {
    1170             :     ReportError(
    1171           0 :         "otherwise clauses cannot fall through in a non-void expression");
    1172             :   }
    1173         181 :   if (label_result != TypeOracle::GetNeverType()) {
    1174          44 :     assembler().Goto(done_block);
    1175             :   }
    1176         225 :   if (label_result->IsVoid() && try_result.type()->IsNever()) {
    1177          22 :     try_result =
    1178          11 :         VisitResult(TypeOracle::GetVoidType(), try_result.stack_range());
    1179             :   }
    1180             : 
    1181         181 :   if (!try_result.type()->IsNever()) {
    1182          96 :     assembler().Bind(done_block);
    1183             :   }
    1184         181 :   return try_result;
    1185             : }
    1186             : 
    1187           0 : VisitResult ImplementationVisitor::Visit(StatementExpression* expr) {
    1188         135 :   return VisitResult{Visit(expr->statement), assembler().TopRange(0)};
    1189             : }
    1190             : 
    1191           1 : VisitResult ImplementationVisitor::Visit(NewExpression* expr) {
    1192             :   StackScope stack_scope(this);
    1193           1 :   const Type* type = Declarations::GetType(expr->type);
    1194           1 :   const ClassType* class_type = ClassType::DynamicCast(type);
    1195           1 :   if (class_type == nullptr) {
    1196             :     ReportError("type for new expression must be a class, \"", *type,
    1197           0 :                 "\" is not");
    1198             :   }
    1199           1 :   Arguments allocate_arguments;
    1200             :   allocate_arguments.parameters.push_back(VisitResult(
    1201           3 :       TypeOracle::GetConstInt31Type(), std::to_string(class_type->size())));
    1202             :   VisitResult allocate_result =
    1203           4 :       GenerateCall("%Allocate", allocate_arguments, {class_type}, false);
    1204           1 :   Arguments constructor_arguments;
    1205           2 :   for (auto p : expr->parameters) {
    1206           0 :     constructor_arguments.parameters.push_back(Visit(p));
    1207             :   }
    1208             :   Callable* callable =
    1209             :       LookupCall({{}, kConstructMethodName}, class_type->Constructors(),
    1210           5 :                  constructor_arguments, {});
    1211             :   return stack_scope.Yield(
    1212             :       GenerateCall(callable,
    1213             :                    LocationReference::Temporary(allocate_result,
    1214             :                                                 "unitialized object from new"),
    1215           9 :                    constructor_arguments, {class_type}, false));
    1216             : }
    1217             : 
    1218          21 : const Type* ImplementationVisitor::Visit(BreakStatement* stmt) {
    1219          42 :   base::Optional<Binding<LocalLabel>*> break_label = TryLookupLabel("_break");
    1220          21 :   if (!break_label) {
    1221           0 :     ReportError("break used outside of loop");
    1222             :   }
    1223          21 :   assembler().Goto((*break_label)->block);
    1224          21 :   return TypeOracle::GetNeverType();
    1225             : }
    1226             : 
    1227          11 : const Type* ImplementationVisitor::Visit(ContinueStatement* stmt) {
    1228             :   base::Optional<Binding<LocalLabel>*> continue_label =
    1229          22 :       TryLookupLabel("_continue");
    1230          11 :   if (!continue_label) {
    1231           0 :     ReportError("continue used outside of loop");
    1232             :   }
    1233          11 :   assembler().Goto((*continue_label)->block);
    1234          11 :   return TypeOracle::GetNeverType();
    1235             : }
    1236             : 
    1237          31 : const Type* ImplementationVisitor::Visit(ForLoopStatement* stmt) {
    1238             :   BlockBindings<LocalValue> loop_bindings(&ValueBindingsManager::Get());
    1239             : 
    1240          31 :   if (stmt->var_declaration) Visit(*stmt->var_declaration, &loop_bindings);
    1241             : 
    1242          62 :   Block* body_block = assembler().NewBlock(assembler().CurrentStack());
    1243          62 :   Block* exit_block = assembler().NewBlock(assembler().CurrentStack());
    1244             : 
    1245          62 :   Block* header_block = assembler().NewBlock();
    1246          31 :   assembler().Goto(header_block);
    1247          31 :   assembler().Bind(header_block);
    1248             : 
    1249             :   // The continue label is where "continue" statements jump to. If no action
    1250             :   // expression is provided, we jump directly to the header.
    1251             :   Block* continue_block = header_block;
    1252             : 
    1253             :   // The action label is only needed when an action expression was provided.
    1254             :   Block* action_block = nullptr;
    1255          62 :   if (stmt->action) {
    1256          52 :     action_block = assembler().NewBlock();
    1257             : 
    1258             :     // The action expression needs to be executed on a continue.
    1259             :     continue_block = action_block;
    1260             :   }
    1261             : 
    1262          31 :   if (stmt->test) {
    1263          26 :     GenerateExpressionBranch(*stmt->test, body_block, exit_block);
    1264             :   } else {
    1265           5 :     assembler().Goto(body_block);
    1266             :   }
    1267             : 
    1268          31 :   assembler().Bind(body_block);
    1269             :   {
    1270          31 :     BreakContinueActivator activator(exit_block, continue_block);
    1271          31 :     const Type* body_result = Visit(stmt->body);
    1272          31 :     if (body_result != TypeOracle::GetNeverType()) {
    1273          31 :       assembler().Goto(continue_block);
    1274             :     }
    1275             :   }
    1276             : 
    1277          31 :   if (stmt->action) {
    1278          26 :     assembler().Bind(action_block);
    1279          26 :     const Type* action_result = Visit(*stmt->action);
    1280          26 :     if (action_result != TypeOracle::GetNeverType()) {
    1281          26 :       assembler().Goto(header_block);
    1282             :     }
    1283             :   }
    1284             : 
    1285          31 :   assembler().Bind(exit_block);
    1286          62 :   return TypeOracle::GetVoidType();
    1287             : }
    1288             : 
    1289          10 : void ImplementationVisitor::GenerateImplementation(const std::string& dir,
    1290             :                                                    Namespace* nspace) {
    1291             :   std::string new_source(nspace->source());
    1292             :   std::string base_file_name =
    1293          30 :       "builtins-" + DashifyString(nspace->name()) + "-from-dsl-gen";
    1294             : 
    1295          20 :   std::string source_file_name = dir + "/" + base_file_name + ".cc";
    1296          10 :   ReplaceFileContentsIfDifferent(source_file_name, new_source);
    1297             :   std::string new_header(nspace->header());
    1298          20 :   std::string header_file_name = dir + "/" + base_file_name + ".h";
    1299          10 :   ReplaceFileContentsIfDifferent(header_file_name, new_header);
    1300          10 : }
    1301             : 
    1302           0 : void ImplementationVisitor::GenerateMacroFunctionDeclaration(
    1303             :     std::ostream& o, const std::string& macro_prefix, Macro* macro) {
    1304         434 :   GenerateFunctionDeclaration(o, macro_prefix, macro->ExternalName(),
    1305        1302 :                               macro->signature(), macro->parameter_names());
    1306           0 : }
    1307             : 
    1308         948 : void ImplementationVisitor::GenerateFunctionDeclaration(
    1309             :     std::ostream& o, const std::string& macro_prefix, const std::string& name,
    1310             :     const Signature& signature, const NameVector& parameter_names) {
    1311         948 :   if (GlobalContext::verbose()) {
    1312           0 :     std::cout << "generating source for declaration " << name << "\n";
    1313             :   }
    1314             : 
    1315         948 :   if (signature.return_type->IsVoidOrNever()) {
    1316         248 :     o << "void";
    1317             :   } else {
    1318        1400 :     o << signature.return_type->GetGeneratedTypeName();
    1319             :   }
    1320        1896 :   o << " " << macro_prefix << name << "(";
    1321             : 
    1322             :   DCHECK_EQ(signature.types().size(), parameter_names.size());
    1323         948 :   auto type_iterator = signature.types().begin();
    1324             :   bool first = true;
    1325        3820 :   for (const std::string& name : parameter_names) {
    1326        1924 :     if (!first) {
    1327        1124 :       o << ", ";
    1328             :     }
    1329        1924 :     const Type* parameter_type = *type_iterator;
    1330             :     const std::string& generated_type_name =
    1331        1924 :         parameter_type->GetGeneratedTypeName();
    1332        5772 :     o << generated_type_name << " " << ExternalParameterName(name);
    1333             :     type_iterator++;
    1334             :     first = false;
    1335             :   }
    1336             : 
    1337        2154 :   for (const LabelDeclaration& label_info : signature.labels) {
    1338         258 :     if (!first) {
    1339         252 :       o << ", ";
    1340             :     }
    1341         774 :     o << "compiler::CodeAssemblerLabel* " << ExternalLabelName(label_info.name);
    1342             :     size_t i = 0;
    1343         540 :     for (const Type* type : label_info.types) {
    1344          24 :       std::string generated_type_name("compiler::TypedCodeAssemblerVariable<");
    1345          48 :       generated_type_name += type->GetGeneratedTNodeTypeName();
    1346             :       generated_type_name += ">*";
    1347          24 :       o << ", ";
    1348          24 :       o << generated_type_name << " "
    1349          48 :         << ExternalLabelParameterName(label_info.name, i);
    1350          24 :       ++i;
    1351             :     }
    1352             :   }
    1353             : 
    1354         948 :   o << ")";
    1355         948 : }
    1356             : 
    1357             : namespace {
    1358             : 
    1359           0 : void FailCallableLookup(const std::string& reason, const QualifiedName& name,
    1360             :                         const Arguments& arguments,
    1361             :                         const std::vector<Signature>& candidates) {
    1362           0 :   std::stringstream stream;
    1363           0 :   stream << "\n"
    1364           0 :          << reason << ": \n  " << name << "("
    1365           0 :          << arguments.parameters.GetTypeVector() << ")";
    1366           0 :   if (arguments.labels.size() != 0) {
    1367           0 :     stream << " labels ";
    1368           0 :     for (size_t i = 0; i < arguments.labels.size(); ++i) {
    1369           0 :       stream << arguments.labels[i]->name() << "("
    1370           0 :              << arguments.labels[i]->parameter_types << ")";
    1371             :     }
    1372             :   }
    1373           0 :   stream << "\ncandidates are:";
    1374           0 :   for (const Signature& signature : candidates) {
    1375           0 :     stream << "\n  " << name;
    1376           0 :     PrintSignature(stream, signature, false);
    1377             :   }
    1378           0 :   ReportError(stream.str());
    1379             : }
    1380             : 
    1381        1698 : Callable* GetOrCreateSpecialization(const SpecializationKey& key) {
    1382        1698 :   if (base::Optional<Callable*> specialization =
    1383        1698 :           key.generic->GetSpecialization(key.specialized_types)) {
    1384        1527 :     return *specialization;
    1385             :   }
    1386         171 :   return DeclarationVisitor().SpecializeImplicit(key);
    1387             : }
    1388             : 
    1389             : }  // namespace
    1390             : 
    1391           0 : base::Optional<Binding<LocalValue>*> ImplementationVisitor::TryLookupLocalValue(
    1392             :     const std::string& name) {
    1393        8125 :   return ValueBindingsManager::Get().TryLookup(name);
    1394             : }
    1395             : 
    1396           0 : base::Optional<Binding<LocalLabel>*> ImplementationVisitor::TryLookupLabel(
    1397             :     const std::string& name) {
    1398        5910 :   return LabelBindingsManager::Get().TryLookup(name);
    1399             : }
    1400             : 
    1401        1090 : Binding<LocalLabel>* ImplementationVisitor::LookupLabel(
    1402             :     const std::string& name) {
    1403             :   base::Optional<Binding<LocalLabel>*> label = TryLookupLabel(name);
    1404        1090 :   if (!label) ReportError("cannot find label ", name);
    1405        1090 :   return *label;
    1406             : }
    1407             : 
    1408          81 : Block* ImplementationVisitor::LookupSimpleLabel(const std::string& name) {
    1409          81 :   LocalLabel* label = LookupLabel(name);
    1410          81 :   if (!label->parameter_types.empty()) {
    1411             :     ReportError("label ", name,
    1412             :                 "was expected to have no parameters, but has parameters (",
    1413           0 :                 label->parameter_types, ")");
    1414             :   }
    1415          81 :   return label->block;
    1416             : }
    1417             : 
    1418             : template <class Container>
    1419        4230 : Callable* ImplementationVisitor::LookupCall(
    1420             :     const QualifiedName& name, const Container& declaration_container,
    1421             :     const Arguments& arguments, const TypeVector& specialization_types) {
    1422             :   Callable* result = nullptr;
    1423        4230 :   TypeVector parameter_types(arguments.parameters.GetTypeVector());
    1424             : 
    1425             :   std::vector<Declarable*> overloads;
    1426        4230 :   std::vector<Signature> overload_signatures;
    1427       22346 :   for (auto* declarable : declaration_container) {
    1428       13886 :     if (Generic* generic = Generic::DynamicCast(declarable)) {
    1429             :       base::Optional<TypeVector> inferred_specialization_types =
    1430             :           generic->InferSpecializationTypes(specialization_types,
    1431        1849 :                                             parameter_types);
    1432        1849 :       if (!inferred_specialization_types) continue;
    1433        3698 :       overloads.push_back(generic);
    1434             :       overload_signatures.push_back(
    1435             :           DeclarationVisitor().MakeSpecializedSignature(
    1436        5547 :               SpecializationKey{generic, *inferred_specialization_types}));
    1437       12037 :     } else if (Callable* callable = Callable::DynamicCast(declarable)) {
    1438       24074 :       overloads.push_back(callable);
    1439       12037 :       overload_signatures.push_back(callable->signature());
    1440             :     }
    1441             :   }
    1442             :   // Indices of candidates in overloads/overload_signatures.
    1443             :   std::vector<size_t> candidates;
    1444       36232 :   for (size_t i = 0; i < overloads.size(); ++i) {
    1445       13886 :     const Signature& signature = overload_signatures[i];
    1446       13886 :     bool try_bool_context = arguments.labels.size() == 0 &&
    1447       13886 :                             signature.return_type == TypeOracle::GetNeverType();
    1448             :     base::Optional<Binding<LocalLabel>*> true_label;
    1449             :     base::Optional<Binding<LocalLabel>*> false_label;
    1450       13886 :     if (try_bool_context) {
    1451        1071 :       true_label = TryLookupLabel(kTrueLabelName);
    1452        1071 :       false_label = TryLookupLabel(kFalseLabelName);
    1453             :     }
    1454       37428 :     if (IsCompatibleSignature(signature, parameter_types, arguments.labels) ||
    1455        9385 :         (true_label && false_label &&
    1456             :          IsCompatibleSignature(signature, parameter_types,
    1457       14699 :                                {*true_label, *false_label}))) {
    1458        4955 :       candidates.push_back(i);
    1459             :     }
    1460             :   }
    1461             : 
    1462        4230 :   if (overloads.empty()) {
    1463           0 :     std::stringstream stream;
    1464           0 :     stream << "no matching declaration found for " << name;
    1465           0 :     ReportError(stream.str());
    1466        4230 :   } else if (candidates.empty()) {
    1467           0 :     FailCallableLookup("cannot find suitable callable with name", name,
    1468           0 :                        arguments, overload_signatures);
    1469             :   }
    1470             : 
    1471        1450 :   auto is_better_candidate = [&](size_t a, size_t b) {
    1472        1450 :     return ParameterDifference(overload_signatures[a].GetExplicitTypes(),
    1473             :                                parameter_types)
    1474             :         .StrictlyBetterThan(ParameterDifference(
    1475       11600 :             overload_signatures[b].GetExplicitTypes(), parameter_types));
    1476        7130 :   };
    1477             : 
    1478        8460 :   size_t best = *std::min_element(candidates.begin(), candidates.end(),
    1479        4230 :                                   is_better_candidate);
    1480             :   // This check is contained in libstdc++'s std::min_element.
    1481             :   DCHECK(!is_better_candidate(best, best));
    1482       13415 :   for (size_t candidate : candidates) {
    1483        4955 :     if (candidate != best && !is_better_candidate(best, candidate)) {
    1484             :       std::vector<Signature> candidate_signatures;
    1485           0 :       for (size_t i : candidates) {
    1486           0 :         candidate_signatures.push_back(overload_signatures[i]);
    1487             :       }
    1488           0 :       FailCallableLookup("ambiguous callable", name, arguments,
    1489           0 :                          candidate_signatures);
    1490             :     }
    1491             :   }
    1492             : 
    1493       12690 :   if (Generic* generic = Generic::DynamicCast(overloads[best])) {
    1494        1639 :     result = GetOrCreateSpecialization(
    1495             :         SpecializationKey{generic, *generic->InferSpecializationTypes(
    1496        4917 :                                        specialization_types, parameter_types)});
    1497             :   } else {
    1498             :     result = Callable::cast(overloads[best]);
    1499             :   }
    1500             : 
    1501        4230 :   size_t caller_size = parameter_types.size();
    1502             :   size_t callee_size =
    1503        8460 :       result->signature().types().size() - result->signature().implicit_count;
    1504        4230 :   if (caller_size != callee_size &&
    1505             :       !result->signature().parameter_types.var_args) {
    1506           0 :     std::stringstream stream;
    1507           0 :     stream << "parameter count mismatch calling " << *result << " - expected "
    1508           0 :            << std::to_string(callee_size) << ", found "
    1509           0 :            << std::to_string(caller_size);
    1510           0 :     ReportError(stream.str());
    1511             :   }
    1512             : 
    1513        4230 :   return result;
    1514             : }
    1515             : 
    1516          90 : const Type* ImplementationVisitor::GetCommonType(const Type* left,
    1517             :                                                  const Type* right) {
    1518             :   const Type* common_type;
    1519          90 :   if (IsAssignableFrom(left, right)) {
    1520             :     common_type = left;
    1521          11 :   } else if (IsAssignableFrom(right, left)) {
    1522             :     common_type = right;
    1523             :   } else {
    1524           0 :     common_type = TypeOracle::GetUnionType(left, right);
    1525             :   }
    1526          90 :   common_type = common_type->NonConstexprVersion();
    1527          90 :   return common_type;
    1528             : }
    1529             : 
    1530       39063 : VisitResult ImplementationVisitor::GenerateCopy(const VisitResult& to_copy) {
    1531       14731 :   if (to_copy.IsOnStack()) {
    1532             :     return VisitResult(to_copy.type(),
    1533       24332 :                        assembler().Peek(to_copy.stack_range(), to_copy.type()));
    1534             :   }
    1535        2565 :   return to_copy;
    1536             : }
    1537             : 
    1538          16 : VisitResult ImplementationVisitor::Visit(StructExpression* decl) {
    1539             :   StackScope stack_scope(this);
    1540             :   const Type* raw_type = Declarations::LookupType(
    1541          48 :       QualifiedName(decl->namespace_qualification, decl->name));
    1542          16 :   if (!raw_type->IsStructType()) {
    1543           0 :     std::stringstream s;
    1544           0 :     s << decl->name << " is not a struct but used like one ";
    1545           0 :     ReportError(s.str());
    1546             :   }
    1547             :   const StructType* struct_type = StructType::cast(raw_type);
    1548          48 :   if (struct_type->fields().size() != decl->expressions.size()) {
    1549           0 :     std::stringstream s;
    1550           0 :     s << "initializer count mismatch for struct " << decl->name << " (expected "
    1551           0 :       << struct_type->fields().size() << ", found " << decl->expressions.size()
    1552           0 :       << ")";
    1553           0 :     ReportError(s.str());
    1554             :   }
    1555             :   // Push uninitialized 'this'
    1556          16 :   TypeVector lowered_types = LowerType(struct_type);
    1557          83 :   for (const Type* type : lowered_types) {
    1558          51 :     assembler().Emit(PushUninitializedInstruction{TypeOracle::GetTopType(
    1559         408 :         "unitialized struct field at " + PositionAsString(decl->pos), type)});
    1560             :   }
    1561             :   VisitResult uninitialized_struct =
    1562          16 :       VisitResult(struct_type, assembler().TopRange(lowered_types.size()));
    1563          16 :   Arguments constructor_arguments;
    1564          76 :   for (auto p : decl->expressions) {
    1565          88 :     constructor_arguments.parameters.push_back(Visit(p));
    1566             :   }
    1567             :   Callable* callable =
    1568             :       LookupCall({{}, kConstructMethodName}, struct_type->Constructors(),
    1569          80 :                  constructor_arguments, {});
    1570             :   return stack_scope.Yield(GenerateCall(
    1571             :       callable, LocationReference::VariableAccess(uninitialized_struct),
    1572         112 :       constructor_arguments, {}, false));
    1573             : }
    1574             : 
    1575         836 : LocationReference ImplementationVisitor::GetLocationReference(
    1576             :     Expression* location) {
    1577         836 :   switch (location->kind) {
    1578             :     case AstNode::Kind::kIdentifierExpression:
    1579         708 :       return GetLocationReference(static_cast<IdentifierExpression*>(location));
    1580             :     case AstNode::Kind::kFieldAccessExpression:
    1581             :       return GetLocationReference(
    1582          64 :           static_cast<FieldAccessExpression*>(location));
    1583             :     case AstNode::Kind::kElementAccessExpression:
    1584             :       return GetLocationReference(
    1585          61 :           static_cast<ElementAccessExpression*>(location));
    1586             :     default:
    1587           9 :       return LocationReference::Temporary(Visit(location), "expression");
    1588             :   }
    1589             : }
    1590             : 
    1591         323 : LocationReference ImplementationVisitor::GetLocationReference(
    1592             :     FieldAccessExpression* expr) {
    1593         323 :   LocationReference reference = GetLocationReference(expr->object);
    1594         401 :   if (reference.IsVariableAccess() &&
    1595          78 :       reference.variable().type()->IsStructType()) {
    1596             :     return LocationReference::VariableAccess(
    1597         168 :         ProjectStructField(reference.variable(), expr->field));
    1598             :   }
    1599         507 :   if (reference.IsTemporary() && reference.temporary().type()->IsStructType()) {
    1600             :     return LocationReference::Temporary(
    1601             :         ProjectStructField(reference.temporary(), expr->field),
    1602          92 :         reference.temporary_description());
    1603             :   }
    1604             :   return LocationReference::FieldAccess(GenerateFetchFromLocation(reference),
    1605         732 :                                         expr->field);
    1606             : }
    1607             : 
    1608         195 : LocationReference ImplementationVisitor::GetLocationReference(
    1609             :     ElementAccessExpression* expr) {
    1610         195 :   VisitResult array = Visit(expr->array);
    1611         195 :   VisitResult index = Visit(expr->index);
    1612         780 :   return LocationReference::ArrayAccess(array, index);
    1613             : }
    1614             : 
    1615        5642 : LocationReference ImplementationVisitor::GetLocationReference(
    1616             :     IdentifierExpression* expr) {
    1617        5642 :   if (expr->namespace_qualification.empty()) {
    1618        5642 :     if (expr->IsThis()) {
    1619          88 :       if (CurrentConstructorInfo::Get()) {
    1620          26 :         CurrentConstructorInfo::Get()->accessed_this = true;
    1621             :       }
    1622             :     }
    1623        5642 :     if (base::Optional<Binding<LocalValue>*> value =
    1624        5642 :             TryLookupLocalValue(expr->name)) {
    1625       10430 :       if (expr->generic_arguments.size() != 0) {
    1626             :         ReportError("cannot have generic parameters on local name ",
    1627           0 :                     expr->name);
    1628             :       }
    1629        4792 :       if ((*value)->is_const) {
    1630             :         return LocationReference::Temporary((*value)->value,
    1631        9663 :                                             "constant value " + expr->name);
    1632             :       }
    1633        3142 :       return LocationReference::VariableAccess((*value)->value);
    1634             :     }
    1635             :   }
    1636             : 
    1637         850 :   if (expr->IsThis()) {
    1638           0 :     ReportError("\"this\" cannot be qualified");
    1639             :   }
    1640        2550 :   QualifiedName name = QualifiedName(expr->namespace_qualification, expr->name);
    1641         850 :   if (base::Optional<Builtin*> builtin = Declarations::TryLookupBuiltin(name)) {
    1642             :     return LocationReference::Temporary(GetBuiltinCode(*builtin),
    1643          12 :                                         "builtin " + expr->name);
    1644             :   }
    1645         846 :   if (expr->generic_arguments.size() != 0) {
    1646          59 :     Generic* generic = Declarations::LookupUniqueGeneric(name);
    1647             :     Callable* specialization = GetOrCreateSpecialization(
    1648         118 :         SpecializationKey{generic, GetTypeVector(expr->generic_arguments)});
    1649          59 :     if (Builtin* builtin = Builtin::DynamicCast(specialization)) {
    1650             :       DCHECK(!builtin->IsExternal());
    1651             :       return LocationReference::Temporary(GetBuiltinCode(builtin),
    1652         177 :                                           "builtin " + expr->name);
    1653             :     } else {
    1654             :       ReportError("cannot create function pointer for non-builtin ",
    1655           0 :                   generic->name());
    1656             :     }
    1657             :   }
    1658         787 :   Value* value = Declarations::LookupValue(name);
    1659         787 :   if (auto* constant = NamespaceConstant::DynamicCast(value)) {
    1660         879 :     if (constant->type()->IsConstexpr()) {
    1661             :       return LocationReference::Temporary(
    1662         144 :           VisitResult(constant->type(), constant->ExternalAssemblerName() +
    1663          72 :                                             "(state_)." +
    1664         144 :                                             constant->constant_name() + "()"),
    1665         216 :           "namespace constant " + expr->name);
    1666             :     }
    1667         735 :     assembler().Emit(NamespaceConstantInstruction{constant});
    1668             :     StackRange stack_range =
    1669         245 :         assembler().TopRange(LoweredSlotCount(constant->type()));
    1670             :     return LocationReference::Temporary(
    1671             :         VisitResult(constant->type(), stack_range),
    1672         735 :         "namespace constant " + expr->name);
    1673             :   }
    1674             :   ExternConstant* constant = ExternConstant::cast(value);
    1675             :   return LocationReference::Temporary(constant->value(),
    1676        1410 :                                       "extern value " + expr->name);
    1677             : }
    1678             : 
    1679        5706 : VisitResult ImplementationVisitor::GenerateFetchFromLocation(
    1680             :     const LocationReference& reference) {
    1681        5706 :   if (reference.IsTemporary()) {
    1682        4074 :     return GenerateCopy(reference.temporary());
    1683        1632 :   } else if (reference.IsVariableAccess()) {
    1684        1263 :     return GenerateCopy(reference.variable());
    1685             :   } else {
    1686             :     DCHECK(reference.IsCallAccess());
    1687         369 :     return GenerateCall(reference.eval_function(),
    1688        1107 :                         Arguments{reference.call_arguments(), {}});
    1689             :   }
    1690             : }
    1691             : 
    1692         510 : void ImplementationVisitor::GenerateAssignToLocation(
    1693             :     const LocationReference& reference, const VisitResult& assignment_value) {
    1694         510 :   if (reference.IsCallAccess()) {
    1695             :     Arguments arguments{reference.call_arguments(), {}};
    1696          70 :     arguments.parameters.push_back(assignment_value);
    1697         280 :     GenerateCall(reference.assign_function(), arguments);
    1698         440 :   } else if (reference.IsVariableAccess()) {
    1699         440 :     VisitResult variable = reference.variable();
    1700             :     VisitResult converted_value =
    1701         880 :         GenerateImplicitConvert(variable.type(), assignment_value);
    1702         440 :     assembler().Poke(variable.stack_range(), converted_value.stack_range(),
    1703         880 :                      variable.type());
    1704             :   } else {
    1705             :     DCHECK(reference.IsTemporary());
    1706             :     ReportError("cannot assign to temporary ",
    1707           0 :                 reference.temporary_description());
    1708             :   }
    1709         510 : }
    1710             : 
    1711          36 : VisitResult ImplementationVisitor::GeneratePointerCall(
    1712             :     Expression* callee, const Arguments& arguments, bool is_tailcall) {
    1713             :   StackScope scope(this);
    1714          36 :   TypeVector parameter_types(arguments.parameters.GetTypeVector());
    1715          36 :   VisitResult callee_result = Visit(callee);
    1716          72 :   if (!callee_result.type()->IsBuiltinPointerType()) {
    1717           0 :     std::stringstream stream;
    1718           0 :     stream << "Expected a function pointer type but found "
    1719           0 :            << *callee_result.type();
    1720           0 :     ReportError(stream.str());
    1721             :   }
    1722          36 :   const BuiltinPointerType* type =
    1723             :       BuiltinPointerType::cast(callee_result.type());
    1724             : 
    1725         108 :   if (type->parameter_types().size() != parameter_types.size()) {
    1726           0 :     std::stringstream stream;
    1727           0 :     stream << "parameter count mismatch calling function pointer with Type: "
    1728           0 :            << *type << " - expected "
    1729           0 :            << std::to_string(type->parameter_types().size()) << ", found "
    1730           0 :            << std::to_string(parameter_types.size());
    1731           0 :     ReportError(stream.str());
    1732             :   }
    1733             : 
    1734          36 :   ParameterTypes types{type->parameter_types(), false};
    1735          36 :   Signature sig;
    1736             :   sig.parameter_types = types;
    1737          72 :   if (!IsCompatibleSignature(sig, parameter_types, {})) {
    1738           0 :     std::stringstream stream;
    1739           0 :     stream << "parameters do not match function pointer signature. Expected: ("
    1740           0 :            << type->parameter_types() << ") but got: (" << parameter_types
    1741           0 :            << ")";
    1742           0 :     ReportError(stream.str());
    1743             :   }
    1744             : 
    1745          72 :   callee_result = GenerateCopy(callee_result);
    1746             :   StackRange arg_range = assembler().TopRange(0);
    1747         310 :   for (size_t current = 0; current < arguments.parameters.size(); ++current) {
    1748         238 :     const Type* to_type = type->parameter_types()[current];
    1749             :     arg_range.Extend(
    1750         155 :         GenerateImplicitConvert(to_type, arguments.parameters[current])
    1751         357 :             .stack_range());
    1752             :   }
    1753             : 
    1754          36 :   assembler().Emit(
    1755         144 :       CallBuiltinPointerInstruction{is_tailcall, type, arg_range.Size()});
    1756             : 
    1757          36 :   if (is_tailcall) {
    1758           0 :     return VisitResult::NeverResult();
    1759             :   }
    1760             :   DCHECK_EQ(1, LoweredSlotCount(type->return_type()));
    1761          72 :   return scope.Yield(VisitResult(type->return_type(), assembler().TopRange(1)));
    1762             : }
    1763             : 
    1764        7689 : void ImplementationVisitor::AddCallParameter(
    1765             :     Callable* callable, VisitResult parameter, const Type* parameter_type,
    1766             :     std::vector<VisitResult>* converted_arguments, StackRange* argument_range,
    1767             :     std::vector<std::string>* constexpr_arguments) {
    1768       15378 :   VisitResult converted = GenerateImplicitConvert(parameter_type, parameter);
    1769        7689 :   converted_arguments->push_back(converted);
    1770        7689 :   if (!callable->ShouldBeInlined()) {
    1771        7643 :     if (converted.IsOnStack()) {
    1772             :       argument_range->Extend(converted.stack_range());
    1773             :     } else {
    1774        1722 :       constexpr_arguments->push_back(converted.constexpr_value());
    1775             :     }
    1776             :   }
    1777        7689 : }
    1778             : 
    1779        4230 : VisitResult ImplementationVisitor::GenerateCall(
    1780        8460 :     Callable* callable, base::Optional<LocationReference> this_reference,
    1781             :     Arguments arguments, const TypeVector& specialization_types,
    1782             :     bool is_tailcall) {
    1783             :   // Operators used in a branching context can also be function calls that never
    1784             :   // return but have a True and False label
    1785       17063 :   if (arguments.labels.size() == 0 &&
    1786        3907 :       callable->signature().labels.size() == 2) {
    1787         136 :     Binding<LocalLabel>* true_label = LookupLabel(kTrueLabelName);
    1788          68 :     arguments.labels.push_back(true_label);
    1789         136 :     Binding<LocalLabel>* false_label = LookupLabel(kFalseLabelName);
    1790          68 :     arguments.labels.push_back(false_label);
    1791             :   }
    1792             : 
    1793        4230 :   const Type* return_type = callable->signature().return_type;
    1794             : 
    1795             :   std::vector<VisitResult> converted_arguments;
    1796        4230 :   StackRange argument_range = assembler().TopRange(0);
    1797        4230 :   std::vector<std::string> constexpr_arguments;
    1798             : 
    1799             :   size_t current = 0;
    1800        4230 :   if (this_reference) {
    1801             :     DCHECK(callable->IsMethod());
    1802          24 :     Method* method = Method::cast(callable);
    1803             :     // By now, the this reference should either be a variable or
    1804             :     // a temporary, in both cases the fetch of the VisitResult should succeed.
    1805          24 :     VisitResult this_value = this_reference->GetVisitResult();
    1806          24 :     if (method->ShouldBeInlined()) {
    1807          34 :       if (!this_value.type()->IsSubtypeOf(method->aggregate_type())) {
    1808             :         ReportError("this parameter must be a subtype of ",
    1809           0 :                     *method->aggregate_type());
    1810             :       }
    1811             :     } else {
    1812             :       AddCallParameter(callable, this_value, method->aggregate_type(),
    1813             :                        &converted_arguments, &argument_range,
    1814          14 :                        &constexpr_arguments);
    1815             :     }
    1816             :     ++current;
    1817             :   }
    1818             : 
    1819         492 :   for (; current < callable->signature().implicit_count; ++current) {
    1820         984 :     std::string implicit_name = callable->signature().parameter_names[current];
    1821             :     base::Optional<Binding<LocalValue>*> val =
    1822             :         TryLookupLocalValue(implicit_name);
    1823         492 :     if (!val) {
    1824             :       ReportError("implicit parameter '", implicit_name,
    1825           0 :                   "' required for call to '", callable->ReadableName(),
    1826           0 :                   "' is not defined");
    1827             :     }
    1828             :     AddCallParameter(callable, (*val)->value,
    1829         492 :                      callable->signature().parameter_types.types[current],
    1830             :                      &converted_arguments, &argument_range,
    1831         984 :                      &constexpr_arguments);
    1832             :   }
    1833             : 
    1834       15650 :   for (auto arg : arguments.parameters) {
    1835        7190 :     const Type* to_type = (current >= callable->signature().types().size())
    1836             :                               ? TypeOracle::GetObjectType()
    1837       14380 :                               : callable->signature().types()[current++];
    1838             :     AddCallParameter(callable, arg, to_type, &converted_arguments,
    1839       14380 :                      &argument_range, &constexpr_arguments);
    1840             :   }
    1841             : 
    1842        4230 :   if (GlobalContext::verbose()) {
    1843           0 :     std::cout << "generating code for call to " << callable->ReadableName()
    1844           0 :               << "\n";
    1845             :   }
    1846             : 
    1847        4230 :   size_t label_count = callable->signature().labels.size();
    1848        4230 :   if (label_count != arguments.labels.size()) {
    1849           0 :     std::stringstream s;
    1850           0 :     s << "unexpected number of otherwise labels for "
    1851           0 :       << callable->ReadableName() << " (expected "
    1852           0 :       << std::to_string(label_count) << " found "
    1853           0 :       << std::to_string(arguments.labels.size()) << ")";
    1854           0 :     ReportError(s.str());
    1855             :   }
    1856             : 
    1857        4230 :   if (callable->IsTransitioning()) {
    1858         153 :     if (!CurrentCallable::Get()->IsTransitioning()) {
    1859           0 :       std::stringstream s;
    1860           0 :       s << *CurrentCallable::Get()
    1861           0 :         << " isn't marked transitioning but calls the transitioning "
    1862           0 :         << *callable;
    1863           0 :       ReportError(s.str());
    1864             :     }
    1865             :   }
    1866             : 
    1867        4230 :   if (auto* builtin = Builtin::DynamicCast(callable)) {
    1868          71 :     base::Optional<Block*> catch_block = GetCatchBlock();
    1869          71 :     assembler().Emit(CallBuiltinInstruction{
    1870         284 :         is_tailcall, builtin, argument_range.Size(), catch_block});
    1871          71 :     GenerateCatchBlock(catch_block);
    1872          71 :     if (is_tailcall) {
    1873           1 :       return VisitResult::NeverResult();
    1874             :     } else {
    1875          70 :       size_t slot_count = LoweredSlotCount(return_type);
    1876             :       DCHECK_LE(slot_count, 1);
    1877             :       // TODO(tebbi): Actually, builtins have to return a value, so we should
    1878             :       // assert slot_count == 1 here.
    1879             :       return VisitResult(return_type, assembler().TopRange(slot_count));
    1880             :     }
    1881        4159 :   } else if (auto* macro = Macro::DynamicCast(callable)) {
    1882        4077 :     if (is_tailcall) {
    1883           0 :       ReportError("can't tail call a macro");
    1884             :     }
    1885        4077 :     if (return_type->IsConstexpr()) {
    1886             :       DCHECK_EQ(0, arguments.labels.size());
    1887          98 :       std::stringstream result;
    1888         196 :       result << "(" << macro->external_assembler_name() << "(state_)."
    1889          98 :              << macro->ExternalName() << "(";
    1890             :       bool first = true;
    1891         313 :       for (VisitResult arg : arguments.parameters) {
    1892             :         DCHECK(!arg.IsOnStack());
    1893         117 :         if (!first) {
    1894          54 :           result << ", ";
    1895             :         }
    1896             :         first = false;
    1897             :         result << arg.constexpr_value();
    1898             :       }
    1899          98 :       result << "))";
    1900          98 :       return VisitResult(return_type, result.str());
    1901        3979 :     } else if (macro->ShouldBeInlined()) {
    1902             :       std::vector<Block*> label_blocks;
    1903          37 :       for (Binding<LocalLabel>* label : arguments.labels) {
    1904           1 :         label_blocks.push_back(label->block);
    1905             :       }
    1906             :       return InlineMacro(macro, this_reference, converted_arguments,
    1907          72 :                          label_blocks);
    1908        7532 :     } else if (arguments.labels.empty() &&
    1909        3571 :                return_type != TypeOracle::GetNeverType()) {
    1910        3541 :       base::Optional<Block*> catch_block = GetCatchBlock();
    1911        3541 :       assembler().Emit(
    1912       14164 :           CallCsaMacroInstruction{macro, constexpr_arguments, catch_block});
    1913        3541 :       GenerateCatchBlock(catch_block);
    1914        3541 :       size_t return_slot_count = LoweredSlotCount(return_type);
    1915             :       return VisitResult(return_type, assembler().TopRange(return_slot_count));
    1916             :     } else {
    1917             :       base::Optional<Block*> return_continuation;
    1918         420 :       if (return_type != TypeOracle::GetNeverType()) {
    1919         626 :         return_continuation = assembler().NewBlock();
    1920             :       }
    1921             : 
    1922             :       std::vector<Block*> label_blocks;
    1923             : 
    1924         886 :       for (size_t i = 0; i < label_count; ++i) {
    1925        1398 :         label_blocks.push_back(assembler().NewBlock());
    1926             :       }
    1927         420 :       base::Optional<Block*> catch_block = GetCatchBlock();
    1928         420 :       assembler().Emit(CallCsaMacroAndBranchInstruction{
    1929             :           macro, constexpr_arguments, return_continuation, label_blocks,
    1930        2100 :           catch_block});
    1931         420 :       GenerateCatchBlock(catch_block);
    1932             : 
    1933         886 :       for (size_t i = 0; i < label_count; ++i) {
    1934         466 :         Binding<LocalLabel>* label = arguments.labels[i];
    1935             :         size_t callee_label_parameters =
    1936         932 :             callable->signature().labels[i].types.size();
    1937         946 :         if (label->parameter_types.size() != callee_label_parameters) {
    1938           0 :           std::stringstream s;
    1939           0 :           s << "label " << label->name()
    1940           0 :             << " doesn't have the right number of parameters (found "
    1941           0 :             << std::to_string(label->parameter_types.size()) << " expected "
    1942           0 :             << std::to_string(callee_label_parameters) << ")";
    1943           0 :           ReportError(s.str());
    1944             :         }
    1945         932 :         assembler().Bind(label_blocks[i]);
    1946             :         assembler().Goto(
    1947             :             label->block,
    1948        1864 :             LowerParameterTypes(callable->signature().labels[i].types).size());
    1949             : 
    1950             :         size_t j = 0;
    1951        1412 :         for (auto t : callable->signature().labels[i].types) {
    1952          14 :           const Type* parameter_type = label->parameter_types[j];
    1953          14 :           if (parameter_type != t) {
    1954             :             ReportError("mismatch of label parameters (expected ", *t, " got ",
    1955           0 :                         parameter_type, " for parameter ", i + 1, ")");
    1956             :           }
    1957          14 :           j++;
    1958             :         }
    1959             :       }
    1960             : 
    1961         420 :       if (return_continuation) {
    1962         313 :         assembler().Bind(*return_continuation);
    1963         313 :         size_t return_slot_count = LoweredSlotCount(return_type);
    1964             :         return VisitResult(return_type,
    1965             :                            assembler().TopRange(return_slot_count));
    1966             :       } else {
    1967         107 :         return VisitResult::NeverResult();
    1968             :       }
    1969             :     }
    1970          82 :   } else if (auto* runtime_function = RuntimeFunction::DynamicCast(callable)) {
    1971          20 :     base::Optional<Block*> catch_block = GetCatchBlock();
    1972          20 :     assembler().Emit(CallRuntimeInstruction{
    1973          80 :         is_tailcall, runtime_function, argument_range.Size(), catch_block});
    1974          20 :     GenerateCatchBlock(catch_block);
    1975          20 :     if (is_tailcall || return_type == TypeOracle::GetNeverType()) {
    1976           5 :       return VisitResult::NeverResult();
    1977             :     } else {
    1978          15 :       size_t slot_count = LoweredSlotCount(return_type);
    1979             :       DCHECK_LE(slot_count, 1);
    1980             :       // TODO(tebbi): Actually, runtime functions have to return a value, so
    1981             :       // we should assert slot_count == 1 here.
    1982             :       return VisitResult(return_type, assembler().TopRange(slot_count));
    1983             :     }
    1984          62 :   } else if (auto* intrinsic = Intrinsic::DynamicCast(callable)) {
    1985         124 :     if (intrinsic->ExternalName() == "%RawConstexprCast") {
    1986           3 :       if (intrinsic->signature().parameter_types.types.size() != 1 ||
    1987           1 :           constexpr_arguments.size() != 1) {
    1988             :         ReportError(
    1989             :             "%RawConstexprCast must take a single parameter with constexpr "
    1990           0 :             "type");
    1991             :       }
    1992           1 :       if (!return_type->IsConstexpr()) {
    1993           0 :         std::stringstream s;
    1994           0 :         s << *return_type
    1995           0 :           << " return type for %RawConstexprCast is not constexpr";
    1996           0 :         ReportError(s.str());
    1997             :       }
    1998           1 :       std::stringstream result;
    1999           3 :       result << "static_cast<" << return_type->GetGeneratedTypeName() << ">(";
    2000           1 :       result << constexpr_arguments[0];
    2001           1 :       result << ")";
    2002           1 :       return VisitResult(return_type, result.str());
    2003             :     } else {
    2004          61 :       assembler().Emit(
    2005         305 :           CallIntrinsicInstruction{intrinsic, constexpr_arguments});
    2006             :       size_t return_slot_count =
    2007          61 :           LoweredSlotCount(intrinsic->signature().return_type);
    2008             :       return VisitResult(return_type, assembler().TopRange(return_slot_count));
    2009             :     }
    2010             :   } else {
    2011           0 :     UNREACHABLE();
    2012        4230 :   }
    2013             : }
    2014             : 
    2015        4206 : VisitResult ImplementationVisitor::GenerateCall(
    2016             :     const QualifiedName& callable_name, Arguments arguments,
    2017             :     const TypeVector& specialization_types, bool is_tailcall) {
    2018             :   Callable* callable =
    2019             :       LookupCall(callable_name, Declarations::Lookup(callable_name), arguments,
    2020        8412 :                  specialization_types);
    2021             :   return GenerateCall(callable, base::nullopt, arguments, specialization_types,
    2022       12618 :                       is_tailcall);
    2023             : }
    2024             : 
    2025        2476 : VisitResult ImplementationVisitor::Visit(CallExpression* expr,
    2026             :                                          bool is_tailcall) {
    2027             :   StackScope scope(this);
    2028        2476 :   Arguments arguments;
    2029             :   QualifiedName name =
    2030        9904 :       QualifiedName(expr->callee->namespace_qualification, expr->callee->name);
    2031             :   TypeVector specialization_types =
    2032        2476 :       GetTypeVector(expr->callee->generic_arguments);
    2033             :   bool has_template_arguments = !specialization_types.empty();
    2034       10029 :   for (Expression* arg : expr->arguments)
    2035       10154 :     arguments.parameters.push_back(Visit(arg));
    2036        4952 :   arguments.labels = LabelsFromIdentifiers(expr->labels);
    2037        9452 :   if (!has_template_arguments && name.namespace_qualification.empty() &&
    2038        6458 :       TryLookupLocalValue(name.name)) {
    2039             :     return scope.Yield(
    2040          72 :         GeneratePointerCall(expr->callee, arguments, is_tailcall));
    2041             :   } else {
    2042             :     return scope.Yield(
    2043        7320 :         GenerateCall(name, arguments, specialization_types, is_tailcall));
    2044             :   }
    2045             : }
    2046             : 
    2047           7 : VisitResult ImplementationVisitor::Visit(CallMethodExpression* expr) {
    2048             :   StackScope scope(this);
    2049           7 :   Arguments arguments;
    2050           7 :   std::string method_name = expr->method->name;
    2051             :   TypeVector specialization_types =
    2052           7 :       GetTypeVector(expr->method->generic_arguments);
    2053          14 :   if (method_name == kConstructMethodName || method_name == kSuperMethodName) {
    2054           6 :     if (CurrentConstructorInfo::Get()) {
    2055             :       ConstructorInfo& info = *CurrentConstructorInfo::Get();
    2056           6 :       if (method_name == kSuperMethodName) {
    2057           6 :         if (info.accessed_this) {
    2058           0 :           ReportError("cannot call super after accessing \"this\"");
    2059             :         }
    2060           6 :         if (info.super_calls != 0) {
    2061           0 :           ReportError("\"super\" can only be called once from a constructor");
    2062             :         }
    2063           6 :         ++info.super_calls;
    2064             :       } else {
    2065           0 :         ReportError("cannot call a constructor from a constructor");
    2066             :       }
    2067             :     } else {
    2068             :       ReportError(
    2069           0 :           "cannot call a constructor or \"super\" from a non-constructor");
    2070             :     }
    2071             :   }
    2072             :   const AggregateType* target_type;
    2073          14 :   LocationReference target = GetLocationReference(expr->target);
    2074           7 :   if (target.IsVariableAccess()) {
    2075           1 :     target_type = AggregateType::DynamicCast(target.variable().type());
    2076             :   } else {
    2077           6 :     VisitResult result = GenerateFetchFromLocation(target);
    2078          24 :     target = LocationReference::Temporary(result, "method target result");
    2079           6 :     target_type = AggregateType::DynamicCast(result.type());
    2080             :   }
    2081           7 :   if (!target_type) {
    2082           0 :     ReportError("target of method call not a struct or class type");
    2083             :   }
    2084          30 :   for (Expression* arg : expr->arguments)
    2085          32 :     arguments.parameters.push_back(Visit(arg));
    2086          14 :   arguments.labels = LabelsFromIdentifiers(expr->labels);
    2087           7 :   TypeVector argument_types = arguments.parameters.GetTypeVector();
    2088             :   DCHECK_EQ(expr->method->namespace_qualification.size(), 0);
    2089          21 :   QualifiedName qualified_name = QualifiedName(method_name);
    2090             :   Callable* callable = nullptr;
    2091           7 :   if (method_name == kConstructMethodName) {
    2092             :     callable =
    2093           0 :         LookupCall(qualified_name, target_type->Constructors(), arguments, {});
    2094           7 :   } else if (method_name == kSuperMethodName) {
    2095           6 :     if (!target_type->IsClassType()) {
    2096           0 :       ReportError("cannot call super in struct constructor");
    2097             :     }
    2098             :     target_type = ClassType::cast(target_type)->GetSuperClass();
    2099           6 :     if (!target_type) {
    2100           0 :       ReportError("cannot call \"super\" on a class with no superclass");
    2101             :     }
    2102             :     callable = LookupCall(QualifiedName(kConstructMethodName),
    2103          24 :                           target_type->Constructors(), arguments, {});
    2104             :   } else {
    2105             :     callable = LookupCall(qualified_name, target_type->Methods(method_name),
    2106           3 :                           arguments, {});
    2107             :   }
    2108          35 :   return scope.Yield(GenerateCall(callable, target, arguments, {}, false));
    2109             : }
    2110             : 
    2111          13 : VisitResult ImplementationVisitor::Visit(LoadObjectFieldExpression* expr) {
    2112          13 :   VisitResult base_result = Visit(expr->base);
    2113          13 :   auto class_type = ClassType::DynamicCast(base_result.type());
    2114          13 :   if (!class_type) {
    2115             :     ReportError(
    2116             :         "base expression for a LoadObjectFieldExpression is not a class type "
    2117             :         "but instead ",
    2118           0 :         *base_result.type());
    2119             :   }
    2120          13 :   VisitResult result = base_result;
    2121          65 :   assembler().Emit(LoadObjectFieldInstruction{class_type, expr->field_name});
    2122          13 :   const Field& field = class_type->LookupField(expr->field_name);
    2123          13 :   result.SetType(field.name_and_type.type);
    2124          13 :   return result;
    2125             : }
    2126             : 
    2127          25 : VisitResult ImplementationVisitor::Visit(StoreObjectFieldExpression* expr) {
    2128          25 :   VisitResult base_result = Visit(expr->base);
    2129          25 :   auto class_type = ClassType::DynamicCast(base_result.type());
    2130          25 :   if (!class_type) {
    2131             :     ReportError(
    2132             :         "base expression for a StoreObjectFieldExpression is not a class type "
    2133             :         "but instead ",
    2134           0 :         *base_result.type());
    2135             :   }
    2136          25 :   VisitResult value = Visit(expr->value);
    2137         125 :   assembler().Emit(StoreObjectFieldInstruction{class_type, expr->field_name});
    2138          50 :   return VisitResult(value.type(), assembler().TopRange(0));
    2139             : }
    2140             : 
    2141          61 : VisitResult ImplementationVisitor::Visit(IntrinsicCallExpression* expr) {
    2142             :   StackScope scope(this);
    2143          61 :   Arguments arguments;
    2144          61 :   TypeVector specialization_types = GetTypeVector(expr->generic_arguments);
    2145         183 :   for (Expression* arg : expr->arguments)
    2146         122 :     arguments.parameters.push_back(Visit(arg));
    2147             :   return scope.Yield(
    2148         244 :       GenerateCall(expr->name, arguments, specialization_types, false));
    2149             : }
    2150             : 
    2151           0 : void ImplementationVisitor::GenerateBranch(const VisitResult& condition,
    2152             :                                            Block* true_block,
    2153             :                                            Block* false_block) {
    2154             :   DCHECK_EQ(condition,
    2155             :             VisitResult(TypeOracle::GetBoolType(), assembler().TopRange(1)));
    2156         520 :   assembler().Branch(true_block, false_block);
    2157           0 : }
    2158             : 
    2159         603 : void ImplementationVisitor::GenerateExpressionBranch(Expression* expression,
    2160             :                                                      Block* true_block,
    2161             :                                                      Block* false_block) {
    2162             :   // Conditional expressions can either explicitly return a bit
    2163             :   // type, or they can be backed by macros that don't return but
    2164             :   // take a true and false label. By declaring the labels before
    2165             :   // visiting the conditional expression, those label-based
    2166             :   // macro conditionals will be able to find them through normal
    2167             :   // label lookups.
    2168             :   Binding<LocalLabel> true_binding{&LabelBindingsManager::Get(), kTrueLabelName,
    2169        2412 :                                    LocalLabel{true_block}};
    2170             :   Binding<LocalLabel> false_binding{&LabelBindingsManager::Get(),
    2171        3015 :                                     kFalseLabelName, LocalLabel{false_block}};
    2172             :   StackScope stack_scope(this);
    2173         603 :   VisitResult expression_result = Visit(expression);
    2174         603 :   if (!expression_result.type()->IsNever()) {
    2175        2080 :     expression_result = stack_scope.Yield(
    2176         520 :         GenerateImplicitConvert(TypeOracle::GetBoolType(), expression_result));
    2177             :     GenerateBranch(expression_result, true_block, false_block);
    2178         603 :   }
    2179         603 : }
    2180             : 
    2181       10478 : VisitResult ImplementationVisitor::GenerateImplicitConvert(
    2182       22904 :     const Type* destination_type, VisitResult source) {
    2183             :   StackScope scope(this);
    2184       10478 :   if (source.type() == TypeOracle::GetNeverType()) {
    2185           0 :     ReportError("it is not allowed to use a value of type never");
    2186             :   }
    2187             : 
    2188       10478 :   if (destination_type == source.type()) {
    2189       17060 :     return scope.Yield(GenerateCopy(source));
    2190             :   }
    2191             : 
    2192        1948 :   if (TypeOracle::IsImplicitlyConvertableFrom(destination_type,
    2193             :                                               source.type())) {
    2194             :     return scope.Yield(GenerateCall(kFromConstexprMacroName, {{source}, {}},
    2195        8960 :                                     {destination_type, source.type()}, false));
    2196         828 :   } else if (IsAssignableFrom(destination_type, source.type())) {
    2197             :     source.SetType(destination_type);
    2198        1656 :     return scope.Yield(GenerateCopy(source));
    2199             :   } else {
    2200           0 :     std::stringstream s;
    2201           0 :     s << "cannot use expression of type " << *source.type()
    2202           0 :       << " as a value of type " << *destination_type;
    2203           0 :     ReportError(s.str());
    2204             :   }
    2205             : }
    2206             : 
    2207           0 : StackRange ImplementationVisitor::GenerateLabelGoto(
    2208           0 :     LocalLabel* label, base::Optional<StackRange> arguments) {
    2209         411 :   return assembler().Goto(label->block, arguments ? arguments->Size() : 0);
    2210             : }
    2211             : 
    2212        2483 : std::vector<Binding<LocalLabel>*> ImplementationVisitor::LabelsFromIdentifiers(
    2213        2483 :     const std::vector<std::string>& names) {
    2214             :   std::vector<Binding<LocalLabel>*> result;
    2215        2483 :   result.reserve(names.size());
    2216        5297 :   for (const auto& name : names) {
    2217         662 :     result.push_back(LookupLabel(name));
    2218             :   }
    2219        2483 :   return result;
    2220             : }
    2221             : 
    2222         908 : StackRange ImplementationVisitor::LowerParameter(
    2223             :     const Type* type, const std::string& parameter_name,
    2224             :     Stack<std::string>* lowered_parameters) {
    2225         908 :   if (type->IsStructType()) {
    2226             :     const StructType* struct_type = StructType::cast(type);
    2227             :     StackRange range = lowered_parameters->TopRange(0);
    2228          27 :     for (auto& field : struct_type->fields()) {
    2229             :       StackRange parameter_range = LowerParameter(
    2230             :           field.name_and_type.type,
    2231          68 :           parameter_name + "." + field.name_and_type.name, lowered_parameters);
    2232             :       range.Extend(parameter_range);
    2233             :     }
    2234           5 :     return range;
    2235             :   } else {
    2236        1806 :     lowered_parameters->Push(parameter_name);
    2237             :     return lowered_parameters->TopRange(1);
    2238             :   }
    2239             : }
    2240             : 
    2241           0 : std::string ImplementationVisitor::ExternalLabelName(
    2242             :     const std::string& label_name) {
    2243         387 :   return "label_" + label_name;
    2244             : }
    2245             : 
    2246          36 : std::string ImplementationVisitor::ExternalLabelParameterName(
    2247             :     const std::string& label_name, size_t i) {
    2248         180 :   return "label_" + label_name + "_parameter_" + std::to_string(i);
    2249             : }
    2250             : 
    2251        2886 : std::string ImplementationVisitor::ExternalParameterName(
    2252             :     const std::string& name) {
    2253        5772 :   return std::string("p_") + name;
    2254             : }
    2255             : 
    2256           0 : DEFINE_CONTEXTUAL_VARIABLE(ImplementationVisitor::ValueBindingsManager);
    2257           0 : DEFINE_CONTEXTUAL_VARIABLE(ImplementationVisitor::LabelBindingsManager);
    2258           0 : DEFINE_CONTEXTUAL_VARIABLE(ImplementationVisitor::CurrentCallable);
    2259           0 : DEFINE_CONTEXTUAL_VARIABLE(ImplementationVisitor::CurrentReturnValue);
    2260           0 : DEFINE_CONTEXTUAL_VARIABLE(ImplementationVisitor::CurrentConstructorInfo);
    2261             : 
    2262       28386 : bool IsCompatibleSignature(const Signature& sig, const TypeVector& types,
    2263       14112 :                            const std::vector<Binding<LocalLabel>*>& labels) {
    2264       46619 :   auto i = sig.parameter_types.types.begin() + sig.implicit_count;
    2265       28386 :   if ((sig.parameter_types.types.size() - sig.implicit_count) > types.size())
    2266             :     return false;
    2267             :   // TODO(danno): The test below is actually insufficient. The labels'
    2268             :   // parameters must be checked too. ideally, the named part of
    2269             :   // LabelDeclarationVector would be factored out so that the label count and
    2270             :   // parameter types could be passed separately.
    2271       28224 :   if (sig.labels.size() != labels.size()) return false;
    2272       41457 :   for (auto current : types) {
    2273       18233 :     if (i == sig.parameter_types.types.end()) {
    2274          55 :       if (!sig.parameter_types.var_args) return false;
    2275           0 :       if (!IsAssignableFrom(TypeOracle::GetObjectType(), current)) return false;
    2276             :     } else {
    2277       18178 :       if (!IsAssignableFrom(*i++, current)) return false;
    2278             :     }
    2279             :   }
    2280             :   return true;
    2281             : }
    2282             : 
    2283        4052 : base::Optional<Block*> ImplementationVisitor::GetCatchBlock() {
    2284        4052 :   base::Optional<Block*> catch_block;
    2285        4052 :   if (base::Optional<Binding<LocalLabel>*> catch_handler =
    2286        8104 :           TryLookupLabel("_catch")) {
    2287          44 :     catch_block = assembler().NewBlock(base::nullopt, true);
    2288             :   }
    2289        4052 :   return catch_block;
    2290             : }
    2291             : 
    2292        4052 : void ImplementationVisitor::GenerateCatchBlock(
    2293        4052 :     base::Optional<Block*> catch_block) {
    2294        4052 :   if (catch_block) {
    2295             :     base::Optional<Binding<LocalLabel>*> catch_handler =
    2296          44 :         TryLookupLabel("_catch");
    2297          44 :     if (assembler().CurrentBlockIsComplete()) {
    2298           4 :       assembler().Bind(*catch_block);
    2299           4 :       assembler().Goto((*catch_handler)->block, 1);
    2300             :     } else {
    2301          18 :       CfgAssemblerScopedTemporaryBlock temp(&assembler(), *catch_block);
    2302          18 :       assembler().Goto((*catch_handler)->block, 1);
    2303             :     }
    2304             :   }
    2305        4052 : }
    2306             : 
    2307           1 : void ImplementationVisitor::VisitAllDeclarables() {
    2308        5011 :   const std::vector<std::unique_ptr<Declarable>>& all_declarables =
    2309             :       GlobalContext::AllDeclarables();
    2310             :   // This has to be an index-based loop because all_declarables can be extended
    2311             :   // during the loop.
    2312       10022 :   for (size_t i = 0; i < all_declarables.size(); ++i) {
    2313        5010 :     Visit(all_declarables[i].get());
    2314             :   }
    2315           1 : }
    2316             : 
    2317       15030 : void ImplementationVisitor::Visit(Declarable* declarable) {
    2318             :   CurrentConstructorInfo::Scope current_constructor(base::nullopt);
    2319        5010 :   CurrentScope::Scope current_scope(declarable->ParentScope());
    2320        5010 :   CurrentSourcePosition::Scope current_source_position(declarable->pos());
    2321        5010 :   switch (declarable->kind()) {
    2322             :     case Declarable::kMacro:
    2323         783 :       return Visit(Macro::cast(declarable));
    2324             :     case Declarable::kMethod:
    2325          20 :       return Visit(Method::cast(declarable));
    2326             :     case Declarable::kBuiltin:
    2327         134 :       return Visit(Builtin::cast(declarable));
    2328             :     case Declarable::kTypeAlias:
    2329        3845 :       return Visit(TypeAlias::cast(declarable));
    2330             :     case Declarable::kNamespaceConstant:
    2331          40 :       return Visit(NamespaceConstant::cast(declarable));
    2332             :     case Declarable::kRuntimeFunction:
    2333             :     case Declarable::kIntrinsic:
    2334             :     case Declarable::kExternConstant:
    2335             :     case Declarable::kNamespace:
    2336             :     case Declarable::kGeneric:
    2337             :       return;
    2338             :   }
    2339             : }
    2340             : 
    2341           1 : void ImplementationVisitor::GenerateBuiltinDefinitions(std::string& file_name) {
    2342           1 :   std::stringstream new_contents_stream;
    2343             :   new_contents_stream
    2344             :       << "#ifndef V8_BUILTINS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n"
    2345             :          "#define V8_BUILTINS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n"
    2346             :          "\n"
    2347             :          "#define BUILTIN_LIST_FROM_DSL(CPP, API, TFJ, TFC, TFS, TFH, ASM) "
    2348           1 :          "\\\n";
    2349        5012 :   for (auto& declarable : GlobalContext::AllDeclarables()) {
    2350         167 :     Builtin* builtin = Builtin::DynamicCast(declarable.get());
    2351        5144 :     if (!builtin || builtin->IsExternal()) continue;
    2352             :     int firstParameterIndex = 1;
    2353             :     bool declareParameters = true;
    2354         120 :     if (builtin->IsStub()) {
    2355          73 :       new_contents_stream << "TFS(" << builtin->ExternalName();
    2356             :     } else {
    2357          47 :       new_contents_stream << "TFJ(" << builtin->ExternalName();
    2358          47 :       if (builtin->IsVarArgsJavaScript()) {
    2359             :         new_contents_stream
    2360          43 :             << ", SharedFunctionInfo::kDontAdaptArgumentsSentinel";
    2361             :         declareParameters = false;
    2362             :       } else {
    2363             :         assert(builtin->IsFixedArgsJavaScript());
    2364             :         // FixedArg javascript builtins need to offer the parameter
    2365             :         // count.
    2366             :         assert(builtin->parameter_names().size() >= 2);
    2367           8 :         new_contents_stream << ", " << (builtin->parameter_names().size() - 2);
    2368             :         // And the receiver is explicitly declared.
    2369           4 :         new_contents_stream << ", kReceiver";
    2370             :         firstParameterIndex = 2;
    2371             :       }
    2372             :     }
    2373         120 :     if (declareParameters) {
    2374             :       int index = 0;
    2375         472 :       for (const auto& parameter : builtin->parameter_names()) {
    2376         318 :         if (index >= firstParameterIndex) {
    2377         474 :           new_contents_stream << ", k" << CamelifyString(parameter);
    2378             :         }
    2379         318 :         index++;
    2380             :       }
    2381             :     }
    2382         120 :     new_contents_stream << ") \\\n";
    2383             :   }
    2384           1 :   new_contents_stream << "\n";
    2385             : 
    2386             :   new_contents_stream
    2387           1 :       << "#define TORQUE_FUNCTION_POINTER_TYPE_TO_BUILTIN_MAP(V) \\\n";
    2388          22 :   for (const BuiltinPointerType* type : TypeOracle::AllBuiltinPointerTypes()) {
    2389             :     Builtin* example_builtin =
    2390          10 :         Declarations::FindSomeInternalBuiltinWithType(type);
    2391          10 :     if (!example_builtin) {
    2392             :       CurrentSourcePosition::Scope current_source_position(
    2393           0 :           SourcePosition{CurrentSourceFile::Get(), -1, -1});
    2394           0 :       ReportError("unable to find any builtin with type \"", *type, "\"");
    2395             :     }
    2396          20 :     new_contents_stream << "  V(" << type->function_pointer_type_id() << ","
    2397          10 :                         << example_builtin->ExternalName() << ")\\\n";
    2398             :   }
    2399           1 :   new_contents_stream << "\n";
    2400             : 
    2401             :   new_contents_stream
    2402           1 :       << "#endif  // V8_BUILTINS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n";
    2403             : 
    2404             :   std::string new_contents(new_contents_stream.str());
    2405           2 :   ReplaceFileContentsIfDifferent(file_name, new_contents);
    2406           1 : }
    2407             : 
    2408           1 : void ImplementationVisitor::GenerateClassDefinitions(std::string& file_name) {
    2409           1 :   std::stringstream new_contents_stream;
    2410             :   new_contents_stream << "#ifndef V8_CLASS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n"
    2411             :                          "#define V8_CLASS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n"
    2412           1 :                          "\n\n";
    2413             : 
    2414           9 :   for (auto i : GlobalContext::GetClasses()) {
    2415             :     // TODO(danno): Ideally (and we've got several core V8 dev's feedback
    2416             :     // supporting this), Torque should generate the constants for the offsets
    2417             :     // directly and not go through the existing layer of macros, which actually
    2418             :     // currently just serves to additionally obfuscate where these values come
    2419             :     // from.
    2420           7 :     new_contents_stream << "#define ";
    2421          14 :     new_contents_stream << CapifyStringWithUnderscores(i.first)
    2422           7 :                         << "_FIELDS(V) \\\n";
    2423           7 :     const ClassType* type = i.second;
    2424          14 :     std::vector<Field> fields = type->fields();
    2425           7 :     new_contents_stream << "V(kStartOfStrongFieldsOffset, 0) \\\n";
    2426          27 :     for (auto f : fields) {
    2427          13 :       if (!f.is_weak) {
    2428          22 :         new_contents_stream << "V(k" << CamelifyString(f.name_and_type.name)
    2429          11 :                             << "Offset, kTaggedSize) \\\n";
    2430             :       }
    2431             :     }
    2432           7 :     new_contents_stream << "V(kEndOfStrongFieldsOffset, 0) \\\n";
    2433           7 :     new_contents_stream << "V(kStartOfWeakFieldsOffset, 0) \\\n";
    2434          27 :     for (auto f : fields) {
    2435          13 :       if (f.is_weak) {
    2436           4 :         new_contents_stream << "V(k" << CamelifyString(f.name_and_type.name)
    2437           2 :                             << "Offset, kTaggedSize) \\\n";
    2438             :       }
    2439             :     }
    2440           7 :     new_contents_stream << "V(kEndOfWeakFieldsOffset, 0) \\\n";
    2441           7 :     new_contents_stream << "V(kSize, 0) \\\n";
    2442           7 :     new_contents_stream << "\n";
    2443             :   }
    2444             : 
    2445             :   new_contents_stream
    2446           1 :       << "\n#endif  // V8_CLASS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n";
    2447             : 
    2448             :   std::string new_contents(new_contents_stream.str());
    2449           2 :   ReplaceFileContentsIfDifferent(file_name, new_contents);
    2450           1 : }
    2451             : 
    2452             : }  // namespace torque
    2453             : }  // namespace internal
    2454        9078 : }  // namespace v8

Generated by: LCOV version 1.10