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" 16 VisitResult ImplementationVisitor::Visit(Expression* expr) {
17 CurrentSourcePosition::Scope scope(expr->pos);
19 #define ENUM_ITEM(name) \ 20 case AstNode::Kind::k##name: \ 21 return Visit(name::cast(expr)); 22 AST_EXPRESSION_NODE_KIND_LIST(ENUM_ITEM)
29 const Type* ImplementationVisitor::Visit(Statement* stmt) {
30 CurrentSourcePosition::Scope scope(stmt->pos);
31 StackScope stack_scope(
this);
34 #define ENUM_ITEM(name) \ 35 case AstNode::Kind::k##name: \ 36 result = Visit(name::cast(stmt)); \ 38 AST_STATEMENT_NODE_KIND_LIST(ENUM_ITEM)
43 DCHECK_EQ(result == TypeOracle::GetNeverType(),
44 assembler().CurrentBlockIsComplete());
48 void ImplementationVisitor::BeginNamespaceFile(Namespace* nspace) {
49 std::ostream& source = nspace->source_stream();
50 std::ostream& header = nspace->header_stream();
52 source <<
"#include \"src/objects/arguments.h\"\n";
53 source <<
"#include \"src/builtins/builtins-utils-gen.h\"\n";
54 source <<
"#include \"src/builtins/builtins.h\"\n";
55 source <<
"#include \"src/code-factory.h\"\n";
56 source <<
"#include \"src/elements-kind.h\"\n";
57 source <<
"#include \"src/heap/factory-inl.h\"\n";
58 source <<
"#include \"src/objects.h\"\n";
59 source <<
"#include \"src/objects/bigint.h\"\n";
61 for (Namespace* n : GlobalContext::Get().GetNamespaces()) {
62 source <<
"#include \"torque-generated/builtins-" +
63 DashifyString(n->name()) +
"-from-dsl-gen.h\"\n";
64 if (n != GlobalContext::GetDefaultNamespace()) {
65 source <<
"#include \"src/builtins/builtins-" + DashifyString(n->name()) +
71 source <<
"namespace v8 {\n" 72 <<
"namespace internal {\n" 75 std::string upper_name(nspace->name());
76 transform(upper_name.begin(), upper_name.end(), upper_name.begin(),
78 std::string headerDefine =
79 std::string(
"V8_TORQUE_") + upper_name +
"_FROM_DSL_BASE_H__";
80 header <<
"#ifndef " << headerDefine <<
"\n";
81 header <<
"#define " << headerDefine <<
"\n\n";
82 header <<
"#include \"src/compiler/code-assembler.h\"\n";
83 if (nspace != GlobalContext::GetDefaultNamespace()) {
84 header <<
"#include \"src/code-stub-assembler.h\"\n";
88 header <<
"namespace v8 {\n" 89 <<
"namespace internal {\n" 92 header <<
"class " << nspace->ExternalName() <<
" {\n";
93 header <<
" public:\n";
94 header <<
" explicit " << nspace->ExternalName()
95 <<
"(compiler::CodeAssemblerState* state) : state_(state), ca_(state) " 96 "{ USE(state_, ca_); }\n";
99 void ImplementationVisitor::EndNamespaceFile(Namespace* nspace) {
100 std::ostream& source = nspace->source_stream();
101 std::ostream& header = nspace->header_stream();
103 std::string upper_name(nspace->name());
104 transform(upper_name.begin(), upper_name.end(), upper_name.begin(),
106 std::string headerDefine =
107 std::string(
"V8_TORQUE_") + upper_name +
"_FROM_DSL_BASE_H__";
109 source <<
"} // namespace internal\n" 110 <<
"} // namespace v8\n" 113 header <<
" private:\n" 114 <<
" compiler::CodeAssemblerState* const state_;\n" 115 <<
" compiler::CodeAssembler ca_;" 117 header <<
"} // namespace internal\n" 118 <<
"} // namespace v8\n" 120 header <<
"#endif // " << headerDefine <<
"\n";
123 void ImplementationVisitor::Visit(NamespaceConstant* decl) {
124 Signature signature{{}, base::nullopt, {{},
false}, 0, decl->type(), {}};
125 const std::string& name = decl->name();
127 BindingsManagersScope bindings_managers_scope;
130 GenerateFunctionDeclaration(header_out(),
"", name, signature, {});
131 header_out() <<
";\n";
133 GenerateFunctionDeclaration(source_out(),
134 CurrentNamespace()->ExternalName() +
"::", name,
136 source_out() <<
" {\n";
138 DCHECK(!signature.return_type->IsVoidOrNever());
140 assembler_ = CfgAssembler(Stack<const Type*>{});
142 VisitResult expression_result = Visit(decl->body());
143 VisitResult return_result =
144 GenerateImplicitConvert(signature.return_type, expression_result);
146 CSAGenerator csa_generator{assembler().Result(), source_out()};
147 Stack<std::string> values = *csa_generator.EmitGraph(Stack<std::string>{});
149 assembler_ = base::nullopt;
151 source_out() <<
"return ";
152 CSAGenerator::EmitCSAValue(return_result, values, source_out());
153 source_out() <<
";\n";
154 source_out() <<
"}\n\n";
157 void ImplementationVisitor::Visit(TypeAlias* alias) {
158 if (alias->IsRedeclaration())
return;
159 const StructType* struct_type = StructType::DynamicCast(alias->type());
160 if (!struct_type)
return;
161 const std::string& name = struct_type->name();
162 header_out() <<
" struct " << name <<
" {\n";
163 for (
auto& field : struct_type->fields()) {
164 header_out() <<
" " << field.type->GetGeneratedTypeName();
165 header_out() <<
" " << field.name <<
";\n";
167 header_out() <<
"\n std::tuple<";
169 for (
const Type* type : LowerType(struct_type)) {
171 header_out() <<
", ";
174 header_out() << type->GetGeneratedTypeName();
176 header_out() <<
"> Flatten() const {\n" 177 <<
" return std::tuple_cat(";
179 for (
auto& field : struct_type->fields()) {
181 header_out() <<
", ";
184 if (field.type->IsStructType()) {
185 header_out() << field.name <<
".Flatten()";
187 header_out() <<
"std::make_tuple(" << field.name <<
")";
190 header_out() <<
");\n";
191 header_out() <<
" }\n";
192 header_out() <<
" };\n";
195 void ImplementationVisitor::Visit(Macro* macro) {
196 if (macro->IsExternal())
return;
197 CurrentScope::Scope current_scope(macro);
198 const Signature& signature = macro->signature();
199 const Type* return_type = macro->signature().return_type;
200 bool can_return = return_type != TypeOracle::GetNeverType();
201 bool has_return_value =
202 can_return && return_type != TypeOracle::GetVoidType();
204 CurrentCallable::Scope current_callable(macro);
207 GenerateMacroFunctionDeclaration(header_out(),
"", macro);
208 header_out() <<
";\n";
210 GenerateMacroFunctionDeclaration(
211 source_out(), CurrentNamespace()->ExternalName() +
"::", macro);
212 source_out() <<
" {\n";
214 Stack<std::string> lowered_parameters;
215 Stack<const Type*> lowered_parameter_types;
217 BindingsManagersScope bindings_managers_scope;
219 BlockBindings<LocalValue> parameter_bindings(&ValueBindingsManager::Get());
220 for (
size_t i = 0;
i < macro->signature().parameter_names.size(); ++
i) {
221 const std::string& name = macro->parameter_names()[
i];
222 std::string external_name = GetParameterVariableFromName(name);
223 const Type* type = macro->signature().types()[
i];
224 if (type->IsConstexpr()) {
225 parameter_bindings.Add(
226 name, LocalValue{
true, VisitResult(type, external_name)});
228 LowerParameter(type, external_name, &lowered_parameters);
229 StackRange range = lowered_parameter_types.PushMany(LowerType(type));
230 parameter_bindings.Add(name, LocalValue{
true, VisitResult(type, range)});
234 DCHECK_EQ(lowered_parameters.Size(), lowered_parameter_types.Size());
235 assembler_ = CfgAssembler(lowered_parameter_types);
237 BlockBindings<LocalLabel> label_bindings(&LabelBindingsManager::Get());
238 for (
const LabelDeclaration& label_info : signature.labels) {
239 Stack<const Type*> label_input_stack;
240 for (
const Type* type : label_info.types) {
241 label_input_stack.PushMany(LowerType(type));
243 Block* block = assembler().NewBlock(std::move(label_input_stack));
244 label_bindings.Add(label_info.name, LocalLabel{block, label_info.types});
248 base::Optional<Binding<LocalLabel>> macro_end_binding;
250 macro_end = assembler().NewBlock(
251 Stack<const Type*>{LowerType(signature.return_type)});
252 macro_end_binding.emplace(&LabelBindingsManager::Get(),
"_macro_end",
253 LocalLabel{macro_end, {signature.return_type}});
256 const Type* result = Visit(*macro->body());
258 if (result->IsNever()) {
259 if (!macro->signature().return_type->IsNever() && !macro->HasReturns()) {
261 s <<
"macro " << macro->ReadableName()
262 <<
" that never returns must have return type never";
263 ReportError(s.str());
266 if (macro->signature().return_type->IsNever()) {
268 s <<
"macro " << macro->ReadableName()
269 <<
" has implicit return at end of its declartion but return type " 271 ReportError(s.str());
272 }
else if (!macro->signature().return_type->IsVoid()) {
274 s <<
"macro " << macro->ReadableName()
275 <<
" expects to return a value but doesn't on all paths";
276 ReportError(s.str());
279 if (!result->IsNever()) {
280 assembler().Goto(macro_end);
283 for (
auto* label_binding : label_bindings.bindings()) {
284 assembler().Bind(label_binding->block);
285 std::vector<std::string> label_parameter_variables;
286 for (
size_t i = 0;
i < label_binding->parameter_types.size(); ++
i) {
287 label_parameter_variables.push_back(
288 ExternalLabelParameterName(label_binding->name(),
i));
290 assembler().Emit(GotoExternalInstruction{
291 ExternalLabelName(label_binding->name()), label_parameter_variables});
294 if (macro->HasReturns() || !result->IsNever()) {
295 assembler().Bind(macro_end);
298 CSAGenerator csa_generator{assembler().Result(), source_out()};
299 base::Optional<Stack<std::string>> values =
300 csa_generator.EmitGraph(lowered_parameters);
302 assembler_ = base::nullopt;
304 if (has_return_value) {
305 source_out() <<
" return ";
306 CSAGenerator::EmitCSAValue(GetAndClearReturnValue(), *values, source_out());
307 source_out() <<
";\n";
309 source_out() <<
"}\n\n";
314 std::string AddParameter(
size_t i, Builtin* builtin,
315 Stack<std::string>* parameters,
316 Stack<const Type*>* parameter_types,
317 BlockBindings<LocalValue>* parameter_bindings) {
318 const std::string& name = builtin->signature().parameter_names[
i];
319 const Type* type = builtin->signature().types()[
i];
320 std::string external_name =
"parameter" + std::to_string(
i);
321 parameters->Push(external_name);
322 StackRange range = parameter_types->PushMany(LowerType(type));
323 parameter_bindings->Add(name, LocalValue{
true, VisitResult(type, range)});
324 return external_name;
329 void ImplementationVisitor::Visit(Builtin* builtin) {
330 if (builtin->IsExternal())
return;
331 CurrentScope::Scope current_scope(builtin);
332 const std::string& name = builtin->ExternalName();
333 const Signature& signature = builtin->signature();
334 source_out() <<
"TF_BUILTIN(" << name <<
", CodeStubAssembler) {\n" 335 <<
" compiler::CodeAssemblerState* state_ = state();" 336 <<
" compiler::CodeAssembler ca_(state());\n";
338 CurrentCallable::Scope current_callable(builtin);
340 Stack<const Type*> parameter_types;
341 Stack<std::string> parameters;
343 BindingsManagersScope bindings_managers_scope;
345 BlockBindings<LocalValue> parameter_bindings(&ValueBindingsManager::Get());
348 std::string parameter0 = AddParameter(0, builtin, ¶meters,
349 ¶meter_types, ¶meter_bindings);
350 source_out() <<
" TNode<Context> " << parameter0
351 <<
" = UncheckedCast<Context>(Parameter(" 352 <<
"Descriptor::kContext));\n";
353 source_out() <<
" USE(" << parameter0 <<
");\n";
356 if (builtin->IsVarArgsJavaScript()) {
357 DCHECK(signature.parameter_types.var_args);
359 <<
" Node* argc = Parameter(Descriptor::kJSActualArgumentsCount);\n";
360 source_out() <<
" CodeStubArguments arguments_impl(this, " 361 "ChangeInt32ToIntPtr(argc));\n";
362 std::string parameter1 = AddParameter(
363 1, builtin, ¶meters, ¶meter_types, ¶meter_bindings);
365 source_out() <<
" TNode<Object> " << parameter1
366 <<
" = arguments_impl.GetReceiver();\n";
367 source_out() <<
"auto " << CSAGenerator::ARGUMENTS_VARIABLE_STRING
368 <<
" = &arguments_impl;\n";
369 source_out() <<
"USE(arguments);\n";
370 source_out() <<
"USE(" << parameter1 <<
");\n";
371 parameter_bindings.Add(
372 *signature.arguments_variable,
374 VisitResult(TypeOracle::GetArgumentsType(),
"arguments")});
378 for (
size_t i = 0;
i < signature.parameter_names.size(); ++
i) {
379 if (
i < first)
continue;
380 const std::string& parameter_name = signature.parameter_names[
i];
381 const Type* type = signature.types()[
i];
382 std::string var = AddParameter(
i, builtin, ¶meters, ¶meter_types,
383 ¶meter_bindings);
384 source_out() <<
" " << type->GetGeneratedTypeName() <<
" " << var <<
" = " 385 <<
"UncheckedCast<" << type->GetGeneratedTNodeTypeName()
386 <<
">(Parameter(Descriptor::k" 387 << CamelifyString(parameter_name) <<
"));\n";
388 source_out() <<
" USE(" << var <<
");\n";
391 assembler_ = CfgAssembler(parameter_types);
392 const Type* body_result = Visit(*builtin->body());
393 if (body_result != TypeOracle::GetNeverType()) {
394 ReportError(
"control reaches end of builtin, expected return of a value");
396 CSAGenerator csa_generator{assembler().Result(), source_out(),
398 csa_generator.EmitGraph(parameters);
399 assembler_ = base::nullopt;
400 source_out() <<
"}\n\n";
403 const Type* ImplementationVisitor::Visit(VarDeclarationStatement* stmt) {
404 BlockBindings<LocalValue> block_bindings(&ValueBindingsManager::Get());
405 return Visit(stmt, &block_bindings);
408 const Type* ImplementationVisitor::Visit(
409 VarDeclarationStatement* stmt, BlockBindings<LocalValue>* block_bindings) {
410 if (!stmt->const_qualified && !stmt->type) {
412 "variable declaration is missing type. Only 'const' bindings can " 416 if (stmt->const_qualified && !stmt->initializer) {
417 ReportError(
"local constant \"", stmt->name,
"\" is not initialized.");
420 base::Optional<const Type*> type;
422 type = Declarations::GetType(*stmt->type);
423 if ((*type)->IsConstexpr() && !stmt->const_qualified) {
425 "cannot declare variable with constexpr type. Use 'const' instead.");
428 base::Optional<VisitResult> init_result;
429 if (stmt->initializer) {
430 StackScope scope(
this);
431 init_result = Visit(*stmt->initializer);
433 init_result = GenerateImplicitConvert(*type, *init_result);
435 init_result = scope.Yield(*init_result);
437 DCHECK(type.has_value());
438 if ((*type)->IsConstexpr()) {
439 ReportError(
"constexpr variables need an initializer");
441 TypeVector lowered_types = LowerType(*type);
442 for (
const Type* type : lowered_types) {
443 assembler().Emit(PushUninitializedInstruction{TypeOracle::GetTopType(
444 "unitialized variable '" + stmt->name +
"' of type " +
445 type->ToString() +
" originally defined at " +
446 PositionAsString(stmt->pos),
450 VisitResult(*type, assembler().TopRange(lowered_types.size()));
452 block_bindings->Add(stmt->name,
453 LocalValue{stmt->const_qualified, *init_result});
454 return TypeOracle::GetVoidType();
457 const Type* ImplementationVisitor::Visit(TailCallStatement* stmt) {
458 return Visit(stmt->call,
true).type();
461 VisitResult ImplementationVisitor::Visit(ConditionalExpression* expr) {
462 Block* true_block = assembler().NewBlock(assembler().CurrentStack());
463 Block* false_block = assembler().NewBlock(assembler().CurrentStack());
464 Block* done_block = assembler().NewBlock();
465 Block* true_conversion_block = assembler().NewBlock();
466 GenerateExpressionBranch(expr->condition, true_block, false_block);
476 assembler().Bind(true_block);
477 StackScope left_scope(
this);
478 left = Visit(expr->if_true);
479 assembler().Goto(true_conversion_block);
481 const Type* common_type;
483 assembler().Bind(false_block);
484 StackScope right_scope(
this);
485 right = Visit(expr->if_false);
486 common_type = GetCommonType(left.type(), right.type());
487 right = right_scope.Yield(GenerateImplicitConvert(common_type, right));
488 assembler().Goto(done_block);
491 assembler().Bind(true_conversion_block);
492 left = left_scope.Yield(GenerateImplicitConvert(common_type, left));
493 assembler().Goto(done_block);
496 assembler().Bind(done_block);
497 CHECK_EQ(left, right);
501 VisitResult ImplementationVisitor::Visit(LogicalOrExpression* expr) {
502 VisitResult left_result;
504 Block* false_block = assembler().NewBlock(assembler().CurrentStack());
505 Binding<LocalLabel> false_binding{&LabelBindingsManager::Get(),
506 kFalseLabelName, LocalLabel{false_block}};
507 left_result = Visit(expr->left);
508 if (left_result.type()->IsBool()) {
509 Block* true_block = LookupSimpleLabel(kTrueLabelName);
510 assembler().Branch(true_block, false_block);
511 assembler().Bind(false_block);
512 }
else if (left_result.type()->IsNever()) {
513 assembler().Bind(false_block);
514 }
else if (!left_result.type()->IsConstexprBool()) {
516 "expected type bool, constexpr bool, or never on left-hand side of " 521 if (left_result.type()->IsConstexprBool()) {
522 VisitResult right_result = Visit(expr->right);
523 if (!right_result.type()->IsConstexprBool()) {
525 "expected type constexpr bool on right-hand side of operator " 528 return VisitResult(TypeOracle::GetConstexprBoolType(),
529 std::string(
"(") + left_result.constexpr_value() +
530 " || " + right_result.constexpr_value() +
")");
533 VisitResult right_result = Visit(expr->right);
534 if (right_result.type()->IsBool()) {
535 Block* true_block = LookupSimpleLabel(kTrueLabelName);
536 Block* false_block = LookupSimpleLabel(kFalseLabelName);
537 assembler().Branch(true_block, false_block);
538 return VisitResult::NeverResult();
539 }
else if (!right_result.type()->IsNever()) {
541 "expected type bool or never on right-hand side of operator ||");
546 VisitResult ImplementationVisitor::Visit(LogicalAndExpression* expr) {
547 VisitResult left_result;
549 Block* true_block = assembler().NewBlock(assembler().CurrentStack());
550 Binding<LocalLabel> false_binding{&LabelBindingsManager::Get(),
551 kTrueLabelName, LocalLabel{true_block}};
552 left_result = Visit(expr->left);
553 if (left_result.type()->IsBool()) {
554 Block* false_block = LookupSimpleLabel(kFalseLabelName);
555 assembler().Branch(true_block, false_block);
556 assembler().Bind(true_block);
557 }
else if (left_result.type()->IsNever()) {
558 assembler().Bind(true_block);
559 }
else if (!left_result.type()->IsConstexprBool()) {
561 "expected type bool, constexpr bool, or never on left-hand side of " 566 if (left_result.type()->IsConstexprBool()) {
567 VisitResult right_result = Visit(expr->right);
568 if (!right_result.type()->IsConstexprBool()) {
570 "expected type constexpr bool on right-hand side of operator " 573 return VisitResult(TypeOracle::GetConstexprBoolType(),
574 std::string(
"(") + left_result.constexpr_value() +
575 " && " + right_result.constexpr_value() +
")");
578 VisitResult right_result = Visit(expr->right);
579 if (right_result.type()->IsBool()) {
580 Block* true_block = LookupSimpleLabel(kTrueLabelName);
581 Block* false_block = LookupSimpleLabel(kFalseLabelName);
582 assembler().Branch(true_block, false_block);
583 return VisitResult::NeverResult();
584 }
else if (!right_result.type()->IsNever()) {
586 "expected type bool or never on right-hand side of operator &&");
591 VisitResult ImplementationVisitor::Visit(IncrementDecrementExpression* expr) {
592 StackScope scope(
this);
593 LocationReference location_ref = GetLocationReference(expr->location);
594 VisitResult current_value = GenerateFetchFromLocation(location_ref);
595 VisitResult one = {TypeOracle::GetConstInt31Type(),
"1"};
597 args.parameters = {current_value, one};
598 VisitResult assignment_value = GenerateCall(
599 expr->op == IncrementDecrementOperator::kIncrement ?
"+" :
"-", args);
600 GenerateAssignToLocation(location_ref, assignment_value);
601 return scope.Yield(expr->postfix ? current_value : assignment_value);
604 VisitResult ImplementationVisitor::Visit(AssignmentExpression* expr) {
605 StackScope scope(
this);
606 LocationReference location_ref = GetLocationReference(expr->location);
607 VisitResult assignment_value;
609 VisitResult location_value = GenerateFetchFromLocation(location_ref);
610 assignment_value = Visit(expr->value);
612 args.parameters = {location_value, assignment_value};
613 assignment_value = GenerateCall(*expr->op, args);
614 GenerateAssignToLocation(location_ref, assignment_value);
616 assignment_value = Visit(expr->value);
617 GenerateAssignToLocation(location_ref, assignment_value);
619 return scope.Yield(assignment_value);
622 VisitResult ImplementationVisitor::Visit(NumberLiteralExpression* expr) {
624 double d = std::stod(expr->number.c_str());
625 int32_t
i =
static_cast<int32_t
>(d);
626 const Type* result_type = Declarations::LookupType(CONST_FLOAT64_TYPE_STRING);
628 if ((
i >> 30) == (
i >> 31)) {
629 result_type = Declarations::LookupType(CONST_INT31_TYPE_STRING);
631 result_type = Declarations::LookupType(CONST_INT32_TYPE_STRING);
634 return VisitResult{result_type, expr->number};
637 VisitResult ImplementationVisitor::Visit(AssumeTypeImpossibleExpression* expr) {
638 VisitResult result = Visit(expr->expression);
639 const Type* result_type =
640 SubtractType(result.type(), Declarations::GetType(expr->excluded_type));
641 if (result_type->IsNever()) {
642 ReportError(
"unreachable code");
644 CHECK_EQ(LowerType(result_type), TypeVector{result_type});
645 assembler().Emit(UnsafeCastInstruction{result_type});
646 result.SetType(result_type);
650 VisitResult ImplementationVisitor::Visit(StringLiteralExpression* expr) {
652 TypeOracle::GetConstStringType(),
653 "\"" + expr->literal.substr(1, expr->literal.size() - 2) +
"\""};
656 VisitResult ImplementationVisitor::GetBuiltinCode(Builtin* builtin) {
657 if (builtin->IsExternal() || builtin->kind() != Builtin::kStub) {
659 "creating function pointers is only allowed for internal builtins with " 662 const Type* type = TypeOracle::GetFunctionPointerType(
663 builtin->signature().parameter_types.types,
664 builtin->signature().return_type);
665 assembler().Emit(PushCodePointerInstruction{builtin->ExternalName(), type});
666 return VisitResult(type, assembler().TopRange(1));
669 VisitResult ImplementationVisitor::Visit(IdentifierExpression* expr) {
670 StackScope scope(
this);
671 return scope.Yield(GenerateFetchFromLocation(GetLocationReference(expr)));
674 const Type* ImplementationVisitor::Visit(GotoStatement* stmt) {
675 LocalLabel* label = LookupLabel(stmt->label);
676 size_t parameter_count = label->parameter_types.size();
677 if (stmt->arguments.size() != parameter_count) {
678 ReportError(
"goto to label has incorrect number of parameters (expected ",
679 parameter_count,
" found ", stmt->arguments.size(),
")");
683 StackRange arguments = assembler().TopRange(0);
684 for (Expression* e : stmt->arguments) {
685 StackScope scope(
this);
686 VisitResult result = Visit(e);
687 const Type* parameter_type = label->parameter_types[
i++];
688 result = GenerateImplicitConvert(parameter_type, result);
689 arguments.Extend(scope.Yield(result).stack_range());
692 assembler().Goto(label->block, arguments.Size());
693 return TypeOracle::GetNeverType();
696 const Type* ImplementationVisitor::Visit(IfStatement* stmt) {
697 bool has_else = stmt->if_false.has_value();
699 if (stmt->is_constexpr) {
700 VisitResult expression_result = Visit(stmt->condition);
702 if (!(expression_result.type() == TypeOracle::GetConstexprBoolType())) {
703 std::stringstream stream;
704 stream <<
"expression should return type constexpr bool " 705 <<
"but returns type " << *expression_result.type();
706 ReportError(stream.str());
709 Block* true_block = assembler().NewBlock();
710 Block* false_block = assembler().NewBlock();
711 Block* done_block = assembler().NewBlock();
713 assembler().Emit(ConstexprBranchInstruction{
714 expression_result.constexpr_value(), true_block, false_block});
716 assembler().Bind(true_block);
717 const Type* left_result = Visit(stmt->if_true);
718 if (left_result == TypeOracle::GetVoidType()) {
719 assembler().Goto(done_block);
722 assembler().Bind(false_block);
723 const Type* right_result = TypeOracle::GetVoidType();
725 right_result = Visit(*stmt->if_false);
727 if (right_result == TypeOracle::GetVoidType()) {
728 assembler().Goto(done_block);
731 if (left_result->IsNever() != right_result->IsNever()) {
732 std::stringstream stream;
733 stream <<
"either both or neither branches in a constexpr if statement " 734 "must reach their end at" 735 << PositionAsString(stmt->pos);
736 ReportError(stream.str());
739 if (left_result != TypeOracle::GetNeverType()) {
740 assembler().Bind(done_block);
744 Block* true_block = assembler().NewBlock(assembler().CurrentStack(),
745 IsDeferred(stmt->if_true));
747 assembler().NewBlock(assembler().CurrentStack(),
748 stmt->if_false && IsDeferred(*stmt->if_false));
749 GenerateExpressionBranch(stmt->condition, true_block, false_block);
754 done_block = assembler().NewBlock();
756 done_block = false_block;
760 assembler().Bind(true_block);
762 const Type* result = Visit(stmt->if_true);
763 if (result == TypeOracle::GetVoidType()) {
765 assembler().Goto(done_block);
770 assembler().Bind(false_block);
771 const Type* result = Visit(*stmt->if_false);
772 if (result == TypeOracle::GetVoidType()) {
774 assembler().Goto(done_block);
779 assembler().Bind(done_block);
781 return live ? TypeOracle::GetVoidType() : TypeOracle::GetNeverType();
785 const Type* ImplementationVisitor::Visit(WhileStatement* stmt) {
786 Block* body_block = assembler().NewBlock(assembler().CurrentStack());
787 Block* exit_block = assembler().NewBlock(assembler().CurrentStack());
789 Block* header_block = assembler().NewBlock();
790 assembler().Goto(header_block);
792 assembler().Bind(header_block);
793 GenerateExpressionBranch(stmt->condition, body_block, exit_block);
795 assembler().Bind(body_block);
797 BreakContinueActivator activator{exit_block, header_block};
798 const Type* body_result = Visit(stmt->body);
799 if (body_result != TypeOracle::GetNeverType()) {
800 assembler().Goto(header_block);
804 assembler().Bind(exit_block);
805 return TypeOracle::GetVoidType();
808 const Type* ImplementationVisitor::Visit(BlockStatement* block) {
809 BlockBindings<LocalValue> block_bindings(&ValueBindingsManager::Get());
810 const Type* type = TypeOracle::GetVoidType();
811 for (Statement* s : block->statements) {
812 CurrentSourcePosition::Scope source_position(s->pos);
813 if (type->IsNever()) {
814 ReportError(
"statement after non-returning statement");
816 if (
auto* var_declaration = VarDeclarationStatement::DynamicCast(s)) {
817 type = Visit(var_declaration, &block_bindings);
825 const Type* ImplementationVisitor::Visit(DebugStatement* stmt) {
827 assembler().Emit(PrintConstantStringInstruction{
"halting because of '" +
828 stmt->reason +
"' at " +
829 PositionAsString(stmt->pos)});
831 assembler().Emit(AbortInstruction{stmt->never_continues
832 ? AbortInstruction::Kind::kUnreachable
833 : AbortInstruction::Kind::kDebugBreak});
834 if (stmt->never_continues) {
835 return TypeOracle::GetNeverType();
837 return TypeOracle::GetVoidType();
843 std::string FormatAssertSource(
const std::string& str) {
845 std::string str_no_newlines = str;
846 std::replace_if(str_no_newlines.begin(), str_no_newlines.end(),
847 [](
unsigned char c) {
return isspace(c); },
' ');
851 std::unique_copy(str_no_newlines.begin(), str_no_newlines.end(),
852 std::back_inserter(result),
853 [](
char a,
char b) {
return a ==
' ' && b ==
' '; });
859 const Type* ImplementationVisitor::Visit(AssertStatement* stmt) {
860 bool do_check = !stmt->debug_only;
874 Block* true_block = assembler().NewBlock(assembler().CurrentStack());
875 Block* false_block = assembler().NewBlock(assembler().CurrentStack(),
true);
876 GenerateExpressionBranch(stmt->expression, true_block, false_block);
878 assembler().Bind(false_block);
880 assembler().Emit(AbortInstruction{
881 AbortInstruction::Kind::kAssertionFailure,
882 "Torque assert '" + FormatAssertSource(stmt->source) +
"' failed"});
884 assembler().Bind(true_block);
886 return TypeOracle::GetVoidType();
889 const Type* ImplementationVisitor::Visit(ExpressionStatement* stmt) {
890 const Type* type = Visit(stmt->expression).type();
891 return type->IsNever() ? type : TypeOracle::GetVoidType();
894 const Type* ImplementationVisitor::Visit(ReturnStatement* stmt) {
895 Callable* current_callable = CurrentCallable::Get();
896 if (current_callable->signature().return_type->IsNever()) {
898 s <<
"cannot return from a function with return type never";
899 ReportError(s.str());
902 current_callable->IsMacro() ? LookupLabel(
"_macro_end") : nullptr;
903 if (current_callable->HasReturnValue()) {
906 s <<
"return expression needs to be specified for a return type of " 907 << *current_callable->signature().return_type;
908 ReportError(s.str());
910 VisitResult expression_result = Visit(*stmt->value);
911 VisitResult return_result = GenerateImplicitConvert(
912 current_callable->signature().return_type, expression_result);
913 if (current_callable->IsMacro()) {
914 if (return_result.IsOnStack()) {
915 StackRange return_value_range =
916 GenerateLabelGoto(end, return_result.stack_range());
917 SetReturnValue(VisitResult(return_result.type(), return_value_range));
919 GenerateLabelGoto(end);
920 SetReturnValue(return_result);
922 }
else if (current_callable->IsBuiltin()) {
923 assembler().Emit(ReturnInstruction{});
930 s <<
"return expression can't be specified for a void or never return " 932 ReportError(s.str());
934 GenerateLabelGoto(end);
936 current_callable->IncrementReturns();
937 return TypeOracle::GetNeverType();
940 const Type* ImplementationVisitor::Visit(ForOfLoopStatement* stmt) {
941 VisitResult expression_result = Visit(stmt->iterable);
942 VisitResult begin = stmt->begin
943 ? Visit(*stmt->begin)
944 : VisitResult(TypeOracle::GetConstInt31Type(),
"0");
946 VisitResult end = stmt->end
948 : GenerateCall(
".length", {{expression_result}, {}});
950 const Type* common_type = GetCommonType(begin.type(), end.type());
951 VisitResult index = GenerateImplicitConvert(common_type, begin);
953 Block* body_block = assembler().NewBlock();
954 Block* increment_block = assembler().NewBlock(assembler().CurrentStack());
955 Block* exit_block = assembler().NewBlock(assembler().CurrentStack());
957 Block* header_block = assembler().NewBlock();
959 assembler().Goto(header_block);
961 assembler().Bind(header_block);
963 BreakContinueActivator activator(exit_block, increment_block);
966 StackScope comparison_scope(
this);
967 VisitResult result = GenerateCall(
"<", {{index, end}, {}});
968 if (result.type() != TypeOracle::GetBoolType()) {
969 ReportError(
"operator < with arguments(", *index.type(),
", ",
971 ") used in for-of loop has to return type bool, but " 975 comparison_scope.Yield(result);
977 assembler().Branch(body_block, exit_block);
979 assembler().Bind(body_block);
981 VisitResult element_result;
983 StackScope element_scope(
this);
984 VisitResult result = GenerateCall(
"[]", {{expression_result, index}, {}});
985 if (stmt->var_declaration->type) {
986 const Type* declared_type =
987 Declarations::GetType(*stmt->var_declaration->type);
988 result = GenerateImplicitConvert(declared_type, result);
990 element_result = element_scope.Yield(result);
992 Binding<LocalValue> element_var_binding{&ValueBindingsManager::Get(),
993 stmt->var_declaration->name,
994 LocalValue{
true, element_result}};
997 assembler().Goto(increment_block);
999 assembler().Bind(increment_block);
1001 Arguments increment_args;
1002 increment_args.parameters = {index, {TypeOracle::GetConstInt31Type(),
"1"}};
1003 VisitResult increment_result = GenerateCall(
"+", increment_args);
1005 GenerateAssignToLocation(LocationReference::VariableAccess(index),
1009 assembler().Goto(header_block);
1011 assembler().Bind(exit_block);
1012 return TypeOracle::GetVoidType();
1015 VisitResult ImplementationVisitor::Visit(TryLabelExpression* expr) {
1016 size_t parameter_count = expr->label_block->parameters.names.size();
1017 std::vector<VisitResult> parameters;
1019 Block* label_block =
nullptr;
1020 Block* done_block = assembler().NewBlock();
1021 VisitResult try_result;
1024 CurrentSourcePosition::Scope source_position(expr->label_block->pos);
1025 if (expr->label_block->parameters.has_varargs) {
1026 ReportError(
"cannot use ... for label parameters");
1028 Stack<const Type*> label_input_stack = assembler().CurrentStack();
1029 TypeVector parameter_types;
1030 for (
size_t i = 0;
i < parameter_count; ++
i) {
1032 Declarations::GetType(expr->label_block->parameters.types[
i]);
1033 parameter_types.push_back(type);
1034 if (type->IsConstexpr()) {
1035 ReportError(
"no constexpr type allowed for label arguments");
1037 StackRange range = label_input_stack.PushMany(LowerType(type));
1038 parameters.push_back(VisitResult(type, range));
1040 label_block = assembler().NewBlock(label_input_stack,
1041 IsDeferred(expr->label_block->body));
1043 Binding<LocalLabel> label_binding{&LabelBindingsManager::Get(),
1044 expr->label_block->label,
1045 LocalLabel{label_block, parameter_types}};
1048 StackScope stack_scope(
this);
1049 try_result = Visit(expr->try_expression);
1050 if (try_result.type() != TypeOracle::GetNeverType()) {
1051 try_result = stack_scope.Yield(try_result);
1052 assembler().Goto(done_block);
1060 assembler().Bind(label_block);
1061 const Type* label_result;
1063 BlockBindings<LocalValue> parameter_bindings(&ValueBindingsManager::Get());
1064 for (
size_t i = 0;
i < parameter_count; ++
i) {
1065 parameter_bindings.Add(expr->label_block->parameters.names[
i],
1066 LocalValue{true, parameters[i]});
1069 label_result = Visit(expr->label_block->body);
1071 if (!try_result.type()->IsVoidOrNever() && label_result->IsVoid()) {
1073 "otherwise clauses cannot fall through in a non-void expression");
1075 if (label_result != TypeOracle::GetNeverType()) {
1076 assembler().Goto(done_block);
1078 if (label_result->IsVoid() && try_result.type()->IsNever()) {
1080 VisitResult(TypeOracle::GetVoidType(), try_result.stack_range());
1083 if (!try_result.type()->IsNever()) {
1084 assembler().Bind(done_block);
1089 VisitResult ImplementationVisitor::Visit(StatementExpression* expr) {
1090 return VisitResult{Visit(expr->statement), assembler().TopRange(0)};
1093 const Type* ImplementationVisitor::Visit(BreakStatement* stmt) {
1094 base::Optional<Binding<LocalLabel>*> break_label = TryLookupLabel(
"_break");
1096 ReportError(
"break used outside of loop");
1098 assembler().Goto((*break_label)->block);
1099 return TypeOracle::GetNeverType();
1102 const Type* ImplementationVisitor::Visit(ContinueStatement* stmt) {
1103 base::Optional<Binding<LocalLabel>*> continue_label =
1104 TryLookupLabel(
"_continue");
1105 if (!continue_label) {
1106 ReportError(
"continue used outside of loop");
1108 assembler().Goto((*continue_label)->block);
1109 return TypeOracle::GetNeverType();
1112 const Type* ImplementationVisitor::Visit(ForLoopStatement* stmt) {
1113 BlockBindings<LocalValue> loop_bindings(&ValueBindingsManager::Get());
1115 if (stmt->var_declaration) Visit(*stmt->var_declaration, &loop_bindings);
1117 Block* body_block = assembler().NewBlock(assembler().CurrentStack());
1118 Block* exit_block = assembler().NewBlock(assembler().CurrentStack());
1120 Block* header_block = assembler().NewBlock();
1121 assembler().Goto(header_block);
1122 assembler().Bind(header_block);
1126 Block* continue_block = header_block;
1129 Block* action_block =
nullptr;
1131 action_block = assembler().NewBlock();
1134 continue_block = action_block;
1138 GenerateExpressionBranch(*stmt->test, body_block, exit_block);
1140 assembler().Goto(body_block);
1143 assembler().Bind(body_block);
1145 BreakContinueActivator activator(exit_block, continue_block);
1146 const Type* body_result = Visit(stmt->body);
1147 if (body_result != TypeOracle::GetNeverType()) {
1148 assembler().Goto(continue_block);
1153 assembler().Bind(action_block);
1154 const Type* action_result = Visit(*stmt->action);
1155 if (action_result != TypeOracle::GetNeverType()) {
1156 assembler().Goto(header_block);
1160 assembler().Bind(exit_block);
1161 return TypeOracle::GetVoidType();
1164 void ImplementationVisitor::GenerateImplementation(
const std::string& dir,
1165 Namespace* nspace) {
1166 std::string new_source(nspace->source());
1167 std::string base_file_name =
1168 "builtins-" + DashifyString(nspace->name()) +
"-from-dsl-gen";
1170 std::string source_file_name = dir +
"/" + base_file_name +
".cc";
1171 ReplaceFileContentsIfDifferent(source_file_name, new_source);
1172 std::string new_header(nspace->header());
1173 std::string header_file_name = dir +
"/" + base_file_name +
".h";
1174 ReplaceFileContentsIfDifferent(header_file_name, new_header);
1177 void ImplementationVisitor::GenerateMacroFunctionDeclaration(
1178 std::ostream& o,
const std::string& macro_prefix, Macro* macro) {
1179 GenerateFunctionDeclaration(o, macro_prefix, macro->ExternalName(),
1180 macro->signature(), macro->parameter_names());
1183 void ImplementationVisitor::GenerateFunctionDeclaration(
1184 std::ostream& o,
const std::string& macro_prefix,
const std::string& name,
1185 const Signature& signature,
const NameVector& parameter_names) {
1186 if (GlobalContext::verbose()) {
1187 std::cout <<
"generating source for declaration " << name <<
"\n";
1190 if (signature.return_type->IsVoidOrNever()) {
1193 o << signature.return_type->GetGeneratedTypeName();
1195 o <<
" " << macro_prefix << name <<
"(";
1197 DCHECK_EQ(signature.types().size(), parameter_names.size());
1198 auto type_iterator = signature.types().begin();
1200 for (
const std::string& name : parameter_names) {
1204 const Type* parameter_type = *type_iterator;
1205 const std::string& generated_type_name =
1206 parameter_type->GetGeneratedTypeName();
1207 o << generated_type_name <<
" " << ExternalParameterName(name);
1212 for (
const LabelDeclaration& label_info : signature.labels) {
1216 o <<
"compiler::CodeAssemblerLabel* " << ExternalLabelName(label_info.name);
1218 for (
const Type* type : label_info.types) {
1219 std::string generated_type_name(
"compiler::TypedCodeAssemblerVariable<");
1220 generated_type_name += type->GetGeneratedTNodeTypeName();
1221 generated_type_name +=
">*";
1223 o << generated_type_name <<
" " 1224 << ExternalLabelParameterName(label_info.name,
i);
1234 void FailCallableLookup(
const std::string& reason,
const QualifiedName& name,
1235 const Arguments& arguments,
1236 const std::vector<Signature>& candidates) {
1237 std::stringstream stream;
1239 << reason <<
": \n " << name <<
"(" 1240 << arguments.parameters.GetTypeVector() <<
")";
1241 if (arguments.labels.size() != 0) {
1242 stream <<
" labels ";
1243 for (
size_t i = 0;
i < arguments.labels.size(); ++
i) {
1244 stream << arguments.labels[
i]->name() <<
"(" 1245 << arguments.labels[
i]->parameter_types <<
")";
1248 stream <<
"\ncandidates are:";
1249 for (
const Signature& signature : candidates) {
1250 stream <<
"\n " << name;
1251 PrintSignature(stream, signature,
false);
1253 ReportError(stream.str());
1256 Callable* GetOrCreateSpecialization(
const SpecializationKey& key) {
1257 if (base::Optional<Callable*> specialization =
1258 key.generic->GetSpecialization(key.specialized_types)) {
1259 return *specialization;
1261 return DeclarationVisitor().SpecializeImplicit(key);
1266 base::Optional<Binding<LocalValue>*> ImplementationVisitor::TryLookupLocalValue(
1267 const std::string& name) {
1268 return ValueBindingsManager::Get().TryLookup(name);
1271 base::Optional<Binding<LocalLabel>*> ImplementationVisitor::TryLookupLabel(
1272 const std::string& name) {
1273 return LabelBindingsManager::Get().TryLookup(name);
1276 Binding<LocalLabel>* ImplementationVisitor::LookupLabel(
1277 const std::string& name) {
1278 base::Optional<Binding<LocalLabel>*> label = TryLookupLabel(name);
1279 if (!label) ReportError(
"cannot find label ", name);
1283 Block* ImplementationVisitor::LookupSimpleLabel(
const std::string& name) {
1284 LocalLabel* label = LookupLabel(name);
1285 if (!label->parameter_types.empty()) {
1286 ReportError(
"label ", name,
1287 "was expected to have no parameters, but has parameters (",
1288 label->parameter_types,
")");
1290 return label->block;
1293 Callable* ImplementationVisitor::LookupCall(
1294 const QualifiedName& name,
const Arguments& arguments,
1295 const TypeVector& specialization_types) {
1296 Callable* result =
nullptr;
1297 TypeVector parameter_types(arguments.parameters.GetTypeVector());
1299 std::vector<Declarable*> overloads;
1300 std::vector<Signature> overload_signatures;
1301 for (Declarable* declarable : Declarations::Lookup(name)) {
1302 if (Generic*
generic = Generic::DynamicCast(declarable)) {
1303 base::Optional<TypeVector> inferred_specialization_types =
1304 generic->InferSpecializationTypes(specialization_types,
1306 if (!inferred_specialization_types)
continue;
1307 overloads.push_back(
generic);
1308 overload_signatures.push_back(
1309 DeclarationVisitor().MakeSpecializedSignature(
1310 SpecializationKey{
generic, *inferred_specialization_types}));
1311 }
else if (Callable* callable = Callable::DynamicCast(declarable)) {
1312 overloads.push_back(callable);
1313 overload_signatures.push_back(callable->signature());
1317 std::vector<size_t> candidates;
1318 for (
size_t i = 0;
i < overloads.size(); ++
i) {
1319 const Signature& signature = overload_signatures[
i];
1320 bool try_bool_context = arguments.labels.size() == 0 &&
1321 signature.return_type == TypeOracle::GetNeverType();
1322 base::Optional<Binding<LocalLabel>*> true_label;
1323 base::Optional<Binding<LocalLabel>*> false_label;
1324 if (try_bool_context) {
1325 true_label = TryLookupLabel(kTrueLabelName);
1326 false_label = TryLookupLabel(kFalseLabelName);
1328 if (IsCompatibleSignature(signature, parameter_types, arguments.labels) ||
1329 (true_label && false_label &&
1330 IsCompatibleSignature(signature, parameter_types,
1331 {*true_label, *false_label}))) {
1332 candidates.push_back(
i);
1336 if (overloads.empty()) {
1337 std::stringstream stream;
1338 stream <<
"no matching declaration found for " << name;
1339 ReportError(stream.str());
1340 }
else if (candidates.empty()) {
1341 FailCallableLookup(
"cannot find suitable callable with name", name,
1342 arguments, overload_signatures);
1345 auto is_better_candidate = [&](
size_t a,
size_t b) {
1346 return ParameterDifference(overload_signatures[a].GetExplicitTypes(),
1348 .StrictlyBetterThan(ParameterDifference(
1349 overload_signatures[b].GetExplicitTypes(), parameter_types));
1352 size_t best = *std::min_element(candidates.begin(), candidates.end(),
1353 is_better_candidate);
1355 DCHECK(!is_better_candidate(best, best));
1356 for (
size_t candidate : candidates) {
1357 if (candidate != best && !is_better_candidate(best, candidate)) {
1358 std::vector<Signature> candidate_signatures;
1359 for (
size_t i : candidates) {
1360 candidate_signatures.push_back(overload_signatures[
i]);
1362 FailCallableLookup(
"ambiguous callable", name, arguments,
1363 candidate_signatures);
1367 if (Generic*
generic = Generic::DynamicCast(overloads[best])) {
1368 result = GetOrCreateSpecialization(
1369 SpecializationKey{
generic, *
generic->InferSpecializationTypes(
1370 specialization_types, parameter_types)});
1372 result = Callable::cast(overloads[best]);
1375 size_t caller_size = parameter_types.size();
1376 size_t callee_size =
1377 result->signature().types().size() - result->signature().implicit_count;
1378 if (caller_size != callee_size &&
1379 !result->signature().parameter_types.var_args) {
1380 std::stringstream stream;
1381 stream <<
"parameter count mismatch calling " << *result <<
" - expected " 1382 << std::to_string(callee_size) <<
", found " 1383 << std::to_string(caller_size);
1384 ReportError(stream.str());
1390 const Type* ImplementationVisitor::GetCommonType(
const Type* left,
1391 const Type* right) {
1392 const Type* common_type;
1393 if (IsAssignableFrom(left, right)) {
1395 }
else if (IsAssignableFrom(right, left)) {
1396 common_type = right;
1398 common_type = TypeOracle::GetUnionType(left, right);
1400 common_type = common_type->NonConstexprVersion();
1404 VisitResult ImplementationVisitor::GenerateCopy(
const VisitResult& to_copy) {
1405 if (to_copy.IsOnStack()) {
1406 return VisitResult(to_copy.type(),
1407 assembler().Peek(to_copy.stack_range(), to_copy.type()));
1412 VisitResult ImplementationVisitor::Visit(StructExpression* decl) {
1413 const Type* raw_type = Declarations::LookupType(
1414 QualifiedName(decl->namespace_qualification, decl->name));
1415 if (!raw_type->IsStructType()) {
1416 std::stringstream s;
1417 s << decl->name <<
" is not a struct but used like one ";
1418 ReportError(s.str());
1420 const StructType* struct_type = StructType::cast(raw_type);
1421 if (struct_type->fields().size() != decl->expressions.size()) {
1422 std::stringstream s;
1423 s <<
"initializer count mismatch for struct " << decl->name <<
" (expected " 1424 << struct_type->fields().size() <<
", found " << decl->expressions.size()
1426 ReportError(s.str());
1428 StackRange stack_range = assembler().TopRange(0);
1429 for (
size_t i = 0;
i < struct_type->fields().size(); ++
i) {
1430 const NameAndType& field = struct_type->fields()[
i];
1431 StackScope scope(
this);
1432 VisitResult value = Visit(decl->expressions[
i]);
1433 value = GenerateImplicitConvert(field.type, value);
1434 stack_range.Extend(scope.Yield(value).stack_range());
1436 return VisitResult(struct_type, stack_range);
1439 LocationReference ImplementationVisitor::GetLocationReference(
1440 Expression* location) {
1441 switch (location->kind) {
1442 case AstNode::Kind::kIdentifierExpression:
1443 return GetLocationReference(static_cast<IdentifierExpression*>(location));
1444 case AstNode::Kind::kFieldAccessExpression:
1445 return GetLocationReference(
1446 static_cast<FieldAccessExpression*>(location));
1447 case AstNode::Kind::kElementAccessExpression:
1448 return GetLocationReference(
1449 static_cast<ElementAccessExpression*>(location));
1451 return LocationReference::Temporary(Visit(location),
"expression");
1455 LocationReference ImplementationVisitor::GetLocationReference(
1456 FieldAccessExpression* expr) {
1457 LocationReference reference = GetLocationReference(expr->object);
1458 if (reference.IsVariableAccess() &&
1459 reference.variable().type()->IsStructType()) {
1460 return LocationReference::VariableAccess(
1461 ProjectStructField(reference.variable(), expr->field));
1463 if (reference.IsTemporary() && reference.temporary().type()->IsStructType()) {
1464 return LocationReference::Temporary(
1465 ProjectStructField(reference.temporary(), expr->field),
1466 reference.temporary_description());
1468 return LocationReference::FieldAccess(GenerateFetchFromLocation(reference),
1472 LocationReference ImplementationVisitor::GetLocationReference(
1473 ElementAccessExpression* expr) {
1474 VisitResult array = Visit(expr->array);
1475 VisitResult index = Visit(expr->index);
1476 return LocationReference::ArrayAccess(array, index);
1479 LocationReference ImplementationVisitor::GetLocationReference(
1480 IdentifierExpression* expr) {
1481 if (expr->namespace_qualification.empty()) {
1482 if (base::Optional<Binding<LocalValue>*> value =
1483 TryLookupLocalValue(expr->name)) {
1484 if (expr->generic_arguments.size() != 0) {
1485 ReportError(
"cannot have generic parameters on local name ",
1488 if ((*value)->is_const) {
1489 return LocationReference::Temporary((*value)->value,
1490 "constant value " + expr->name);
1492 return LocationReference::VariableAccess((*value)->value);
1496 QualifiedName name = QualifiedName(expr->namespace_qualification, expr->name);
1497 if (base::Optional<Builtin*> builtin = Declarations::TryLookupBuiltin(name)) {
1498 return LocationReference::Temporary(GetBuiltinCode(*builtin),
1499 "builtin " + expr->name);
1501 if (expr->generic_arguments.size() != 0) {
1502 Generic*
generic = Declarations::LookupUniqueGeneric(name);
1503 Callable* specialization = GetOrCreateSpecialization(
1504 SpecializationKey{
generic, GetTypeVector(expr->generic_arguments)});
1505 if (Builtin* builtin = Builtin::DynamicCast(specialization)) {
1506 DCHECK(!builtin->IsExternal());
1507 return LocationReference::Temporary(GetBuiltinCode(builtin),
1508 "builtin " + expr->name);
1510 ReportError(
"cannot create function pointer for non-builtin ",
1514 Value* value = Declarations::LookupValue(name);
1515 if (
auto* constant = NamespaceConstant::DynamicCast(value)) {
1516 if (constant->type()->IsConstexpr()) {
1517 return LocationReference::Temporary(
1518 VisitResult(constant->type(), constant->ExternalAssemblerName() +
1520 constant->constant_name() +
"()"),
1521 "namespace constant " + expr->name);
1523 assembler().Emit(NamespaceConstantInstruction{constant});
1524 StackRange stack_range =
1525 assembler().TopRange(LoweredSlotCount(constant->type()));
1526 return LocationReference::Temporary(
1527 VisitResult(constant->type(), stack_range),
1528 "namespace constant " + expr->name);
1530 ExternConstant* constant = ExternConstant::cast(value);
1531 return LocationReference::Temporary(constant->value(),
1532 "extern value " + expr->name);
1535 VisitResult ImplementationVisitor::GenerateFetchFromLocation(
1536 const LocationReference& reference) {
1537 if (reference.IsTemporary()) {
1538 return GenerateCopy(reference.temporary());
1539 }
else if (reference.IsVariableAccess()) {
1540 return GenerateCopy(reference.variable());
1542 DCHECK(reference.IsCallAccess());
1543 return GenerateCall(reference.eval_function(),
1544 Arguments{reference.call_arguments(), {}});
1548 void ImplementationVisitor::GenerateAssignToLocation(
1549 const LocationReference& reference,
const VisitResult& assignment_value) {
1550 if (reference.IsCallAccess()) {
1551 Arguments arguments{reference.call_arguments(), {}};
1552 arguments.parameters.push_back(assignment_value);
1553 GenerateCall(reference.assign_function(), arguments);
1554 }
else if (reference.IsVariableAccess()) {
1555 VisitResult variable = reference.variable();
1556 VisitResult converted_value =
1557 GenerateImplicitConvert(variable.type(), assignment_value);
1558 assembler().Poke(variable.stack_range(), converted_value.stack_range(),
1561 DCHECK(reference.IsTemporary());
1562 ReportError(
"cannot assign to ", reference.temporary_description());
1566 VisitResult ImplementationVisitor::GeneratePointerCall(
1567 Expression* callee,
const Arguments& arguments,
bool is_tailcall) {
1568 StackScope scope(
this);
1569 TypeVector parameter_types(arguments.parameters.GetTypeVector());
1570 VisitResult callee_result = Visit(callee);
1571 if (!callee_result.type()->IsFunctionPointerType()) {
1572 std::stringstream stream;
1573 stream <<
"Expected a function pointer type but found " 1574 << *callee_result.type();
1575 ReportError(stream.str());
1577 const FunctionPointerType* type =
1578 FunctionPointerType::cast(callee_result.type());
1580 if (type->parameter_types().size() != parameter_types.size()) {
1581 std::stringstream stream;
1582 stream <<
"parameter count mismatch calling function pointer with Type: " 1583 << *type <<
" - expected " 1584 << std::to_string(type->parameter_types().size()) <<
", found " 1585 << std::to_string(parameter_types.size());
1586 ReportError(stream.str());
1589 ParameterTypes types{type->parameter_types(),
false};
1591 sig.parameter_types = types;
1592 if (!IsCompatibleSignature(sig, parameter_types, {})) {
1593 std::stringstream stream;
1594 stream <<
"parameters do not match function pointer signature. Expected: (" 1595 << type->parameter_types() <<
") but got: (" << parameter_types
1597 ReportError(stream.str());
1600 callee_result = GenerateCopy(callee_result);
1601 StackRange arg_range = assembler().TopRange(0);
1602 for (
size_t current = 0; current < arguments.parameters.size(); ++current) {
1603 const Type* to_type = type->parameter_types()[current];
1605 GenerateImplicitConvert(to_type, arguments.parameters[current])
1610 CallBuiltinPointerInstruction{is_tailcall, type, arg_range.Size()});
1613 return VisitResult::NeverResult();
1615 DCHECK_EQ(1, LoweredSlotCount(type->return_type()));
1616 return scope.Yield(VisitResult(type->return_type(), assembler().TopRange(1)));
1619 VisitResult ImplementationVisitor::GenerateCall(
1620 const QualifiedName& callable_name, Arguments arguments,
1621 const TypeVector& specialization_types,
bool is_tailcall) {
1622 Callable* callable =
1623 LookupCall(callable_name, arguments, specialization_types);
1627 if (arguments.labels.size() == 0 &&
1628 callable->signature().labels.size() == 2) {
1629 Binding<LocalLabel>* true_label = LookupLabel(kTrueLabelName);
1630 arguments.labels.push_back(true_label);
1631 Binding<LocalLabel>* false_label = LookupLabel(kFalseLabelName);
1632 arguments.labels.push_back(false_label);
1635 const Type* return_type = callable->signature().return_type;
1637 std::vector<VisitResult> converted_arguments;
1638 StackRange argument_range = assembler().TopRange(0);
1639 std::vector<std::string> constexpr_arguments;
1641 for (
size_t current = 0; current < callable->signature().implicit_count;
1643 std::string implicit_name = callable->signature().parameter_names[current];
1644 base::Optional<Binding<LocalValue>*> val =
1645 TryLookupLocalValue(implicit_name);
1647 ReportError(
"implicit parameter '", implicit_name,
1648 "' required for call to '", callable_name,
1649 "' is not defined");
1651 VisitResult converted = GenerateImplicitConvert(
1652 callable->signature().parameter_types.types[current], (*val)->value);
1653 converted_arguments.push_back(converted);
1654 if (converted.IsOnStack()) {
1655 argument_range.Extend(converted.stack_range());
1657 constexpr_arguments.push_back(converted.constexpr_value());
1661 for (
size_t current = 0; current < arguments.parameters.size(); ++current) {
1662 size_t current_after_implicit =
1663 current + callable->signature().implicit_count;
1664 const Type* to_type =
1665 (current_after_implicit >= callable->signature().types().size())
1666 ? TypeOracle::GetObjectType()
1667 : callable->signature().types()[current_after_implicit];
1668 VisitResult converted =
1669 GenerateImplicitConvert(to_type, arguments.parameters[current]);
1670 converted_arguments.push_back(converted);
1671 if (converted.IsOnStack()) {
1672 argument_range.Extend(converted.stack_range());
1674 constexpr_arguments.push_back(converted.constexpr_value());
1678 if (GlobalContext::verbose()) {
1679 std::cout <<
"generating code for call to " << callable_name <<
"\n";
1682 size_t label_count = callable->signature().labels.size();
1683 if (label_count != arguments.labels.size()) {
1684 std::stringstream s;
1685 s <<
"unexpected number of otherwise labels for " 1686 << callable->ReadableName() <<
" (expected " 1687 << std::to_string(label_count) <<
" found " 1688 << std::to_string(arguments.labels.size()) <<
")";
1689 ReportError(s.str());
1692 if (callable->IsTransitioning()) {
1693 if (!CurrentCallable::Get()->IsTransitioning()) {
1694 std::stringstream s;
1695 s << *CurrentCallable::Get()
1696 <<
" isn't marked transitioning but calls the transitioning " 1698 ReportError(s.str());
1702 if (
auto* builtin = Builtin::DynamicCast(callable)) {
1703 base::Optional<Block*> catch_block = GetCatchBlock();
1704 assembler().Emit(CallBuiltinInstruction{
1705 is_tailcall, builtin, argument_range.Size(), catch_block});
1706 GenerateCatchBlock(catch_block);
1708 return VisitResult::NeverResult();
1710 size_t slot_count = LoweredSlotCount(return_type);
1711 DCHECK_LE(slot_count, 1);
1714 return VisitResult(return_type, assembler().TopRange(slot_count));
1716 }
else if (
auto* macro = Macro::DynamicCast(callable)) {
1718 ReportError(
"can't tail call a macro");
1720 if (return_type->IsConstexpr()) {
1721 DCHECK_EQ(0, arguments.labels.size());
1722 std::stringstream result;
1723 result <<
"(" << macro->external_assembler_name() <<
"(state_)." 1724 << macro->ExternalName() <<
"(";
1726 for (VisitResult arg : arguments.parameters) {
1727 DCHECK(!arg.IsOnStack());
1732 result << arg.constexpr_value();
1735 return VisitResult(return_type, result.str());
1736 }
else if (arguments.labels.empty() &&
1737 return_type != TypeOracle::GetNeverType()) {
1738 base::Optional<Block*> catch_block = GetCatchBlock();
1740 CallCsaMacroInstruction{macro, constexpr_arguments, catch_block});
1741 GenerateCatchBlock(catch_block);
1742 size_t return_slot_count = LoweredSlotCount(return_type);
1743 return VisitResult(return_type, assembler().TopRange(return_slot_count));
1745 base::Optional<Block*> return_continuation;
1746 if (return_type != TypeOracle::GetNeverType()) {
1747 return_continuation = assembler().NewBlock();
1750 std::vector<Block*> label_blocks;
1752 for (
size_t i = 0;
i < label_count; ++
i) {
1753 label_blocks.push_back(assembler().NewBlock());
1755 base::Optional<Block*> catch_block = GetCatchBlock();
1756 assembler().Emit(CallCsaMacroAndBranchInstruction{
1757 macro, constexpr_arguments, return_continuation, label_blocks,
1759 GenerateCatchBlock(catch_block);
1761 for (
size_t i = 0;
i < label_count; ++
i) {
1762 Binding<LocalLabel>* label = arguments.labels[
i];
1763 size_t callee_label_parameters =
1764 callable->signature().labels[
i].types.size();
1765 if (label->parameter_types.size() != callee_label_parameters) {
1766 std::stringstream s;
1767 s <<
"label " << label->name()
1768 <<
" doesn't have the right number of parameters (found " 1769 << std::to_string(label->parameter_types.size()) <<
" expected " 1770 << std::to_string(callee_label_parameters) <<
")";
1771 ReportError(s.str());
1773 assembler().Bind(label_blocks[
i]);
1776 LowerParameterTypes(callable->signature().labels[
i].types).size());
1779 for (
auto t : callable->signature().labels[
i].types) {
1780 const Type* parameter_type = label->parameter_types[j];
1781 if (parameter_type != t) {
1782 ReportError(
"mismatch of label parameters (expected ", *t,
" got ",
1783 parameter_type,
" for parameter ",
i + 1,
")");
1789 if (return_continuation) {
1790 assembler().Bind(*return_continuation);
1791 size_t return_slot_count = LoweredSlotCount(return_type);
1792 return VisitResult(return_type,
1793 assembler().TopRange(return_slot_count));
1795 return VisitResult::NeverResult();
1798 }
else if (
auto* runtime_function = RuntimeFunction::DynamicCast(callable)) {
1799 base::Optional<Block*> catch_block = GetCatchBlock();
1800 assembler().Emit(CallRuntimeInstruction{
1801 is_tailcall, runtime_function, argument_range.Size(), catch_block});
1802 GenerateCatchBlock(catch_block);
1803 if (is_tailcall || return_type == TypeOracle::GetNeverType()) {
1804 return VisitResult::NeverResult();
1806 size_t slot_count = LoweredSlotCount(return_type);
1807 DCHECK_LE(slot_count, 1);
1810 return VisitResult(return_type, assembler().TopRange(slot_count));
1812 }
else if (
auto* intrinsic = Intrinsic::DynamicCast(callable)) {
1813 assembler().Emit(CallIntrinsicInstruction{intrinsic, constexpr_arguments});
1814 size_t return_slot_count =
1815 LoweredSlotCount(intrinsic->signature().return_type);
1816 return VisitResult(return_type, assembler().TopRange(return_slot_count));
1822 VisitResult ImplementationVisitor::Visit(CallExpression* expr,
1824 StackScope scope(
this);
1825 Arguments arguments;
1826 QualifiedName name =
1827 QualifiedName(expr->callee->namespace_qualification, expr->callee->name);
1828 TypeVector specialization_types =
1829 GetTypeVector(expr->callee->generic_arguments);
1830 bool has_template_arguments = !specialization_types.empty();
1831 for (Expression* arg : expr->arguments)
1832 arguments.parameters.push_back(Visit(arg));
1833 arguments.labels = LabelsFromIdentifiers(expr->labels);
1835 if (!has_template_arguments && name.namespace_qualification.empty() &&
1836 TryLookupLocalValue(name.name)) {
1838 GeneratePointerCall(expr->callee, arguments, is_tailcall));
1841 GenerateCall(name, arguments, specialization_types, is_tailcall));
1845 VisitResult ImplementationVisitor::Visit(IntrinsicCallExpression* expr) {
1846 StackScope scope(
this);
1847 Arguments arguments;
1848 TypeVector specialization_types = GetTypeVector(expr->generic_arguments);
1849 for (Expression* arg : expr->arguments)
1850 arguments.parameters.push_back(Visit(arg));
1852 GenerateCall(expr->name, arguments, specialization_types,
false));
1855 void ImplementationVisitor::GenerateBranch(
const VisitResult& condition,
1857 Block* false_block) {
1858 DCHECK_EQ(condition,
1859 VisitResult(TypeOracle::GetBoolType(), assembler().TopRange(1)));
1860 assembler().Branch(true_block, false_block);
1863 void ImplementationVisitor::GenerateExpressionBranch(Expression* expression,
1865 Block* false_block) {
1872 Binding<LocalLabel> true_binding{&LabelBindingsManager::Get(), kTrueLabelName,
1873 LocalLabel{true_block}};
1874 Binding<LocalLabel> false_binding{&LabelBindingsManager::Get(),
1875 kFalseLabelName, LocalLabel{false_block}};
1876 StackScope stack_scope(
this);
1877 VisitResult expression_result = Visit(expression);
1878 if (!expression_result.type()->IsNever()) {
1879 expression_result = stack_scope.Yield(
1880 GenerateImplicitConvert(TypeOracle::GetBoolType(), expression_result));
1881 GenerateBranch(expression_result, true_block, false_block);
1885 VisitResult ImplementationVisitor::GenerateImplicitConvert(
1886 const Type* destination_type, VisitResult source) {
1887 StackScope scope(
this);
1888 if (source.type() == TypeOracle::GetNeverType()) {
1889 ReportError(
"it is not allowed to use a value of type never");
1892 if (destination_type == source.type()) {
1893 return scope.Yield(GenerateCopy(source));
1896 if (TypeOracle::IsImplicitlyConvertableFrom(destination_type,
1898 return scope.Yield(GenerateCall(kFromConstexprMacroName, {{source}, {}},
1899 {destination_type},
false));
1900 }
else if (IsAssignableFrom(destination_type, source.type())) {
1901 source.SetType(destination_type);
1902 return scope.Yield(GenerateCopy(source));
1904 std::stringstream s;
1905 s <<
"cannot use expression of type " << *source.type()
1906 <<
" as a value of type " << *destination_type;
1907 ReportError(s.str());
1911 StackRange ImplementationVisitor::GenerateLabelGoto(
1912 LocalLabel* label, base::Optional<StackRange> arguments) {
1913 return assembler().Goto(label->block, arguments ? arguments->Size() : 0);
1916 std::vector<Binding<LocalLabel>*> ImplementationVisitor::LabelsFromIdentifiers(
1917 const std::vector<std::string>& names) {
1918 std::vector<Binding<LocalLabel>*> result;
1919 result.reserve(names.size());
1920 for (
const auto& name : names) {
1921 result.push_back(LookupLabel(name));
1926 StackRange ImplementationVisitor::LowerParameter(
1927 const Type* type,
const std::string& parameter_name,
1928 Stack<std::string>* lowered_parameters) {
1929 if (type->IsStructType()) {
1930 const StructType* struct_type = StructType::cast(type);
1931 StackRange range = lowered_parameters->TopRange(0);
1932 for (
auto& field : struct_type->fields()) {
1933 StackRange parameter_range = LowerParameter(
1934 field.type, parameter_name +
"." + field.name, lowered_parameters);
1935 range.Extend(parameter_range);
1939 lowered_parameters->Push(parameter_name);
1940 return lowered_parameters->TopRange(1);
1944 std::string ImplementationVisitor::ExternalLabelName(
1945 const std::string& label_name) {
1946 return "label_" + label_name;
1949 std::string ImplementationVisitor::ExternalLabelParameterName(
1950 const std::string& label_name,
size_t i) {
1951 return "label_" + label_name +
"_parameter_" + std::to_string(
i);
1954 std::string ImplementationVisitor::ExternalParameterName(
1955 const std::string& name) {
1956 return std::string(
"p_") + name;
1959 DEFINE_CONTEXTUAL_VARIABLE(ImplementationVisitor::ValueBindingsManager);
1960 DEFINE_CONTEXTUAL_VARIABLE(ImplementationVisitor::LabelBindingsManager);
1961 DEFINE_CONTEXTUAL_VARIABLE(ImplementationVisitor::CurrentCallable);
1963 bool IsCompatibleSignature(
const Signature& sig,
const TypeVector& types,
1964 const std::vector<Binding<LocalLabel>*>& labels) {
1965 auto i = sig.parameter_types.types.begin() + sig.implicit_count;
1966 if ((sig.parameter_types.types.size() - sig.implicit_count) > types.size())
1972 if (sig.labels.size() != labels.size())
return false;
1973 for (
auto current : types) {
1974 if (
i == sig.parameter_types.types.end()) {
1975 if (!sig.parameter_types.var_args)
return false;
1976 if (!IsAssignableFrom(TypeOracle::GetObjectType(), current))
return false;
1978 if (!IsAssignableFrom(*
i++, current))
return false;
1984 base::Optional<Block*> ImplementationVisitor::GetCatchBlock() {
1985 base::Optional<Block*> catch_block;
1986 if (base::Optional<Binding<LocalLabel>*> catch_handler =
1987 TryLookupLabel(
"_catch")) {
1988 catch_block = assembler().NewBlock(base::nullopt,
true);
1993 void ImplementationVisitor::GenerateCatchBlock(
1994 base::Optional<Block*> catch_block) {
1996 base::Optional<Binding<LocalLabel>*> catch_handler =
1997 TryLookupLabel(
"_catch");
1998 if (assembler().CurrentBlockIsComplete()) {
1999 assembler().Bind(*catch_block);
2000 assembler().Goto((*catch_handler)->block, 1);
2002 CfgAssemblerScopedTemporaryBlock temp(&assembler(), *catch_block);
2003 assembler().Goto((*catch_handler)->block, 1);
2008 void ImplementationVisitor::VisitAllDeclarables() {
2009 const std::vector<std::unique_ptr<Declarable>>& all_declarables =
2010 GlobalContext::AllDeclarables();
2013 for (
size_t i = 0;
i < all_declarables.size(); ++
i) {
2014 Visit(all_declarables[
i].
get());
2018 void ImplementationVisitor::Visit(Declarable* declarable) {
2019 CurrentScope::Scope current_scope(declarable->ParentScope());
2020 CurrentSourcePosition::Scope current_source_position(declarable->pos());
2021 switch (declarable->kind()) {
2022 case Declarable::kMacro:
2023 return Visit(Macro::cast(declarable));
2024 case Declarable::kBuiltin:
2025 return Visit(Builtin::cast(declarable));
2026 case Declarable::kTypeAlias:
2027 return Visit(TypeAlias::cast(declarable));
2028 case Declarable::kNamespaceConstant:
2029 return Visit(NamespaceConstant::cast(declarable));
2030 case Declarable::kRuntimeFunction:
2031 case Declarable::kIntrinsic:
2032 case Declarable::kExternConstant:
2033 case Declarable::kNamespace:
2034 case Declarable::kGeneric:
2039 void ImplementationVisitor::GenerateBuiltinDefinitions(std::string& file_name) {
2040 std::stringstream new_contents_stream;
2042 <<
"#ifndef V8_BUILTINS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n" 2043 "#define V8_BUILTINS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n" 2045 "#define BUILTIN_LIST_FROM_DSL(CPP, API, TFJ, TFC, TFS, TFH, ASM) " 2047 for (
auto& declarable : GlobalContext::AllDeclarables()) {
2048 Builtin* builtin = Builtin::DynamicCast(declarable.get());
2049 if (!builtin || builtin->IsExternal())
continue;
2050 int firstParameterIndex = 1;
2051 bool declareParameters =
true;
2052 if (builtin->IsStub()) {
2053 new_contents_stream <<
"TFS(" << builtin->ExternalName();
2055 new_contents_stream <<
"TFJ(" << builtin->ExternalName();
2056 if (builtin->IsVarArgsJavaScript()) {
2058 <<
", SharedFunctionInfo::kDontAdaptArgumentsSentinel";
2059 declareParameters =
false;
2061 assert(builtin->IsFixedArgsJavaScript());
2064 assert(builtin->parameter_names().size() >= 2);
2065 new_contents_stream <<
", " << (builtin->parameter_names().size() - 2);
2067 new_contents_stream <<
", kReceiver";
2068 firstParameterIndex = 2;
2071 if (declareParameters) {
2073 for (
const auto& parameter : builtin->parameter_names()) {
2074 if (index >= firstParameterIndex) {
2075 new_contents_stream <<
", k" << CamelifyString(parameter);
2080 new_contents_stream <<
") \\\n";
2082 new_contents_stream <<
"\n";
2085 <<
"#define TORQUE_FUNCTION_POINTER_TYPE_TO_BUILTIN_MAP(V) \\\n";
2086 for (
const FunctionPointerType* type :
2087 TypeOracle::AllFunctionPointerTypes()) {
2088 Builtin* example_builtin =
2089 Declarations::FindSomeInternalBuiltinWithType(type);
2090 if (!example_builtin) {
2091 CurrentSourcePosition::Scope current_source_position(
2092 SourcePosition{CurrentSourceFile::Get(), -1, -1});
2093 ReportError(
"unable to find any builtin with type \"", *type,
"\"");
2095 new_contents_stream <<
" V(" << type->function_pointer_type_id() <<
"," 2096 << example_builtin->ExternalName() <<
")\\\n";
2098 new_contents_stream <<
"\n";
2101 <<
"#endif // V8_BUILTINS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n";
2103 std::string new_contents(new_contents_stream.str());
2104 ReplaceFileContentsIfDifferent(file_name, new_contents);