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

Generated by: LCOV version 1.10