LCOV - code coverage report
Current view: top level - src/torque - implementation-visitor.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 1228 1418 86.6 %
Date: 2019-02-19 Functions: 86 103 83.5 %

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

Generated by: LCOV version 1.10