aboutsummaryrefslogtreecommitdiff
path: root/deps/v8/src/torque/implementation-visitor.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/torque/implementation-visitor.cc')
-rw-r--r--deps/v8/src/torque/implementation-visitor.cc702
1 files changed, 430 insertions, 272 deletions
diff --git a/deps/v8/src/torque/implementation-visitor.cc b/deps/v8/src/torque/implementation-visitor.cc
index d4798b28cb..a0aeeee81b 100644
--- a/deps/v8/src/torque/implementation-visitor.cc
+++ b/deps/v8/src/torque/implementation-visitor.cc
@@ -48,61 +48,62 @@ const Type* ImplementationVisitor::Visit(Statement* stmt) {
return result;
}
-void ImplementationVisitor::BeginNamespaceFile(Namespace* nspace) {
- std::ostream& source = nspace->source_stream();
- std::ostream& header = nspace->header_stream();
+void ImplementationVisitor::BeginCSAFiles() {
+ for (SourceId file : SourceFileMap::AllSources()) {
+ std::ostream& source = GlobalContext::GeneratedPerFile(file).csa_ccfile;
+ std::ostream& header = GlobalContext::GeneratedPerFile(file).csa_headerfile;
- for (const std::string& include_path : GlobalContext::CppIncludes()) {
- source << "#include " << StringLiteralQuote(include_path) << "\n";
- }
+ for (const std::string& include_path : GlobalContext::CppIncludes()) {
+ source << "#include " << StringLiteralQuote(include_path) << "\n";
+ }
- for (Namespace* n : GlobalContext::Get().GetNamespaces()) {
- source << "#include \"torque-generated/builtins-" +
- DashifyString(n->name()) + "-gen-tq.h\"\n";
- }
- source << "\n";
+ for (SourceId file : SourceFileMap::AllSources()) {
+ source << "#include \"torque-generated/" +
+ SourceFileMap::PathFromV8RootWithoutExtension(file) +
+ "-tq-csa.h\"\n";
+ }
+ source << "\n";
- source << "namespace v8 {\n"
- << "namespace internal {\n"
- << "\n";
+ source << "namespace v8 {\n"
+ << "namespace internal {\n"
+ << "\n";
- std::string upper_name(nspace->name());
- transform(upper_name.begin(), upper_name.end(), upper_name.begin(),
- ::toupper);
- std::string headerDefine =
- "V8_GEN_TORQUE_GENERATED_" + upper_name + "_NAMESPACE_TQ_H_";
- header << "#ifndef " << headerDefine << "\n";
- header << "#define " << headerDefine << "\n\n";
- header << "#include \"src/compiler/code-assembler.h\"\n";
- header << "#include \"src/codegen/code-stub-assembler.h\"\n";
- header << "#include \"src/utils/utils.h\"\n";
- header << "#include \"torque-generated/field-offsets-tq.h\"\n";
- header << "#include \"torque-generated/csa-types-tq.h\"\n";
- header << "\n";
+ std::string headerDefine =
+ "V8_GEN_TORQUE_GENERATED_" +
+ UnderlinifyPath(SourceFileMap::PathFromV8Root(file)) + "_H_";
+ header << "#ifndef " << headerDefine << "\n";
+ header << "#define " << headerDefine << "\n\n";
+ header << "#include \"src/compiler/code-assembler.h\"\n";
+ header << "#include \"src/codegen/code-stub-assembler.h\"\n";
+ header << "#include \"src/utils/utils.h\"\n";
+ header << "#include \"torque-generated/field-offsets-tq.h\"\n";
+ header << "#include \"torque-generated/csa-types-tq.h\"\n";
+ header << "\n";
- header << "namespace v8 {\n"
- << "namespace internal {\n"
- << "\n";
+ header << "namespace v8 {\n"
+ << "namespace internal {\n"
+ << "\n";
+ }
}
-void ImplementationVisitor::EndNamespaceFile(Namespace* nspace) {
- std::ostream& source = nspace->source_stream();
- std::ostream& header = nspace->header_stream();
+void ImplementationVisitor::EndCSAFiles() {
+ for (SourceId file : SourceFileMap::AllSources()) {
+ std::ostream& source = GlobalContext::GeneratedPerFile(file).csa_ccfile;
+ std::ostream& header = GlobalContext::GeneratedPerFile(file).csa_headerfile;
- std::string upper_name(nspace->name());
- transform(upper_name.begin(), upper_name.end(), upper_name.begin(),
- ::toupper);
- std::string headerDefine =
- "V8_GEN_TORQUE_GENERATED_" + upper_name + "_NAMESPACE_V8_H_";
+ std::string headerDefine =
+ "V8_GEN_TORQUE_GENERATED_" +
+ UnderlinifyPath(SourceFileMap::PathFromV8Root(file)) + "_H_";
- source << "} // namespace internal\n"
- << "} // namespace v8\n"
- << "\n";
+ source << "} // namespace internal\n"
+ << "} // namespace v8\n"
+ << "\n";
- header << "} // namespace internal\n"
- << "} // namespace v8\n"
- << "\n";
- header << "#endif // " << headerDefine << "\n";
+ header << "} // namespace internal\n"
+ << "} // namespace v8\n"
+ << "\n";
+ header << "#endif // " << headerDefine << "\n";
+ }
}
void ImplementationVisitor::Visit(NamespaceConstant* decl) {
@@ -179,14 +180,15 @@ VisitResult ImplementationVisitor::InlineMacro(
DCHECK(macro->IsMethod());
LocalValue this_value = LocalValue{!this_reference->IsVariableAccess(),
this_reference->GetVisitResult()};
- parameter_bindings.Add(kThisParameterName, this_value);
+ parameter_bindings.Add(kThisParameterName, this_value, true);
}
size_t i = 0;
for (auto arg : arguments) {
if (this_reference && i == signature.implicit_count) i++;
+ const bool mark_as_used = signature.implicit_count > i;
const Identifier* name = macro->parameter_names()[i++];
- parameter_bindings.Add(name, LocalValue{true, arg});
+ parameter_bindings.Add(name, LocalValue{true, arg}, mark_as_used);
}
DCHECK_EQ(label_blocks.size(), signature.labels.size());
@@ -217,7 +219,7 @@ VisitResult ImplementationVisitor::InlineMacro(
}
}
macro_end = assembler().NewBlock(std::move(stack));
- macro_end_binding.emplace(&LabelBindingsManager::Get(), "_macro_end",
+ macro_end_binding.emplace(&LabelBindingsManager::Get(), kMacroEndLabelName,
LocalLabel{macro_end, {return_type}});
} else {
SetReturnValue(VisitResult::NeverResult());
@@ -380,13 +382,15 @@ namespace {
std::string AddParameter(size_t i, Builtin* builtin,
Stack<std::string>* parameters,
Stack<const Type*>* parameter_types,
- BlockBindings<LocalValue>* parameter_bindings) {
+ BlockBindings<LocalValue>* parameter_bindings,
+ bool mark_as_used) {
const Identifier* name = builtin->signature().parameter_names[i];
const Type* type = builtin->signature().types()[i];
std::string external_name = "parameter" + std::to_string(i);
parameters->Push(external_name);
StackRange range = parameter_types->PushMany(LowerType(type));
- parameter_bindings->Add(name, LocalValue{true, VisitResult(type, range)});
+ parameter_bindings->Add(name, LocalValue{true, VisitResult(type, range)},
+ mark_as_used);
return external_name;
}
@@ -395,15 +399,15 @@ std::string AddParameter(size_t i, Builtin* builtin,
void ImplementationVisitor::Visit(Builtin* builtin) {
if (builtin->IsExternal()) return;
CurrentScope::Scope current_scope(builtin);
+ CurrentCallable::Scope current_callable(builtin);
+ CurrentReturnValue::Scope current_return_value;
+
const std::string& name = builtin->ExternalName();
const Signature& signature = builtin->signature();
source_out() << "TF_BUILTIN(" << name << ", CodeStubAssembler) {\n"
<< " compiler::CodeAssemblerState* state_ = state();"
<< " compiler::CodeAssembler ca_(state());\n";
- CurrentCallable::Scope current_callable(builtin);
- CurrentReturnValue::Scope current_return_value;
-
Stack<const Type*> parameter_types;
Stack<std::string> parameters;
@@ -411,58 +415,128 @@ void ImplementationVisitor::Visit(Builtin* builtin) {
BlockBindings<LocalValue> parameter_bindings(&ValueBindingsManager::Get());
- // Context
- std::string parameter0 = AddParameter(0, builtin, &parameters,
- &parameter_types, &parameter_bindings);
- source_out() << " TNode<Context> " << parameter0
- << " = UncheckedCast<Context>(Parameter("
- << "Descriptor::kContext));\n";
- source_out() << " USE(" << parameter0 << ");\n";
-
- size_t first = 1;
- if (builtin->IsVarArgsJavaScript()) {
- DCHECK(signature.parameter_types.var_args);
- source_out()
- << " Node* argc = Parameter(Descriptor::kJSActualArgumentsCount);\n";
- std::string parameter1 = AddParameter(
- 1, builtin, &parameters, &parameter_types, &parameter_bindings);
- source_out()
- << " TNode<IntPtrT> arguments_length(ChangeInt32ToIntPtr(argc));\n";
- source_out() << " TNode<RawPtrT> arguments_frame = "
- "UncheckedCast<RawPtrT>(LoadFramePointer());\n";
- source_out() << " TorqueStructArguments "
- "torque_arguments(GetFrameArguments(arguments_frame, "
- "arguments_length));\n";
- source_out() << " CodeStubArguments arguments(this, torque_arguments);\n";
-
- source_out() << " TNode<Object> " << parameter1
- << " = arguments.GetReceiver();\n";
- source_out() << "USE(" << parameter1 << ");\n";
- parameters.Push("torque_arguments.frame");
- parameters.Push("torque_arguments.base");
- parameters.Push("torque_arguments.length");
- const Type* arguments_type = TypeOracle::GetArgumentsType();
- StackRange range = parameter_types.PushMany(LowerType(arguments_type));
- parameter_bindings.Add(
- *signature.arguments_variable,
- LocalValue{true, VisitResult(arguments_type, range)});
-
- first = 2;
- }
-
- for (size_t i = 0; i < signature.parameter_names.size(); ++i) {
- if (i < first) continue;
- const std::string& parameter_name = signature.parameter_names[i]->value;
- const Type* type = signature.types()[i];
- std::string var = AddParameter(i, builtin, &parameters, &parameter_types,
- &parameter_bindings);
- source_out() << " " << type->GetGeneratedTypeName() << " " << var << " = "
- << "UncheckedCast<" << type->GetGeneratedTNodeTypeName()
- << ">(Parameter(Descriptor::k"
- << CamelifyString(parameter_name) << "));\n";
- source_out() << " USE(" << var << ");\n";
- }
+ if (builtin->IsVarArgsJavaScript() || builtin->IsFixedArgsJavaScript()) {
+ if (builtin->IsVarArgsJavaScript()) {
+ DCHECK(signature.parameter_types.var_args);
+ if (signature.ExplicitCount() > 0) {
+ Error("Cannot mix explicit parameters with varargs.")
+ .Position(signature.parameter_names[signature.implicit_count]->pos);
+ }
+ source_out()
+ << " Node* argc = Parameter(Descriptor::kJSActualArgumentsCount);\n";
+ source_out()
+ << " TNode<IntPtrT> arguments_length(ChangeInt32ToIntPtr(argc));\n";
+ source_out() << " TNode<RawPtrT> arguments_frame = "
+ "UncheckedCast<RawPtrT>(LoadFramePointer());\n";
+ source_out() << " TorqueStructArguments "
+ "torque_arguments(GetFrameArguments(arguments_frame, "
+ "arguments_length));\n";
+ source_out()
+ << " CodeStubArguments arguments(this, torque_arguments);\n";
+
+ parameters.Push("torque_arguments.frame");
+ parameters.Push("torque_arguments.base");
+ parameters.Push("torque_arguments.length");
+ const Type* arguments_type = TypeOracle::GetArgumentsType();
+ StackRange range = parameter_types.PushMany(LowerType(arguments_type));
+ parameter_bindings.Add(
+ *signature.arguments_variable,
+ LocalValue{true, VisitResult(arguments_type, range)}, true);
+ }
+
+ for (size_t i = 0; i < signature.implicit_count; ++i) {
+ const std::string& param_name = signature.parameter_names[i]->value;
+ SourcePosition param_pos = signature.parameter_names[i]->pos;
+ std::string generated_name = AddParameter(
+ i, builtin, &parameters, &parameter_types, &parameter_bindings, true);
+ const Type* actual_type = signature.parameter_types.types[i];
+ const Type* expected_type;
+ if (param_name == "context") {
+ source_out() << " TNode<Context> " << generated_name
+ << " = UncheckedCast<Context>(Parameter("
+ << "Descriptor::kContext));\n";
+ source_out() << " USE(" << generated_name << ");\n";
+ expected_type = TypeOracle::GetContextType();
+ } else if (param_name == "receiver") {
+ source_out()
+ << " TNode<Object> " << generated_name << " = "
+ << (builtin->IsVarArgsJavaScript()
+ ? "arguments.GetReceiver()"
+ : "UncheckedCast<Object>(Parameter(Descriptor::kReceiver))")
+ << ";\n";
+ source_out() << "USE(" << generated_name << ");\n";
+ expected_type = TypeOracle::GetObjectType();
+ } else if (param_name == "newTarget") {
+ source_out() << " TNode<Object> " << generated_name
+ << " = UncheckedCast<Object>(Parameter("
+ << "Descriptor::kJSNewTarget));\n";
+ source_out() << "USE(" << generated_name << ");\n";
+ expected_type = TypeOracle::GetObjectType();
+ } else if (param_name == "target") {
+ source_out() << " TNode<JSFunction> " << generated_name
+ << " = UncheckedCast<JSFunction>(Parameter("
+ << "Descriptor::kJSTarget));\n";
+ source_out() << "USE(" << generated_name << ");\n";
+ expected_type = TypeOracle::GetJSFunctionType();
+ } else {
+ Error(
+ "Unexpected implicit parameter \"", param_name,
+ "\" for JavaScript calling convention, "
+ "expected \"context\", \"receiver\", \"target\", or \"newTarget\"")
+ .Position(param_pos);
+ expected_type = actual_type;
+ }
+ if (actual_type != expected_type) {
+ Error("According to JavaScript calling convention, expected parameter ",
+ param_name, " to have type ", *expected_type, " but found type ",
+ *actual_type)
+ .Position(param_pos);
+ }
+ }
+
+ for (size_t i = signature.implicit_count;
+ i < signature.parameter_names.size(); ++i) {
+ const std::string& parameter_name = signature.parameter_names[i]->value;
+ const Type* type = signature.types()[i];
+ const bool mark_as_used = signature.implicit_count > i;
+ std::string var = AddParameter(i, builtin, &parameters, &parameter_types,
+ &parameter_bindings, mark_as_used);
+ source_out() << " " << type->GetGeneratedTypeName() << " " << var
+ << " = "
+ << "UncheckedCast<" << type->GetGeneratedTNodeTypeName()
+ << ">(Parameter(Descriptor::k"
+ << CamelifyString(parameter_name) << "));\n";
+ source_out() << " USE(" << var << ");\n";
+ }
+
+ } else {
+ DCHECK(builtin->IsStub());
+
+ // Context
+ const bool context_is_implicit = signature.implicit_count > 0;
+ std::string parameter0 =
+ AddParameter(0, builtin, &parameters, &parameter_types,
+ &parameter_bindings, context_is_implicit);
+ source_out() << " TNode<Context> " << parameter0
+ << " = UncheckedCast<Context>(Parameter("
+ << "Descriptor::kContext));\n";
+ source_out() << " USE(" << parameter0 << ");\n";
+
+ for (size_t i = 1; i < signature.parameter_names.size(); ++i) {
+ const std::string& parameter_name = signature.parameter_names[i]->value;
+ const Type* type = signature.types()[i];
+ const bool mark_as_used = signature.implicit_count > i;
+ std::string var = AddParameter(i, builtin, &parameters, &parameter_types,
+ &parameter_bindings, mark_as_used);
+ source_out() << " " << type->GetGeneratedTypeName() << " " << var
+ << " = "
+ << "UncheckedCast<" << type->GetGeneratedTNodeTypeName()
+ << ">(Parameter(Descriptor::k"
+ << CamelifyString(parameter_name) << "));\n";
+ source_out() << " USE(" << var << ");\n";
+ }
+ }
assembler_ = CfgAssembler(parameter_types);
const Type* body_result = Visit(*builtin->body());
if (body_result != TypeOracle::GetNeverType()) {
@@ -961,6 +1035,26 @@ const Type* ImplementationVisitor::Visit(AssertStatement* stmt) {
"Torque assert '" + FormatAssertSource(stmt->source) + "' failed"});
assembler().Bind(true_block);
+ } else {
+ // Visit the expression so bindings only used in asserts are marked
+ // as such. Otherwise they might be wrongly reported as unused bindings
+ // in release builds.
+ stmt->expression->VisitAllSubExpressions([](Expression* expression) {
+ if (auto id = IdentifierExpression::DynamicCast(expression)) {
+ ValueBindingsManager::Get().TryLookup(id->name->value);
+ } else if (auto call = CallExpression::DynamicCast(expression)) {
+ for (Identifier* label : call->labels) {
+ LabelBindingsManager::Get().TryLookup(label->value);
+ }
+ // TODO(szuend): In case the call expression resolves to a macro
+ // callable, mark the macro as used as well.
+ } else if (auto call = CallMethodExpression::DynamicCast(expression)) {
+ for (Identifier* label : call->labels) {
+ LabelBindingsManager::Get().TryLookup(label->value);
+ }
+ // TODO(szuend): Mark the underlying macro as used.
+ }
+ });
}
return TypeOracle::GetVoidType();
}
@@ -978,7 +1072,7 @@ const Type* ImplementationVisitor::Visit(ReturnStatement* stmt) {
ReportError(s.str());
}
LocalLabel* end =
- current_callable->IsMacro() ? LookupLabel("_macro_end") : nullptr;
+ current_callable->IsMacro() ? LookupLabel(kMacroEndLabelName) : nullptr;
if (current_callable->HasReturnValue()) {
if (!stmt->value) {
std::stringstream s;
@@ -1016,81 +1110,6 @@ const Type* ImplementationVisitor::Visit(ReturnStatement* stmt) {
return TypeOracle::GetNeverType();
}
-const Type* ImplementationVisitor::Visit(ForOfLoopStatement* stmt) {
- VisitResult expression_result = Visit(stmt->iterable);
- VisitResult begin = stmt->begin
- ? Visit(*stmt->begin)
- : VisitResult(TypeOracle::GetConstInt31Type(), "0");
-
- VisitResult end = stmt->end
- ? Visit(*stmt->end)
- : GenerateCall(".length", {{expression_result}, {}});
-
- const Type* common_type = GetCommonType(begin.type(), end.type());
- VisitResult index = GenerateImplicitConvert(common_type, begin);
-
- Block* body_block = assembler().NewBlock();
- Block* increment_block = assembler().NewBlock(assembler().CurrentStack());
- Block* exit_block = assembler().NewBlock(assembler().CurrentStack());
-
- Block* header_block = assembler().NewBlock();
-
- assembler().Goto(header_block);
-
- assembler().Bind(header_block);
-
- BreakContinueActivator activator(exit_block, increment_block);
-
- {
- StackScope comparison_scope(this);
- VisitResult result = GenerateCall("<", {{index, end}, {}});
- if (result.type() != TypeOracle::GetBoolType()) {
- ReportError("operator < with arguments(", *index.type(), ", ",
- *end.type(),
- ") used in for-of loop has to return type bool, but "
- "returned type ",
- *result.type());
- }
- comparison_scope.Yield(result);
- }
- assembler().Branch(body_block, exit_block);
-
- assembler().Bind(body_block);
- {
- VisitResult element_result;
- {
- StackScope element_scope(this);
- VisitResult result = GenerateCall("[]", {{expression_result, index}, {}});
- if (stmt->var_declaration->type) {
- const Type* declared_type =
- TypeVisitor::ComputeType(*stmt->var_declaration->type);
- result = GenerateImplicitConvert(declared_type, result);
- }
- element_result = element_scope.Yield(result);
- }
- Binding<LocalValue> element_var_binding{&ValueBindingsManager::Get(),
- stmt->var_declaration->name->value,
- LocalValue{true, element_result}};
- Visit(stmt->body);
- }
- assembler().Goto(increment_block);
-
- assembler().Bind(increment_block);
- {
- Arguments increment_args;
- increment_args.parameters = {index, {TypeOracle::GetConstInt31Type(), "1"}};
- VisitResult increment_result = GenerateCall("+", increment_args);
-
- GenerateAssignToLocation(LocationReference::VariableAccess(index),
- increment_result);
- }
-
- assembler().Goto(header_block);
-
- assembler().Bind(exit_block);
- return TypeOracle::GetVoidType();
-}
-
VisitResult ImplementationVisitor::TemporaryUninitializedStruct(
const StructType* struct_type, const std::string& reason) {
StackRange range = assembler().TopRange(0);
@@ -1346,43 +1365,51 @@ VisitResult ImplementationVisitor::Visit(NewExpression* expr) {
InitializerResults initializer_results =
VisitInitializerResults(class_type, expr->initializers);
- // Output the code to generate an uninitialized object of the class size in
- // the GC heap.
- VisitResult allocate_result;
+ VisitResult object_map;
+ const Field& map_field = class_type->LookupField("map");
+ if (map_field.offset != 0) {
+ ReportError("class initializers must have a map as first parameter");
+ }
+ const std::map<std::string, VisitResult>& initializer_fields =
+ initializer_results.field_value_map;
+ auto it_object_map = initializer_fields.find(map_field.name_and_type.name);
if (class_type->IsExtern()) {
- const Field& map_field = class_type->LookupField("map");
- if (map_field.offset != 0) {
- ReportError(
- "external classes initializers must have a map as first parameter");
- }
- NameValueMap initializer_fields = initializer_results.field_value_map;
- if (initializer_fields.find(map_field.name_and_type.name) ==
- initializer_fields.end()) {
+ if (it_object_map == initializer_fields.end()) {
ReportError("Constructor for ", class_type->name(),
" needs Map argument!");
}
- VisitResult object_map = initializer_fields[map_field.name_and_type.name];
- Arguments size_arguments;
- size_arguments.parameters.push_back(object_map);
- VisitResult object_size = GenerateCall("%GetAllocationBaseSize",
- size_arguments, {class_type}, false);
-
- object_size =
- AddVariableObjectSize(object_size, class_type, initializer_results);
-
- Arguments allocate_arguments;
- allocate_arguments.parameters.push_back(object_size);
- allocate_result =
- GenerateCall("%Allocate", allocate_arguments, {class_type}, false);
- DCHECK(allocate_result.IsOnStack());
+ object_map = it_object_map->second;
} else {
- Arguments allocate_arguments;
- allocate_arguments.parameters.push_back(
- VisitResult(TypeOracle::GetConstexprIntPtrType(),
- std::to_string(class_type->size() / kTaggedSize)));
- allocate_result = GenerateCall("%AllocateInternalClass", allocate_arguments,
- {class_type}, false);
- }
+ if (it_object_map != initializer_fields.end()) {
+ ReportError(
+ "Constructor for ", class_type->name(),
+ " must not specify Map argument; it is automatically inserted.");
+ }
+ Arguments get_struct_map_arguments;
+ get_struct_map_arguments.parameters.push_back(
+ VisitResult(TypeOracle::GetConstexprInstanceTypeType(),
+ CapifyStringWithUnderscores(class_type->name()) + "_TYPE"));
+ object_map =
+ GenerateCall("%GetStructMap", get_struct_map_arguments, {}, false);
+ CurrentSourcePosition::Scope current_pos(expr->pos);
+ initializer_results.names.insert(initializer_results.names.begin(),
+ MakeNode<Identifier>("map"));
+ initializer_results.field_value_map[map_field.name_and_type.name] =
+ object_map;
+ }
+ Arguments size_arguments;
+ size_arguments.parameters.push_back(object_map);
+ VisitResult object_size = GenerateCall("%GetAllocationBaseSize",
+ size_arguments, {class_type}, false);
+
+ object_size =
+ AddVariableObjectSize(object_size, class_type, initializer_results);
+
+ Arguments allocate_arguments;
+ allocate_arguments.parameters.push_back(object_size);
+ VisitResult allocate_result =
+ GenerateCall("%Allocate", allocate_arguments, {class_type}, false);
+ DCHECK(allocate_result.IsOnStack());
InitializeAggregate(class_type, allocate_result, initializer_results);
@@ -1390,7 +1417,8 @@ VisitResult ImplementationVisitor::Visit(NewExpression* expr) {
}
const Type* ImplementationVisitor::Visit(BreakStatement* stmt) {
- base::Optional<Binding<LocalLabel>*> break_label = TryLookupLabel("_break");
+ base::Optional<Binding<LocalLabel>*> break_label =
+ TryLookupLabel(kBreakLabelName);
if (!break_label) {
ReportError("break used outside of loop");
}
@@ -1400,7 +1428,7 @@ const Type* ImplementationVisitor::Visit(BreakStatement* stmt) {
const Type* ImplementationVisitor::Visit(ContinueStatement* stmt) {
base::Optional<Binding<LocalLabel>*> continue_label =
- TryLookupLabel("_continue");
+ TryLookupLabel(kContinueLabelName);
if (!continue_label) {
ReportError("continue used outside of loop");
}
@@ -1466,17 +1494,21 @@ VisitResult ImplementationVisitor::Visit(SpreadExpression* expr) {
"initialization expressions");
}
-void ImplementationVisitor::GenerateImplementation(const std::string& dir,
- Namespace* nspace) {
- std::string new_source(nspace->source());
- std::string base_file_name =
- "builtins-" + DashifyString(nspace->name()) + "-gen-tq";
+void ImplementationVisitor::GenerateImplementation(const std::string& dir) {
+ for (SourceId file : SourceFileMap::AllSources()) {
+ std::string path_from_root =
+ SourceFileMap::PathFromV8RootWithoutExtension(file);
- std::string source_file_name = dir + "/" + base_file_name + ".cc";
- WriteFile(source_file_name, new_source);
- std::string new_header(nspace->header());
- std::string header_file_name = dir + "/" + base_file_name + ".h";
- WriteFile(header_file_name, new_header);
+ std::string new_source(
+ GlobalContext::GeneratedPerFile(file).csa_ccfile.str());
+
+ std::string source_file_name = dir + "/" + path_from_root + "-tq-csa.cc";
+ WriteFile(source_file_name, new_source);
+ std::string new_header(
+ GlobalContext::GeneratedPerFile(file).csa_headerfile.str());
+ std::string header_file_name = dir + "/" + path_from_root + "-tq-csa.h";
+ WriteFile(header_file_name, new_header);
+ }
}
void ImplementationVisitor::GenerateMacroFunctionDeclaration(
@@ -1569,7 +1601,7 @@ void FailCallableLookup(const std::string& reason, const QualifiedName& name,
Callable* GetOrCreateSpecialization(const SpecializationKey& key) {
if (base::Optional<Callable*> specialization =
- key.generic->GetSpecialization(key.specialized_types)) {
+ key.generic->specializations().Get(key.specialized_types)) {
return *specialization;
}
return DeclarationVisitor::SpecializeImplicit(key);
@@ -1876,7 +1908,7 @@ LocationReference ImplementationVisitor::GetLocationReference(
return LocationReference::Temporary(
(*value)->value, "constant value " + expr->name->value);
}
- return LocationReference::VariableAccess((*value)->value);
+ return LocationReference::VariableAccess((*value)->value, *value);
}
}
@@ -1973,6 +2005,12 @@ void ImplementationVisitor::GenerateAssignToLocation(
GenerateImplicitConvert(variable.type(), assignment_value);
assembler().Poke(variable.stack_range(), converted_value.stack_range(),
variable.type());
+
+ // Local variables are detected by the existence of a binding. Assignment
+ // to local variables is recorded to support lint errors.
+ if (reference.binding()) {
+ (*reference.binding())->SetWritten();
+ }
} else if (reference.IsIndexedFieldAccess()) {
ReportError("assigning a value directly to an indexed field isn't allowed");
} else if (reference.IsHeapReference()) {
@@ -2167,6 +2205,7 @@ VisitResult ImplementationVisitor::GenerateCall(
if (is_tailcall) {
ReportError("can't tail call a macro");
}
+ macro->SetUsed();
if (return_type->IsConstexpr()) {
DCHECK_EQ(0, arguments.labels.size());
std::stringstream result;
@@ -2534,6 +2573,7 @@ std::string ImplementationVisitor::ExternalParameterName(
DEFINE_CONTEXTUAL_VARIABLE(ImplementationVisitor::ValueBindingsManager)
DEFINE_CONTEXTUAL_VARIABLE(ImplementationVisitor::LabelBindingsManager)
DEFINE_CONTEXTUAL_VARIABLE(ImplementationVisitor::CurrentCallable)
+DEFINE_CONTEXTUAL_VARIABLE(ImplementationVisitor::CurrentFileStreams)
DEFINE_CONTEXTUAL_VARIABLE(ImplementationVisitor::CurrentReturnValue)
bool IsCompatibleSignature(const Signature& sig, const TypeVector& types,
@@ -2556,7 +2596,7 @@ bool IsCompatibleSignature(const Signature& sig, const TypeVector& types,
base::Optional<Block*> ImplementationVisitor::GetCatchBlock() {
base::Optional<Block*> catch_block;
if (base::Optional<Binding<LocalLabel>*> catch_handler =
- TryLookupLabel("_catch")) {
+ TryLookupLabel(kCatchLabelName)) {
catch_block = assembler().NewBlock(base::nullopt, true);
}
return catch_block;
@@ -2566,7 +2606,7 @@ void ImplementationVisitor::GenerateCatchBlock(
base::Optional<Block*> catch_block) {
if (catch_block) {
base::Optional<Binding<LocalLabel>*> catch_handler =
- TryLookupLabel("_catch");
+ TryLookupLabel(kCatchLabelName);
if (assembler().CurrentBlockIsComplete()) {
assembler().Bind(*catch_block);
assembler().Goto((*catch_handler)->block, 1);
@@ -2594,6 +2634,12 @@ void ImplementationVisitor::VisitAllDeclarables() {
void ImplementationVisitor::Visit(Declarable* declarable) {
CurrentScope::Scope current_scope(declarable->ParentScope());
CurrentSourcePosition::Scope current_source_position(declarable->Position());
+ CurrentFileStreams::Scope current_file_streams(
+ &GlobalContext::GeneratedPerFile(declarable->Position().source));
+ if (Callable* callable = Callable::DynamicCast(declarable)) {
+ if (!callable->ShouldGenerateExternalCode())
+ CurrentFileStreams::Get() = nullptr;
+ }
switch (declarable->kind()) {
case Declarable::kExternMacro:
return Visit(ExternMacro::cast(declarable));
@@ -2612,6 +2658,7 @@ void ImplementationVisitor::Visit(Declarable* declarable) {
case Declarable::kExternConstant:
case Declarable::kNamespace:
case Declarable::kGeneric:
+ case Declarable::kGenericStructType:
return;
}
}
@@ -2891,9 +2938,81 @@ class MacroFieldOffsetsGenerator : public FieldOffsetsGenerator {
private:
std::ostream& out_;
};
-
} // namespace
+void ImplementationVisitor::GenerateInstanceTypes(
+ const std::string& output_directory) {
+ std::stringstream header;
+ std::string file_name = "instance-types-tq.h";
+ {
+ IncludeGuardScope(header, file_name);
+
+ header << "#define TORQUE_DEFINED_INSTANCE_TYPES(V) \\\n";
+ for (const TypeAlias* alias : GlobalContext::GetClasses()) {
+ const ClassType* type = ClassType::DynamicCast(alias->type());
+ if (type->IsExtern()) continue;
+ std::string type_name =
+ CapifyStringWithUnderscores(type->name()) + "_TYPE";
+ header << " V(" << type_name << ") \\\n";
+ }
+ header << "\n\n";
+
+ header << "#define TORQUE_STRUCT_LIST_GENERATOR(V, _) \\\n";
+ for (const TypeAlias* alias : GlobalContext::GetClasses()) {
+ const ClassType* type = ClassType::DynamicCast(alias->type());
+ if (type->IsExtern()) continue;
+ std::string type_name =
+ CapifyStringWithUnderscores(type->name()) + "_TYPE";
+ std::string variable_name = SnakeifyString(type->name());
+ header << " V(_, " << type_name << ", " << type->name() << ", "
+ << variable_name << ") \\\n";
+ }
+ header << "\n";
+ }
+ std::string output_header_path = output_directory + "/" + file_name;
+ WriteFile(output_header_path, header.str());
+}
+
+void ImplementationVisitor::GenerateCppForInternalClasses(
+ const std::string& output_directory) {
+ std::stringstream header;
+ std::stringstream inl;
+ std::string base_name = "internal-class-definitions-tq";
+ {
+ IncludeGuardScope header_guard(header, base_name + ".h");
+ header << "#include \"src/objects/objects.h\"\n";
+ header << "#include \"src/objects/struct.h\"\n";
+ header << "#include \"src/objects/js-objects.h\"\n";
+ header << "#include \"src/utils/utils.h\"\n";
+ header << "#include \"torque-generated/class-definitions-tq.h\"\n";
+ IncludeObjectMacrosScope header_macros(header);
+ NamespaceScope header_namespaces(header, {"v8", "internal"});
+
+ IncludeGuardScope inl_guard(inl, base_name + "-inl.h");
+ inl << "#include \"torque-generated/" << base_name << ".h\"\n";
+ inl << "#include \"torque-generated/class-definitions-tq-inl.h\"\n";
+ IncludeObjectMacrosScope inl_macros(inl);
+ NamespaceScope inl_namespaces(inl, {"v8", "internal"});
+
+ for (const TypeAlias* alias : GlobalContext::GetClasses()) {
+ const ClassType* type = ClassType::DynamicCast(alias->type());
+ if (type->IsExtern()) continue;
+ const ClassType* super = type->GetSuperClass();
+ std::string parent = "TorqueGenerated" + type->name() + "<" +
+ type->name() + ", " + super->name() + ">";
+ header << "class " << type->name() << ": public " << parent << " {\n";
+ header << " public:\n";
+ header << " TQ_OBJECT_CONSTRUCTORS(" << type->name() << ")\n";
+ header << "};\n\n";
+
+ inl << "TQ_OBJECT_CONSTRUCTORS_IMPL(" << type->name() << ")\n";
+ }
+ }
+ std::string dir_basename = output_directory + "/" + base_name;
+ WriteFile(dir_basename + ".h", header.str());
+ WriteFile(dir_basename + "-inl.h", inl.str());
+}
+
void ImplementationVisitor::GenerateClassFieldOffsets(
const std::string& output_directory) {
std::stringstream header;
@@ -2903,7 +3022,6 @@ void ImplementationVisitor::GenerateClassFieldOffsets(
for (const TypeAlias* alias : GlobalContext::GetClasses()) {
const ClassType* type = ClassType::DynamicCast(alias->type());
- if (!type->IsExtern()) continue;
// TODO(danno): Remove this once all classes use ClassFieldOffsetGenerator
// to generate field offsets without the use of macros.
@@ -2938,8 +3056,8 @@ class ClassFieldOffsetGenerator : public FieldOffsetsGenerator {
hdr_ << " static constexpr int " << field << " = " << previous_field_end_
<< ";\n";
hdr_ << " static constexpr int " << field_end << " = " << field << " + "
- << size_string << ";\n";
- previous_field_end_ = field_end;
+ << size_string << " - 1;\n";
+ previous_field_end_ = field_end + " + 1";
}
virtual void WriteMarker(const std::string& marker) {
hdr_ << " static constexpr int " << marker << " = " << previous_field_end_
@@ -3148,7 +3266,7 @@ void CppClassGenerator::GenerateFieldAccessorForSmi(const Field& f) {
// Generate implementation in inline header.
inl_ << "template <class D, class P>\n";
inl_ << type << " " << gen_name_ << "<D, P>::" << name << "() const {\n";
- inl_ << " return Smi::cast(READ_FIELD(*this, " << offset << "));\n";
+ inl_ << " return TaggedField<Smi, " << offset << ">::load(*this);\n";
inl_ << "}\n";
inl_ << "template <class D, class P>\n";
@@ -3173,6 +3291,7 @@ void CppClassGenerator::GenerateFieldAccessorForObject(const Field& f) {
hdr_ << " // Torque type: " << field_type->ToString() << "\n";
}
hdr_ << " inline " << type << " " << name << "() const;\n";
+ hdr_ << " inline " << type << " " << name << "(Isolate* isolate) const;\n";
hdr_ << " inline void set_" << name << "(" << type
<< " value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER);\n\n";
@@ -3185,10 +3304,20 @@ void CppClassGenerator::GenerateFieldAccessorForObject(const Field& f) {
// Generate implementation in inline header.
inl_ << "template <class D, class P>\n";
inl_ << type << " " << gen_name_ << "<D, P>::" << name << "() const {\n";
- inl_ << " Object value = READ_FIELD(*this, " << offset << ");\n";
+ inl_ << " Isolate* isolate = GetIsolateForPtrCompr(*this);\n";
+ inl_ << " return " << gen_name_ << "::" << name << "(isolate);\n";
+ inl_ << "}\n";
+
+ inl_ << "template <class D, class P>\n";
+ inl_ << type << " " << gen_name_ << "<D, P>::" << name
+ << "(Isolate* isolate) const {\n";
if (class_type) {
- inl_ << " return " << type << "::cast(value);\n";
+ inl_ << " return TaggedField<" << type << ", " << offset
+ << ">::load(isolate, *this);\n";
} else {
+ // TODO(tebbi): load value as HeapObject when possible
+ inl_ << " Object value = TaggedField<Object, " << offset
+ << ">::load(isolate, *this);\n";
inl_ << " DCHECK(" << type_check << ");\n";
inl_ << " return value;\n";
}
@@ -3235,14 +3364,18 @@ void ImplementationVisitor::GenerateClassDefinitions(
<< "#include \"torque-generated/class-definitions-tq.h\"\n\n";
implementation << "#include \"torque-generated/class-verifiers-tq.h\"\n\n";
implementation << "#include \"src/objects/struct-inl.h\"\n\n";
+ implementation
+ << "#include "
+ "\"torque-generated/internal-class-definitions-tq-inl.h\"\n\n";
NamespaceScope implementation_namespaces(implementation,
{"v8", "internal"});
for (const TypeAlias* alias : GlobalContext::GetClasses()) {
const ClassType* type = ClassType::DynamicCast(alias->type());
- if (!type->GenerateCppClassDefinitions()) continue;
- CppClassGenerator g(type, header, inline_header, implementation);
- g.GenerateClass();
+ if (type->GenerateCppClassDefinitions()) {
+ CppClassGenerator g(type, header, inline_header, implementation);
+ g.GenerateClass();
+ }
}
}
WriteFile(file_basename + ".h", header.str());
@@ -3282,6 +3415,8 @@ void ImplementationVisitor::GeneratePrintDefinitions(
impl << "#include \"src/objects/objects.h\"\n\n";
impl << "#include <iosfwd>\n\n";
+ impl << "#include "
+ "\"torque-generated/internal-class-definitions-tq-inl.h\"\n";
impl << "#include \"src/objects/struct-inl.h\"\n\n";
impl << "#include \"src/objects/template-objects-inl.h\"\n\n";
@@ -3291,7 +3426,7 @@ void ImplementationVisitor::GeneratePrintDefinitions(
const ClassType* type = ClassType::DynamicCast(alias->type());
if (!type->ShouldGeneratePrint()) continue;
- if (type->IsExtern() && type->GenerateCppClassDefinitions()) {
+ if (type->GenerateCppClassDefinitions()) {
const ClassType* super = type->GetSuperClass();
std::string gen_name = "TorqueGenerated" + type->name();
std::string gen_name_T =
@@ -3319,8 +3454,10 @@ void GenerateClassFieldVerifier(const std::string& class_name,
if (!f.generate_verify) return;
const Type* field_type = f.name_and_type.type;
- // We only verify tagged types, not raw numbers or pointers.
- if (!field_type->IsSubtypeOf(TypeOracle::GetTaggedType())) return;
+ // We only verify tagged types, not raw numbers or pointers. Note that this
+ // must check against GetObjectType not GetTaggedType, because Uninitialized
+ // is a Tagged but should not be verified.
+ if (!field_type->IsSubtypeOf(TypeOracle::GetObjectType())) return;
if (f.index) {
if ((*f.index)->name_and_type.type != TypeOracle::GetSmiType()) {
@@ -3328,26 +3465,24 @@ void GenerateClassFieldVerifier(const std::string& class_name,
}
// We already verified the index field because it was listed earlier, so we
// can assume it's safe to read here.
- cc_contents << " for (int i = 0; i < Smi::ToInt(READ_FIELD(o, "
- << class_name << "::k"
- << CamelifyString((*f.index)->name_and_type.name)
- << "Offset)); ++i) {\n";
+ cc_contents << " for (int i = 0; i < TaggedField<Smi, " << class_name
+ << "::k" << CamelifyString((*f.index)->name_and_type.name)
+ << "Offset>::load(o).value(); ++i) {\n";
} else {
cc_contents << " {\n";
}
const char* object_type = f.is_weak ? "MaybeObject" : "Object";
- const char* read_fn = f.is_weak ? "READ_WEAK_FIELD" : "READ_FIELD";
const char* verify_fn =
f.is_weak ? "VerifyMaybeObjectPointer" : "VerifyPointer";
- const char* index_offset = f.index ? " + i * kTaggedSize" : "";
+ const char* index_offset = f.index ? "i * kTaggedSize" : "0";
// Name the local var based on the field name for nicer CHECK output.
- const std::string value = f.name_and_type.name + "_value";
+ const std::string value = f.name_and_type.name + "__value";
// Read the field.
- cc_contents << " " << object_type << " " << value << " = " << read_fn
- << "(o, " << class_name << "::k"
- << CamelifyString(f.name_and_type.name) << "Offset"
+ cc_contents << " " << object_type << " " << value << " = TaggedField<"
+ << object_type << ", " << class_name << "::k"
+ << CamelifyString(f.name_and_type.name) << "Offset>::load(o, "
<< index_offset << ");\n";
// Call VerifyPointer or VerifyMaybeObjectPointer on it.
@@ -3365,16 +3500,6 @@ void GenerateClassFieldVerifier(const std::string& class_name,
if (!type_check.empty()) type_check += " || ";
type_check += strong_value + ".Is" + runtime_type + "()";
}
- // Many subtypes of JSObject can be verified in partially-initialized states
- // where their fields are all undefined. We explicitly allow that here. For
- // any such fields that should never be undefined, we can include extra code
- // in the custom verifier functions for them.
- // TODO(1240798): If Factory::InitializeJSObjectFromMap is updated to use
- // correct initial values based on the type of the field, then make this
- // check stricter too.
- if (class_type.IsSubtypeOf(TypeOracle::GetJSObjectType())) {
- type_check += " || " + strong_value + ".IsUndefined(isolate)";
- }
cc_contents << " CHECK(" << type_check << ");\n";
}
cc_contents << " }\n";
@@ -3398,6 +3523,8 @@ void ImplementationVisitor::GenerateClassVerifiers(
cc_contents << "#include " << StringLiteralQuote(include_path) << "\n";
}
cc_contents << "#include \"torque-generated/" << file_name << ".h\"\n";
+ cc_contents << "#include "
+ "\"torque-generated/internal-class-definitions-tq-inl.h\"\n";
IncludeObjectMacrosScope object_macros(cc_contents);
@@ -3408,7 +3535,7 @@ void ImplementationVisitor::GenerateClassVerifiers(
h_contents << "class Isolate;\n";
for (const TypeAlias* alias : GlobalContext::GetClasses()) {
const ClassType* type = ClassType::DynamicCast(alias->type());
- if (!type->IsExtern() || !type->ShouldGenerateVerify()) continue;
+ if (!type->ShouldGenerateVerify()) continue;
h_contents << "class " << type->name() << ";\n";
}
@@ -3420,7 +3547,7 @@ void ImplementationVisitor::GenerateClassVerifiers(
for (const TypeAlias* alias : GlobalContext::GetClasses()) {
const ClassType* type = ClassType::DynamicCast(alias->type());
std::string name = type->name();
- if (!type->IsExtern() || !type->ShouldGenerateVerify()) continue;
+ if (!type->ShouldGenerateVerify()) continue;
std::string method_name = name + "Verify";
@@ -3483,10 +3610,14 @@ void ImplementationVisitor::GenerateExportedMacrosAssembler(
h_contents << "#include \"src/compiler/code-assembler.h\"\n";
h_contents << "#include \"src/execution/frames.h\"\n";
h_contents << "#include \"torque-generated/csa-types-tq.h\"\n";
+ h_contents
+ << "#include \"torque-generated/internal-class-definitions-tq.h\"\n";
cc_contents << "#include \"torque-generated/" << file_name << ".h\"\n";
- for (Namespace* n : GlobalContext::Get().GetNamespaces()) {
- cc_contents << "#include \"torque-generated/builtins-" +
- DashifyString(n->name()) + "-gen-tq.h\"\n";
+
+ for (SourceId file : SourceFileMap::AllSources()) {
+ cc_contents << "#include \"torque-generated/" +
+ SourceFileMap::PathFromV8RootWithoutExtension(file) +
+ "-tq-csa.h\"\n";
}
NamespaceScope h_namespaces(h_contents, {"v8", "internal"});
@@ -3541,13 +3672,13 @@ void ImplementationVisitor::GenerateCSATypes(
NamespaceScope h_namespaces(h_contents, {"v8", "internal"});
- for (auto& declarable : GlobalContext::AllDeclarables()) {
- TypeAlias* alias = TypeAlias::DynamicCast(declarable.get());
- if (!alias || alias->IsRedeclaration()) continue;
- const StructType* struct_type = StructType::DynamicCast(alias->type());
+ // Generates headers for all structs in a topologically-sorted order, since
+ // TypeOracle keeps them in the order of their resolution
+ for (auto& type : *TypeOracle::GetAggregateTypes()) {
+ const StructType* struct_type = StructType::DynamicCast(type.get());
if (!struct_type) continue;
- const std::string& name = struct_type->name();
- h_contents << "struct TorqueStruct" << name << " {\n";
+ h_contents << "struct " << struct_type->GetGeneratedTypeNameImpl()
+ << " {\n";
for (auto& field : struct_type->fields()) {
h_contents << " " << field.name_and_type.type->GetGeneratedTypeName();
h_contents << " " << field.name_and_type.name << ";\n";
@@ -3583,6 +3714,33 @@ void ImplementationVisitor::GenerateCSATypes(
WriteFile(output_directory + "/" + file_name + ".h", h_contents.str());
}
+void ReportAllUnusedMacros() {
+ for (const auto& declarable : GlobalContext::AllDeclarables()) {
+ if (!declarable->IsMacro() || declarable->IsExternMacro()) continue;
+
+ Macro* macro = Macro::cast(declarable.get());
+ if (macro->IsUsed()) continue;
+
+ if (macro->IsTorqueMacro() && TorqueMacro::cast(macro)->IsExportedToCSA()) {
+ continue;
+ }
+
+ std::vector<std::string> ignored_prefixes = {"Convert<", "Cast<",
+ "FromConstexpr<"};
+ const std::string name = macro->ReadableName();
+ const bool ignore =
+ std::any_of(ignored_prefixes.begin(), ignored_prefixes.end(),
+ [&name](const std::string& prefix) {
+ return StringStartsWith(name, prefix);
+ });
+
+ if (!ignore) {
+ Lint("Macro '", macro->ReadableName(), "' is never used.")
+ .Position(macro->IdentifierPosition());
+ }
+ }
+}
+
} // namespace torque
} // namespace internal
} // namespace v8