diff options
Diffstat (limited to 'deps/v8/src/torque/implementation-visitor.cc')
-rw-r--r-- | deps/v8/src/torque/implementation-visitor.cc | 702 |
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, ¶meters, - ¶meter_types, ¶meter_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, ¶meters, ¶meter_types, ¶meter_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, ¶meters, ¶meter_types, - ¶meter_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, ¶meters, ¶meter_types, ¶meter_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, ¶meters, ¶meter_types, + ¶meter_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, ¶meters, ¶meter_types, + ¶meter_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, ¶meters, ¶meter_types, + ¶meter_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 |