[torque] Generate non-object field accessors from torque
Bug: v8:7793 Change-Id: Ic485dc953c80d055ff190b8be2a5434e5cdbeb5d Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1624214 Commit-Queue: Sigurd Schneider <sigurds@chromium.org> Reviewed-by: Tobias Tebbi <tebbi@chromium.org> Cr-Commit-Position: refs/heads/master@{#61828}
This commit is contained in:
parent
843b6646b1
commit
628431b214
@ -73,6 +73,7 @@ extern class Context extends HeapObject {
|
||||
}
|
||||
type NativeContext extends Context;
|
||||
|
||||
@generateCppClass
|
||||
extern class Oddball extends HeapObject {
|
||||
to_number_raw: float64;
|
||||
to_string: String;
|
||||
@ -169,6 +170,7 @@ type RootIndex generates 'TNode<Int32T>' constexpr 'RootIndex';
|
||||
|
||||
@abstract
|
||||
@noVerifier
|
||||
@generateCppClass
|
||||
extern class FixedArrayBase extends HeapObject {
|
||||
length: Smi;
|
||||
}
|
||||
|
@ -1107,7 +1107,7 @@ void JSGlobalObject::JSGlobalObjectVerify(Isolate* isolate) {
|
||||
}
|
||||
|
||||
void Oddball::OddballVerify(Isolate* isolate) {
|
||||
TorqueGeneratedClassVerifiers::OddballVerify(*this, isolate);
|
||||
TorqueGeneratedOddball::OddballVerify(isolate);
|
||||
Heap* heap = isolate->heap();
|
||||
Object number = to_number();
|
||||
if (number.IsHeapObject()) {
|
||||
|
@ -18,33 +18,19 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
OBJECT_CONSTRUCTORS_IMPL(Oddball, HeapObject)
|
||||
|
||||
CAST_ACCESSOR(Oddball)
|
||||
|
||||
double Oddball::to_number_raw() const {
|
||||
return ReadField<double>(kToNumberRawOffset);
|
||||
}
|
||||
|
||||
void Oddball::set_to_number_raw(double value) {
|
||||
WriteField<double>(kToNumberRawOffset, value);
|
||||
}
|
||||
TQ_OBJECT_CONSTRUCTORS_IMPL(Oddball)
|
||||
|
||||
void Oddball::set_to_number_raw_as_bits(uint64_t bits) {
|
||||
// Bug(v8:8875): HeapNumber's double may be unaligned.
|
||||
WriteUnalignedValue<uint64_t>(field_address(kToNumberRawOffset), bits);
|
||||
}
|
||||
|
||||
ACCESSORS(Oddball, to_string, String, kToStringOffset)
|
||||
ACCESSORS(Oddball, to_number, Object, kToNumberOffset)
|
||||
ACCESSORS(Oddball, type_of, String, kTypeOfOffset)
|
||||
|
||||
byte Oddball::kind() const {
|
||||
return Smi::ToInt(READ_FIELD(*this, kKindOffset));
|
||||
return Smi::ToInt(TorqueGeneratedOddball::kind());
|
||||
}
|
||||
|
||||
void Oddball::set_kind(byte value) {
|
||||
WRITE_FIELD(*this, kKindOffset, Smi::FromInt(value));
|
||||
TorqueGeneratedOddball::set_kind(Smi::FromInt(value));
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -6,7 +6,7 @@
|
||||
#define V8_OBJECTS_ODDBALL_H_
|
||||
|
||||
#include "src/objects/heap-object.h"
|
||||
#include "torque-generated/field-offsets-tq.h"
|
||||
#include "torque-generated/class-definitions-tq.h"
|
||||
|
||||
// Has to be the last include (doesn't have include guards):
|
||||
#include "src/objects/object-macros.h"
|
||||
@ -15,45 +15,26 @@ namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// The Oddball describes objects null, undefined, true, and false.
|
||||
class Oddball : public HeapObject {
|
||||
class Oddball : public TorqueGeneratedOddball<Oddball, HeapObject> {
|
||||
public:
|
||||
// [to_number_raw]: Cached raw to_number computed at startup.
|
||||
inline double to_number_raw() const;
|
||||
inline void set_to_number_raw(double value);
|
||||
inline void set_to_number_raw_as_bits(uint64_t bits);
|
||||
|
||||
// [to_string]: Cached to_string computed at startup.
|
||||
DECL_ACCESSORS(to_string, String)
|
||||
|
||||
// [to_number]: Cached to_number computed at startup.
|
||||
DECL_ACCESSORS(to_number, Object)
|
||||
|
||||
// [typeof]: Cached type_of computed at startup.
|
||||
DECL_ACCESSORS(type_of, String)
|
||||
|
||||
inline byte kind() const;
|
||||
inline void set_kind(byte kind);
|
||||
|
||||
// Oddball has a custom verifier.
|
||||
void OddballVerify(Isolate* isolate);
|
||||
|
||||
// ES6 section 7.1.3 ToNumber for Boolean, Null, Undefined.
|
||||
V8_WARN_UNUSED_RESULT static inline Handle<Object> ToNumber(
|
||||
Isolate* isolate, Handle<Oddball> input);
|
||||
|
||||
DECL_CAST(Oddball)
|
||||
|
||||
// Dispatched behavior.
|
||||
DECL_VERIFIER(Oddball)
|
||||
|
||||
// Initialize the fields.
|
||||
static void Initialize(Isolate* isolate, Handle<Oddball> oddball,
|
||||
const char* to_string, Handle<Object> to_number,
|
||||
const char* type_of, byte kind);
|
||||
|
||||
DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize,
|
||||
TORQUE_GENERATED_ODDBALL_FIELDS)
|
||||
// TODO(v8:8989): [torque] Support marker constants.
|
||||
static const int kTaggedFieldsStartOffset = kToStringOffset;
|
||||
static const int kTaggedFieldsEndOffset = kKindOffset;
|
||||
|
||||
static const byte kFalse = 0;
|
||||
static const byte kTrue = 1;
|
||||
static const byte kNotBooleanMask = static_cast<byte>(~1);
|
||||
@ -68,14 +49,16 @@ class Oddball : public HeapObject {
|
||||
static const byte kStaleRegister = 10;
|
||||
static const byte kSelfReferenceMarker = 10;
|
||||
|
||||
using BodyDescriptor = FixedBodyDescriptor<kTaggedFieldsStartOffset,
|
||||
kTaggedFieldsEndOffset, kSize>;
|
||||
static_assert(kStartOfWeakFieldsOffset == kEndOfWeakFieldsOffset,
|
||||
"Ensure BodyDescriptor does not need to handle weak fields.");
|
||||
using BodyDescriptor = FixedBodyDescriptor<kStartOfStrongFieldsOffset,
|
||||
kEndOfStrongFieldsOffset, kSize>;
|
||||
|
||||
STATIC_ASSERT(kKindOffset == Internals::kOddballKindOffset);
|
||||
STATIC_ASSERT(kNull == Internals::kNullOddballKind);
|
||||
STATIC_ASSERT(kUndefined == Internals::kUndefinedOddballKind);
|
||||
|
||||
OBJECT_CONSTRUCTORS(Oddball, HeapObject);
|
||||
TQ_OBJECT_CONSTRUCTORS(Oddball)
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
@ -3004,7 +3004,11 @@ class CppClassGenerator {
|
||||
|
||||
private:
|
||||
void GenerateClassConstructors();
|
||||
void GenerateClassFieldAccessor(const Field& f);
|
||||
void GenerateFieldAccessor(const Field& f);
|
||||
void GenerateFieldAccessorForUntagged(const Field& f);
|
||||
void GenerateFieldAccessorForSmi(const Field& f);
|
||||
void GenerateFieldAccessorForObject(const Field& f);
|
||||
|
||||
void GenerateClassCasts();
|
||||
|
||||
const ClassType* type_;
|
||||
@ -3031,7 +3035,7 @@ void CppClassGenerator::GenerateClass() {
|
||||
hdr_ << "public: \n";
|
||||
hdr_ << " using Super = P;\n";
|
||||
for (const Field& f : type_->fields()) {
|
||||
GenerateClassFieldAccessor(f);
|
||||
GenerateFieldAccessor(f);
|
||||
}
|
||||
|
||||
GenerateClassCasts();
|
||||
@ -3109,27 +3113,123 @@ void CppClassGenerator::GenerateClassConstructors() {
|
||||
}
|
||||
|
||||
// TODO(sigurds): Keep in sync with DECL_ACCESSORS and ACCESSORS macro.
|
||||
void CppClassGenerator::GenerateClassFieldAccessor(const Field& f) {
|
||||
void CppClassGenerator::GenerateFieldAccessor(const Field& f) {
|
||||
const Type* field_type = f.name_and_type.type;
|
||||
if (field_type == TypeOracle::GetVoidType()) return;
|
||||
if (!f.name_and_type.type->IsSubtypeOf(TypeOracle::GetTaggedType())) {
|
||||
return GenerateFieldAccessorForUntagged(f);
|
||||
}
|
||||
if (f.name_and_type.type->IsSubtypeOf(TypeOracle::GetSmiType())) {
|
||||
return GenerateFieldAccessorForSmi(f);
|
||||
}
|
||||
if (f.name_and_type.type->IsSubtypeOf(TypeOracle::GetObjectType())) {
|
||||
return GenerateFieldAccessorForObject(f);
|
||||
}
|
||||
|
||||
Error("Generation of field accessor for ", type_->name(),
|
||||
":: ", f.name_and_type.name, " : ", *field_type, " is not supported.")
|
||||
.Position(f.pos);
|
||||
}
|
||||
|
||||
void CppClassGenerator::GenerateFieldAccessorForUntagged(const Field& f) {
|
||||
DCHECK(!f.name_and_type.type->IsSubtypeOf(TypeOracle::GetTaggedType()));
|
||||
const Type* field_type = f.name_and_type.type;
|
||||
if (field_type == TypeOracle::GetVoidType()) return;
|
||||
const Type* constexpr_version = field_type->ConstexprVersion();
|
||||
if (!constexpr_version) {
|
||||
Error("Field accessor for ", type_->name(), ":: ", f.name_and_type.name,
|
||||
" cannot be generated because its type ", *field_type,
|
||||
" is neither a subclass of Object nor does the type have a constexpr "
|
||||
"version.")
|
||||
.Position(f.pos);
|
||||
return;
|
||||
}
|
||||
const std::string& name = f.name_and_type.name;
|
||||
const std::string& type = f.name_and_type.type->GetGeneratedTNodeTypeName();
|
||||
DCHECK(!f.name_and_type.type->IsSubtypeOf(TypeOracle::GetSmiType()));
|
||||
const std::string type = constexpr_version->GetGeneratedTypeName();
|
||||
const std::string offset = "k" + CamelifyString(name) + "Offset";
|
||||
|
||||
// Generate declarations in header.
|
||||
hdr_ << " inline " << type << " " << name << "() const;\n";
|
||||
hdr_ << " inline void set_" << name << "(" << type << " value,\n";
|
||||
hdr_ << " WriteBarrierMode mode = UPDATE_WRITE_BARRIER);\n\n";
|
||||
hdr_ << " inline void set_" << name << "(" << type << " value);\n\n";
|
||||
|
||||
const std::string offset =
|
||||
"k" + CamelifyString(f.name_and_type.name) + "Offset";
|
||||
// Generate implementation in inline header.
|
||||
inl_ << "template <class D, class P>\n";
|
||||
inl_ << " " << type << " " << gen_name_ << "<D, P>::" << name
|
||||
<< "() const {\n";
|
||||
inl_ << " " << type << " value = " << type << "::cast(READ_FIELD(*this, "
|
||||
<< offset << "));\n";
|
||||
inl_ << " return value;\n";
|
||||
inl_ << type << " " << gen_name_ << "<D, P>::" << name << "() const {\n";
|
||||
inl_ << " return this->template ReadField<" << type << ">(" << offset
|
||||
<< ");\n";
|
||||
inl_ << "}\n";
|
||||
|
||||
inl_ << "template <class D, class P>\n";
|
||||
inl_ << "void " << gen_name_ << "<D, P>::set_" << name << "(" << type
|
||||
<< " value) {\n";
|
||||
inl_ << " this->template WriteField<" << type << ">(" << offset
|
||||
<< ", value);\n";
|
||||
inl_ << "}\n\n";
|
||||
}
|
||||
|
||||
void CppClassGenerator::GenerateFieldAccessorForSmi(const Field& f) {
|
||||
DCHECK(f.name_and_type.type->IsSubtypeOf(TypeOracle::GetSmiType()));
|
||||
const std::string type = "Smi";
|
||||
const std::string& name = f.name_and_type.name;
|
||||
const std::string offset = "k" + CamelifyString(name) + "Offset";
|
||||
|
||||
// Generate declarations in header.
|
||||
hdr_ << " inline " << type << " " << name << "() const;\n";
|
||||
hdr_ << " inline void set_" << name << "(" << type << " value);\n\n";
|
||||
|
||||
// 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_ << "}\n";
|
||||
|
||||
inl_ << "template <class D, class P>\n";
|
||||
inl_ << "void " << gen_name_ << "<D, P>::set_" << name << "(" << type
|
||||
<< " value) {\n";
|
||||
inl_ << " DCHECK(value.IsSmi());\n";
|
||||
inl_ << " WRITE_FIELD(*this, " << offset << ", value);\n";
|
||||
inl_ << "}\n\n";
|
||||
}
|
||||
|
||||
void CppClassGenerator::GenerateFieldAccessorForObject(const Field& f) {
|
||||
const Type* field_type = f.name_and_type.type;
|
||||
DCHECK(field_type->IsSubtypeOf(TypeOracle::GetObjectType()));
|
||||
const std::string& name = f.name_and_type.name;
|
||||
const std::string offset = "k" + CamelifyString(name) + "Offset";
|
||||
const ClassType* class_type = ClassType::DynamicCast(field_type);
|
||||
|
||||
std::string type = class_type ? class_type->name() : "Object";
|
||||
|
||||
// Generate declarations in header.
|
||||
if (!class_type && field_type != TypeOracle::GetObjectType()) {
|
||||
hdr_ << " // Torque type: " << field_type->ToString() << "\n";
|
||||
}
|
||||
hdr_ << " inline " << type << " " << name << "() const;\n";
|
||||
hdr_ << " inline void set_" << name << "(" << type
|
||||
<< " value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER);\n\n";
|
||||
|
||||
std::string type_check;
|
||||
for (const std::string& runtime_type : field_type->GetRuntimeTypes()) {
|
||||
if (!type_check.empty()) type_check += " || ";
|
||||
type_check += "value.Is" + runtime_type + "()";
|
||||
}
|
||||
|
||||
// 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";
|
||||
if (class_type) {
|
||||
inl_ << " return " << type << "::cast(value);\n";
|
||||
} else {
|
||||
inl_ << " DCHECK(" << type_check << ");\n";
|
||||
inl_ << " return value;\n";
|
||||
}
|
||||
inl_ << "}\n";
|
||||
|
||||
inl_ << "template <class D, class P>\n";
|
||||
inl_ << "void " << gen_name_ << "<D, P>::set_" << name << "(" << type
|
||||
<< " value, WriteBarrierMode mode) {\n";
|
||||
inl_ << " SLOW_DCHECK(" << type_check << ");\n";
|
||||
inl_ << " WRITE_FIELD(*this, " << offset << ", value);\n";
|
||||
inl_ << " CONDITIONAL_WRITE_BARRIER(*this, " << offset
|
||||
<< ", value, mode);\n";
|
||||
@ -3150,6 +3250,7 @@ void ImplementationVisitor::GenerateClassDefinitions(
|
||||
IncludeGuardScope header_guard(header, basename + ".h");
|
||||
header << "#include \"src/objects/heap-number.h\"\n";
|
||||
header << "#include \"src/objects/objects.h\"\n";
|
||||
header << "#include \"src/objects/smi.h\"\n";
|
||||
header << "#include \"torque-generated/field-offsets-tq.h\"\n";
|
||||
header << "#include <type_traits>\n\n";
|
||||
IncludeObjectMacrosScope header_macros(header);
|
||||
@ -3158,6 +3259,7 @@ void ImplementationVisitor::GenerateClassDefinitions(
|
||||
|
||||
IncludeGuardScope inline_header_guard(inline_header, basename + "-inl.h");
|
||||
inline_header << "#include \"torque-generated/class-definitions-tq.h\"\n\n";
|
||||
inline_header << "#include \"src/objects/objects-inl.h\"\n\n";
|
||||
IncludeObjectMacrosScope inline_header_macros(inline_header);
|
||||
NamespaceScope inline_header_namespaces(inline_header, {"v8", "internal"});
|
||||
|
||||
|
@ -19,11 +19,14 @@ class TypeOracle : public ContextualClass<TypeOracle> {
|
||||
public:
|
||||
static const AbstractType* GetAbstractType(
|
||||
const Type* parent, std::string name, bool transient,
|
||||
std::string generated, const Type* non_constexpr_version) {
|
||||
std::string generated, const AbstractType* non_constexpr_version) {
|
||||
AbstractType* result =
|
||||
new AbstractType(parent, transient, std::move(name),
|
||||
std::move(generated), non_constexpr_version);
|
||||
Get().nominal_types_.push_back(std::unique_ptr<AbstractType>(result));
|
||||
if (non_constexpr_version) {
|
||||
non_constexpr_version->SetConstexprVersion(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -67,10 +67,12 @@ const AbstractType* TypeVisitor::ComputeType(AbstractTypeDeclaration* decl) {
|
||||
ReportError("cannot declare a transient type that is also constexpr");
|
||||
}
|
||||
|
||||
const Type* non_constexpr_version = nullptr;
|
||||
const AbstractType* non_constexpr_version = nullptr;
|
||||
if (decl->is_constexpr) {
|
||||
non_constexpr_version = Declarations::LookupType(
|
||||
QualifiedName{GetNonConstexprName(decl->name->value)});
|
||||
QualifiedName non_constexpr_name{GetNonConstexprName(decl->name->value)};
|
||||
const Type* non_constexpr_type =
|
||||
Declarations::LookupType(non_constexpr_name);
|
||||
non_constexpr_version = AbstractType::DynamicCast(non_constexpr_type);
|
||||
DCHECK_NOT_NULL(non_constexpr_version);
|
||||
}
|
||||
|
||||
|
@ -341,7 +341,7 @@ void ClassType::Finalize() const {
|
||||
if (const ClassType* super_class = ClassType::DynamicCast(parent())) {
|
||||
if (super_class->HasIndexedField()) flags_ |= ClassFlag::kHasIndexedField;
|
||||
if (!super_class->IsAbstract() && !HasSameInstanceTypeAsParent()) {
|
||||
Lint(
|
||||
Error(
|
||||
"Super class must either be abstract (annotate super class with "
|
||||
"@abstract) "
|
||||
"or this class must have the same instance type as the super class "
|
||||
@ -355,13 +355,10 @@ void ClassType::Finalize() const {
|
||||
is_finalized_ = true;
|
||||
if (GenerateCppClassDefinitions()) {
|
||||
for (const Field& f : fields()) {
|
||||
const Type* field_type = f.name_and_type.type;
|
||||
if (!field_type->IsSubtypeOf(TypeOracle::GetObjectType()) ||
|
||||
field_type->IsSubtypeOf(TypeOracle::GetSmiType()) ||
|
||||
field_type->IsSubtypeOf(TypeOracle::GetNumberType())) {
|
||||
Lint("Generation of C++ class for Torque class ", name(),
|
||||
" is not supported yet, because the type of field ",
|
||||
f.name_and_type.name, " cannot be handled yet")
|
||||
if (f.is_weak) {
|
||||
Error("Generation of C++ class for Torque class ", name(),
|
||||
" is not supported yet, because field ", f.name_and_type.name,
|
||||
": ", *f.name_and_type.type, " is a weak field.")
|
||||
.Position(f.pos);
|
||||
}
|
||||
}
|
||||
|
@ -102,6 +102,7 @@ class V8_EXPORT_PRIVATE Type : public TypeBase {
|
||||
}
|
||||
virtual bool IsTransient() const { return false; }
|
||||
virtual const Type* NonConstexprVersion() const { return this; }
|
||||
virtual const Type* ConstexprVersion() const { return nullptr; }
|
||||
base::Optional<const ClassType*> ClassSupertype() const;
|
||||
virtual std::vector<std::string> GetRuntimeTypes() const { return {}; }
|
||||
static const Type* CommonSupertype(const Type* a, const Type* b);
|
||||
@ -210,8 +211,16 @@ class AbstractType final : public Type {
|
||||
|
||||
const Type* NonConstexprVersion() const override {
|
||||
if (non_constexpr_version_) return non_constexpr_version_;
|
||||
return this;
|
||||
if (!IsConstexpr()) return this;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const AbstractType* ConstexprVersion() const override {
|
||||
if (constexpr_version_) return constexpr_version_;
|
||||
if (IsConstexpr()) return this;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<std::string> GetRuntimeTypes() const override { return {name()}; }
|
||||
|
||||
private:
|
||||
@ -230,12 +239,18 @@ class AbstractType final : public Type {
|
||||
!non_constexpr_version->IsConstexpr());
|
||||
}
|
||||
|
||||
void SetConstexprVersion(const AbstractType* type) const {
|
||||
DCHECK_EQ(GetConstexprName(name()), type->name());
|
||||
constexpr_version_ = type;
|
||||
}
|
||||
|
||||
bool IsTransient() const override { return transient_; }
|
||||
|
||||
bool transient_;
|
||||
const std::string name_;
|
||||
const std::string generated_type_;
|
||||
const Type* non_constexpr_version_;
|
||||
mutable const AbstractType* constexpr_version_ = nullptr;
|
||||
};
|
||||
|
||||
// For now, builtin pointers are restricted to Torque-defined builtins.
|
||||
|
Loading…
Reference in New Issue
Block a user