38using namespace std::string_literals;
41const char* BuiltinIncludesMarker =
"// __BUILTIN_INCLUDES_MARKER__\n";
45 CurrentSourcePosition::Scope scope(expr->
pos);
47#define ENUM_ITEM(name) \
48 case AstNode::Kind::k##name: \
49 return Visit(name::cast(expr));
58 CurrentSourcePosition::Scope scope(stmt->
pos);
62#define ENUM_ITEM(name) \
63 case AstNode::Kind::k##name: \
64 result = Visit(name::cast(stmt)); \
77 std::set<SourceId> contains_class_definitions;
78 std::set<SourceId> contains_class_asserts;
80 if (type->ShouldGenerateCppClassDefinitions()) {
81 contains_class_definitions.insert(type->AttributedToFile());
83 if (type->ShouldGenerateCppObjectDefinitionAsserts() ||
84 type->ShouldGenerateCppObjectLayoutDefinitionAsserts()) {
85 contains_class_asserts.insert(type->AttributedToFile());
98 file <<
"#include \"src/codegen/code-stub-assembler-inl.h\"\n";
100 file <<
"// Required Builtins:\n";
101 file <<
"#include \"torque-generated/" +
110 file << BuiltinIncludesMarker;
113 streams.csa_cc.BeginNamespace(
"v8",
"internal");
114 streams.csa_ccfile <<
"\n";
119 std::string header_define =
120 "V8_GEN_TORQUE_GENERATED_" +
122 streams.csa_header.BeginIncludeGuard(header_define);
123 file <<
"#include \"src/builtins/torque-csa-header-includes.h\"\n";
126 streams.csa_header.BeginNamespace(
"v8",
"internal");
127 streams.csa_headerfile <<
"\n";
131 cpp::File& file = streams.class_definition_cc;
132 if (contains_class_definitions.count(source) != 0) {
133 file <<
"#include \""
136 file <<
"#include \"torque-generated/class-verifiers.h\"\n";
137 file <<
"#include \"src/objects/instance-type-inl.h\"\n\n";
139 if (contains_class_asserts.count(source) != 0) {
140 file <<
"#include \""
146 streams.class_definition_ccfile <<
"\n";
156 streams.csa_cc.EndNamespace(
"v8",
"internal");
160 std::string header_define =
161 "V8_GEN_TORQUE_GENERATED_" +
164 streams.csa_header.EndNamespace(
"v8",
"internal");
165 streams.csa_headerfile <<
"\n";
166 streams.csa_header.EndIncludeGuard(header_define);
170 streams.class_definition_cc.EndNamespace(
"v8",
"internal");
179 source <<
"#include \"torque-generated/debug-macros.h\"\n\n";
180 source <<
"#include \"src/objects/swiss-name-dictionary.h\"\n";
181 source <<
"#include \"src/objects/ordered-hash-table.h\"\n";
182 source <<
"#include \"src/torque/runtime-support.h\"\n";
183 source <<
"#include \"tools/debug_helper/debug-macro-shims.h\"\n";
184 source <<
"#include \"include/v8-internal.h\"\n";
187 source <<
"namespace v8 {\n"
188 <<
"namespace internal {\n"
189 <<
"namespace debug_helper_internal {\n"
192 const char* kHeaderDefine =
"V8_GEN_TORQUE_GENERATED_DEBUG_MACROS_H_";
193 header <<
"#ifndef " << kHeaderDefine <<
"\n";
194 header <<
"#define " << kHeaderDefine <<
"\n\n";
195 header <<
"#include \"tools/debug_helper/debug-helper-internal.h\"\n";
196 header <<
"#include \"src/numbers/integer-literal.h\"\n";
199 header <<
"namespace v8 {\n"
200 <<
"namespace internal {\n"
201 <<
"namespace debug_helper_internal {\n"
210 source <<
"} // namespace internal\n"
211 <<
"} // namespace v8\n"
212 <<
"} // namespace debug_helper_internal\n"
215 header <<
"\n} // namespace internal\n"
216 <<
"} // namespace v8\n"
217 <<
"} // namespace debug_helper_internal\n"
219 header <<
"#endif // V8_GEN_TORQUE_GENERATED_DEBUG_MACROS_H_\n";
223 Signature signature{{}, std::nullopt, {{},
false}, 0,
224 decl->
type(), {},
false};
234 stream <<
" compiler::CodeAssembler ca_(state_);\n";
236 DCHECK(!signature.return_type->IsVoidOrNever());
249 stream <<
" return ";
257 if (
const ClassType* class_type = ClassType::DynamicCast(alias->
type())) {
258 if (class_type->IsExtern() && !class_type->nspace()->IsDefaultNamespace()) {
260 "extern classes are currently only supported in the default "
273 ReportError(
"Recursive macro call to ", *macro);
284 Macro* macro, std::optional<LocationReference> this_reference,
285 const std::vector<VisitResult>& arguments,
286 const std::vector<Block*> label_blocks) {
288 CurrentScope::Scope current_scope(macro);
290 CurrentCallable::Scope current_callable(macro);
291 CurrentReturnValue::Scope current_return_value;
292 const Signature& signature = macro->signature();
293 const Type* return_type = macro->signature().return_type;
298 DCHECK_EQ(macro->signature().parameter_names.size(),
299 arguments.size() + (this_reference ? 1 : 0));
300 DCHECK_EQ(this_reference.has_value(), macro->IsMethod());
309 if (this_reference) {
310 DCHECK(macro->IsMethod());
318 for (
const auto& arg : arguments) {
323 parameter_bindings.
Add(name,
325 arg,
"parameter " + name->value)},
333 for (
size_t i = 0;
i < signature.
labels.size(); ++
i) {
343 std::optional<Binding<LocalLabel>> macro_end_binding;
346 std::vector<const Type*> lowered_return_types =
LowerType(return_type);
347 stack.PushMany(lowered_return_types);
350 stack.TopRange(lowered_return_types.size())));
357 for (
auto i = stack.begin();
i != stack.end(); ++
i) {
358 if ((*i)->IsTopType()) {
359 *
i = TopType::cast(*i)->source_type();
372 if (!return_type->
IsNever() && !macro->HasReturns()) {
374 s <<
"macro " << macro->ReadableName()
375 <<
" that never returns must have return type never";
381 s <<
"macro " << macro->ReadableName()
382 <<
" has implicit return at end of its declartion but return type "
385 }
else if (!macro->signature().return_type->IsVoid()) {
387 s <<
"macro " << macro->ReadableName()
388 <<
" expects to return a value but doesn't on all paths";
396 if (macro->HasReturns() || !
result->IsNever()) {
404 CurrentCallable::Scope current_callable(macro);
405 const Signature& signature = macro->signature();
406 const Type* return_type = macro->signature().return_type;
408 bool has_return_value =
420 std::optional<cpp::IncludeGuardScope> include_guard;
422 include_guard.emplace(&csa_cc,
"V8_INTERNAL_DEFINED_"s + macro->CCName());
424 include_guard.emplace(&csa_cc,
425 "V8_INTERNAL_DEFINED_"s + macro->CCDebugName());
433 csa_ccfile() <<
" DisallowGarbageCollection no_gc;\n";
435 csa_ccfile() <<
" compiler::CodeAssembler ca_(state_);\n";
437 <<
" compiler::CodeAssembler::SourcePositionScope pos_scope(&ca_);\n";
443 std::vector<VisitResult> arguments;
445 std::optional<LocationReference> this_reference;
447 const Type* this_type =
method->aggregate_type();
449 &lowered_parameters);
467 for (
size_t i = 0;
i < macro->signature().parameter_names.
size(); ++
i) {
468 if (this_reference &&
i == macro->signature().implicit_count)
continue;
469 const std::string& name = macro->parameter_names()[
i]->value;
471 const Type* type = macro->signature().types()[
i];
473 if (type->IsConstexpr()) {
474 arguments.push_back(
VisitResult(type, external_name));
485 std::vector<Block*> label_blocks;
488 for (
const Type* type : label_info.
types) {
492 label_blocks.push_back(block);
496 InlineMacro(macro, this_reference, arguments, label_blocks);
502 for (
size_t i = 0;
i < label_blocks.size(); ++
i) {
503 Block* label_block = label_blocks[
i];
506 std::vector<std::string> label_parameter_variables;
507 for (
size_t j = 0; j < label_info.
types.size(); ++j) {
510 &label_parameter_variables);
514 std::move(label_parameter_variables)});
521 std::optional<Stack<std::string>> values;
524 values = cc_generator.
EmitGraph(lowered_parameters);
527 values = cc_generator.
EmitGraph(lowered_parameters);
530 values = csa_generator.
EmitGraph(lowered_parameters);
535 if (has_return_value) {
538 csa_ccfile() <<
"{d::MemoryAccessResult::kOk, ";
550 include_guard.reset();
564std::string AddParameter(
size_t i,
Builtin* builtin,
569 const Identifier* name = builtin->signature().parameter_names[
i];
570 const Type* type = builtin->signature().types()[
i];
571 std::string external_name =
"parameter" + std::to_string(
i);
572 parameters->
Push(external_name);
577 "parameter " + name->value)},
582 return external_name;
588 if (builtin->IsExternal())
return;
589 CurrentScope::Scope current_scope(builtin);
590 CurrentCallable::Scope current_callable(builtin);
591 CurrentReturnValue::Scope current_return_value;
593 const std::string& name = builtin->ExternalName();
594 const Signature& signature = builtin->signature();
595 csa_ccfile() <<
"TF_BUILTIN(" << name <<
", CodeStubAssembler) {\n"
596 <<
" compiler::CodeAssemblerState* state_ = state();"
597 <<
" compiler::CodeAssembler ca_(state());\n";
606 if (builtin->IsVarArgsJavaScript() || builtin->IsFixedArgsJavaScript()) {
607 if (builtin->IsVarArgsJavaScript()) {
610 Error(
"Cannot mix explicit parameters with varargs.")
614 csa_ccfile() <<
" TNode<Word32T> argc = UncheckedParameter<Word32T>("
615 <<
"Descriptor::kJSActualArgumentsCount);\n";
617 "arguments_length(ChangeInt32ToIntPtr(UncheckedCast<"
618 "Int32T>(argc)));\n";
619 csa_ccfile() <<
" TNode<RawPtrT> arguments_frame = "
620 "UncheckedCast<RawPtrT>(LoadFramePointer());\n";
622 <<
" TorqueStructArguments "
623 "torque_arguments(GetFrameArguments(arguments_frame, "
624 "arguments_length, FrameArgumentsArgcType::kCountIncludesReceiver"
627 <<
" CodeStubArguments arguments(this, torque_arguments);\n";
629 parameters.
Push(
"torque_arguments.frame");
630 parameters.
Push(
"torque_arguments.base");
631 parameters.
Push(
"torque_arguments.length");
632 parameters.
Push(
"torque_arguments.actual_count");
637 VisitResult(arguments_type, range),
638 "parameter " + *signature.arguments_variable)},
645 std::string generated_name = AddParameter(
646 i, builtin, ¶meters, ¶meter_types, ¶meter_bindings,
true);
648 std::vector<const Type*> expected_types;
649 if (param_name ==
"context") {
650 csa_ccfile() <<
" TNode<NativeContext> " << generated_name
651 <<
" = UncheckedParameter<NativeContext>("
652 <<
"Descriptor::kContext);\n";
653 csa_ccfile() <<
" USE(" << generated_name <<
");\n";
656 }
else if (param_name ==
"receiver") {
658 <<
" TNode<JSAny> " << generated_name <<
" = "
659 << (builtin->IsVarArgsJavaScript()
660 ?
"arguments.GetReceiver()"
661 :
"UncheckedParameter<JSAny>(Descriptor::kReceiver)")
663 csa_ccfile() <<
" USE(" << generated_name <<
");\n";
665 }
else if (param_name ==
"newTarget") {
666 csa_ccfile() <<
" TNode<JSAny> " << generated_name
667 <<
" = UncheckedParameter<JSAny>("
668 <<
"Descriptor::kJSNewTarget);\n";
669 csa_ccfile() <<
" USE(" << generated_name <<
");\n";
671 }
else if (param_name ==
"target") {
672 csa_ccfile() <<
" TNode<JSFunction> " << generated_name
673 <<
" = UncheckedParameter<JSFunction>("
674 <<
"Descriptor::kJSTarget);\n";
675 csa_ccfile() <<
" USE(" << generated_name <<
");\n";
677 }
else if (param_name ==
"dispatchHandle") {
679 csa_ccfile() <<
" TNode<JSDispatchHandleT> " << generated_name
681 "UncheckedParameter<JSDispatchHandleT>(Descriptor::"
682 "kJSDispatchHandle);\n";
684 csa_ccfile() <<
" TNode<JSDispatchHandleT> " << generated_name
686 "ReinterpretCast<JSDispatchHandleT>("
687 "LoadJSFunctionDispatchHandle("
688 "UncheckedParameter<JSFunction>("
689 <<
"Descriptor::kJSTarget)));\n";
691 csa_ccfile() <<
" TNode<JSDispatchHandleT> " << generated_name
692 <<
" = InvalidDispatchHandleConstant();\n";
694 csa_ccfile() <<
" USE(" << generated_name <<
");\n";
698 "Unexpected implicit parameter \"", param_name,
699 "\" for JavaScript calling convention, "
700 "expected \"context\", \"receiver\", \"target\", or \"newTarget\"")
702 expected_types = {actual_type};
704 if (std::find(expected_types.begin(), expected_types.end(),
705 actual_type) == expected_types.end()) {
706 Error(
"According to JavaScript calling convention, expected parameter ",
707 param_name,
" to have type ",
PrintList(expected_types,
" or "),
708 " but found type ", *actual_type)
718 std::string var = AddParameter(
i, builtin, ¶meters, ¶meter_types,
719 ¶meter_bindings, mark_as_used);
720 csa_ccfile() <<
" " << type->GetGeneratedTypeName() <<
" " << var
722 <<
"UncheckedParameter<" << type->GetGeneratedTNodeTypeName()
729 DCHECK(builtin->IsStub());
735 std::string var = AddParameter(
i, builtin, ¶meters, ¶meter_types,
736 ¶meter_bindings, mark_as_used);
737 csa_ccfile() <<
" " << type->GetGeneratedTypeName() <<
" " << var
739 <<
"UncheckedParameter<" << type->GetGeneratedTNodeTypeName()
746 if (builtin->use_counter_name()) {
751 csa_ccfile() <<
" CodeStubAssembler(state_).CallRuntime("
752 <<
"Runtime::kIncrementUseCounter, parameter0, "
753 <<
"CodeStubAssembler(state_).SmiConstant("
754 << *builtin->use_counter_name() <<
"));\n";
758 const Type* body_result =
Visit(*builtin->body());
760 ReportError(
"control reaches end of builtin, expected return of a value");
771 return Visit(stmt, &block_bindings);
778 ReportError(
"local constant \"", stmt->
name,
"\" is not initialized.");
781 std::optional<const Type*>
type;
785 std::optional<VisitResult> init_result;
792 type = init_result->type();
794 Error(
"Use 'const' instead of 'let' for variable '", stmt->
name->
value,
795 "' of constexpr type '", (*type)->ToString(),
"'.")
799 init_result = scope.
Yield(*init_result);
802 if ((*type)->IsConstexpr()) {
803 ReportError(
"constexpr variables need an initializer");
806 for (
const Type* t : lowered_types) {
808 "uninitialized variable '" + stmt->
name->
value +
"' of type " +
809 t->ToString() +
" originally defined at " +
818 *init_result,
"const " + stmt->
name->
value)
848 const Type* common_type;
872 if (left_result.
type()->IsConstexprBool()) {
874 if (!right_result.
type()->IsConstexprBool()) {
876 "expected type constexpr bool on right-hand side of operator "
899 false_result = false_block_scope.
Yield(
906 return outer_scope.
Yield(true_result);
913 if (left_result.
type()->IsConstexprBool()) {
915 if (!right_result.
type()->IsConstexprBool()) {
917 "expected type constexpr bool on right-hand side of operator "
942 "Please use & rather than && when checking multiple bitfield "
943 "values, to avoid complexity in generated code.");
945 true_result = true_block_scope.
Yield(
956 return outer_scope.
Yield(true_result);
969 return scope.
Yield(expr->
postfix ? current_value : assignment_value);
987 return scope.
Yield(assignment_value);
992 std::stringstream str;
993 str << std::setprecision(std::numeric_limits<double>::digits10 + 1)
1000 std::stringstream str;
1001 str <<
"IntegerLiteral("
1016 result.SetType(result_type);
1023 "\"" + expr->
literal.substr(1, expr->
literal.size() - 2) +
"\""};
1027 if (builtin->IsExternal() || builtin->kind() !=
Builtin::kStub) {
1029 "creating function pointers is only allowed for internal builtins with "
1033 builtin->signature().parameter_types.types,
1034 builtin->signature().return_type);
1060 ReportError(
"goto to label has incorrect number of parameters (expected ",
1066 label->declaration_position());
1077 const Type* parameter_type =
label->parameter_types[
i++];
1087 bool has_else = stmt->
if_false.has_value();
1093 std::stringstream stream;
1094 stream <<
"expression should return type constexpr bool "
1095 <<
"but returns type " << *expression_result.
type();
1122 std::stringstream stream;
1123 stream <<
"either both or neither branches in a constexpr if statement "
1124 "must reach their end at"
1136 Block* false_block =
1146 done_block = false_block;
1201 for (
Statement* s : block->statements) {
1202 CurrentSourcePosition::Scope source_position(s->pos);
1203 if (type->IsNever()) {
1204 ReportError(
"statement after non-returning statement");
1206 if (
auto* var_declaration = VarDeclarationStatement::DynamicCast(s)) {
1207 type =
Visit(var_declaration, &block_bindings);
1217 const Type* return_type;
1219 switch (stmt->
kind) {
1227 reason =
"debug break";
1242std::string FormatAssertSource(
const std::string& str) {
1244 std::string str_no_newlines = str;
1246 str_no_newlines.begin(), str_no_newlines.end(),
1247 [](
unsigned char c) { return isspace(c); },
' ');
1251 std::unique_copy(str_no_newlines.begin(), str_no_newlines.end(),
1252 std::back_inserter(
result),
1253 [](
char a,
char b) { return a ==
' ' && b ==
' '; });
1261 std::string message =
1279 Block* resume_block;
1305 "Torque assert '" + FormatAssertSource(stmt->
source) +
"' failed"});
1322 Callable* current_callable = CurrentCallable::Get();
1323 if (current_callable->
signature().return_type->IsNever()) {
1324 std::stringstream
s;
1325 s <<
"cannot return from a function with return type never";
1332 std::stringstream
s;
1333 s <<
"return expression needs to be specified for a return type of "
1334 << *current_callable->
signature().return_type;
1339 current_callable->
signature().return_type, expression_result);
1340 if (current_callable->
IsMacro()) {
1349 }
else if (current_callable->
IsBuiltin()) {
1357 std::stringstream
s;
1358 s <<
"return expression can't be specified for a void or never return "
1370 std::vector<VisitResult> parameters;
1372 Block* label_block =
nullptr;
1377 CurrentSourcePosition::Scope source_position(expr->
label_block->
pos);
1379 ReportError(
"cannot use ... for label parameters");
1386 parameter_types.push_back(type);
1387 if (type->IsConstexpr()) {
1388 ReportError(
"no constexpr type allowed for label arguments");
1398 LocalLabel{label_block, std::move(parameter_types)}};
1404 try_result = stack_scope.
Yield(try_result);
1414 const Type* label_result;
1419 parameter_bindings.
Add(name,
1421 parameters[
i],
"parameter " + name->value)});
1426 if (!try_result.
type()->IsVoidOrNever() && label_result->
IsVoid()) {
1428 "otherwise clauses cannot fall through in a non-void expression");
1433 if (label_result->
IsVoid() && try_result.
type()->IsNever()) {
1438 if (!try_result.
type()->IsNever()) {
1450 const std::vector<NameAndExpression>& initializers) {
1453 result.names.push_back(initializer.name);
1456 bool has_index = field.
index.has_value();
1460 "spread expressions can only be used to initialize indexed class "
1462 initializer.name->value,
"' is not)");
1465 }
else if (has_index) {
1466 ReportError(
"the indexed class field '", initializer.name->value,
1467 "' must be initialized with a spread operator");
1476 bool treat_optional_as_indexed) {
1477 if (field.
index.has_value()) {
1480 if (field.
index->optional && !treat_optional_as_indexed) {
1489 DCHECK(field.offset.has_value());
1491 result_range.
Extend(GenerateCopy(
object).stack_range());
1497 field.const_qualified);
1499 field.synchronization);
1508 result_range.
Extend(GenerateCopy(
object).stack_range());
1515 result_range.
Extend(length.stack_range());
1516 const Type* slice_type =
1518 return LocationReference::HeapSlice(
VisitResult(slice_type, result_range));
1524 return LocationReference::HeapReference(heap_reference);
1528void ImplementationVisitor::InitializeClass(
1533 InitializeClass(super, allocate_result, initializer_results, layout);
1538 if (f.name_and_type.type->IsVoid())
continue;
1542 GenerateFieldReferenceForInit(allocate_result, f, layout);
1546 GenerateCall(
QualifiedName({TORQUE_INTERNAL_NAMESPACE_STRING},
1547 "InitializeFieldsFromIterator"),
1548 {{slice, initializer_value}, {}});
1550 GenerateAssignToLocation(field, initializer_value);
1557 const std::map<std::string, LocalValue>& bindings) {
1559 CurrentSourcePosition::Scope pos_scope(array_length->
pos);
1561 CurrentScope::Scope current_scope_scope(nspace);
1565 for (
auto& p : bindings) {
1570 GenerateCall(
"Convert",
Arguments{{length}, {}},
1571 {TypeOracle::GetIntPtrType(), length.type()},
false);
1572 return stack_scope.
Yield(converted_length);
1576 const Field& field) {
1581 std::map<std::string, LocalValue> bindings;
1582 bool before_current =
true;
1585 before_current =
false;
1593 {f.name_and_type.name,
1596 ?
LocalValue{[
this, object, f, class_type]() {
1597 return GenerateFieldReference(
object, f, class_type);
1599 :
LocalValue(
"Array lengths may only refer to fields "
1602 "Non-const fields cannot be used for array lengths.")});
1604 return stack_scope.
Yield(
1605 GenerateArrayLength(field.
index->expr, class_type->
nspace(), bindings));
1610 const Field& field) {
1614 std::map<std::string, LocalValue> bindings;
1617 const std::string& fieldname = f.name_and_type.name;
1623 value,
"initial field " + fieldname)}
1625 "Non-const fields cannot be used for array lengths.")});
1627 return stack_scope.
Yield(
1628 GenerateArrayLength(field.
index->expr, class_type->
nspace(), bindings));
1637 if (f.offset.has_value()) {
1643 size_t element_size;
1644 std::string element_size_string;
1645 std::tie(element_size, element_size_string) =
1646 *
SizeOf(f.name_and_type.type);
1648 VisitResult(TypeOracle::GetConstInt31Type(), element_size_string);
1650 GenerateArrayLength(class_type, initializer_results, f);
1655 "AddIndexedFieldSizeToObjectSize"),
1658 DCHECK(f.offset.has_value());
1667 if ((
size_t{1} << class_type->
size().AlignmentLog2()) <
1668 TargetArchitecture::TaggedSize()) {
1671 layout.
size = GenerateCall(
1672 QualifiedName({TORQUE_INTERNAL_NAMESPACE_STRING},
"AlignTagged"),
1680 const Type* type = TypeVisitor::ComputeType(expr->
type);
1681 const ClassType* class_type = ClassType::DynamicCast(type);
1682 if (class_type ==
nullptr) {
1683 ReportError(
"type for new expression must be a class, \"", *type,
1690 " cannot be allocated with new (it's used for testing)");
1694 VisitInitializerResults(class_type, expr->
initializers);
1697 if (*map_field.
offset != 0) {
1698 ReportError(
"class initializers must have a map as first parameter");
1700 const std::map<std::string, VisitResult>& initializer_fields =
1705 if (it_object_map == initializer_fields.end()) {
1707 " needs Map argument!");
1709 object_map = it_object_map->second;
1711 if (it_object_map != initializer_fields.end()) {
1713 "Constructor for ", class_type->
name(),
1714 " must not specify Map argument; it is automatically inserted.");
1717 get_struct_map_arguments.
parameters.push_back(
1718 VisitResult(TypeOracle::GetConstexprInstanceTypeType(),
1720 object_map = GenerateCall(
1721 QualifiedName({TORQUE_INTERNAL_NAMESPACE_STRING},
"GetInstanceTypeMap"),
1722 get_struct_map_arguments, {},
false);
1723 CurrentSourcePosition::Scope current_pos(expr->
pos);
1724 initializer_results.
names.insert(initializer_results.
names.begin(),
1725 MakeNode<Identifier>(
"map"));
1730 CheckInitializersWellformed(class_type->
name(),
1735 GenerateLayoutForInitialization(class_type, initializer_results);
1739 allocate_arguments.
parameters.push_back(object_map);
1745 QualifiedName({TORQUE_INTERNAL_NAMESPACE_STRING},
"AllocateFromNew"),
1746 allocate_arguments, {class_type},
false);
1749 InitializeClass(class_type, allocate_result, initializer_results, layout);
1751 return stack_scope.
Yield(GenerateCall(
1752 "%RawDownCast",
Arguments{{allocate_result}, {}}, {class_type}));
1756 std::optional<Binding<LocalLabel>*> break_label =
1757 TryLookupLabel(kBreakLabelName);
1761 assembler().Goto((*break_label)->block);
1762 return TypeOracle::GetNeverType();
1766 std::optional<Binding<LocalLabel>*> continue_label =
1767 TryLookupLabel(kContinueLabelName);
1768 if (!continue_label) {
1771 assembler().Goto((*continue_label)->block);
1772 return TypeOracle::GetNeverType();
1789 Block* continue_block = header_block;
1792 Block* action_block =
nullptr;
1797 continue_block = action_block;
1801 GenerateExpressionBranch(*stmt->
test, body_block, exit_block);
1809 const Type* body_result = Visit(stmt->
body);
1810 if (body_result != TypeOracle::GetNeverType()) {
1817 const Type* action_result = Visit(*stmt->
action);
1818 if (action_result != TypeOracle::GetNeverType()) {
1824 return TypeOracle::GetVoidType();
1829 "spread operators are only currently supported in indexed class field "
1830 "initialization expressions");
1833void ImplementationVisitor::GenerateImplementation(
const std::string& dir) {
1834 for (
SourceId file : SourceFileMap::AllSources()) {
1835 std::string base_filename =
1836 dir +
"/" + SourceFileMap::PathFromV8RootWithoutExtension(file);
1838 GlobalContext::GeneratedPerFile(file);
1840 std::string csa_cc = streams.
csa_ccfile.str();
1843 auto pos = csa_cc.find(BuiltinIncludesMarker);
1845 std::string includes;
1847 std::string include_file =
1848 SourceFileMap::PathFromV8RootWithoutExtension(include);
1849 includes +=
"#include \"torque-generated/";
1850 includes += include_file;
1851 includes +=
"-tq-csa.h\"\n";
1853 csa_cc.replace(
pos, strlen(BuiltinIncludesMarker), std::move(includes));
1857 WriteFile(base_filename +
"-tq-csa.cc", std::move(csa_cc));
1858 WriteFile(base_filename +
"-tq-csa.h", streams.
csa_headerfile.str());
1859 WriteFile(base_filename +
"-tq.inc",
1862 base_filename +
"-tq-inl.inc",
1869 WriteFile(dir +
"/debug-macros.h", debug_macros_h_.str());
1870 WriteFile(dir +
"/debug-macros.cc", debug_macros_cc_.str());
1875 return GenerateFunction(
nullptr,
1876 output_type_ == OutputType::kCC
1878 : output_type_ == OutputType::kCCDebug
1879 ? macro->CCDebugName()
1880 : macro->ExternalName(),
1881 macro->signature(), macro->parameter_names());
1886 const NameVector& parameter_names,
bool pass_code_assembler_state,
1887 std::vector<std::string>* generated_parameter_names) {
1889 f.SetInline(output_type_ == OutputType::kCC);
1896 }
else if (output_type_ == OutputType::kCCDebug) {
1899 }
else if (output_type_ == OutputType::kCC) {
1902 DCHECK_EQ(output_type_, OutputType::kCSA);
1908 bool ignore_first_parameter =
true;
1909 if (output_type_ == OutputType::kCCDebug) {
1911 }
else if (output_type_ == OutputType::kCSA && pass_code_assembler_state) {
1912 f.
AddParameter(
"compiler::CodeAssemblerState*",
"state_");
1914 ignore_first_parameter =
false;
1920 for (std::size_t
i = 0;
i < signature.
types().
size(); ++
i) {
1921 const Type* parameter_type = signature.
types()[
i];
1923 if (output_type_ == OutputType::kCC) {
1925 }
else if (output_type_ == OutputType::kCCDebug) {
1928 DCHECK_EQ(output_type_, OutputType::kCSA);
1936 ExternalParameterName(
i < parameter_names.size()
1937 ? parameter_names[
i]->value
1938 : std::to_string(
i)));
1942 if (output_type_ == OutputType::kCC ||
1943 output_type_ == OutputType::kCCDebug) {
1944 ReportError(
"Macros that generate runtime code can't have label exits");
1947 ExternalLabelName(label_info.
name->
value));
1949 for (
const Type* type : label_info.
types) {
1950 std::string generated_type_name;
1951 if (type->StructSupertype()) {
1952 generated_type_name =
"\n#error no structs allowed in labels\n";
1954 generated_type_name =
"compiler::TypedCodeAssemblerVariable<";
1955 generated_type_name += type->GetGeneratedTNodeTypeName();
1956 generated_type_name +=
">*";
1959 ExternalLabelParameterName(label_info.
name->
value,
i));
1964 if (generated_parameter_names) {
1966 if (ignore_first_parameter) {
1967 DCHECK(!generated_parameter_names->empty());
1968 generated_parameter_names->erase(generated_parameter_names->begin());
1976void FailCallableLookup(
1981 const std::vector<std::pair<GenericCallable*, std::string>>
1982 inapplicable_generics) {
1983 std::stringstream stream;
1984 stream <<
"\n" << reason <<
": \n " << name <<
"(" << parameter_types <<
")";
1985 if (!labels.empty()) {
1986 stream <<
" labels ";
1987 for (
size_t i = 0;
i < labels.
size(); ++
i) {
1988 stream << labels[
i]->name() <<
"(" << labels[
i]->parameter_types <<
")";
1991 stream <<
"\ncandidates are:";
1993 stream <<
"\n " <<
name;
1994 PrintSignature(stream, signature,
false);
1996 if (!inapplicable_generics.empty()) {
1997 stream <<
"\nfailed to instantiate all of these generic declarations:";
1998 for (
auto& failure : inapplicable_generics) {
1999 GenericCallable*
generic = failure.first;
2000 const std::string& fail_reason = failure.second;
2001 stream <<
"\n " <<
generic->name() <<
" defined at "
2002 << PositionAsString(generic->Position()) <<
":\n "
2003 << fail_reason <<
"\n";
2009Callable* GetOrCreateSpecialization(
2010 const SpecializationKey<GenericCallable>&
key) {
2011 if (std::optional<Callable*> specialization =
2012 key.generic->GetSpecialization(
key.specialized_types)) {
2013 return *specialization;
2015 return DeclarationVisitor::SpecializeImplicit(
key);
2020std::optional<Binding<LocalValue>*> ImplementationVisitor::TryLookupLocalValue(
2021 const std::string& name) {
2022 return ValueBindingsManager::Get().TryLookup(name);
2025std::optional<Binding<LocalLabel>*> ImplementationVisitor::TryLookupLabel(
2026 const std::string& name) {
2027 return LabelBindingsManager::Get().TryLookup(name);
2031 const std::string& name) {
2032 std::optional<Binding<LocalLabel>*>
label = TryLookupLabel(name);
2037Block* ImplementationVisitor::LookupSimpleLabel(
const std::string& name) {
2039 if (!
label->parameter_types.empty()) {
2041 "was expected to have no parameters, but has parameters (",
2042 label->parameter_types,
")");
2044 return label->block;
2050bool ImplementationVisitor::TestLookupCallable(
2052 return LookupCallable(name, Declarations::TryLookup(name), parameter_types,
2053 {}, {},
true) !=
nullptr;
2059 std::vector<std::optional<const Type*>> all_arguments;
2060 const ParameterList& parameters =
generic->declaration()->parameters;
2062 std::optional<Binding<LocalValue>*> val =
2063 TryLookupLocalValue(parameters.
names[
i]->value);
2064 all_arguments.push_back(
2065 val ? (*val)->GetLocationReference(*val).ReferencedType()
2068 for (
const Type* explicit_argument : explicit_arguments) {
2069 all_arguments.push_back(explicit_argument);
2071 return generic->InferSpecializationTypes(explicit_specialization_types,
2075template <
class Container>
2077 const QualifiedName& name,
const Container& declaration_container,
2080 const TypeVector& specialization_types,
bool silence_errors) {
2083 std::vector<Declarable*> overloads;
2084 std::vector<Signature> overload_signatures;
2085 std::vector<std::pair<GenericCallable*, std::string>> inapplicable_generics;
2086 for (
auto* declarable : declaration_container) {
2087 if (
GenericCallable* generic = GenericCallable::DynamicCast(declarable)) {
2089 generic, specialization_types, parameter_types);
2091 inapplicable_generics.push_back(
2095 overloads.push_back(generic);
2096 overload_signatures.push_back(
2097 DeclarationVisitor::MakeSpecializedSignature(
2100 }
else if (
Callable* callable = Callable::DynamicCast(declarable)) {
2101 overloads.push_back(callable);
2102 overload_signatures.push_back(callable->signature());
2107 for (
size_t i = 0;
i < overloads.size(); ++
i) {
2108 const Signature& signature = overload_signatures[
i];
2114 if (overloads.empty() && inapplicable_generics.empty()) {
2115 if (silence_errors)
return nullptr;
2116 std::stringstream stream;
2117 stream <<
"no matching declaration found for " <<
name;
2120 if (silence_errors)
return nullptr;
2121 FailCallableLookup(
"cannot find suitable callable with name", name,
2122 parameter_types, labels, overload_signatures,
2123 inapplicable_generics);
2126 auto is_better_candidate = [&](
size_t a,
size_t b) {
2130 overload_signatures[b].GetExplicitTypes(), parameter_types));
2134 is_better_candidate);
2136 DCHECK(!is_better_candidate(best, best));
2138 if (candidate != best && !is_better_candidate(best, candidate)) {
2139 std::vector<Signature> candidate_signatures;
2140 candidate_signatures.reserve(
candidates.size());
2142 candidate_signatures.push_back(overload_signatures[
i]);
2144 FailCallableLookup(
"ambiguous callable ", name, parameter_types, labels,
2145 candidate_signatures, inapplicable_generics);
2150 GenericCallable::DynamicCast(overloads[best])) {
2152 generic, specialization_types, parameter_types);
2153 result = GetOrCreateSpecialization(
2156 result = Callable::cast(overloads[best]);
2159 size_t caller_size = parameter_types.size();
2160 size_t callee_size =
2162 if (caller_size != callee_size &&
2163 !
result->signature().parameter_types.var_args) {
2164 std::stringstream stream;
2165 stream <<
"parameter count mismatch calling " << *
result <<
" - expected "
2166 << std::to_string(callee_size) <<
", found "
2167 << std::to_string(caller_size);
2174template <
class Container>
2176 const QualifiedName& name,
const Container& declaration_container,
2178 return LookupCallable(name, declaration_container,
2179 arguments.parameters.ComputeTypeVector(),
2180 arguments.labels, specialization_types);
2184 const std::string& name,
const AggregateType* receiver_type,
2186 TypeVector types(arguments.parameters.ComputeTypeVector());
2187 types.insert(types.begin(), receiver_type);
2188 return Method::cast(LookupCallable({{}, name}, receiver_type->
Methods(name),
2189 types, arguments.labels,
2190 specialization_types));
2193const Type* ImplementationVisitor::GetCommonType(
const Type* left,
2194 const Type* right) {
2195 const Type* common_type;
2199 common_type = right;
2201 common_type = TypeOracle::GetUnionType(left, right);
2219 std::vector<VisitResult> values;
2220 std::vector<const Type*> term_argument_types;
2221 values.reserve(initializers.size());
2222 term_argument_types.reserve(initializers.size());
2226 VisitResult value = Visit(initializer.expression);
2227 values.push_back(value);
2228 term_argument_types.push_back(value.type());
2232 const Type* type = TypeVisitor::ComputeTypeForStructExpression(
2233 expr->
type, term_argument_types);
2234 if (
const auto* struct_type = StructType::DynamicCast(type)) {
2235 CheckInitializersWellformed(struct_type->name(), struct_type->fields(),
2240 auto& fields = struct_type->fields();
2241 for (
size_t i = 0;
i < values.
size();
i++) {
2244 struct_range.
Extend(values[
i].stack_range());
2249 const auto* bitfield_struct_type = BitFieldStructType::cast(type);
2250 CheckInitializersWellformed(bitfield_struct_type->name(),
2251 bitfield_struct_type->fields(), initializers);
2255 result = GenerateImplicitConvert(TypeOracle::GetInt32Type(),
result);
2258 {bitfield_struct_type});
2263 auto& fields = bitfield_struct_type->fields();
2264 for (
size_t i = 0;
i < values.
size();
i++) {
2267 result = GenerateSetBitField(bitfield_struct_type, fields[
i],
result,
2276 const Type* bitfield_struct_type,
const BitField& bitfield,
2278 GenerateCopy(bitfield_struct);
2279 GenerateCopy(value);
2287 switch (location->
kind) {
2288 case AstNode::Kind::kIdentifierExpression:
2290 case AstNode::Kind::kFieldAccessExpression:
2291 return GetLocationReference(
2293 case AstNode::Kind::kElementAccessExpression:
2294 return GetLocationReference(
2296 case AstNode::Kind::kDereferenceExpression:
2297 return GetLocationReference(
2300 return LocationReference::Temporary(Visit(location),
"expression");
2306 return GenerateFieldAccess(GetLocationReference(expr->
object),
2312 bool ignore_stuct_field_constness, std::optional<SourcePosition>
pos) {
2314 reference.
variable().type()->StructSupertype()) {
2316 const Field& field = type->LookupField(fieldname);
2317 if (GlobalContext::collect_language_server_data() &&
pos.has_value()) {
2318 LanguageServerData::AddDefinition(*
pos, field.
pos);
2320 if (GlobalContext::collect_kythe_data() &&
pos.has_value()) {
2321 KytheData::AddClassFieldUse(*
pos, &field);
2325 return LocationReference::Temporary(
2328 return LocationReference::VariableAccess(
2333 reference.
temporary().type()->StructSupertype()) {
2334 if (GlobalContext::collect_language_server_data() &&
pos.has_value()) {
2336 const Field& field = type->LookupField(fieldname);
2337 LanguageServerData::AddDefinition(*
pos, field.
pos);
2339 return LocationReference::Temporary(
2343 if (std::optional<const Type*> referenced_type = reference.
ReferencedType()) {
2344 if ((*referenced_type)->IsBitFieldStructType()) {
2346 BitFieldStructType::cast(*referenced_type);
2348 return LocationReference::BitFieldAccess(reference, field);
2350 if (
const auto type_wrapped_in_smi = Type::MatchUnaryGeneric(
2351 (*referenced_type), TypeOracle::GetSmiTaggedGeneric())) {
2353 BitFieldStructType::DynamicCast(*type_wrapped_in_smi);
2354 if (bitfield_struct ==
nullptr) {
2356 "When a value of type SmiTagged<T> is used in a field access "
2357 "expression, T is expected to be a bitfield struct type. Instead, "
2360 **type_wrapped_in_smi);
2363 return LocationReference::BitFieldAccess(reference, field);
2370 TypeOracle::MatchReferenceGeneric(ref.
type(), &is_const);
2371 if (!generic_type) {
2373 "Left-hand side of field access expression is marked as a reference "
2374 "but is not of type Reference<...>. Found type: ",
2375 ref.
type()->ToString());
2377 if (
auto struct_type = (*generic_type)->StructSupertype()) {
2378 const Field& field = (*struct_type)->LookupField(fieldname);
2381 ref.
SetType(TypeOracle::GetReferenceType(
2385 if (!field.
offset.has_value()) {
2386 Error(
"accessing field with unknown offset").Throw();
2388 if (*field.
offset != 0) {
2392 ref = GenerateCopy(ref);
2395 TypeOracle::GetIntPtrType()->ConstexprVersion(),
2396 std::to_string(*field.
offset)};
2398 GenerateCall(
"+",
Arguments{{ref_offset, struct_offset}, {}});
2401 ref = scope.
Yield(ref);
2403 return LocationReference::HeapReference(ref);
2406 VisitResult object_result = GenerateFetchFromLocation(reference);
2407 if (std::optional<const ClassType*> class_type =
2408 object_result.
type()->ClassSupertype()) {
2411 bool has_explicit_overloads = TestLookupCallable(
2413 if ((*class_type)->HasField(fieldname) && !has_explicit_overloads) {
2414 const Field& field = (*class_type)->LookupField(fieldname);
2415 if (GlobalContext::collect_language_server_data() &&
pos.has_value()) {
2416 LanguageServerData::AddDefinition(*
pos, field.
pos);
2418 if (GlobalContext::collect_kythe_data()) {
2419 KytheData::AddClassFieldUse(*
pos, &field);
2421 return GenerateFieldReference(object_result, field, *class_type);
2424 return LocationReference::FieldAccess(object_result, fieldname);
2432 return GenerateReferenceToItemInHeapSlice(reference, index);
2434 return LocationReference::ArrayAccess(GenerateFetchFromLocation(reference),
2444 Method*
method = LookupMethod(
"AtIndex", slice_type, arguments, {});
2448 LocationReference::Temporary(slice.
GetVisitResult(),
"slice as value");
2449 return LocationReference::HeapReference(
2450 GenerateCall(
method, std::move(slice_value), arguments, {},
false));
2457 TryLookupLocalValue(expr->
name->
value)) {
2458 if (GlobalContext::collect_language_server_data()) {
2459 LanguageServerData::AddDefinition(expr->
name->
pos,
2460 (*value)->declaration_position());
2462 if (GlobalContext::collect_kythe_data()) {
2466 KytheData::AddBindingUse(expr->
name->
pos, *value);
2470 ReportError(
"cannot have generic parameters on local name ",
2473 return (*value)->GetLocationReference(*value);
2482 if (std::optional<Builtin*> builtin = Declarations::TryLookupBuiltin(name)) {
2483 if (GlobalContext::collect_language_server_data()) {
2484 LanguageServerData::AddDefinition(expr->
name->
pos,
2485 (*builtin)->Position());
2488 return LocationReference::Temporary(GetBuiltinCode(*builtin),
2496 if (
Builtin* builtin = Builtin::DynamicCast(specialization)) {
2497 DCHECK(!builtin->IsExternal());
2498 return LocationReference::Temporary(GetBuiltinCode(builtin),
2501 ReportError(
"cannot create function pointer for non-builtin ",
2505 Value* value = Declarations::LookupValue(name);
2506 CHECK(value->Position().source.IsValid());
2507 if (
auto stream = CurrentFileStreams::Get()) {
2508 stream->required_builtin_includes.insert(value->Position().source);
2510 if (GlobalContext::collect_language_server_data()) {
2511 LanguageServerData::AddDefinition(expr->
name->
pos, value->name()->pos);
2513 if (
auto* constant = NamespaceConstant::DynamicCast(value)) {
2514 if (GlobalContext::collect_kythe_data()) {
2515 KytheData::AddConstantUse(expr->
name->
pos, constant);
2517 if (constant->type()->IsConstexpr()) {
2518 return LocationReference::Temporary(
2519 VisitResult(constant->type(), constant->external_name() +
"(state_)"),
2520 "namespace constant " + expr->
name->
value);
2525 return LocationReference::Temporary(
2527 "namespace constant " + expr->
name->
value);
2530 if (GlobalContext::collect_kythe_data()) {
2531 KytheData::AddConstantUse(expr->
name->
pos, constant);
2533 return LocationReference::Temporary(constant->value(),
2540 if (!TypeOracle::MatchReferenceGeneric(ref.
type())) {
2541 Error(
"Operator * expects a reference type but found a value of type ",
2545 return LocationReference::HeapReference(ref);
2551 return GenerateCopy(reference.
temporary());
2553 return GenerateCopy(reference.
variable());
2556 if (referenced_type == TypeOracle::GetFloat64OrUndefinedOrHoleType()) {
2557 return GenerateCall(
QualifiedName({TORQUE_INTERNAL_NAMESPACE_STRING},
2558#ifdef V8_ENABLE_EXPERIMENTAL_UNDEFINED_DOUBLE
2559 "LoadFloat64OrUndefinedOrHole"
2567 for (
const Field& field : (*struct_type)->fields()) {
2569 const std::string& fieldname = field.name_and_type.name;
2571 GenerateFieldAccess(reference, fieldname)));
2574 return VisitResult(referenced_type, result_range);
2592 "fetching a value directly from an indexed field isn't allowed");
2596 Arguments{reference.call_arguments(), {}});
2600void ImplementationVisitor::GenerateAssignToLocation(
2604 arguments.
parameters.push_back(assignment_value);
2609 GenerateImplicitConvert(variable.
type(), assignment_value);
2616 (*reference.
binding())->SetWritten();
2619 ReportError(
"assigning a value directly to an indexed field isn't allowed");
2623 Error(
"cannot assign to const value of type ", *referenced_type).Throw();
2625 if (referenced_type == TypeOracle::GetFloat64OrUndefinedOrHoleType()) {
2628#ifdef V8_ENABLE_EXPERIMENTAL_UNDEFINED_DOUBLE
2629 "StoreFloat64OrUndefinedOrHole"
2631 "StoreFloat64OrHole"
2636 if (!assignment_value.
type()->IsSubtypeOf(referenced_type)) {
2637 ReportError(
"Cannot assign to ", *referenced_type,
2638 " with value of type ", *assignment_value.
type());
2640 for (
const Field& field : (*struct_type)->fields()) {
2641 const std::string& fieldname = field.name_and_type.name;
2644 bool ignore_stuct_field_constness =
true;
2645 GenerateAssignToLocation(
2646 GenerateFieldAccess(reference, fieldname,
2647 ignore_stuct_field_constness),
2653 GenerateImplicitConvert(referenced_type, assignment_value);
2654 if (referenced_type == TypeOracle::GetFloat64Type()) {
2656 "Float64SilenceNaN",
Arguments{{assignment_value}, {}});
2658 silenced_float_value.
stack_range(), referenced_type);
2668 GenerateImplicitConvert(*reference.
ReferencedType(), assignment_value);
2670 GenerateSetBitField(bit_field_struct.
type(), reference.
bit_field(),
2671 bit_field_struct, converted_value);
2673 updated_bit_field_struct);
2676 ReportError(
"cannot assign to const-bound or temporary ",
2684 TypeVector parameter_types(arguments.parameters.ComputeTypeVector());
2686 if (!callee_result.
type()->IsBuiltinPointerType()) {
2687 std::stringstream stream;
2688 stream <<
"Expected a function pointer type but found "
2689 << *callee_result.
type();
2693 BuiltinPointerType::cast(callee_result.
type());
2695 if (type->parameter_types().size() != parameter_types.size()) {
2696 std::stringstream stream;
2697 stream <<
"parameter count mismatch calling function pointer with Type: "
2698 << *type <<
" - expected "
2699 << std::to_string(type->parameter_types().size()) <<
", found "
2700 << std::to_string(parameter_types.size());
2708 std::stringstream stream;
2709 stream <<
"parameters do not match function pointer signature. Expected: ("
2710 << type->parameter_types() <<
") but got: (" << parameter_types
2715 callee_result = GenerateCopy(callee_result);
2717 for (
size_t current = 0; current < arguments.parameters.size(); ++
current) {
2718 const Type* to_type = type->parameter_types()[
current];
2720 GenerateImplicitConvert(to_type, arguments.parameters[current])
2728 return VisitResult::NeverResult();
2731 return scope.
Yield(
VisitResult(type->return_type(), assembler().TopRange(1)));
2734void ImplementationVisitor::AddCallParameter(
2736 std::vector<VisitResult>* converted_arguments,
StackRange* argument_range,
2737 std::vector<std::string>* constexpr_arguments,
bool inline_macro) {
2739 if ((converted_arguments->size() < callable->
signature().implicit_count) &&
2740 parameter.
type()->IsTopType()) {
2741 converted = GenerateCopy(parameter);
2743 converted = GenerateImplicitConvert(parameter_type, parameter);
2745 converted_arguments->push_back(converted);
2746 if (!inline_macro) {
2756std::pair<std::string, std::string> GetClassInstanceTypeRange(
2758 std::pair<std::string, std::string>
result;
2761 std::string instance_type_string_first =
2762 "static_cast<InstanceType>(" +
2763 std::to_string(instance_type_range.first) +
")";
2764 std::string instance_type_string_second =
2765 "static_cast<InstanceType>(" +
2766 std::to_string(instance_type_range.second) +
")";
2768 std::make_pair(instance_type_string_first, instance_type_string_second);
2771 "%Min/MaxInstanceType must take a class type that is either a string "
2772 "or has a generated instance type range");
2779 Callable* callable, std::optional<LocationReference> this_reference,
2783 if (
auto stream = CurrentFileStreams::Get()) {
2784 stream->required_builtin_includes.insert(callable->
Position().source);
2787 const Type* return_type = callable->
signature().return_type;
2790 if (
Builtin* builtin = Builtin::DynamicCast(CurrentCallable::Get())) {
2791 const Type* outer_return_type = builtin->signature().return_type;
2792 if (!return_type->
IsSubtypeOf(outer_return_type)) {
2793 Error(
"Cannot tailcall, type of result is ", *return_type,
2794 " but should be a subtype of ", *outer_return_type,
".");
2797 Error(
"Tail calls are only allowed from builtins");
2802 std::vector<VisitResult> implicit_arguments;
2803 for (
size_t i = 0;
i < callable->
signature().implicit_count; ++
i) {
2804 std::string implicit_name = callable->
signature().parameter_names[
i]->value;
2805 std::optional<Binding<LocalValue>*> val =
2806 TryLookupLocalValue(implicit_name);
2808 implicit_arguments.push_back(
2809 GenerateFetchFromLocation((*val)->GetLocationReference(*val)));
2811 VisitResult unititialized = VisitResult::TopTypeResult(
2812 "implicit parameter '" + implicit_name +
2813 "' is not defined when invoking " + callable->
ReadableName() +
2815 callable->
signature().parameter_types.types[
i]);
2816 implicit_arguments.push_back(unititialized);
2818 const Type* type = implicit_arguments.back().type();
2819 if (
const TopType* top_type = TopType::DynamicCast(type)) {
2822 "unititialized implicit parameters can only be passed to "
2823 "Torque-defined macros: the ",
2824 top_type->reason());
2826 inline_macro =
true;
2830 std::vector<VisitResult> converted_arguments;
2832 std::vector<std::string> constexpr_arguments;
2836 AddCallParameter(callable, implicit_arguments[current],
2837 callable->
signature().parameter_types.types[current],
2838 &converted_arguments, &argument_range,
2839 &constexpr_arguments, inline_macro);
2842 if (this_reference) {
2847 VisitResult this_value = this_reference->GetVisitResult();
2849 if (!this_value.
type()->IsSubtypeOf(
method->aggregate_type())) {
2850 ReportError(
"this parameter must be a subtype of ",
2851 *
method->aggregate_type(),
" but it is of type ",
2852 *this_value.
type());
2855 AddCallParameter(callable, this_value,
method->aggregate_type(),
2856 &converted_arguments, &argument_range,
2857 &constexpr_arguments, inline_macro);
2862 for (
const auto& arg : arguments.parameters) {
2864 ? TypeOracle::GetObjectType()
2865 : callable->
signature().types()[current++];
2866 AddCallParameter(callable, arg, to_type, &converted_arguments,
2867 &argument_range, &constexpr_arguments, inline_macro);
2870 size_t label_count = callable->
signature().labels.size();
2871 if (label_count != arguments.labels.size()) {
2872 std::stringstream
s;
2873 s <<
"unexpected number of otherwise labels for "
2875 << std::to_string(label_count) <<
" found "
2876 << std::to_string(arguments.labels.size()) <<
")";
2881 if (!CurrentCallable::Get()->IsTransitioning()) {
2882 std::stringstream
s;
2883 s << *CurrentCallable::Get()
2884 <<
" isn't marked transitioning but calls the transitioning "
2890 if (
auto* builtin = Builtin::DynamicCast(callable)) {
2891 std::optional<Block*> catch_block = GetCatchBlock();
2893 is_tailcall,
builtin, argument_range.
Size(), catch_block});
2894 GenerateCatchBlock(catch_block);
2896 return VisitResult::NeverResult();
2897 }
else if (return_type->
IsNever()) {
2899 return VisitResult::NeverResult();
2902 if (builtin->IsStub()) {
2903 if (slot_count < 1 || slot_count > 2) {
2905 "Builtin with stub linkage is expected to return one or two "
2906 "values but returns ",
2910 if (slot_count != 1) {
2912 "Builtin with JS linkage is expected to return one value but "
2919 }
else if (
auto* macro = Macro::DynamicCast(callable)) {
2929 if ((output_type_ == OutputType::kCC ||
2930 output_type_ == OutputType::kCCDebug) &&
2932 if (
auto* torque_macro = TorqueMacro::DynamicCast(macro)) {
2933 auto* streams = CurrentFileStreams::Get();
2934 SourceId file = streams ? streams->file : SourceId::Invalid();
2935 GlobalContext::EnsureInCCOutputList(torque_macro, file);
2942 std::stringstream
result;
2945 switch (output_type_) {
2946 case OutputType::kCSA: {
2947 if (
auto* extern_macro = ExternMacro::DynamicCast(macro)) {
2948 result << extern_macro->external_assembler_name() <<
"(state_)."
2949 << extern_macro->ExternalName() <<
"(";
2951 result << macro->ExternalName() <<
"(state_";
2956 case OutputType::kCC: {
2957 auto* extern_macro = ExternMacro::DynamicCast(macro);
2959 result << extern_macro->CCName() <<
"(";
2962 case OutputType::kCCDebug: {
2963 auto* extern_macro = ExternMacro::DynamicCast(macro);
2965 result << extern_macro->CCDebugName() <<
"(accessor";
2970 for (
const VisitResult& arg : converted_arguments) {
2971 DCHECK(!arg.IsOnStack());
2976 result << arg.constexpr_value();
2980 }
else if (inline_macro) {
2981 std::vector<Block*> label_blocks;
2982 label_blocks.reserve(arguments.labels.size());
2984 label_blocks.push_back(
label->block);
2986 return InlineMacro(macro, this_reference, converted_arguments,
2987 std::move(label_blocks));
2988 }
else if (arguments.labels.empty() &&
2989 return_type != TypeOracle::GetNeverType()) {
2990 std::optional<Block*> catch_block = GetCatchBlock();
2992 macro, std::move(constexpr_arguments), catch_block});
2993 GenerateCatchBlock(catch_block);
2997 std::optional<Block*> return_continuation;
2998 if (return_type != TypeOracle::GetNeverType()) {
2999 return_continuation =
assembler().NewBlock();
3002 std::vector<Block*> label_blocks;
3004 for (
size_t i = 0;
i < label_count; ++
i) {
3005 label_blocks.push_back(
assembler().NewBlock());
3007 std::optional<Block*> catch_block = GetCatchBlock();
3009 macro, constexpr_arguments, return_continuation, label_blocks,
3011 GenerateCatchBlock(catch_block);
3013 for (
size_t i = 0;
i < label_count; ++
i) {
3015 size_t callee_label_parameters =
3016 callable->
signature().labels[
i].types.size();
3017 if (
label->parameter_types.size() != callee_label_parameters) {
3018 std::stringstream
s;
3019 s <<
"label " <<
label->name()
3020 <<
" doesn't have the right number of parameters (found "
3021 << std::to_string(
label->parameter_types.size()) <<
" expected "
3022 << std::to_string(callee_label_parameters) <<
")";
3031 for (
auto t : callable->
signature().labels[
i].types) {
3032 const Type* parameter_type =
label->parameter_types[j];
3033 if (!t->IsSubtypeOf(parameter_type)) {
3034 ReportError(
"mismatch of label parameters (label expects ",
3035 *parameter_type,
" but macro produces ", *t,
3036 " for parameter ",
i + 1,
")");
3042 if (return_continuation) {
3046 assembler().TopRange(return_slot_count));
3048 return VisitResult::NeverResult();
3051 }
else if (
auto* runtime_function = RuntimeFunction::DynamicCast(callable)) {
3052 std::optional<Block*> catch_block = GetCatchBlock();
3054 is_tailcall, runtime_function, argument_range.
Size(), catch_block});
3055 GenerateCatchBlock(catch_block);
3056 if (is_tailcall || return_type == TypeOracle::GetNeverType()) {
3057 return VisitResult::NeverResult();
3065 }
else if (
auto* intrinsic = Intrinsic::DynamicCast(callable)) {
3066 if (intrinsic->ExternalName() ==
"%SizeOf") {
3067 if (specialization_types.size() != 1) {
3068 ReportError(
"%SizeOf must take a single type parameter");
3070 const Type* type = specialization_types[0];
3071 std::string size_string;
3072 if (std::optional<std::tuple<size_t, std::string>> size =
SizeOf(type)) {
3073 size_string = std::get<1>(*size);
3075 Error(
"size of ", *type,
" is not known.");
3078 }
else if (intrinsic->ExternalName() ==
"%ClassHasMapConstant") {
3079 const Type* type = specialization_types[0];
3080 const ClassType* class_type = ClassType::DynamicCast(type);
3082 ReportError(
"%ClassHasMapConstant must take a class type parameter");
3089 return VisitResult(return_type, std::string(
"false"));
3093 std::string(
"CodeStubAssembler(state_).ClassHasMapConstant<") +
3094 class_type->
name() +
">()");
3096 }
else if (intrinsic->ExternalName() ==
"%MinInstanceType") {
3097 if (specialization_types.size() != 1) {
3098 ReportError(
"%MinInstanceType must take a single type parameter");
3100 const Type* type = specialization_types[0];
3101 const ClassType* class_type = ClassType::DynamicCast(type);
3103 ReportError(
"%MinInstanceType must take a class type parameter");
3105 std::pair<std::string, std::string> instance_types =
3106 GetClassInstanceTypeRange(class_type);
3107 return VisitResult(return_type, instance_types.first);
3108 }
else if (intrinsic->ExternalName() ==
"%MaxInstanceType") {
3109 if (specialization_types.size() != 1) {
3110 ReportError(
"%MaxInstanceType must take a single type parameter");
3112 const Type* type = specialization_types[0];
3113 const ClassType* class_type = ClassType::DynamicCast(type);
3115 ReportError(
"%MaxInstanceType must take a class type parameter");
3117 std::pair<std::string, std::string> instance_types =
3118 GetClassInstanceTypeRange(class_type);
3119 return VisitResult(return_type, instance_types.second);
3120 }
else if (intrinsic->ExternalName() ==
"%RawConstexprCast") {
3121 if (intrinsic->signature().parameter_types.types.size() != 1 ||
3122 constexpr_arguments.size() != 1) {
3124 "%RawConstexprCast must take a single parameter with constexpr "
3128 std::stringstream
s;
3130 <<
" return type for %RawConstexprCast is not constexpr";
3133 std::stringstream
result;
3135 result << constexpr_arguments[0];
3138 }
else if (intrinsic->ExternalName() ==
"%IndexedFieldLength") {
3139 const Type* type = specialization_types[0];
3140 const ClassType* class_type = ClassType::DynamicCast(type);
3142 ReportError(
"%IndexedFieldLength must take a class type parameter");
3144 const Field& field =
3146 return GenerateArrayLength(
VisitResult(type, argument_range), field);
3147 }
else if (intrinsic->ExternalName() ==
"%MakeLazy") {
3148 if (specialization_types[0]->IsStructType()) {
3149 ReportError(
"%MakeLazy can't use macros that return structs");
3155 QualifiedName qualified_getter_name = QualifiedName::Parse(getter_name);
3162 converted_arguments.begin() + 1, converted_arguments.end());
3164 Callable* callable_macro = LookupCallable(
3165 qualified_getter_name, Declarations::Lookup(qualified_getter_name),
3166 arguments_to_getter, {});
3167 Macro*
getter = Macro::DynamicCast(callable_macro);
3170 "%MakeLazy expects a macro, not builtin or other type of callable");
3172 if (!
getter->signature().labels.empty()) {
3173 ReportError(
"%MakeLazy requires a macro with no labels");
3175 if (!
getter->signature().return_type->IsSubtypeOf(
3176 specialization_types[0])) {
3177 ReportError(
"%MakeLazy expected return type ", *specialization_types[0],
3178 " but found ", *
getter->signature().return_type);
3180 if (
getter->signature().implicit_count > 0) {
3181 ReportError(
"Implicit parameters are not yet supported in %MakeLazy");
3190 std::vector<VisitResult> converted_arguments_for_getter;
3192 std::vector<std::string> constexpr_arguments_for_getter;
3194 size_t arg_count = 0;
3195 for (
const auto& arg : arguments_to_getter.
parameters) {
3197 const Type* to_type =
getter->signature().types()[arg_count++];
3198 AddCallParameter(
getter, arg, to_type, &converted_arguments_for_getter,
3199 &argument_range_for_getter,
3200 &constexpr_arguments_for_getter,
3207 getter, return_type, std::move(constexpr_arguments_for_getter)});
3209 }
else if (intrinsic->ExternalName() ==
"%FieldSlice") {
3210 const Type* type = specialization_types[0];
3211 const ClassType* class_type = ClassType::DynamicCast(type);
3213 ReportError(
"The first type parameter to %FieldSlice must be a class");
3215 const Field& field =
3217 const Type* expected_slice_type =
3221 const Type* declared_slice_type = specialization_types[1];
3222 if (expected_slice_type != declared_slice_type) {
3224 "The second type parameter to %FieldSlice must be the precise "
3225 "slice type for the named field");
3228 VisitResult(type, argument_range), field, class_type,
3231 ReportError(
"%FieldSlice expected an indexed or optional field");
3236 constexpr_arguments});
3237 size_t return_slot_count =
3248 const TypeVector& specialization_types,
bool is_tailcall) {
3250 LookupCallable(callable_name, Declarations::Lookup(callable_name),
3251 arguments, specialization_types);
3252 return GenerateCall(callable, std::nullopt, arguments, specialization_types,
3261 if (
auto* loc_expr = LocationExpression::DynamicCast(expr->
arguments[0])) {
3266 ReportError(
"Unable to create a heap reference.");
3274 bool has_template_arguments = !specialization_types.empty();
3276 arguments.parameters.push_back(Visit(arg));
3277 arguments.labels = LabelsFromIdentifiers(expr->
labels);
3278 if (!has_template_arguments && name.namespace_qualification.empty() &&
3279 TryLookupLocalValue(name.name)) {
3281 GeneratePointerCall(expr->
callee, arguments, is_tailcall));
3283 if (GlobalContext::collect_language_server_data()) {
3284 Callable* callable = LookupCallable(name, Declarations::Lookup(name),
3285 arguments, specialization_types);
3289 if (GlobalContext::collect_kythe_data()) {
3290 Callable* callable = LookupCallable(name, Declarations::Lookup(name),
3291 arguments, specialization_types);
3292 Callable* caller = CurrentCallable::Get();
3293 KytheData::AddCall(caller, expr->
callee->
name->
pos, callable);
3295 if (expr->
callee->
name->
value ==
"!" && arguments.parameters.size() == 1) {
3296 PropagateBitfieldMark(expr->
arguments[0], expr);
3298 if (expr->
callee->
name->
value ==
"==" && arguments.parameters.size() == 2) {
3299 if (arguments.parameters[0].type()->IsConstexpr()) {
3300 PropagateBitfieldMark(expr->
arguments[1], expr);
3301 }
else if (arguments.parameters[1].type()->IsConstexpr()) {
3302 PropagateBitfieldMark(expr->
arguments[0], expr);
3306 GenerateCall(name, arguments, specialization_types, is_tailcall));
3317 if (!target.IsVariableAccess()) {
3319 target = LocationReference::Temporary(
result,
"this parameter");
3324 ReportError(
"target of method call not a struct or class type");
3327 arguments.parameters.push_back(Visit(arg));
3329 arguments.labels = LabelsFromIdentifiers(expr->
labels);
3330 TypeVector argument_types = arguments.parameters.ComputeTypeVector();
3333 Callable* callable = LookupMethod(method_name, target_type, arguments, {});
3334 if (GlobalContext::collect_language_server_data()) {
3338 if (GlobalContext::collect_kythe_data()) {
3339 Callable* caller = CurrentCallable::Get();
3340 KytheData::AddCall(caller, expr->
method->
name->
pos, callable);
3342 return scope.
Yield(GenerateCall(callable, target, arguments, {},
false));
3351 arguments.parameters.push_back(Visit(arg));
3353 GenerateCall(expr->
name->
value, arguments, specialization_types,
false));
3358 Block* false_block) {
3361 assembler().Branch(true_block, false_block);
3364VisitResult ImplementationVisitor::GenerateBoolConstant(
bool constant) {
3365 return GenerateImplicitConvert(TypeOracle::GetBoolType(),
3367 constant ?
"true" :
"false"));
3370void ImplementationVisitor::GenerateExpressionBranch(
Expression* expression,
3372 Block* false_block) {
3374 VisitResult expression_result = this->Visit(expression);
3375 expression_result = stack_scope.
Yield(
3376 GenerateImplicitConvert(TypeOracle::GetBoolType(), expression_result));
3377 GenerateBranch(expression_result, true_block, false_block);
3383 if (source.type() == TypeOracle::GetNeverType()) {
3384 ReportError(
"it is not allowed to use a value of type never");
3387 if (destination_type == source.type()) {
3388 return scope.
Yield(GenerateCopy(source));
3391 if (
auto from = TypeOracle::ImplicitlyConvertableFrom(destination_type,
3393 return scope.
Yield(GenerateCall(kFromConstexprMacroName,
3395 {destination_type, *from},
false));
3397 source.SetType(destination_type);
3398 return scope.
Yield(GenerateCopy(source));
3400 std::stringstream
s;
3401 if (
const TopType* top_type = TopType::DynamicCast(source.type())) {
3402 s <<
"undefined expression of type " << *destination_type <<
": the "
3403 << top_type->reason();
3405 s <<
"cannot use expression of type " << *source.type()
3406 <<
" as a value of type " << *destination_type;
3414 return assembler().Goto(
label->block, arguments ? arguments->Size() : 0);
3417std::vector<Binding<LocalLabel>*> ImplementationVisitor::LabelsFromIdentifiers(
3418 const std::vector<Identifier*>& names) {
3419 std::vector<Binding<LocalLabel>*>
result;
3421 for (
const auto& name : names) {
3428 if (GlobalContext::collect_language_server_data()) {
3429 LanguageServerData::AddDefinition(name->pos,
3430 label->declaration_position());
3438 const Type* type,
const std::string& parameter_name,
3440 if (std::optional<const StructType*> struct_type = type->StructSupertype()) {
3442 for (
auto& field : (*struct_type)->fields()) {
3444 field.name_and_type.type,
3445 parameter_name +
"." + field.name_and_type.name, lowered_parameters);
3446 range.Extend(parameter_range);
3450 lowered_parameters->
Push(parameter_name);
3451 return lowered_parameters->
TopRange(1);
3455void ImplementationVisitor::LowerLabelParameter(
3456 const Type* type,
const std::string& parameter_name,
3457 std::vector<std::string>* lowered_parameters) {
3458 if (std::optional<const StructType*> struct_type = type->StructSupertype()) {
3459 for (
auto& field : (*struct_type)->fields()) {
3460 LowerLabelParameter(
3461 field.name_and_type.type,
3462 "&((*" + parameter_name +
")." + field.name_and_type.name +
")",
3463 lowered_parameters);
3466 lowered_parameters->push_back(parameter_name);
3470std::string ImplementationVisitor::ExternalLabelName(
3471 const std::string& label_name) {
3472 return "label_" + label_name;
3475std::string ImplementationVisitor::ExternalLabelParameterName(
3476 const std::string& label_name,
size_t i) {
3477 return "label_" + label_name +
"_parameter_" + std::to_string(
i);
3480std::string ImplementationVisitor::ExternalParameterName(
3481 const std::string& name) {
3482 return std::string(
"p_") +
name;
3486 size_t label_count) {
3487 auto i =
sig.parameter_types.types.begin() +
sig.implicit_count;
3488 if ((
sig.parameter_types.types.size() -
sig.implicit_count) > types.size())
3490 if (
sig.labels.size() != label_count)
return false;
3491 for (
auto current : types) {
3492 if (
i ==
sig.parameter_types.types.end()) {
3493 if (!
sig.parameter_types.var_args)
return false;
3502std::optional<Block*> ImplementationVisitor::GetCatchBlock() {
3503 std::optional<Block*> catch_block;
3504 if (TryLookupLabel(kCatchLabelName)) {
3505 catch_block =
assembler().NewBlock(std::nullopt,
true);
3510void ImplementationVisitor::GenerateCatchBlock(
3511 std::optional<Block*> catch_block) {
3513 std::optional<Binding<LocalLabel>*> catch_handler =
3514 TryLookupLabel(kCatchLabelName);
3518 if (
assembler().CurrentBlockIsComplete()) {
3520 GenerateCall(
QualifiedName({TORQUE_INTERNAL_NAMESPACE_STRING},
3521 "GetAndResetPendingMessage"),
3523 assembler().Goto((*catch_handler)->block, 2);
3526 GenerateCall(
QualifiedName({TORQUE_INTERNAL_NAMESPACE_STRING},
3527 "GetAndResetPendingMessage"),
3529 assembler().Goto((*catch_handler)->block, 2);
3533void ImplementationVisitor::VisitAllDeclarables() {
3534 CurrentCallable::Scope current_callable(
nullptr);
3535 const std::vector<std::unique_ptr<Declarable>>& all_declarables =
3536 GlobalContext::AllDeclarables();
3540 for (
size_t i = 0;
i < all_declarables.size(); ++
i) {
3542 Visit(all_declarables[
i].get());
3549 output_type_ = OutputType::kCC;
3550 const std::vector<std::pair<TorqueMacro*, SourceId>>& cc_macros =
3551 GlobalContext::AllMacrosForCCOutput();
3552 for (
size_t i = 0;
i < cc_macros.size(); ++
i) {
3562 output_type_ = OutputType::kCCDebug;
3563 const std::vector<std::pair<TorqueMacro*, SourceId>>& cc_debug_macros =
3564 GlobalContext::AllMacrosForCCDebugOutput();
3565 for (
size_t i = 0;
i < cc_debug_macros.size(); ++
i) {
3567 Visit(
static_cast<Declarable*
>(cc_debug_macros[
i].first),
3574 output_type_ = OutputType::kCSA;
3578 std::optional<SourceId> file) {
3579 CurrentScope::Scope current_scope(declarable->
ParentScope());
3580 CurrentSourcePosition::Scope current_source_position(declarable->
Position());
3581 CurrentFileStreams::Scope current_file_streams(
3582 &GlobalContext::GeneratedPerFile(file ? *file
3584 if (
Callable* callable = Callable::DynamicCast(declarable)) {
3585 if (!callable->ShouldGenerateExternalCode(output_type_))
3586 CurrentFileStreams::Get() =
nullptr;
3588 switch (declarable->
kind()) {
3589 case Declarable::kExternMacro:
3590 return Visit(ExternMacro::cast(declarable));
3591 case Declarable::kTorqueMacro:
3592 return Visit(TorqueMacro::cast(declarable));
3593 case Declarable::kMethod:
3594 return Visit(Method::cast(declarable));
3595 case Declarable::kBuiltin:
3596 return Visit(Builtin::cast(declarable));
3597 case Declarable::kTypeAlias:
3598 return Visit(TypeAlias::cast(declarable));
3599 case Declarable::kNamespaceConstant:
3600 return Visit(NamespaceConstant::cast(declarable));
3601 case Declarable::kRuntimeFunction:
3602 case Declarable::kIntrinsic:
3603 case Declarable::kExternConstant:
3604 case Declarable::kNamespace:
3605 case Declarable::kGenericCallable:
3606 case Declarable::kGenericType:
3612 if (type->IsSubtypeOf(TypeOracle::GetSmiType())) {
3613 return "MachineType::TaggedSigned()";
3615 if (type->IsSubtypeOf(TypeOracle::GetHeapObjectType())) {
3616 return "MachineType::TaggedPointer()";
3618 if (type->IsSubtypeOf(TypeOracle::GetTaggedType())) {
3619 return "MachineType::AnyTagged()";
3621 return "MachineTypeOf<" + type->GetGeneratedTNodeTypeName() +
">::value";
3624void ImplementationVisitor::GenerateBuiltinDefinitionsAndInterfaceDescriptors(
3625 const std::string& output_directory) {
3626 std::stringstream builtin_definitions;
3627 std::string builtin_definitions_file_name =
"builtin-definitions.h";
3632 std::stringstream interface_descriptors;
3633 std::string interface_descriptors_file_name =
"interface-descriptors.inc";
3636 builtin_definitions, builtin_definitions_file_name);
3640 "#define BUILTIN_LIST_FROM_TORQUE(CPP, TFJ, TFC, TFS, TFH, "
3643 for (
auto& declarable : GlobalContext::AllDeclarables()) {
3644 Builtin* builtin = Builtin::DynamicCast(declarable.get());
3645 if (!builtin || builtin->IsExternal())
continue;
3646 if (builtin->IsStub()) {
3647 builtin_definitions <<
"TFC(" << builtin->ExternalName() <<
", "
3648 << builtin->ExternalName();
3649 if (!builtin->HasCustomInterfaceDescriptor()) {
3650 std::string descriptor_name = builtin->ExternalName() +
"Descriptor";
3651 bool has_context_parameter =
3652 builtin->signature().HasContextParameter();
3653 size_t kFirstNonContextParameter = has_context_parameter ? 1 : 0;
3656 interface_descriptors <<
"class " << descriptor_name
3657 <<
" : public StaticCallInterfaceDescriptor<"
3658 << descriptor_name <<
"> {\n";
3660 interface_descriptors <<
" public:\n";
3664 interface_descriptors <<
" INTERNAL_DESCRIPTOR()\n";
3666 if (has_context_parameter) {
3667 interface_descriptors <<
" DEFINE_RESULT_AND_PARAMETERS(";
3669 interface_descriptors
3670 <<
" DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(";
3672 interface_descriptors << return_types.size();
3673 for (
size_t i = kFirstNonContextParameter;
3674 i < builtin->parameter_names().
size(); ++
i) {
3675 Identifier* parameter = builtin->parameter_names()[
i];
3678 interface_descriptors <<
")\n";
3680 interface_descriptors <<
" DEFINE_RESULT_AND_PARAMETER_TYPES(";
3683 bool is_first = return_types.empty();
3684 for (
size_t i = kFirstNonContextParameter;
3685 i < builtin->parameter_names().
size(); ++
i) {
3686 const Type* type = builtin->signature().parameter_types.types[
i];
3687 interface_descriptors << (is_first ?
"" :
", ")
3691 interface_descriptors <<
")\n";
3693 interface_descriptors <<
" DECLARE_DEFAULT_DESCRIPTOR("
3694 << descriptor_name <<
")\n";
3695 interface_descriptors <<
"};\n\n";
3698 builtin_definitions <<
"TFJ(" << builtin->ExternalName();
3699 if (builtin->IsVarArgsJavaScript()) {
3700 builtin_definitions <<
", kDontAdaptArgumentsSentinel";
3702 DCHECK(builtin->IsFixedArgsJavaScript());
3706 static_cast<int>(builtin->signature().ExplicitCount());
3710 builtin_definitions <<
", kReceiver";
3711 for (
size_t i = builtin->signature().implicit_count;
3712 i < builtin->parameter_names().
size(); ++
i) {
3713 Identifier* parameter = builtin->parameter_names()[
i];
3718 builtin_definitions <<
") \\\n";
3720 builtin_definitions <<
"\n";
3723 <<
"#define TORQUE_FUNCTION_POINTER_TYPE_TO_BUILTIN_MAP(V) \\\n";
3725 TypeOracle::AllBuiltinPointerTypes()) {
3727 Declarations::FindSomeInternalBuiltinWithType(type);
3728 if (!example_builtin) {
3729 CurrentSourcePosition::Scope current_source_position(
3730 SourcePosition{CurrentSourceFile::Get(), LineAndColumn::Invalid(),
3731 LineAndColumn::Invalid()});
3732 ReportError(
"unable to find any builtin with type \"", *type,
"\"");
3734 builtin_definitions <<
" V(" << type->function_pointer_type_id() <<
","
3737 builtin_definitions <<
"\n";
3739 WriteFile(output_directory +
"/" + builtin_definitions_file_name,
3740 builtin_definitions.str());
3741 WriteFile(output_directory +
"/" + interface_descriptors_file_name,
3742 interface_descriptors.str());
3747enum class FieldSectionType : uint32_t {
3749 kWeakSection = 1 << 0,
3750 kStrongSection = 2 << 0,
3751 kScalarSection = 3 << 0
3754bool IsPointerSection(FieldSectionType type) {
3755 return type == FieldSectionType::kWeakSection ||
3756 type == FieldSectionType::kStrongSection;
3761std::string
ToString(FieldSectionType type) {
3763 case FieldSectionType::kNoSection:
3765 case FieldSectionType::kWeakSection:
3766 return "WeakFields";
3767 case FieldSectionType::kStrongSection:
3768 return "StrongFields";
3769 case FieldSectionType::kScalarSection:
3770 return "ScalarFields";
3775class FieldOffsetsGenerator {
3777 explicit FieldOffsetsGenerator(
const ClassType* type) :
type_(type) {}
3779 virtual void WriteField(
const Field& f,
const std::string& size_string) = 0;
3780 virtual void WriteFieldOffsetGetter(
const Field& f) = 0;
3781 virtual void WriteMarker(
const std::string& marker) = 0;
3785 void RecordOffsetFor(
const Field& f) {
3791 WriteMarker(
"kHeaderSize");
3797 std::string size_string =
"0";
3798 if (!f.index.has_value()) {
3800 std::tie(field_size, size_string) = f.GetFieldSizeInformation();
3802 if (f.offset.has_value()) {
3803 WriteField(f, size_string);
3805 WriteFieldOffsetGetter(f);
3812 Begin(FieldSectionType::kWeakSection);
3813 End(FieldSectionType::kWeakSection);
3816 Begin(FieldSectionType::kStrongSection);
3817 End(FieldSectionType::kStrongSection);
3824 WriteMarker(
"kHeaderSize");
3826 if (!
type_->IsAbstract() &&
type_->HasStaticSize()) {
3827 WriteMarker(
"kSize");
3835 FieldSectionType GetSectionFor(
const Field& f) {
3836 const Type* field_type = f.name_and_type.type;
3837 if (field_type == TypeOracle::GetVoidType()) {
3841 StructType::Classification struct_contents =
3842 StructType::ClassificationFlag::kEmpty;
3843 if (
auto field_as_struct = field_type->StructSupertype()) {
3844 struct_contents = (*field_as_struct)->ClassifyContents();
3846 if ((struct_contents & StructType::ClassificationFlag::kStrongTagged) &&
3847 (struct_contents & StructType::ClassificationFlag::kWeakTagged)) {
3850 struct_contents &= ~StructType::Classification(
3851 StructType::ClassificationFlag::kStrongTagged);
3853 bool struct_contains_tagged_fields =
3854 (struct_contents & StructType::ClassificationFlag::kStrongTagged) ||
3855 (struct_contents & StructType::ClassificationFlag::kWeakTagged);
3856 if (struct_contains_tagged_fields &&
3857 (struct_contents & StructType::ClassificationFlag::kUntagged)) {
3861 "Classes do not support fields which are structs containing both "
3862 "tagged and untagged data.")
3865 if ((field_type->IsSubtypeOf(TypeOracle::GetStrongTaggedType()) ||
3866 struct_contents == StructType::ClassificationFlag::kStrongTagged) &&
3867 !f.custom_weak_marking) {
3868 return FieldSectionType::kStrongSection;
3869 }
else if (field_type->IsSubtypeOf(TypeOracle::GetTaggedType()) ||
3870 struct_contains_tagged_fields) {
3871 return FieldSectionType::kWeakSection;
3873 return FieldSectionType::kScalarSection;
3876 void UpdateSection(
const Field& f) {
3877 FieldSectionType type = GetSectionFor(f);
3879 if (IsPointerSection(type)) {
3881 std::stringstream
s;
3882 s <<
"cannot declare field " << f.name_and_type.name <<
" in class "
3884 <<
" to which it belongs has already been finished.";
3885 Error(s.str()).Position(f.pos);
3892 void Begin(FieldSectionType type) {
3893 DCHECK(type != FieldSectionType::kNoSection);
3894 if (!IsPointerSection(type))
return;
3895 WriteMarker(
"kStartOf" +
ToString(type) +
"Offset");
3897 void End(FieldSectionType type) {
3898 if (!IsPointerSection(type))
return;
3900 WriteMarker(
"kEndOf" +
ToString(type) +
"Offset");
3909void GenerateClassExport(
const ClassType* type, std::ostream& header,
3910 std::ostream& inl_header) {
3911 const ClassType* super = type->GetSuperClass();
3912 std::string parent =
"TorqueGenerated" + type->name() +
"<" + type->name() +
3913 ", " + super->name() +
">";
3914 header <<
"class " << type->name() <<
" : public " << parent <<
" {\n";
3915 header <<
" public:\n";
3916 if (type->ShouldGenerateBodyDescriptor()) {
3917 header <<
" class BodyDescriptor;\n";
3919 header <<
" TQ_OBJECT_CONSTRUCTORS(" << type->name() <<
")\n";
3921 inl_header <<
"TQ_OBJECT_CONSTRUCTORS_IMPL(" << type->name() <<
")\n";
3926void ImplementationVisitor::GenerateVisitorLists(
3927 const std::string& output_directory) {
3928 std::stringstream header;
3929 std::string file_name =
"visitor-lists.h";
3933 header <<
"#define TORQUE_INSTANCE_TYPE_TO_BODY_DESCRIPTOR_LIST(V)\\\n";
3934 for (
const ClassType* type : TypeOracle::GetClasses()) {
3935 if (type->ShouldGenerateBodyDescriptor() && type->OwnInstanceType()) {
3936 std::string type_name =
3938 header <<
"V(" << type_name <<
"," << type->name() <<
")\\\n";
3943 header <<
"#define TORQUE_DATA_ONLY_VISITOR_ID_LIST(V)\\\n";
3944 for (
const ClassType* type : TypeOracle::GetClasses()) {
3945 if (type->ShouldGenerateBodyDescriptor() &&
3946 type->HasNoPointerSlotsExceptMap()) {
3947 header <<
"V(" << type->name() <<
")\\\n";
3952 header <<
"#define TORQUE_POINTER_VISITOR_ID_LIST(V)\\\n";
3953 for (
const ClassType* type : TypeOracle::GetClasses()) {
3954 if (type->ShouldGenerateBodyDescriptor() &&
3955 !type->HasNoPointerSlotsExceptMap()) {
3956 header <<
"V(" << type->name() <<
")\\\n";
3961 const std::string output_header_path = output_directory +
"/" + file_name;
3962 WriteFile(output_header_path, header.str());
3965void ImplementationVisitor::GenerateBitFields(
3966 const std::string& output_directory) {
3967 std::stringstream header;
3968 std::string file_name =
"bit-fields.h";
3971 header <<
"#include \"src/base/bit-field.h\"\n\n";
3974 for (
const auto& type : TypeOracle::GetBitFieldStructTypes()) {
3975 bool all_single_bits =
true;
3976 header <<
"// " << type->GetPosition() <<
"\n";
3977 header <<
"#define DEFINE_TORQUE_GENERATED_"
3979 std::string type_name = type->GetConstexprGeneratedTypeName();
3980 for (
const auto& field : type->fields()) {
3981 const char* suffix = field.num_bits == 1 ?
"Bit" :
"Bits";
3982 all_single_bits = all_single_bits && field.num_bits == 1;
3983 std::string field_type_name =
3984 field.name_and_type.type->GetConstexprGeneratedTypeName();
3986 << suffix <<
" = base::BitField<" << field_type_name <<
", "
3987 << field.offset <<
", " << field.num_bits <<
", " << type_name
3992 if (all_single_bits) {
3993 header <<
" enum Flag: " << type_name <<
" { \\\n";
3994 header <<
" kNone = 0, \\\n";
3995 for (
const auto& field : type->fields()) {
3996 header <<
" k" <<
CamelifyString(field.name_and_type.name) <<
" = "
3997 << type_name <<
"{1} << " << field.offset <<
", \\\n";
3999 header <<
" }; \\\n";
4000 header <<
" using Flags = base::Flags<Flag>; \\\n";
4001 header <<
" static constexpr int kFlagCount = "
4002 << type->fields().size() <<
"; \\\n";
4008 const std::string output_header_path = output_directory +
"/" + file_name;
4009 WriteFile(output_header_path, header.str());
4014class ClassFieldOffsetGenerator :
public FieldOffsetsGenerator {
4016 ClassFieldOffsetGenerator(std::ostream& header, std::ostream& inline_header,
4017 const ClassType* type, std::string gen_name,
4018 const ClassType* parent,
bool use_templates =
true)
4019 : FieldOffsetsGenerator(type),
4021 inl_(inline_header),
4025 void WriteField(
const Field& f,
const std::string& size_string)
override {
4026 hdr_ <<
" // " << f.pos <<
"\n";
4027 std::string field =
"k" + CamelifyString(f.name_and_type.name) +
"Offset";
4028 std::string field_end = field +
"End";
4031 hdr_ <<
" static constexpr int " << field_end <<
" = " << field <<
" + "
4032 << size_string <<
" - 1;\n";
4036 void WriteFieldOffsetGetter(
const Field& f)
override {
4039 DCHECK(!f.offset.has_value());
4041 std::string function_name = CamelifyString(f.name_and_type.name) +
"Offset";
4043 std::vector<cpp::TemplateParameter> params = {cpp::TemplateParameter(
"D"),
4044 cpp::TemplateParameter(
"P")};
4045 cpp::Class owner(std::move(params),
gen_name_);
4047 auto getter = cpp::Function::DefaultGetter(
"int", &owner, function_name);
4049 getter.PrintDefinition(
inl_, [&](std::ostream& stream) {
4051 stream <<
" return static_cast<int>(std::get<1>("
4052 << Callable::PrefixNameForCCOutput(
type_->GetSliceMacroName(f))
4053 <<
"(*static_cast<const D*>(this))));\n";
4056 void WriteMarker(
const std::string& marker)
override {
4062 static std::string FirstFieldStart(
const ClassType* type,
4063 const ClassType* parent,
4064 bool use_templates =
true) {
4065 std::string parent_name = use_templates ?
"P" : parent->name();
4067 if (type->IsLayoutDefinedInCpp()) {
4071 if (parent_name ==
"HeapObject" || parent_name ==
"TrustedObject" ||
4072 parent_name ==
"Struct") {
4073 parent_name +=
"Layout";
4076 return "sizeof(" + parent_name +
")";
4079 if (parent && parent->IsShape()) {
4080 return parent_name +
"::kSize";
4082 return parent_name +
"::kHeaderSize";
4091class CppClassGenerator {
4093 CppClassGenerator(
const ClassType* type, std::ostream& header,
4094 std::ostream& inl_header, std::ostream&
impl)
4096 super_(type->GetSuperClass()),
4097 name_(type->name()),
4104 const std::string template_decl()
const {
4105 return "template <class D, class P>";
4108 void GenerateClass();
4109 void GenerateCppObjectDefinitionAsserts();
4110 void GenerateCppObjectLayoutDefinitionAsserts();
4113 SourcePosition Position();
4115 void GenerateClassConstructors();
4121 void GenerateFieldAccessors(
const Field& class_field,
4122 std::vector<const Field*>& struct_fields);
4123 void EmitLoadFieldStatement(std::ostream& stream,
const Field& class_field,
4124 std::vector<const Field*>& struct_fields);
4125 void EmitStoreFieldStatement(std::ostream& stream,
const Field& class_field,
4126 std::vector<const Field*>& struct_fields);
4128 std::string GetFieldOffsetForAccessor(
const Field& f);
4132 std::string GetTypeNameForAccessor(
const Field& f);
4134 bool CanContainHeapObjects(
const Type* t);
4136 const ClassType*
type_;
4147std::optional<std::vector<Field>> GetOrderedUniqueIndexFields(
4148 const ClassType& type) {
4149 std::vector<Field>
result;
4150 std::set<std::string> index_names;
4151 for (
const Field& field : type.ComputeAllFields()) {
4155 return std::nullopt;
4161 for (
const Field& field : type.ComputeAllFields()) {
4162 if (index_names.count(field.name_and_type.name) != 0) {
4170void CppClassGenerator::GenerateClass() {
4172 if (!
type_->IsShape()) {
4173 cpp::Function f(
"Is"s +
name_ +
"_NonInline");
4174 f.SetDescription(
"Alias for Is"s +
name_ +
"() that avoids inlining.");
4176 f.SetReturnType(
"bool");
4177 f.AddParameter(
"Tagged<HeapObject>",
"o");
4179 f.PrintDeclaration(
hdr_);
4181 f.PrintDefinition(
impl_, [&](std::ostream& stream) {
4182 stream <<
" return Is" <<
name_ <<
"(o);\n";
4185 hdr_ <<
"// Definition " << Position() <<
"\n";
4186 hdr_ << template_decl() <<
"\n";
4188 hdr_ <<
" static_assert(\n"
4189 <<
" std::is_same<" <<
name_ <<
", D>::value,\n"
4190 <<
" \"Use this class as direct base for " <<
name_ <<
".\");\n";
4191 hdr_ <<
" static_assert(\n"
4192 <<
" std::is_same<" <<
super_->name() <<
", P>::value,\n"
4193 <<
" \"Pass in " <<
super_->name()
4194 <<
" as second template parameter for " <<
gen_name_ <<
".\");\n\n";
4195 hdr_ <<
" public: \n";
4196 hdr_ <<
" using Super = P;\n";
4197 hdr_ <<
" using TorqueGeneratedClass = " <<
gen_name_ <<
"<D,P>;\n\n";
4198 if (!
type_->ShouldExport() && !
type_->IsExtern()) {
4199 hdr_ <<
" protected: // not extern or @export\n";
4201 for (
const Field& f :
type_->fields()) {
4202 CurrentSourcePosition::Scope scope(f.pos);
4203 std::vector<const Field*> struct_fields;
4204 GenerateFieldAccessors(f, struct_fields);
4206 if (!
type_->ShouldExport() && !
type_->IsExtern()) {
4207 hdr_ <<
" public:\n";
4210 std::vector<cpp::TemplateParameter> templateArgs = {
4211 cpp::TemplateParameter(
"D"), cpp::TemplateParameter(
"P")};
4212 cpp::Class c(std::move(templateArgs),
gen_name_);
4214 if (
type_->ShouldGeneratePrint()) {
4215 hdr_ <<
" DECL_PRINTER(" <<
name_ <<
")\n\n";
4218 if (
type_->ShouldGenerateVerify()) {
4219 IfDefScope hdr_scope(
hdr_,
"VERIFY_HEAP");
4221 cpp::Function f(&c,
name_ +
"Verify");
4223 f.SetReturnType(
"void");
4224 f.AddParameter(
"Isolate*",
"isolate");
4225 f.PrintDeclaration(
hdr_);
4227 IfDefScope impl_scope(
impl_,
"VERIFY_HEAP");
4228 impl_ <<
"\ntemplate <>\n";
4230 <<
"Verify(Isolate* isolate) {\n";
4231 impl_ <<
" TorqueGeneratedClassVerifiers::" <<
name_ <<
"Verify(Cast<"
4241 type_->GetSuperClass());
4242 for (
const auto& f :
type_->fields()) {
4243 CurrentSourcePosition::Scope scope(f.pos);
4244 g.RecordOffsetFor(f);
4249 auto index_fields = GetOrderedUniqueIndexFields(*
type_);
4251 if (!index_fields.has_value()) {
4252 hdr_ <<
" // SizeFor implementations not generated due to complex array "
4255 const Field& last_field =
type_->LastField();
4256 std::string last_field_item_size =
4257 std::get<1>(*
SizeOf(last_field.name_and_type.type));
4262 cpp::Function::DefaultGetter(
"int", &c,
"AllocatedSize");
4263 f.PrintDeclaration(
hdr_);
4265 f.PrintDefinition(
inl_, [&](std::ostream& stream) {
4266 stream <<
" auto slice = "
4267 << Callable::PrefixNameForCCOutput(
4268 type_->GetSliceMacroName(last_field))
4269 <<
"(*static_cast<const D*>(this));\n";
4270 stream <<
" return static_cast<int>(std::get<1>(slice)) + "
4271 << last_field_item_size
4272 <<
" * static_cast<int>(std::get<2>(slice));\n";
4275 }
else if (
type_->ShouldGenerateBodyDescriptor() ||
4276 (!
type_->IsAbstract() &&
4277 !
type_->IsSubtypeOf(TypeOracle::GetJSObjectType()))) {
4278 cpp::Function f(&c,
"SizeFor");
4279 f.SetReturnType(
"int32_t");
4280 f.SetFlags(cpp::Function::kStatic | cpp::Function::kConstexpr |
4281 cpp::Function::kV8Inline);
4282 for (
const Field& field : *index_fields) {
4283 f.AddParameter(
"int", field.name_and_type.name);
4285 f.PrintInlineDefinition(
hdr_, [&](std::ostream& stream) {
4286 if (index_fields->empty()) {
4287 stream <<
" DCHECK(kHeaderSize == kSize && kHeaderSize == "
4288 << *
type_->size().SingleValue() <<
");\n";
4290 stream <<
" int32_t size = kHeaderSize;\n";
4291 for (
const Field& field :
type_->ComputeAllFields()) {
4293 auto index_name_and_type =
4295 stream <<
" size += " << index_name_and_type.name <<
" * "
4296 << std::get<0>(field.GetFieldSizeInformation()) <<
";\n";
4299 if (
type_->size().Alignment() < TargetArchitecture::TaggedSize()) {
4300 stream <<
" size = OBJECT_POINTER_ALIGN(size);\n";
4302 stream <<
" return size;\n";
4307 cpp::Function allocated_size_f =
4308 cpp::Function::DefaultGetter(
"int32_t", &c,
"AllocatedSize");
4309 allocated_size_f.SetFlag(cpp::Function::kV8Inline);
4310 allocated_size_f.PrintInlineDefinition(
hdr_, [&](std::ostream& stream) {
4311 stream <<
" return SizeFor(";
4313 for (
const auto& field : *index_fields) {
4314 if (!first) stream <<
", ";
4315 stream <<
"this->" << field.name_and_type.name <<
"()";
4323 hdr_ <<
" friend class Factory;\n\n";
4325 GenerateClassConstructors();
4329 if (
type_->ShouldGenerateFullClassDefinition()) {
4336 std::optional<const ClassType*> parent =
type_->parent()->ClassSupertype();
4338 if ((*parent)->ShouldGenerateCppClassDefinitions() &&
4339 !(*parent)->ShouldGenerateFullClassDefinition() &&
4340 (*parent)->AttributedToFile() ==
type_->AttributedToFile()) {
4341 Error(
"Exported ", *
type_,
4342 " cannot be in the same file as its parent extern ", **parent);
4344 parent = (*parent)->parent()->ClassSupertype();
4351void CppClassGenerator::GenerateCppObjectDefinitionAsserts() {
4352 impl_ <<
"// Definition " << Position() <<
"\n"
4353 <<
"class " <<
gen_name_ <<
"Asserts {\n";
4356 type_->GetSuperClass(),
false);
4357 for (
const auto& f :
type_->fields()) {
4358 CurrentSourcePosition::Scope scope(f.pos);
4359 g.RecordOffsetFor(f);
4364 for (
const auto& f :
type_->fields()) {
4365 std::string field_offset =
4367 impl_ <<
" static_assert(" << field_offset <<
" == " <<
name_
4368 <<
"::" << field_offset <<
",\n"
4369 <<
" \"Values of " <<
name_ <<
"::" << field_offset
4370 <<
" defined in Torque and C++ do not match\");\n";
4372 if (!
type_->IsAbstract() &&
type_->HasStaticSize()) {
4373 impl_ <<
" static_assert(kSize == " <<
name_ <<
"::kSize);\n";
4379void CppClassGenerator::GenerateCppObjectLayoutDefinitionAsserts() {
4380 impl_ <<
"// Definition " << Position() <<
"\n"
4381 <<
"class " <<
gen_name_ <<
"Asserts {\n";
4384 type_->GetSuperClass(),
false);
4385 for (
const auto& f :
type_->fields()) {
4386 CurrentSourcePosition::Scope scope(f.pos);
4387 g.RecordOffsetFor(f);
4392 for (
const auto& f :
type_->fields()) {
4393 std::string field_offset =
4395 std::string cpp_field_offset =
4397 ?
"OFFSET_OF_DATA_START(" +
name_ +
")"
4398 :
"offsetof(" +
name_ +
", " + f.name_and_type.name +
"_)";
4399 impl_ <<
" static_assert(" << field_offset <<
" == " << cpp_field_offset
4401 <<
" \"Value of " <<
name_ <<
"::" << field_offset
4402 <<
" defined in Torque and offset of field " <<
name_
4403 <<
"::" << f.name_and_type.name <<
" in C++ do not match\");\n";
4405 if (!
type_->IsAbstract() &&
type_->HasStaticSize()) {
4406 impl_ <<
" static_assert(kSize == sizeof(" +
name_ +
"));\n";
4412SourcePosition CppClassGenerator::Position() {
return type_->GetPosition(); }
4414void CppClassGenerator::GenerateClassConstructors() {
4415 const ClassType* typecheck_type =
type_;
4416 while (typecheck_type->IsShape()) {
4417 typecheck_type = typecheck_type->GetSuperClass();
4424 hdr_ <<
" template <class DAlias = D>\n";
4426 hdr_ <<
" static_assert(\n";
4427 hdr_ <<
" std::is_base_of<" <<
gen_name_ <<
", DAlias>::value,\n";
4429 <<
" should be used as direct base for " <<
name_ <<
".\");\n";
4432 hdr_ <<
" protected:\n";
4434 <<
"(Address ptr, typename P::SkipTypeCheckTag\n)";
4435 hdr_ <<
" : P(ptr, typename P::SkipTypeCheckTag{}) {}\n";
4436 hdr_ <<
" inline explicit " <<
gen_name_ <<
"(Address ptr);\n";
4438 inl_ <<
"template<class D, class P>\n";
4440 inl_ <<
" : P(ptr) {\n";
4441 inl_ <<
" SLOW_DCHECK(Is" << typecheck_type->name()
4442 <<
"_NonInline(*this));\n";
4447std::string GenerateRuntimeTypeCheck(
const Type* type,
4448 const std::string& value) {
4449 bool maybe_object = !type->IsSubtypeOf(TypeOracle::GetStrongTaggedType());
4450 std::stringstream type_check;
4451 bool at_start =
true;
4454 type_check << value <<
".IsCleared()";
4457 for (
const TypeChecker& runtime_type : type->GetTypeCheckers()) {
4458 if (!at_start) type_check <<
" || ";
4461 bool strong = runtime_type.weak_ref_to.empty();
4462 if (strong && runtime_type.type == WEAK_HEAP_OBJECT) {
4466 type_check << value <<
".IsWeak()";
4468 type_check <<
"(" << (strong ?
"!" :
"") << value <<
".IsWeak() && Is"
4469 << (strong ? runtime_type.type : runtime_type.weak_ref_to)
4470 <<
"(" << value <<
".GetHeapObjectOrSmi()))";
4473 type_check <<
"Is" << runtime_type.type <<
"(" << value <<
")";
4476 return type_check.str();
4479void GenerateBoundsDCheck(std::ostream& os,
const std::string& index,
4480 const ClassType* type,
const Field& f) {
4481 os <<
" DCHECK_GE(" << index <<
", 0);\n";
4482 std::string length_expression;
4483 if (std::optional<NameAndType> array_length =
4485 length_expression =
"this ->" + array_length->name +
"()";
4489 "static_cast<int>(std::get<2>(" +
4490 Callable::PrefixNameForCCOutput(type->GetSliceMacroName(f)) +
4491 "(*static_cast<const D*>(this))))";
4493 os <<
" DCHECK_LT(" << index <<
", " << length_expression <<
");\n";
4496bool CanGenerateFieldAccessors(
const Type* field_type) {
4500 return field_type != TypeOracle::GetVoidType() &&
4501 field_type != TypeOracle::GetFloat64OrUndefinedOrHoleType() &&
4502 !field_type->IsSubtypeOf(TypeOracle::GetExternalPointerType()) &&
4503 !field_type->IsSubtypeOf(TypeOracle::GetTrustedPointerType()) &&
4504 !field_type->IsSubtypeOf(TypeOracle::GetProtectedPointerType());
4509void CppClassGenerator::GenerateFieldAccessors(
4510 const Field& class_field, std::vector<const Field*>& struct_fields) {
4511 const Field& innermost_field =
4512 struct_fields.empty() ? class_field : *struct_fields.back();
4513 const Type* field_type = innermost_field.name_and_type.type;
4514 if (!CanGenerateFieldAccessors(field_type))
return;
4516 if (
const StructType* struct_type = StructType::DynamicCast(field_type)) {
4517 struct_fields.resize(struct_fields.size() + 1);
4518 for (
const Field& struct_field : struct_type->fields()) {
4519 struct_fields[struct_fields.size() - 1] = &struct_field;
4520 GenerateFieldAccessors(class_field, struct_fields);
4522 struct_fields.resize(struct_fields.size() - 1);
4526 bool indexed = class_field.index && !class_field.index->optional;
4527 std::string type_name = GetTypeNameForAccessor(innermost_field);
4528 bool can_contain_heap_objects = CanContainHeapObjects(field_type);
4532 std::string name = class_field.name_and_type.name;
4533 for (
const Field* nested_struct_field : struct_fields) {
4534 name +=
"_" + nested_struct_field->name_and_type.name;
4538 if (can_contain_heap_objects && !field_type->IsClassType() &&
4539 !field_type->IsStructType() &&
4540 field_type != TypeOracle::GetObjectType()) {
4541 hdr_ <<
" // Torque type: " << field_type->ToString() <<
"\n";
4544 std::vector<cpp::TemplateParameter> templateParameters = {
4545 cpp::TemplateParameter(
"D"), cpp::TemplateParameter(
"P")};
4546 cpp::Class owner(std::move(templateParameters),
gen_name_);
4550 auto getter = cpp::Function::DefaultGetter(type_name, &owner, name);
4552 getter.AddParameter(
"int",
"i");
4554 const char* tag_argument;
4555 switch (class_field.synchronization) {
4556 case FieldSynchronization::kNone:
4559 case FieldSynchronization::kRelaxed:
4560 getter.AddParameter(
"RelaxedLoadTag");
4561 tag_argument =
", kRelaxedLoad";
4563 case FieldSynchronization::kAcquireRelease:
4564 getter.AddParameter(
"AcquireLoadTag");
4565 tag_argument =
", kAcquireLoad";
4573 if (can_contain_heap_objects) {
4574 getter.PrintDefinition(
inl_, [&](
auto& stream) {
4576 <<
" PtrComprCageBase cage_base = GetPtrComprCageBase(*this);\n";
4577 stream <<
" return " <<
gen_name_ <<
"::" << name <<
"(cage_base"
4578 << (indexed ?
", i" :
"") << tag_argument <<
");\n";
4581 getter.InsertParameter(0,
"PtrComprCageBase",
"cage_base");
4585 getter.PrintDefinition(
inl_, [&](
auto& stream) {
4586 EmitLoadFieldStatement(stream, class_field, struct_fields);
4587 stream <<
" return value;\n";
4593 auto setter = cpp::Function::DefaultSetter(
4594 &owner, std::string(
"set_") + name, type_name,
"value");
4596 setter.InsertParameter(0,
"int",
"i");
4598 switch (class_field.synchronization) {
4599 case FieldSynchronization::kNone:
4601 case FieldSynchronization::kRelaxed:
4602 setter.AddParameter(
"RelaxedStoreTag");
4604 case FieldSynchronization::kAcquireRelease:
4605 setter.AddParameter(
"ReleaseStoreTag");
4608 if (can_contain_heap_objects) {
4609 setter.AddParameter(
"WriteBarrierMode",
"mode",
"UPDATE_WRITE_BARRIER");
4613 setter.PrintDefinition(
inl_, [&](
auto& stream) {
4614 EmitStoreFieldStatement(stream, class_field, struct_fields);
4621std::string CppClassGenerator::GetFieldOffsetForAccessor(
const Field& f) {
4622 if (f.offset.has_value()) {
4628std::string CppClassGenerator::GetTypeNameForAccessor(
const Field& f) {
4629 const Type* field_type = f.name_and_type.type;
4630 if (!field_type->IsSubtypeOf(TypeOracle::GetTaggedType())) {
4631 const Type* constexpr_version = field_type->ConstexprVersion();
4632 if (!constexpr_version) {
4633 Error(
"Field accessor for ",
type_->name(),
":: ", f.name_and_type.name,
4634 " cannot be generated because its type ", *field_type,
4635 " is neither a subclass of Object nor does the type have a "
4641 return constexpr_version->GetGeneratedTypeName();
4643 return field_type->TagglifiedCppTypeName();
4646bool CppClassGenerator::CanContainHeapObjects(
const Type* t) {
4647 return t->IsSubtypeOf(TypeOracle::GetTaggedType()) &&
4648 !t->IsSubtypeOf(TypeOracle::GetSmiType());
4651void CppClassGenerator::EmitLoadFieldStatement(
4652 std::ostream& stream,
const Field& class_field,
4653 std::vector<const Field*>& struct_fields) {
4654 const Field& innermost_field =
4655 struct_fields.empty() ? class_field : *struct_fields.back();
4656 const Type* field_type = innermost_field.name_and_type.type;
4657 std::string type_name = GetTypeNameForAccessor(innermost_field);
4658 const std::string class_field_size =
4659 std::get<1>(class_field.GetFieldSizeInformation());
4664 std::string field_offset = GetFieldOffsetForAccessor(class_field);
4665 for (
const Field* nested_struct_field : struct_fields) {
4666 field_offset +=
" + " + std::to_string(*nested_struct_field->offset);
4669 std::string
offset = field_offset;
4670 if (class_field.index) {
4671 const char* index = class_field.index->optional ?
"0" :
"i";
4672 GenerateBoundsDCheck(stream, index,
type_, class_field);
4673 stream <<
" int offset = " << field_offset <<
" + " << index <<
" * "
4674 << class_field_size <<
";\n";
4678 stream <<
" " << type_name <<
" value = ";
4680 if (!field_type->IsSubtypeOf(TypeOracle::GetTaggedType())) {
4682 switch (class_field.synchronization) {
4683 case FieldSynchronization::kNone:
4686 case FieldSynchronization::kRelaxed:
4687 load =
"Relaxed_ReadField";
4689 case FieldSynchronization::kAcquireRelease:
4690 ReportError(
"Torque doesn't support @cppAcquireLoad on untagged data");
4692 stream <<
"this->template " << load <<
"<" << type_name <<
">(" <<
offset
4696 switch (class_field.synchronization) {
4697 case FieldSynchronization::kNone:
4700 case FieldSynchronization::kRelaxed:
4701 load =
"Relaxed_Load";
4703 case FieldSynchronization::kAcquireRelease:
4704 load =
"Acquire_Load";
4707 bool is_smi = field_type->IsSubtypeOf(TypeOracle::GetSmiType());
4708 const std::string load_type = is_smi ?
"Smi" : type_name;
4709 const char* postfix = is_smi ?
".value()" :
"";
4710 const char* optional_cage_base = is_smi ?
"" :
"cage_base, ";
4712 stream <<
"TaggedField<" << load_type <<
">::" << load <<
"("
4713 << optional_cage_base <<
"*this, " <<
offset <<
")" << postfix
4717 if (CanContainHeapObjects(field_type)) {
4718 stream <<
" DCHECK(" << GenerateRuntimeTypeCheck(field_type,
"value")
4723void CppClassGenerator::EmitStoreFieldStatement(
4724 std::ostream& stream,
const Field& class_field,
4725 std::vector<const Field*>& struct_fields) {
4726 const Field& innermost_field =
4727 struct_fields.empty() ? class_field : *struct_fields.back();
4728 const Type* field_type = innermost_field.name_and_type.type;
4729 std::string type_name = GetTypeNameForAccessor(innermost_field);
4730 const std::string class_field_size =
4731 std::get<1>(class_field.GetFieldSizeInformation());
4736 std::string field_offset = GetFieldOffsetForAccessor(class_field);
4737 for (
const Field* nested_struct_field : struct_fields) {
4738 field_offset +=
" + " + std::to_string(*nested_struct_field->offset);
4741 std::string
offset = field_offset;
4742 if (class_field.index) {
4743 const char* index = class_field.index->optional ?
"0" :
"i";
4744 GenerateBoundsDCheck(stream, index,
type_, class_field);
4745 stream <<
" int offset = " << field_offset <<
" + " << index <<
" * "
4746 << class_field_size <<
";\n";
4750 if (!field_type->IsSubtypeOf(TypeOracle::GetTaggedType())) {
4752 switch (class_field.synchronization) {
4753 case FieldSynchronization::kNone:
4754 store =
"WriteField";
4756 case FieldSynchronization::kRelaxed:
4757 store =
"Relaxed_WriteField";
4759 case FieldSynchronization::kAcquireRelease:
4760 ReportError(
"Torque doesn't support @cppReleaseStore on untagged data");
4762 stream <<
" this->template " << store <<
"<" << type_name <<
">(" <<
offset
4765 bool strong_pointer = field_type->IsSubtypeOf(TypeOracle::GetObjectType());
4766 bool is_smi = field_type->IsSubtypeOf(TypeOracle::GetSmiType());
4767 const char* write_macro;
4768 if (!strong_pointer) {
4769 if (class_field.synchronization ==
4770 FieldSynchronization::kAcquireRelease) {
4771 ReportError(
"Torque doesn't support @cppReleaseStore on weak fields");
4773 write_macro =
"RELAXED_WRITE_WEAK_FIELD";
4775 switch (class_field.synchronization) {
4776 case FieldSynchronization::kNone:
4777 write_macro =
"WRITE_FIELD";
4779 case FieldSynchronization::kRelaxed:
4780 write_macro =
"RELAXED_WRITE_FIELD";
4782 case FieldSynchronization::kAcquireRelease:
4783 write_macro =
"RELEASE_WRITE_FIELD";
4787 std::string value_to_write;
4788 if (
const auto type_wrapped_in_smi = Type::MatchUnaryGeneric(
4789 field_type, TypeOracle::GetSmiTaggedGeneric())) {
4791 stream <<
" // " << type_wrapped_in_smi.value()->ToString() <<
"\n";
4792 value_to_write =
"Smi::From31BitPattern(value)";
4794 value_to_write = is_smi ?
"Smi::FromInt(value)" :
"value";
4801 "SLOW_DCHECK(!IsolateGroup::current()->shared_read_only_heap()-"
4802 ">roots_init_complete() || ("
4803 << GenerateRuntimeTypeCheck(field_type,
"value") <<
"));\n";
4805 stream <<
" " << write_macro <<
"(*this, " <<
offset <<
", "
4806 << value_to_write <<
");\n";
4808 stream <<
" CONDITIONAL_WRITE_BARRIER(*this, " <<
offset
4809 <<
", value, mode);\n";
4814void GenerateStructLayoutDescription(std::ostream& header,
4815 const StructType* type) {
4816 header <<
"struct TorqueGenerated" <<
CamelifyString(type->name())
4818 for (
const Field& field : type->fields()) {
4819 header <<
" static constexpr int k"
4821 <<
"Offset = " << *field.offset <<
";\n";
4823 header <<
" static constexpr int kSize = " << type->PackedSize() <<
";\n";
4829void ImplementationVisitor::GenerateClassDefinitions(
4830 const std::string& output_directory) {
4831 std::stringstream factory_header;
4832 std::stringstream factory_impl;
4833 std::string factory_basename =
"factory";
4835 std::stringstream forward_declarations;
4836 std::string forward_declarations_filename =
"class-forward-declarations.h";
4839 factory_impl <<
"#include \"src/heap/factory-base.h\"\n";
4840 factory_impl <<
"#include \"src/heap/factory-base-inl.h\"\n";
4841 factory_impl <<
"#include \"src/heap/heap.h\"\n";
4842 factory_impl <<
"#include \"src/heap/heap-inl.h\"\n";
4843 factory_impl <<
"#include \"src/execution/isolate.h\"\n";
4844 factory_impl <<
"#include "
4845 "\"src/objects/all-objects-inl.h\"\n\n";
4846 NamespaceScope factory_impl_namespaces(factory_impl, {
"v8",
"internal"});
4847 factory_impl <<
"\n";
4850 forward_declarations_filename);
4851 NamespaceScope forward_declarations_namespaces(forward_declarations,
4852 {
"v8",
"internal"});
4854 std::set<const StructType*, TypeLess> structs_used_in_classes;
4857 for (
const ClassType* type : TypeOracle::GetClasses()) {
4858 CurrentSourcePosition::Scope position_activator(type->GetPosition());
4859 auto& streams = GlobalContext::GeneratedPerFile(type->AttributedToFile());
4860 std::ostream& header = streams.class_definition_headerfile;
4861 std::string name = type->ShouldGenerateCppClassDefinitions()
4863 : type->GetGeneratedTNodeTypeName();
4864 if (type->ShouldGenerateCppClassDefinitions()) {
4865 header <<
"class " << name <<
";\n";
4867 forward_declarations <<
"class " << name <<
";\n";
4870 for (
const ClassType* type : TypeOracle::GetClasses()) {
4871 CurrentSourcePosition::Scope position_activator(type->GetPosition());
4872 auto& streams = GlobalContext::GeneratedPerFile(type->AttributedToFile());
4873 std::ostream& header = streams.class_definition_headerfile;
4874 std::ostream& inline_header = streams.class_definition_inline_headerfile;
4875 std::ostream& implementation = streams.class_definition_ccfile;
4877 if (type->ShouldGenerateCppClassDefinitions()) {
4878 CppClassGenerator g(type, header, inline_header, implementation);
4880 }
else if (type->ShouldGenerateCppObjectDefinitionAsserts()) {
4881 CppClassGenerator g(type, header, inline_header, implementation);
4882 g.GenerateCppObjectDefinitionAsserts();
4883 }
else if (type->ShouldGenerateCppObjectLayoutDefinitionAsserts()) {
4884 CppClassGenerator g(type, header, inline_header, implementation);
4885 g.GenerateCppObjectLayoutDefinitionAsserts();
4887 for (
const Field& f : type->fields()) {
4888 const Type* field_type = f.name_and_type.type;
4890 structs_used_in_classes.insert(*field_as_struct);
4893 if (type->ShouldGenerateFactoryFunction()) {
4894 std::string return_type =
4895 type->HandlifiedCppTypeName(Type::HandleKind::kIndirect);
4896 std::string function_name =
"New" + type->name();
4897 std::stringstream parameters;
4898 for (
const Field& f : type->ComputeAllFields()) {
4899 if (f.name_and_type.name ==
"map")
continue;
4900 if (f.name_and_type.name ==
"self_indirect_pointer")
continue;
4902 std::string type_string =
4903 f.name_and_type.type->HandlifiedCppTypeName(
4904 Type::HandleKind::kDirect);
4905 parameters << type_string <<
" " << f.name_and_type.name <<
", ";
4908 parameters <<
"AllocationType allocation_type";
4910 factory_header << return_type <<
" " << function_name <<
"("
4911 << parameters.str() <<
");\n";
4912 factory_impl <<
"template <typename Impl>\n";
4913 factory_impl << return_type
4914 <<
" TorqueGeneratedFactory<Impl>::" << function_name
4915 <<
"(" << parameters.str() <<
") {\n";
4917 factory_impl <<
" int size = ";
4919 std::string gen_name =
"TorqueGenerated" + type->name();
4920 std::string gen_name_T =
4921 gen_name +
"<" + type->name() +
", " + super->
name() +
">";
4922 factory_impl << gen_name_T <<
"::SizeFor(";
4925 auto index_fields = GetOrderedUniqueIndexFields(*type);
4926 CHECK(index_fields.has_value());
4927 for (
const auto& index_field : *index_fields) {
4929 factory_impl <<
", ";
4931 factory_impl << index_field.name_and_type.name;
4935 factory_impl <<
");\n";
4936 factory_impl <<
" Tagged<Map> map = factory()->read_only_roots()."
4938 factory_impl <<
" Tagged<HeapObject> raw_object =\n";
4939 factory_impl <<
" factory()->AllocateRawWithImmortalMap(size, "
4940 "allocation_type, map);\n";
4941 factory_impl <<
" " << type->TagglifiedCppTypeName()
4942 <<
" result = Cast<"
4943 << type->GetConstexprGeneratedTypeName()
4944 <<
">(raw_object);\n";
4945 factory_impl <<
" DisallowGarbageCollection no_gc;\n";
4946 factory_impl <<
" WriteBarrierMode write_barrier_mode =\n"
4947 <<
" allocation_type == AllocationType::kYoung\n"
4948 <<
" ? SKIP_WRITE_BARRIER : UPDATE_WRITE_BARRIER;\n"
4949 <<
" USE(write_barrier_mode);\n";
4951 for (
const Field& f : type->ComputeAllFields()) {
4952 if (f.name_and_type.name ==
"map")
continue;
4953 if (f.name_and_type.name ==
"self_indirect_pointer") {
4955 "result->init_self_indirect_pointer(factory()->"
4957 }
else if (!f.index) {
4958 factory_impl <<
" result->TorqueGeneratedClass::set_"
4960 if (f.name_and_type.type->IsSubtypeOf(
4961 TypeOracle::GetTaggedType()) &&
4962 !f.name_and_type.type->IsSubtypeOf(TypeOracle::GetSmiType())) {
4963 factory_impl <<
"*" << f.name_and_type.name
4964 <<
", write_barrier_mode";
4966 factory_impl << f.name_and_type.name;
4968 factory_impl <<
");\n";
4972 factory_impl <<
" return handle(result, factory()->isolate());\n";
4973 factory_impl <<
"}\n\n";
4975 factory_impl <<
"template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) "
4977 <<
" TorqueGeneratedFactory<Factory>::" << function_name
4978 <<
"(" << parameters.str() <<
");\n";
4979 factory_impl <<
"template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) "
4980 << return_type <<
" TorqueGeneratedFactory<LocalFactory>::"
4981 << function_name <<
"(" << parameters.str() <<
");\n";
4983 factory_impl <<
"\n\n";
4987 for (
const StructType* type : structs_used_in_classes) {
4988 CurrentSourcePosition::Scope position_activator(type->GetPosition());
4989 std::ostream& header =
4990 GlobalContext::GeneratedPerFile(type->GetPosition().source)
4991 .class_definition_headerfile;
4992 if (type != TypeOracle::GetFloat64OrUndefinedOrHoleType()) {
4993 GenerateStructLayoutDescription(header, type);
4997 WriteFile(output_directory +
"/" + factory_basename +
".inc",
4998 factory_header.str());
4999 WriteFile(output_directory +
"/" + factory_basename +
".cc",
5000 factory_impl.str());
5001 WriteFile(output_directory +
"/" + forward_declarations_filename,
5002 forward_declarations.str());
5006void GeneratePrintDefinitionsForClass(std::ostream& impl,
const ClassType* type,
5007 const std::string& gen_name,
5008 const std::string& gen_name_T,
5009 const std::string template_params) {
5010 impl << template_params <<
"\n";
5011 impl <<
"void " << gen_name_T <<
"::" << type->name()
5012 <<
"Print(std::ostream& os) {\n";
5013 impl <<
" this->PrintHeader(os, \"" << type->name() <<
"\");\n";
5014 auto hierarchy = type->GetHierarchy();
5015 std::map<std::string, const AggregateType*> field_names;
5017 for (
const Field& f : aggregate_type->fields()) {
5018 if (f.name_and_type.name ==
"map" || f.index.has_value() ||
5019 !CanGenerateFieldAccessors(f.name_and_type.type)) {
5022 std::string
getter = f.name_and_type.name;
5023 if (aggregate_type != type) {
5026 getter = aggregate_type->name() +
"::TorqueGeneratedClass::" +
getter;
5028 if (f.name_and_type.type->IsSubtypeOf(TypeOracle::GetSmiType()) ||
5029 !f.name_and_type.type->IsSubtypeOf(TypeOracle::GetTaggedType())) {
5030 impl <<
" os << \"\\n - " << f.name_and_type.name <<
": \" << ";
5031 if (f.name_and_type.type->StructSupertype()) {
5033 impl <<
"\" <struct field printing still unimplemented>\";\n";
5035 impl <<
"this->" <<
getter;
5036 switch (f.synchronization) {
5037 case FieldSynchronization::kNone:
5040 case FieldSynchronization::kRelaxed:
5041 impl <<
"(kRelaxedLoad);\n";
5043 case FieldSynchronization::kAcquireRelease:
5044 impl <<
"(kAcquireLoad);\n";
5049 impl <<
" os << \"\\n - " << f.name_and_type.name <<
": \" << "
5050 <<
"Brief(this->" <<
getter;
5051 switch (f.synchronization) {
5052 case FieldSynchronization::kNone:
5055 case FieldSynchronization::kRelaxed:
5056 impl <<
"(kRelaxedLoad));\n";
5058 case FieldSynchronization::kAcquireRelease:
5059 impl <<
"(kAcquireLoad));\n";
5065 impl <<
" os << '\\n';\n";
5070void ImplementationVisitor::GeneratePrintDefinitions(
5071 const std::string& output_directory) {
5072 std::stringstream impl;
5073 std::string file_name =
"objects-printer.cc";
5075 IfDefScope object_print(impl,
"OBJECT_PRINT");
5077 impl <<
"#include <iosfwd>\n\n";
5078 impl <<
"#include \"src/objects/all-objects-inl.h\"\n\n";
5082 for (
const ClassType* type : TypeOracle::GetClasses()) {
5083 if (!type->ShouldGeneratePrint())
continue;
5084 DCHECK(type->ShouldGenerateCppClassDefinitions());
5086 std::string gen_name =
"TorqueGenerated" + type->name();
5087 std::string gen_name_T =
5088 gen_name +
"<" + type->name() +
", " + super->
name() +
">";
5089 std::string template_decl =
"template <>";
5090 GeneratePrintDefinitionsForClass(impl, type, gen_name, gen_name_T,
5095 std::string new_contents(impl.str());
5096 WriteFile(output_directory +
"/" + file_name, new_contents);
5100 std::vector<ObjectSlotKind> slots = type->ComputeHeaderSlotKinds();
5101 if (!type->HasStaticSize()) {
5102 slots.push_back(*type->ComputeArraySlotKind());
5107 while (
i < slots.
size() && slots[
i] == ObjectSlotKind::kNoPointer) ++
i;
5108 if (
i == slots.
size())
return "DataOnlyBodyDescriptor";
5109 bool has_weak_pointers =
false;
5110 size_t start_index =
i;
5111 for (;
i < slots.
size(); ++
i) {
5112 if (slots[
i] == ObjectSlotKind::kStrongPointer) {
5114 }
else if (slots[
i] == ObjectSlotKind::kMaybeObjectPointer) {
5115 has_weak_pointers =
true;
5116 }
else if (slots[
i] == ObjectSlotKind::kNoPointer) {
5119 return std::nullopt;
5122 size_t end_index =
i;
5123 for (;
i < slots.
size(); ++
i) {
5124 if (slots[
i] != ObjectSlotKind::kNoPointer)
return std::nullopt;
5126 size_t start_offset = start_index * TargetArchitecture::TaggedSize();
5127 size_t end_offset = end_index * TargetArchitecture::TaggedSize();
5130 if (end_index == slots.size()) {
5131 return ToString(
"SuffixRange", has_weak_pointers ?
"Weak" :
"",
5132 "BodyDescriptor<", start_offset,
">");
5134 if (!has_weak_pointers) {
5135 return ToString(
"FixedRangeBodyDescriptor<", start_offset,
", ", end_offset,
5138 return std::nullopt;
5141void ImplementationVisitor::GenerateBodyDescriptors(
5142 const std::string& output_directory) {
5143 std::string file_name =
"objects-body-descriptors-inl.inc";
5144 std::stringstream h_contents;
5146 for (
const ClassType* type : TypeOracle::GetClasses()) {
5147 std::string name = type->name();
5148 if (!type->ShouldGenerateBodyDescriptor())
continue;
5150 bool has_array_fields = !type->HasStaticSize();
5151 std::vector<ObjectSlotKind> header_slot_kinds =
5152 type->ComputeHeaderSlotKinds();
5153 std::optional<ObjectSlotKind> array_slot_kind =
5154 type->ComputeArraySlotKind();
5155 DCHECK_EQ(has_array_fields, array_slot_kind.has_value());
5157 h_contents <<
"class " << name <<
"::BodyDescriptor final : public ";
5159 h_contents << *descriptor_name <<
" {\n";
5160 h_contents <<
" public:\n";
5162 h_contents <<
"BodyDescriptorBase {\n";
5163 h_contents <<
" public:\n";
5165 h_contents <<
" template <typename ObjectVisitor>\n";
5167 <<
" static inline void IterateBody(Tagged<Map> map, "
5168 "Tagged<HeapObject> obj, int object_size, ObjectVisitor* v) {\n";
5170 std::vector<ObjectSlotKind> slots = std::move(header_slot_kinds);
5171 if (has_array_fields) slots.push_back(*array_slot_kind);
5174 slots.erase(slots.begin());
5175 size_t start_offset = TargetArchitecture::TaggedSize();
5177 size_t end_offset = start_offset;
5179 for (
size_t i = 0;
i <= slots.
size(); ++
i) {
5180 std::optional<ObjectSlotKind> next_section_kind;
5181 bool finished_section =
false;
5183 next_section_kind = slots[
i];
5184 }
else if (
i < slots.
size()) {
5185 if (
auto combined =
Combine(section_kind, slots[
i])) {
5186 next_section_kind = *combined;
5188 next_section_kind = slots[
i];
5189 finished_section =
true;
5192 finished_section =
true;
5194 if (finished_section) {
5195 bool is_array_slot =
i == slots.
size() && has_array_fields;
5196 bool multiple_slots =
5198 (end_offset - start_offset > TargetArchitecture::TaggedSize());
5199 std::optional<std::string> iterate_command;
5200 switch (section_kind) {
5201 case ObjectSlotKind::kStrongPointer:
5202 iterate_command =
"IteratePointer";
5204 case ObjectSlotKind::kMaybeObjectPointer:
5205 iterate_command =
"IterateMaybeWeakPointer";
5207 case ObjectSlotKind::kCustomWeakPointer:
5208 iterate_command =
"IterateCustomWeakPointer";
5210 case ObjectSlotKind::kNoPointer:
5213 if (iterate_command) {
5214 if (multiple_slots) *iterate_command +=
"s";
5215 h_contents <<
" " << *iterate_command <<
"(obj, "
5217 if (multiple_slots) {
5219 << (
i == slots.
size() ?
"object_size"
5220 : std::to_string(end_offset));
5222 h_contents <<
", v);\n";
5224 start_offset = end_offset;
5226 if (
i < slots.
size()) section_kind = *next_section_kind;
5227 end_offset += TargetArchitecture::TaggedSize();
5230 h_contents <<
" }\n\n";
5233 h_contents <<
" static inline int SizeOf(Tagged<Map> map, "
5234 "Tagged<HeapObject> raw_object) {\n";
5235 if (type->size().SingleValue()) {
5236 h_contents <<
" return " << *type->size().SingleValue() <<
";\n";
5240 h_contents <<
" return UncheckedCast<" << name
5241 <<
">(raw_object)->AllocatedSize();\n";
5243 h_contents <<
" }\n\n";
5245 h_contents <<
"};\n";
5248 WriteFile(output_directory +
"/" + file_name, h_contents.str());
5256void GenerateFieldValueVerifier(
const std::string& class_name,
bool indexed,
5258 std::string indexed_field_size,
5259 std::ostream& cc_contents,
bool is_map) {
5263 !field_type->
IsSubtypeOf(TypeOracle::GetStrongTaggedType());
5264 const char* object_type = maybe_object ?
"MaybeObject" :
"Object";
5265 const char* tagged_object_type =
5266 maybe_object ?
"Tagged<MaybeObject>" :
"Tagged<Object>";
5267 const char* verify_fn =
5268 maybe_object ?
"VerifyMaybeObjectPointer" :
"VerifyPointer";
5270 offset +=
" + i * " + indexed_field_size;
5277 cc_contents <<
" " << tagged_object_type <<
" " << value
5278 <<
" = o->map();\n";
5280 cc_contents <<
" " << tagged_object_type <<
" " << value
5281 <<
" = TaggedField<" << object_type <<
">::load(o, " <<
offset
5286 cc_contents <<
" Object::" << verify_fn <<
"(isolate, " << value <<
");\n";
5291 if (field_type != TypeOracle::GetObjectType()) {
5292 cc_contents <<
" CHECK(" << GenerateRuntimeTypeCheck(field_type, value)
5297void GenerateClassFieldVerifier(
const std::string& class_name,
5298 const ClassType& class_type,
const Field& f,
5299 std::ostream& h_contents,
5300 std::ostream& cc_contents) {
5301 const Type* field_type = f.name_and_type.type;
5305 if (!field_type->IsSubtypeOf(TypeOracle::GetTaggedType()) &&
5306 !field_type->StructSupertype())
5309 if (field_type->IsSubtypeOf(TypeOracle::GetProtectedPointerType()))
return;
5310 if (field_type == TypeOracle::GetFloat64OrUndefinedOrHoleType())
return;
5312 if (TypeOracle::GetUninitializedType()->
IsSubtypeOf(field_type))
return;
5314 std::string field_start_offset;
5316 field_start_offset = f.name_and_type.name +
"__offset";
5317 std::string length = f.name_and_type.name +
"__length";
5318 cc_contents <<
" intptr_t " << field_start_offset <<
", " << length
5320 cc_contents <<
" std::tie(std::ignore, " << field_start_offset <<
", "
5322 << Callable::PrefixNameForCCOutput(
5323 class_type.GetSliceMacroName(f))
5328 cc_contents <<
" CHECK_EQ(" << field_start_offset <<
", static_cast<int>("
5329 << field_start_offset <<
"));\n";
5330 cc_contents <<
" CHECK_EQ(" << length <<
", static_cast<int>(" << length
5332 field_start_offset =
"static_cast<int>(" + field_start_offset +
")";
5333 length =
"static_cast<int>(" + length +
")";
5335 cc_contents <<
" for (int i = 0; i < " << length <<
"; ++i) {\n";
5338 field_start_offset = std::to_string(*f.offset);
5339 cc_contents <<
" {\n";
5342 if (
auto struct_type = field_type->StructSupertype()) {
5343 for (
const Field& struct_field : (*struct_type)->fields()) {
5344 if (struct_field.name_and_type.type->IsSubtypeOf(
5345 TypeOracle::GetTaggedType())) {
5346 GenerateFieldValueVerifier(
5347 class_name, f.index.has_value(),
5348 field_start_offset +
" + " + std::to_string(*struct_field.offset),
5349 struct_field, std::to_string((*struct_type)->PackedSize()),
5350 cc_contents, f.name_and_type.name ==
"map");
5354 GenerateFieldValueVerifier(class_name, f.index.has_value(),
5355 field_start_offset, f,
"kTaggedSize",
5356 cc_contents, f.name_and_type.name ==
"map");
5359 cc_contents <<
" }\n";
5364void ImplementationVisitor::GenerateClassVerifiers(
5365 const std::string& output_directory) {
5366 std::string file_name =
"class-verifiers";
5367 std::stringstream h_contents;
5368 std::stringstream cc_contents;
5371 IfDefScope verify_heap_h(h_contents,
"VERIFY_HEAP");
5372 IfDefScope verify_heap_cc(cc_contents,
"VERIFY_HEAP");
5374 h_contents <<
"#include \"src/base/macros.h\"\n\n";
5376 cc_contents <<
"#include \"torque-generated/" << file_name <<
".h\"\n\n";
5377 cc_contents <<
"#include \"src/objects/all-objects-inl.h\"\n";
5385 <<
"#include \"torque-generated/test/torque/test-torque-tq-inl.inc\"\n";
5388 h_contents <<
"class Isolate;\n";
5389 h_contents <<
"template<typename T>\nclass Tagged;\n";
5390 for (
const ClassType* type : TypeOracle::GetClasses()) {
5391 if (!type->ShouldGenerateVerify())
continue;
5392 h_contents <<
"class " << type->name() <<
";\n";
5395 const char* verifier_class =
"TorqueGeneratedClassVerifiers";
5397 h_contents <<
"class V8_EXPORT_PRIVATE " << verifier_class <<
"{\n";
5398 h_contents <<
" public:\n";
5400 for (
const ClassType* type : TypeOracle::GetClasses()) {
5401 std::string name = type->name();
5402 std::string cpp_name = type->TagglifiedCppTypeName();
5403 if (!type->ShouldGenerateVerify())
continue;
5405 std::string method_name = name +
"Verify";
5407 h_contents <<
" static void " << method_name <<
"(" << cpp_name
5408 <<
" o, Isolate* isolate);\n";
5410 cc_contents <<
"void " << verifier_class <<
"::" << method_name <<
"("
5411 << cpp_name <<
" o, Isolate* isolate) {\n";
5420 std::string super_name = super_type->
name();
5421 cc_contents <<
" o->" << super_name <<
"Verify(isolate);\n";
5425 cc_contents <<
" CHECK(Is" << name <<
"(o, isolate));\n";
5428 for (
const auto& f : type->fields()) {
5429 GenerateClassFieldVerifier(name, *type, f, h_contents, cc_contents);
5432 cc_contents <<
"}\n";
5435 h_contents <<
"};\n";
5437 WriteFile(output_directory +
"/" + file_name +
".h", h_contents.str());
5438 WriteFile(output_directory +
"/" + file_name +
".cc", cc_contents.str());
5441void ImplementationVisitor::GenerateEnumVerifiers(
5442 const std::string& output_directory) {
5443 std::string file_name =
"enum-verifiers";
5444 std::stringstream cc_contents;
5446 cc_contents <<
"#include \"src/compiler/code-assembler.h\"\n";
5447 for (
const std::string& include_path : GlobalContext::CppIncludes()) {
5450 cc_contents <<
"\n";
5452 NamespaceScope cc_namespaces(cc_contents, {
"v8",
"internal",
""});
5454 cc_contents <<
"class EnumVerifier {\n";
5455 for (
const auto& desc : GlobalContext::Get().ast()->EnumDescriptions()) {
5456 std::stringstream alias_checks;
5457 cc_contents <<
" // " << desc.name <<
" (" << desc.pos <<
")\n";
5458 cc_contents <<
" void VerifyEnum_" << desc.name <<
"("
5459 << desc.constexpr_generates
5462 for (
const auto& entry : desc.entries) {
5463 if (entry.alias_entry.empty()) {
5464 cc_contents <<
" case " << entry.name <<
": break;\n";
5468 alias_checks <<
" static_assert(" << entry.name
5469 <<
" == " << entry.alias_entry <<
");\n";
5472 if (desc.is_open) cc_contents <<
" default: break;\n";
5473 cc_contents <<
" }\n";
5474 cc_contents << alias_checks.str();
5475 cc_contents <<
" }\n\n";
5477 cc_contents <<
"};\n";
5480 WriteFile(output_directory +
"/" + file_name +
".cc", cc_contents.str());
5483void ImplementationVisitor::GenerateExportedMacrosAssembler(
5484 const std::string& output_directory) {
5485 std::string file_name =
"exported-macros-assembler";
5486 std::stringstream h_contents;
5487 std::stringstream cc_contents;
5491 h_contents <<
"#include \"src/compiler/code-assembler.h\"\n";
5492 h_contents <<
"#include \"src/execution/frames.h\"\n";
5493 h_contents <<
"#include \"torque-generated/csa-types.h\"\n";
5495 for (
const std::string& include_path : GlobalContext::CppIncludes()) {
5498 cc_contents <<
"#include \"torque-generated/" << file_name <<
".h\"\n";
5500 for (
SourceId file : SourceFileMap::AllSources()) {
5501 cc_contents <<
"#include \"torque-generated/" +
5502 SourceFileMap::PathFromV8RootWithoutExtension(file) +
5509 h_contents <<
"class V8_EXPORT_PRIVATE "
5510 "TorqueGeneratedExportedMacrosAssembler {\n"
5512 <<
" explicit TorqueGeneratedExportedMacrosAssembler"
5513 "(compiler::CodeAssemblerState* state) : state_(state) {\n"
5514 <<
" USE(state_);\n"
5517 for (
auto& declarable : GlobalContext::AllDeclarables()) {
5518 TorqueMacro* macro = TorqueMacro::DynamicCast(declarable.get());
5519 if (!(macro && macro->IsExportedToCSA()))
continue;
5520 CurrentSourcePosition::Scope position_activator(macro->Position());
5523 std::vector<std::string> generated_parameter_names;
5525 &assembler, macro->ReadableName(), macro->signature(),
5526 macro->parameter_names(),
false, &generated_parameter_names);
5530 stream <<
"return " << macro->ExternalName() <<
"(state_";
5531 for (
const auto& name : generated_parameter_names) {
5532 stream <<
", " <<
name;
5538 h_contents <<
" private:\n"
5539 <<
" compiler::CodeAssemblerState* state_;\n"
5542 WriteFile(output_directory +
"/" + file_name +
".h", h_contents.str());
5543 WriteFile(output_directory +
"/" + file_name +
".cc", cc_contents.str());
5548void CollectAllFields(
const std::string& path,
const Field& field,
5549 std::vector<std::string>&
result) {
5554 for (
const auto& inner_field : struct_type->
fields()) {
5555 CollectAllFields(next_path, inner_field,
result);
5564void ImplementationVisitor::GenerateCSATypes(
5565 const std::string& output_directory) {
5566 std::string file_name =
"csa-types";
5567 std::stringstream h_contents;
5570 h_contents <<
"#include \"src/compiler/code-assembler.h\"\n\n";
5576 for (
const auto& type : TypeOracle::GetAggregateTypes()) {
5577 const StructType* struct_type = StructType::DynamicCast(type.get());
5578 if (!struct_type)
continue;
5581 for (
auto& field : struct_type->
fields()) {
5585 h_contents <<
"\n std::tuple<";
5592 h_contents << lowered_type->GetGeneratedTypeName();
5594 std::vector<std::string> all_fields;
5595 for (
auto& field : struct_type->
fields()) {
5596 CollectAllFields(
"", field, all_fields);
5598 h_contents <<
"> Flatten() const {\n"
5599 " return std::make_tuple(";
5601 h_contents <<
");\n";
5602 h_contents <<
" }\n";
5603 h_contents <<
"};\n";
5606 WriteFile(output_directory +
"/" + file_name +
".h", h_contents.str());
5610 for (
const auto& declarable : GlobalContext::AllDeclarables()) {
5611 if (!declarable->IsMacro() || declarable->IsExternMacro())
continue;
5613 Macro* macro = Macro::cast(declarable.get());
5614 if (macro->IsUsed())
continue;
5616 if (macro->IsTorqueMacro() && TorqueMacro::cast(macro)->IsExportedToCSA()) {
5623 StructType::DynamicCast(
method->aggregate_type())) {
5624 if (struct_type->GetSpecializedFrom().has_value()) {
5630 std::vector<std::string> ignored_prefixes = {
"Convert<",
"Cast<",
5632 const std::string name = macro->ReadableName();
5635 std::any_of(ignored_prefixes.begin(), ignored_prefixes.end(),
5636 [&name](
const std::string& prefix) {
5637 return StringStartsWith(name, prefix);
5641 Lint(
"Macro '", macro->ReadableName(),
"' is never used.")
5642 .
Position(macro->IdentifierPosition());
NameAndType name_and_type
uint64_t absolute_value() const
void reserve(size_t new_cap)
void push_back(const T &value)
Namespace * nspace() const
const Field & LookupField(const std::string &name) const
const std::string & name() const
const std::vector< Field > & fields() const
const std::vector< Method * > & Methods() const
const BitField & LookupField(const std::string &name) const
Binding< T > * Add(std::string name, T value, bool mark_as_used=false)
std::optional< Stack< std::string > > EmitGraph(Stack< std::string > parameters)
static void EmitCCValue(VisitResult result, const Stack< std::string > &values, std::ostream &out)
std::optional< Stack< std::string > > EmitGraph(Stack< std::string > parameters)
static void EmitCSAValue(VisitResult result, const Stack< std::string > &values, std::ostream &out)
bool HasReturnValue() const
virtual bool ShouldBeInlined(OutputType output_type) const
const Signature & signature() const
const std::string & ExternalName() const
const std::string & ReadableName() const
bool IsTransitioning() const
StackRange TopRange(size_t slot_count) const
const Stack< const Type * > & CurrentStack() const
Block * NewBlock(std::optional< Stack< const Type * > > input_types=std::nullopt, bool is_deferred=false)
void Emit(Instruction instruction)
const ControlFlowGraph & Result()
const ClassType * GetSuperClass() const
std::optional< std::pair< int, int > > InstanceTypeRange() const
ResidueClass size() const
std::string GetSliceMacroName(const Field &field) const
bool ShouldGenerateVerify() const
bool AllowInstantiation() const
std::vector< Field > ComputeAllFields() const
Scope * ParentScope() const
SourcePosition IdentifierPosition() const
SourcePosition Position() const
static PerFileStreams & GeneratedPerFile(SourceId file)
static bool collect_language_server_data()
static bool force_assert_statements()
static const std::set< std::string > & CppIncludes()
static bool collect_kythe_data()
MacroInliningScope(ImplementationVisitor *visitor, const Macro *macro)
ImplementationVisitor * visitor_
VisitResult Yield(VisitResult result)
void VisitMacroCommon(Macro *macro)
std::unordered_set< const Macro * > inlining_macros_
VisitResult GetAndClearReturnValue()
std::ostream & csa_ccfile()
VisitResult GenerateFetchFromLocation(const LocationReference &reference)
void GenerateAssignToLocation(const LocationReference &reference, const VisitResult &assignment_value)
void LowerLabelParameter(const Type *type, const std::string ¶meter_name, std::vector< std::string > *lowered_parameters)
cpp::Function GenerateFunction(cpp::Class *owner, const std::string &name, const Signature &signature, const NameVector ¶meter_names, bool pass_code_assembler_state=true, std::vector< std::string > *generated_parameter_names=nullptr)
void GenerateBranch(const VisitResult &condition, Block *true_block, Block *false_block)
std::string ExternalLabelParameterName(const std::string &label_name, size_t i)
void EndDebugMacrosFile()
Binding< LocalLabel > * LookupLabel(const std::string &name)
InitializerResults VisitInitializerResults(const ClassType *class_type, const std::vector< NameAndExpression > &expressions)
LocationReference GenerateFieldReference(VisitResult object, const Field &field, const ClassType *class_type, bool treat_optional_as_indexed=false)
VisitResult GenerateCall(Callable *callable, std::optional< LocationReference > this_parameter, Arguments parameters, const TypeVector &specialization_types={}, bool tail_call=false)
VisitResult GetBuiltinCode(Builtin *builtin)
LocationReference GenerateReferenceToItemInHeapSlice(LocationReference slice, VisitResult index)
VisitResult GenerateBoolConstant(bool constant)
std::string ExternalParameterName(const std::string &name)
std::stringstream debug_macros_cc_
const Identifier * TryGetSourceForBitfieldExpression(const Expression *expr) const
void SetReturnValue(VisitResult return_value)
std::ostream & csa_headerfile()
CfgAssembler & assembler()
std::optional< CfgAssembler > assembler_
VisitResult InlineMacro(Macro *macro, std::optional< LocationReference > this_reference, const std::vector< VisitResult > &arguments, const std::vector< Block * > label_blocks)
VisitResult Visit(Expression *expr)
LocationReference GetLocationReference(Expression *location)
std::stringstream debug_macros_h_
StackRange LowerParameter(const Type *type, const std::string ¶meter_name, Stack< std::string > *lowered_parameters)
StackRange GenerateLabelGoto(LocalLabel *label, std::optional< StackRange > arguments={})
void BeginDebugMacrosFile()
VisitResult GenerateImplicitConvert(const Type *destination_type, VisitResult source)
const Type * GetCommonType(const Type *left, const Type *right)
std::string ExternalLabelName(const std::string &label_name)
void GenerateExpressionBranch(Expression *expression, Block *true_block, Block *false_block)
std::unordered_map< const Expression *, const Identifier * > bitfield_expressions_
void BeginGeneratedFiles()
cpp::Function GenerateMacroFunctionDeclaration(Macro *macro)
static V8_EXPORT_PRIVATE void AddBindingUse(SourcePosition use_position, Binding< LocalValue > *binding)
static V8_EXPORT_PRIVATE kythe_entity_t AddBindingDefinition(Binding< LocalValue > *binding)
static V8_EXPORT_PRIVATE void AddDefinition(SourcePosition token, SourcePosition definition)
const BitField & bit_field() const
const VisitResult & heap_slice() const
const VisitResult & temporary() const
FieldSynchronization heap_reference_synchronization() const
const LocationReference & bit_field_struct_location() const
bool IsBitFieldAccess() const
bool IsHeapReference() const
const VisitResult & GetVisitResult() const
bool IsVariableAccess() const
static LocationReference HeapReference(VisitResult heap_reference, FieldSynchronization synchronization=FieldSynchronization::kNone)
static LocationReference Temporary(VisitResult temporary, std::string description)
bool IsCallAccess() const
static LocationReference HeapSlice(VisitResult heap_slice)
static LocationReference VariableAccess(VisitResult variable, std::optional< Binding< LocalValue > * > binding=std::nullopt)
const VisitResultVector & call_arguments() const
const VisitResult & heap_reference() const
const VisitResult & variable() const
const std::string & assign_function() const
const std::string & temporary_description() const
const std::string & eval_function() const
std::optional< const Type * > ReferencedType() const
std::optional< Binding< LocalValue > * > binding() const
MessageBuilder & Position(SourcePosition position)
Expression * body() const
const std::string & external_name() const
bool StrictlyBetterThan(const ParameterDifference &other) const
std::optional< size_t > SingleValue() const
static std::vector< SourceId > AllSources()
static const std::string & PathFromV8Root(SourceId file)
static std::string PathFromV8RootWithoutExtension(SourceId file)
void Extend(StackRange adjacent)
StackRange TopRange(size_t slot_count) const
StackRange PushMany(const std::vector< T > &v)
std::string GetGeneratedTypeNameImpl() const override
const Type * type() const
bool IsRedeclaration() const
TypeVector GetResult() const
const std::string & GetFailureReason()
static const Type * GetConstexprStringType()
static const Type * GetJSFunctionType()
static std::vector< const ClassType * > GetClasses()
static const Type * GetConstFloat64Type()
static const Type * GetConstexprBoolType()
static const Type * GetArgumentsType()
static const BuiltinPointerType * GetBuiltinPointerType(TypeVector argument_types, const Type *return_type)
static const Type * GetNativeContextType()
static const Type * GetVoidType()
static const TopType * GetTopType(std::string reason, const Type *source_type)
static const Type * GetIntPtrType()
static const Type * GetReferenceType(const Type *referenced_type, bool is_const)
static const Type * GetBoolType()
static const Type * GetContextType()
static const Type * GetJSAnyType()
static const Type * GetNeverType()
static const Type * GetIntegerLiteralType()
static const Type * GetDispatchHandleType()
static const Type * GetConstStringType()
static const Type * GetConstInt31Type()
static const Type * ComputeType(TypeExpression *type_expression)
std::string GetGeneratedTNodeTypeName() const
virtual bool IsSubtypeOf(const Type *supertype) const
virtual const Type * NonConstexprVersion() const
std::optional< const AggregateType * > AggregateSupertype() const
virtual std::string GetRuntimeType() const
std::optional< const StructType * > StructSupertype() const
std::string GetGeneratedTypeName() const
virtual std::string GetDebugType() const
std::optional< const ClassType * > ClassSupertype() const
std::string TagglifiedCppTypeName() const
virtual bool IsConstexpr() const
const Type * type() const
static VisitResult NeverResult()
const Type * type() const
const StackRange & stack_range() const
const std::string & constexpr_value() const
void SetType(const Type *new_type)
void BeginNamespace(std::string name)
void AddParameter(std::string type, std::string name={}, std::string default_value={})
void PrintDeclaration(std::ostream &stream, int indentation=kAutomaticIndentation) const
std::vector< std::string > GetParameterNames() const
void PrintEndDefinition(std::ostream &stream, int indentation=0) const
void PrintBeginDefinition(std::ostream &stream, int indentation=0) const
void PrintDefinition(std::ostream &stream, const std::function< void(std::ostream &)> &builder, int indentation=0) const
void SetReturnType(std::string return_type)
#define V8_ENABLE_LEAPTIERING_BOOL
#define V8_JS_LINKAGE_INCLUDES_DISPATCH_HANDLE_BOOL
#define V8_ENABLE_SANDBOX_BOOL
ZoneVector< OpIndex > candidates
base::Vector< const DirectHandle< Object > > args
FieldSections completed_sections_
const std::string gen_name_I_
bool header_size_emitted_
FieldSectionType current_section_
std::string previous_field_end_
const std::string gen_name_T_
std::optional< TNode< JSArray > > a
ZoneVector< RpoNumber > & result
constexpr const char * kUnreachableCodeMessage
constexpr auto Field(char const (&s)[count], uint8_t type)
static const char *const TORQUE_INTERNAL_NAMESPACE_STRING
std::optional< std::string > MatchSimpleBodyDescriptor(const ClassType *type)
static const char *const kThisParameterName
std::string CapifyStringWithUnderscores(const std::string &camellified_string)
bool IsAssignableFrom(const Type *to, const Type *from)
size_t LoweredSlotCount(const Type *type)
std::optional< NameAndType > ExtractSimpleFieldArraySize(const ClassType &class_type, Expression *array_size)
std::string StringLiteralQuote(const std::string &s)
void ReportError(Args &&... args)
uint64_t next_unique_binding_index
std::string MachineTypeString(const Type *type)
std::string ToString(Args &&... args)
MessageBuilder Lint(Args &&... args)
void ReportAllUnusedMacros()
VisitResult ProjectStructField(VisitResult structure, const std::string &fieldname)
std::string SnakeifyString(const std::string &camel_string)
static const char *const STATIC_ASSERT_MACRO_STRING
std::vector< Identifier * > NameVector
bool StartsWithSingleUnderscore(const std::string &str)
std::string PositionAsString(SourcePosition pos)
bool IsDeferred(Statement *stmt)
std::string CamelifyString(const std::string &underscore_string)
std::optional< std::tuple< size_t, std::string > > SizeOf(const Type *type)
auto PrintList(const T &list, const std::string &separator=", ")
static constexpr const char * kMacroEndLabelName
std::vector< const Type * > TypeVector
TypeVector LowerType(const Type *type)
const Type * SubtractType(const Type *a, const Type *b)
void PrintCommaSeparatedList(std::ostream &os, const T &list, C &&transform)
std::string UnderlinifyPath(std::string path)
MessageBuilder Error(Args &&... args)
bool IsCompatibleSignature(const Signature &sig, const TypeVector &types, size_t label_count)
std::string StringLiteralUnquote(const std::string &s)
TypeVector LowerParameterTypes(const TypeVector ¶meters)
V8_INLINE bool IsSubtypeOf(ValueType subtype, ValueType supertype, const WasmModule *sub_module, const WasmModule *super_module)
constexpr const char * ToString(DeoptimizeKind kind)
ContainedInLattice Combine(ContainedInLattice a, ContainedInLattice b)
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in allocation gc speed threshold for starting incremental marking via a task in percent of available threshold for starting incremental marking immediately in percent of available Use a single schedule for determining a marking schedule between JS and C objects schedules the minor GC task with kUserVisible priority max worker number of concurrent for NumberOfWorkerThreads start background threads that allocate memory concurrent_array_buffer_sweeping use parallel threads to clear weak refs in the atomic pause trace progress of the incremental marking trace object counts and memory usage report a tick only when allocated zone memory changes by this amount TracingFlags::gc_stats store(v8::tracing::TracingCategoryObserver::ENABLED_BY_NATIVE)) DEFINE_GENERIC_IMPLICATION(trace_gc_object_stats
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in name
kWasmInternalFunctionIndirectPointerTag kProtectedInstanceDataOffset sig
auto impl(C *x) -> typename implement< C >::type *
#define DCHECK_LE(v1, v2)
#define CHECK_NOT_NULL(val)
#define DCHECK_IMPLIES(v1, v2)
#define CHECK_NE(lhs, rhs)
#define DCHECK_GE(v1, v2)
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
#define DCHECK_LT(v1, v2)
#define DCHECK_EQ(v1, v2)
VisitResultVector parameters
std::optional< std::string > op
TypeExpression * excluded_type
std::vector< Identifier * > labels
IdentifierExpression * callee
std::vector< Expression * > arguments
IdentifierExpression * method
std::vector< Identifier * > labels
std::vector< Expression * > arguments
std::optional< ClassFieldIndexInfo > index
NameAndType name_and_type
std::optional< size_t > offset
std::optional< Statement * > action
std::optional< Expression * > test
std::optional< VarDeclarationStatement * > var_declaration
std::stringstream class_definition_headerfile
std::stringstream class_definition_inline_headerfile_macro_definitions
std::stringstream csa_ccfile
std::stringstream class_definition_ccfile
std::set< SourceId > required_builtin_includes
std::stringstream csa_headerfile
std::stringstream class_definition_inline_headerfile_macro_declarations
std::stringstream class_definition_inline_headerfile
std::vector< Expression * > arguments
std::vector< TypeExpression * > generic_arguments
std::vector< std::string > namespace_qualification
std::optional< Statement * > if_false
IncrementDecrementOperator op
std::vector< Identifier * > names
std::map< std::string, VisitResult > field_value_map
std::vector< TypeExpression * > generic_arguments
std::vector< Expression * > arguments
std::map< std::string, VisitResult > offsets
std::map< std::string, VisitResult > array_lengths
std::vector< NameAndExpression > initializers
std::vector< TypeExpression * > types
std::vector< Identifier * > names
std::optional< Expression * > value
LabelDeclarationVector labels
NameVector parameter_names
ParameterTypes parameter_types
size_t ExplicitCount() const
const TypeVector & types() const
std::optional< std::string > arguments_variable
std::vector< NameAndExpression > initializers
Expression * try_expression
std::optional< Expression * > initializer
std::optional< TypeExpression * > type
#define AST_STATEMENT_NODE_KIND_LIST(V)
#define AST_EXPRESSION_NODE_KIND_LIST(V)