implementation-visitor.cc 94.9 KB
Newer Older
1 2 3 4
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6
#include <algorithm>

7
#include "src/torque/csa-generator.h"
8
#include "src/torque/declaration-visitor.h"
9
#include "src/torque/implementation-visitor.h"
10
#include "src/torque/parameter-difference.h"
11 12 13 14 15 16

namespace v8 {
namespace internal {
namespace torque {

VisitResult ImplementationVisitor::Visit(Expression* expr) {
17
  CurrentSourcePosition::Scope scope(expr->pos);
18 19 20 21 22 23 24
  switch (expr->kind) {
#define ENUM_ITEM(name)        \
  case AstNode::Kind::k##name: \
    return Visit(name::cast(expr));
    AST_EXPRESSION_NODE_KIND_LIST(ENUM_ITEM)
#undef ENUM_ITEM
    default:
25
      UNREACHABLE();
26 27 28
  }
}

29
const Type* ImplementationVisitor::Visit(Statement* stmt) {
30
  CurrentSourcePosition::Scope scope(stmt->pos);
31
  StackScope stack_scope(this);
32
  const Type* result;
33
  switch (stmt->kind) {
34 35 36 37
#define ENUM_ITEM(name)               \
  case AstNode::Kind::k##name:        \
    result = Visit(name::cast(stmt)); \
    break;
38 39 40
    AST_STATEMENT_NODE_KIND_LIST(ENUM_ITEM)
#undef ENUM_ITEM
    default:
41
      UNREACHABLE();
42
  }
43 44 45
  DCHECK_EQ(result == TypeOracle::GetNeverType(),
            assembler().CurrentBlockIsComplete());
  return result;
46 47
}

48 49 50
void ImplementationVisitor::BeginNamespaceFile(Namespace* nspace) {
  std::ostream& source = nspace->source_stream();
  std::ostream& header = nspace->header_stream();
51

52 53 54
  for (const std::string& include_path : GlobalContext::CppIncludes()) {
    source << "#include " << StringLiteralQuote(include_path) << "\n";
  }
55

56
  for (Namespace* n : GlobalContext::Get().GetNamespaces()) {
57
    source << "#include \"torque-generated/builtins-" +
58
                  DashifyString(n->name()) + "-from-dsl-gen.h\"\n";
59 60
  }
  source << "\n";
61

62 63 64
  source << "namespace v8 {\n"
         << "namespace internal {\n"
         << "\n";
65

66
  std::string upper_name(nspace->name());
67 68 69 70
  transform(upper_name.begin(), upper_name.end(), upper_name.begin(),
            ::toupper);
  std::string headerDefine =
      std::string("V8_TORQUE_") + upper_name + "_FROM_DSL_BASE_H__";
71 72
  header << "#ifndef " << headerDefine << "\n";
  header << "#define " << headerDefine << "\n\n";
73 74 75 76 77
  header << "#include \"src/compiler/code-assembler.h\"\n";
  if (nspace != GlobalContext::GetDefaultNamespace()) {
    header << "#include \"src/code-stub-assembler.h\"\n";
  }
  header << "\n";
78

79 80 81
  header << "namespace v8 {\n"
         << "namespace internal {\n"
         << "\n";
82

83
  header << "class " << nspace->ExternalName() << " {\n";
84
  header << " public:\n";
85
  header << "  explicit " << nspace->ExternalName()
86 87
         << "(compiler::CodeAssemblerState* state) : state_(state), ca_(state) "
            "{ USE(state_, ca_); }\n";
88
}
89

90 91 92
void ImplementationVisitor::EndNamespaceFile(Namespace* nspace) {
  std::ostream& source = nspace->source_stream();
  std::ostream& header = nspace->header_stream();
93

94
  std::string upper_name(nspace->name());
95 96 97 98 99
  transform(upper_name.begin(), upper_name.end(), upper_name.begin(),
            ::toupper);
  std::string headerDefine =
      std::string("V8_TORQUE_") + upper_name + "_FROM_DSL_BASE_H__";

100 101 102
  source << "}  // namespace internal\n"
         << "}  // namespace v8\n"
         << "\n";
103

104 105 106 107
  header << " private:\n"
         << "  compiler::CodeAssemblerState* const state_;\n"
         << "  compiler::CodeAssembler ca_;"
         << "}; \n\n";
108 109 110 111
  header << "}  // namespace internal\n"
         << "}  // namespace v8\n"
         << "\n";
  header << "#endif  // " << headerDefine << "\n";
112 113
}

114
void ImplementationVisitor::Visit(NamespaceConstant* decl) {
115 116
  Signature signature{{}, base::nullopt, {{}, false}, 0, decl->type(), {}};
  const std::string& name = decl->name();
117

118 119
  BindingsManagersScope bindings_managers_scope;

120 121 122 123 124
  header_out() << "  ";
  GenerateFunctionDeclaration(header_out(), "", name, signature, {});
  header_out() << ";\n";

  GenerateFunctionDeclaration(source_out(),
125
                              CurrentNamespace()->ExternalName() + "::", name,
126 127 128 129 130
                              signature, {});
  source_out() << " {\n";

  DCHECK(!signature.return_type->IsVoidOrNever());

131 132
  assembler_ = CfgAssembler(Stack<const Type*>{});

133
  VisitResult expression_result = Visit(decl->body());
134 135 136
  VisitResult return_result =
      GenerateImplicitConvert(signature.return_type, expression_result);

137 138 139 140 141 142 143 144
  CSAGenerator csa_generator{assembler().Result(), source_out()};
  Stack<std::string> values = *csa_generator.EmitGraph(Stack<std::string>{});

  assembler_ = base::nullopt;

  source_out() << "return ";
  CSAGenerator::EmitCSAValue(return_result, values, source_out());
  source_out() << ";\n";
145 146 147
  source_out() << "}\n\n";
}

148 149 150 151 152 153
void ImplementationVisitor::Visit(TypeAlias* alias) {
  if (alias->IsRedeclaration()) return;
  const StructType* struct_type = StructType::DynamicCast(alias->type());
  if (!struct_type) return;
  const std::string& name = struct_type->name();
  header_out() << "  struct " << name << " {\n";
154
  for (auto& field : struct_type->fields()) {
155 156
    header_out() << "    " << field.name_and_type.type->GetGeneratedTypeName();
    header_out() << " " << field.name_and_type.name << ";\n";
157
  }
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
  header_out() << "\n    std::tuple<";
  bool first = true;
  for (const Type* type : LowerType(struct_type)) {
    if (!first) {
      header_out() << ", ";
    }
    first = false;
    header_out() << type->GetGeneratedTypeName();
  }
  header_out() << "> Flatten() const {\n"
               << "      return std::tuple_cat(";
  first = true;
  for (auto& field : struct_type->fields()) {
    if (!first) {
      header_out() << ", ";
    }
    first = false;
175 176
    if (field.name_and_type.type->IsStructType()) {
      header_out() << field.name_and_type.name << ".Flatten()";
177
    } else {
178
      header_out() << "std::make_tuple(" << field.name_and_type.name << ")";
179 180 181 182 183
    }
  }
  header_out() << ");\n";
  header_out() << "    }\n";
  header_out() << "  };\n";
184 185
}

186
VisitResult ImplementationVisitor::InlineMacro(
187 188
    Macro* macro, base::Optional<LocationReference> this_reference,
    const std::vector<VisitResult>& arguments,
189 190 191 192 193 194 195 196 197
    const std::vector<Block*> label_blocks) {
  CurrentScope::Scope current_scope(macro);
  BindingsManagersScope bindings_managers_scope;
  CurrentCallable::Scope current_callable(macro);
  CurrentReturnValue::Scope current_return_value;
  const Signature& signature = macro->signature();
  const Type* return_type = macro->signature().return_type;
  bool can_return = return_type != TypeOracle::GetNeverType();

198 199 200 201
  CurrentConstructorInfo::Scope current_constructor;
  if (macro->IsConstructor())
    CurrentConstructorInfo::Get() = ConstructorInfo{0};

202
  BlockBindings<LocalValue> parameter_bindings(&ValueBindingsManager::Get());
203 204 205 206 207
  BlockBindings<LocalLabel> label_bindings(&LabelBindingsManager::Get());
  DCHECK_EQ(macro->signature().parameter_names.size(),
            arguments.size() + (this_reference ? 1 : 0));
  DCHECK_EQ(this_reference.has_value(), macro->IsMethod());

208 209 210 211 212 213 214 215 216 217 218 219 220
  // Bind the this for methods. Methods that modify a struct-type "this" must
  // only be called if the this is in a variable, in which case the
  // LocalValue is non-const. Otherwise, the LocalValue used for the parameter
  // binding is const, and thus read-only, which will cause errors if
  // modified, e.g. when called by a struct method that sets the structs
  // fields. This prevents using temporary struct values for anything other
  // than read operations.
  if (this_reference) {
    DCHECK(macro->IsMethod());
    LocalValue this_value = LocalValue{!this_reference->IsVariableAccess(),
                                       this_reference->GetVisitResult()};
    parameter_bindings.Add(kThisParameterName, this_value);
  }
221

222 223 224 225 226
  size_t i = 0;
  for (auto arg : arguments) {
    if (this_reference && i == signature.implicit_count) i++;
    const std::string& name = macro->parameter_names()[i++];
    parameter_bindings.Add(name, LocalValue{true, arg});
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
  }

  DCHECK_EQ(label_blocks.size(), signature.labels.size());
  for (size_t i = 0; i < signature.labels.size(); ++i) {
    const LabelDeclaration& label_info = signature.labels[i];
    label_bindings.Add(label_info.name,
                       LocalLabel{label_blocks[i], label_info.types});
  }

  Block* macro_end;
  base::Optional<Binding<LocalLabel>> macro_end_binding;
  if (can_return) {
    Stack<const Type*> stack = assembler().CurrentStack();
    std::vector<const Type*> lowered_return_types = LowerType(return_type);
    stack.PushMany(lowered_return_types);
    if (!return_type->IsConstexpr()) {
      SetReturnValue(VisitResult(return_type,
                                 stack.TopRange(lowered_return_types.size())));
    }
246 247 248 249 250 251 252 253 254 255
    // The stack copy used to initialize the _macro_end block is only used
    // as a template for the actual gotos generated by return statements. It
    // doesn't correspond to any real return values, and thus shouldn't contain
    // top types, because these would pollute actual return value types that get
    // unioned with them for return statements, erroneously forcing them to top.
    for (auto i = stack.begin(); i != stack.end(); ++i) {
      if ((*i)->IsTopType()) {
        *i = TopType::cast(*i)->source_type();
      }
    }
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
    macro_end = assembler().NewBlock(std::move(stack));
    macro_end_binding.emplace(&LabelBindingsManager::Get(), "_macro_end",
                              LocalLabel{macro_end, {return_type}});
  } else {
    SetReturnValue(VisitResult::NeverResult());
  }

  const Type* result = Visit(*macro->body());

  if (result->IsNever()) {
    if (!return_type->IsNever() && !macro->HasReturns()) {
      std::stringstream s;
      s << "macro " << macro->ReadableName()
        << " that never returns must have return type never";
      ReportError(s.str());
    }
  } else {
    if (return_type->IsNever()) {
      std::stringstream s;
      s << "macro " << macro->ReadableName()
        << " has implicit return at end of its declartion but return type "
           "never";
      ReportError(s.str());
    } else if (!macro->signature().return_type->IsVoid()) {
      std::stringstream s;
      s << "macro " << macro->ReadableName()
        << " expects to return a value but doesn't on all paths";
      ReportError(s.str());
    }
  }
  if (!result->IsNever()) {
    assembler().Goto(macro_end);
  }

  if (macro->HasReturns() || !result->IsNever()) {
    assembler().Bind(macro_end);
  }

  return GetAndClearReturnValue();
}

297
void ImplementationVisitor::VisitMacroCommon(Macro* macro) {
298 299 300 301 302
  // Do not generate code for inlined macros.
  if (macro->ShouldBeInlined()) {
    return;
  }

303
  CurrentCallable::Scope current_callable(macro);
304 305
  const Signature& signature = macro->signature();
  const Type* return_type = macro->signature().return_type;
306 307 308
  bool can_return = return_type != TypeOracle::GetNeverType();
  bool has_return_value =
      can_return && return_type != TypeOracle::GetVoidType();
309

310 311 312 313
  // Struct methods should never generate code, they should always be inlined
  DCHECK(!macro->IsMethod() ||
         Method::cast(macro)->aggregate_type()->IsClassType());

314 315 316
  header_out() << "  ";
  GenerateMacroFunctionDeclaration(header_out(), "", macro);
  header_out() << ";\n";
317

318
  GenerateMacroFunctionDeclaration(
319
      source_out(), CurrentNamespace()->ExternalName() + "::", macro);
320
  source_out() << " {\n";
321

322 323
  Stack<std::string> lowered_parameters;
  Stack<const Type*> lowered_parameter_types;
324

325
  std::vector<VisitResult> arguments;
326

327 328 329 330 331 332 333 334 335 336 337 338 339
  base::Optional<LocationReference> this_reference;
  if (Method* method = Method::DynamicCast(macro)) {
    const Type* this_type = method->aggregate_type();
    DCHECK(this_type->IsClassType());
    lowered_parameter_types.Push(this_type);
    lowered_parameters.Push(ExternalParameterName(kThisParameterName));
    VisitResult this_result =
        VisitResult(this_type, lowered_parameters.TopRange(1));
    // Mark the this as a temporary to prevent assignment to it.
    this_reference =
        LocationReference::Temporary(this_result, "this parameter");
  }

340 341
  for (size_t i = 0; i < macro->signature().parameter_names.size(); ++i) {
    if (this_reference && i == macro->signature().implicit_count) continue;
342
    const std::string& name = macro->parameter_names()[i];
343
    std::string external_name = ExternalParameterName(name);
344
    const Type* type = macro->signature().types()[i];
345

346
    if (type->IsConstexpr()) {
347
      arguments.push_back(VisitResult(type, external_name));
348 349 350
    } else {
      LowerParameter(type, external_name, &lowered_parameters);
      StackRange range = lowered_parameter_types.PushMany(LowerType(type));
351
      arguments.push_back(VisitResult(type, range));
352
    }
353
  }
354

355 356
  DCHECK_EQ(lowered_parameters.Size(), lowered_parameter_types.Size());
  assembler_ = CfgAssembler(lowered_parameter_types);
357

358
  std::vector<Block*> label_blocks;
359 360 361 362
  for (const LabelDeclaration& label_info : signature.labels) {
    Stack<const Type*> label_input_stack;
    for (const Type* type : label_info.types) {
      label_input_stack.PushMany(LowerType(type));
363
    }
364
    Block* block = assembler().NewBlock(std::move(label_input_stack));
365
    label_blocks.push_back(block);
366
  }
367

368 369
  VisitResult return_value =
      InlineMacro(macro, this_reference, arguments, label_blocks);
370 371 372
  Block* end = assembler().NewBlock();
  if (return_type != TypeOracle::GetNeverType()) {
    assembler().Goto(end);
373
  }
374

375 376 377 378
  for (size_t i = 0; i < label_blocks.size(); ++i) {
    Block* label_block = label_blocks[i];
    const LabelDeclaration& label_info = signature.labels[i];
    assembler().Bind(label_block);
379
    std::vector<std::string> label_parameter_variables;
380
    for (size_t i = 0; i < label_info.types.size(); ++i) {
381
      label_parameter_variables.push_back(
382
          ExternalLabelParameterName(label_info.name, i));
383
    }
384 385
    assembler().Emit(GotoExternalInstruction{ExternalLabelName(label_info.name),
                                             label_parameter_variables});
386
  }
387

388 389
  if (return_type != TypeOracle::GetNeverType()) {
    assembler().Bind(end);
390
  }
391

392 393 394
  CSAGenerator csa_generator{assembler().Result(), source_out()};
  base::Optional<Stack<std::string>> values =
      csa_generator.EmitGraph(lowered_parameters);
395

396
  assembler_ = base::nullopt;
397

398 399
  if (has_return_value) {
    source_out() << "  return ";
400
    CSAGenerator::EmitCSAValue(return_value, *values, source_out());
401
    source_out() << ";\n";
402
  }
403
  source_out() << "}\n\n";
404 405
}

406 407 408 409 410 411 412 413 414 415
void ImplementationVisitor::Visit(Macro* macro) {
  if (macro->IsExternal()) return;
  VisitMacroCommon(macro);
}

void ImplementationVisitor::Visit(Method* method) {
  DCHECK(!method->IsExternal());
  VisitMacroCommon(method);
}

416
namespace {
417

418
std::string AddParameter(size_t i, Builtin* builtin,
419
                         Stack<std::string>* parameters,
420 421
                         Stack<const Type*>* parameter_types,
                         BlockBindings<LocalValue>* parameter_bindings) {
422 423
  const std::string& name = builtin->signature().parameter_names[i];
  const Type* type = builtin->signature().types()[i];
424 425 426 427 428
  std::string external_name = "parameter" + std::to_string(i);
  parameters->Push(external_name);
  StackRange range = parameter_types->PushMany(LowerType(type));
  parameter_bindings->Add(name, LocalValue{true, VisitResult(type, range)});
  return external_name;
429
}
430

431 432
}  // namespace

433 434 435
void ImplementationVisitor::Visit(Builtin* builtin) {
  if (builtin->IsExternal()) return;
  CurrentScope::Scope current_scope(builtin);
436
  const std::string& name = builtin->ExternalName();
437
  const Signature& signature = builtin->signature();
438 439 440 441
  source_out() << "TF_BUILTIN(" << name << ", CodeStubAssembler) {\n"
               << "  compiler::CodeAssemblerState* state_ = state();"
               << "  compiler::CodeAssembler ca_(state());\n";

442
  CurrentCallable::Scope current_callable(builtin);
443
  CurrentReturnValue::Scope current_return_value;
444

445 446 447
  Stack<const Type*> parameter_types;
  Stack<std::string> parameters;

448 449 450 451
  BindingsManagersScope bindings_managers_scope;

  BlockBindings<LocalValue> parameter_bindings(&ValueBindingsManager::Get());

452
  // Context
453
  std::string parameter0 = AddParameter(0, builtin, &parameters,
454
                                        &parameter_types, &parameter_bindings);
455
  source_out() << "  TNode<Context> " << parameter0
456
               << " = UncheckedCast<Context>(Parameter("
457
               << "Descriptor::kContext));\n";
458
  source_out() << "  USE(" << parameter0 << ");\n";
459 460

  size_t first = 1;
461
  if (builtin->IsVarArgsJavaScript()) {
462
    DCHECK(signature.parameter_types.var_args);
463
    source_out()
464 465
        << "  Node* argc = Parameter(Descriptor::kJSActualArgumentsCount);\n";
    source_out() << "  CodeStubArguments arguments_impl(this, "
466
                    "ChangeInt32ToIntPtr(argc));\n";
467
    std::string parameter1 = AddParameter(
468
        1, builtin, &parameters, &parameter_types, &parameter_bindings);
469 470

    source_out() << "  TNode<Object> " << parameter1
471
                 << " = arguments_impl.GetReceiver();\n";
472 473
    source_out() << "auto " << CSAGenerator::ARGUMENTS_VARIABLE_STRING
                 << " = &arguments_impl;\n";
474
    source_out() << "USE(arguments);\n";
475
    source_out() << "USE(" << parameter1 << ");\n";
476
    parameter_bindings.Add(
477
        *signature.arguments_variable,
478 479
        LocalValue{true,
                   VisitResult(TypeOracle::GetArgumentsType(), "arguments")});
480
    first = 2;
481 482
  }

483
  for (size_t i = 0; i < signature.parameter_names.size(); ++i) {
484
    if (i < first) continue;
485
    const std::string& parameter_name = signature.parameter_names[i];
486
    const Type* type = signature.types()[i];
487 488
    std::string var = AddParameter(i, builtin, &parameters, &parameter_types,
                                   &parameter_bindings);
489 490
    source_out() << "  " << type->GetGeneratedTypeName() << " " << var << " = "
                 << "UncheckedCast<" << type->GetGeneratedTNodeTypeName()
491 492 493 494 495 496
                 << ">(Parameter(Descriptor::k"
                 << CamelifyString(parameter_name) << "));\n";
    source_out() << "  USE(" << var << ");\n";
  }

  assembler_ = CfgAssembler(parameter_types);
497
  const Type* body_result = Visit(*builtin->body());
498 499 500 501 502 503 504
  if (body_result != TypeOracle::GetNeverType()) {
    ReportError("control reaches end of builtin, expected return of a value");
  }
  CSAGenerator csa_generator{assembler().Result(), source_out(),
                             builtin->kind()};
  csa_generator.EmitGraph(parameters);
  assembler_ = base::nullopt;
505
  source_out() << "}\n\n";
506 507
}

508
const Type* ImplementationVisitor::Visit(VarDeclarationStatement* stmt) {
509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524
  BlockBindings<LocalValue> block_bindings(&ValueBindingsManager::Get());
  return Visit(stmt, &block_bindings);
}

const Type* ImplementationVisitor::Visit(
    VarDeclarationStatement* stmt, BlockBindings<LocalValue>* block_bindings) {
  if (!stmt->const_qualified && !stmt->type) {
    ReportError(
        "variable declaration is missing type. Only 'const' bindings can "
        "infer the type.");
  }
  // const qualified variables are required to be initialized properly.
  if (stmt->const_qualified && !stmt->initializer) {
    ReportError("local constant \"", stmt->name, "\" is not initialized.");
  }

525
  base::Optional<const Type*> type;
526
  if (stmt->type) {
527
    type = Declarations::GetType(*stmt->type);
528 529 530 531 532
    if ((*type)->IsConstexpr() && !stmt->const_qualified) {
      ReportError(
          "cannot declare variable with constexpr type. Use 'const' instead.");
    }
  }
533 534
  base::Optional<VisitResult> init_result;
  if (stmt->initializer) {
535
    StackScope scope(this);
536
    init_result = Visit(*stmt->initializer);
537 538 539 540 541 542 543 544 545 546 547
    if (type) {
      init_result = GenerateImplicitConvert(*type, *init_result);
    }
    init_result = scope.Yield(*init_result);
  } else {
    DCHECK(type.has_value());
    if ((*type)->IsConstexpr()) {
      ReportError("constexpr variables need an initializer");
    }
    TypeVector lowered_types = LowerType(*type);
    for (const Type* type : lowered_types) {
548 549 550 551 552
      assembler().Emit(PushUninitializedInstruction{TypeOracle::GetTopType(
          "unitialized variable '" + stmt->name + "' of type " +
              type->ToString() + " originally defined at " +
              PositionAsString(stmt->pos),
          type)});
553 554 555
    }
    init_result =
        VisitResult(*type, assembler().TopRange(lowered_types.size()));
556
  }
557 558
  block_bindings->Add(stmt->name,
                      LocalValue{stmt->const_qualified, *init_result});
559
  return TypeOracle::GetVoidType();
560 561
}

562
const Type* ImplementationVisitor::Visit(TailCallStatement* stmt) {
563 564 565 566
  return Visit(stmt->call, true).type();
}

VisitResult ImplementationVisitor::Visit(ConditionalExpression* expr) {
567 568
  Block* true_block = assembler().NewBlock(assembler().CurrentStack());
  Block* false_block = assembler().NewBlock(assembler().CurrentStack());
569 570
  Block* done_block = assembler().NewBlock();
  Block* true_conversion_block = assembler().NewBlock();
571
  GenerateExpressionBranch(expr->condition, true_block, false_block);
572

573 574
  VisitResult left;
  VisitResult right;
575 576

  {
577 578 579 580
    // The code for both paths of the conditional need to be generated first
    // before evaluating the conditional expression because the common type of
    // the result of both the true and false of the condition needs to be known
    // to convert both branches to a common type.
581
    assembler().Bind(true_block);
582 583 584
    StackScope left_scope(this);
    left = Visit(expr->if_true);
    assembler().Goto(true_conversion_block);
585

586 587
    const Type* common_type;
    {
588
      assembler().Bind(false_block);
589 590 591 592 593
      StackScope right_scope(this);
      right = Visit(expr->if_false);
      common_type = GetCommonType(left.type(), right.type());
      right = right_scope.Yield(GenerateImplicitConvert(common_type, right));
      assembler().Goto(done_block);
594 595
    }

596 597 598
    assembler().Bind(true_conversion_block);
    left = left_scope.Yield(GenerateImplicitConvert(common_type, left));
    assembler().Goto(done_block);
599
  }
600 601 602 603

  assembler().Bind(done_block);
  CHECK_EQ(left, right);
  return left;
604 605 606
}

VisitResult ImplementationVisitor::Visit(LogicalOrExpression* expr) {
607
  VisitResult left_result;
608
  {
609 610 611
    Block* false_block = assembler().NewBlock(assembler().CurrentStack());
    Binding<LocalLabel> false_binding{&LabelBindingsManager::Get(),
                                      kFalseLabelName, LocalLabel{false_block}};
612
    left_result = Visit(expr->left);
613
    if (left_result.type()->IsBool()) {
614 615 616
      Block* true_block = LookupSimpleLabel(kTrueLabelName);
      assembler().Branch(true_block, false_block);
      assembler().Bind(false_block);
617
    } else if (left_result.type()->IsNever()) {
618
      assembler().Bind(false_block);
619 620 621 622
    } else if (!left_result.type()->IsConstexprBool()) {
      ReportError(
          "expected type bool, constexpr bool, or never on left-hand side of "
          "operator ||");
623 624
    }
  }
625

626
  if (left_result.type()->IsConstexprBool()) {
627 628 629 630 631 632
    VisitResult right_result = Visit(expr->right);
    if (!right_result.type()->IsConstexprBool()) {
      ReportError(
          "expected type constexpr bool on right-hand side of operator "
          "||");
    }
633 634 635
    return VisitResult(TypeOracle::GetConstexprBoolType(),
                       std::string("(") + left_result.constexpr_value() +
                           " || " + right_result.constexpr_value() + ")");
636
  }
637 638 639

  VisitResult right_result = Visit(expr->right);
  if (right_result.type()->IsBool()) {
640 641 642
    Block* true_block = LookupSimpleLabel(kTrueLabelName);
    Block* false_block = LookupSimpleLabel(kFalseLabelName);
    assembler().Branch(true_block, false_block);
643
    return VisitResult::NeverResult();
644 645 646 647 648
  } else if (!right_result.type()->IsNever()) {
    ReportError(
        "expected type bool or never on right-hand side of operator ||");
  }
  return right_result;
649 650 651
}

VisitResult ImplementationVisitor::Visit(LogicalAndExpression* expr) {
652
  VisitResult left_result;
653
  {
654 655 656
    Block* true_block = assembler().NewBlock(assembler().CurrentStack());
    Binding<LocalLabel> false_binding{&LabelBindingsManager::Get(),
                                      kTrueLabelName, LocalLabel{true_block}};
657
    left_result = Visit(expr->left);
658
    if (left_result.type()->IsBool()) {
659 660 661
      Block* false_block = LookupSimpleLabel(kFalseLabelName);
      assembler().Branch(true_block, false_block);
      assembler().Bind(true_block);
662
    } else if (left_result.type()->IsNever()) {
663
      assembler().Bind(true_block);
664 665 666 667
    } else if (!left_result.type()->IsConstexprBool()) {
      ReportError(
          "expected type bool, constexpr bool, or never on left-hand side of "
          "operator &&");
668 669
    }
  }
670

671
  if (left_result.type()->IsConstexprBool()) {
672 673 674 675 676 677
    VisitResult right_result = Visit(expr->right);
    if (!right_result.type()->IsConstexprBool()) {
      ReportError(
          "expected type constexpr bool on right-hand side of operator "
          "&&");
    }
678 679 680
    return VisitResult(TypeOracle::GetConstexprBoolType(),
                       std::string("(") + left_result.constexpr_value() +
                           " && " + right_result.constexpr_value() + ")");
681
  }
682 683 684

  VisitResult right_result = Visit(expr->right);
  if (right_result.type()->IsBool()) {
685 686 687
    Block* true_block = LookupSimpleLabel(kTrueLabelName);
    Block* false_block = LookupSimpleLabel(kFalseLabelName);
    assembler().Branch(true_block, false_block);
688
    return VisitResult::NeverResult();
689 690 691 692 693
  } else if (!right_result.type()->IsNever()) {
    ReportError(
        "expected type bool or never on right-hand side of operator &&");
  }
  return right_result;
694 695 696
}

VisitResult ImplementationVisitor::Visit(IncrementDecrementExpression* expr) {
697 698 699
  StackScope scope(this);
  LocationReference location_ref = GetLocationReference(expr->location);
  VisitResult current_value = GenerateFetchFromLocation(location_ref);
700
  VisitResult one = {TypeOracle::GetConstInt31Type(), "1"};
701 702
  Arguments args;
  args.parameters = {current_value, one};
703
  VisitResult assignment_value = GenerateCall(
704
      expr->op == IncrementDecrementOperator::kIncrement ? "+" : "-", args);
705 706
  GenerateAssignToLocation(location_ref, assignment_value);
  return scope.Yield(expr->postfix ? current_value : assignment_value);
707 708 709
}

VisitResult ImplementationVisitor::Visit(AssignmentExpression* expr) {
710
  StackScope scope(this);
711 712 713
  LocationReference location_ref = GetLocationReference(expr->location);
  VisitResult assignment_value;
  if (expr->op) {
714
    VisitResult location_value = GenerateFetchFromLocation(location_ref);
715 716
    assignment_value = Visit(expr->value);
    Arguments args;
717
    args.parameters = {location_value, assignment_value};
718
    assignment_value = GenerateCall(*expr->op, args);
719
    GenerateAssignToLocation(location_ref, assignment_value);
720 721
  } else {
    assignment_value = Visit(expr->value);
722
    GenerateAssignToLocation(location_ref, assignment_value);
723
  }
724
  return scope.Yield(assignment_value);
725 726 727 728 729 730
}

VisitResult ImplementationVisitor::Visit(NumberLiteralExpression* expr) {
  // TODO(tebbi): Do not silently loose precision; support 64bit literals.
  double d = std::stod(expr->number.c_str());
  int32_t i = static_cast<int32_t>(d);
731
  const Type* result_type = Declarations::LookupType(CONST_FLOAT64_TYPE_STRING);
732
  if (i == d) {
733
    if ((i >> 30) == (i >> 31)) {
734
      result_type = Declarations::LookupType(CONST_INT31_TYPE_STRING);
735
    } else {
736
      result_type = Declarations::LookupType(CONST_INT32_TYPE_STRING);
737 738
    }
  }
739
  return VisitResult{result_type, expr->number};
740 741
}

742 743 744
VisitResult ImplementationVisitor::Visit(AssumeTypeImpossibleExpression* expr) {
  VisitResult result = Visit(expr->expression);
  const Type* result_type =
745
      SubtractType(result.type(), Declarations::GetType(expr->excluded_type));
746 747 748
  if (result_type->IsNever()) {
    ReportError("unreachable code");
  }
749 750 751 752
  CHECK_EQ(LowerType(result_type), TypeVector{result_type});
  assembler().Emit(UnsafeCastInstruction{result_type});
  result.SetType(result_type);
  return result;
753 754
}

755
VisitResult ImplementationVisitor::Visit(StringLiteralExpression* expr) {
756 757 758
  return VisitResult{
      TypeOracle::GetConstStringType(),
      "\"" + expr->literal.substr(1, expr->literal.size() - 2) + "\""};
759 760
}

761
VisitResult ImplementationVisitor::GetBuiltinCode(Builtin* builtin) {
762
  if (builtin->IsExternal() || builtin->kind() != Builtin::kStub) {
763 764 765
    ReportError(
        "creating function pointers is only allowed for internal builtins with "
        "stub linkage");
766
  }
767
  const Type* type = TypeOracle::GetBuiltinPointerType(
768
      builtin->signature().parameter_types.types,
769
      builtin->signature().return_type);
770 771
  assembler().Emit(
      PushBuiltinPointerInstruction{builtin->ExternalName(), type});
772
  return VisitResult(type, assembler().TopRange(1));
773 774
}

775
VisitResult ImplementationVisitor::Visit(IdentifierExpression* expr) {
776 777
  StackScope scope(this);
  return scope.Yield(GenerateFetchFromLocation(GetLocationReference(expr)));
778 779
}

780
const Type* ImplementationVisitor::Visit(GotoStatement* stmt) {
781 782 783 784 785
  LocalLabel* label = LookupLabel(stmt->label);
  size_t parameter_count = label->parameter_types.size();
  if (stmt->arguments.size() != parameter_count) {
    ReportError("goto to label has incorrect number of parameters (expected ",
                parameter_count, " found ", stmt->arguments.size(), ")");
786 787 788
  }

  size_t i = 0;
789
  StackRange arguments = assembler().TopRange(0);
790
  for (Expression* e : stmt->arguments) {
791
    StackScope scope(this);
792
    VisitResult result = Visit(e);
793 794
    const Type* parameter_type = label->parameter_types[i++];
    result = GenerateImplicitConvert(parameter_type, result);
795
    arguments.Extend(scope.Yield(result).stack_range());
796 797
  }

798
  assembler().Goto(label->block, arguments.Size());
799
  return TypeOracle::GetNeverType();
800 801
}

802
const Type* ImplementationVisitor::Visit(IfStatement* stmt) {
803 804
  bool has_else = stmt->if_false.has_value();

805 806
  if (stmt->is_constexpr) {
    VisitResult expression_result = Visit(stmt->condition);
807

808
    if (!(expression_result.type() == TypeOracle::GetConstexprBoolType())) {
809
      std::stringstream stream;
810
      stream << "expression should return type constexpr bool "
811
             << "but returns type " << *expression_result.type();
812 813 814
      ReportError(stream.str());
    }

815 816 817 818 819 820 821 822
    Block* true_block = assembler().NewBlock();
    Block* false_block = assembler().NewBlock();
    Block* done_block = assembler().NewBlock();

    assembler().Emit(ConstexprBranchInstruction{
        expression_result.constexpr_value(), true_block, false_block});

    assembler().Bind(true_block);
823
    const Type* left_result = Visit(stmt->if_true);
824 825 826
    if (left_result == TypeOracle::GetVoidType()) {
      assembler().Goto(done_block);
    }
827

828 829
    assembler().Bind(false_block);
    const Type* right_result = TypeOracle::GetVoidType();
830
    if (has_else) {
831 832
      right_result = Visit(*stmt->if_false);
    }
833 834 835 836
    if (right_result == TypeOracle::GetVoidType()) {
      assembler().Goto(done_block);
    }

837 838 839 840 841 842
    if (left_result->IsNever() != right_result->IsNever()) {
      std::stringstream stream;
      stream << "either both or neither branches in a constexpr if statement "
                "must reach their end at"
             << PositionAsString(stmt->pos);
      ReportError(stream.str());
843 844
    }

845 846 847
    if (left_result != TypeOracle::GetNeverType()) {
      assembler().Bind(done_block);
    }
848
    return left_result;
849
  } else {
850 851 852 853 854 855
    Block* true_block = assembler().NewBlock(assembler().CurrentStack(),
                                             IsDeferred(stmt->if_true));
    Block* false_block =
        assembler().NewBlock(assembler().CurrentStack(),
                             stmt->if_false && IsDeferred(*stmt->if_false));
    GenerateExpressionBranch(stmt->condition, true_block, false_block);
856

857
    Block* done_block;
858 859
    bool live = false;
    if (has_else) {
860
      done_block = assembler().NewBlock();
861
    } else {
862
      done_block = false_block;
863 864
      live = true;
    }
865 866 867 868 869 870 871 872

    assembler().Bind(true_block);
    {
      const Type* result = Visit(stmt->if_true);
      if (result == TypeOracle::GetVoidType()) {
        live = true;
        assembler().Goto(done_block);
      }
873
    }
874 875 876 877 878 879 880 881 882 883

    if (has_else) {
      assembler().Bind(false_block);
      const Type* result = Visit(*stmt->if_false);
      if (result == TypeOracle::GetVoidType()) {
        live = true;
        assembler().Goto(done_block);
      }
    }

884
    if (live) {
885
      assembler().Bind(done_block);
886
    }
887
    return live ? TypeOracle::GetVoidType() : TypeOracle::GetNeverType();
888 889 890
  }
}

891
const Type* ImplementationVisitor::Visit(WhileStatement* stmt) {
892 893
  Block* body_block = assembler().NewBlock(assembler().CurrentStack());
  Block* exit_block = assembler().NewBlock(assembler().CurrentStack());
894

895 896 897 898
  Block* header_block = assembler().NewBlock();
  assembler().Goto(header_block);

  assembler().Bind(header_block);
899
  GenerateExpressionBranch(stmt->condition, body_block, exit_block);
900

901 902 903 904 905 906 907 908
  assembler().Bind(body_block);
  {
    BreakContinueActivator activator{exit_block, header_block};
    const Type* body_result = Visit(stmt->body);
    if (body_result != TypeOracle::GetNeverType()) {
      assembler().Goto(header_block);
    }
  }
909

910
  assembler().Bind(exit_block);
911
  return TypeOracle::GetVoidType();
912 913
}

914
const Type* ImplementationVisitor::Visit(BlockStatement* block) {
915
  BlockBindings<LocalValue> block_bindings(&ValueBindingsManager::Get());
916
  const Type* type = TypeOracle::GetVoidType();
917
  for (Statement* s : block->statements) {
918
    CurrentSourcePosition::Scope source_position(s->pos);
919
    if (type->IsNever()) {
920 921 922 923 924 925
      ReportError("statement after non-returning statement");
    }
    if (auto* var_declaration = VarDeclarationStatement::DynamicCast(s)) {
      type = Visit(var_declaration, &block_bindings);
    } else {
      type = Visit(s);
926 927 928 929 930
    }
  }
  return type;
}

931
const Type* ImplementationVisitor::Visit(DebugStatement* stmt) {
932
#if defined(DEBUG)
933 934 935
  assembler().Emit(PrintConstantStringInstruction{"halting because of '" +
                                                  stmt->reason + "' at " +
                                                  PositionAsString(stmt->pos)});
936
#endif
937 938 939
  assembler().Emit(AbortInstruction{stmt->never_continues
                                        ? AbortInstruction::Kind::kUnreachable
                                        : AbortInstruction::Kind::kDebugBreak});
940
  if (stmt->never_continues) {
941
    return TypeOracle::GetNeverType();
942
  } else {
943
    return TypeOracle::GetVoidType();
944 945 946
  }
}

947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964
namespace {

std::string FormatAssertSource(const std::string& str) {
  // Replace all whitespace characters with a space character.
  std::string str_no_newlines = str;
  std::replace_if(str_no_newlines.begin(), str_no_newlines.end(),
                  [](unsigned char c) { return isspace(c); }, ' ');

  // str might include indentation, squash multiple space characters into one.
  std::string result;
  std::unique_copy(str_no_newlines.begin(), str_no_newlines.end(),
                   std::back_inserter(result),
                   [](char a, char b) { return a == ' ' && b == ' '; });
  return result;
}

}  // namespace

965
const Type* ImplementationVisitor::Visit(AssertStatement* stmt) {
966
  bool do_check = !stmt->debug_only;
967
#if defined(DEBUG)
968 969 970 971 972 973 974 975 976 977 978 979
  do_check = true;
#endif
  if (do_check) {
    // CSA_ASSERT & co. are not used here on purpose for two reasons. First,
    // Torque allows and handles two types of expressions in the if protocol
    // automagically, ones that return TNode<BoolT> and those that use the
    // BranchIf(..., Label* true, Label* false) idiom. Because the machinery to
    // handle this is embedded in the expression handling and to it's not
    // possible to make the decision to use CSA_ASSERT or CSA_ASSERT_BRANCH
    // isn't trivial up-front. Secondly, on failure, the assert text should be
    // the corresponding Torque code, not the -gen.cc code, which would be the
    // case when using CSA_ASSERT_XXX.
980 981 982
    Block* true_block = assembler().NewBlock(assembler().CurrentStack());
    Block* false_block = assembler().NewBlock(assembler().CurrentStack(), true);
    GenerateExpressionBranch(stmt->expression, true_block, false_block);
983

984
    assembler().Bind(false_block);
985 986 987 988

    assembler().Emit(AbortInstruction{
        AbortInstruction::Kind::kAssertionFailure,
        "Torque assert '" + FormatAssertSource(stmt->source) + "' failed"});
989

990
    assembler().Bind(true_block);
991
  }
992
  return TypeOracle::GetVoidType();
993 994
}

995 996
const Type* ImplementationVisitor::Visit(ExpressionStatement* stmt) {
  const Type* type = Visit(stmt->expression).type();
997
  return type->IsNever() ? type : TypeOracle::GetVoidType();
998 999
}

1000
const Type* ImplementationVisitor::Visit(ReturnStatement* stmt) {
1001
  Callable* current_callable = CurrentCallable::Get();
1002
  if (current_callable->signature().return_type->IsNever()) {
1003
    std::stringstream s;
1004
    s << "cannot return from a function with return type never";
1005 1006
    ReportError(s.str());
  }
1007 1008
  LocalLabel* end =
      current_callable->IsMacro() ? LookupLabel("_macro_end") : nullptr;
1009 1010 1011 1012
  if (current_callable->HasReturnValue()) {
    if (!stmt->value) {
      std::stringstream s;
      s << "return expression needs to be specified for a return type of "
1013
        << *current_callable->signature().return_type;
1014 1015 1016 1017
      ReportError(s.str());
    }
    VisitResult expression_result = Visit(*stmt->value);
    VisitResult return_result = GenerateImplicitConvert(
1018
        current_callable->signature().return_type, expression_result);
1019
    if (current_callable->IsMacro()) {
1020 1021 1022 1023
      if (return_result.IsOnStack()) {
        StackRange return_value_range =
            GenerateLabelGoto(end, return_result.stack_range());
        SetReturnValue(VisitResult(return_result.type(), return_value_range));
1024
      } else {
1025 1026
        GenerateLabelGoto(end);
        SetReturnValue(return_result);
1027
      }
1028 1029
    } else if (current_callable->IsBuiltin()) {
      assembler().Emit(ReturnInstruction{});
1030 1031 1032 1033 1034 1035 1036
    } else {
      UNREACHABLE();
    }
  } else {
    if (stmt->value) {
      std::stringstream s;
      s << "return expression can't be specified for a void or never return "
1037
           "type";
1038 1039 1040 1041 1042
      ReportError(s.str());
    }
    GenerateLabelGoto(end);
  }
  current_callable->IncrementReturns();
1043
  return TypeOracle::GetNeverType();
1044 1045
}

1046
const Type* ImplementationVisitor::Visit(ForOfLoopStatement* stmt) {
1047
  VisitResult expression_result = Visit(stmt->iterable);
1048 1049 1050
  VisitResult begin = stmt->begin
                          ? Visit(*stmt->begin)
                          : VisitResult(TypeOracle::GetConstInt31Type(), "0");
1051

1052 1053 1054
  VisitResult end = stmt->end
                        ? Visit(*stmt->end)
                        : GenerateCall(".length", {{expression_result}, {}});
1055

1056
  const Type* common_type = GetCommonType(begin.type(), end.type());
1057
  VisitResult index = GenerateImplicitConvert(common_type, begin);
1058

1059 1060 1061
  Block* body_block = assembler().NewBlock();
  Block* increment_block = assembler().NewBlock(assembler().CurrentStack());
  Block* exit_block = assembler().NewBlock(assembler().CurrentStack());
1062

1063
  Block* header_block = assembler().NewBlock();
1064

1065
  assembler().Goto(header_block);
1066

1067
  assembler().Bind(header_block);
1068

1069
  BreakContinueActivator activator(exit_block, increment_block);
1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083

  {
    StackScope comparison_scope(this);
    VisitResult result = GenerateCall("<", {{index, end}, {}});
    if (result.type() != TypeOracle::GetBoolType()) {
      ReportError("operator < with arguments(", *index.type(), ", ",
                  *end.type(),
                  ")  used in for-of loop has to return type bool, but "
                  "returned type ",
                  *result.type());
    }
    comparison_scope.Yield(result);
  }
  assembler().Branch(body_block, exit_block);
1084

1085 1086 1087 1088 1089 1090 1091 1092
  assembler().Bind(body_block);
  {
    VisitResult element_result;
    {
      StackScope element_scope(this);
      VisitResult result = GenerateCall("[]", {{expression_result, index}, {}});
      if (stmt->var_declaration->type) {
        const Type* declared_type =
1093
            Declarations::GetType(*stmt->var_declaration->type);
1094 1095 1096 1097
        result = GenerateImplicitConvert(declared_type, result);
      }
      element_result = element_scope.Yield(result);
    }
1098 1099 1100
    Binding<LocalValue> element_var_binding{&ValueBindingsManager::Get(),
                                            stmt->var_declaration->name,
                                            LocalValue{true, element_result}};
1101 1102 1103
    Visit(stmt->body);
  }
  assembler().Goto(increment_block);
1104

1105 1106 1107 1108 1109
  assembler().Bind(increment_block);
  {
    Arguments increment_args;
    increment_args.parameters = {index, {TypeOracle::GetConstInt31Type(), "1"}};
    VisitResult increment_result = GenerateCall("+", increment_args);
1110

1111 1112 1113
    GenerateAssignToLocation(LocationReference::VariableAccess(index),
                             increment_result);
  }
1114

1115
  assembler().Goto(header_block);
1116

1117
  assembler().Bind(exit_block);
1118
  return TypeOracle::GetVoidType();
1119 1120
}

1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143
VisitResult ImplementationVisitor::TemporaryUninitializedStruct(
    const StructType* struct_type, const std::string& reason) {
  StackRange range = assembler().TopRange(0);
  for (const Field& f : struct_type->fields()) {
    if (const StructType* struct_type =
            StructType::DynamicCast(f.name_and_type.type)) {
      range.Extend(
          TemporaryUninitializedStruct(struct_type, reason).stack_range());
    } else {
      std::string descriptor = "unitialized field '" + f.name_and_type.name +
                               "' declared at " + PositionAsString(f.pos) +
                               " (" + reason + ")";
      TypeVector lowered_types = LowerType(f.name_and_type.type);
      for (const Type* type : lowered_types) {
        assembler().Emit(PushUninitializedInstruction{
            TypeOracle::GetTopType(descriptor, type)});
      }
      range.Extend(assembler().TopRange(lowered_types.size()));
    }
  }
  return VisitResult(struct_type, range);
}

1144
VisitResult ImplementationVisitor::Visit(TryLabelExpression* expr) {
1145 1146 1147 1148
  size_t parameter_count = expr->label_block->parameters.names.size();
  std::vector<VisitResult> parameters;

  Block* label_block = nullptr;
1149
  Block* done_block = assembler().NewBlock();
1150
  VisitResult try_result;
1151 1152

  {
1153 1154 1155 1156 1157 1158 1159 1160
    CurrentSourcePosition::Scope source_position(expr->label_block->pos);
    if (expr->label_block->parameters.has_varargs) {
      ReportError("cannot use ... for label parameters");
    }
    Stack<const Type*> label_input_stack = assembler().CurrentStack();
    TypeVector parameter_types;
    for (size_t i = 0; i < parameter_count; ++i) {
      const Type* type =
1161
          Declarations::GetType(expr->label_block->parameters.types[i]);
1162 1163 1164
      parameter_types.push_back(type);
      if (type->IsConstexpr()) {
        ReportError("no constexpr type allowed for label arguments");
1165
      }
1166 1167
      StackRange range = label_input_stack.PushMany(LowerType(type));
      parameters.push_back(VisitResult(type, range));
1168
    }
1169 1170 1171 1172 1173 1174
    label_block = assembler().NewBlock(label_input_stack,
                                       IsDeferred(expr->label_block->body));

    Binding<LocalLabel> label_binding{&LabelBindingsManager::Get(),
                                      expr->label_block->label,
                                      LocalLabel{label_block, parameter_types}};
1175 1176

    // Visit try
1177 1178 1179 1180 1181
    StackScope stack_scope(this);
    try_result = Visit(expr->try_expression);
    if (try_result.type() != TypeOracle::GetNeverType()) {
      try_result = stack_scope.Yield(try_result);
      assembler().Goto(done_block);
1182 1183 1184
    }
  }

1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195
  // Visit and output the code for the label block. If the label block falls
  // through, then the try must not return a value. Also, if the try doesn't
  // fall through, but the label does, then overall the try-label block
  // returns type void.
  assembler().Bind(label_block);
  const Type* label_result;
  {
    BlockBindings<LocalValue> parameter_bindings(&ValueBindingsManager::Get());
    for (size_t i = 0; i < parameter_count; ++i) {
      parameter_bindings.Add(expr->label_block->parameters.names[i],
                             LocalValue{true, parameters[i]});
1196
    }
1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209

    label_result = Visit(expr->label_block->body);
  }
  if (!try_result.type()->IsVoidOrNever() && label_result->IsVoid()) {
    ReportError(
        "otherwise clauses cannot fall through in a non-void expression");
  }
  if (label_result != TypeOracle::GetNeverType()) {
    assembler().Goto(done_block);
  }
  if (label_result->IsVoid() && try_result.type()->IsNever()) {
    try_result =
        VisitResult(TypeOracle::GetVoidType(), try_result.stack_range());
1210 1211
  }

1212
  if (!try_result.type()->IsNever()) {
1213
    assembler().Bind(done_block);
1214 1215 1216 1217
  }
  return try_result;
}

1218 1219 1220 1221
VisitResult ImplementationVisitor::Visit(StatementExpression* expr) {
  return VisitResult{Visit(expr->statement), assembler().TopRange(0)};
}

1222 1223 1224 1225 1226 1227 1228 1229
VisitResult ImplementationVisitor::Visit(NewExpression* expr) {
  StackScope stack_scope(this);
  const Type* type = Declarations::GetType(expr->type);
  const ClassType* class_type = ClassType::DynamicCast(type);
  if (class_type == nullptr) {
    ReportError("type for new expression must be a class, \"", *type,
                "\" is not");
  }
1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253

  // In order to ensure "atomicity" of object allocation, a class' constructors
  // operate on a per-class internal struct rather than the class directly until
  // the constructor has successfully completed and all class members are
  // available. Create the appropriate unitialized struct and pass it to the
  // matching class constructor with the arguments that were passed to new{}
  StructType* class_this_struct = class_type->struct_type();
  VisitResult unitialized_struct = TemporaryUninitializedStruct(
      class_this_struct,
      "it's not set in the constructor for class " + class_type->name());
  Arguments constructor_arguments;
  for (auto p : expr->parameters) {
    constructor_arguments.parameters.push_back(Visit(p));
  }
  LocationReference unitialized_struct_ref =
      LocationReference::VariableAccess(unitialized_struct);
  Callable* callable =
      LookupConstructor(unitialized_struct_ref, constructor_arguments, {});
  GenerateCall(callable, unitialized_struct_ref, constructor_arguments,
               {class_type}, false);
  VisitResult new_struct_result = unitialized_struct;

  // Output the code to generate an unitialized object of the class size in the
  // GC heap.
1254 1255 1256 1257 1258
  Arguments allocate_arguments;
  allocate_arguments.parameters.push_back(VisitResult(
      TypeOracle::GetConstInt31Type(), std::to_string(class_type->size())));
  VisitResult allocate_result =
      GenerateCall("%Allocate", allocate_arguments, {class_type}, false);
1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278
  DCHECK(allocate_result.IsOnStack());

  // Fill in the fields of the newly allocated class by copying the values
  // from the struct that was built by the constructor. So that the generaeted
  // code is a bit more readable, assign the values from the first class
  // member to the last, in order. To do this, first build a list of fields
  // to assign to in reverse order by visiting the class heirarchy.
  std::vector<std::pair<const Field*, VisitResult>> store_pairs;
  const ClassType* current_class = class_type;
  while (current_class != nullptr) {
    auto& fields = current_class->fields();
    for (auto i = fields.rbegin(); i != fields.rend(); ++i) {
      store_pairs.push_back(std::make_pair(
          &*i, ProjectStructField(new_struct_result, i->name_and_type.name)));
    }
    current_class = current_class->GetSuperClass();
    if (current_class) {
      new_struct_result = ProjectStructField(new_struct_result,
                                             kConstructorStructSuperFieldName);
    }
1279
  }
1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293

  // Now that the reversed list of fields and the assignment VisitResults are
  // available, emit the copies in reverse order of the reversed list to
  // produce the class field assignments in the expected order.
  for (auto i = store_pairs.rbegin(); i != store_pairs.rend(); ++i) {
    assembler().Emit(
        PeekInstruction(allocate_result.stack_range().begin(), class_type));
    assembler().Emit(PeekInstruction(i->second.stack_range().begin(),
                                     i->first->name_and_type.type));
    assembler().Emit(
        StoreObjectFieldInstruction(class_type, i->first->name_and_type.name));
  }

  return stack_scope.Yield(allocate_result);
1294 1295
}

1296
const Type* ImplementationVisitor::Visit(BreakStatement* stmt) {
1297 1298
  base::Optional<Binding<LocalLabel>*> break_label = TryLookupLabel("_break");
  if (!break_label) {
1299
    ReportError("break used outside of loop");
1300
  }
1301
  assembler().Goto((*break_label)->block);
1302
  return TypeOracle::GetNeverType();
1303 1304
}

1305
const Type* ImplementationVisitor::Visit(ContinueStatement* stmt) {
1306 1307 1308
  base::Optional<Binding<LocalLabel>*> continue_label =
      TryLookupLabel("_continue");
  if (!continue_label) {
1309
    ReportError("continue used outside of loop");
1310
  }
1311
  assembler().Goto((*continue_label)->block);
1312
  return TypeOracle::GetNeverType();
1313 1314
}

1315
const Type* ImplementationVisitor::Visit(ForLoopStatement* stmt) {
1316
  BlockBindings<LocalValue> loop_bindings(&ValueBindingsManager::Get());
1317

1318 1319 1320 1321
  if (stmt->var_declaration) Visit(*stmt->var_declaration, &loop_bindings);

  Block* body_block = assembler().NewBlock(assembler().CurrentStack());
  Block* exit_block = assembler().NewBlock(assembler().CurrentStack());
1322

1323 1324 1325
  Block* header_block = assembler().NewBlock();
  assembler().Goto(header_block);
  assembler().Bind(header_block);
1326

1327 1328
  // The continue label is where "continue" statements jump to. If no action
  // expression is provided, we jump directly to the header.
1329
  Block* continue_block = header_block;
1330

1331
  // The action label is only needed when an action expression was provided.
1332
  Block* action_block = nullptr;
1333
  if (stmt->action) {
1334
    action_block = assembler().NewBlock();
1335 1336

    // The action expression needs to be executed on a continue.
1337
    continue_block = action_block;
1338 1339 1340
  }

  if (stmt->test) {
1341
    GenerateExpressionBranch(*stmt->test, body_block, exit_block);
1342
  } else {
1343 1344 1345 1346 1347 1348 1349 1350 1351 1352
    assembler().Goto(body_block);
  }

  assembler().Bind(body_block);
  {
    BreakContinueActivator activator(exit_block, continue_block);
    const Type* body_result = Visit(stmt->body);
    if (body_result != TypeOracle::GetNeverType()) {
      assembler().Goto(continue_block);
    }
1353 1354
  }

1355
  if (stmt->action) {
1356
    assembler().Bind(action_block);
1357 1358 1359 1360
    const Type* action_result = Visit(*stmt->action);
    if (action_result != TypeOracle::GetNeverType()) {
      assembler().Goto(header_block);
    }
1361 1362
  }

1363
  assembler().Bind(exit_block);
1364
  return TypeOracle::GetVoidType();
1365 1366 1367
}

void ImplementationVisitor::GenerateImplementation(const std::string& dir,
1368 1369
                                                   Namespace* nspace) {
  std::string new_source(nspace->source());
1370
  std::string base_file_name =
1371
      "builtins-" + DashifyString(nspace->name()) + "-from-dsl-gen";
1372 1373

  std::string source_file_name = dir + "/" + base_file_name + ".cc";
1374
  ReplaceFileContentsIfDifferent(source_file_name, new_source);
1375
  std::string new_header(nspace->header());
1376
  std::string header_file_name = dir + "/" + base_file_name + ".h";
1377 1378 1379 1380
  ReplaceFileContentsIfDifferent(header_file_name, new_header);
}

void ImplementationVisitor::GenerateMacroFunctionDeclaration(
1381
    std::ostream& o, const std::string& macro_prefix, Macro* macro) {
1382
  GenerateFunctionDeclaration(o, macro_prefix, macro->ExternalName(),
1383 1384 1385 1386 1387 1388
                              macro->signature(), macro->parameter_names());
}

void ImplementationVisitor::GenerateFunctionDeclaration(
    std::ostream& o, const std::string& macro_prefix, const std::string& name,
    const Signature& signature, const NameVector& parameter_names) {
1389
  if (GlobalContext::verbose()) {
1390
    std::cout << "generating source for declaration " << name << "\n";
1391 1392
  }

1393 1394 1395 1396
  if (signature.return_type->IsVoidOrNever()) {
    o << "void";
  } else {
    o << signature.return_type->GetGeneratedTypeName();
1397
  }
1398
  o << " " << macro_prefix << name << "(";
1399

1400 1401
  DCHECK_EQ(signature.types().size(), parameter_names.size());
  auto type_iterator = signature.types().begin();
1402
  bool first = true;
1403
  for (const std::string& name : parameter_names) {
1404 1405 1406
    if (!first) {
      o << ", ";
    }
1407
    const Type* parameter_type = *type_iterator;
1408
    const std::string& generated_type_name =
1409
        parameter_type->GetGeneratedTypeName();
1410
    o << generated_type_name << " " << ExternalParameterName(name);
1411 1412 1413 1414
    type_iterator++;
    first = false;
  }

1415
  for (const LabelDeclaration& label_info : signature.labels) {
1416 1417 1418
    if (!first) {
      o << ", ";
    }
1419
    o << "compiler::CodeAssemblerLabel* " << ExternalLabelName(label_info.name);
1420
    size_t i = 0;
1421
    for (const Type* type : label_info.types) {
1422
      std::string generated_type_name("compiler::TypedCodeAssemblerVariable<");
1423
      generated_type_name += type->GetGeneratedTNodeTypeName();
1424 1425
      generated_type_name += ">*";
      o << ", ";
1426 1427
      o << generated_type_name << " "
        << ExternalLabelParameterName(label_info.name, i);
1428
      ++i;
1429 1430 1431 1432 1433 1434
    }
  }

  o << ")";
}

1435 1436
namespace {

1437
void FailCallableLookup(const std::string& reason, const QualifiedName& name,
1438 1439
                        const TypeVector& parameter_types,
                        const std::vector<Binding<LocalLabel>*>& labels,
1440
                        const std::vector<Signature>& candidates) {
1441
  std::stringstream stream;
1442 1443
  stream << "\n" << reason << ": \n  " << name << "(" << parameter_types << ")";
  if (labels.size() != 0) {
1444
    stream << " labels ";
1445 1446
    for (size_t i = 0; i < labels.size(); ++i) {
      stream << labels[i]->name() << "(" << labels[i]->parameter_types << ")";
1447 1448 1449
    }
  }
  stream << "\ncandidates are:";
1450 1451 1452 1453
  for (const Signature& signature : candidates) {
    stream << "\n  " << name;
    PrintSignature(stream, signature, false);
  }
1454 1455 1456
  ReportError(stream.str());
}

1457 1458 1459 1460 1461 1462 1463 1464
Callable* GetOrCreateSpecialization(const SpecializationKey& key) {
  if (base::Optional<Callable*> specialization =
          key.generic->GetSpecialization(key.specialized_types)) {
    return *specialization;
  }
  return DeclarationVisitor().SpecializeImplicit(key);
}

1465 1466
}  // namespace

1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493
base::Optional<Binding<LocalValue>*> ImplementationVisitor::TryLookupLocalValue(
    const std::string& name) {
  return ValueBindingsManager::Get().TryLookup(name);
}

base::Optional<Binding<LocalLabel>*> ImplementationVisitor::TryLookupLabel(
    const std::string& name) {
  return LabelBindingsManager::Get().TryLookup(name);
}

Binding<LocalLabel>* ImplementationVisitor::LookupLabel(
    const std::string& name) {
  base::Optional<Binding<LocalLabel>*> label = TryLookupLabel(name);
  if (!label) ReportError("cannot find label ", name);
  return *label;
}

Block* ImplementationVisitor::LookupSimpleLabel(const std::string& name) {
  LocalLabel* label = LookupLabel(name);
  if (!label->parameter_types.empty()) {
    ReportError("label ", name,
                "was expected to have no parameters, but has parameters (",
                label->parameter_types, ")");
  }
  return label->block;
}

1494
template <class Container>
1495
Callable* ImplementationVisitor::LookupCallable(
1496
    const QualifiedName& name, const Container& declaration_container,
1497 1498 1499
    const TypeVector& parameter_types,
    const std::vector<Binding<LocalLabel>*>& labels,
    const TypeVector& specialization_types) {
1500
  Callable* result = nullptr;
1501 1502 1503

  std::vector<Declarable*> overloads;
  std::vector<Signature> overload_signatures;
1504
  for (auto* declarable : declaration_container) {
1505
    if (Generic* generic = Generic::DynamicCast(declarable)) {
1506 1507 1508 1509
      base::Optional<TypeVector> inferred_specialization_types =
          generic->InferSpecializationTypes(specialization_types,
                                            parameter_types);
      if (!inferred_specialization_types) continue;
1510 1511 1512
      overloads.push_back(generic);
      overload_signatures.push_back(
          DeclarationVisitor().MakeSpecializedSignature(
1513
              SpecializationKey{generic, *inferred_specialization_types}));
1514 1515 1516 1517 1518 1519 1520 1521 1522
    } else if (Callable* callable = Callable::DynamicCast(declarable)) {
      overloads.push_back(callable);
      overload_signatures.push_back(callable->signature());
    }
  }
  // Indices of candidates in overloads/overload_signatures.
  std::vector<size_t> candidates;
  for (size_t i = 0; i < overloads.size(); ++i) {
    const Signature& signature = overload_signatures[i];
1523
    bool try_bool_context = labels.size() == 0 &&
1524 1525 1526 1527 1528 1529 1530
                            signature.return_type == TypeOracle::GetNeverType();
    base::Optional<Binding<LocalLabel>*> true_label;
    base::Optional<Binding<LocalLabel>*> false_label;
    if (try_bool_context) {
      true_label = TryLookupLabel(kTrueLabelName);
      false_label = TryLookupLabel(kFalseLabelName);
    }
1531
    if (IsCompatibleSignature(signature, parameter_types, labels) ||
1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544
        (true_label && false_label &&
         IsCompatibleSignature(signature, parameter_types,
                               {*true_label, *false_label}))) {
      candidates.push_back(i);
    }
  }

  if (overloads.empty()) {
    std::stringstream stream;
    stream << "no matching declaration found for " << name;
    ReportError(stream.str());
  } else if (candidates.empty()) {
    FailCallableLookup("cannot find suitable callable with name", name,
1545
                       parameter_types, labels, overload_signatures);
1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563
  }

  auto is_better_candidate = [&](size_t a, size_t b) {
    return ParameterDifference(overload_signatures[a].GetExplicitTypes(),
                               parameter_types)
        .StrictlyBetterThan(ParameterDifference(
            overload_signatures[b].GetExplicitTypes(), parameter_types));
  };

  size_t best = *std::min_element(candidates.begin(), candidates.end(),
                                  is_better_candidate);
  // This check is contained in libstdc++'s std::min_element.
  DCHECK(!is_better_candidate(best, best));
  for (size_t candidate : candidates) {
    if (candidate != best && !is_better_candidate(best, candidate)) {
      std::vector<Signature> candidate_signatures;
      for (size_t i : candidates) {
        candidate_signatures.push_back(overload_signatures[i]);
1564
      }
1565
      FailCallableLookup("ambiguous callable ", name, parameter_types, labels,
1566
                         candidate_signatures);
1567
    }
1568
  }
1569

1570 1571
  if (Generic* generic = Generic::DynamicCast(overloads[best])) {
    result = GetOrCreateSpecialization(
1572 1573
        SpecializationKey{generic, *generic->InferSpecializationTypes(
                                       specialization_types, parameter_types)});
1574
  } else {
1575
    result = Callable::cast(overloads[best]);
1576 1577 1578
  }

  size_t caller_size = parameter_types.size();
1579 1580
  size_t callee_size =
      result->signature().types().size() - result->signature().implicit_count;
1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592
  if (caller_size != callee_size &&
      !result->signature().parameter_types.var_args) {
    std::stringstream stream;
    stream << "parameter count mismatch calling " << *result << " - expected "
           << std::to_string(callee_size) << ", found "
           << std::to_string(caller_size);
    ReportError(stream.str());
  }

  return result;
}

1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613
template <class Container>
Callable* ImplementationVisitor::LookupCallable(
    const QualifiedName& name, const Container& declaration_container,
    const Arguments& arguments, const TypeVector& specialization_types) {
  return LookupCallable(name, declaration_container,
                        arguments.parameters.GetTypeVector(), arguments.labels,
                        specialization_types);
}

Method* ImplementationVisitor::LookupMethod(
    const std::string& name, LocationReference this_reference,
    const Arguments& arguments, const TypeVector& specialization_types) {
  TypeVector types(arguments.parameters.GetTypeVector());
  types.insert(types.begin(), this_reference.GetVisitResult().type());
  return Method::cast(
      LookupCallable({{}, name},
                     AggregateType::cast(this_reference.GetVisitResult().type())
                         ->Methods(name),
                     types, arguments.labels, specialization_types));
}

1614
const Type* ImplementationVisitor::GetCommonType(const Type* left,
1615
                                                 const Type* right) {
1616
  const Type* common_type;
1617
  if (IsAssignableFrom(left, right)) {
1618
    common_type = left;
1619
  } else if (IsAssignableFrom(right, left)) {
1620 1621
    common_type = right;
  } else {
1622
    common_type = TypeOracle::GetUnionType(left, right);
1623
  }
1624
  common_type = common_type->NonConstexprVersion();
1625 1626 1627 1628
  return common_type;
}

VisitResult ImplementationVisitor::GenerateCopy(const VisitResult& to_copy) {
1629 1630 1631 1632 1633
  if (to_copy.IsOnStack()) {
    return VisitResult(to_copy.type(),
                       assembler().Peek(to_copy.stack_range(), to_copy.type()));
  }
  return to_copy;
1634 1635
}

1636
VisitResult ImplementationVisitor::Visit(StructExpression* decl) {
1637
  StackScope stack_scope(this);
1638 1639
  const Type* raw_type = Declarations::LookupType(
      QualifiedName(decl->namespace_qualification, decl->name));
1640 1641 1642 1643 1644 1645
  if (!raw_type->IsStructType()) {
    std::stringstream s;
    s << decl->name << " is not a struct but used like one ";
    ReportError(s.str());
  }
  const StructType* struct_type = StructType::cast(raw_type);
1646 1647 1648 1649
  // Push unitialized 'this'
  VisitResult uninitialized_struct = TemporaryUninitializedStruct(
      struct_type,
      "it's not set in the constructor for struct " + struct_type->name());
1650 1651 1652 1653
  Arguments constructor_arguments;
  for (auto p : decl->expressions) {
    constructor_arguments.parameters.push_back(Visit(p));
  }
1654 1655 1656 1657 1658
  LocationReference this_ref =
      LocationReference::VariableAccess(uninitialized_struct);
  Callable* callable = LookupConstructor(this_ref, constructor_arguments, {});
  GenerateCall(callable, this_ref, constructor_arguments, {}, false);
  return stack_scope.Yield(uninitialized_struct);
1659 1660
}

1661
LocationReference ImplementationVisitor::GetLocationReference(
1662
    Expression* location) {
1663 1664 1665 1666 1667 1668 1669 1670 1671 1672
  switch (location->kind) {
    case AstNode::Kind::kIdentifierExpression:
      return GetLocationReference(static_cast<IdentifierExpression*>(location));
    case AstNode::Kind::kFieldAccessExpression:
      return GetLocationReference(
          static_cast<FieldAccessExpression*>(location));
    case AstNode::Kind::kElementAccessExpression:
      return GetLocationReference(
          static_cast<ElementAccessExpression*>(location));
    default:
1673
      return LocationReference::Temporary(Visit(location), "expression");
1674 1675 1676
  }
}

1677 1678
LocationReference ImplementationVisitor::GetLocationReference(
    FieldAccessExpression* expr) {
1679 1680 1681 1682 1683
  LocationReference reference = GetLocationReference(expr->object);
  if (reference.IsVariableAccess() &&
      reference.variable().type()->IsStructType()) {
    return LocationReference::VariableAccess(
        ProjectStructField(reference.variable(), expr->field));
1684
  }
1685 1686 1687 1688
  if (reference.IsTemporary() && reference.temporary().type()->IsStructType()) {
    return LocationReference::Temporary(
        ProjectStructField(reference.temporary(), expr->field),
        reference.temporary_description());
1689
  }
1690 1691
  return LocationReference::FieldAccess(GenerateFetchFromLocation(reference),
                                        expr->field);
1692 1693
}

1694 1695 1696 1697 1698
LocationReference ImplementationVisitor::GetLocationReference(
    ElementAccessExpression* expr) {
  VisitResult array = Visit(expr->array);
  VisitResult index = Visit(expr->index);
  return LocationReference::ArrayAccess(array, index);
1699 1700
}

1701 1702
LocationReference ImplementationVisitor::GetLocationReference(
    IdentifierExpression* expr) {
1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714
  if (expr->namespace_qualification.empty()) {
    if (base::Optional<Binding<LocalValue>*> value =
            TryLookupLocalValue(expr->name)) {
      if (expr->generic_arguments.size() != 0) {
        ReportError("cannot have generic parameters on local name ",
                    expr->name);
      }
      if ((*value)->is_const) {
        return LocationReference::Temporary((*value)->value,
                                            "constant value " + expr->name);
      }
      return LocationReference::VariableAccess((*value)->value);
1715 1716 1717
    }
  }

1718 1719 1720
  if (expr->IsThis()) {
    ReportError("\"this\" cannot be qualified");
  }
1721
  QualifiedName name = QualifiedName(expr->namespace_qualification, expr->name);
1722 1723
  if (base::Optional<Builtin*> builtin = Declarations::TryLookupBuiltin(name)) {
    return LocationReference::Temporary(GetBuiltinCode(*builtin),
1724 1725 1726
                                        "builtin " + expr->name);
  }
  if (expr->generic_arguments.size() != 0) {
1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737
    Generic* generic = Declarations::LookupUniqueGeneric(name);
    Callable* specialization = GetOrCreateSpecialization(
        SpecializationKey{generic, GetTypeVector(expr->generic_arguments)});
    if (Builtin* builtin = Builtin::DynamicCast(specialization)) {
      DCHECK(!builtin->IsExternal());
      return LocationReference::Temporary(GetBuiltinCode(builtin),
                                          "builtin " + expr->name);
    } else {
      ReportError("cannot create function pointer for non-builtin ",
                  generic->name());
    }
1738
  }
1739
  Value* value = Declarations::LookupValue(name);
1740
  if (auto* constant = NamespaceConstant::DynamicCast(value)) {
1741 1742
    if (constant->type()->IsConstexpr()) {
      return LocationReference::Temporary(
1743 1744 1745
          VisitResult(constant->type(), constant->ExternalAssemblerName() +
                                            "(state_)." +
                                            constant->constant_name() + "()"),
1746
          "namespace constant " + expr->name);
1747
    }
1748
    assembler().Emit(NamespaceConstantInstruction{constant});
1749 1750 1751 1752
    StackRange stack_range =
        assembler().TopRange(LoweredSlotCount(constant->type()));
    return LocationReference::Temporary(
        VisitResult(constant->type(), stack_range),
1753
        "namespace constant " + expr->name);
1754
  }
1755 1756 1757
  ExternConstant* constant = ExternConstant::cast(value);
  return LocationReference::Temporary(constant->value(),
                                      "extern value " + expr->name);
1758 1759
}

1760 1761 1762 1763 1764 1765
VisitResult ImplementationVisitor::GenerateFetchFromLocation(
    const LocationReference& reference) {
  if (reference.IsTemporary()) {
    return GenerateCopy(reference.temporary());
  } else if (reference.IsVariableAccess()) {
    return GenerateCopy(reference.variable());
1766
  } else {
1767 1768 1769
    DCHECK(reference.IsCallAccess());
    return GenerateCall(reference.eval_function(),
                        Arguments{reference.call_arguments(), {}});
1770 1771 1772
  }
}

1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784
void ImplementationVisitor::GenerateAssignToLocation(
    const LocationReference& reference, const VisitResult& assignment_value) {
  if (reference.IsCallAccess()) {
    Arguments arguments{reference.call_arguments(), {}};
    arguments.parameters.push_back(assignment_value);
    GenerateCall(reference.assign_function(), arguments);
  } else if (reference.IsVariableAccess()) {
    VisitResult variable = reference.variable();
    VisitResult converted_value =
        GenerateImplicitConvert(variable.type(), assignment_value);
    assembler().Poke(variable.stack_range(), converted_value.stack_range(),
                     variable.type());
1785
  } else {
1786
    DCHECK(reference.IsTemporary());
1787 1788
    ReportError("cannot assign to temporary ",
                reference.temporary_description());
1789 1790 1791
  }
}

1792
VisitResult ImplementationVisitor::GeneratePointerCall(
1793
    Expression* callee, const Arguments& arguments, bool is_tailcall) {
1794
  StackScope scope(this);
1795 1796
  TypeVector parameter_types(arguments.parameters.GetTypeVector());
  VisitResult callee_result = Visit(callee);
1797
  if (!callee_result.type()->IsBuiltinPointerType()) {
1798 1799
    std::stringstream stream;
    stream << "Expected a function pointer type but found "
1800
           << *callee_result.type();
1801 1802
    ReportError(stream.str());
  }
1803 1804
  const BuiltinPointerType* type =
      BuiltinPointerType::cast(callee_result.type());
1805

1806 1807 1808
  if (type->parameter_types().size() != parameter_types.size()) {
    std::stringstream stream;
    stream << "parameter count mismatch calling function pointer with Type: "
1809
           << *type << " - expected "
1810 1811 1812 1813 1814 1815
           << std::to_string(type->parameter_types().size()) << ", found "
           << std::to_string(parameter_types.size());
    ReportError(stream.str());
  }

  ParameterTypes types{type->parameter_types(), false};
1816 1817 1818
  Signature sig;
  sig.parameter_types = types;
  if (!IsCompatibleSignature(sig, parameter_types, {})) {
1819 1820 1821 1822 1823 1824 1825
    std::stringstream stream;
    stream << "parameters do not match function pointer signature. Expected: ("
           << type->parameter_types() << ") but got: (" << parameter_types
           << ")";
    ReportError(stream.str());
  }

1826 1827
  callee_result = GenerateCopy(callee_result);
  StackRange arg_range = assembler().TopRange(0);
1828 1829
  for (size_t current = 0; current < arguments.parameters.size(); ++current) {
    const Type* to_type = type->parameter_types()[current];
1830 1831 1832
    arg_range.Extend(
        GenerateImplicitConvert(to_type, arguments.parameters[current])
            .stack_range());
1833 1834
  }

1835 1836
  assembler().Emit(
      CallBuiltinPointerInstruction{is_tailcall, type, arg_range.Size()});
1837

1838 1839
  if (is_tailcall) {
    return VisitResult::NeverResult();
1840
  }
1841 1842
  DCHECK_EQ(1, LoweredSlotCount(type->return_type()));
  return scope.Yield(VisitResult(type->return_type(), assembler().TopRange(1)));
1843 1844
}

1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858
void ImplementationVisitor::AddCallParameter(
    Callable* callable, VisitResult parameter, const Type* parameter_type,
    std::vector<VisitResult>* converted_arguments, StackRange* argument_range,
    std::vector<std::string>* constexpr_arguments) {
  VisitResult converted = GenerateImplicitConvert(parameter_type, parameter);
  converted_arguments->push_back(converted);
  if (!callable->ShouldBeInlined()) {
    if (converted.IsOnStack()) {
      argument_range->Extend(converted.stack_range());
    } else {
      constexpr_arguments->push_back(converted.constexpr_value());
    }
  }
}
1859

1860 1861 1862 1863
VisitResult ImplementationVisitor::GenerateCall(
    Callable* callable, base::Optional<LocationReference> this_reference,
    Arguments arguments, const TypeVector& specialization_types,
    bool is_tailcall) {
1864
  // Operators used in a branching context can also be function calls that never
1865
  // return but have a True and False label
1866 1867
  if (arguments.labels.size() == 0 &&
      callable->signature().labels.size() == 2) {
1868
    Binding<LocalLabel>* true_label = LookupLabel(kTrueLabelName);
1869
    arguments.labels.push_back(true_label);
1870
    Binding<LocalLabel>* false_label = LookupLabel(kFalseLabelName);
1871 1872 1873
    arguments.labels.push_back(false_label);
  }

1874
  const Type* return_type = callable->signature().return_type;
1875

1876 1877 1878
  std::vector<VisitResult> converted_arguments;
  StackRange argument_range = assembler().TopRange(0);
  std::vector<std::string> constexpr_arguments;
1879

1880
  size_t current = 0;
1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895
  for (; current < callable->signature().implicit_count; ++current) {
    std::string implicit_name = callable->signature().parameter_names[current];
    base::Optional<Binding<LocalValue>*> val =
        TryLookupLocalValue(implicit_name);
    if (!val) {
      ReportError("implicit parameter '", implicit_name,
                  "' required for call to '", callable->ReadableName(),
                  "' is not defined");
    }
    AddCallParameter(callable, (*val)->value,
                     callable->signature().parameter_types.types[current],
                     &converted_arguments, &argument_range,
                     &constexpr_arguments);
  }

1896 1897 1898 1899 1900 1901 1902 1903 1904
  if (this_reference) {
    DCHECK(callable->IsMethod());
    Method* method = Method::cast(callable);
    // By now, the this reference should either be a variable or
    // a temporary, in both cases the fetch of the VisitResult should succeed.
    VisitResult this_value = this_reference->GetVisitResult();
    if (method->ShouldBeInlined()) {
      if (!this_value.type()->IsSubtypeOf(method->aggregate_type())) {
        ReportError("this parameter must be a subtype of ",
1905 1906
                    *method->aggregate_type(), " but it is of type ",
                    this_value.type());
1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921
      }
    } else {
      AddCallParameter(callable, this_value, method->aggregate_type(),
                       &converted_arguments, &argument_range,
                       &constexpr_arguments);
    }
    ++current;
  }

  for (auto arg : arguments.parameters) {
    const Type* to_type = (current >= callable->signature().types().size())
                              ? TypeOracle::GetObjectType()
                              : callable->signature().types()[current++];
    AddCallParameter(callable, arg, to_type, &converted_arguments,
                     &argument_range, &constexpr_arguments);
1922
  }
1923

1924
  if (GlobalContext::verbose()) {
1925 1926
    std::cout << "generating code for call to " << callable->ReadableName()
              << "\n";
1927 1928
  }

1929
  size_t label_count = callable->signature().labels.size();
1930 1931
  if (label_count != arguments.labels.size()) {
    std::stringstream s;
1932 1933 1934
    s << "unexpected number of otherwise labels for "
      << callable->ReadableName() << " (expected "
      << std::to_string(label_count) << " found "
1935
      << std::to_string(arguments.labels.size()) << ")";
1936 1937
    ReportError(s.str());
  }
1938

1939
  if (callable->IsTransitioning()) {
1940
    if (!CurrentCallable::Get()->IsTransitioning()) {
1941
      std::stringstream s;
1942
      s << *CurrentCallable::Get()
1943 1944 1945 1946 1947 1948
        << " isn't marked transitioning but calls the transitioning "
        << *callable;
      ReportError(s.str());
    }
  }

1949
  if (auto* builtin = Builtin::DynamicCast(callable)) {
1950 1951 1952 1953
    base::Optional<Block*> catch_block = GetCatchBlock();
    assembler().Emit(CallBuiltinInstruction{
        is_tailcall, builtin, argument_range.Size(), catch_block});
    GenerateCatchBlock(catch_block);
1954 1955 1956 1957 1958 1959 1960 1961
    if (is_tailcall) {
      return VisitResult::NeverResult();
    } else {
      size_t slot_count = LoweredSlotCount(return_type);
      DCHECK_LE(slot_count, 1);
      // TODO(tebbi): Actually, builtins have to return a value, so we should
      // assert slot_count == 1 here.
      return VisitResult(return_type, assembler().TopRange(slot_count));
1962
    }
1963 1964 1965
  } else if (auto* macro = Macro::DynamicCast(callable)) {
    if (is_tailcall) {
      ReportError("can't tail call a macro");
1966
    }
1967 1968 1969
    if (return_type->IsConstexpr()) {
      DCHECK_EQ(0, arguments.labels.size());
      std::stringstream result;
1970
      result << "(" << macro->external_assembler_name() << "(state_)."
1971
             << macro->ExternalName() << "(";
1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982
      bool first = true;
      for (VisitResult arg : arguments.parameters) {
        DCHECK(!arg.IsOnStack());
        if (!first) {
          result << ", ";
        }
        first = false;
        result << arg.constexpr_value();
      }
      result << "))";
      return VisitResult(return_type, result.str());
1983 1984 1985 1986 1987
    } else if (macro->ShouldBeInlined()) {
      std::vector<Block*> label_blocks;
      for (Binding<LocalLabel>* label : arguments.labels) {
        label_blocks.push_back(label->block);
      }
1988 1989
      return InlineMacro(macro, this_reference, converted_arguments,
                         label_blocks);
1990 1991
    } else if (arguments.labels.empty() &&
               return_type != TypeOracle::GetNeverType()) {
1992 1993 1994 1995
      base::Optional<Block*> catch_block = GetCatchBlock();
      assembler().Emit(
          CallCsaMacroInstruction{macro, constexpr_arguments, catch_block});
      GenerateCatchBlock(catch_block);
1996 1997 1998 1999 2000 2001
      size_t return_slot_count = LoweredSlotCount(return_type);
      return VisitResult(return_type, assembler().TopRange(return_slot_count));
    } else {
      base::Optional<Block*> return_continuation;
      if (return_type != TypeOracle::GetNeverType()) {
        return_continuation = assembler().NewBlock();
2002 2003
      }

2004 2005 2006 2007 2008
      std::vector<Block*> label_blocks;

      for (size_t i = 0; i < label_count; ++i) {
        label_blocks.push_back(assembler().NewBlock());
      }
2009
      base::Optional<Block*> catch_block = GetCatchBlock();
2010
      assembler().Emit(CallCsaMacroAndBranchInstruction{
2011 2012 2013
          macro, constexpr_arguments, return_continuation, label_blocks,
          catch_block});
      GenerateCatchBlock(catch_block);
2014 2015

      for (size_t i = 0; i < label_count; ++i) {
2016
        Binding<LocalLabel>* label = arguments.labels[i];
2017 2018
        size_t callee_label_parameters =
            callable->signature().labels[i].types.size();
2019
        if (label->parameter_types.size() != callee_label_parameters) {
2020 2021 2022
          std::stringstream s;
          s << "label " << label->name()
            << " doesn't have the right number of parameters (found "
2023
            << std::to_string(label->parameter_types.size()) << " expected "
2024 2025 2026 2027 2028
            << std::to_string(callee_label_parameters) << ")";
          ReportError(s.str());
        }
        assembler().Bind(label_blocks[i]);
        assembler().Goto(
2029
            label->block,
2030 2031 2032 2033
            LowerParameterTypes(callable->signature().labels[i].types).size());

        size_t j = 0;
        for (auto t : callable->signature().labels[i].types) {
2034 2035 2036 2037
          const Type* parameter_type = label->parameter_types[j];
          if (parameter_type != t) {
            ReportError("mismatch of label parameters (expected ", *t, " got ",
                        parameter_type, " for parameter ", i + 1, ")");
2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052
          }
          j++;
        }
      }

      if (return_continuation) {
        assembler().Bind(*return_continuation);
        size_t return_slot_count = LoweredSlotCount(return_type);
        return VisitResult(return_type,
                           assembler().TopRange(return_slot_count));
      } else {
        return VisitResult::NeverResult();
      }
    }
  } else if (auto* runtime_function = RuntimeFunction::DynamicCast(callable)) {
2053 2054 2055 2056
    base::Optional<Block*> catch_block = GetCatchBlock();
    assembler().Emit(CallRuntimeInstruction{
        is_tailcall, runtime_function, argument_range.Size(), catch_block});
    GenerateCatchBlock(catch_block);
2057
    if (is_tailcall || return_type == TypeOracle::GetNeverType()) {
2058 2059 2060 2061 2062 2063 2064 2065
      return VisitResult::NeverResult();
    } else {
      size_t slot_count = LoweredSlotCount(return_type);
      DCHECK_LE(slot_count, 1);
      // TODO(tebbi): Actually, runtime functions have to return a value, so
      // we should assert slot_count == 1 here.
      return VisitResult(return_type, assembler().TopRange(slot_count));
    }
2066
  } else if (auto* intrinsic = Intrinsic::DynamicCast(callable)) {
2067 2068 2069 2070 2071 2072 2073
    if (intrinsic->ExternalName() == "%RawConstexprCast") {
      if (intrinsic->signature().parameter_types.types.size() != 1 ||
          constexpr_arguments.size() != 1) {
        ReportError(
            "%RawConstexprCast must take a single parameter with constexpr "
            "type");
      }
2074 2075 2076 2077 2078 2079
      if (!return_type->IsConstexpr()) {
        std::stringstream s;
        s << *return_type
          << " return type for %RawConstexprCast is not constexpr";
        ReportError(s.str());
      }
2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091
      std::stringstream result;
      result << "static_cast<" << return_type->GetGeneratedTypeName() << ">(";
      result << constexpr_arguments[0];
      result << ")";
      return VisitResult(return_type, result.str());
    } else {
      assembler().Emit(
          CallIntrinsicInstruction{intrinsic, constexpr_arguments});
      size_t return_slot_count =
          LoweredSlotCount(intrinsic->signature().return_type);
      return VisitResult(return_type, assembler().TopRange(return_slot_count));
    }
2092 2093
  } else {
    UNREACHABLE();
2094 2095 2096
  }
}

2097 2098 2099 2100
VisitResult ImplementationVisitor::GenerateCall(
    const QualifiedName& callable_name, Arguments arguments,
    const TypeVector& specialization_types, bool is_tailcall) {
  Callable* callable =
2101 2102
      LookupCallable(callable_name, Declarations::Lookup(callable_name),
                     arguments, specialization_types);
2103 2104 2105 2106
  return GenerateCall(callable, base::nullopt, arguments, specialization_types,
                      is_tailcall);
}

2107 2108
VisitResult ImplementationVisitor::Visit(CallExpression* expr,
                                         bool is_tailcall) {
2109
  StackScope scope(this);
2110
  Arguments arguments;
2111 2112
  QualifiedName name =
      QualifiedName(expr->callee->namespace_qualification, expr->callee->name);
2113
  TypeVector specialization_types =
2114
      GetTypeVector(expr->callee->generic_arguments);
2115 2116 2117 2118
  bool has_template_arguments = !specialization_types.empty();
  for (Expression* arg : expr->arguments)
    arguments.parameters.push_back(Visit(arg));
  arguments.labels = LabelsFromIdentifiers(expr->labels);
2119 2120
  if (!has_template_arguments && name.namespace_qualification.empty() &&
      TryLookupLocalValue(name.name)) {
2121
    return scope.Yield(
2122
        GeneratePointerCall(expr->callee, arguments, is_tailcall));
2123
  } else {
2124 2125
    return scope.Yield(
        GenerateCall(name, arguments, specialization_types, is_tailcall));
2126 2127 2128
  }
}

2129 2130 2131 2132 2133 2134
VisitResult ImplementationVisitor::Visit(CallMethodExpression* expr) {
  StackScope scope(this);
  Arguments arguments;
  std::string method_name = expr->method->name;
  TypeVector specialization_types =
      GetTypeVector(expr->method->generic_arguments);
2135 2136 2137 2138 2139 2140 2141 2142 2143 2144
  LocationReference target = GetLocationReference(expr->target);
  if (!target.IsVariableAccess()) {
    VisitResult result = GenerateFetchFromLocation(target);
    target = LocationReference::Temporary(result, "method target result");
  }
  const AggregateType* target_type =
      AggregateType::DynamicCast(target.GetVisitResult().type());
  if (!target_type) {
    ReportError("target of method call not a struct or class type");
  }
2145 2146 2147 2148 2149 2150 2151 2152
  if (method_name == kConstructMethodName || method_name == kSuperMethodName) {
    if (CurrentConstructorInfo::Get()) {
      ConstructorInfo& info = *CurrentConstructorInfo::Get();
      if (method_name == kSuperMethodName) {
        if (info.super_calls != 0) {
          ReportError("\"super\" can only be called once from a constructor");
        }
        ++info.super_calls;
2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163
        DCHECK(target_type->IsStructType());
        base::Optional<const ClassType*> derived_from =
            StructType::cast(target_type)->GetDerivedFrom();
        if (!derived_from) {
          ReportError("\"super\" can only be called from class constructors");
        }
        if ((*derived_from)->GetSuperClass() == nullptr) {
          ReportError(
              "\"super\" can only be called in constructors for derived "
              "classes");
        }
2164 2165 2166 2167 2168 2169 2170 2171
      } else {
        ReportError("cannot call a constructor from a constructor");
      }
    } else {
      ReportError(
          "cannot call a constructor or \"super\" from a non-constructor");
    }
  }
2172
  for (Expression* arg : expr->arguments) {
2173
    arguments.parameters.push_back(Visit(arg));
2174
  }
2175 2176 2177 2178 2179 2180
  arguments.labels = LabelsFromIdentifiers(expr->labels);
  TypeVector argument_types = arguments.parameters.GetTypeVector();
  DCHECK_EQ(expr->method->namespace_qualification.size(), 0);
  QualifiedName qualified_name = QualifiedName(method_name);
  Callable* callable = nullptr;
  if (method_name == kConstructMethodName) {
2181
    callable = LookupConstructor(target, arguments, {});
2182
  } else if (method_name == kSuperMethodName) {
2183 2184 2185 2186 2187 2188 2189
    LocationReference super_this =
        LocationReference::VariableAccess(ProjectStructField(
            target.GetVisitResult(), kConstructorStructSuperFieldName));
    callable = LookupConstructor(super_this, arguments, {});
    VisitResult super_result =
        GenerateCall(callable, super_this, arguments, {}, false);
    return scope.Yield(super_result);
2190
  } else {
2191
    callable = LookupMethod(method_name, target, arguments, {});
2192 2193 2194 2195
  }
  return scope.Yield(GenerateCall(callable, target, arguments, {}, false));
}

2196
VisitResult ImplementationVisitor::Visit(LoadObjectFieldExpression* expr) {
2197 2198
  VisitResult base_result = Visit(expr->base);
  auto class_type = ClassType::DynamicCast(base_result.type());
2199 2200 2201 2202
  if (!class_type) {
    ReportError(
        "base expression for a LoadObjectFieldExpression is not a class type "
        "but instead ",
2203
        *base_result.type());
2204
  }
2205
  VisitResult result = base_result;
2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225
  assembler().Emit(LoadObjectFieldInstruction{class_type, expr->field_name});
  const Field& field = class_type->LookupField(expr->field_name);
  result.SetType(field.name_and_type.type);
  return result;
}

VisitResult ImplementationVisitor::Visit(StoreObjectFieldExpression* expr) {
  VisitResult base_result = Visit(expr->base);
  auto class_type = ClassType::DynamicCast(base_result.type());
  if (!class_type) {
    ReportError(
        "base expression for a StoreObjectFieldExpression is not a class type "
        "but instead ",
        *base_result.type());
  }
  VisitResult value = Visit(expr->value);
  assembler().Emit(StoreObjectFieldInstruction{class_type, expr->field_name});
  return VisitResult(value.type(), assembler().TopRange(0));
}

2226 2227 2228 2229 2230 2231 2232 2233 2234 2235
VisitResult ImplementationVisitor::Visit(IntrinsicCallExpression* expr) {
  StackScope scope(this);
  Arguments arguments;
  TypeVector specialization_types = GetTypeVector(expr->generic_arguments);
  for (Expression* arg : expr->arguments)
    arguments.parameters.push_back(Visit(arg));
  return scope.Yield(
      GenerateCall(expr->name, arguments, specialization_types, false));
}

2236
void ImplementationVisitor::GenerateBranch(const VisitResult& condition,
2237 2238
                                           Block* true_block,
                                           Block* false_block) {
2239 2240
  DCHECK_EQ(condition,
            VisitResult(TypeOracle::GetBoolType(), assembler().TopRange(1)));
2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257
  assembler().Branch(true_block, false_block);
}

void ImplementationVisitor::GenerateExpressionBranch(Expression* expression,
                                                     Block* true_block,
                                                     Block* false_block) {
  // Conditional expressions can either explicitly return a bit
  // type, or they can be backed by macros that don't return but
  // take a true and false label. By declaring the labels before
  // visiting the conditional expression, those label-based
  // macro conditionals will be able to find them through normal
  // label lookups.
  Binding<LocalLabel> true_binding{&LabelBindingsManager::Get(), kTrueLabelName,
                                   LocalLabel{true_block}};
  Binding<LocalLabel> false_binding{&LabelBindingsManager::Get(),
                                    kFalseLabelName, LocalLabel{false_block}};
  StackScope stack_scope(this);
2258
  VisitResult expression_result = Visit(expression);
2259 2260 2261 2262
  if (!expression_result.type()->IsNever()) {
    expression_result = stack_scope.Yield(
        GenerateImplicitConvert(TypeOracle::GetBoolType(), expression_result));
    GenerateBranch(expression_result, true_block, false_block);
2263 2264 2265 2266
  }
}

VisitResult ImplementationVisitor::GenerateImplicitConvert(
2267
    const Type* destination_type, VisitResult source) {
2268
  StackScope scope(this);
2269 2270 2271 2272
  if (source.type() == TypeOracle::GetNeverType()) {
    ReportError("it is not allowed to use a value of type never");
  }

2273
  if (destination_type == source.type()) {
2274
    return scope.Yield(GenerateCopy(source));
2275
  }
2276

2277 2278
  if (TypeOracle::IsImplicitlyConvertableFrom(destination_type,
                                              source.type())) {
2279
    return scope.Yield(GenerateCall(kFromConstexprMacroName, {{source}, {}},
2280
                                    {destination_type, source.type()}, false));
2281
  } else if (IsAssignableFrom(destination_type, source.type())) {
2282
    source.SetType(destination_type);
2283
    return scope.Yield(GenerateCopy(source));
2284 2285
  } else {
    std::stringstream s;
2286 2287
    s << "cannot use expression of type " << *source.type()
      << " as a value of type " << *destination_type;
2288 2289 2290 2291
    ReportError(s.str());
  }
}

2292
StackRange ImplementationVisitor::GenerateLabelGoto(
2293 2294
    LocalLabel* label, base::Optional<StackRange> arguments) {
  return assembler().Goto(label->block, arguments ? arguments->Size() : 0);
2295 2296
}

2297
std::vector<Binding<LocalLabel>*> ImplementationVisitor::LabelsFromIdentifiers(
2298
    const std::vector<std::string>& names) {
2299
  std::vector<Binding<LocalLabel>*> result;
2300
  result.reserve(names.size());
2301
  for (const auto& name : names) {
2302
    result.push_back(LookupLabel(name));
2303 2304 2305 2306
  }
  return result;
}

2307 2308 2309
StackRange ImplementationVisitor::LowerParameter(
    const Type* type, const std::string& parameter_name,
    Stack<std::string>* lowered_parameters) {
2310
  if (const StructType* struct_type = StructType::DynamicCast(type)) {
2311 2312 2313
    StackRange range = lowered_parameters->TopRange(0);
    for (auto& field : struct_type->fields()) {
      StackRange parameter_range = LowerParameter(
2314 2315
          field.name_and_type.type,
          parameter_name + "." + field.name_and_type.name, lowered_parameters);
2316 2317 2318 2319 2320 2321 2322 2323 2324
      range.Extend(parameter_range);
    }
    return range;
  } else {
    lowered_parameters->Push(parameter_name);
    return lowered_parameters->TopRange(1);
  }
}

2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341
std::string ImplementationVisitor::ExternalLabelName(
    const std::string& label_name) {
  return "label_" + label_name;
}

std::string ImplementationVisitor::ExternalLabelParameterName(
    const std::string& label_name, size_t i) {
  return "label_" + label_name + "_parameter_" + std::to_string(i);
}

std::string ImplementationVisitor::ExternalParameterName(
    const std::string& name) {
  return std::string("p_") + name;
}

DEFINE_CONTEXTUAL_VARIABLE(ImplementationVisitor::ValueBindingsManager);
DEFINE_CONTEXTUAL_VARIABLE(ImplementationVisitor::LabelBindingsManager);
2342
DEFINE_CONTEXTUAL_VARIABLE(ImplementationVisitor::CurrentCallable);
2343
DEFINE_CONTEXTUAL_VARIABLE(ImplementationVisitor::CurrentReturnValue);
2344
DEFINE_CONTEXTUAL_VARIABLE(ImplementationVisitor::CurrentConstructorInfo);
2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364

bool IsCompatibleSignature(const Signature& sig, const TypeVector& types,
                           const std::vector<Binding<LocalLabel>*>& labels) {
  auto i = sig.parameter_types.types.begin() + sig.implicit_count;
  if ((sig.parameter_types.types.size() - sig.implicit_count) > types.size())
    return false;
  // TODO(danno): The test below is actually insufficient. The labels'
  // parameters must be checked too. ideally, the named part of
  // LabelDeclarationVector would be factored out so that the label count and
  // parameter types could be passed separately.
  if (sig.labels.size() != labels.size()) return false;
  for (auto current : types) {
    if (i == sig.parameter_types.types.end()) {
      if (!sig.parameter_types.var_args) return false;
      if (!IsAssignableFrom(TypeOracle::GetObjectType(), current)) return false;
    } else {
      if (!IsAssignableFrom(*i++, current)) return false;
    }
  }
  return true;
2365 2366
}

2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390
base::Optional<Block*> ImplementationVisitor::GetCatchBlock() {
  base::Optional<Block*> catch_block;
  if (base::Optional<Binding<LocalLabel>*> catch_handler =
          TryLookupLabel("_catch")) {
    catch_block = assembler().NewBlock(base::nullopt, true);
  }
  return catch_block;
}

void ImplementationVisitor::GenerateCatchBlock(
    base::Optional<Block*> catch_block) {
  if (catch_block) {
    base::Optional<Binding<LocalLabel>*> catch_handler =
        TryLookupLabel("_catch");
    if (assembler().CurrentBlockIsComplete()) {
      assembler().Bind(*catch_block);
      assembler().Goto((*catch_handler)->block, 1);
    } else {
      CfgAssemblerScopedTemporaryBlock temp(&assembler(), *catch_block);
      assembler().Goto((*catch_handler)->block, 1);
    }
  }
}

2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401
void ImplementationVisitor::VisitAllDeclarables() {
  const std::vector<std::unique_ptr<Declarable>>& all_declarables =
      GlobalContext::AllDeclarables();
  // This has to be an index-based loop because all_declarables can be extended
  // during the loop.
  for (size_t i = 0; i < all_declarables.size(); ++i) {
    Visit(all_declarables[i].get());
  }
}

void ImplementationVisitor::Visit(Declarable* declarable) {
2402
  CurrentConstructorInfo::Scope current_constructor(base::nullopt);
2403 2404 2405 2406 2407
  CurrentScope::Scope current_scope(declarable->ParentScope());
  CurrentSourcePosition::Scope current_source_position(declarable->pos());
  switch (declarable->kind()) {
    case Declarable::kMacro:
      return Visit(Macro::cast(declarable));
2408 2409
    case Declarable::kMethod:
      return Visit(Method::cast(declarable));
2410 2411 2412 2413
    case Declarable::kBuiltin:
      return Visit(Builtin::cast(declarable));
    case Declarable::kTypeAlias:
      return Visit(TypeAlias::cast(declarable));
2414 2415
    case Declarable::kNamespaceConstant:
      return Visit(NamespaceConstant::cast(declarable));
2416
    case Declarable::kRuntimeFunction:
2417
    case Declarable::kIntrinsic:
2418
    case Declarable::kExternConstant:
2419
    case Declarable::kNamespace:
2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438
    case Declarable::kGeneric:
      return;
  }
}

void ImplementationVisitor::GenerateBuiltinDefinitions(std::string& file_name) {
  std::stringstream new_contents_stream;
  new_contents_stream
      << "#ifndef V8_BUILTINS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n"
         "#define V8_BUILTINS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n"
         "\n"
         "#define BUILTIN_LIST_FROM_DSL(CPP, API, TFJ, TFC, TFS, TFH, ASM) "
         "\\\n";
  for (auto& declarable : GlobalContext::AllDeclarables()) {
    Builtin* builtin = Builtin::DynamicCast(declarable.get());
    if (!builtin || builtin->IsExternal()) continue;
    int firstParameterIndex = 1;
    bool declareParameters = true;
    if (builtin->IsStub()) {
2439
      new_contents_stream << "TFS(" << builtin->ExternalName();
2440
    } else {
2441
      new_contents_stream << "TFJ(" << builtin->ExternalName();
2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471
      if (builtin->IsVarArgsJavaScript()) {
        new_contents_stream
            << ", SharedFunctionInfo::kDontAdaptArgumentsSentinel";
        declareParameters = false;
      } else {
        assert(builtin->IsFixedArgsJavaScript());
        // FixedArg javascript builtins need to offer the parameter
        // count.
        assert(builtin->parameter_names().size() >= 2);
        new_contents_stream << ", " << (builtin->parameter_names().size() - 2);
        // And the receiver is explicitly declared.
        new_contents_stream << ", kReceiver";
        firstParameterIndex = 2;
      }
    }
    if (declareParameters) {
      int index = 0;
      for (const auto& parameter : builtin->parameter_names()) {
        if (index >= firstParameterIndex) {
          new_contents_stream << ", k" << CamelifyString(parameter);
        }
        index++;
      }
    }
    new_contents_stream << ") \\\n";
  }
  new_contents_stream << "\n";

  new_contents_stream
      << "#define TORQUE_FUNCTION_POINTER_TYPE_TO_BUILTIN_MAP(V) \\\n";
2472
  for (const BuiltinPointerType* type : TypeOracle::AllBuiltinPointerTypes()) {
2473 2474 2475 2476 2477 2478 2479 2480
    Builtin* example_builtin =
        Declarations::FindSomeInternalBuiltinWithType(type);
    if (!example_builtin) {
      CurrentSourcePosition::Scope current_source_position(
          SourcePosition{CurrentSourceFile::Get(), -1, -1});
      ReportError("unable to find any builtin with type \"", *type, "\"");
    }
    new_contents_stream << "  V(" << type->function_pointer_type_id() << ","
2481
                        << example_builtin->ExternalName() << ")\\\n";
2482 2483 2484 2485 2486 2487 2488 2489 2490 2491
  }
  new_contents_stream << "\n";

  new_contents_stream
      << "#endif  // V8_BUILTINS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n";

  std::string new_contents(new_contents_stream.str());
  ReplaceFileContentsIfDifferent(file_name, new_contents);
}

2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535
void ImplementationVisitor::GenerateClassDefinitions(std::string& file_name) {
  std::stringstream new_contents_stream;
  new_contents_stream << "#ifndef V8_CLASS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n"
                         "#define V8_CLASS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n"
                         "\n\n";

  for (auto i : GlobalContext::GetClasses()) {
    // TODO(danno): Ideally (and we've got several core V8 dev's feedback
    // supporting this), Torque should generate the constants for the offsets
    // directly and not go through the existing layer of macros, which actually
    // currently just serves to additionally obfuscate where these values come
    // from.
    new_contents_stream << "#define ";
    new_contents_stream << CapifyStringWithUnderscores(i.first)
                        << "_FIELDS(V) \\\n";
    const ClassType* type = i.second;
    std::vector<Field> fields = type->fields();
    new_contents_stream << "V(kStartOfStrongFieldsOffset, 0) \\\n";
    for (auto f : fields) {
      if (!f.is_weak) {
        new_contents_stream << "V(k" << CamelifyString(f.name_and_type.name)
                            << "Offset, kTaggedSize) \\\n";
      }
    }
    new_contents_stream << "V(kEndOfStrongFieldsOffset, 0) \\\n";
    new_contents_stream << "V(kStartOfWeakFieldsOffset, 0) \\\n";
    for (auto f : fields) {
      if (f.is_weak) {
        new_contents_stream << "V(k" << CamelifyString(f.name_and_type.name)
                            << "Offset, kTaggedSize) \\\n";
      }
    }
    new_contents_stream << "V(kEndOfWeakFieldsOffset, 0) \\\n";
    new_contents_stream << "V(kSize, 0) \\\n";
    new_contents_stream << "\n";
  }

  new_contents_stream
      << "\n#endif  // V8_CLASS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n";

  std::string new_contents(new_contents_stream.str());
  ReplaceFileContentsIfDifferent(file_name, new_contents);
}

2536 2537 2538
}  // namespace torque
}  // namespace internal
}  // namespace v8