Commit 4c9bc648 authored by Daniel Clifford's avatar Daniel Clifford Committed by Commit Bot

Reland "[torque] Implement safe initialization of classes through hidden structs"

This is a reland of d11a0648

Original change's description:
> [torque] Implement safe initialization of classes through hidden structs
> 
> Initialization of classes now happens atomically at the end of the
> class constructor only once all of the values for the class' fields
> have been fully computed. This makes Torque constructors completely
> GC safe, e.g. hardened against allocations or exceptions in
> constructors.
> 
> As part of this change, make the 'this' parameter for method calls
> explicit rather than implicit.
> 
> Drive by: add validation to check for duplicate field declarations
> 
> Bug: v8:7793
> Change-Id: I8b5e85980d6a103ef9fc3262b76f6514f36ebf88
> Reviewed-on: https://chromium-review.googlesource.com/c/1411252
> Commit-Queue: Daniel Clifford <danno@chromium.org>
> Reviewed-by: Tobias Tebbi <tebbi@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#58979}

Bug: v8:7793
Change-Id: Ia8c23a36a661a73b5dc34437efd514a7c13a1ae8
Reviewed-on: https://chromium-review.googlesource.com/c/1426840Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Commit-Queue: Daniel Clifford <danno@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59005}
parent 4306e211
......@@ -688,6 +688,10 @@ struct NameAndTypeExpression {
TypeExpression* type;
};
struct StructFieldExpression {
NameAndTypeExpression name_and_type;
};
struct ClassFieldExpression {
NameAndTypeExpression name_and_type;
bool weak;
......@@ -883,33 +887,32 @@ struct StructDeclaration : Declaration {
DEFINE_AST_NODE_LEAF_BOILERPLATE(StructDeclaration)
StructDeclaration(SourcePosition pos, std::string name,
std::vector<Declaration*> methods,
std::vector<NameAndTypeExpression> fields)
std::vector<StructFieldExpression> fields)
: Declaration(kKind, pos),
name(std::move(name)),
methods(std::move(methods)),
fields(std::move(fields)) {}
std::string name;
std::vector<Declaration*> methods;
std::vector<NameAndTypeExpression> fields;
std::vector<StructFieldExpression> fields;
};
struct ClassDeclaration : Declaration {
DEFINE_AST_NODE_LEAF_BOILERPLATE(ClassDeclaration)
ClassDeclaration(SourcePosition pos, std::string name, bool transient,
base::Optional<std::string> extends,
base::Optional<std::string> generates,
std::string super, base::Optional<std::string> generates,
std::vector<Declaration*> methods,
std::vector<ClassFieldExpression> fields)
: Declaration(kKind, pos),
name(std::move(name)),
transient(transient),
extends(std::move(extends)),
super(std::move(super)),
generates(std::move(generates)),
methods(std::move(methods)),
fields(std::move(fields)) {}
std::string name;
bool transient;
base::Optional<std::string> extends;
std::string super;
base::Optional<std::string> generates;
std::vector<Declaration*> methods;
std::vector<ClassFieldExpression> fields;
......
......@@ -326,7 +326,9 @@ class Method : public Macro {
DECLARE_DECLARABLE_BOILERPLATE(Method, Method);
bool ShouldBeInlined() const override {
return Macro::ShouldBeInlined() ||
signature().parameter_types.types[0]->IsStructType();
signature()
.parameter_types.types[signature().implicit_count]
->IsStructType();
}
AggregateType* aggregate_type() const { return aggregate_type_; }
......
......@@ -163,13 +163,6 @@ void DeclarationVisitor::Visit(GenericDeclaration* decl) {
Declarations::DeclareGeneric(decl->callable->name, decl);
}
static Statement* WrapBodyWithNoThrow(Statement* body, std::string reason) {
return MakeNode<ExpressionStatement>(MakeNode<TryLabelExpression>(
true, MakeNode<StatementExpression>(body),
MakeNode<LabelBlock>("_catch", ParameterList{},
MakeNode<DebugStatement>(reason, true))));
}
void DeclarationVisitor::Visit(SpecializationDeclaration* decl) {
if ((decl->body != nullptr) == decl->external) {
std::stringstream stream;
......@@ -241,21 +234,27 @@ void DeclarationVisitor::DeclareMethods(
// Declare the class' methods
IdentifierExpression* constructor_this = MakeNode<IdentifierExpression>(
std::vector<std::string>{}, kThisParameterName);
AggregateType* constructor_this_type =
container_type->IsStructType()
? container_type
: ClassType::cast(container_type)->struct_type();
for (auto declaration : methods) {
CurrentSourcePosition::Scope pos_scope(declaration->pos);
StandardDeclaration* standard_declaration =
StandardDeclaration::DynamicCast(declaration);
DCHECK(standard_declaration);
TorqueMacroDeclaration* method =
TorqueMacroDeclaration::DynamicCast(standard_declaration->callable);
Signature signature = MakeSignature(method->signature.get());
signature.parameter_names.insert(signature.parameter_names.begin(),
kThisParameterName);
signature.parameter_types.types.insert(
signature.parameter_types.types.begin(), container_type);
signature.implicit_count++;
signature.parameter_names.insert(
signature.parameter_names.begin() + signature.implicit_count,
kThisParameterName);
Statement* body = *(standard_declaration->body);
std::string method_name(method->name);
if (method->name == kConstructMethodName) {
signature.parameter_types.types.insert(
signature.parameter_types.types.begin() + signature.implicit_count,
constructor_this_type);
// Constructor
if (!signature.return_type->IsVoid()) {
ReportError("constructors musn't have a return type");
......@@ -264,15 +263,15 @@ void DeclarationVisitor::DeclareMethods(
ReportError("constructors musn't have labels");
}
method_name = kConstructMethodName;
signature.return_type = container_type;
ReturnStatement* return_statement = MakeNode<ReturnStatement>(
MakeNode<IdentifierExpression>(kThisParameterName));
body = MakeNode<BlockStatement>(
false, std::vector<Statement*>{body, return_statement});
body = WrapBodyWithNoThrow(body, "exception thrown from constructor");
Declarations::CreateMethod(constructor_this_type, method_name, signature,
false, body);
} else {
signature.parameter_types.types.insert(
signature.parameter_types.types.begin() + signature.implicit_count,
container_type);
Declarations::CreateMethod(container_type, method_name, signature, false,
body);
}
Declarations::CreateMethod(container_type, method_name, signature, false,
body);
}
if (container_type->Constructors().size() != 0) return;
......@@ -280,7 +279,7 @@ void DeclarationVisitor::DeclareMethods(
// Generate default constructor.
Signature constructor_signature;
constructor_signature.parameter_types.var_args = false;
constructor_signature.return_type = container_type;
constructor_signature.return_type = TypeOracle::GetVoidType();
std::vector<const AggregateType*> hierarchy = container_type->GetHierarchy();
std::vector<Statement*> statements;
......@@ -288,8 +287,7 @@ void DeclarationVisitor::DeclareMethods(
size_t parameter_number = 0;
constructor_signature.parameter_names.push_back(kThisParameterName);
constructor_signature.parameter_types.types.push_back(container_type);
constructor_signature.implicit_count = 1;
constructor_signature.parameter_types.types.push_back(constructor_this_type);
std::vector<Expression*> super_arguments;
for (auto current_type : hierarchy) {
for (auto& f : current_type->fields()) {
......@@ -302,13 +300,7 @@ void DeclarationVisitor::DeclareMethods(
if (container_type != current_type) {
super_arguments.push_back(MakeNode<IdentifierExpression>(
std::vector<std::string>{}, parameter_name));
} else if (container_type->IsClassType()) {
Statement* statement =
MakeNode<ExpressionStatement>(MakeNode<StoreObjectFieldExpression>(
constructor_this, f.name_and_type.name, value));
initializer_statements.push_back(statement);
} else {
DCHECK(container_type->IsStructType());
LocationExpression* location = MakeNode<FieldAccessExpression>(
constructor_this, f.name_and_type.name);
Statement* statement = MakeNode<ExpressionStatement>(
......@@ -321,26 +313,20 @@ void DeclarationVisitor::DeclareMethods(
if (hierarchy.size() > 1) {
IdentifierExpression* super_identifier = MakeNode<IdentifierExpression>(
std::vector<std::string>{}, kSuperMethodName);
Statement* super_call_statement =
Statement* statement =
MakeNode<ExpressionStatement>(MakeNode<CallMethodExpression>(
constructor_this, super_identifier, super_arguments,
std::vector<std::string>{}));
statements.push_back(super_call_statement);
statements.push_back(statement);
}
for (auto s : initializer_statements) {
statements.push_back(s);
}
statements.push_back(MakeNode<ReturnStatement>(MakeNode<IdentifierExpression>(
std::vector<std::string>{}, kThisParameterName)));
Statement* constructor_body = MakeNode<BlockStatement>(false, statements);
constructor_body = WrapBodyWithNoThrow(constructor_body,
"exception thrown from constructor");
Declarations::CreateMethod(container_type, kConstructMethodName,
Declarations::CreateMethod(constructor_this_type, kConstructMethodName,
constructor_signature, false, constructor_body);
}
......@@ -348,8 +334,11 @@ void DeclarationVisitor::Visit(StructDeclaration* decl) {
std::vector<Field> fields;
size_t offset = 0;
for (auto& field : decl->fields) {
const Type* field_type = Declarations::GetType(field.type);
fields.push_back({{field.name, field_type}, offset, false});
const Type* field_type = Declarations::GetType(field.name_and_type.type);
fields.push_back({field.name_and_type.type->pos,
{field.name_and_type.name, field_type},
offset,
false});
offset += LoweredSlotCount(field_type);
}
StructType* struct_type = Declarations::DeclareStruct(decl->name, fields);
......@@ -360,17 +349,14 @@ void DeclarationVisitor::Visit(ClassDeclaration* decl) {
// Compute the offset of the class' first member. If the class extends
// another class, it's the size of the extended class, otherwise zero.
size_t first_field_offset = 0;
if (decl->extends) {
const Type* super_type = Declarations::LookupType(*decl->extends);
if (super_type != TypeOracle::GetTaggedType()) {
const ClassType* super_class = ClassType::DynamicCast(super_type);
if (!super_class) {
ReportError(
"class \"", decl->name,
"\" must extend either Tagged or an already declared class");
}
first_field_offset = super_class->size();
const Type* super_type = Declarations::LookupType(decl->super);
if (super_type != TypeOracle::GetTaggedType()) {
const ClassType* super_class = ClassType::DynamicCast(super_type);
if (!super_class) {
ReportError("class \"", decl->name,
"\" must extend either Tagged or an already declared class");
}
first_field_offset = super_class->size();
}
// The generates clause must create a TNode<>
......@@ -385,7 +371,7 @@ void DeclarationVisitor::Visit(ClassDeclaration* decl) {
}
std::vector<Field> fields;
size_t offset = first_field_offset;
size_t class_offset = first_field_offset;
bool seen_strong = false;
bool seen_weak = false;
for (ClassFieldExpression& field : decl->fields) {
......@@ -412,13 +398,15 @@ void DeclarationVisitor::Visit(ClassDeclaration* decl) {
"field \"", field.name_and_type.name, "\" of class \"", decl->name,
"\" must be a subtype of Tagged (other types not yet supported)");
}
fields.push_back(
{{field.name_and_type.name, field_type}, offset, field.weak});
offset += kTaggedSize;
fields.push_back({field.name_and_type.type->pos,
{field.name_and_type.name, field_type},
class_offset,
field.weak});
class_offset += kTaggedSize;
}
auto new_class = Declarations::DeclareClass(
decl->extends, decl->name, decl->transient, generates, fields, offset);
super_type, decl->name, decl->transient, generates, fields, class_offset);
DeclareMethods(new_class, decl->methods);
// For each field, construct AST snippits that implement a CSA accessor
......
......@@ -174,16 +174,43 @@ StructType* Declarations::DeclareStruct(const std::string& name,
return new_type;
}
ClassType* Declarations::DeclareClass(base::Optional<std::string> parent,
ClassType* Declarations::DeclareClass(const Type* super_type,
const std::string& name, bool transient,
const std::string& generates,
std::vector<Field> fields, size_t size) {
const Type* parent_type = nullptr;
if (parent) {
parent_type = LookupType(QualifiedName{*parent});
std::vector<Field> this_struct_fields;
size_t struct_offset = 0;
const StructType* super_struct_type = nullptr;
// In order to ensure "atomicity" of object allocation, a class'
// constructors operate on a per-class internal struct rather than the class
// directly until the constructor has successfully completed and all class
// members are available. Create the appropriate struct type for use in the
// class' constructors, including a '_super' field in the struct that
// contains the values constructed by calls to super constructors.
if (const ClassType* super_class = ClassType::DynamicCast(super_type)) {
super_struct_type = super_class->struct_type();
this_struct_fields.push_back(
{CurrentSourcePosition::Get(),
{kConstructorStructSuperFieldName, super_struct_type},
struct_offset,
false});
struct_offset += LoweredSlotCount(super_struct_type);
}
ClassType* new_type = TypeOracle::GetClassType(
parent_type, name, transient, generates, std::move(fields), size);
for (auto& field : fields) {
const Type* field_type = field.name_and_type.type;
this_struct_fields.push_back({field.pos,
{field.name_and_type.name, field_type},
struct_offset,
false});
struct_offset += LoweredSlotCount(field_type);
}
StructType* this_struct_type = DeclareStruct(
kClassConstructorThisStructPrefix + name, this_struct_fields);
ClassType* new_type =
TypeOracle::GetClassType(super_type, name, transient, generates,
std::move(fields), this_struct_type, size);
this_struct_type->SetDerivedFrom(new_type);
DeclareType(name, new_type, false);
return new_type;
}
......
......@@ -84,9 +84,8 @@ class Declarations {
static StructType* DeclareStruct(const std::string& name,
const std::vector<Field>& fields);
static ClassType* DeclareClass(base::Optional<std::string> parent,
const std::string& name, bool transient,
const std::string& generates,
static ClassType* DeclareClass(const Type* super, const std::string& name,
bool transient, const std::string& generates,
std::vector<Field> fields, size_t size);
static Macro* CreateMacro(std::string external_name,
......
This diff is collapsed.
......@@ -212,6 +212,8 @@ class ImplementationVisitor : public FileVisitor {
VisitResult Visit(Expression* expr);
const Type* Visit(Statement* stmt);
VisitResult TemporaryUninitializedStruct(const StructType* struct_type,
const std::string& reason);
VisitResult Visit(StructExpression* decl);
LocationReference GetLocationReference(Expression* location);
......@@ -290,7 +292,6 @@ class ImplementationVisitor : public FileVisitor {
struct ConstructorInfo {
int super_calls;
bool accessed_this;
};
DECLARE_CONTEXTUAL_VARIABLE(ValueBindingsManager,
......@@ -396,11 +397,29 @@ class ImplementationVisitor : public FileVisitor {
Binding<LocalLabel>* LookupLabel(const std::string& name);
Block* LookupSimpleLabel(const std::string& name);
template <class Container>
Callable* LookupCall(const QualifiedName& name,
const Container& declaration_container,
Callable* LookupCallable(const QualifiedName& name,
const Container& declaration_container,
const TypeVector& types,
const std::vector<Binding<LocalLabel>*>& labels,
const TypeVector& specialization_types);
template <class Container>
Callable* LookupCallable(const QualifiedName& name,
const Container& declaration_container,
const Arguments& arguments,
const TypeVector& specialization_types);
Method* LookupMethod(const std::string& name, LocationReference target,
const Arguments& arguments,
const TypeVector& specialization_types);
Method* LookupConstructor(LocationReference target,
const Arguments& arguments,
const TypeVector& specialization_types) {
return LookupMethod(kConstructMethodName, target, arguments,
specialization_types);
}
const Type* GetCommonType(const Type* left, const Type* right);
VisitResult GenerateCopy(const VisitResult& to_copy);
......
......@@ -42,8 +42,10 @@ enum class ParseResultHolderBase::TypeId {
kOptionalLabelBlockPtr,
kNameAndTypeExpression,
kClassFieldExpression,
kStructFieldExpression,
kStdVectorOfNameAndTypeExpression,
kStdVectorOfClassFieldExpression,
kStdVectorOfStructFieldExpression,
kIncrementDecrementOperator,
kOptionalStdString,
kStdVectorOfStatementPtr,
......@@ -107,6 +109,10 @@ V8_EXPORT_PRIVATE const ParseResultTypeId
ParseResultHolder<ClassFieldExpression>::id =
ParseResultTypeId::kClassFieldExpression;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
ParseResultHolder<StructFieldExpression>::id =
ParseResultTypeId::kStructFieldExpression;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
ParseResultHolder<std::vector<NameAndTypeExpression>>::id =
ParseResultTypeId::kStdVectorOfNameAndTypeExpression;
......@@ -115,6 +121,10 @@ V8_EXPORT_PRIVATE const ParseResultTypeId
ParseResultHolder<std::vector<ClassFieldExpression>>::id =
ParseResultTypeId::kStdVectorOfClassFieldExpression;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
ParseResultHolder<std::vector<StructFieldExpression>>::id =
ParseResultTypeId::kStdVectorOfStructFieldExpression;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
ParseResultHolder<IncrementDecrementOperator>::id =
ParseResultTypeId::kIncrementDecrementOperator;
......@@ -581,7 +591,7 @@ base::Optional<ParseResult> MakeClassDeclaration(
if (!IsValidTypeName(name)) {
NamingConventionError("Type", name, "UpperCamelCase");
}
auto extends = child_results->NextAs<base::Optional<std::string>>();
auto extends = child_results->NextAs<std::string>();
auto generates = child_results->NextAs<base::Optional<std::string>>();
auto methods = child_results->NextAs<std::vector<Declaration*>>();
auto fields = child_results->NextAs<std::vector<ClassFieldExpression>>();
......@@ -623,7 +633,7 @@ base::Optional<ParseResult> MakeStructDeclaration(
ParseResultIterator* child_results) {
auto name = child_results->NextAs<std::string>();
auto methods = child_results->NextAs<std::vector<Declaration*>>();
auto fields = child_results->NextAs<std::vector<NameAndTypeExpression>>();
auto fields = child_results->NextAs<std::vector<StructFieldExpression>>();
Declaration* result = MakeNode<StructDeclaration>(
std::move(name), std::move(methods), std::move(fields));
return ParseResult{result};
......@@ -1119,6 +1129,13 @@ base::Optional<ParseResult> MakeClassField(ParseResultIterator* child_results) {
return ParseResult{ClassFieldExpression{{std::move(name), type}, weak}};
}
base::Optional<ParseResult> MakeStructField(
ParseResultIterator* child_results) {
auto name = child_results->NextAs<std::string>();
auto type = child_results->NextAs<TypeExpression*>();
return ParseResult{StructFieldExpression{{std::move(name), type}}};
}
base::Optional<ParseResult> ExtractAssignmentOperator(
ParseResultIterator* child_results) {
auto op = child_results->NextAs<std::string>();
......@@ -1309,6 +1326,9 @@ struct TorqueGrammar : Grammar {
Rule({CheckIf(Token("weak")), &identifier, Token(":"), &type, Token(";")},
MakeClassField)};
Symbol structField = {
Rule({&identifier, Token(":"), &type, Token(";")}, MakeStructField)};
// Result: ParameterList
Symbol parameterListNoVararg = {
Rule({optionalImplicitParameterList, Token("("),
......@@ -1589,7 +1609,7 @@ struct TorqueGrammar : Grammar {
&externalString, Token(";")},
MakeExternConstDeclaration),
Rule({CheckIf(Token("transient")), Token("class"), &identifier,
Optional<std::string>(Sequence({Token("extends"), &identifier})),
Sequence({Token("extends"), &identifier}),
Optional<std::string>(
Sequence({Token("generates"), &externalString})),
Token("{"), List<Declaration*>(&method),
......@@ -1597,8 +1617,7 @@ struct TorqueGrammar : Grammar {
MakeClassDeclaration),
Rule({Token("struct"), &identifier, Token("{"),
List<Declaration*>(&method),
List<NameAndTypeExpression>(Sequence({&nameAndType, Token(";")})),
Token("}")},
List<StructFieldExpression>(&structField), Token("}")},
MakeStructDeclaration),
Rule({CheckIf(Token("transient")), Token("type"), &identifier,
Optional<std::string>(Sequence({Token("extends"), &identifier})),
......
......@@ -38,9 +38,10 @@ class TypeOracle : public ContextualClass<TypeOracle> {
static ClassType* GetClassType(const Type* parent, const std::string& name,
bool transient, const std::string& generates,
const std::vector<Field>& fields,
size_t size) {
ClassType* result = new ClassType(parent, CurrentNamespace(), name,
transient, generates, fields, size);
StructType* this_struct, size_t size) {
ClassType* result =
new ClassType(parent, CurrentNamespace(), name, transient, generates,
fields, this_struct, size);
Get().struct_types_.push_back(std::unique_ptr<ClassType>(result));
return result;
}
......
......@@ -184,6 +184,35 @@ const Type* SubtractType(const Type* a, const Type* b) {
return TypeOracle::GetUnionType(result);
}
void AggregateType::CheckForDuplicateFields() {
// Check the aggregate hierarchy and currently defined class for duplicate
// field declarations.
auto hierarchy = GetHierarchy();
std::map<std::string, const AggregateType*> field_names;
for (const AggregateType* aggregate_type : hierarchy) {
for (const Field& field : aggregate_type->fields()) {
const std::string& field_name = field.name_and_type.name;
auto i = field_names.find(field_name);
if (i != field_names.end()) {
CurrentSourcePosition::Scope current_source_position(field.pos);
std::string aggregate_type_name =
aggregate_type->IsClassType() ? "class" : "struct";
if (i->second == this) {
ReportError(aggregate_type_name, " '", name(),
"' declares a field with the name '", field_name,
"' more than once");
} else {
ReportError(aggregate_type_name, " '", name(),
"' declares a field with the name '", field_name,
"' that masks an inherited field from class '",
i->second->name(), "'");
}
}
field_names[field_name] = aggregate_type;
}
}
}
std::vector<const AggregateType*> AggregateType::GetHierarchy() {
std::vector<const AggregateType*> hierarchy;
const AggregateType* current_container_type = this;
......@@ -217,7 +246,7 @@ std::string StructType::GetGeneratedTypeName() const {
std::vector<Method*> AggregateType::Methods(const std::string& name) const {
std::vector<Method*> result;
std::copy_if(methods_.begin(), methods_.end(), std::back_inserter(result),
[&](Macro* macro) { return macro->ReadableName() == name; });
[name](Macro* macro) { return macro->ReadableName() == name; });
return result;
}
......@@ -343,19 +372,54 @@ bool operator<(const Type& a, const Type& b) {
return a.MangledName() < b.MangledName();
}
VisitResult ProjectStructField(VisitResult structure,
VisitResult ProjectStructField(const StructType* original_struct,
VisitResult structure,
const std::string& fieldname) {
DCHECK(structure.IsOnStack());
BottomOffset begin = structure.stack_range().begin();
// Check constructor this super classes for fields.
const StructType* type = StructType::cast(structure.type());
for (auto& field : type->fields()) {
auto& fields = type->fields();
for (auto& field : fields) {
BottomOffset end = begin + LoweredSlotCount(field.name_and_type.type);
if (field.name_and_type.name == fieldname) {
return VisitResult(field.name_and_type.type, StackRange{begin, end});
}
begin = end;
}
UNREACHABLE();
if (fields.size() > 0 &&
fields[0].name_and_type.name == kConstructorStructSuperFieldName) {
structure = ProjectStructField(original_struct, structure,
kConstructorStructSuperFieldName);
return ProjectStructField(original_struct, structure, fieldname);
} else {
base::Optional<const ClassType*> class_type =
original_struct->GetDerivedFrom();
if (original_struct == type) {
if (class_type) {
ReportError("class '", (*class_type)->name(),
"' doesn't contain a field '", fieldname, "'");
} else {
ReportError("struct '", original_struct->name(),
"' doesn't contain a field '", fieldname, "'");
}
} else {
DCHECK(class_type);
ReportError(
"class '", (*class_type)->name(),
"' or one of its derived-from classes doesn't contain a field '",
fieldname, "'");
}
}
}
VisitResult ProjectStructField(VisitResult structure,
const std::string& fieldname) {
DCHECK(structure.IsOnStack());
DCHECK(structure.type()->IsStructType());
const StructType* type = StructType::cast(structure.type());
return ProjectStructField(type, structure, fieldname);
}
namespace {
......
......@@ -12,6 +12,7 @@
#include <vector>
#include "src/base/optional.h"
#include "src/torque/source-positions.h"
#include "src/torque/utils.h"
namespace v8 {
......@@ -43,6 +44,7 @@ static const char* const CONST_FLOAT64_TYPE_STRING = "constexpr float64";
class Macro;
class Method;
class StructType;
class ClassType;
class Value;
class Namespace;
......@@ -150,6 +152,7 @@ struct NameAndType {
std::ostream& operator<<(std::ostream& os, const NameAndType& name_and_type);
struct Field {
SourcePosition pos;
NameAndType name_and_type;
size_t offset;
bool is_weak;
......@@ -409,6 +412,8 @@ class AggregateType : public Type {
const std::string& name, const std::vector<Field>& fields)
: Type(kind, parent), namespace_(nspace), name_(name), fields_(fields) {}
void CheckForDuplicateFields();
private:
Namespace* namespace_;
std::string name_;
......@@ -422,13 +427,24 @@ class StructType final : public AggregateType {
std::string ToExplicitString() const override;
std::string GetGeneratedTypeName() const override;
void SetDerivedFrom(const ClassType* derived_from) {
derived_from_ = derived_from;
}
base::Optional<const ClassType*> GetDerivedFrom() const {
return derived_from_;
}
private:
friend class TypeOracle;
StructType(Namespace* nspace, const std::string& name,
const std::vector<Field>& fields)
: AggregateType(Kind::kStructType, nullptr, nspace, name, fields) {}
: AggregateType(Kind::kStructType, nullptr, nspace, name, fields) {
CheckForDuplicateFields();
}
const std::string& GetStructName() const { return name(); }
base::Optional<const ClassType*> derived_from_;
};
class ClassType final : public AggregateType {
......@@ -441,7 +457,9 @@ class ClassType final : public AggregateType {
std::string GetGeneratedTNodeTypeName() const override;
bool IsTransient() const override { return transient_; }
size_t size() const { return size_; }
StructType* struct_type() const { return this_struct_; }
const ClassType* GetSuperClass() const {
if (parent() == nullptr) return nullptr;
return parent()->IsClassType() ? ClassType::DynamicCast(parent()) : nullptr;
}
......@@ -449,12 +467,17 @@ class ClassType final : public AggregateType {
friend class TypeOracle;
ClassType(const Type* parent, Namespace* nspace, const std::string& name,
bool transient, const std::string& generates,
const std::vector<Field>& fields, size_t size)
const std::vector<Field>& fields, StructType* this_struct,
size_t size)
: AggregateType(Kind::kClassType, parent, nspace, name, fields),
this_struct_(this_struct),
transient_(transient),
size_(size),
generates_(generates) {}
generates_(generates) {
CheckForDuplicateFields();
}
StructType* this_struct_;
bool transient_;
size_t size_;
const std::string generates_;
......
......@@ -272,6 +272,8 @@ constexpr int kTaggedSize = sizeof(void*);
static const char* const kConstructMethodName = "constructor";
static const char* const kSuperMethodName = "super";
static const char* const kConstructorStructSuperFieldName = "_super";
static const char* const kClassConstructorThisStructPrefix = "_ThisStruct";
// Erase elements of a container that has a constant-time erase function, like
// std::set or std::list. Calling this on std::vector would have quadratic
......
......@@ -736,10 +736,36 @@ namespace test {
c: int32;
}
struct TestCustomStructConstructor {
constructor(x: int32, y: Smi) {
this.a = x;
this.c = x;
this.b = y;
this.d = y;
}
a: int32;
b: Smi;
c: int32;
d: Smi;
}
macro TestStructConstructor(implicit context: Context)() {
let a: TestOuter = TestOuter{0, TestInner{0, 0}, 0};
// Test default constructor
let a: TestOuter = TestOuter{5, TestInner{6, 7}, 8};
assert(a.a == 5);
assert(a.b.x == 6);
assert(a.b.y == 7);
assert(a.c == 8);
a.b.x = 1;
assert(a.b.x == 1);
a.b.SetX(2);
assert(a.b.x == 2);
assert(a.b.GetX() == 2);
// Test custom constructor
let w: TestCustomStructConstructor = TestCustomStructConstructor{1, 2};
assert(w.a == 1);
assert(w.b == 2);
assert(w.c == 1);
assert(w.d == 2);
}
}
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