LCOV - code coverage report
Current view: top level - src/torque - implementation-visitor.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 1288 1509 85.4 %
Date: 2019-04-17 Functions: 95 110 86.4 %

          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/globals.h"
       8             : #include "src/torque/csa-generator.h"
       9             : #include "src/torque/declaration-visitor.h"
      10             : #include "src/torque/implementation-visitor.h"
      11             : #include "src/torque/parameter-difference.h"
      12             : #include "src/torque/server-data.h"
      13             : 
      14             : namespace v8 {
      15             : namespace internal {
      16             : namespace torque {
      17             : 
      18       13495 : VisitResult ImplementationVisitor::Visit(Expression* expr) {
      19       13495 :   CurrentSourcePosition::Scope scope(expr->pos);
      20       13495 :   switch (expr->kind) {
      21             : #define ENUM_ITEM(name)        \
      22             :   case AstNode::Kind::k##name: \
      23             :     return Visit(name::cast(expr));
      24       13495 :     AST_EXPRESSION_NODE_KIND_LIST(ENUM_ITEM)
      25             : #undef ENUM_ITEM
      26             :     default:
      27           0 :       UNREACHABLE();
      28             :   }
      29             : }
      30             : 
      31        5836 : const Type* ImplementationVisitor::Visit(Statement* stmt) {
      32        5836 :   CurrentSourcePosition::Scope scope(stmt->pos);
      33             :   StackScope stack_scope(this);
      34             :   const Type* result;
      35        5836 :   switch (stmt->kind) {
      36             : #define ENUM_ITEM(name)               \
      37             :   case AstNode::Kind::k##name:        \
      38             :     result = Visit(name::cast(stmt)); \
      39             :     break;
      40        5836 :     AST_STATEMENT_NODE_KIND_LIST(ENUM_ITEM)
      41             : #undef ENUM_ITEM
      42             :     default:
      43           0 :       UNREACHABLE();
      44             :   }
      45             :   DCHECK_EQ(result == TypeOracle::GetNeverType(),
      46             :             assembler().CurrentBlockIsComplete());
      47        5836 :   return result;
      48             : }
      49             : 
      50          44 : void ImplementationVisitor::BeginNamespaceFile(Namespace* nspace) {
      51             :   std::ostream& source = nspace->source_stream();
      52             :   std::ostream& header = nspace->header_stream();
      53             : 
      54        1556 :   for (const std::string& include_path : GlobalContext::CppIncludes()) {
      55        4536 :     source << "#include " << StringLiteralQuote(include_path) << "\n";
      56             :   }
      57             : 
      58          44 :   for (Namespace* n : GlobalContext::Get().GetNamespaces()) {
      59        3532 :     source << "#include \"torque-generated/builtins-" +
      60        7064 :                   DashifyString(n->name()) + "-from-dsl-gen.h\"\n";
      61             :   }
      62          44 :   source << "\n";
      63             : 
      64             :   source << "namespace v8 {\n"
      65             :          << "namespace internal {\n"
      66          44 :          << "\n";
      67             : 
      68             :   std::string upper_name(nspace->name());
      69             :   transform(upper_name.begin(), upper_name.end(), upper_name.begin(),
      70             :             ::toupper);
      71             :   std::string headerDefine =
      72         132 :       std::string("V8_TORQUE_") + upper_name + "_FROM_DSL_BASE_H__";
      73          44 :   header << "#ifndef " << headerDefine << "\n";
      74          44 :   header << "#define " << headerDefine << "\n\n";
      75          44 :   header << "#include \"src/compiler/code-assembler.h\"\n";
      76          44 :   if (nspace != GlobalContext::GetDefaultNamespace()) {
      77          41 :     header << "#include \"src/code-stub-assembler.h\"\n";
      78             :   }
      79          44 :   header << "#include \"src/utils.h\"\n";
      80          44 :   header << "#include \"torque-generated/class-definitions-from-dsl.h\"\n";
      81          44 :   header << "\n";
      82             : 
      83             :   header << "namespace v8 {\n"
      84             :          << "namespace internal {\n"
      85          44 :          << "\n";
      86             : 
      87          44 :   header << "class ";
      88          44 :   if (nspace->IsTestNamespace()) {
      89           1 :     header << "V8_EXPORT_PRIVATE ";
      90             :   }
      91         132 :   header << nspace->ExternalName() << " {\n";
      92          44 :   header << " public:\n";
      93          88 :   header << "  explicit " << nspace->ExternalName()
      94             :          << "(compiler::CodeAssemblerState* state) : state_(state), ca_(state) "
      95          44 :             "{ USE(state_, ca_); }\n";
      96          44 : }
      97             : 
      98          42 : void ImplementationVisitor::EndNamespaceFile(Namespace* nspace) {
      99             :   std::ostream& source = nspace->source_stream();
     100             :   std::ostream& header = nspace->header_stream();
     101             : 
     102             :   std::string upper_name(nspace->name());
     103             :   transform(upper_name.begin(), upper_name.end(), upper_name.begin(),
     104             :             ::toupper);
     105             :   std::string headerDefine =
     106         126 :       std::string("V8_TORQUE_") + upper_name + "_FROM_DSL_BASE_H__";
     107             : 
     108             :   source << "}  // namespace internal\n"
     109             :          << "}  // namespace v8\n"
     110          42 :          << "\n";
     111             : 
     112             :   header << " private:\n"
     113             :          << "  compiler::CodeAssemblerState* const state_;\n"
     114             :          << "  compiler::CodeAssembler ca_;\n"
     115          42 :          << "};\n\n";
     116             :   header << "}  // namespace internal\n"
     117             :          << "}  // namespace v8\n"
     118          42 :          << "\n";
     119          42 :   header << "#endif  // " << headerDefine << "\n";
     120          42 : }
     121             : 
     122          33 : void ImplementationVisitor::Visit(NamespaceConstant* decl) {
     123         198 :   Signature signature{{}, base::nullopt, {{}, false}, 0, decl->type(), {}};
     124          33 :   const std::string& name = decl->name()->value;
     125             : 
     126          66 :   BindingsManagersScope bindings_managers_scope;
     127             : 
     128          33 :   header_out() << "  ";
     129          99 :   GenerateFunctionDeclaration(header_out(), "", name, signature, {});
     130          33 :   header_out() << ";\n";
     131             : 
     132          66 :   GenerateFunctionDeclaration(source_out(),
     133          99 :                               CurrentNamespace()->ExternalName() + "::", name,
     134          33 :                               signature, {});
     135          33 :   source_out() << " {\n";
     136             : 
     137             :   DCHECK(!signature.return_type->IsVoidOrNever());
     138             : 
     139          99 :   assembler_ = CfgAssembler(Stack<const Type*>{});
     140             : 
     141          33 :   VisitResult expression_result = Visit(decl->body());
     142             :   VisitResult return_result =
     143          66 :       GenerateImplicitConvert(signature.return_type, expression_result);
     144             : 
     145          33 :   CSAGenerator csa_generator{assembler().Result(), source_out()};
     146          99 :   Stack<std::string> values = *csa_generator.EmitGraph(Stack<std::string>{});
     147             : 
     148             :   assembler_ = base::nullopt;
     149             : 
     150          33 :   source_out() << "return ";
     151          99 :   CSAGenerator::EmitCSAValue(return_result, values, source_out());
     152          33 :   source_out() << ";\n";
     153          33 :   source_out() << "}\n\n";
     154          33 : }
     155             : 
     156        5526 : void ImplementationVisitor::Visit(TypeAlias* alias) {
     157        5526 :   if (alias->IsRedeclaration()) return;
     158             :   const ClassType* class_type = ClassType::DynamicCast(alias->type());
     159         269 :   if (class_type && class_type->IsExtern()) {
     160             :     // Classes that are in the default namespace are defined in the C++
     161             :     // world and all of their fields and methods are declared explicitly.
     162             :     // Internal classes (e.g. ones used for testing that are not in the default
     163             :     // name space) need to be defined by Torque.
     164             :     // TODO(danno): This is a pretty cheesy hack for now. There should be a more
     165             :     // robust mechanism for this, e.g. declaring classes 'extern' or something.
     166         118 :     if (class_type->nspace()->IsTestNamespace()) {
     167             :       std::string class_name{
     168           1 :           class_type->GetSuperClass()->GetGeneratedTNodeTypeName()};
     169           1 :       header_out() << "  class " << class_type->name() << " : public "
     170           1 :                    << class_name << " {\n";
     171           1 :       header_out() << "   public:\n";
     172           1 :       header_out() << "    DEFINE_FIELD_OFFSET_CONSTANTS(" << class_name
     173             :                    << "::kSize, TORQUE_GENERATED_"
     174           2 :                    << CapifyStringWithUnderscores(class_type->name())
     175           1 :                    << "_FIELDS)\n";
     176           1 :       header_out() << "  };\n";
     177         117 :     } else if (!class_type->nspace()->IsDefaultNamespace()) {
     178             :       ReportError(
     179             :           "extern classes are currently only supported in the default and test "
     180           0 :           "namespaces");
     181             :     }
     182             :     return;
     183             :   }
     184             :   const StructType* struct_type = StructType::DynamicCast(alias->type());
     185         151 :   if (!struct_type) return;
     186             :   const std::string& name = struct_type->name();
     187          36 :   header_out() << "  struct " << name << " {\n";
     188          66 :   for (auto& field : struct_type->fields()) {
     189          96 :     header_out() << "    " << field.name_and_type.type->GetGeneratedTypeName();
     190          96 :     header_out() << " " << field.name_and_type.name << ";\n";
     191             :   }
     192          18 :   header_out() << "\n    std::tuple<";
     193             :   bool first = true;
     194          91 :   for (const Type* type : LowerType(struct_type)) {
     195          55 :     if (!first) {
     196          38 :       header_out() << ", ";
     197             :     }
     198             :     first = false;
     199         110 :     header_out() << type->GetGeneratedTypeName();
     200             :   }
     201          18 :   header_out() << "> Flatten() const {\n"
     202          18 :                << "      return std::tuple_cat(";
     203             :   first = true;
     204          66 :   for (auto& field : struct_type->fields()) {
     205          48 :     if (!first) {
     206          31 :       header_out() << ", ";
     207             :     }
     208             :     first = false;
     209          48 :     if (field.name_and_type.type->IsStructType()) {
     210           8 :       header_out() << field.name_and_type.name << ".Flatten()";
     211             :     } else {
     212          88 :       header_out() << "std::make_tuple(" << field.name_and_type.name << ")";
     213             :     }
     214             :   }
     215          18 :   header_out() << ");\n";
     216          18 :   header_out() << "    }\n";
     217          18 :   header_out() << "  };\n";
     218             : }
     219             : 
     220        1229 : VisitResult ImplementationVisitor::InlineMacro(
     221             :     Macro* macro, base::Optional<LocationReference> this_reference,
     222             :     const std::vector<VisitResult>& arguments,
     223             :     const std::vector<Block*> label_blocks) {
     224        1229 :   CurrentScope::Scope current_scope(macro);
     225        2458 :   BindingsManagersScope bindings_managers_scope;
     226             :   CurrentCallable::Scope current_callable(macro);
     227             :   CurrentReturnValue::Scope current_return_value;
     228             :   const Signature& signature = macro->signature();
     229        1229 :   const Type* return_type = macro->signature().return_type;
     230        1229 :   bool can_return = return_type != TypeOracle::GetNeverType();
     231             : 
     232             :   BlockBindings<LocalValue> parameter_bindings(&ValueBindingsManager::Get());
     233             :   BlockBindings<LocalLabel> label_bindings(&LabelBindingsManager::Get());
     234             :   DCHECK_EQ(macro->signature().parameter_names.size(),
     235             :             arguments.size() + (this_reference ? 1 : 0));
     236             :   DCHECK_EQ(this_reference.has_value(), macro->IsMethod());
     237             : 
     238             :   // Bind the this for methods. Methods that modify a struct-type "this" must
     239             :   // only be called if the this is in a variable, in which case the
     240             :   // LocalValue is non-const. Otherwise, the LocalValue used for the parameter
     241             :   // binding is const, and thus read-only, which will cause errors if
     242             :   // modified, e.g. when called by a struct method that sets the structs
     243             :   // fields. This prevents using temporary struct values for anything other
     244             :   // than read operations.
     245        1229 :   if (this_reference) {
     246             :     DCHECK(macro->IsMethod());
     247         147 :     LocalValue this_value = LocalValue{!this_reference->IsVariableAccess(),
     248         147 :                                        this_reference->GetVisitResult()};
     249         441 :     parameter_bindings.Add(kThisParameterName, this_value);
     250             :   }
     251             : 
     252             :   size_t i = 0;
     253        3304 :   for (auto arg : arguments) {
     254        2075 :     if (this_reference && i == signature.implicit_count) i++;
     255        4150 :     const Identifier* name = macro->parameter_names()[i++];
     256        6225 :     parameter_bindings.Add(name, LocalValue{true, arg});
     257             :   }
     258             : 
     259             :   DCHECK_EQ(label_blocks.size(), signature.labels.size());
     260        1583 :   for (size_t i = 0; i < signature.labels.size(); ++i) {
     261             :     const LabelDeclaration& label_info = signature.labels[i];
     262         708 :     label_bindings.Add(label_info.name,
     263         177 :                        LocalLabel{label_blocks[i], label_info.types});
     264             :   }
     265             : 
     266             :   Block* macro_end;
     267        1229 :   base::Optional<Binding<LocalLabel>> macro_end_binding;
     268        1229 :   if (can_return) {
     269             :     Stack<const Type*> stack = assembler().CurrentStack();
     270        1205 :     std::vector<const Type*> lowered_return_types = LowerType(return_type);
     271        1205 :     stack.PushMany(lowered_return_types);
     272        1205 :     if (!return_type->IsConstexpr()) {
     273        1192 :       SetReturnValue(VisitResult(return_type,
     274             :                                  stack.TopRange(lowered_return_types.size())));
     275             :     }
     276             :     // The stack copy used to initialize the _macro_end block is only used
     277             :     // as a template for the actual gotos generated by return statements. It
     278             :     // doesn't correspond to any real return values, and thus shouldn't contain
     279             :     // top types, because these would pollute actual return value types that get
     280             :     // unioned with them for return statements, erroneously forcing them to top.
     281       10275 :     for (auto i = stack.begin(); i != stack.end(); ++i) {
     282        4535 :       if ((*i)->IsTopType()) {
     283          44 :         *i = TopType::cast(*i)->source_type();
     284             :       }
     285             :     }
     286        2410 :     macro_end = assembler().NewBlock(std::move(stack));
     287             :     macro_end_binding.emplace(&LabelBindingsManager::Get(), "_macro_end",
     288        4820 :                               LocalLabel{macro_end, {return_type}});
     289             :   } else {
     290          48 :     SetReturnValue(VisitResult::NeverResult());
     291             :   }
     292             : 
     293        2458 :   const Type* result = Visit(*macro->body());
     294             : 
     295        1229 :   if (result->IsNever()) {
     296         766 :     if (!return_type->IsNever() && !macro->HasReturns()) {
     297           0 :       std::stringstream s;
     298           0 :       s << "macro " << macro->ReadableName()
     299           0 :         << " that never returns must have return type never";
     300           0 :       ReportError(s.str());
     301             :     }
     302             :   } else {
     303         463 :     if (return_type->IsNever()) {
     304           0 :       std::stringstream s;
     305           0 :       s << "macro " << macro->ReadableName()
     306             :         << " has implicit return at end of its declartion but return type "
     307           0 :            "never";
     308           0 :       ReportError(s.str());
     309         463 :     } else if (!macro->signature().return_type->IsVoid()) {
     310           0 :       std::stringstream s;
     311           0 :       s << "macro " << macro->ReadableName()
     312           0 :         << " expects to return a value but doesn't on all paths";
     313           0 :       ReportError(s.str());
     314             :     }
     315             :   }
     316        1229 :   if (!result->IsNever()) {
     317         463 :     assembler().Goto(macro_end);
     318             :   }
     319             : 
     320        1229 :   if (macro->HasReturns() || !result->IsNever()) {
     321        1205 :     assembler().Bind(macro_end);
     322             :   }
     323             : 
     324        2458 :   return GetAndClearReturnValue();
     325             : }
     326             : 
     327        1120 : void ImplementationVisitor::VisitMacroCommon(Macro* macro) {
     328             :   CurrentCallable::Scope current_callable(macro);
     329             :   const Signature& signature = macro->signature();
     330        1120 :   const Type* return_type = macro->signature().return_type;
     331        1120 :   bool can_return = return_type != TypeOracle::GetNeverType();
     332             :   bool has_return_value =
     333        1120 :       can_return && return_type != TypeOracle::GetVoidType();
     334             : 
     335        1120 :   header_out() << "  ";
     336        2240 :   GenerateMacroFunctionDeclaration(header_out(), "", macro);
     337        1120 :   header_out() << ";\n";
     338             : 
     339             :   GenerateMacroFunctionDeclaration(
     340        3360 :       source_out(), CurrentNamespace()->ExternalName() + "::", macro);
     341        1120 :   source_out() << " {\n";
     342             : 
     343             :   Stack<std::string> lowered_parameters;
     344             :   Stack<const Type*> lowered_parameter_types;
     345             : 
     346        1120 :   std::vector<VisitResult> arguments;
     347             : 
     348        1120 :   base::Optional<LocationReference> this_reference;
     349        1120 :   if (Method* method = Method::DynamicCast(macro)) {
     350             :     const Type* this_type = method->aggregate_type();
     351         117 :     LowerParameter(this_type, ExternalParameterName(kThisParameterName),
     352          39 :                    &lowered_parameters);
     353          78 :     StackRange range = lowered_parameter_types.PushMany(LowerType(this_type));
     354             :     VisitResult this_result = VisitResult(this_type, range);
     355             :     // For classes, mark 'this' as a temporary to prevent assignment to it.
     356             :     // Note that using a VariableAccess for non-class types is technically
     357             :     // incorrect because changes to the 'this' variable do not get reflected
     358             :     // to the caller. Therefore struct methods should always be inlined and a
     359             :     // C++ version should never be generated, since it would be incorrect.
     360             :     // However, in order to be able to type- and semantics-check even unused
     361             :     // struct methods, set the this_reference to be the local variable copy of
     362             :     // the passed-in this, which allows the visitor to at least find and report
     363             :     // errors.
     364         135 :     this_reference =
     365             :         (this_type->IsClassType())
     366             :             ? LocationReference::Temporary(this_result, "this parameter")
     367             :             : LocationReference::VariableAccess(this_result);
     368             :   }
     369             : 
     370        5142 :   for (size_t i = 0; i < macro->signature().parameter_names.size(); ++i) {
     371        2050 :     if (this_reference && i == macro->signature().implicit_count) continue;
     372        1972 :     const std::string& name = macro->parameter_names()[i]->value;
     373        1972 :     std::string external_name = ExternalParameterName(name);
     374        1972 :     const Type* type = macro->signature().types()[i];
     375             : 
     376        1972 :     if (type->IsConstexpr()) {
     377          63 :       arguments.push_back(VisitResult(type, external_name));
     378             :     } else {
     379        1909 :       LowerParameter(type, external_name, &lowered_parameters);
     380        3818 :       StackRange range = lowered_parameter_types.PushMany(LowerType(type));
     381        1909 :       arguments.push_back(VisitResult(type, range));
     382             :     }
     383             :   }
     384             : 
     385             :   DCHECK_EQ(lowered_parameters.Size(), lowered_parameter_types.Size());
     386        3360 :   assembler_ = CfgAssembler(lowered_parameter_types);
     387             : 
     388             :   std::vector<Block*> label_blocks;
     389        1256 :   for (const LabelDeclaration& label_info : signature.labels) {
     390             :     Stack<const Type*> label_input_stack;
     391         162 :     for (const Type* type : label_info.types) {
     392          52 :       label_input_stack.PushMany(LowerType(type));
     393             :     }
     394         272 :     Block* block = assembler().NewBlock(std::move(label_input_stack));
     395         136 :     label_blocks.push_back(block);
     396             :   }
     397             : 
     398             :   VisitResult return_value =
     399        4480 :       InlineMacro(macro, this_reference, arguments, label_blocks);
     400        2240 :   Block* end = assembler().NewBlock();
     401        1120 :   if (return_type != TypeOracle::GetNeverType()) {
     402        1097 :     assembler().Goto(end);
     403             :   }
     404             : 
     405        1392 :   for (size_t i = 0; i < label_blocks.size(); ++i) {
     406         136 :     Block* label_block = label_blocks[i];
     407             :     const LabelDeclaration& label_info = signature.labels[i];
     408         136 :     assembler().Bind(label_block);
     409         136 :     std::vector<std::string> label_parameter_variables;
     410         188 :     for (size_t i = 0; i < label_info.types.size(); ++i) {
     411          26 :       LowerLabelParameter(label_info.types[i],
     412          52 :                           ExternalLabelParameterName(label_info.name, i),
     413          26 :                           &label_parameter_variables);
     414             :     }
     415         544 :     assembler().Emit(GotoExternalInstruction{ExternalLabelName(label_info.name),
     416         136 :                                              label_parameter_variables});
     417             :   }
     418             : 
     419        1120 :   if (return_type != TypeOracle::GetNeverType()) {
     420        1097 :     assembler().Bind(end);
     421             :   }
     422             : 
     423        1120 :   CSAGenerator csa_generator{assembler().Result(), source_out()};
     424             :   base::Optional<Stack<std::string>> values =
     425        2240 :       csa_generator.EmitGraph(lowered_parameters);
     426             : 
     427             :   assembler_ = base::nullopt;
     428             : 
     429        1120 :   if (has_return_value) {
     430         670 :     source_out() << "  return ";
     431        2010 :     CSAGenerator::EmitCSAValue(return_value, *values, source_out());
     432         670 :     source_out() << ";\n";
     433             :   }
     434        1120 :   source_out() << "}\n\n";
     435        1120 : }
     436             : 
     437           0 : void ImplementationVisitor::Visit(Macro* macro) {
     438        1509 :   if (macro->IsExternal()) return;
     439        1081 :   VisitMacroCommon(macro);
     440             : }
     441             : 
     442           0 : void ImplementationVisitor::Visit(Method* method) {
     443             :   DCHECK(!method->IsExternal());
     444          39 :   VisitMacroCommon(method);
     445           0 : }
     446             : 
     447             : namespace {
     448             : 
     449         644 : std::string AddParameter(size_t i, Builtin* builtin,
     450             :                          Stack<std::string>* parameters,
     451             :                          Stack<const Type*>* parameter_types,
     452             :                          BlockBindings<LocalValue>* parameter_bindings) {
     453         644 :   const Identifier* name = builtin->signature().parameter_names[i];
     454         644 :   const Type* type = builtin->signature().types()[i];
     455        1288 :   std::string external_name = "parameter" + std::to_string(i);
     456         644 :   parameters->Push(external_name);
     457        1288 :   StackRange range = parameter_types->PushMany(LowerType(type));
     458        1932 :   parameter_bindings->Add(name, LocalValue{true, VisitResult(type, range)});
     459         644 :   return external_name;
     460             : }
     461             : 
     462             : }  // namespace
     463             : 
     464         203 : void ImplementationVisitor::Visit(Builtin* builtin) {
     465         425 :   if (builtin->IsExternal()) return;
     466         184 :   CurrentScope::Scope current_scope(builtin);
     467         184 :   const std::string& name = builtin->ExternalName();
     468             :   const Signature& signature = builtin->signature();
     469         184 :   source_out() << "TF_BUILTIN(" << name << ", CodeStubAssembler) {\n"
     470             :                << "  compiler::CodeAssemblerState* state_ = state();"
     471         184 :                << "  compiler::CodeAssembler ca_(state());\n";
     472             : 
     473             :   CurrentCallable::Scope current_callable(builtin);
     474             :   CurrentReturnValue::Scope current_return_value;
     475             : 
     476             :   Stack<const Type*> parameter_types;
     477             :   Stack<std::string> parameters;
     478             : 
     479         368 :   BindingsManagersScope bindings_managers_scope;
     480             : 
     481             :   BlockBindings<LocalValue> parameter_bindings(&ValueBindingsManager::Get());
     482             : 
     483             :   // Context
     484             :   std::string parameter0 = AddParameter(0, builtin, &parameters,
     485         184 :                                         &parameter_types, &parameter_bindings);
     486         184 :   source_out() << "  TNode<Context> " << parameter0
     487             :                << " = UncheckedCast<Context>(Parameter("
     488         184 :                << "Descriptor::kContext));\n";
     489         368 :   source_out() << "  USE(" << parameter0 << ");\n";
     490             : 
     491             :   size_t first = 1;
     492         184 :   if (builtin->IsVarArgsJavaScript()) {
     493             :     DCHECK(signature.parameter_types.var_args);
     494          77 :     source_out()
     495          77 :         << "  Node* argc = Parameter(Descriptor::kJSActualArgumentsCount);\n";
     496             :     std::string parameter1 = AddParameter(
     497          77 :         1, builtin, &parameters, &parameter_types, &parameter_bindings);
     498          77 :     source_out()
     499          77 :         << "  TNode<IntPtrT> arguments_length(ChangeInt32ToIntPtr(argc));\n";
     500          77 :     source_out() << "  TNode<RawPtrT> arguments_frame = "
     501          77 :                     "UncheckedCast<RawPtrT>(LoadFramePointer());\n";
     502          77 :     source_out() << "  BaseBuiltinsFromDSLAssembler::Arguments "
     503             :                     "torque_arguments(GetFrameArguments(arguments_frame, "
     504          77 :                     "arguments_length));\n";
     505          77 :     source_out() << "  CodeStubArguments arguments(this, torque_arguments);\n";
     506             : 
     507          77 :     source_out() << "  TNode<Object> " << parameter1
     508          77 :                  << " = arguments.GetReceiver();\n";
     509         154 :     source_out() << "USE(" << parameter1 << ");\n";
     510         154 :     parameters.Push("torque_arguments.frame");
     511         154 :     parameters.Push("torque_arguments.base");
     512         154 :     parameters.Push("torque_arguments.length");
     513          77 :     const Type* arguments_type = TypeOracle::GetArgumentsType();
     514         154 :     StackRange range = parameter_types.PushMany(LowerType(arguments_type));
     515         231 :     parameter_bindings.Add(
     516             :         *signature.arguments_variable,
     517          77 :         LocalValue{true, VisitResult(arguments_type, range)});
     518             : 
     519             :     first = 2;
     520             :   }
     521             : 
     522        1472 :   for (size_t i = 0; i < signature.parameter_names.size(); ++i) {
     523         905 :     if (i < first) continue;
     524         383 :     const std::string& parameter_name = signature.parameter_names[i]->value;
     525         383 :     const Type* type = signature.types()[i];
     526             :     std::string var = AddParameter(i, builtin, &parameters, &parameter_types,
     527         383 :                                    &parameter_bindings);
     528         766 :     source_out() << "  " << type->GetGeneratedTypeName() << " " << var << " = "
     529         766 :                  << "UncheckedCast<" << type->GetGeneratedTNodeTypeName()
     530             :                  << ">(Parameter(Descriptor::k"
     531        1149 :                  << CamelifyString(parameter_name) << "));\n";
     532         766 :     source_out() << "  USE(" << var << ");\n";
     533             :   }
     534             : 
     535         552 :   assembler_ = CfgAssembler(parameter_types);
     536         368 :   const Type* body_result = Visit(*builtin->body());
     537         184 :   if (body_result != TypeOracle::GetNeverType()) {
     538           0 :     ReportError("control reaches end of builtin, expected return of a value");
     539             :   }
     540         184 :   CSAGenerator csa_generator{assembler().Result(), source_out(),
     541         184 :                              builtin->kind()};
     542         552 :   csa_generator.EmitGraph(parameters);
     543             :   assembler_ = base::nullopt;
     544         184 :   source_out() << "}\n\n";
     545             : }
     546             : 
     547           0 : const Type* ImplementationVisitor::Visit(VarDeclarationStatement* stmt) {
     548             :   BlockBindings<LocalValue> block_bindings(&ValueBindingsManager::Get());
     549           0 :   return Visit(stmt, &block_bindings);
     550             : }
     551             : 
     552        1368 : const Type* ImplementationVisitor::Visit(
     553             :     VarDeclarationStatement* stmt, BlockBindings<LocalValue>* block_bindings) {
     554             :   // const qualified variables are required to be initialized properly.
     555        1368 :   if (stmt->const_qualified && !stmt->initializer) {
     556           0 :     ReportError("local constant \"", stmt->name, "\" is not initialized.");
     557             :   }
     558             : 
     559             :   base::Optional<const Type*> type;
     560        1368 :   if (stmt->type) {
     561        1025 :     type = Declarations::GetType(*stmt->type);
     562        1025 :     if ((*type)->IsConstexpr() && !stmt->const_qualified) {
     563             :       ReportError(
     564           0 :           "cannot declare variable with constexpr type. Use 'const' instead.");
     565             :     }
     566             :   }
     567        1368 :   base::Optional<VisitResult> init_result;
     568        1368 :   if (stmt->initializer) {
     569             :     StackScope scope(this);
     570        2678 :     init_result = Visit(*stmt->initializer);
     571        1339 :     if (type) {
     572        2988 :       init_result = GenerateImplicitConvert(*type, *init_result);
     573             :     }
     574        4017 :     init_result = scope.Yield(*init_result);
     575             :   } else {
     576             :     DCHECK(type.has_value());
     577          29 :     if ((*type)->IsConstexpr()) {
     578           0 :       ReportError("constexpr variables need an initializer");
     579             :     }
     580          29 :     TypeVector lowered_types = LowerType(*type);
     581          61 :     for (const Type* type : lowered_types) {
     582         128 :       assembler().Emit(PushUninitializedInstruction{TypeOracle::GetTopType(
     583         128 :           "uninitialized variable '" + stmt->name->value + "' of type " +
     584         160 :               type->ToString() + " originally defined at " +
     585          64 :               PositionAsString(stmt->pos),
     586          32 :           type)});
     587             :     }
     588          29 :     init_result =
     589             :         VisitResult(*type, assembler().TopRange(lowered_types.size()));
     590             :   }
     591        4104 :   block_bindings->Add(stmt->name,
     592        2736 :                       LocalValue{stmt->const_qualified, *init_result});
     593        2736 :   return TypeOracle::GetVoidType();
     594             : }
     595             : 
     596           2 : const Type* ImplementationVisitor::Visit(TailCallStatement* stmt) {
     597           4 :   return Visit(stmt->call, true).type();
     598             : }
     599             : 
     600         102 : VisitResult ImplementationVisitor::Visit(ConditionalExpression* expr) {
     601         204 :   Block* true_block = assembler().NewBlock(assembler().CurrentStack());
     602         204 :   Block* false_block = assembler().NewBlock(assembler().CurrentStack());
     603         204 :   Block* done_block = assembler().NewBlock();
     604         204 :   Block* true_conversion_block = assembler().NewBlock();
     605         102 :   GenerateExpressionBranch(expr->condition, true_block, false_block);
     606             : 
     607         102 :   VisitResult left;
     608         102 :   VisitResult right;
     609             : 
     610             :   {
     611             :     // The code for both paths of the conditional need to be generated first
     612             :     // before evaluating the conditional expression because the common type of
     613             :     // the result of both the true and false of the condition needs to be known
     614             :     // to convert both branches to a common type.
     615         102 :     assembler().Bind(true_block);
     616             :     StackScope left_scope(this);
     617         204 :     left = Visit(expr->if_true);
     618         102 :     assembler().Goto(true_conversion_block);
     619             : 
     620             :     const Type* common_type;
     621             :     {
     622         102 :       assembler().Bind(false_block);
     623             :       StackScope right_scope(this);
     624         204 :       right = Visit(expr->if_false);
     625         102 :       common_type = GetCommonType(left.type(), right.type());
     626         408 :       right = right_scope.Yield(GenerateImplicitConvert(common_type, right));
     627         102 :       assembler().Goto(done_block);
     628             :     }
     629             : 
     630         102 :     assembler().Bind(true_conversion_block);
     631         408 :     left = left_scope.Yield(GenerateImplicitConvert(common_type, left));
     632         102 :     assembler().Goto(done_block);
     633             :   }
     634             : 
     635         102 :   assembler().Bind(done_block);
     636         102 :   CHECK_EQ(left, right);
     637         102 :   return left;
     638             : }
     639             : 
     640          33 : VisitResult ImplementationVisitor::Visit(LogicalOrExpression* expr) {
     641          33 :   VisitResult left_result;
     642             :   {
     643          66 :     Block* false_block = assembler().NewBlock(assembler().CurrentStack());
     644             :     Binding<LocalLabel> false_binding{&LabelBindingsManager::Get(),
     645         165 :                                       kFalseLabelName, LocalLabel{false_block}};
     646          66 :     left_result = Visit(expr->left);
     647          33 :     if (left_result.type()->IsBool()) {
     648          38 :       Block* true_block = LookupSimpleLabel(kTrueLabelName);
     649          19 :       assembler().Branch(true_block, false_block);
     650          19 :       assembler().Bind(false_block);
     651          14 :     } else if (left_result.type()->IsNever()) {
     652           7 :       assembler().Bind(false_block);
     653           7 :     } else if (!left_result.type()->IsConstexprBool()) {
     654             :       ReportError(
     655             :           "expected type bool, constexpr bool, or never on left-hand side of "
     656           0 :           "operator ||");
     657             :     }
     658             :   }
     659             : 
     660          33 :   if (left_result.type()->IsConstexprBool()) {
     661           7 :     VisitResult right_result = Visit(expr->right);
     662           7 :     if (!right_result.type()->IsConstexprBool()) {
     663             :       ReportError(
     664             :           "expected type constexpr bool on right-hand side of operator "
     665           0 :           "||");
     666             :     }
     667             :     return VisitResult(TypeOracle::GetConstexprBoolType(),
     668          28 :                        std::string("(") + left_result.constexpr_value() +
     669          21 :                            " || " + right_result.constexpr_value() + ")");
     670             :   }
     671             : 
     672          26 :   VisitResult right_result = Visit(expr->right);
     673          26 :   if (right_result.type()->IsBool()) {
     674          42 :     Block* true_block = LookupSimpleLabel(kTrueLabelName);
     675          42 :     Block* false_block = LookupSimpleLabel(kFalseLabelName);
     676          21 :     assembler().Branch(true_block, false_block);
     677          21 :     return VisitResult::NeverResult();
     678           5 :   } else if (!right_result.type()->IsNever()) {
     679             :     ReportError(
     680           0 :         "expected type bool or never on right-hand side of operator ||");
     681             :   }
     682           5 :   return right_result;
     683             : }
     684             : 
     685          24 : VisitResult ImplementationVisitor::Visit(LogicalAndExpression* expr) {
     686          24 :   VisitResult left_result;
     687             :   {
     688          48 :     Block* true_block = assembler().NewBlock(assembler().CurrentStack());
     689             :     Binding<LocalLabel> false_binding{&LabelBindingsManager::Get(),
     690         120 :                                       kTrueLabelName, LocalLabel{true_block}};
     691          48 :     left_result = Visit(expr->left);
     692          24 :     if (left_result.type()->IsBool()) {
     693          36 :       Block* false_block = LookupSimpleLabel(kFalseLabelName);
     694          18 :       assembler().Branch(true_block, false_block);
     695          18 :       assembler().Bind(true_block);
     696           6 :     } else if (left_result.type()->IsNever()) {
     697           6 :       assembler().Bind(true_block);
     698           0 :     } else if (!left_result.type()->IsConstexprBool()) {
     699             :       ReportError(
     700             :           "expected type bool, constexpr bool, or never on left-hand side of "
     701           0 :           "operator &&");
     702             :     }
     703             :   }
     704             : 
     705          24 :   if (left_result.type()->IsConstexprBool()) {
     706           0 :     VisitResult right_result = Visit(expr->right);
     707           0 :     if (!right_result.type()->IsConstexprBool()) {
     708             :       ReportError(
     709             :           "expected type constexpr bool on right-hand side of operator "
     710           0 :           "&&");
     711             :     }
     712             :     return VisitResult(TypeOracle::GetConstexprBoolType(),
     713           0 :                        std::string("(") + left_result.constexpr_value() +
     714           0 :                            " && " + right_result.constexpr_value() + ")");
     715             :   }
     716             : 
     717          24 :   VisitResult right_result = Visit(expr->right);
     718          24 :   if (right_result.type()->IsBool()) {
     719          38 :     Block* true_block = LookupSimpleLabel(kTrueLabelName);
     720          38 :     Block* false_block = LookupSimpleLabel(kFalseLabelName);
     721          19 :     assembler().Branch(true_block, false_block);
     722          19 :     return VisitResult::NeverResult();
     723           5 :   } else if (!right_result.type()->IsNever()) {
     724             :     ReportError(
     725           0 :         "expected type bool or never on right-hand side of operator &&");
     726             :   }
     727           5 :   return right_result;
     728             : }
     729             : 
     730         160 : VisitResult ImplementationVisitor::Visit(IncrementDecrementExpression* expr) {
     731             :   StackScope scope(this);
     732         320 :   LocationReference location_ref = GetLocationReference(expr->location);
     733         160 :   VisitResult current_value = GenerateFetchFromLocation(location_ref);
     734         320 :   VisitResult one = {TypeOracle::GetConstInt31Type(), "1"};
     735         160 :   Arguments args;
     736         320 :   args.parameters = {current_value, one};
     737             :   VisitResult assignment_value = GenerateCall(
     738         480 :       expr->op == IncrementDecrementOperator::kIncrement ? "+" : "-", args);
     739         160 :   GenerateAssignToLocation(location_ref, assignment_value);
     740         640 :   return scope.Yield(expr->postfix ? current_value : assignment_value);
     741             : }
     742             : 
     743         807 : VisitResult ImplementationVisitor::Visit(AssignmentExpression* expr) {
     744             :   StackScope scope(this);
     745        1614 :   LocationReference location_ref = GetLocationReference(expr->location);
     746         807 :   VisitResult assignment_value;
     747         807 :   if (expr->op) {
     748          11 :     VisitResult location_value = GenerateFetchFromLocation(location_ref);
     749          22 :     assignment_value = Visit(expr->value);
     750          11 :     Arguments args;
     751          22 :     args.parameters = {location_value, assignment_value};
     752          55 :     assignment_value = GenerateCall(*expr->op, args);
     753          11 :     GenerateAssignToLocation(location_ref, assignment_value);
     754             :   } else {
     755        1592 :     assignment_value = Visit(expr->value);
     756         796 :     GenerateAssignToLocation(location_ref, assignment_value);
     757             :   }
     758        2421 :   return scope.Yield(assignment_value);
     759             : }
     760             : 
     761         939 : VisitResult ImplementationVisitor::Visit(NumberLiteralExpression* expr) {
     762             :   // TODO(tebbi): Do not silently loose precision; support 64bit literals.
     763        1878 :   double d = std::stod(expr->number.c_str());
     764         939 :   int32_t i = static_cast<int32_t>(d);
     765        1878 :   const Type* result_type = Declarations::LookupType(CONST_FLOAT64_TYPE_STRING);
     766         939 :   if (i == d) {
     767         934 :     if ((i >> 30) == (i >> 31)) {
     768        1864 :       result_type = Declarations::LookupType(CONST_INT31_TYPE_STRING);
     769             :     } else {
     770           4 :       result_type = Declarations::LookupType(CONST_INT32_TYPE_STRING);
     771             :     }
     772             :   }
     773         939 :   return VisitResult{result_type, expr->number};
     774             : }
     775             : 
     776          42 : VisitResult ImplementationVisitor::Visit(AssumeTypeImpossibleExpression* expr) {
     777          42 :   VisitResult result = Visit(expr->expression);
     778             :   const Type* result_type =
     779          42 :       SubtractType(result.type(), Declarations::GetType(expr->excluded_type));
     780          42 :   if (result_type->IsNever()) {
     781           0 :     ReportError("unreachable code");
     782             :   }
     783         126 :   CHECK_EQ(LowerType(result_type), TypeVector{result_type});
     784         168 :   assembler().Emit(UnsafeCastInstruction{result_type});
     785             :   result.SetType(result_type);
     786          42 :   return result;
     787             : }
     788             : 
     789         107 : VisitResult ImplementationVisitor::Visit(StringLiteralExpression* expr) {
     790             :   return VisitResult{
     791             :       TypeOracle::GetConstStringType(),
     792         428 :       "\"" + expr->literal.substr(1, expr->literal.size() - 2) + "\""};
     793             : }
     794             : 
     795          74 : VisitResult ImplementationVisitor::GetBuiltinCode(Builtin* builtin) {
     796          74 :   if (builtin->IsExternal() || builtin->kind() != Builtin::kStub) {
     797             :     ReportError(
     798             :         "creating function pointers is only allowed for internal builtins with "
     799           0 :         "stub linkage");
     800             :   }
     801         148 :   const Type* type = TypeOracle::GetBuiltinPointerType(
     802             :       builtin->signature().parameter_types.types,
     803         148 :       builtin->signature().return_type);
     804         296 :   assembler().Emit(
     805          74 :       PushBuiltinPointerInstruction{builtin->ExternalName(), type});
     806          74 :   return VisitResult(type, assembler().TopRange(1));
     807             : }
     808             : 
     809        7203 : VisitResult ImplementationVisitor::Visit(LocationExpression* expr) {
     810             :   StackScope scope(this);
     811       21609 :   return scope.Yield(GenerateFetchFromLocation(GetLocationReference(expr)));
     812             : }
     813             : 
     814         237 : const Type* ImplementationVisitor::Visit(GotoStatement* stmt) {
     815         237 :   LocalLabel* label = LookupLabel(stmt->label);
     816         237 :   size_t parameter_count = label->parameter_types.size();
     817         237 :   if (stmt->arguments.size() != parameter_count) {
     818           0 :     ReportError("goto to label has incorrect number of parameters (expected ",
     819           0 :                 parameter_count, " found ", stmt->arguments.size(), ")");
     820             :   }
     821             : 
     822             :   size_t i = 0;
     823             :   StackRange arguments = assembler().TopRange(0);
     824         315 :   for (Expression* e : stmt->arguments) {
     825             :     StackScope scope(this);
     826          78 :     VisitResult result = Visit(e);
     827         156 :     const Type* parameter_type = label->parameter_types[i++];
     828         234 :     result = GenerateImplicitConvert(parameter_type, result);
     829         234 :     arguments.Extend(scope.Yield(result).stack_range());
     830             :   }
     831             : 
     832         474 :   assembler().Goto(label->block, arguments.Size());
     833         237 :   return TypeOracle::GetNeverType();
     834             : }
     835             : 
     836         598 : const Type* ImplementationVisitor::Visit(IfStatement* stmt) {
     837             :   bool has_else = stmt->if_false.has_value();
     838             : 
     839         598 :   if (stmt->is_constexpr) {
     840          53 :     VisitResult expression_result = Visit(stmt->condition);
     841             : 
     842          53 :     if (!(expression_result.type() == TypeOracle::GetConstexprBoolType())) {
     843           0 :       std::stringstream stream;
     844             :       stream << "expression should return type constexpr bool "
     845           0 :              << "but returns type " << *expression_result.type();
     846           0 :       ReportError(stream.str());
     847             :     }
     848             : 
     849         106 :     Block* true_block = assembler().NewBlock();
     850         106 :     Block* false_block = assembler().NewBlock();
     851         106 :     Block* done_block = assembler().NewBlock();
     852             : 
     853         212 :     assembler().Emit(ConstexprBranchInstruction{
     854          53 :         expression_result.constexpr_value(), true_block, false_block});
     855             : 
     856          53 :     assembler().Bind(true_block);
     857          53 :     const Type* left_result = Visit(stmt->if_true);
     858          53 :     if (left_result == TypeOracle::GetVoidType()) {
     859          14 :       assembler().Goto(done_block);
     860             :     }
     861             : 
     862          53 :     assembler().Bind(false_block);
     863          53 :     const Type* right_result = TypeOracle::GetVoidType();
     864          53 :     if (has_else) {
     865          49 :       right_result = Visit(*stmt->if_false);
     866             :     }
     867          53 :     if (right_result == TypeOracle::GetVoidType()) {
     868          14 :       assembler().Goto(done_block);
     869             :     }
     870             : 
     871          53 :     if (left_result->IsNever() != right_result->IsNever()) {
     872           0 :       std::stringstream stream;
     873             :       stream << "either both or neither branches in a constexpr if statement "
     874             :                 "must reach their end at"
     875           0 :              << PositionAsString(stmt->pos);
     876           0 :       ReportError(stream.str());
     877             :     }
     878             : 
     879          53 :     if (left_result != TypeOracle::GetNeverType()) {
     880          14 :       assembler().Bind(done_block);
     881             :     }
     882             :     return left_result;
     883             :   } else {
     884        1090 :     Block* true_block = assembler().NewBlock(assembler().CurrentStack(),
     885        1090 :                                              IsDeferred(stmt->if_true));
     886             :     Block* false_block =
     887        1090 :         assembler().NewBlock(assembler().CurrentStack(),
     888        1236 :                              stmt->if_false && IsDeferred(*stmt->if_false));
     889         545 :     GenerateExpressionBranch(stmt->condition, true_block, false_block);
     890             : 
     891             :     Block* done_block;
     892             :     bool live = false;
     893         545 :     if (has_else) {
     894         292 :       done_block = assembler().NewBlock();
     895             :     } else {
     896             :       done_block = false_block;
     897             :       live = true;
     898             :     }
     899             : 
     900         545 :     assembler().Bind(true_block);
     901             :     {
     902         545 :       const Type* result = Visit(stmt->if_true);
     903         545 :       if (result == TypeOracle::GetVoidType()) {
     904             :         live = true;
     905         204 :         assembler().Goto(done_block);
     906             :       }
     907             :     }
     908             : 
     909         545 :     if (has_else) {
     910         146 :       assembler().Bind(false_block);
     911         146 :       const Type* result = Visit(*stmt->if_false);
     912         146 :       if (result == TypeOracle::GetVoidType()) {
     913             :         live = true;
     914         107 :         assembler().Goto(done_block);
     915             :       }
     916             :     }
     917             : 
     918         545 :     if (live) {
     919         513 :       assembler().Bind(done_block);
     920             :     }
     921         545 :     return live ? TypeOracle::GetVoidType() : TypeOracle::GetNeverType();
     922             :   }
     923             : }
     924             : 
     925          43 : const Type* ImplementationVisitor::Visit(WhileStatement* stmt) {
     926          86 :   Block* body_block = assembler().NewBlock(assembler().CurrentStack());
     927          86 :   Block* exit_block = assembler().NewBlock(assembler().CurrentStack());
     928             : 
     929          86 :   Block* header_block = assembler().NewBlock();
     930          43 :   assembler().Goto(header_block);
     931             : 
     932          43 :   assembler().Bind(header_block);
     933          43 :   GenerateExpressionBranch(stmt->condition, body_block, exit_block);
     934             : 
     935          43 :   assembler().Bind(body_block);
     936             :   {
     937          43 :     BreakContinueActivator activator{exit_block, header_block};
     938          43 :     const Type* body_result = Visit(stmt->body);
     939          43 :     if (body_result != TypeOracle::GetNeverType()) {
     940          43 :       assembler().Goto(header_block);
     941             :     }
     942             :   }
     943             : 
     944          43 :   assembler().Bind(exit_block);
     945          43 :   return TypeOracle::GetVoidType();
     946             : }
     947             : 
     948        1804 : const Type* ImplementationVisitor::Visit(BlockStatement* block) {
     949             :   BlockBindings<LocalValue> block_bindings(&ValueBindingsManager::Get());
     950        1804 :   const Type* type = TypeOracle::GetVoidType();
     951        6051 :   for (Statement* s : block->statements) {
     952        4247 :     CurrentSourcePosition::Scope source_position(s->pos);
     953        4247 :     if (type->IsNever()) {
     954           0 :       ReportError("statement after non-returning statement");
     955             :     }
     956        4247 :     if (auto* var_declaration = VarDeclarationStatement::DynamicCast(s)) {
     957        1322 :       type = Visit(var_declaration, &block_bindings);
     958             :     } else {
     959        2925 :       type = Visit(s);
     960             :     }
     961             :   }
     962        1804 :   return type;
     963             : }
     964             : 
     965         125 : const Type* ImplementationVisitor::Visit(DebugStatement* stmt) {
     966             : #if defined(DEBUG)
     967             :   assembler().Emit(PrintConstantStringInstruction{"halting because of '" +
     968             :                                                   stmt->reason + "' at " +
     969             :                                                   PositionAsString(stmt->pos)});
     970             : #endif
     971         500 :   assembler().Emit(AbortInstruction{stmt->never_continues
     972             :                                         ? AbortInstruction::Kind::kUnreachable
     973         125 :                                         : AbortInstruction::Kind::kDebugBreak});
     974         125 :   if (stmt->never_continues) {
     975         125 :     return TypeOracle::GetNeverType();
     976             :   } else {
     977           0 :     return TypeOracle::GetVoidType();
     978             :   }
     979             : }
     980             : 
     981             : namespace {
     982             : 
     983         111 : std::string FormatAssertSource(const std::string& str) {
     984             :   // Replace all whitespace characters with a space character.
     985             :   std::string str_no_newlines = str;
     986             :   std::replace_if(str_no_newlines.begin(), str_no_newlines.end(),
     987        3251 :                   [](unsigned char c) { return isspace(c); }, ' ');
     988             : 
     989             :   // str might include indentation, squash multiple space characters into one.
     990             :   std::string result;
     991             :   std::unique_copy(str_no_newlines.begin(), str_no_newlines.end(),
     992             :                    std::back_inserter(result),
     993        3140 :                    [](char a, char b) { return a == ' ' && b == ' '; });
     994         111 :   return result;
     995             : }
     996             : 
     997             : }  // namespace
     998             : 
     999         291 : const Type* ImplementationVisitor::Visit(AssertStatement* stmt) {
    1000         291 :   bool do_check = !stmt->debug_only;
    1001             : #if defined(DEBUG)
    1002             :   do_check = true;
    1003             : #endif
    1004         291 :   if (do_check) {
    1005             :     // CSA_ASSERT & co. are not used here on purpose for two reasons. First,
    1006             :     // Torque allows and handles two types of expressions in the if protocol
    1007             :     // automagically, ones that return TNode<BoolT> and those that use the
    1008             :     // BranchIf(..., Label* true, Label* false) idiom. Because the machinery to
    1009             :     // handle this is embedded in the expression handling and to it's not
    1010             :     // possible to make the decision to use CSA_ASSERT or CSA_ASSERT_BRANCH
    1011             :     // isn't trivial up-front. Secondly, on failure, the assert text should be
    1012             :     // the corresponding Torque code, not the -gen.cc code, which would be the
    1013             :     // case when using CSA_ASSERT_XXX.
    1014         222 :     Block* true_block = assembler().NewBlock(assembler().CurrentStack());
    1015         222 :     Block* false_block = assembler().NewBlock(assembler().CurrentStack(), true);
    1016         111 :     GenerateExpressionBranch(stmt->expression, true_block, false_block);
    1017             : 
    1018         111 :     assembler().Bind(false_block);
    1019             : 
    1020         333 :     assembler().Emit(AbortInstruction{
    1021             :         AbortInstruction::Kind::kAssertionFailure,
    1022         555 :         "Torque assert '" + FormatAssertSource(stmt->source) + "' failed"});
    1023             : 
    1024         111 :     assembler().Bind(true_block);
    1025             :   }
    1026         291 :   return TypeOracle::GetVoidType();
    1027             : }
    1028             : 
    1029        1515 : const Type* ImplementationVisitor::Visit(ExpressionStatement* stmt) {
    1030        3030 :   const Type* type = Visit(stmt->expression).type();
    1031        1515 :   return type->IsNever() ? type : TypeOracle::GetVoidType();
    1032             : }
    1033             : 
    1034        1116 : const Type* ImplementationVisitor::Visit(ReturnStatement* stmt) {
    1035        1116 :   Callable* current_callable = CurrentCallable::Get();
    1036        1116 :   if (current_callable->signature().return_type->IsNever()) {
    1037           0 :     std::stringstream s;
    1038           0 :     s << "cannot return from a function with return type never";
    1039           0 :     ReportError(s.str());
    1040             :   }
    1041             :   LocalLabel* end =
    1042        1989 :       current_callable->IsMacro() ? LookupLabel("_macro_end") : nullptr;
    1043        1116 :   if (current_callable->HasReturnValue()) {
    1044        1108 :     if (!stmt->value) {
    1045           0 :       std::stringstream s;
    1046             :       s << "return expression needs to be specified for a return type of "
    1047           0 :         << *current_callable->signature().return_type;
    1048           0 :       ReportError(s.str());
    1049             :     }
    1050        1108 :     VisitResult expression_result = Visit(*stmt->value);
    1051             :     VisitResult return_result = GenerateImplicitConvert(
    1052        2216 :         current_callable->signature().return_type, expression_result);
    1053        1108 :     if (current_callable->IsMacro()) {
    1054         865 :       if (return_result.IsOnStack()) {
    1055             :         StackRange return_value_range =
    1056         852 :             GenerateLabelGoto(end, return_result.stack_range());
    1057         852 :         SetReturnValue(VisitResult(return_result.type(), return_value_range));
    1058             :       } else {
    1059             :         GenerateLabelGoto(end);
    1060          13 :         SetReturnValue(return_result);
    1061             :       }
    1062         243 :     } else if (current_callable->IsBuiltin()) {
    1063        1215 :       assembler().Emit(ReturnInstruction{});
    1064             :     } else {
    1065           0 :       UNREACHABLE();
    1066             :     }
    1067             :   } else {
    1068           8 :     if (stmt->value) {
    1069           0 :       std::stringstream s;
    1070             :       s << "return expression can't be specified for a void or never return "
    1071           0 :            "type";
    1072           0 :       ReportError(s.str());
    1073             :     }
    1074             :     GenerateLabelGoto(end);
    1075             :   }
    1076             :   current_callable->IncrementReturns();
    1077        1116 :   return TypeOracle::GetNeverType();
    1078             : }
    1079             : 
    1080           0 : const Type* ImplementationVisitor::Visit(ForOfLoopStatement* stmt) {
    1081           0 :   VisitResult expression_result = Visit(stmt->iterable);
    1082             :   VisitResult begin = stmt->begin
    1083             :                           ? Visit(*stmt->begin)
    1084           0 :                           : VisitResult(TypeOracle::GetConstInt31Type(), "0");
    1085             : 
    1086             :   VisitResult end = stmt->end
    1087             :                         ? Visit(*stmt->end)
    1088           0 :                         : GenerateCall(".length", {{expression_result}, {}});
    1089             : 
    1090           0 :   const Type* common_type = GetCommonType(begin.type(), end.type());
    1091           0 :   VisitResult index = GenerateImplicitConvert(common_type, begin);
    1092             : 
    1093           0 :   Block* body_block = assembler().NewBlock();
    1094           0 :   Block* increment_block = assembler().NewBlock(assembler().CurrentStack());
    1095           0 :   Block* exit_block = assembler().NewBlock(assembler().CurrentStack());
    1096             : 
    1097           0 :   Block* header_block = assembler().NewBlock();
    1098             : 
    1099           0 :   assembler().Goto(header_block);
    1100             : 
    1101           0 :   assembler().Bind(header_block);
    1102             : 
    1103           0 :   BreakContinueActivator activator(exit_block, increment_block);
    1104             : 
    1105             :   {
    1106             :     StackScope comparison_scope(this);
    1107           0 :     VisitResult result = GenerateCall("<", {{index, end}, {}});
    1108           0 :     if (result.type() != TypeOracle::GetBoolType()) {
    1109             :       ReportError("operator < with arguments(", *index.type(), ", ",
    1110             :                   *end.type(),
    1111             :                   ")  used in for-of loop has to return type bool, but "
    1112             :                   "returned type ",
    1113           0 :                   *result.type());
    1114             :     }
    1115           0 :     comparison_scope.Yield(result);
    1116             :   }
    1117           0 :   assembler().Branch(body_block, exit_block);
    1118             : 
    1119           0 :   assembler().Bind(body_block);
    1120             :   {
    1121           0 :     VisitResult element_result;
    1122             :     {
    1123             :       StackScope element_scope(this);
    1124           0 :       VisitResult result = GenerateCall("[]", {{expression_result, index}, {}});
    1125           0 :       if (stmt->var_declaration->type) {
    1126             :         const Type* declared_type =
    1127           0 :             Declarations::GetType(*stmt->var_declaration->type);
    1128           0 :         result = GenerateImplicitConvert(declared_type, result);
    1129             :       }
    1130           0 :       element_result = element_scope.Yield(result);
    1131             :     }
    1132             :     Binding<LocalValue> element_var_binding{&ValueBindingsManager::Get(),
    1133           0 :                                             stmt->var_declaration->name->value,
    1134           0 :                                             LocalValue{true, element_result}};
    1135           0 :     Visit(stmt->body);
    1136             :   }
    1137           0 :   assembler().Goto(increment_block);
    1138             : 
    1139           0 :   assembler().Bind(increment_block);
    1140             :   {
    1141           0 :     Arguments increment_args;
    1142           0 :     increment_args.parameters = {index, {TypeOracle::GetConstInt31Type(), "1"}};
    1143           0 :     VisitResult increment_result = GenerateCall("+", increment_args);
    1144             : 
    1145           0 :     GenerateAssignToLocation(LocationReference::VariableAccess(index),
    1146           0 :                              increment_result);
    1147             :   }
    1148             : 
    1149           0 :   assembler().Goto(header_block);
    1150             : 
    1151           0 :   assembler().Bind(exit_block);
    1152           0 :   return TypeOracle::GetVoidType();
    1153             : }
    1154             : 
    1155          25 : VisitResult ImplementationVisitor::TemporaryUninitializedStruct(
    1156             :     const StructType* struct_type, const std::string& reason) {
    1157             :   StackRange range = assembler().TopRange(0);
    1158          91 :   for (const Field& f : struct_type->fields()) {
    1159          66 :     if (const StructType* struct_type =
    1160          66 :             StructType::DynamicCast(f.name_and_type.type)) {
    1161             :       range.Extend(
    1162           8 :           TemporaryUninitializedStruct(struct_type, reason).stack_range());
    1163             :     } else {
    1164         186 :       std::string descriptor = "uninitialized field '" + f.name_and_type.name +
    1165         310 :                                "' declared at " + PositionAsString(f.pos) +
    1166         124 :                                " (" + reason + ")";
    1167          62 :       TypeVector lowered_types = LowerType(f.name_and_type.type);
    1168         124 :       for (const Type* type : lowered_types) {
    1169         186 :         assembler().Emit(PushUninitializedInstruction{
    1170         186 :             TypeOracle::GetTopType(descriptor, type)});
    1171             :       }
    1172             :       range.Extend(assembler().TopRange(lowered_types.size()));
    1173             :     }
    1174             :   }
    1175          25 :   return VisitResult(struct_type, range);
    1176             : }
    1177             : 
    1178         356 : VisitResult ImplementationVisitor::Visit(TryLabelExpression* expr) {
    1179         356 :   size_t parameter_count = expr->label_block->parameters.names.size();
    1180         356 :   std::vector<VisitResult> parameters;
    1181             : 
    1182             :   Block* label_block = nullptr;
    1183         712 :   Block* done_block = assembler().NewBlock();
    1184         356 :   VisitResult try_result;
    1185             : 
    1186             :   {
    1187         356 :     CurrentSourcePosition::Scope source_position(expr->label_block->pos);
    1188         356 :     if (expr->label_block->parameters.has_varargs) {
    1189           0 :       ReportError("cannot use ... for label parameters");
    1190             :     }
    1191             :     Stack<const Type*> label_input_stack = assembler().CurrentStack();
    1192             :     TypeVector parameter_types;
    1193         424 :     for (size_t i = 0; i < parameter_count; ++i) {
    1194             :       const Type* type =
    1195          68 :           Declarations::GetType(expr->label_block->parameters.types[i]);
    1196          34 :       parameter_types.push_back(type);
    1197          34 :       if (type->IsConstexpr()) {
    1198           0 :         ReportError("no constexpr type allowed for label arguments");
    1199             :       }
    1200          68 :       StackRange range = label_input_stack.PushMany(LowerType(type));
    1201          68 :       parameters.push_back(VisitResult(type, range));
    1202             :     }
    1203         712 :     label_block = assembler().NewBlock(label_input_stack,
    1204         712 :                                        IsDeferred(expr->label_block->body));
    1205             : 
    1206             :     Binding<LocalLabel> label_binding{&LabelBindingsManager::Get(),
    1207         356 :                                       expr->label_block->label,
    1208        1780 :                                       LocalLabel{label_block, parameter_types}};
    1209             : 
    1210             :     // Visit try
    1211             :     StackScope stack_scope(this);
    1212         712 :     try_result = Visit(expr->try_expression);
    1213         356 :     if (try_result.type() != TypeOracle::GetNeverType()) {
    1214         672 :       try_result = stack_scope.Yield(try_result);
    1215         224 :       assembler().Goto(done_block);
    1216             :     }
    1217             :   }
    1218             : 
    1219             :   // Visit and output the code for the label block. If the label block falls
    1220             :   // through, then the try must not return a value. Also, if the try doesn't
    1221             :   // fall through, but the label does, then overall the try-label block
    1222             :   // returns type void.
    1223         356 :   assembler().Bind(label_block);
    1224             :   const Type* label_result;
    1225             :   {
    1226             :     BlockBindings<LocalValue> parameter_bindings(&ValueBindingsManager::Get());
    1227         424 :     for (size_t i = 0; i < parameter_count; ++i) {
    1228         136 :       parameter_bindings.Add(expr->label_block->parameters.names[i],
    1229          34 :                              LocalValue{true, parameters[i]});
    1230             :     }
    1231             : 
    1232         356 :     label_result = Visit(expr->label_block->body);
    1233             :   }
    1234         356 :   if (!try_result.type()->IsVoidOrNever() && label_result->IsVoid()) {
    1235             :     ReportError(
    1236           0 :         "otherwise clauses cannot fall through in a non-void expression");
    1237             :   }
    1238         356 :   if (label_result != TypeOracle::GetNeverType()) {
    1239          58 :     assembler().Goto(done_block);
    1240             :   }
    1241         356 :   if (label_result->IsVoid() && try_result.type()->IsNever()) {
    1242          26 :     try_result =
    1243          13 :         VisitResult(TypeOracle::GetVoidType(), try_result.stack_range());
    1244             :   }
    1245             : 
    1246         356 :   if (!try_result.type()->IsNever()) {
    1247         237 :     assembler().Bind(done_block);
    1248             :   }
    1249         356 :   return try_result;
    1250             : }
    1251             : 
    1252         189 : VisitResult ImplementationVisitor::Visit(StatementExpression* expr) {
    1253         378 :   return VisitResult{Visit(expr->statement), assembler().TopRange(0)};
    1254             : }
    1255             : 
    1256          33 : InitializerResults ImplementationVisitor::VisitInitializerResults(
    1257             :     const AggregateType* current_aggregate,
    1258             :     const std::vector<NameAndExpression>& initializers) {
    1259             :   InitializerResults result;
    1260         139 :   for (const NameAndExpression& initializer : initializers) {
    1261         106 :     result.names.push_back(initializer.name);
    1262         106 :     Expression* e = initializer.expression;
    1263             :     const Field& field =
    1264         106 :         current_aggregate->LookupField(initializer.name->value);
    1265         106 :     auto field_index = field.index;
    1266         106 :     if (SpreadExpression* s = SpreadExpression::DynamicCast(e)) {
    1267           2 :       if (!field_index) {
    1268           0 :         ReportError(
    1269             :             "spread expressions can only be used to initialize indexed class "
    1270             :             "fields ('",
    1271           0 :             initializer.name->value, "' is not)");
    1272             :       }
    1273           2 :       e = s->spreadee;
    1274         104 :     } else if (field_index) {
    1275           0 :       ReportError("the indexed class field '", initializer.name->value,
    1276           0 :                   "' must be initialized with a spread operator");
    1277             :     }
    1278         212 :     result.field_value_map[field.name_and_type.name] = Visit(e);
    1279             :   }
    1280          33 :   return result;
    1281             : }
    1282             : 
    1283          55 : size_t ImplementationVisitor::InitializeAggregateHelper(
    1284             :     const AggregateType* aggregate_type, VisitResult allocate_result,
    1285             :     const InitializerResults& initializer_results) {
    1286             :   const ClassType* current_class = ClassType::DynamicCast(aggregate_type);
    1287             :   size_t current = 0;
    1288          55 :   if (current_class) {
    1289             :     const ClassType* super = current_class->GetSuperClass();
    1290          34 :     if (super) {
    1291          22 :       current = InitializeAggregateHelper(super, allocate_result,
    1292          22 :                                           initializer_results);
    1293             :     }
    1294             :   }
    1295             : 
    1296         161 :   for (Field f : aggregate_type->fields()) {
    1297         106 :     if (current == initializer_results.field_value_map.size()) {
    1298             :       ReportError("insufficient number of initializers for ",
    1299           0 :                   aggregate_type->name());
    1300             :     }
    1301             :     VisitResult current_value =
    1302         106 :         initializer_results.field_value_map.at(f.name_and_type.name);
    1303         106 :     Identifier* fieldname = initializer_results.names[current];
    1304         212 :     if (fieldname->value != f.name_and_type.name) {
    1305           0 :       CurrentSourcePosition::Scope scope(fieldname->pos);
    1306             :       ReportError("Expected fieldname \"", f.name_and_type.name,
    1307           0 :                   "\" instead of \"", fieldname->value, "\"");
    1308             :     }
    1309         106 :     if (aggregate_type->IsClassType()) {
    1310          51 :       if (f.index) {
    1311           4 :         InitializeFieldFromSpread(allocate_result, f, initializer_results);
    1312             :       } else {
    1313             :         allocate_result.SetType(aggregate_type);
    1314          98 :         GenerateCopy(allocate_result);
    1315         196 :         assembler().Emit(CreateFieldReferenceInstruction{
    1316          49 :             ClassType::cast(aggregate_type), f.name_and_type.name});
    1317             :         VisitResult heap_reference(
    1318          49 :             TypeOracle::GetReferenceType(f.name_and_type.type),
    1319             :             assembler().TopRange(2));
    1320             :         GenerateAssignToLocation(
    1321          98 :             LocationReference::HeapReference(heap_reference), current_value);
    1322             :       }
    1323             :     } else {
    1324             :       LocationReference struct_field_ref = LocationReference::VariableAccess(
    1325         220 :           ProjectStructField(allocate_result, f.name_and_type.name));
    1326          55 :       GenerateAssignToLocation(struct_field_ref, current_value);
    1327             :     }
    1328         106 :     ++current;
    1329             :   }
    1330          55 :   return current;
    1331             : }
    1332             : 
    1333           2 : void ImplementationVisitor::InitializeFieldFromSpread(
    1334             :     VisitResult object, const Field& field,
    1335             :     const InitializerResults& initializer_results) {
    1336             :   StackScope stack_scope(this);
    1337             : 
    1338           4 :   VisitResult zero(TypeOracle::GetConstInt31Type(), "0");
    1339           2 :   const Type* index_type = (*field.index)->name_and_type.type;
    1340           4 :   VisitResult index = GenerateImplicitConvert(index_type, zero);
    1341           4 :   Block* post_exit_block = assembler().NewBlock(assembler().CurrentStack());
    1342           4 :   Block* exit_block = assembler().NewBlock(assembler().CurrentStack());
    1343           4 :   Block* body_block = assembler().NewBlock(assembler().CurrentStack());
    1344           4 :   Block* fail_block = assembler().NewBlock(assembler().CurrentStack(), true);
    1345           4 :   Block* header_block = assembler().NewBlock(assembler().CurrentStack());
    1346             : 
    1347           2 :   assembler().Goto(header_block);
    1348             : 
    1349           2 :   assembler().Bind(header_block);
    1350           2 :   Arguments compare_arguments;
    1351           2 :   compare_arguments.parameters.push_back(index);
    1352             :   compare_arguments.parameters.push_back(initializer_results.field_value_map.at(
    1353           2 :       (*field.index)->name_and_type.name));
    1354           2 :   GenerateExpressionBranch(
    1355           8 :       [&]() { return GenerateCall("<", compare_arguments); }, body_block,
    1356           2 :       exit_block);
    1357             : 
    1358           2 :   assembler().Bind(body_block);
    1359             :   {
    1360             :     VisitResult spreadee =
    1361           2 :         initializer_results.field_value_map.at(field.name_and_type.name);
    1362           4 :     LocationReference target = LocationReference::VariableAccess(spreadee);
    1363             :     Binding<LocalLabel> no_more{&LabelBindingsManager::Get(), "_Done",
    1364          10 :                                 LocalLabel{fail_block}};
    1365             : 
    1366             :     // Call the Next() method of the iterator
    1367           2 :     Arguments next_arguments;
    1368           4 :     next_arguments.labels.push_back(&no_more);
    1369           6 :     Callable* callable = LookupMethod("Next", target, next_arguments, {});
    1370             :     VisitResult next_result =
    1371           8 :         GenerateCall(callable, target, next_arguments, {}, false);
    1372           2 :     Arguments assign_arguments;
    1373           2 :     assign_arguments.parameters.push_back(object);
    1374           2 :     assign_arguments.parameters.push_back(index);
    1375           2 :     assign_arguments.parameters.push_back(next_result);
    1376           8 :     GenerateCall("[]=", assign_arguments);
    1377             : 
    1378             :     // Increment the indexed field index.
    1379           4 :     LocationReference index_ref = LocationReference::VariableAccess(index);
    1380           2 :     Arguments increment_arguments;
    1381           4 :     VisitResult one = {TypeOracle::GetConstInt31Type(), "1"};
    1382           4 :     increment_arguments.parameters = {index, one};
    1383           6 :     VisitResult assignment_value = GenerateCall("+", increment_arguments);
    1384           2 :     GenerateAssignToLocation(index_ref, assignment_value);
    1385             :   }
    1386           2 :   assembler().Goto(header_block);
    1387             : 
    1388           2 :   assembler().Bind(fail_block);
    1389           8 :   assembler().Emit(AbortInstruction(AbortInstruction::Kind::kUnreachable));
    1390             : 
    1391           2 :   assembler().Bind(exit_block);
    1392           2 :   assembler().Goto(post_exit_block);
    1393             : 
    1394           2 :   assembler().Bind(post_exit_block);
    1395           2 : }
    1396             : 
    1397          33 : void ImplementationVisitor::InitializeAggregate(
    1398             :     const AggregateType* aggregate_type, VisitResult allocate_result,
    1399             :     const InitializerResults& initializer_results) {
    1400          33 :   size_t consumed_initializers = InitializeAggregateHelper(
    1401          33 :       aggregate_type, allocate_result, initializer_results);
    1402          33 :   if (consumed_initializers != initializer_results.field_value_map.size()) {
    1403             :     ReportError("more initializers than fields present in ",
    1404           0 :                 aggregate_type->name());
    1405             :   }
    1406          33 : }
    1407             : 
    1408           9 : VisitResult ImplementationVisitor::AddVariableObjectSize(
    1409             :     VisitResult object_size, const ClassType* current_class,
    1410             :     const InitializerResults& initializer_results) {
    1411          71 :   while (current_class != nullptr) {
    1412             :     auto current_field = current_class->fields().begin();
    1413          64 :     while (current_field != current_class->fields().end()) {
    1414          33 :       if (current_field->index) {
    1415           4 :         if (!current_field->name_and_type.type->IsSubtypeOf(
    1416           2 :                 TypeOracle::GetObjectType())) {
    1417             :           ReportError(
    1418             :               "allocating objects containing indexed fields of non-object "
    1419           0 :               "types is not yet supported");
    1420             :         }
    1421             :         VisitResult index_field_size =
    1422           4 :             VisitResult(TypeOracle::GetConstInt31Type(), "kTaggedSize");
    1423             :         VisitResult initializer_value = initializer_results.field_value_map.at(
    1424           2 :             (*current_field->index)->name_and_type.name);
    1425             :         VisitResult index_intptr_size =
    1426             :             GenerateCall("Convert", {{initializer_value}, {}},
    1427          10 :                          {TypeOracle::GetIntPtrType()}, false);
    1428             :         VisitResult variable_size = GenerateCall(
    1429           8 :             "*", {{index_intptr_size, index_field_size}, {}}, {}, false);
    1430             :         object_size =
    1431          10 :             GenerateCall("+", {{object_size, variable_size}, {}}, {}, false);
    1432             :       }
    1433             :       ++current_field;
    1434             :     }
    1435             :     current_class = current_class->GetSuperClass();
    1436             :   }
    1437           9 :   return object_size;
    1438             : }
    1439             : 
    1440          12 : VisitResult ImplementationVisitor::Visit(NewExpression* expr) {
    1441             :   StackScope stack_scope(this);
    1442          12 :   const Type* type = Declarations::GetType(expr->type);
    1443             :   const ClassType* class_type = ClassType::DynamicCast(type);
    1444          12 :   if (class_type == nullptr) {
    1445             :     ReportError("type for new expression must be a class, \"", *type,
    1446           0 :                 "\" is not");
    1447             :   }
    1448             : 
    1449          12 :   if (!class_type->AllowInstantiation()) {
    1450             :     // Classes that are only used for testing should never be instantiated.
    1451             :     ReportError(*class_type,
    1452           0 :                 " cannot be allocated with new (it's used for testing)");
    1453             :   }
    1454             : 
    1455             :   InitializerResults initializer_results =
    1456          24 :       VisitInitializerResults(class_type, expr->initializers);
    1457             : 
    1458             :   // Output the code to generate an uninitialized object of the class size in
    1459             :   // the GC heap.
    1460          12 :   VisitResult allocate_result;
    1461          12 :   if (class_type->IsExtern()) {
    1462          18 :     const Field& map_field = class_type->LookupField("map");
    1463           9 :     if (map_field.offset != 0) {
    1464             :       ReportError(
    1465           0 :           "external classes initializers must have a map as first parameter");
    1466             :     }
    1467             :     VisitResult object_map =
    1468           9 :         initializer_results.field_value_map[map_field.name_and_type.name];
    1469           9 :     Arguments size_arguments;
    1470           9 :     size_arguments.parameters.push_back(object_map);
    1471             :     VisitResult object_size = GenerateCall("%GetAllocationBaseSize",
    1472          27 :                                            size_arguments, {class_type}, false);
    1473             : 
    1474             :     object_size =
    1475          27 :         AddVariableObjectSize(object_size, class_type, initializer_results);
    1476             : 
    1477           9 :     Arguments allocate_arguments;
    1478           9 :     allocate_arguments.parameters.push_back(object_size);
    1479             :     allocate_result =
    1480          36 :         GenerateCall("%Allocate", allocate_arguments, {class_type}, false);
    1481             :     DCHECK(allocate_result.IsOnStack());
    1482             :   } else {
    1483           3 :     Arguments allocate_arguments;
    1484           6 :     allocate_arguments.parameters.push_back(
    1485             :         VisitResult(TypeOracle::GetConstexprIntPtrType(),
    1486           6 :                     std::to_string(class_type->size() / kTaggedSize)));
    1487          12 :     allocate_result = GenerateCall("%AllocateInternalClass", allocate_arguments,
    1488           3 :                                    {class_type}, false);
    1489             :   }
    1490             : 
    1491          24 :   InitializeAggregate(class_type, allocate_result, initializer_results);
    1492             : 
    1493          36 :   return stack_scope.Yield(allocate_result);
    1494             : }
    1495             : 
    1496          27 : const Type* ImplementationVisitor::Visit(BreakStatement* stmt) {
    1497          54 :   base::Optional<Binding<LocalLabel>*> break_label = TryLookupLabel("_break");
    1498          27 :   if (!break_label) {
    1499           0 :     ReportError("break used outside of loop");
    1500             :   }
    1501          54 :   assembler().Goto((*break_label)->block);
    1502          27 :   return TypeOracle::GetNeverType();
    1503             : }
    1504             : 
    1505          17 : const Type* ImplementationVisitor::Visit(ContinueStatement* stmt) {
    1506             :   base::Optional<Binding<LocalLabel>*> continue_label =
    1507          34 :       TryLookupLabel("_continue");
    1508          17 :   if (!continue_label) {
    1509           0 :     ReportError("continue used outside of loop");
    1510             :   }
    1511          34 :   assembler().Goto((*continue_label)->block);
    1512          17 :   return TypeOracle::GetNeverType();
    1513             : }
    1514             : 
    1515          61 : const Type* ImplementationVisitor::Visit(ForLoopStatement* stmt) {
    1516             :   BlockBindings<LocalValue> loop_bindings(&ValueBindingsManager::Get());
    1517             : 
    1518          61 :   if (stmt->var_declaration) Visit(*stmt->var_declaration, &loop_bindings);
    1519             : 
    1520         122 :   Block* body_block = assembler().NewBlock(assembler().CurrentStack());
    1521         122 :   Block* exit_block = assembler().NewBlock(assembler().CurrentStack());
    1522             : 
    1523         122 :   Block* header_block = assembler().NewBlock();
    1524          61 :   assembler().Goto(header_block);
    1525          61 :   assembler().Bind(header_block);
    1526             : 
    1527             :   // The continue label is where "continue" statements jump to. If no action
    1528             :   // expression is provided, we jump directly to the header.
    1529             :   Block* continue_block = header_block;
    1530             : 
    1531             :   // The action label is only needed when an action expression was provided.
    1532             :   Block* action_block = nullptr;
    1533          61 :   if (stmt->action) {
    1534         112 :     action_block = assembler().NewBlock();
    1535             : 
    1536             :     // The action expression needs to be executed on a continue.
    1537             :     continue_block = action_block;
    1538             :   }
    1539             : 
    1540          61 :   if (stmt->test) {
    1541          56 :     GenerateExpressionBranch(*stmt->test, body_block, exit_block);
    1542             :   } else {
    1543           5 :     assembler().Goto(body_block);
    1544             :   }
    1545             : 
    1546          61 :   assembler().Bind(body_block);
    1547             :   {
    1548          61 :     BreakContinueActivator activator(exit_block, continue_block);
    1549          61 :     const Type* body_result = Visit(stmt->body);
    1550          61 :     if (body_result != TypeOracle::GetNeverType()) {
    1551          61 :       assembler().Goto(continue_block);
    1552             :     }
    1553             :   }
    1554             : 
    1555          61 :   if (stmt->action) {
    1556          56 :     assembler().Bind(action_block);
    1557          56 :     const Type* action_result = Visit(*stmt->action);
    1558          56 :     if (action_result != TypeOracle::GetNeverType()) {
    1559          56 :       assembler().Goto(header_block);
    1560             :     }
    1561             :   }
    1562             : 
    1563          61 :   assembler().Bind(exit_block);
    1564         122 :   return TypeOracle::GetVoidType();
    1565             : }
    1566             : 
    1567           0 : VisitResult ImplementationVisitor::Visit(SpreadExpression* expr) {
    1568             :   ReportError(
    1569             :       "spread operators are only currently supported in indexed class field "
    1570           0 :       "initialization expressions");
    1571             : }
    1572             : 
    1573          42 : void ImplementationVisitor::GenerateImplementation(const std::string& dir,
    1574             :                                                    Namespace* nspace) {
    1575             :   std::string new_source(nspace->source());
    1576             :   std::string base_file_name =
    1577         126 :       "builtins-" + DashifyString(nspace->name()) + "-from-dsl-gen";
    1578             : 
    1579         126 :   std::string source_file_name = dir + "/" + base_file_name + ".cc";
    1580          42 :   ReplaceFileContentsIfDifferent(source_file_name, new_source);
    1581             :   std::string new_header(nspace->header());
    1582         126 :   std::string header_file_name = dir + "/" + base_file_name + ".h";
    1583          42 :   ReplaceFileContentsIfDifferent(header_file_name, new_header);
    1584          42 : }
    1585             : 
    1586           0 : void ImplementationVisitor::GenerateMacroFunctionDeclaration(
    1587             :     std::ostream& o, const std::string& macro_prefix, Macro* macro) {
    1588             :   GenerateFunctionDeclaration(o, macro_prefix, macro->ExternalName(),
    1589        2240 :                               macro->signature(), macro->parameter_names());
    1590           0 : }
    1591             : 
    1592        2306 : void ImplementationVisitor::GenerateFunctionDeclaration(
    1593             :     std::ostream& o, const std::string& macro_prefix, const std::string& name,
    1594             :     const Signature& signature, const NameVector& parameter_names) {
    1595        2306 :   if (GlobalContext::verbose()) {
    1596           0 :     std::cout << "generating source for declaration " << name << "\n";
    1597             :   }
    1598             : 
    1599        2306 :   if (signature.return_type->IsVoidOrNever()) {
    1600         900 :     o << "void";
    1601             :   } else {
    1602        2812 :     o << signature.return_type->GetGeneratedTypeName();
    1603             :   }
    1604        2306 :   o << " " << macro_prefix << name << "(";
    1605             : 
    1606             :   DCHECK_EQ(signature.types().size(), parameter_names.size());
    1607             :   auto type_iterator = signature.types().begin();
    1608             :   bool first = true;
    1609        6328 :   for (const Identifier* name : parameter_names) {
    1610        4022 :     if (!first) {
    1611        1856 :       o << ", ";
    1612             :     }
    1613        4022 :     const Type* parameter_type = *type_iterator;
    1614             :     const std::string& generated_type_name =
    1615        4022 :         parameter_type->GetGeneratedTypeName();
    1616        8044 :     o << generated_type_name << " " << ExternalParameterName(name->value);
    1617             :     type_iterator++;
    1618             :     first = false;
    1619             :   }
    1620             : 
    1621        2578 :   for (const LabelDeclaration& label_info : signature.labels) {
    1622         272 :     if (!first) {
    1623         266 :       o << ", ";
    1624             :     }
    1625         544 :     o << "compiler::CodeAssemblerLabel* " << ExternalLabelName(label_info.name);
    1626             :     size_t i = 0;
    1627         324 :     for (const Type* type : label_info.types) {
    1628             :       std::string generated_type_name;
    1629          52 :       if (type->IsStructType()) {
    1630             :         generated_type_name = "\n#error no structs allowed in labels\n";
    1631             :       } else {
    1632             :         generated_type_name = "compiler::TypedCodeAssemblerVariable<";
    1633         100 :         generated_type_name += type->GetGeneratedTNodeTypeName();
    1634             :         generated_type_name += ">*";
    1635             :       }
    1636          52 :       o << ", ";
    1637             :       o << generated_type_name << " "
    1638         104 :         << ExternalLabelParameterName(label_info.name, i);
    1639          52 :       ++i;
    1640             :     }
    1641             :   }
    1642             : 
    1643        2306 :   o << ")";
    1644        2306 : }
    1645             : 
    1646             : namespace {
    1647             : 
    1648           0 : void FailCallableLookup(const std::string& reason, const QualifiedName& name,
    1649             :                         const TypeVector& parameter_types,
    1650             :                         const std::vector<Binding<LocalLabel>*>& labels,
    1651             :                         const std::vector<Signature>& candidates) {
    1652           0 :   std::stringstream stream;
    1653           0 :   stream << "\n" << reason << ": \n  " << name << "(" << parameter_types << ")";
    1654           0 :   if (labels.size() != 0) {
    1655           0 :     stream << " labels ";
    1656           0 :     for (size_t i = 0; i < labels.size(); ++i) {
    1657           0 :       stream << labels[i]->name() << "(" << labels[i]->parameter_types << ")";
    1658             :     }
    1659             :   }
    1660           0 :   stream << "\ncandidates are:";
    1661           0 :   for (const Signature& signature : candidates) {
    1662           0 :     stream << "\n  " << name;
    1663           0 :     PrintSignature(stream, signature, false);
    1664             :   }
    1665           0 :   ReportError(stream.str());
    1666             : }
    1667             : 
    1668        2293 : Callable* GetOrCreateSpecialization(const SpecializationKey& key) {
    1669        2293 :   if (base::Optional<Callable*> specialization =
    1670        2293 :           key.generic->GetSpecialization(key.specialized_types)) {
    1671             :     return *specialization;
    1672             :   }
    1673         187 :   return DeclarationVisitor().SpecializeImplicit(key);
    1674             : }
    1675             : 
    1676             : }  // namespace
    1677             : 
    1678       11740 : base::Optional<Binding<LocalValue>*> ImplementationVisitor::TryLookupLocalValue(
    1679             :     const std::string& name) {
    1680       11740 :   return ValueBindingsManager::Get().TryLookup(name);
    1681             : }
    1682             : 
    1683        7109 : base::Optional<Binding<LocalLabel>*> ImplementationVisitor::TryLookupLabel(
    1684             :     const std::string& name) {
    1685        7109 :   return LabelBindingsManager::Get().TryLookup(name);
    1686             : }
    1687             : 
    1688        1700 : Binding<LocalLabel>* ImplementationVisitor::LookupLabel(
    1689             :     const std::string& name) {
    1690        1700 :   base::Optional<Binding<LocalLabel>*> label = TryLookupLabel(name);
    1691        1700 :   if (!label) ReportError("cannot find label ", name);
    1692        1700 :   return *label;
    1693             : }
    1694             : 
    1695         117 : Block* ImplementationVisitor::LookupSimpleLabel(const std::string& name) {
    1696         117 :   LocalLabel* label = LookupLabel(name);
    1697         117 :   if (!label->parameter_types.empty()) {
    1698           0 :     ReportError("label ", name,
    1699             :                 "was expected to have no parameters, but has parameters (",
    1700           0 :                 label->parameter_types, ")");
    1701             :   }
    1702         117 :   return label->block;
    1703             : }
    1704             : 
    1705             : // Try to lookup a callable with the provided argument types. Do not report
    1706             : // an error if no matching callable was found, but return false instead.
    1707             : // This is used to test the presence of overloaded field accessors.
    1708        1135 : bool ImplementationVisitor::TestLookupCallable(
    1709             :     const QualifiedName& name, const TypeVector& parameter_types) {
    1710        4540 :   return LookupCallable(name, Declarations::TryLookup(name), parameter_types,
    1711        2270 :                         {}, {}, true) != nullptr;
    1712             : }
    1713             : 
    1714             : template <class Container>
    1715        6662 : Callable* ImplementationVisitor::LookupCallable(
    1716             :     const QualifiedName& name, const Container& declaration_container,
    1717             :     const TypeVector& parameter_types,
    1718             :     const std::vector<Binding<LocalLabel>*>& labels,
    1719             :     const TypeVector& specialization_types, bool silence_errors) {
    1720             :   Callable* result = nullptr;
    1721             : 
    1722             :   std::vector<Declarable*> overloads;
    1723        6662 :   std::vector<Signature> overload_signatures;
    1724       27582 :   for (auto* declarable : declaration_container) {
    1725       20920 :     if (Generic* generic = Generic::DynamicCast(declarable)) {
    1726             :       base::Optional<TypeVector> inferred_specialization_types =
    1727             :           generic->InferSpecializationTypes(specialization_types,
    1728        2753 :                                             parameter_types);
    1729        2753 :       if (!inferred_specialization_types) continue;
    1730        5506 :       overloads.push_back(generic);
    1731        8259 :       overload_signatures.push_back(
    1732             :           DeclarationVisitor().MakeSpecializedSignature(
    1733             :               SpecializationKey{generic, *inferred_specialization_types}));
    1734       18167 :     } else if (Callable* callable = Callable::DynamicCast(declarable)) {
    1735       36334 :       overloads.push_back(callable);
    1736       18167 :       overload_signatures.push_back(callable->signature());
    1737             :     }
    1738             :   }
    1739             :   // Indices of candidates in overloads/overload_signatures.
    1740             :   std::vector<size_t> candidates;
    1741       55164 :   for (size_t i = 0; i < overloads.size(); ++i) {
    1742             :     const Signature& signature = overload_signatures[i];
    1743             :     bool try_bool_context = labels.size() == 0 &&
    1744       20920 :                             signature.return_type == TypeOracle::GetNeverType();
    1745       21450 :     if (IsCompatibleSignature(signature, parameter_types, labels.size()) ||
    1746             :         (try_bool_context &&
    1747         530 :          IsCompatibleSignature(signature, parameter_types, 2))) {
    1748        6475 :       candidates.push_back(i);
    1749             :     }
    1750             :   }
    1751             : 
    1752        6662 :   if (overloads.empty()) {
    1753         970 :     if (silence_errors) return nullptr;
    1754           0 :     std::stringstream stream;
    1755           0 :     stream << "no matching declaration found for " << name;
    1756           0 :     ReportError(stream.str());
    1757        5692 :   } else if (candidates.empty()) {
    1758          71 :     if (silence_errors) return nullptr;
    1759           0 :     FailCallableLookup("cannot find suitable callable with name", name,
    1760             :                        parameter_types, labels, overload_signatures);
    1761             :   }
    1762             : 
    1763        1708 :   auto is_better_candidate = [&](size_t a, size_t b) {
    1764        3416 :     return ParameterDifference(overload_signatures[a].GetExplicitTypes(),
    1765        3416 :                                parameter_types)
    1766       10248 :         .StrictlyBetterThan(ParameterDifference(
    1767             :             overload_signatures[b].GetExplicitTypes(), parameter_types));
    1768        9037 :   };
    1769             : 
    1770             :   size_t best = *std::min_element(candidates.begin(), candidates.end(),
    1771        5621 :                                   is_better_candidate);
    1772             :   // This check is contained in libstdc++'s std::min_element.
    1773             :   DCHECK(!is_better_candidate(best, best));
    1774       12096 :   for (size_t candidate : candidates) {
    1775        6475 :     if (candidate != best && !is_better_candidate(best, candidate)) {
    1776             :       std::vector<Signature> candidate_signatures;
    1777           0 :       for (size_t i : candidates) {
    1778           0 :         candidate_signatures.push_back(overload_signatures[i]);
    1779             :       }
    1780           0 :       FailCallableLookup("ambiguous callable ", name, parameter_types, labels,
    1781             :                          candidate_signatures);
    1782             :     }
    1783             :   }
    1784             : 
    1785       11242 :   if (Generic* generic = Generic::DynamicCast(overloads[best])) {
    1786        8892 :     result = GetOrCreateSpecialization(
    1787             :         SpecializationKey{generic, *generic->InferSpecializationTypes(
    1788             :                                        specialization_types, parameter_types)});
    1789             :   } else {
    1790             :     result = Callable::cast(overloads[best]);
    1791             :   }
    1792             : 
    1793             :   size_t caller_size = parameter_types.size();
    1794             :   size_t callee_size =
    1795        5621 :       result->signature().types().size() - result->signature().implicit_count;
    1796        5621 :   if (caller_size != callee_size &&
    1797             :       !result->signature().parameter_types.var_args) {
    1798           0 :     std::stringstream stream;
    1799           0 :     stream << "parameter count mismatch calling " << *result << " - expected "
    1800           0 :            << std::to_string(callee_size) << ", found "
    1801           0 :            << std::to_string(caller_size);
    1802           0 :     ReportError(stream.str());
    1803             :   }
    1804             : 
    1805             :   return result;
    1806             : }
    1807             : 
    1808             : template <class Container>
    1809        5396 : Callable* ImplementationVisitor::LookupCallable(
    1810             :     const QualifiedName& name, const Container& declaration_container,
    1811             :     const Arguments& arguments, const TypeVector& specialization_types) {
    1812             :   return LookupCallable(name, declaration_container,
    1813             :                         arguments.parameters.GetTypeVector(), arguments.labels,
    1814       10792 :                         specialization_types);
    1815             : }
    1816             : 
    1817         131 : Method* ImplementationVisitor::LookupMethod(
    1818             :     const std::string& name, LocationReference this_reference,
    1819             :     const Arguments& arguments, const TypeVector& specialization_types) {
    1820         131 :   TypeVector types(arguments.parameters.GetTypeVector());
    1821         262 :   types.insert(types.begin(), this_reference.ReferencedType());
    1822         393 :   return Method::cast(LookupCallable(
    1823             :       {{}, name},
    1824         262 :       AggregateType::cast(this_reference.ReferencedType())->Methods(name),
    1825         131 :       types, arguments.labels, specialization_types));
    1826             : }
    1827             : 
    1828         102 : const Type* ImplementationVisitor::GetCommonType(const Type* left,
    1829             :                                                  const Type* right) {
    1830             :   const Type* common_type;
    1831         102 :   if (IsAssignableFrom(left, right)) {
    1832             :     common_type = left;
    1833           6 :   } else if (IsAssignableFrom(right, left)) {
    1834             :     common_type = right;
    1835             :   } else {
    1836           0 :     common_type = TypeOracle::GetUnionType(left, right);
    1837             :   }
    1838         102 :   common_type = common_type->NonConstexprVersion();
    1839         102 :   return common_type;
    1840             : }
    1841             : 
    1842       21654 : VisitResult ImplementationVisitor::GenerateCopy(const VisitResult& to_copy) {
    1843       21654 :   if (to_copy.IsOnStack()) {
    1844             :     return VisitResult(to_copy.type(),
    1845       37580 :                        assembler().Peek(to_copy.stack_range(), to_copy.type()));
    1846             :   }
    1847             :   return to_copy;
    1848             : }
    1849             : 
    1850          21 : VisitResult ImplementationVisitor::Visit(StructExpression* expr) {
    1851             :   StackScope stack_scope(this);
    1852          21 :   const Type* raw_type = Declarations::GetType(expr->type);
    1853          21 :   if (!raw_type->IsStructType()) {
    1854           0 :     ReportError(*raw_type, " is not a struct but used like one");
    1855             :   }
    1856             : 
    1857             :   const StructType* struct_type = StructType::cast(raw_type);
    1858             : 
    1859             :   InitializerResults initialization_results =
    1860             :       ImplementationVisitor::VisitInitializerResults(struct_type,
    1861          42 :                                                      expr->initializers);
    1862             : 
    1863             :   // Push uninitialized 'this'
    1864             :   VisitResult result = TemporaryUninitializedStruct(
    1865          42 :       struct_type, "it's not initialized in the struct " + struct_type->name());
    1866             : 
    1867          42 :   InitializeAggregate(struct_type, result, initialization_results);
    1868             : 
    1869          63 :   return stack_scope.Yield(result);
    1870             : }
    1871             : 
    1872       10184 : LocationReference ImplementationVisitor::GetLocationReference(
    1873             :     Expression* location) {
    1874       10184 :   switch (location->kind) {
    1875             :     case AstNode::Kind::kIdentifierExpression:
    1876        8271 :       return GetLocationReference(static_cast<IdentifierExpression*>(location));
    1877             :     case AstNode::Kind::kFieldAccessExpression:
    1878             :       return GetLocationReference(
    1879        1599 :           static_cast<FieldAccessExpression*>(location));
    1880             :     case AstNode::Kind::kElementAccessExpression:
    1881             :       return GetLocationReference(
    1882         283 :           static_cast<ElementAccessExpression*>(location));
    1883             :     case AstNode::Kind::kDereferenceExpression:
    1884             :       return GetLocationReference(
    1885           7 :           static_cast<DereferenceExpression*>(location));
    1886             :     default:
    1887          72 :       return LocationReference::Temporary(Visit(location), "expression");
    1888             :   }
    1889             : }
    1890             : 
    1891        1599 : LocationReference ImplementationVisitor::GetLocationReference(
    1892             :     FieldAccessExpression* expr) {
    1893        1599 :   const std::string& fieldname = expr->field->value;
    1894        3198 :   LocationReference reference = GetLocationReference(expr->object);
    1895        1599 :   if (reference.IsVariableAccess() &&
    1896             :       reference.variable().type()->IsStructType()) {
    1897             :     const StructType* type = StructType::cast(reference.variable().type());
    1898         344 :     const Field& field = type->LookupField(fieldname);
    1899         344 :     if (GlobalContext::collect_language_server_data()) {
    1900           0 :       LanguageServerData::AddDefinition(expr->field->pos, field.pos);
    1901             :     }
    1902         344 :     if (field.const_qualified) {
    1903         116 :       VisitResult t_value = ProjectStructField(reference.variable(), fieldname);
    1904             :       return LocationReference::Temporary(
    1905         290 :           t_value, "for constant field '" + field.name_and_type.name + "'");
    1906             :     } else {
    1907             :       return LocationReference::VariableAccess(
    1908         858 :           ProjectStructField(reference.variable(), fieldname));
    1909             :     }
    1910             :   }
    1911        1255 :   if (reference.IsTemporary() && reference.temporary().type()->IsStructType()) {
    1912         114 :     if (GlobalContext::collect_language_server_data()) {
    1913             :       const StructType* type = StructType::cast(reference.temporary().type());
    1914           0 :       const Field& field = type->LookupField(fieldname);
    1915           0 :       LanguageServerData::AddDefinition(expr->field->pos, field.pos);
    1916             :     }
    1917             :     return LocationReference::Temporary(
    1918         342 :         ProjectStructField(reference.temporary(), fieldname),
    1919         228 :         reference.temporary_description());
    1920             :   }
    1921        1141 :   VisitResult object_result = GenerateFetchFromLocation(reference);
    1922        1141 :   if (base::Optional<const ClassType*> class_type =
    1923        1141 :           object_result.type()->ClassSupertype()) {
    1924             :     // This is a hack to distinguish the situation where we want to use
    1925             :     // overloaded field accessors from when we want to create a reference.
    1926        4540 :     bool has_explicit_overloads = TestLookupCallable(
    1927        3405 :         QualifiedName{"." + fieldname}, {object_result.type()});
    1928        1135 :     if ((*class_type)->HasField(fieldname) && !has_explicit_overloads) {
    1929        1041 :       const Field& field = (*class_type)->LookupField(fieldname);
    1930        1041 :       if (GlobalContext::collect_language_server_data()) {
    1931           0 :         LanguageServerData::AddDefinition(expr->field->pos, field.pos);
    1932             :       }
    1933        1041 :       if (field.index) {
    1934         384 :         return LocationReference::IndexedFieldAccess(object_result, fieldname);
    1935             :       } else {
    1936        3652 :         assembler().Emit(
    1937         913 :             CreateFieldReferenceInstruction{*class_type, fieldname});
    1938             :         const Type* reference_type =
    1939         913 :             TypeOracle::GetReferenceType(field.name_and_type.type);
    1940             :         return LocationReference::HeapReference(
    1941         913 :             VisitResult(reference_type, assembler().TopRange(2)));
    1942             :       }
    1943             :     }
    1944             :   }
    1945         300 :   return LocationReference::FieldAccess(object_result, fieldname);
    1946             : }
    1947             : 
    1948         283 : LocationReference ImplementationVisitor::GetLocationReference(
    1949             :     ElementAccessExpression* expr) {
    1950         566 :   LocationReference reference = GetLocationReference(expr->array);
    1951         283 :   VisitResult index = Visit(expr->index);
    1952         283 :   if (reference.IsIndexedFieldAccess()) {
    1953         256 :     return LocationReference::IndexedFieldIndexedAccess(reference, index);
    1954             :   } else {
    1955         310 :     return LocationReference::ArrayAccess(GenerateFetchFromLocation(reference),
    1956         310 :                                           index);
    1957             :   }
    1958             : }
    1959             : 
    1960        8271 : LocationReference ImplementationVisitor::GetLocationReference(
    1961             :     IdentifierExpression* expr) {
    1962        8271 :   if (expr->namespace_qualification.empty()) {
    1963        8271 :     if (base::Optional<Binding<LocalValue>*> value =
    1964        8271 :             TryLookupLocalValue(expr->name->value)) {
    1965        7168 :       if (GlobalContext::collect_language_server_data()) {
    1966           1 :         LanguageServerData::AddDefinition(expr->name->pos,
    1967           1 :                                           (*value)->declaration_position());
    1968             :       }
    1969        7168 :       if (expr->generic_arguments.size() != 0) {
    1970           0 :         ReportError("cannot have generic parameters on local name ",
    1971           0 :                     expr->name);
    1972             :       }
    1973        7168 :       if ((*value)->is_const) {
    1974             :         return LocationReference::Temporary(
    1975       20312 :             (*value)->value, "constant value " + expr->name->value);
    1976             :       }
    1977        2090 :       return LocationReference::VariableAccess((*value)->value);
    1978             :     }
    1979             :   }
    1980             : 
    1981        1103 :   if (expr->IsThis()) {
    1982           0 :     ReportError("\"this\" cannot be qualified");
    1983             :   }
    1984             :   QualifiedName name =
    1985        5515 :       QualifiedName(expr->namespace_qualification, expr->name->value);
    1986        1103 :   if (base::Optional<Builtin*> builtin = Declarations::TryLookupBuiltin(name)) {
    1987           4 :     if (GlobalContext::collect_language_server_data()) {
    1988           0 :       LanguageServerData::AddDefinition(expr->name->pos, (*builtin)->pos());
    1989             :     }
    1990           8 :     return LocationReference::Temporary(GetBuiltinCode(*builtin),
    1991          12 :                                         "builtin " + expr->name->value);
    1992             :   }
    1993        1099 :   if (expr->generic_arguments.size() != 0) {
    1994          70 :     Generic* generic = Declarations::LookupUniqueGeneric(name);
    1995         140 :     Callable* specialization = GetOrCreateSpecialization(
    1996          70 :         SpecializationKey{generic, GetTypeVector(expr->generic_arguments)});
    1997          70 :     if (Builtin* builtin = Builtin::DynamicCast(specialization)) {
    1998             :       DCHECK(!builtin->IsExternal());
    1999         140 :       return LocationReference::Temporary(GetBuiltinCode(builtin),
    2000         210 :                                           "builtin " + expr->name->value);
    2001             :     } else {
    2002             :       ReportError("cannot create function pointer for non-builtin ",
    2003           0 :                   generic->name());
    2004             :     }
    2005             :   }
    2006        1029 :   Value* value = Declarations::LookupValue(name);
    2007        1029 :   if (GlobalContext::collect_language_server_data()) {
    2008           0 :     LanguageServerData::AddDefinition(expr->name->pos, value->name()->pos);
    2009             :   }
    2010        1029 :   if (auto* constant = NamespaceConstant::DynamicCast(value)) {
    2011         400 :     if (constant->type()->IsConstexpr()) {
    2012             :       return LocationReference::Temporary(
    2013         111 :           VisitResult(constant->type(), constant->ExternalAssemblerName() +
    2014         111 :                                             "(state_)." +
    2015          74 :                                             constant->name()->value + "()"),
    2016         148 :           "namespace constant " + expr->name->value);
    2017             :     }
    2018        1452 :     assembler().Emit(NamespaceConstantInstruction{constant});
    2019             :     StackRange stack_range =
    2020         363 :         assembler().TopRange(LoweredSlotCount(constant->type()));
    2021             :     return LocationReference::Temporary(
    2022             :         VisitResult(constant->type(), stack_range),
    2023        1452 :         "namespace constant " + expr->name->value);
    2024             :   }
    2025             :   ExternConstant* constant = ExternConstant::cast(value);
    2026         629 :   return LocationReference::Temporary(constant->value(),
    2027        1887 :                                       "extern value " + expr->name->value);
    2028             : }
    2029             : 
    2030           7 : LocationReference ImplementationVisitor::GetLocationReference(
    2031             :     DereferenceExpression* expr) {
    2032           7 :   VisitResult ref = Visit(expr->reference);
    2033             :   const ReferenceType* type = ReferenceType::DynamicCast(ref.type());
    2034           7 :   if (!type) {
    2035             :     ReportError("Operator * expects a reference but found a value of type ",
    2036           0 :                 *ref.type());
    2037             :   }
    2038          14 :   return LocationReference::HeapReference(ref);
    2039             : }
    2040             : 
    2041        8701 : VisitResult ImplementationVisitor::GenerateFetchFromLocation(
    2042             :     const LocationReference& reference) {
    2043        8701 :   if (reference.IsTemporary()) {
    2044        6263 :     return GenerateCopy(reference.temporary());
    2045        2438 :   } else if (reference.IsVariableAccess()) {
    2046        1575 :     return GenerateCopy(reference.variable());
    2047         863 :   } else if (reference.IsHeapReference()) {
    2048        1094 :     GenerateCopy(reference.heap_reference());
    2049        2188 :     assembler().Emit(LoadReferenceInstruction{reference.ReferencedType()});
    2050             :     DCHECK_EQ(1, LoweredSlotCount(reference.ReferencedType()));
    2051             :     return VisitResult(reference.ReferencedType(), assembler().TopRange(1));
    2052             :   } else {
    2053         316 :     if (reference.IsIndexedFieldAccess()) {
    2054             :       ReportError(
    2055           0 :           "fetching a value directly from an indexed field isn't allowed");
    2056             :     }
    2057             :     DCHECK(reference.IsCallAccess());
    2058             :     return GenerateCall(reference.eval_function(),
    2059         948 :                         Arguments{reference.call_arguments(), {}});
    2060             :   }
    2061             : }
    2062             : 
    2063        1073 : void ImplementationVisitor::GenerateAssignToLocation(
    2064             :     const LocationReference& reference, const VisitResult& assignment_value) {
    2065        1073 :   if (reference.IsCallAccess()) {
    2066          67 :     Arguments arguments{reference.call_arguments(), {}};
    2067          67 :     arguments.parameters.push_back(assignment_value);
    2068         335 :     GenerateCall(reference.assign_function(), arguments);
    2069        1006 :   } else if (reference.IsVariableAccess()) {
    2070             :     VisitResult variable = reference.variable();
    2071             :     VisitResult converted_value =
    2072        1172 :         GenerateImplicitConvert(variable.type(), assignment_value);
    2073         586 :     assembler().Poke(variable.stack_range(), converted_value.stack_range(),
    2074         586 :                      variable.type());
    2075         420 :   } else if (reference.IsIndexedFieldAccess()) {
    2076           0 :     ReportError("assigning a value directly to an indexed field isn't allowed");
    2077         420 :   } else if (reference.IsHeapReference()) {
    2078             :     const Type* referenced_type = reference.ReferencedType();
    2079         840 :     GenerateCopy(reference.heap_reference());
    2080        1260 :     GenerateImplicitConvert(referenced_type, assignment_value);
    2081        1680 :     assembler().Emit(StoreReferenceInstruction{referenced_type});
    2082             :   } else {
    2083             :     DCHECK(reference.IsTemporary());
    2084             :     ReportError("cannot assign to temporary ",
    2085           0 :                 reference.temporary_description());
    2086             :   }
    2087        1073 : }
    2088             : 
    2089          23 : VisitResult ImplementationVisitor::GeneratePointerCall(
    2090             :     Expression* callee, const Arguments& arguments, bool is_tailcall) {
    2091             :   StackScope scope(this);
    2092          23 :   TypeVector parameter_types(arguments.parameters.GetTypeVector());
    2093          23 :   VisitResult callee_result = Visit(callee);
    2094          23 :   if (!callee_result.type()->IsBuiltinPointerType()) {
    2095           0 :     std::stringstream stream;
    2096             :     stream << "Expected a function pointer type but found "
    2097           0 :            << *callee_result.type();
    2098           0 :     ReportError(stream.str());
    2099             :   }
    2100             :   const BuiltinPointerType* type =
    2101             :       BuiltinPointerType::cast(callee_result.type());
    2102             : 
    2103          23 :   if (type->parameter_types().size() != parameter_types.size()) {
    2104           0 :     std::stringstream stream;
    2105             :     stream << "parameter count mismatch calling function pointer with Type: "
    2106           0 :            << *type << " - expected "
    2107           0 :            << std::to_string(type->parameter_types().size()) << ", found "
    2108           0 :            << std::to_string(parameter_types.size());
    2109           0 :     ReportError(stream.str());
    2110             :   }
    2111             : 
    2112          46 :   ParameterTypes types{type->parameter_types(), false};
    2113          23 :   Signature sig;
    2114             :   sig.parameter_types = types;
    2115          23 :   if (!IsCompatibleSignature(sig, parameter_types, 0)) {
    2116           0 :     std::stringstream stream;
    2117             :     stream << "parameters do not match function pointer signature. Expected: ("
    2118           0 :            << type->parameter_types() << ") but got: (" << parameter_types
    2119           0 :            << ")";
    2120           0 :     ReportError(stream.str());
    2121             :   }
    2122             : 
    2123          46 :   callee_result = GenerateCopy(callee_result);
    2124             :   StackRange arg_range = assembler().TopRange(0);
    2125         157 :   for (size_t current = 0; current < arguments.parameters.size(); ++current) {
    2126          67 :     const Type* to_type = type->parameter_types()[current];
    2127             :     arg_range.Extend(
    2128         201 :         GenerateImplicitConvert(to_type, arguments.parameters[current])
    2129             :             .stack_range());
    2130             :   }
    2131             : 
    2132          69 :   assembler().Emit(
    2133          23 :       CallBuiltinPointerInstruction{is_tailcall, type, arg_range.Size()});
    2134             : 
    2135          23 :   if (is_tailcall) {
    2136           0 :     return VisitResult::NeverResult();
    2137             :   }
    2138             :   DCHECK_EQ(1, LoweredSlotCount(type->return_type()));
    2139          46 :   return scope.Yield(VisitResult(type->return_type(), assembler().TopRange(1)));
    2140             : }
    2141             : 
    2142        9986 : void ImplementationVisitor::AddCallParameter(
    2143             :     Callable* callable, VisitResult parameter, const Type* parameter_type,
    2144             :     std::vector<VisitResult>* converted_arguments, StackRange* argument_range,
    2145             :     std::vector<std::string>* constexpr_arguments) {
    2146       19972 :   VisitResult converted = GenerateImplicitConvert(parameter_type, parameter);
    2147        9986 :   converted_arguments->push_back(converted);
    2148        9986 :   if (!callable->ShouldBeInlined()) {
    2149        9883 :     if (converted.IsOnStack()) {
    2150             :       argument_range->Extend(converted.stack_range());
    2151             :     } else {
    2152        2023 :       constexpr_arguments->push_back(converted.constexpr_value());
    2153             :     }
    2154             :   }
    2155        9986 : }
    2156             : 
    2157        5527 : VisitResult ImplementationVisitor::GenerateCall(
    2158             :     Callable* callable, base::Optional<LocationReference> this_reference,
    2159             :     Arguments arguments, const TypeVector& specialization_types,
    2160             :     bool is_tailcall) {
    2161             :   // Operators used in a branching context can also be function calls that never
    2162             :   // return but have a True and False label
    2163       10587 :   if (arguments.labels.size() == 0 &&
    2164             :       callable->signature().labels.size() == 2) {
    2165             :     base::Optional<Binding<LocalLabel>*> true_label =
    2166         146 :         TryLookupLabel(kTrueLabelName);
    2167             :     base::Optional<Binding<LocalLabel>*> false_label =
    2168         146 :         TryLookupLabel(kFalseLabelName);
    2169          73 :     if (!true_label || !false_label) {
    2170             :       ReportError(
    2171             :           callable->ReadableName(),
    2172             :           " does not return a value, but has to be called in a branching "
    2173             :           "context (e.g., conditional or if-condition). You can fix this by "
    2174           0 :           "adding \"? true : false\".");
    2175             :     }
    2176          73 :     arguments.labels.push_back(*true_label);
    2177          73 :     arguments.labels.push_back(*false_label);
    2178             :   }
    2179             : 
    2180        5527 :   const Type* return_type = callable->signature().return_type;
    2181             : 
    2182        5527 :   std::vector<VisitResult> converted_arguments;
    2183        5527 :   StackRange argument_range = assembler().TopRange(0);
    2184        5527 :   std::vector<std::string> constexpr_arguments;
    2185             : 
    2186             :   size_t current = 0;
    2187        7331 :   for (; current < callable->signature().implicit_count; ++current) {
    2188             :     std::string implicit_name =
    2189         902 :         callable->signature().parameter_names[current]->value;
    2190             :     base::Optional<Binding<LocalValue>*> val =
    2191         902 :         TryLookupLocalValue(implicit_name);
    2192         902 :     if (!val) {
    2193             :       ReportError("implicit parameter '", implicit_name,
    2194             :                   "' required for call to '", callable->ReadableName(),
    2195           0 :                   "' is not defined");
    2196             :     }
    2197        1804 :     AddCallParameter(callable, (*val)->value,
    2198             :                      callable->signature().parameter_types.types[current],
    2199             :                      &converted_arguments, &argument_range,
    2200         902 :                      &constexpr_arguments);
    2201             :   }
    2202             : 
    2203        5527 :   if (this_reference) {
    2204             :     DCHECK(callable->IsMethod());
    2205             :     Method* method = Method::cast(callable);
    2206             :     // By now, the this reference should either be a variable or
    2207             :     // a temporary, in both cases the fetch of the VisitResult should succeed.
    2208             :     VisitResult this_value = this_reference->GetVisitResult();
    2209         131 :     if (method->ShouldBeInlined()) {
    2210         108 :       if (!this_value.type()->IsSubtypeOf(method->aggregate_type())) {
    2211           0 :         ReportError("this parameter must be a subtype of ",
    2212             :                     *method->aggregate_type(), " but it is of type ",
    2213           0 :                     this_value.type());
    2214             :       }
    2215             :     } else {
    2216          23 :       AddCallParameter(callable, this_value, method->aggregate_type(),
    2217             :                        &converted_arguments, &argument_range,
    2218          23 :                        &constexpr_arguments);
    2219             :     }
    2220         131 :     ++current;
    2221             :   }
    2222             : 
    2223       14588 :   for (auto arg : arguments.parameters) {
    2224             :     const Type* to_type = (current >= callable->signature().types().size())
    2225             :                               ? TypeOracle::GetObjectType()
    2226       18122 :                               : callable->signature().types()[current++];
    2227        9061 :     AddCallParameter(callable, arg, to_type, &converted_arguments,
    2228        9061 :                      &argument_range, &constexpr_arguments);
    2229             :   }
    2230             : 
    2231        5527 :   if (GlobalContext::verbose()) {
    2232             :     std::cout << "generating code for call to " << callable->ReadableName()
    2233           0 :               << "\n";
    2234             :   }
    2235             : 
    2236             :   size_t label_count = callable->signature().labels.size();
    2237        5527 :   if (label_count != arguments.labels.size()) {
    2238           0 :     std::stringstream s;
    2239             :     s << "unexpected number of otherwise labels for "
    2240             :       << callable->ReadableName() << " (expected "
    2241           0 :       << std::to_string(label_count) << " found "
    2242           0 :       << std::to_string(arguments.labels.size()) << ")";
    2243           0 :     ReportError(s.str());
    2244             :   }
    2245             : 
    2246        5527 :   if (callable->IsTransitioning()) {
    2247         319 :     if (!CurrentCallable::Get()->IsTransitioning()) {
    2248           0 :       std::stringstream s;
    2249           0 :       s << *CurrentCallable::Get()
    2250             :         << " isn't marked transitioning but calls the transitioning "
    2251           0 :         << *callable;
    2252           0 :       ReportError(s.str());
    2253             :     }
    2254             :   }
    2255             : 
    2256        5527 :   if (auto* builtin = Builtin::DynamicCast(callable)) {
    2257         143 :     base::Optional<Block*> catch_block = GetCatchBlock();
    2258         429 :     assembler().Emit(CallBuiltinInstruction{
    2259         143 :         is_tailcall, builtin, argument_range.Size(), catch_block});
    2260         143 :     GenerateCatchBlock(catch_block);
    2261         143 :     if (is_tailcall) {
    2262           2 :       return VisitResult::NeverResult();
    2263             :     } else {
    2264         141 :       size_t slot_count = LoweredSlotCount(return_type);
    2265             :       DCHECK_LE(slot_count, 1);
    2266             :       // TODO(tebbi): Actually, builtins have to return a value, so we should
    2267             :       // assert slot_count == 1 here.
    2268             :       return VisitResult(return_type, assembler().TopRange(slot_count));
    2269             :     }
    2270        5384 :   } else if (auto* macro = Macro::DynamicCast(callable)) {
    2271        5252 :     if (is_tailcall) {
    2272           0 :       ReportError("can't tail call a macro");
    2273             :     }
    2274        5252 :     if (return_type->IsConstexpr()) {
    2275             :       DCHECK_EQ(0, arguments.labels.size());
    2276         214 :       std::stringstream result;
    2277             :       result << "(" << macro->external_assembler_name() << "(state_)."
    2278         107 :              << macro->ExternalName() << "(";
    2279             :       bool first = true;
    2280         238 :       for (VisitResult arg : arguments.parameters) {
    2281             :         DCHECK(!arg.IsOnStack());
    2282         131 :         if (!first) {
    2283          59 :           result << ", ";
    2284             :         }
    2285             :         first = false;
    2286             :         result << arg.constexpr_value();
    2287             :       }
    2288         107 :       result << "))";
    2289         107 :       return VisitResult(return_type, result.str());
    2290        5145 :     } else if (macro->ShouldBeInlined()) {
    2291             :       std::vector<Block*> label_blocks;
    2292         150 :       for (Binding<LocalLabel>* label : arguments.labels) {
    2293          41 :         label_blocks.push_back(label->block);
    2294             :       }
    2295             :       return InlineMacro(macro, this_reference, converted_arguments,
    2296         436 :                          label_blocks);
    2297        9573 :     } else if (arguments.labels.empty() &&
    2298        4537 :                return_type != TypeOracle::GetNeverType()) {
    2299        4438 :       base::Optional<Block*> catch_block = GetCatchBlock();
    2300       13314 :       assembler().Emit(
    2301        4438 :           CallCsaMacroInstruction{macro, constexpr_arguments, catch_block});
    2302        4438 :       GenerateCatchBlock(catch_block);
    2303        4438 :       size_t return_slot_count = LoweredSlotCount(return_type);
    2304             :       return VisitResult(return_type, assembler().TopRange(return_slot_count));
    2305             :     } else {
    2306         598 :       base::Optional<Block*> return_continuation;
    2307         598 :       if (return_type != TypeOracle::GetNeverType()) {
    2308         828 :         return_continuation = assembler().NewBlock();
    2309             :       }
    2310             : 
    2311             :       std::vector<Block*> label_blocks;
    2312             : 
    2313        1758 :       for (size_t i = 0; i < label_count; ++i) {
    2314        1740 :         label_blocks.push_back(assembler().NewBlock());
    2315             :       }
    2316         598 :       base::Optional<Block*> catch_block = GetCatchBlock();
    2317        1794 :       assembler().Emit(CallCsaMacroAndBranchInstruction{
    2318             :           macro, constexpr_arguments, return_continuation, label_blocks,
    2319         598 :           catch_block});
    2320         598 :       GenerateCatchBlock(catch_block);
    2321             : 
    2322        1758 :       for (size_t i = 0; i < label_count; ++i) {
    2323         580 :         Binding<LocalLabel>* label = arguments.labels[i];
    2324             :         size_t callee_label_parameters =
    2325             :             callable->signature().labels[i].types.size();
    2326         580 :         if (label->parameter_types.size() != callee_label_parameters) {
    2327           0 :           std::stringstream s;
    2328             :           s << "label " << label->name()
    2329             :             << " doesn't have the right number of parameters (found "
    2330           0 :             << std::to_string(label->parameter_types.size()) << " expected "
    2331           0 :             << std::to_string(callee_label_parameters) << ")";
    2332           0 :           ReportError(s.str());
    2333             :         }
    2334         580 :         assembler().Bind(label_blocks[i]);
    2335             :         assembler().Goto(
    2336             :             label->block,
    2337        1740 :             LowerParameterTypes(callable->signature().labels[i].types).size());
    2338             : 
    2339             :         size_t j = 0;
    2340         605 :         for (auto t : callable->signature().labels[i].types) {
    2341          25 :           const Type* parameter_type = label->parameter_types[j];
    2342          25 :           if (parameter_type != t) {
    2343           0 :             ReportError("mismatch of label parameters (expected ", *t, " got ",
    2344           0 :                         parameter_type, " for parameter ", i + 1, ")");
    2345             :           }
    2346          25 :           j++;
    2347             :         }
    2348             :       }
    2349             : 
    2350         598 :       if (return_continuation) {
    2351         414 :         assembler().Bind(*return_continuation);
    2352         414 :         size_t return_slot_count = LoweredSlotCount(return_type);
    2353             :         return VisitResult(return_type,
    2354             :                            assembler().TopRange(return_slot_count));
    2355             :       } else {
    2356         184 :         return VisitResult::NeverResult();
    2357             :       }
    2358             :     }
    2359         132 :   } else if (auto* runtime_function = RuntimeFunction::DynamicCast(callable)) {
    2360          27 :     base::Optional<Block*> catch_block = GetCatchBlock();
    2361          81 :     assembler().Emit(CallRuntimeInstruction{
    2362          27 :         is_tailcall, runtime_function, argument_range.Size(), catch_block});
    2363          27 :     GenerateCatchBlock(catch_block);
    2364          27 :     if (is_tailcall || return_type == TypeOracle::GetNeverType()) {
    2365          12 :       return VisitResult::NeverResult();
    2366             :     } else {
    2367          15 :       size_t slot_count = LoweredSlotCount(return_type);
    2368             :       DCHECK_LE(slot_count, 1);
    2369             :       // TODO(tebbi): Actually, runtime functions have to return a value, so
    2370             :       // we should assert slot_count == 1 here.
    2371             :       return VisitResult(return_type, assembler().TopRange(slot_count));
    2372             :     }
    2373         105 :   } else if (auto* intrinsic = Intrinsic::DynamicCast(callable)) {
    2374         105 :     if (intrinsic->ExternalName() == "%RawConstexprCast") {
    2375           2 :       if (intrinsic->signature().parameter_types.types.size() != 1 ||
    2376             :           constexpr_arguments.size() != 1) {
    2377             :         ReportError(
    2378             :             "%RawConstexprCast must take a single parameter with constexpr "
    2379           0 :             "type");
    2380             :       }
    2381           1 :       if (!return_type->IsConstexpr()) {
    2382           0 :         std::stringstream s;
    2383           0 :         s << *return_type
    2384           0 :           << " return type for %RawConstexprCast is not constexpr";
    2385           0 :         ReportError(s.str());
    2386             :       }
    2387           2 :       std::stringstream result;
    2388           3 :       result << "static_cast<" << return_type->GetGeneratedTypeName() << ">(";
    2389             :       result << constexpr_arguments[0];
    2390           1 :       result << ")";
    2391           1 :       return VisitResult(return_type, result.str());
    2392             :     } else {
    2393         312 :       assembler().Emit(CallIntrinsicInstruction{intrinsic, specialization_types,
    2394         104 :                                                 constexpr_arguments});
    2395             :       size_t return_slot_count =
    2396         104 :           LoweredSlotCount(intrinsic->signature().return_type);
    2397             :       return VisitResult(return_type, assembler().TopRange(return_slot_count));
    2398             :     }
    2399             :   } else {
    2400           0 :     UNREACHABLE();
    2401             :   }
    2402             : }
    2403             : 
    2404        5396 : VisitResult ImplementationVisitor::GenerateCall(
    2405             :     const QualifiedName& callable_name, Arguments arguments,
    2406             :     const TypeVector& specialization_types, bool is_tailcall) {
    2407             :   Callable* callable =
    2408       10792 :       LookupCallable(callable_name, Declarations::Lookup(callable_name),
    2409        5396 :                      arguments, specialization_types);
    2410             :   return GenerateCall(callable, base::nullopt, arguments, specialization_types,
    2411       16188 :                       is_tailcall);
    2412             : }
    2413             : 
    2414        3289 : VisitResult ImplementationVisitor::Visit(CallExpression* expr,
    2415             :                                          bool is_tailcall) {
    2416             :   StackScope scope(this);
    2417             : 
    2418        6603 :   if (expr->callee->name->value == "&" && expr->arguments.size() == 1) {
    2419           6 :     if (auto* loc_expr = LocationExpression::DynamicCast(expr->arguments[0])) {
    2420           3 :       LocationReference ref = GetLocationReference(loc_expr);
    2421           9 :       if (ref.IsHeapReference()) return scope.Yield(ref.heap_reference());
    2422             :     }
    2423           0 :     ReportError("Unable to create a heap reference.");
    2424             :   }
    2425             : 
    2426        3286 :   Arguments arguments;
    2427        3286 :   QualifiedName name = QualifiedName(expr->callee->namespace_qualification,
    2428       16430 :                                      expr->callee->name->value);
    2429             :   TypeVector specialization_types =
    2430        3286 :       GetTypeVector(expr->callee->generic_arguments);
    2431             :   bool has_template_arguments = !specialization_types.empty();
    2432        9647 :   for (Expression* arg : expr->arguments)
    2433       12722 :     arguments.parameters.push_back(Visit(arg));
    2434        6572 :   arguments.labels = LabelsFromIdentifiers(expr->labels);
    2435        5853 :   if (!has_template_arguments && name.namespace_qualification.empty() &&
    2436        2567 :       TryLookupLocalValue(name.name)) {
    2437             :     return scope.Yield(
    2438          46 :         GeneratePointerCall(expr->callee, arguments, is_tailcall));
    2439             :   } else {
    2440        3263 :     if (GlobalContext::collect_language_server_data()) {
    2441           0 :       Callable* callable = LookupCallable(name, Declarations::Lookup(name),
    2442           0 :                                           arguments, specialization_types);
    2443           0 :       LanguageServerData::AddDefinition(expr->callee->name->pos,
    2444           0 :                                         callable->pos());
    2445             :     }
    2446             :     return scope.Yield(
    2447        6526 :         GenerateCall(name, arguments, specialization_types, is_tailcall));
    2448             :   }
    2449             : }
    2450             : 
    2451         129 : VisitResult ImplementationVisitor::Visit(CallMethodExpression* expr) {
    2452             :   StackScope scope(this);
    2453         129 :   Arguments arguments;
    2454         129 :   std::string method_name = expr->method->name->value;
    2455             :   TypeVector specialization_types =
    2456         129 :       GetTypeVector(expr->method->generic_arguments);
    2457         258 :   LocationReference target = GetLocationReference(expr->target);
    2458         129 :   if (!target.IsVariableAccess()) {
    2459          31 :     VisitResult result = GenerateFetchFromLocation(target);
    2460         124 :     target = LocationReference::Temporary(result, "method target result");
    2461             :   }
    2462             :   const AggregateType* target_type =
    2463             :       AggregateType::DynamicCast(target.ReferencedType());
    2464         129 :   if (!target_type) {
    2465           0 :     ReportError("target of method call not a struct or class type");
    2466             :   }
    2467         230 :   for (Expression* arg : expr->arguments) {
    2468         202 :     arguments.parameters.push_back(Visit(arg));
    2469             :   }
    2470         258 :   arguments.labels = LabelsFromIdentifiers(expr->labels);
    2471         129 :   TypeVector argument_types = arguments.parameters.GetTypeVector();
    2472             :   DCHECK_EQ(expr->method->namespace_qualification.size(), 0);
    2473         387 :   QualifiedName qualified_name = QualifiedName(method_name);
    2474             :   Callable* callable = nullptr;
    2475         258 :   callable = LookupMethod(method_name, target, arguments, {});
    2476         774 :   return scope.Yield(GenerateCall(callable, target, arguments, {}, false));
    2477             : }
    2478             : 
    2479          84 : VisitResult ImplementationVisitor::Visit(IntrinsicCallExpression* expr) {
    2480             :   StackScope scope(this);
    2481          84 :   Arguments arguments;
    2482          84 :   TypeVector specialization_types = GetTypeVector(expr->generic_arguments);
    2483         168 :   for (Expression* arg : expr->arguments)
    2484         168 :     arguments.parameters.push_back(Visit(arg));
    2485             :   return scope.Yield(
    2486         420 :       GenerateCall(expr->name, arguments, specialization_types, false));
    2487             : }
    2488             : 
    2489           0 : void ImplementationVisitor::GenerateBranch(const VisitResult& condition,
    2490             :                                            Block* true_block,
    2491             :                                            Block* false_block) {
    2492             :   DCHECK_EQ(condition,
    2493             :             VisitResult(TypeOracle::GetBoolType(), assembler().TopRange(1)));
    2494         759 :   assembler().Branch(true_block, false_block);
    2495           0 : }
    2496             : 
    2497         859 : void ImplementationVisitor::GenerateExpressionBranch(
    2498             :     VisitResultGenerator generator, Block* true_block, Block* false_block) {
    2499             :   // Conditional expressions can either explicitly return a bit
    2500             :   // type, or they can be backed by macros that don't return but
    2501             :   // take a true and false label. By declaring the labels before
    2502             :   // visiting the conditional expression, those label-based
    2503             :   // macro conditionals will be able to find them through normal
    2504             :   // label lookups.
    2505             :   Binding<LocalLabel> true_binding{&LabelBindingsManager::Get(), kTrueLabelName,
    2506        4295 :                                    LocalLabel{true_block}};
    2507             :   Binding<LocalLabel> false_binding{&LabelBindingsManager::Get(),
    2508        4295 :                                     kFalseLabelName, LocalLabel{false_block}};
    2509             :   StackScope stack_scope(this);
    2510             :   VisitResult expression_result = generator();
    2511         859 :   if (!expression_result.type()->IsNever()) {
    2512        1518 :     expression_result = stack_scope.Yield(
    2513        3036 :         GenerateImplicitConvert(TypeOracle::GetBoolType(), expression_result));
    2514             :     GenerateBranch(expression_result, true_block, false_block);
    2515             :   }
    2516         859 : }
    2517             : 
    2518         857 : void ImplementationVisitor::GenerateExpressionBranch(Expression* expression,
    2519             :                                                      Block* true_block,
    2520             :                                                      Block* false_block) {
    2521        1714 :   GenerateExpressionBranch([&]() { return this->Visit(expression); },
    2522         857 :                            true_block, false_block);
    2523         857 : }
    2524             : 
    2525       14239 : VisitResult ImplementationVisitor::GenerateImplicitConvert(
    2526             :     const Type* destination_type, VisitResult source) {
    2527             :   StackScope scope(this);
    2528       14239 :   if (source.type() == TypeOracle::GetNeverType()) {
    2529           0 :     ReportError("it is not allowed to use a value of type never");
    2530             :   }
    2531             : 
    2532       14239 :   if (destination_type == source.type()) {
    2533       23278 :     return scope.Yield(GenerateCopy(source));
    2534             :   }
    2535             : 
    2536        2600 :   if (TypeOracle::IsImplicitlyConvertableFrom(destination_type,
    2537             :                                               source.type())) {
    2538        8772 :     return scope.Yield(GenerateCall(kFromConstexprMacroName, {{source}, {}},
    2539        1462 :                                     {destination_type, source.type()}, false));
    2540        1138 :   } else if (IsAssignableFrom(destination_type, source.type())) {
    2541             :     source.SetType(destination_type);
    2542        2276 :     return scope.Yield(GenerateCopy(source));
    2543             :   } else {
    2544           0 :     std::stringstream s;
    2545           0 :     s << "cannot use expression of type " << *source.type()
    2546           0 :       << " as a value of type " << *destination_type;
    2547           0 :     ReportError(s.str());
    2548             :   }
    2549             : }
    2550             : 
    2551           0 : StackRange ImplementationVisitor::GenerateLabelGoto(
    2552             :     LocalLabel* label, base::Optional<StackRange> arguments) {
    2553        1746 :   return assembler().Goto(label->block, arguments ? arguments->Size() : 0);
    2554             : }
    2555             : 
    2556        3415 : std::vector<Binding<LocalLabel>*> ImplementationVisitor::LabelsFromIdentifiers(
    2557             :     const std::vector<std::string>& names) {
    2558             :   std::vector<Binding<LocalLabel>*> result;
    2559        3415 :   result.reserve(names.size());
    2560        3888 :   for (const auto& name : names) {
    2561         946 :     result.push_back(LookupLabel(name));
    2562             :   }
    2563        3415 :   return result;
    2564             : }
    2565             : 
    2566        2110 : StackRange ImplementationVisitor::LowerParameter(
    2567             :     const Type* type, const std::string& parameter_name,
    2568             :     Stack<std::string>* lowered_parameters) {
    2569        2110 :   if (const StructType* struct_type = StructType::DynamicCast(type)) {
    2570             :     StackRange range = lowered_parameters->TopRange(0);
    2571         209 :     for (auto& field : struct_type->fields()) {
    2572             :       StackRange parameter_range = LowerParameter(
    2573         162 :           field.name_and_type.type,
    2574         648 :           parameter_name + "." + field.name_and_type.name, lowered_parameters);
    2575             :       range.Extend(parameter_range);
    2576             :     }
    2577          47 :     return range;
    2578        2063 :   } else if (type->IsReferenceType()) {
    2579           4 :     lowered_parameters->Push(parameter_name + ".object");
    2580           4 :     lowered_parameters->Push(parameter_name + ".offset");
    2581             :     return lowered_parameters->TopRange(2);
    2582             :   } else {
    2583        2061 :     lowered_parameters->Push(parameter_name);
    2584             :     return lowered_parameters->TopRange(1);
    2585             :   }
    2586             : }
    2587             : 
    2588          29 : void ImplementationVisitor::LowerLabelParameter(
    2589             :     const Type* type, const std::string& parameter_name,
    2590             :     std::vector<std::string>* lowered_parameters) {
    2591          29 :   if (const StructType* struct_type = StructType::DynamicCast(type)) {
    2592           4 :     for (auto& field : struct_type->fields()) {
    2593             :       LowerLabelParameter(
    2594           3 :           field.name_and_type.type,
    2595          15 :           "&((*" + parameter_name + ")." + field.name_and_type.name + ")",
    2596           3 :           lowered_parameters);
    2597             :     }
    2598             :   } else {
    2599          28 :     lowered_parameters->push_back(parameter_name);
    2600             :   }
    2601          29 : }
    2602             : 
    2603           0 : std::string ImplementationVisitor::ExternalLabelName(
    2604             :     const std::string& label_name) {
    2605         408 :   return "label_" + label_name;
    2606             : }
    2607             : 
    2608          78 : std::string ImplementationVisitor::ExternalLabelParameterName(
    2609             :     const std::string& label_name, size_t i) {
    2610         312 :   return "label_" + label_name + "_parameter_" + std::to_string(i);
    2611             : }
    2612             : 
    2613        6033 : std::string ImplementationVisitor::ExternalParameterName(
    2614             :     const std::string& name) {
    2615       12066 :   return std::string("p_") + name;
    2616             : }
    2617             : 
    2618           0 : DEFINE_CONTEXTUAL_VARIABLE(ImplementationVisitor::ValueBindingsManager)
    2619           0 : DEFINE_CONTEXTUAL_VARIABLE(ImplementationVisitor::LabelBindingsManager)
    2620           0 : DEFINE_CONTEXTUAL_VARIABLE(ImplementationVisitor::CurrentCallable)
    2621           0 : DEFINE_CONTEXTUAL_VARIABLE(ImplementationVisitor::CurrentReturnValue)
    2622             : 
    2623       21473 : bool IsCompatibleSignature(const Signature& sig, const TypeVector& types,
    2624             :                            size_t label_count) {
    2625       21473 :   auto i = sig.parameter_types.types.begin() + sig.implicit_count;
    2626       42946 :   if ((sig.parameter_types.types.size() - sig.implicit_count) > types.size())
    2627             :     return false;
    2628       21089 :   if (sig.labels.size() != label_count) return false;
    2629       32972 :   for (auto current : types) {
    2630       26474 :     if (i == sig.parameter_types.types.end()) {
    2631         196 :       if (!sig.parameter_types.var_args) return false;
    2632           0 :       if (!IsAssignableFrom(TypeOracle::GetObjectType(), current)) return false;
    2633             :     } else {
    2634       26278 :       if (!IsAssignableFrom(*i++, current)) return false;
    2635             :     }
    2636             :   }
    2637             :   return true;
    2638             : }
    2639             : 
    2640        5206 : base::Optional<Block*> ImplementationVisitor::GetCatchBlock() {
    2641        5206 :   base::Optional<Block*> catch_block;
    2642        5206 :   if (base::Optional<Binding<LocalLabel>*> catch_handler =
    2643       10412 :           TryLookupLabel("_catch")) {
    2644          26 :     catch_block = assembler().NewBlock(base::nullopt, true);
    2645             :   }
    2646        5206 :   return catch_block;
    2647             : }
    2648             : 
    2649        5206 : void ImplementationVisitor::GenerateCatchBlock(
    2650             :     base::Optional<Block*> catch_block) {
    2651        5206 :   if (catch_block) {
    2652             :     base::Optional<Binding<LocalLabel>*> catch_handler =
    2653          26 :         TryLookupLabel("_catch");
    2654          13 :     if (assembler().CurrentBlockIsComplete()) {
    2655           4 :       assembler().Bind(*catch_block);
    2656           4 :       assembler().Goto((*catch_handler)->block, 1);
    2657             :     } else {
    2658          18 :       CfgAssemblerScopedTemporaryBlock temp(&assembler(), *catch_block);
    2659           9 :       assembler().Goto((*catch_handler)->block, 1);
    2660             :     }
    2661             :   }
    2662        5206 : }
    2663             : 
    2664           3 : void ImplementationVisitor::VisitAllDeclarables() {
    2665             :   CurrentCallable::Scope current_callable(nullptr);
    2666             :   const std::vector<std::unique_ptr<Declarable>>& all_declarables =
    2667             :       GlobalContext::AllDeclarables();
    2668             :   // This has to be an index-based loop because all_declarables can be extended
    2669             :   // during the loop.
    2670       15179 :   for (size_t i = 0; i < all_declarables.size(); ++i) {
    2671        7588 :     Visit(all_declarables[i].get());
    2672             :   }
    2673           3 : }
    2674             : 
    2675        7588 : void ImplementationVisitor::Visit(Declarable* declarable) {
    2676        7588 :   CurrentScope::Scope current_scope(declarable->ParentScope());
    2677        7588 :   CurrentSourcePosition::Scope current_source_position(declarable->pos());
    2678        7588 :   switch (declarable->kind()) {
    2679             :     case Declarable::kMacro:
    2680             :       return Visit(Macro::cast(declarable));
    2681             :     case Declarable::kMethod:
    2682             :       return Visit(Method::cast(declarable));
    2683             :     case Declarable::kBuiltin:
    2684         203 :       return Visit(Builtin::cast(declarable));
    2685             :     case Declarable::kTypeAlias:
    2686        5526 :       return Visit(TypeAlias::cast(declarable));
    2687             :     case Declarable::kNamespaceConstant:
    2688          33 :       return Visit(NamespaceConstant::cast(declarable));
    2689             :     case Declarable::kRuntimeFunction:
    2690             :     case Declarable::kIntrinsic:
    2691             :     case Declarable::kExternConstant:
    2692             :     case Declarable::kNamespace:
    2693             :     case Declarable::kGeneric:
    2694             :       return;
    2695             :   }
    2696             : }
    2697             : 
    2698           1 : void ImplementationVisitor::GenerateBuiltinDefinitions(std::string& file_name) {
    2699           2 :   std::stringstream new_contents_stream;
    2700             :   new_contents_stream
    2701             :       << "#ifndef V8_BUILTINS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n"
    2702             :          "#define V8_BUILTINS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n"
    2703             :          "\n"
    2704             :          "#define BUILTIN_LIST_FROM_DSL(CPP, API, TFJ, TFC, TFS, TFH, ASM) "
    2705           1 :          "\\\n";
    2706        7578 :   for (auto& declarable : GlobalContext::AllDeclarables()) {
    2707             :     Builtin* builtin = Builtin::DynamicCast(declarable.get());
    2708        7780 :     if (!builtin || builtin->IsExternal()) continue;
    2709             :     int firstParameterIndex = 1;
    2710             :     bool declareParameters = true;
    2711         184 :     if (builtin->IsStub()) {
    2712             :       new_contents_stream << "TFS(" << builtin->ExternalName();
    2713             :     } else {
    2714             :       new_contents_stream << "TFJ(" << builtin->ExternalName();
    2715         103 :       if (builtin->IsVarArgsJavaScript()) {
    2716             :         new_contents_stream
    2717          77 :             << ", SharedFunctionInfo::kDontAdaptArgumentsSentinel";
    2718             :         declareParameters = false;
    2719             :       } else {
    2720             :         assert(builtin->IsFixedArgsJavaScript());
    2721             :         // FixedArg javascript builtins need to offer the parameter
    2722             :         // count.
    2723             :         assert(builtin->parameter_names().size() >= 2);
    2724          26 :         new_contents_stream << ", " << (builtin->parameter_names().size() - 2);
    2725             :         // And the receiver is explicitly declared.
    2726          26 :         new_contents_stream << ", kReceiver";
    2727             :         firstParameterIndex = 2;
    2728             :       }
    2729             :     }
    2730         184 :     if (declareParameters) {
    2731             :       int index = 0;
    2732         597 :       for (const auto& parameter : builtin->parameter_names()) {
    2733         490 :         if (index >= firstParameterIndex) {
    2734         714 :           new_contents_stream << ", k" << CamelifyString(parameter->value);
    2735             :         }
    2736         490 :         index++;
    2737             :       }
    2738             :     }
    2739         184 :     new_contents_stream << ") \\\n";
    2740             :   }
    2741           1 :   new_contents_stream << "\n";
    2742             : 
    2743             :   new_contents_stream
    2744           1 :       << "#define TORQUE_FUNCTION_POINTER_TYPE_TO_BUILTIN_MAP(V) \\\n";
    2745          11 :   for (const BuiltinPointerType* type : TypeOracle::AllBuiltinPointerTypes()) {
    2746             :     Builtin* example_builtin =
    2747          10 :         Declarations::FindSomeInternalBuiltinWithType(type);
    2748          10 :     if (!example_builtin) {
    2749             :       CurrentSourcePosition::Scope current_source_position(
    2750           0 :           SourcePosition{CurrentSourceFile::Get(), {-1, -1}, {-1, -1}});
    2751           0 :       ReportError("unable to find any builtin with type \"", *type, "\"");
    2752             :     }
    2753             :     new_contents_stream << "  V(" << type->function_pointer_type_id() << ","
    2754          10 :                         << example_builtin->ExternalName() << ")\\\n";
    2755             :   }
    2756           1 :   new_contents_stream << "\n";
    2757             : 
    2758             :   new_contents_stream
    2759           1 :       << "#endif  // V8_BUILTINS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n";
    2760             : 
    2761             :   std::string new_contents(new_contents_stream.str());
    2762           1 :   ReplaceFileContentsIfDifferent(file_name, new_contents);
    2763           1 : }
    2764             : 
    2765             : namespace {
    2766             : 
    2767             : enum class FieldSectionType {
    2768             :   kNoSection = 0,
    2769             :   kWeakSection,
    2770             :   kStrongSection,
    2771             :   kScalarSection
    2772             : };
    2773             : 
    2774         236 : void PossiblyStartTagged(FieldSectionType* section,
    2775             :                          std::set<FieldSectionType>* completed_sections,
    2776             :                          std::stringstream* o) {
    2777         437 :   if (completed_sections->count(FieldSectionType::kWeakSection) == 0 &&
    2778         118 :       completed_sections->count(FieldSectionType::kStrongSection) == 0 &&
    2779         472 :       *section != FieldSectionType::kWeakSection &&
    2780             :       *section != FieldSectionType::kStrongSection) {
    2781         118 :     *o << "V(kStartOfPointerFieldsOffset, 0) \\\n";
    2782             :   }
    2783         236 : }
    2784             : 
    2785         236 : void PossiblyEndTagged(FieldSectionType* section,
    2786             :                        std::set<FieldSectionType>* completed_sections,
    2787             :                        std::stringstream* o) {
    2788         389 :   if (completed_sections->count(FieldSectionType::kWeakSection) != 0 &&
    2789             :       completed_sections->count(FieldSectionType::kStrongSection) != 0) {
    2790         118 :     *o << "V(kEndOfTaggedFieldsOffset, 0) \\\n";
    2791             :   }
    2792         236 : }
    2793             : 
    2794         717 : void ProcessFieldInSection(FieldSectionType* section,
    2795             :                            std::set<FieldSectionType>* completed_sections,
    2796             :                            FieldSectionType field_section,
    2797             :                            std::stringstream* o) {
    2798         717 :   if (*section != FieldSectionType::kNoSection) {
    2799         450 :     if (*section != field_section) {
    2800         251 :       if (completed_sections->count(field_section) != 0) {
    2801           0 :         ReportError("reopening of weak, strong or scalar field section");
    2802             :       }
    2803             :       completed_sections->insert(*section);
    2804         251 :       if (*section == FieldSectionType::kWeakSection) {
    2805         118 :         *o << "V(kEndOfWeakFieldsOffset, 0) \\\n";
    2806         118 :         PossiblyEndTagged(section, completed_sections, o);
    2807         133 :       } else if (*section == FieldSectionType::kStrongSection) {
    2808         118 :         *o << "V(kEndOfStrongFieldsOffset, 0) \\\n";
    2809         118 :         PossiblyEndTagged(section, completed_sections, o);
    2810             :       }
    2811             :     }
    2812             :   }
    2813         717 :   if (*section != field_section) {
    2814         494 :     if (field_section == FieldSectionType::kWeakSection) {
    2815         118 :       PossiblyStartTagged(section, completed_sections, o);
    2816         118 :       *o << "V(kStartOfWeakFieldsOffset, 0) \\\n";
    2817         376 :     } else if (field_section == FieldSectionType::kStrongSection) {
    2818         118 :       PossiblyStartTagged(section, completed_sections, o);
    2819         118 :       *o << "V(kStartOfStrongFieldsOffset, 0) \\\n";
    2820             :     }
    2821             :   }
    2822         717 :   *section = field_section;
    2823         717 : }
    2824             : 
    2825         236 : void CompleteFieldSection(FieldSectionType* section,
    2826             :                           std::set<FieldSectionType>* completed_sections,
    2827             :                           FieldSectionType field_section,
    2828             :                           std::stringstream* o) {
    2829         236 :   if (completed_sections->count(field_section) == 0) {
    2830         149 :     ProcessFieldInSection(section, completed_sections, field_section, o);
    2831             :     ProcessFieldInSection(section, completed_sections,
    2832         149 :                           FieldSectionType::kNoSection, o);
    2833             :   }
    2834         236 : }
    2835             : 
    2836             : }  // namespace
    2837             : 
    2838           1 : void ImplementationVisitor::GenerateClassDefinitions(std::string& file_name) {
    2839           2 :   std::stringstream new_contents_stream;
    2840             :   new_contents_stream << "#ifndef V8_CLASS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n"
    2841             :                          "#define V8_CLASS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n"
    2842           1 :                          "\n\n";
    2843             : 
    2844         122 :   for (auto i : GlobalContext::GetClasses()) {
    2845             :     ClassType* type = i.second;
    2846         121 :     if (!type->IsExtern()) continue;
    2847             : 
    2848             :     // TODO(danno): Ideally (and we've got several core V8 dev's feedback
    2849             :     // supporting this), Torque should generate the constants for the offsets
    2850             :     // directly and not go through the existing layer of macros, which actually
    2851             :     // currently just serves to additionally obfuscate where these values come
    2852             :     // from.
    2853         118 :     new_contents_stream << "#define ";
    2854             :     new_contents_stream << "TORQUE_GENERATED_"
    2855         236 :                         << CapifyStringWithUnderscores(i.first)
    2856         118 :                         << "_FIELDS(V) \\\n";
    2857         236 :     std::vector<Field> fields = type->fields();
    2858         118 :     FieldSectionType section = FieldSectionType::kNoSection;
    2859             :     std::set<FieldSectionType> completed_sections;
    2860         419 :     for (auto f : fields) {
    2861         301 :       CurrentSourcePosition::Scope scope(f.pos);
    2862         301 :       if (f.name_and_type.type->IsSubtypeOf(TypeOracle::GetTaggedType())) {
    2863         268 :         if (f.is_weak) {
    2864             :           ProcessFieldInSection(&section, &completed_sections,
    2865             :                                 FieldSectionType::kWeakSection,
    2866           6 :                                 &new_contents_stream);
    2867             :         } else {
    2868             :           ProcessFieldInSection(&section, &completed_sections,
    2869             :                                 FieldSectionType::kStrongSection,
    2870         262 :                                 &new_contents_stream);
    2871             :         }
    2872             :       } else {
    2873             :         ProcessFieldInSection(&section, &completed_sections,
    2874             :                               FieldSectionType::kScalarSection,
    2875          33 :                               &new_contents_stream);
    2876             :       }
    2877             :       size_t field_size;
    2878             :       std::string size_string;
    2879             :       std::string machine_type;
    2880         301 :       std::tie(field_size, size_string, machine_type) =
    2881         602 :           f.GetFieldSizeInformation();
    2882         602 :       new_contents_stream << "V(k" << CamelifyString(f.name_and_type.name)
    2883         301 :                           << "Offset, " << size_string << ") \\\n";
    2884             :     }
    2885             : 
    2886             :     ProcessFieldInSection(&section, &completed_sections,
    2887         118 :                           FieldSectionType::kNoSection, &new_contents_stream);
    2888             :     CompleteFieldSection(&section, &completed_sections,
    2889         118 :                          FieldSectionType::kWeakSection, &new_contents_stream);
    2890             :     CompleteFieldSection(&section, &completed_sections,
    2891             :                          FieldSectionType::kStrongSection,
    2892         118 :                          &new_contents_stream);
    2893             : 
    2894         118 :     new_contents_stream << "V(kSize, 0) \\\n";
    2895         118 :     new_contents_stream << "\n";
    2896             :   }
    2897             : 
    2898             :   new_contents_stream
    2899           1 :       << "\n#endif  // V8_CLASS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n";
    2900             : 
    2901             :   std::string new_contents(new_contents_stream.str());
    2902           1 :   ReplaceFileContentsIfDifferent(file_name, new_contents);
    2903           1 : }
    2904             : 
    2905           1 : void ImplementationVisitor::GeneratePrintDefinitions(std::string& file_name) {
    2906           2 :   std::stringstream new_contents_stream;
    2907             : 
    2908           1 :   new_contents_stream << "#ifdef OBJECT_PRINT\n\n";
    2909             : 
    2910           1 :   new_contents_stream << "#include \"src/objects.h\"\n\n";
    2911           1 :   new_contents_stream << "#include <iosfwd>\n\n";
    2912           1 :   new_contents_stream << "#include \"src/objects/struct-inl.h\"\n\n";
    2913             : 
    2914           1 :   new_contents_stream << "namespace v8 {\n";
    2915           1 :   new_contents_stream << "namespace internal {\n\n";
    2916             : 
    2917         122 :   for (auto i : GlobalContext::GetClasses()) {
    2918             :     ClassType* type = i.second;
    2919         121 :     if (!type->ShouldGeneratePrint()) continue;
    2920             : 
    2921             :     new_contents_stream << "void " << type->name() << "::" << type->name()
    2922           3 :                         << "Print(std::ostream& os) {\n";
    2923           3 :     new_contents_stream << "  PrintHeader(os, \"" << type->name() << "\");\n";
    2924           3 :     auto hierarchy = type->GetHierarchy();
    2925             :     std::map<std::string, const AggregateType*> field_names;
    2926          13 :     for (const AggregateType* aggregate_type : hierarchy) {
    2927          20 :       for (const Field& f : aggregate_type->fields()) {
    2928          20 :         if (f.name_and_type.name == "map") continue;
    2929             :         new_contents_stream << "  os << \"\\n - " << f.name_and_type.name
    2930             :                             << ": \" << "
    2931           7 :                             << "Brief(" << f.name_and_type.name << "());\n";
    2932             :       }
    2933             :     }
    2934           3 :     new_contents_stream << "  os << \"\\n\";\n";
    2935           3 :     new_contents_stream << "}\n\n";
    2936             :   }
    2937             : 
    2938           1 :   new_contents_stream << "}  // namespace internal\"\n";
    2939           1 :   new_contents_stream << "}  // namespace v8\"\n";
    2940             : 
    2941           1 :   new_contents_stream << "\n#endif  // OBJECT_PRINT\n\n";
    2942             : 
    2943             :   std::string new_contents(new_contents_stream.str());
    2944           1 :   ReplaceFileContentsIfDifferent(file_name, new_contents);
    2945           1 : }
    2946             : 
    2947             : }  // namespace torque
    2948             : }  // namespace internal
    2949       59456 : }  // namespace v8

Generated by: LCOV version 1.10