Commit f2dbf318 authored by Nico Hartmann's avatar Nico Hartmann Committed by V8 LUCI CQ

[Torque] Introduce a builder pattern to generate C++ code

Generating C++ source files is very cumbersome using raw ostreams. This
CL introduces a few classes und the torque::cpp namespace that build an
abstraction of printing/formatting C++ source code (mostly functions for
now).

This is an initial implementation with a limited set of features and
uses. Landing features incrementally shall avoid huge CLs (+reviews) and
complex rebasing.

Bug: v8:7793
Change-Id: I3ae869755156175c7b37ea9f649e2f9c431ce3a3
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2784688Reviewed-by: 's avatarClemens Backes <clemensb@chromium.org>
Reviewed-by: 's avatarSeth Brenith <seth.brenith@microsoft.com>
Commit-Queue: Nico Hartmann <nicohartmann@chromium.org>
Cr-Commit-Position: refs/heads/master@{#74705}
parent 78a06b56
......@@ -4454,6 +4454,8 @@ v8_source_set("torque_base") {
"src/torque/class-debug-reader-generator.cc",
"src/torque/constants.h",
"src/torque/contextual.h",
"src/torque/cpp-builder.cc",
"src/torque/cpp-builder.h",
"src/torque/csa-generator.cc",
"src/torque/csa-generator.h",
"src/torque/declarable.cc",
......
......@@ -81,7 +81,7 @@ class Flags final {
constexpr operator mask_type() const { return mask_; }
constexpr bool operator!() const { return !mask_; }
Flags without(flag_type flag) { return *this & (~Flags(flag)); }
Flags without(flag_type flag) const { return *this & (~Flags(flag)); }
friend size_t hash_value(const Flags& flags) { return flags.mask_; }
......
// Copyright 2021 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/torque/cpp-builder.h"
namespace v8 {
namespace internal {
namespace torque {
namespace cpp {
void Function::PrintDeclarationHeader(std::ostream& stream,
int indentation) const {
if (!description_.empty()) {
stream << std::string(indentation, ' ') << "// " << description_ << "\n";
}
stream << std::string(indentation, ' ');
if (IsExport()) stream << "V8_EXPORT_PRIVATE ";
if (IsV8Inline())
stream << "V8_INLINE ";
else if (IsInline())
stream << "inline ";
if (IsStatic()) stream << "static ";
if (IsConstexpr()) stream << "constexpr ";
stream << return_type_ << " " << name_ << "(";
bool first = true;
for (const auto& p : parameters_) {
if (!first) stream << ", ";
stream << p.type;
if (!p.name.empty()) stream << " " << p.name;
if (!p.default_value.empty()) stream << " = " << p.default_value;
first = false;
}
stream << ")";
if (IsConst()) stream << " const";
}
void Function::PrintDeclaration(std::ostream& stream, int indentation) const {
PrintDeclarationHeader(stream, indentation);
stream << ";\n";
}
void Function::PrintDefinition(
std::ostream& stream, const std::function<void(std::ostream&)>& builder,
int indentation) const {
PrintBeginDefinition(stream, indentation);
if (builder) {
builder(stream);
}
PrintEndDefinition(stream, indentation);
}
void Function::PrintInlineDefinition(
std::ostream& stream, const std::function<void(std::ostream&)>& builder,
int indentation) const {
PrintDeclarationHeader(stream, indentation);
stream << " {\n";
if (builder) {
builder(stream);
}
PrintEndDefinition(stream, indentation);
}
void Function::PrintBeginDefinition(std::ostream& stream,
int indentation) const {
std::string scope;
if (owning_class_) {
scope = owning_class_->GetName();
const auto class_template_parameters =
owning_class_->GetTemplateParameters();
if (!class_template_parameters.empty()) {
stream << std::string(indentation, ' ');
stream << "template<";
scope += "<";
bool first = true;
for (const auto& p : class_template_parameters) {
if (!first) {
stream << ", ";
scope += ", ";
}
if (p.type.empty()) {
stream << "class " << p.name;
} else {
stream << p.type << " " << p.name;
}
scope += p.name;
first = false;
}
stream << ">\n";
scope += ">";
}
scope += "::";
}
stream << std::string(indentation, ' ') << return_type_ << " " << scope
<< name_ << "(";
bool first = true;
for (const auto& p : parameters_) {
if (!first) stream << ", ";
stream << p.type;
if (!p.name.empty()) stream << " " << p.name;
first = false;
}
stream << ")";
if (IsConst()) {
stream << " const";
}
stream << " {\n";
}
void Function::PrintEndDefinition(std::ostream& stream, int indentation) const {
stream << std::string(indentation, ' ');
stream << "}\n\n";
}
void File::BeginIncludeGuard(const std::string& name) {
s() << "#ifndef " << name
<< "\n"
"#define "
<< name << "\n";
}
void File::EndIncludeGuard(const std::string& name) {
s() << "#endif // " << name << "\n";
}
void File::BeginNamespace(std::string name) {
DCHECK(!name.empty());
DCHECK_EQ(name.find(':'), std::string::npos);
s() << "namespace " << name << " {\n";
namespaces_.push(std::move(name));
}
void File::BeginNamespace(std::string name0, std::string name1) {
BeginNamespace(name0);
BeginNamespace(name1);
}
void File::EndNamespace(const std::string& name) {
DCHECK(!namespaces_.empty());
DCHECK_EQ(namespaces_.top(), name);
s() << "} // namespace " << namespaces_.top() << "\n";
namespaces_.pop();
}
void File::EndNamespace(const std::string& name0, const std::string& name1) {
EndNamespace(name1);
EndNamespace(name0);
}
} // namespace cpp
} // namespace torque
} // namespace internal
} // namespace v8
// Copyright 2021 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_TORQUE_CPP_BUILDER_H_
#define V8_TORQUE_CPP_BUILDER_H_
#include <stack>
#include "src/torque/ast.h"
#include "src/torque/types.h"
namespace v8 {
namespace internal {
namespace torque {
namespace cpp {
struct TemplateParameter {
explicit TemplateParameter(std::string name) : name(std::move(name)) {}
TemplateParameter(std::string type, std::string name)
: name(std::move(name)), type(std::move(type)) {}
std::string name;
std::string type;
};
class Class {
public:
explicit Class(std::string name) : name_(std::move(name)) {}
Class(std::vector<TemplateParameter> template_parameters, std::string name)
: template_parameters_(std::move(template_parameters)),
name_(std::move(name)) {}
std::string GetName() const { return name_; }
std::vector<TemplateParameter> GetTemplateParameters() const {
return template_parameters_;
}
private:
std::vector<TemplateParameter> template_parameters_;
std::string name_;
};
#define FUNCTION_FLAG_LIST(V) \
V(Inline, 0x01) \
V(V8Inline, 0x03) \
V(Const, 0x04) \
V(Constexpr, 0x08) \
V(Export, 0x10) \
V(Static, 0x20) \
V(Override, 0x40)
class Function {
public:
enum FunctionFlag {
#define ENTRY(name, value) k##name = value,
FUNCTION_FLAG_LIST(ENTRY)
#undef ENTRY
};
struct Parameter {
std::string type;
std::string name;
std::string default_value;
Parameter(std::string type, std::string name,
std::string default_value = {})
: type(std::move(type)),
name(std::move(name)),
default_value(std::move(default_value)) {}
};
explicit Function(std::string name)
: owning_class_(nullptr), name_(std::move(name)) {}
Function(Class* owning_class, std::string name)
: owning_class_(owning_class), name_(std::move(name)) {}
~Function() = default;
static Function DefaultGetter(std::string return_type, Class* owner,
std::string name) {
Function getter(owner, std::move(name));
getter.SetReturnType(std::move(return_type));
getter.SetInline();
getter.SetConst();
return getter;
}
static Function DefaultSetter(Class* owner, std::string name,
std::string parameter_type,
std::string parameter_name) {
Function setter(owner, std::move(name));
setter.SetReturnType("void");
setter.AddParameter(std::move(parameter_type), std::move(parameter_name));
setter.SetInline();
return setter;
}
void SetFlag(FunctionFlag flag, bool value = true) {
if (value) {
flags_ = flags_ | flag;
} else {
flags_ = flags_.without(flag);
}
}
void SetFlags(base::Flags<FunctionFlag> flags, bool value = true) {
if (value) {
flags_ |= flags;
} else {
flags_ &= ~flags;
}
}
bool HasFlag(FunctionFlag flag) const { return (flags_ & flag) == flag; }
#define ACCESSOR(name, value) \
void Set##name(bool v = true) { SetFlag(k##name, v); } \
bool Is##name() const { return HasFlag(k##name); }
FUNCTION_FLAG_LIST(ACCESSOR)
#undef ACCESSOR
void SetDescription(std::string description) {
description_ = std::move(description);
}
void SetName(std::string name) { name_ = std::move(name); }
void SetReturnType(std::string return_type) {
return_type_ = std::move(return_type);
}
void AddParameter(std::string type, std::string name = {},
std::string default_value = {}) {
parameters_.emplace_back(std::move(type), std::move(name),
std::move(default_value));
}
void InsertParameter(int index, std::string type, std::string name = {},
std::string default_value = {}) {
DCHECK_GE(index, 0);
DCHECK_LE(index, parameters_.size());
parameters_.insert(
parameters_.begin() + index,
Parameter(std::move(type), std::move(name), std::move(default_value)));
}
std::vector<Parameter> GetParameters() const { return parameters_; }
std::vector<std::string> GetParameterNames() const {
std::vector<std::string> names;
std::transform(parameters_.begin(), parameters_.end(),
std::back_inserter(names),
[](const Parameter& p) { return p.name; });
return names;
}
void PrintDeclaration(std::ostream& stream, int indentation = 0) const;
void PrintDefinition(std::ostream& stream,
const std::function<void(std::ostream&)>& builder,
int indentation = 0) const;
void PrintInlineDefinition(std::ostream& stream,
const std::function<void(std::ostream&)>& builder,
int indentation = 0) const;
void PrintBeginDefinition(std::ostream& stream, int indentation = 0) const;
void PrintEndDefinition(std::ostream& stream, int indentation = 0) const;
protected:
void PrintDeclarationHeader(std::ostream& stream, int indentation) const;
private:
Class* owning_class_;
std::string description_;
std::string name_;
std::string return_type_;
std::vector<Parameter> parameters_;
base::Flags<FunctionFlag> flags_;
};
DEFINE_OPERATORS_FOR_FLAGS(base::Flags<Function::FunctionFlag>)
#undef FUNCTION_FLAG_LIST
class File {
public:
explicit File(std::ostream& stream) : stream_(&stream) {}
void BeginIncludeGuard(const std::string& name);
void EndIncludeGuard(const std::string& name);
void BeginNamespace(std::string name);
void BeginNamespace(std::string name0, std::string name1);
void EndNamespace(const std::string& name);
void EndNamespace(const std::string& name0, const std::string& name1);
void AddInclude(std::string include) { includes_.insert(std::move(include)); }
template <typename T>
File& operator<<(const T& value) {
s() << value;
return *this;
}
protected:
std::ostream& s() { return *stream_; }
private:
std::ostream* stream_;
std::set<std::string> includes_;
std::stack<std::string> namespaces_;
};
class IncludeGuardScope {
public:
explicit IncludeGuardScope(File* file, std::string name)
: file_(file), name_(std::move(name)) {
file_->BeginIncludeGuard(name_);
}
IncludeGuardScope(const IncludeGuardScope&) = delete;
IncludeGuardScope(IncludeGuardScope&& other) V8_NOEXCEPT : file_(nullptr),
name_() {
std::swap(file_, other.file_);
std::swap(name_, other.name_);
}
~IncludeGuardScope() {
if (file_) {
file_->EndIncludeGuard(name_);
}
}
IncludeGuardScope& operator=(const IncludeGuardScope&) = delete;
IncludeGuardScope& operator=(IncludeGuardScope&& other) V8_NOEXCEPT {
if (this != &other) {
DCHECK_NULL(file_);
DCHECK(name_.empty());
std::swap(file_, other.file_);
std::swap(name_, other.name_);
}
return *this;
}
private:
File* file_;
std::string name_;
};
} // namespace cpp
} // namespace torque
} // namespace internal
} // namespace v8
#endif // V8_TORQUE_CPP_BUILDER_H_
......@@ -11,6 +11,7 @@
#include "src/common/globals.h"
#include "src/torque/ast.h"
#include "src/torque/contextual.h"
#include "src/torque/cpp-builder.h"
#include "src/torque/declarable.h"
namespace v8 {
......@@ -62,10 +63,17 @@ class GlobalContext : public ContextualClass<GlobalContext> {
}
struct PerFileStreams {
PerFileStreams() : file(SourceId::Invalid()) {}
PerFileStreams()
: file(SourceId::Invalid()),
csa_header(csa_headerfile),
csa_cc(csa_ccfile),
class_definition_cc(class_definition_ccfile) {}
SourceId file;
std::stringstream csa_headerfile;
cpp::File csa_header;
std::stringstream csa_ccfile;
cpp::File csa_cc;
std::stringstream class_definition_headerfile;
// The beginning of the generated -inl.inc file, which includes declarations
......@@ -79,6 +87,7 @@ class GlobalContext : public ContextualClass<GlobalContext> {
std::stringstream class_definition_inline_headerfile;
std::stringstream class_definition_ccfile;
cpp::File class_definition_cc;
std::set<SourceId> required_builtin_includes;
};
......
......@@ -13,6 +13,7 @@
#include "src/torque/cc-generator.h"
#include "src/torque/cfg.h"
#include "src/torque/constants.h"
#include "src/torque/cpp-builder.h"
#include "src/torque/csa-generator.h"
#include "src/torque/declaration-visitor.h"
#include "src/torque/global-context.h"
......@@ -28,6 +29,12 @@ namespace v8 {
namespace internal {
namespace torque {
// Sadly, 'using std::string_literals::operator""s;' is bugged in MSVC (see
// https://developercommunity.visualstudio.com/t/Incorrect-warning-when-using-standard-st/673948).
// TODO(nicohartmann@): Change to 'using std::string_literals::operator""s;'
// once this is fixed.
using namespace std::string_literals; // NOLINT(build/namespaces)
namespace {
const char* BuiltinIncludesMarker = "// __BUILTIN_INCLUDES_MARKER__\n";
} // namespace
......@@ -72,61 +79,55 @@ void ImplementationVisitor::BeginGeneratedFiles() {
}
}
for (SourceId file : SourceFileMap::AllSources()) {
auto& streams = GlobalContext::GeneratedPerFile(file);
for (SourceId source : SourceFileMap::AllSources()) {
auto& streams = GlobalContext::GeneratedPerFile(source);
// Output beginning of CSA .cc file.
{
std::ostream& out = streams.csa_ccfile;
cpp::File& file = streams.csa_cc;
for (const std::string& include_path : GlobalContext::CppIncludes()) {
out << "#include " << StringLiteralQuote(include_path) << "\n";
file << "#include " << StringLiteralQuote(include_path) << "\n";
}
out << "// Required Builtins:\n";
out << "#include \"torque-generated/" +
SourceFileMap::PathFromV8RootWithoutExtension(file) +
"-tq-csa.h\"\n";
file << "// Required Builtins:\n";
file << "#include \"torque-generated/" +
SourceFileMap::PathFromV8RootWithoutExtension(source) +
"-tq-csa.h\"\n";
// Now that required include files are collected while generting the file,
// we only know the full set at the end. Insert a marker here that is
// replaced with the list of includes at the very end.
// TODO(nicohartmann@): This is not the most beautiful way to do this,
// replace once the cpp file builder is available, where this can be
// handled easily.
out << BuiltinIncludesMarker;
out << "\n";
file << BuiltinIncludesMarker;
file << "\n";
out << "namespace v8 {\n"
<< "namespace internal {\n"
<< "\n";
streams.csa_cc.BeginNamespace("v8", "internal");
}
// Output beginning of CSA .h file.
{
std::ostream& out = streams.csa_headerfile;
cpp::File& file = streams.csa_header;
std::string header_define =
"V8_GEN_TORQUE_GENERATED_" +
UnderlinifyPath(SourceFileMap::PathFromV8Root(file)) + "_CSA_H_";
out << "#ifndef " << header_define << "\n";
out << "#define " << header_define << "\n\n";
out << "#include \"src/builtins/torque-csa-header-includes.h\"\n";
out << "\n";
UnderlinifyPath(SourceFileMap::PathFromV8Root(source)) + "_CSA_H_";
streams.csa_header.BeginIncludeGuard(header_define);
file << "#include \"src/builtins/torque-csa-header-includes.h\"\n";
file << "\n";
out << "namespace v8 {\n"
<< "namespace internal {\n"
<< "\n";
streams.csa_header.BeginNamespace("v8", "internal");
}
// Output beginning of class definition .cc file.
{
std::ostream& out = streams.class_definition_ccfile;
if (contains_class_definitions.count(file) != 0) {
out << "#include \""
<< SourceFileMap::PathFromV8RootWithoutExtension(file)
<< "-inl.h\"\n\n";
out << "#include \"torque-generated/class-verifiers.h\"\n";
out << "#include \"src/objects/instance-type-inl.h\"\n\n";
cpp::File& file = streams.class_definition_cc;
if (contains_class_definitions.count(source) != 0) {
file << "#include \""
<< SourceFileMap::PathFromV8RootWithoutExtension(source)
<< "-inl.h\"\n\n";
file << "#include \"torque-generated/class-verifiers.h\"\n";
file << "#include \"src/objects/instance-type-inl.h\"\n\n";
}
out << "namespace v8 {\n";
out << "namespace internal {\n";
streams.class_definition_cc.BeginNamespace("v8", "internal");
}
}
}
......@@ -134,35 +135,27 @@ void ImplementationVisitor::BeginGeneratedFiles() {
void ImplementationVisitor::EndGeneratedFiles() {
for (SourceId file : SourceFileMap::AllSources()) {
auto& streams = GlobalContext::GeneratedPerFile(file);
{
std::ostream& out = streams.csa_ccfile;
out << "} // namespace internal\n"
<< "} // namespace v8\n"
<< "\n";
}
{
std::ostream& out = streams.csa_headerfile;
// Output ending of CSA .cc file.
streams.csa_cc.EndNamespace("v8", "internal");
// Output ending of CSA .h file.
{
std::string header_define =
"V8_GEN_TORQUE_GENERATED_" +
UnderlinifyPath(SourceFileMap::PathFromV8Root(file)) + "_CSA_H_";
out << "} // namespace internal\n"
<< "} // namespace v8\n"
<< "\n";
out << "#endif // " << header_define << "\n";
streams.csa_header.EndNamespace("v8", "internal");
streams.csa_header.EndIncludeGuard(header_define);
}
{
std::ostream& out = streams.class_definition_ccfile;
out << "} // namespace v8\n";
out << "} // namespace internal\n";
}
// Output ending of class definition .cc file.
streams.class_definition_cc.EndNamespace("v8", "internal");
}
}
void ImplementationVisitor::BeginDebugMacrosFile() {
// TODO(torque-builer): Can use builder for debug_macros_*_
std::ostream& source = debug_macros_cc_;
std::ostream& header = debug_macros_h_;
......@@ -191,6 +184,7 @@ void ImplementationVisitor::BeginDebugMacrosFile() {
}
void ImplementationVisitor::EndDebugMacrosFile() {
// TODO(torque-builder): Can use builder for debug_macros_*_
std::ostream& source = debug_macros_cc_;
std::ostream& header = debug_macros_h_;
......@@ -212,33 +206,31 @@ void ImplementationVisitor::Visit(NamespaceConstant* decl) {
BindingsManagersScope bindings_managers_scope;
csa_headerfile() << " ";
GenerateFunctionDeclaration(csa_headerfile(), "", decl->external_name(),
signature, {});
csa_headerfile() << ";\n";
cpp::Function f =
GenerateFunction(nullptr, decl->external_name(), signature, {});
GenerateFunctionDeclaration(csa_ccfile(), "", decl->external_name(),
signature, {});
csa_ccfile() << " {\n";
csa_ccfile() << " compiler::CodeAssembler ca_(state_);\n";
f.PrintDeclaration(csa_headerfile());
DCHECK(!signature.return_type->IsVoidOrNever());
f.PrintDefinition(csa_ccfile(), [&](std::ostream& stream) {
stream << " compiler::CodeAssembler ca_(state_);\n";
assembler_ = CfgAssembler(Stack<const Type*>{});
DCHECK(!signature.return_type->IsVoidOrNever());
VisitResult expression_result = Visit(decl->body());
VisitResult return_result =
GenerateImplicitConvert(signature.return_type, expression_result);
assembler_ = CfgAssembler(Stack<const Type*>{});
CSAGenerator csa_generator{assembler().Result(), csa_ccfile()};
Stack<std::string> values = *csa_generator.EmitGraph(Stack<std::string>{});
VisitResult expression_result = Visit(decl->body());
VisitResult return_result =
GenerateImplicitConvert(signature.return_type, expression_result);
assembler_ = base::nullopt;
CSAGenerator csa_generator{assembler().Result(), stream};
Stack<std::string> values = *csa_generator.EmitGraph(Stack<std::string>{});
csa_ccfile() << " return ";
CSAGenerator::EmitCSAValue(return_result, values, csa_ccfile());
csa_ccfile() << ";\n";
csa_ccfile() << "}\n\n";
assembler_ = base::nullopt;
stream << " return ";
CSAGenerator::EmitCSAValue(return_result, values, stream);
stream << ";";
});
}
void ImplementationVisitor::Visit(TypeAlias* alias) {
......@@ -370,24 +362,23 @@ void ImplementationVisitor::VisitMacroCommon(Macro* macro) {
bool has_return_value =
can_return && return_type != TypeOracle::GetVoidType();
GenerateMacroFunctionDeclaration(csa_headerfile(), macro);
csa_headerfile() << ";\n";
cpp::Function f = GenerateMacroFunctionDeclaration(macro);
f.PrintDeclaration(csa_headerfile());
cpp::File csa_cc(csa_ccfile());
// Avoid multiple-definition errors since it is possible for multiple
// generated -inl.inc files to all contain function definitions for the same
// Torque macro.
base::Optional<cpp::IncludeGuardScope> include_guard;
if (output_type_ == OutputType::kCC) {
csa_ccfile() << "#ifndef V8_INTERNAL_DEFINED_" << macro->CCName() << "\n";
csa_ccfile() << "#define V8_INTERNAL_DEFINED_" << macro->CCName() << "\n";
include_guard.emplace(&csa_cc, "V8_INTERNAL_DEFINED_"s + macro->CCName());
} else if (output_type_ == OutputType::kCCDebug) {
csa_ccfile() << "#ifndef V8_INTERNAL_DEFINED_" << macro->CCDebugName()
<< "\n";
csa_ccfile() << "#define V8_INTERNAL_DEFINED_" << macro->CCDebugName()
<< "\n";
include_guard.emplace(&csa_cc,
"V8_INTERNAL_DEFINED_"s + macro->CCDebugName());
}
GenerateMacroFunctionDeclaration(csa_ccfile(), macro);
csa_ccfile() << " {\n";
f.PrintBeginDefinition(csa_ccfile());
if (output_type_ == OutputType::kCC) {
// For now, generated C++ is only for field offset computations. If we ever
......@@ -506,14 +497,9 @@ void ImplementationVisitor::VisitMacroCommon(Macro* macro) {
}
csa_ccfile() << ";\n";
}
csa_ccfile() << "}\n";
if (output_type_ == OutputType::kCC) {
csa_ccfile() << "#endif // V8_INTERNAL_DEFINED_" << macro->CCName()
<< "\n";
} else if (output_type_ == OutputType::kCCDebug) {
csa_ccfile() << "#endif // V8_INTERNAL_DEFINED_" << macro->CCDebugName()
<< "\n";
}
f.PrintEndDefinition(csa_ccfile());
include_guard.reset();
csa_ccfile() << "\n";
}
......@@ -1765,6 +1751,7 @@ void ImplementationVisitor::GenerateImplementation(const std::string& dir) {
csa_cc.replace(pos, strlen(BuiltinIncludesMarker), std::move(includes));
}
// TODO(torque-builder): Pass file directly.
WriteFile(base_filename + "-tq-csa.cc", std::move(csa_cc));
WriteFile(base_filename + "-tq-csa.h", streams.csa_headerfile.str());
WriteFile(base_filename + "-tq.inc",
......@@ -1781,63 +1768,66 @@ void ImplementationVisitor::GenerateImplementation(const std::string& dir) {
WriteFile(dir + "/debug-macros.cc", debug_macros_cc_.str());
}
void ImplementationVisitor::GenerateMacroFunctionDeclaration(std::ostream& o,
Macro* macro) {
GenerateFunctionDeclaration(o, "",
output_type_ == OutputType::kCC
? macro->CCName()
: output_type_ == OutputType::kCCDebug
? macro->CCDebugName()
: macro->ExternalName(),
macro->signature(), macro->parameter_names());
cpp::Function ImplementationVisitor::GenerateMacroFunctionDeclaration(
Macro* macro) {
return GenerateFunction(nullptr,
output_type_ == OutputType::kCC
? macro->CCName()
: output_type_ == OutputType::kCCDebug
? macro->CCDebugName()
: macro->ExternalName(),
macro->signature(), macro->parameter_names());
}
std::vector<std::string> ImplementationVisitor::GenerateFunctionDeclaration(
std::ostream& o, const std::string& macro_prefix, const std::string& name,
const Signature& signature, const NameVector& parameter_names,
bool pass_code_assembler_state) {
std::vector<std::string> generated_parameter_names;
if (output_type_ == OutputType::kCC) {
o << "inline ";
}
cpp::Function ImplementationVisitor::GenerateFunction(
cpp::Class* owner, const std::string& name, const Signature& signature,
const NameVector& parameter_names, bool pass_code_assembler_state,
std::vector<std::string>* generated_parameter_names) {
cpp::Function f(owner, name);
f.SetInline(output_type_ == OutputType::kCC);
// Set return type.
// TODO(torque-builder): Consider an overload of SetReturnType that handles
// this.
if (signature.return_type->IsVoidOrNever()) {
o << "void";
f.SetReturnType("void");
} else if (output_type_ == OutputType::kCCDebug) {
f.SetReturnType(std::string("Value<") +
signature.return_type->GetDebugType() + ">");
} else if (output_type_ == OutputType::kCC) {
f.SetReturnType(signature.return_type->GetRuntimeType());
} else {
if (output_type_ == OutputType::kCCDebug) {
o << "Value<" << signature.return_type->GetDebugType() << ">";
} else {
o << (output_type_ == OutputType::kCC
? signature.return_type->GetRuntimeType()
: signature.return_type->GetGeneratedTypeName());
}
DCHECK_EQ(output_type_, OutputType::kCSA);
f.SetReturnType(signature.return_type->GetGeneratedTypeName());
}
o << " " << macro_prefix << name << "(";
bool first = true;
bool ignore_first_parameter = true;
if (output_type_ == OutputType::kCCDebug) {
first = false;
o << "d::MemoryAccessor accessor";
f.AddParameter("d::MemoryAccessor", "accessor");
} else if (output_type_ == OutputType::kCSA && pass_code_assembler_state) {
first = false;
o << "compiler::CodeAssemblerState* state_";
f.AddParameter("compiler::CodeAssemblerState*", "state_");
} else {
ignore_first_parameter = false;
}
// TODO(torque-builder): Consider an overload for AddParameter that handles
// this.
DCHECK_GE(signature.types().size(), parameter_names.size());
for (size_t i = 0; i < signature.types().size(); ++i) {
if (!first) o << ", ";
first = false;
for (std::size_t i = 0; i < signature.types().size(); ++i) {
const Type* parameter_type = signature.types()[i];
const std::string& generated_type_name =
output_type_ == OutputType::kCC
? parameter_type->GetRuntimeType()
: output_type_ == OutputType::kCCDebug
? parameter_type->GetDebugType()
: parameter_type->GetGeneratedTypeName();
generated_parameter_names.push_back(ExternalParameterName(
i < parameter_names.size() ? parameter_names[i]->value
: std::to_string(i)));
o << generated_type_name << " " << generated_parameter_names.back();
std::string type;
if (output_type_ == OutputType::kCC) {
type = parameter_type->GetRuntimeType();
} else if (output_type_ == OutputType::kCCDebug) {
type = parameter_type->GetDebugType();
} else {
DCHECK_EQ(output_type_, OutputType::kCSA);
type = parameter_type->GetGeneratedTypeName();
}
f.AddParameter(std::move(type),
ExternalParameterName(i < parameter_names.size()
? parameter_names[i]->value
: std::to_string(i)));
}
for (const LabelDeclaration& label_info : signature.labels) {
......@@ -1845,11 +1835,8 @@ std::vector<std::string> ImplementationVisitor::GenerateFunctionDeclaration(
output_type_ == OutputType::kCCDebug) {
ReportError("Macros that generate runtime code can't have label exits");
}
if (!first) o << ", ";
first = false;
generated_parameter_names.push_back(
ExternalLabelName(label_info.name->value));
o << "compiler::CodeAssemblerLabel* " << generated_parameter_names.back();
f.AddParameter("compiler::CodeAssemblerLabel*",
ExternalLabelName(label_info.name->value));
size_t i = 0;
for (const Type* type : label_info.types) {
std::string generated_type_name;
......@@ -1860,16 +1847,20 @@ std::vector<std::string> ImplementationVisitor::GenerateFunctionDeclaration(
generated_type_name += type->GetGeneratedTNodeTypeName();
generated_type_name += ">*";
}
o << ", ";
generated_parameter_names.push_back(
ExternalLabelParameterName(label_info.name->value, i));
o << generated_type_name << " " << generated_parameter_names.back();
f.AddParameter(generated_type_name,
ExternalLabelParameterName(label_info.name->value, i));
++i;
}
}
o << ")";
return generated_parameter_names;
if (generated_parameter_names) {
*generated_parameter_names = f.GetParameterNames();
if (ignore_first_parameter) {
DCHECK(!generated_parameter_names->empty());
generated_parameter_names->erase(generated_parameter_names->begin());
}
}
return f;
}
namespace {
......@@ -2801,6 +2792,7 @@ VisitResult ImplementationVisitor::GenerateCall(
}
}
// TODO(torque-builder): Consider a function builder here.
if (return_type->IsConstexpr()) {
DCHECK_EQ(0, arguments.labels.size());
std::stringstream result;
......@@ -3500,7 +3492,6 @@ void ImplementationVisitor::GenerateBuiltinDefinitionsAndInterfaceDescriptors(
interface_descriptors << " DECLARE_DEFAULT_DESCRIPTOR("
<< descriptor_name << ")\n";
interface_descriptors << "};\n\n";
} else {
builtin_definitions << "TFJ(" << builtin->ExternalName();
......@@ -3850,12 +3841,12 @@ namespace {
class ClassFieldOffsetGenerator : public FieldOffsetsGenerator {
public:
ClassFieldOffsetGenerator(std::ostream& header, std::ostream& inline_header,
const ClassType* type, std::string gen_name_T)
const ClassType* type, std::string gen_name)
: FieldOffsetsGenerator(type),
hdr_(header),
inl_(inline_header),
previous_field_end_("P::kHeaderSize"),
gen_name_T_(gen_name_T) {}
gen_name_(gen_name) {}
void WriteField(const Field& f, const std::string& size_string) override {
std::string field = "k" + CamelifyString(f.name_and_type.name) + "Offset";
std::string field_end = field + "End";
......@@ -3872,14 +3863,18 @@ class ClassFieldOffsetGenerator : public FieldOffsetsGenerator {
std::string function_name = CamelifyString(f.name_and_type.name) + "Offset";
hdr_ << " inline int " << function_name << "() const;\n";
inl_ << "template <class D, class P>\n";
inl_ << "int " << gen_name_T_ << "::" << function_name << "() const {\n";
// Item 1 in a flattened slice is the offset.
inl_ << " return static_cast<int>(std::get<1>("
<< Callable::PrefixNameForCCOutput(type_->GetSliceMacroName(f))
<< "(*static_cast<const D*>(this))));\n";
inl_ << "}\n\n";
std::vector<cpp::TemplateParameter> params = {cpp::TemplateParameter("D"),
cpp::TemplateParameter("P")};
cpp::Class owner(std::move(params), gen_name_);
auto getter = cpp::Function::DefaultGetter("int", &owner, function_name);
getter.PrintDeclaration(hdr_);
getter.PrintDefinition(inl_, [&](std::ostream& stream) {
// Item 1 in a flattened slice is the offset.
stream << " return static_cast<int>(std::get<1>("
<< Callable::PrefixNameForCCOutput(type_->GetSliceMacroName(f))
<< "(*static_cast<const D*>(this))));\n";
});
}
void WriteMarker(const std::string& marker) override {
hdr_ << " static constexpr int " << marker << " = " << previous_field_end_
......@@ -3890,7 +3885,7 @@ class ClassFieldOffsetGenerator : public FieldOffsetsGenerator {
std::ostream& hdr_;
std::ostream& inl_;
std::string previous_field_end_;
std::string gen_name_T_;
std::string gen_name_;
};
class CppClassGenerator {
......@@ -3921,9 +3916,9 @@ class CppClassGenerator {
// active struct fields.
void GenerateFieldAccessors(const Field& class_field,
std::vector<const Field*>& struct_fields);
void EmitLoadFieldStatement(const Field& class_field,
void EmitLoadFieldStatement(std::ostream& stream, const Field& class_field,
std::vector<const Field*>& struct_fields);
void EmitStoreFieldStatement(const Field& class_field,
void EmitStoreFieldStatement(std::ostream& stream, const Field& class_field,
std::vector<const Field*>& struct_fields);
void GenerateClassCasts();
......@@ -3971,16 +3966,20 @@ base::Optional<std::vector<Field>> GetOrderedUniqueIndexFields(
}
void CppClassGenerator::GenerateClass() {
hdr_ << "\n";
hdr_ << "// Alias for HeapObject::Is" << name_
<< "() that avoids inlining.\n";
hdr_ << "V8_EXPORT_PRIVATE bool Is" << name_ << "_NonInline(HeapObject o);\n";
hdr_ << "\n";
// Is<name>_NonInline(HeapObject)
{
cpp::Function f("Is"s + name_ + "_NonInline");
f.SetDescription("Alias for HeapObject::Is"s + name_ +
"() that avoids inlining.");
f.SetExport(true);
f.SetReturnType("bool");
f.AddParameter("HeapObject", "o");
impl_ << "\n";
impl_ << "bool Is" << name_ << "_NonInline(HeapObject o) {\n";
impl_ << " return o.Is" << name_ << "();\n";
impl_ << "}\n\n";
f.PrintDeclaration(hdr_);
f.PrintDefinition(impl_, [&](std::ostream& stream) {
stream << " return o.Is" << name_ << "();";
});
}
hdr_ << template_decl() << "\n";
hdr_ << "class " << gen_name_ << " : public P {\n";
......@@ -4005,14 +4004,22 @@ void CppClassGenerator::GenerateClass() {
GenerateClassCasts();
std::vector<cpp::TemplateParameter> templateArgs = {
cpp::TemplateParameter("D"), cpp::TemplateParameter("P")};
cpp::Class c(std::move(templateArgs), gen_name_);
if (type_->ShouldGeneratePrint()) {
hdr_ << "\n DECL_PRINTER(" << name_ << ")\n";
}
if (type_->ShouldGenerateVerify()) {
IfDefScope hdr_scope(hdr_, "VERIFY_HEAP");
hdr_ << " V8_EXPORT_PRIVATE void " << name_
<< "Verify(Isolate* isolate);\n";
// V8_EXPORT_PRIVATE void Verify(Isolate*);
cpp::Function f(&c, name_ + "Verify");
f.SetExport();
f.SetReturnType("void");
f.AddParameter("Isolate*", "isolate");
f.PrintDeclaration(hdr_);
IfDefScope impl_scope(impl_, "VERIFY_HEAP");
impl_ << "\ntemplate <>\n";
......@@ -4025,7 +4032,7 @@ void CppClassGenerator::GenerateClass() {
}
hdr_ << "\n";
ClassFieldOffsetGenerator g(hdr_, inl_, type_, gen_name_T_);
ClassFieldOffsetGenerator g(hdr_, inl_, type_, gen_name_);
for (auto f : type_->fields()) {
CurrentSourcePosition::Scope scope(f.pos);
g.RecordOffsetFor(f);
......@@ -4042,58 +4049,69 @@ void CppClassGenerator::GenerateClass() {
const Field& last_field = type_->LastField();
std::string last_field_item_size =
std::get<1>(*SizeOf(last_field.name_and_type.type));
hdr_ << " inline int AllocatedSize() const;\n\n";
inl_ << "template <class D, class P>\n";
inl_ << "int " << gen_name_T_ << "::AllocatedSize() const {\n";
inl_ << " auto slice = "
<< Callable::PrefixNameForCCOutput(
type_->GetSliceMacroName(last_field))
<< "(*static_cast<const D*>(this));\n";
inl_ << " return static_cast<int>(std::get<1>(slice)) + "
<< last_field_item_size
<< " * static_cast<int>(std::get<2>(slice));\n";
inl_ << "}\n\n";
// int AllocatedSize() const
{
cpp::Function f =
cpp::Function::DefaultGetter("int", &c, "AllocatedSize");
f.PrintDeclaration(hdr_, 2);
f.PrintDefinition(inl_, [&](std::ostream& stream) {
stream << " auto slice = "
<< Callable::PrefixNameForCCOutput(
type_->GetSliceMacroName(last_field))
<< "(*static_cast<const D*>(this));\n";
stream << " return static_cast<int>(std::get<1>(slice)) + "
<< last_field_item_size
<< " * static_cast<int>(std::get<2>(slice));\n";
});
}
} else if (type_->ShouldGenerateBodyDescriptor() ||
(!type_->IsAbstract() &&
!type_->IsSubtypeOf(TypeOracle::GetJSObjectType()))) {
hdr_ << " V8_INLINE static constexpr int32_t SizeFor(";
bool first = true;
cpp::Function f(&c, "SizeFor");
f.SetReturnType("int32_t");
f.SetFlags(cpp::Function::kStatic | cpp::Function::kConstexpr |
cpp::Function::kV8Inline);
for (const Field& field : *index_fields) {
if (!first) hdr_ << ", ";
hdr_ << "int " << field.name_and_type.name;
first = false;
}
hdr_ << ") {\n";
if (index_fields->empty()) {
hdr_ << " DCHECK(kHeaderSize == kSize && kHeaderSize == "
<< *type_->size().SingleValue() << ");\n";
}
hdr_ << " int32_t size = kHeaderSize;\n";
for (const Field& field : type_->ComputeAllFields()) {
if (field.index) {
auto index_name_and_type =
*ExtractSimpleFieldArraySize(*type_, field.index->expr);
size_t field_size = 0;
std::tie(field_size, std::ignore) = field.GetFieldSizeInformation();
hdr_ << " size += " << index_name_and_type.name << " * "
<< field_size << ";\n";
}
}
if (type_->size().Alignment() < TargetArchitecture::TaggedSize()) {
hdr_ << " size = OBJECT_POINTER_ALIGN(size);\n";
f.AddParameter("int", field.name_and_type.name);
}
hdr_ << " return size;\n";
hdr_ << " }\n\n";
hdr_ << " V8_INLINE int32_t AllocatedSize() const {\n";
hdr_ << " return SizeFor(";
first = true;
for (auto field : *index_fields) {
if (!first) hdr_ << ", ";
hdr_ << "this->" << field.name_and_type.name << "()";
first = false;
f.PrintInlineDefinition(hdr_, [&](std::ostream& stream) {
if (index_fields->empty()) {
stream << " DCHECK(kHeaderSize == kSize && kHeaderSize == "
<< *type_->size().SingleValue() << ");\n";
}
stream << " int32_t size = kHeaderSize;\n";
for (const Field& field : type_->ComputeAllFields()) {
if (field.index) {
auto index_name_and_type =
*ExtractSimpleFieldArraySize(*type_, field.index->expr);
stream << " size += " << index_name_and_type.name << " * "
<< std::get<0>(field.GetFieldSizeInformation()) << ";\n";
}
}
if (type_->size().Alignment() < TargetArchitecture::TaggedSize()) {
stream << " size = OBJECT_POINTER_ALIGN(size);\n";
}
stream << " return size;\n";
});
// V8_INLINE int32_t AllocatedSize() const
{
cpp::Function f =
cpp::Function::DefaultGetter("int32_t", &c, "AllocatedSize");
f.SetFlag(cpp::Function::kV8Inline);
f.PrintInlineDefinition(hdr_, [&](std::ostream& stream) {
stream << " return SizeFor(";
bool first = true;
for (auto field : *index_fields) {
if (!first) stream << ", ";
stream << "this->" << field.name_and_type.name << "()";
first = false;
}
stream << ");\n";
});
}
hdr_ << ");\n }\n";
hdr_ << "\n";
}
hdr_ << " friend class Factory;\n\n";
......@@ -4108,13 +4126,20 @@ void CppClassGenerator::GenerateClass() {
}
void CppClassGenerator::GenerateClassCasts() {
hdr_ << " V8_INLINE static D cast(Object object) {\n";
hdr_ << " return D(object.ptr());\n";
hdr_ << " }\n";
hdr_ << " V8_INLINE static D unchecked_cast(Object object) {\n";
hdr_ << " return bit_cast<D>(object);\n";
hdr_ << " }\n";
cpp::Function f("cast");
f.SetFlags(cpp::Function::kV8Inline | cpp::Function::kStatic);
f.SetReturnType("D");
f.AddParameter("Object", "object");
// V8_INLINE static D cast(Object)
f.PrintInlineDefinition(hdr_, [](std::ostream& stream) {
stream << " return D(object.ptr());\n";
});
// V8_INLINE static D unchecked_cast(Object)
f.SetName("unchecked_cast");
f.PrintInlineDefinition(hdr_, [](std::ostream& stream) {
stream << " return bit_cast<D>(object);\n";
});
}
void CppClassGenerator::GenerateClassConstructors() {
......@@ -4250,134 +4275,82 @@ void CppClassGenerator::GenerateFieldAccessors(
hdr_ << " // Torque type: " << field_type->ToString() << "\n";
}
hdr_ << " inline " << type_name << " " << name << "("
<< (indexed ? "int i" : "");
switch (class_field.read_synchronization) {
case FieldSynchronization::kNone:
break;
case FieldSynchronization::kRelaxed:
hdr_ << (indexed ? ", RelaxedLoadTag" : "RelaxedLoadTag");
break;
case FieldSynchronization::kAcquireRelease:
hdr_ << (indexed ? ", AcquireLoadTag" : "AcquireLoadTag");
break;
}
hdr_ << ") const;\n";
if (can_contain_heap_objects) {
hdr_ << " inline " << type_name << " " << name
<< "(PtrComprCageBase cage_base" << (indexed ? ", int i" : "");
std::vector<cpp::TemplateParameter> templateParameters = {
cpp::TemplateParameter("D"), cpp::TemplateParameter("P")};
cpp::Class owner(std::move(templateParameters), gen_name_);
// getter
{
auto getter = cpp::Function::DefaultGetter(type_name, &owner, name);
if (indexed) {
getter.AddParameter("int", "i");
}
const char* tag_argument;
switch (class_field.read_synchronization) {
case FieldSynchronization::kNone:
tag_argument = "";
break;
case FieldSynchronization::kRelaxed:
hdr_ << ", RelaxedLoadTag";
getter.AddParameter("RelaxedLoadTag");
tag_argument = ", kRelaxedLoad";
break;
case FieldSynchronization::kAcquireRelease:
hdr_ << ", AcquireLoadTag";
getter.AddParameter("AcquireLoadTag");
tag_argument = ", kAcquireLoad";
break;
}
hdr_ << ") const;\n";
}
hdr_ << " inline void set_" << name << "(" << (indexed ? "int i, " : "")
<< type_name << " value";
switch (class_field.write_synchronization) {
case FieldSynchronization::kNone:
break;
case FieldSynchronization::kRelaxed:
hdr_ << ", RelaxedStoreTag";
break;
case FieldSynchronization::kAcquireRelease:
hdr_ << ", ReleaseStoreTag";
break;
getter.PrintDeclaration(hdr_);
// For tagged data, generate the extra getter that derives an
// PtrComprCageBase from the current object's pointer.
if (can_contain_heap_objects) {
getter.PrintDefinition(inl_, [&](auto& stream) {
stream
<< " PtrComprCageBase cage_base = GetPtrComprCageBase(*this);\n";
stream << " return " << gen_name_ << "::" << name << "(cage_base"
<< (indexed ? ", i" : "") << tag_argument << ");\n";
});
getter.InsertParameter(0, "PtrComprCageBase", "cage_base");
getter.PrintDeclaration(hdr_);
}
getter.PrintDefinition(inl_, [&](auto& stream) {
stream << " " << type_name << " value;\n";
EmitLoadFieldStatement(stream, class_field, struct_fields);
stream << " return value;\n";
});
}
hdr_ << (can_contain_heap_objects
? ", WriteBarrierMode mode = UPDATE_WRITE_BARRIER"
: "")
<< ");\n\n";
// For tagged data, generate the extra getter that derives an PtrComprCageBase
// from the current object's pointer.
if (can_contain_heap_objects) {
inl_ << "template <class D, class P>\n";
inl_ << type_name << " " << gen_name_ << "<D, P>::" << name << "("
<< (indexed ? "int i" : "");
switch (class_field.read_synchronization) {
case FieldSynchronization::kNone:
break;
case FieldSynchronization::kRelaxed:
inl_ << (indexed ? ", RelaxedLoadTag" : "RelaxedLoadTag");
break;
case FieldSynchronization::kAcquireRelease:
inl_ << (indexed ? ", AcquireLoadTag" : "AcquireLoadTag");
break;
// setter
{
auto setter = cpp::Function::DefaultSetter(
&owner, std::string("set_") + name, type_name, "value");
if (indexed) {
setter.InsertParameter(0, "int", "i");
}
inl_ << ") const {\n";
inl_ << " PtrComprCageBase cage_base = GetPtrComprCageBase(*this);\n";
inl_ << " return " << gen_name_ << "::" << name << "(cage_base"
<< (indexed ? ", i" : "");
switch (class_field.read_synchronization) {
switch (class_field.write_synchronization) {
case FieldSynchronization::kNone:
break;
case FieldSynchronization::kRelaxed:
inl_ << ", kRelaxedLoad";
setter.AddParameter("RelaxedStoreTag");
break;
case FieldSynchronization::kAcquireRelease:
inl_ << ", kAcquireLoad";
setter.AddParameter("ReleaseStoreTag");
break;
}
inl_ << ");\n";
inl_ << "}\n";
}
if (can_contain_heap_objects) {
setter.AddParameter("WriteBarrierMode", "mode", "UPDATE_WRITE_BARRIER");
}
setter.PrintDeclaration(hdr_);
// Generate the getter implementation.
inl_ << "template <class D, class P>\n";
inl_ << type_name << " " << gen_name_ << "<D, P>::" << name << "(";
if (can_contain_heap_objects) inl_ << "PtrComprCageBase cage_base";
if (can_contain_heap_objects && indexed) inl_ << ", ";
if (indexed) inl_ << "int i";
switch (class_field.read_synchronization) {
case FieldSynchronization::kNone:
break;
case FieldSynchronization::kRelaxed:
inl_ << ((can_contain_heap_objects || indexed) ? ", RelaxedLoadTag"
: "RelaxedLoadTag");
break;
case FieldSynchronization::kAcquireRelease:
inl_ << ((can_contain_heap_objects || indexed) ? ", AcquireLoadTag"
: "AcquireLoadTag");
break;
setter.PrintDefinition(inl_, [&](auto& stream) {
EmitStoreFieldStatement(stream, class_field, struct_fields);
});
}
inl_ << ") const {\n";
inl_ << " " << type_name << " value;\n";
EmitLoadFieldStatement(class_field, struct_fields);
inl_ << " return value;\n";
inl_ << "}\n";
// Generate the setter implementation.
inl_ << "template <class D, class P>\n";
inl_ << "void " << gen_name_ << "<D, P>::set_" << name << "(";
if (indexed) {
inl_ << "int i, ";
}
inl_ << type_name << " value";
switch (class_field.write_synchronization) {
case FieldSynchronization::kNone:
break;
case FieldSynchronization::kRelaxed:
inl_ << ", RelaxedStoreTag";
break;
case FieldSynchronization::kAcquireRelease:
inl_ << ", ReleaseStoreTag";
break;
}
if (can_contain_heap_objects) {
inl_ << ", WriteBarrierMode mode";
}
inl_ << ") {\n";
EmitStoreFieldStatement(class_field, struct_fields);
inl_ << "}\n\n";
hdr_ << "\n";
}
std::string CppClassGenerator::GetFieldOffsetForAccessor(const Field& f) {
......@@ -4415,7 +4388,8 @@ bool CppClassGenerator::CanContainHeapObjects(const Type* t) {
}
void CppClassGenerator::EmitLoadFieldStatement(
const Field& class_field, std::vector<const Field*>& struct_fields) {
std::ostream& stream, const Field& class_field,
std::vector<const Field*>& struct_fields) {
const Field& innermost_field =
struct_fields.empty() ? class_field : *struct_fields.back();
const Type* field_type = innermost_field.name_and_type.type;
......@@ -4434,13 +4408,13 @@ void CppClassGenerator::EmitLoadFieldStatement(
std::string offset = field_offset;
if (class_field.index) {
const char* index = class_field.index->optional ? "0" : "i";
GenerateBoundsDCheck(inl_, index, type_, class_field);
inl_ << " int offset = " << field_offset << " + " << index << " * "
<< class_field_size << ";\n";
GenerateBoundsDCheck(stream, index, type_, class_field);
stream << " int offset = " << field_offset << " + " << index << " * "
<< class_field_size << ";\n";
offset = "offset";
}
inl_ << " value = ";
stream << " value = ";
if (!field_type->IsSubtypeOf(TypeOracle::GetTaggedType())) {
if (class_field.read_synchronization ==
......@@ -4450,8 +4424,8 @@ void CppClassGenerator::EmitLoadFieldStatement(
FieldSynchronization::kRelaxed) {
ReportError("Torque doesn't support @cppRelaxedRead on untagged data");
}
inl_ << "this->template ReadField<" << type_name << ">(" << offset
<< ");\n";
stream << "this->template ReadField<" << type_name << ">(" << offset
<< ");\n";
} else {
const char* load;
switch (class_field.read_synchronization) {
......@@ -4470,19 +4444,20 @@ void CppClassGenerator::EmitLoadFieldStatement(
const char* postfix = is_smi ? ".value()" : "";
const char* optional_cage_base = is_smi ? "" : "cage_base, ";
inl_ << "TaggedField<" << load_type << ">::" << load << "("
<< optional_cage_base << "*this, " << offset << ")" << postfix
<< ";\n";
stream << "TaggedField<" << load_type << ">::" << load << "("
<< optional_cage_base << "*this, " << offset << ")" << postfix
<< ";\n";
}
if (CanContainHeapObjects(field_type)) {
inl_ << " DCHECK(" << GenerateRuntimeTypeCheck(field_type, "value")
<< ");\n";
stream << " DCHECK(" << GenerateRuntimeTypeCheck(field_type, "value")
<< ");\n";
}
}
void CppClassGenerator::EmitStoreFieldStatement(
const Field& class_field, std::vector<const Field*>& struct_fields) {
std::ostream& stream, const Field& class_field,
std::vector<const Field*>& struct_fields) {
const Field& innermost_field =
struct_fields.empty() ? class_field : *struct_fields.back();
const Type* field_type = innermost_field.name_and_type.type;
......@@ -4501,15 +4476,15 @@ void CppClassGenerator::EmitStoreFieldStatement(
std::string offset = field_offset;
if (class_field.index) {
const char* index = class_field.index->optional ? "0" : "i";
GenerateBoundsDCheck(inl_, index, type_, class_field);
inl_ << " int offset = " << field_offset << " + " << index << " * "
<< class_field_size << ";\n";
GenerateBoundsDCheck(stream, index, type_, class_field);
stream << " int offset = " << field_offset << " + " << index << " * "
<< class_field_size << ";\n";
offset = "offset";
}
if (!field_type->IsSubtypeOf(TypeOracle::GetTaggedType())) {
inl_ << " this->template WriteField<" << type_name << ">(" << offset
<< ", value);\n";
stream << " this->template WriteField<" << type_name << ">(" << offset
<< ", value);\n";
} else {
bool strong_pointer = field_type->IsSubtypeOf(TypeOracle::GetObjectType());
bool is_smi = field_type->IsSubtypeOf(TypeOracle::GetSmiType());
......@@ -4536,17 +4511,17 @@ void CppClassGenerator::EmitStoreFieldStatement(
const std::string value_to_write = is_smi ? "Smi::FromInt(value)" : "value";
if (!is_smi) {
inl_ << " SLOW_DCHECK(" << GenerateRuntimeTypeCheck(field_type, "value")
<< ");\n";
stream << " SLOW_DCHECK("
<< GenerateRuntimeTypeCheck(field_type, "value") << ");\n";
}
inl_ << " " << write_macro << "(*this, " << offset << ", "
<< value_to_write << ");\n";
stream << " " << write_macro << "(*this, " << offset << ", "
<< value_to_write << ");\n";
if (!is_smi) {
const char* write_barrier = strong_pointer
? "CONDITIONAL_WRITE_BARRIER"
: "CONDITIONAL_WEAK_WRITE_BARRIER";
inl_ << " " << write_barrier << "(*this, " << offset
<< ", value, mode);\n";
stream << " " << write_barrier << "(*this, " << offset
<< ", value, mode);\n";
}
}
}
......@@ -5266,23 +5241,20 @@ void ImplementationVisitor::GenerateExportedMacrosAssembler(
TorqueMacro* macro = TorqueMacro::DynamicCast(declarable.get());
if (!(macro && macro->IsExportedToCSA())) continue;
h_contents << " ";
GenerateFunctionDeclaration(h_contents, "", macro->ReadableName(),
macro->signature(), macro->parameter_names(),
false);
h_contents << ";\n";
std::vector<std::string> parameter_names = GenerateFunctionDeclaration(
cc_contents,
"TorqueGeneratedExportedMacrosAssembler::", macro->ReadableName(),
macro->signature(), macro->parameter_names(), false);
cc_contents << "{\n";
cc_contents << "return " << macro->ExternalName() << "(state_";
for (auto& name : parameter_names) {
cc_contents << ", " << name;
}
cc_contents << ");\n";
cc_contents << "}\n";
cpp::Class assembler("TorqueGeneratedExportedMacrosAssembler");
std::vector<std::string> generated_parameter_names;
cpp::Function f = GenerateFunction(
&assembler, macro->ReadableName(), macro->signature(),
macro->parameter_names(), false, &generated_parameter_names);
f.PrintDeclaration(h_contents);
f.PrintDefinition(cc_contents, [&](std::ostream& stream) {
stream << "return " << macro->ExternalName() << "(state_";
for (const auto& name : generated_parameter_names) {
stream << ", " << name;
}
stream << ");";
});
}
h_contents << " private:\n"
......
......@@ -11,6 +11,7 @@
#include "src/base/macros.h"
#include "src/torque/ast.h"
#include "src/torque/cfg.h"
#include "src/torque/cpp-builder.h"
#include "src/torque/declarations.h"
#include "src/torque/global-context.h"
#include "src/torque/type-oracle.h"
......@@ -742,12 +743,12 @@ class ImplementationVisitor {
void GenerateExpressionBranch(Expression* expression, Block* true_block,
Block* false_block);
void GenerateMacroFunctionDeclaration(std::ostream& o,
Macro* macro);
std::vector<std::string> GenerateFunctionDeclaration(
std::ostream& o, const std::string& macro_prefix, const std::string& name,
const Signature& signature, const NameVector& parameter_names,
bool pass_code_assembler_state = true);
cpp::Function GenerateMacroFunctionDeclaration(Macro* macro);
cpp::Function GenerateFunction(
cpp::Class* owner, const std::string& name, const Signature& signature,
const NameVector& parameter_names, bool pass_code_assembler_state = true,
std::vector<std::string>* generated_parameter_names = nullptr);
VisitResult GenerateImplicitConvert(const Type* destination_type,
VisitResult source);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment