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 { ...@@ -688,6 +688,10 @@ struct NameAndTypeExpression {
TypeExpression* type; TypeExpression* type;
}; };
struct StructFieldExpression {
NameAndTypeExpression name_and_type;
};
struct ClassFieldExpression { struct ClassFieldExpression {
NameAndTypeExpression name_and_type; NameAndTypeExpression name_and_type;
bool weak; bool weak;
...@@ -883,33 +887,32 @@ struct StructDeclaration : Declaration { ...@@ -883,33 +887,32 @@ struct StructDeclaration : Declaration {
DEFINE_AST_NODE_LEAF_BOILERPLATE(StructDeclaration) DEFINE_AST_NODE_LEAF_BOILERPLATE(StructDeclaration)
StructDeclaration(SourcePosition pos, std::string name, StructDeclaration(SourcePosition pos, std::string name,
std::vector<Declaration*> methods, std::vector<Declaration*> methods,
std::vector<NameAndTypeExpression> fields) std::vector<StructFieldExpression> fields)
: Declaration(kKind, pos), : Declaration(kKind, pos),
name(std::move(name)), name(std::move(name)),
methods(std::move(methods)), methods(std::move(methods)),
fields(std::move(fields)) {} fields(std::move(fields)) {}
std::string name; std::string name;
std::vector<Declaration*> methods; std::vector<Declaration*> methods;
std::vector<NameAndTypeExpression> fields; std::vector<StructFieldExpression> fields;
}; };
struct ClassDeclaration : Declaration { struct ClassDeclaration : Declaration {
DEFINE_AST_NODE_LEAF_BOILERPLATE(ClassDeclaration) DEFINE_AST_NODE_LEAF_BOILERPLATE(ClassDeclaration)
ClassDeclaration(SourcePosition pos, std::string name, bool transient, ClassDeclaration(SourcePosition pos, std::string name, bool transient,
base::Optional<std::string> extends, std::string super, base::Optional<std::string> generates,
base::Optional<std::string> generates,
std::vector<Declaration*> methods, std::vector<Declaration*> methods,
std::vector<ClassFieldExpression> fields) std::vector<ClassFieldExpression> fields)
: Declaration(kKind, pos), : Declaration(kKind, pos),
name(std::move(name)), name(std::move(name)),
transient(transient), transient(transient),
extends(std::move(extends)), super(std::move(super)),
generates(std::move(generates)), generates(std::move(generates)),
methods(std::move(methods)), methods(std::move(methods)),
fields(std::move(fields)) {} fields(std::move(fields)) {}
std::string name; std::string name;
bool transient; bool transient;
base::Optional<std::string> extends; std::string super;
base::Optional<std::string> generates; base::Optional<std::string> generates;
std::vector<Declaration*> methods; std::vector<Declaration*> methods;
std::vector<ClassFieldExpression> fields; std::vector<ClassFieldExpression> fields;
......
...@@ -326,7 +326,9 @@ class Method : public Macro { ...@@ -326,7 +326,9 @@ class Method : public Macro {
DECLARE_DECLARABLE_BOILERPLATE(Method, Method); DECLARE_DECLARABLE_BOILERPLATE(Method, Method);
bool ShouldBeInlined() const override { bool ShouldBeInlined() const override {
return Macro::ShouldBeInlined() || return Macro::ShouldBeInlined() ||
signature().parameter_types.types[0]->IsStructType(); signature()
.parameter_types.types[signature().implicit_count]
->IsStructType();
} }
AggregateType* aggregate_type() const { return aggregate_type_; } AggregateType* aggregate_type() const { return aggregate_type_; }
......
...@@ -163,13 +163,6 @@ void DeclarationVisitor::Visit(GenericDeclaration* decl) { ...@@ -163,13 +163,6 @@ void DeclarationVisitor::Visit(GenericDeclaration* decl) {
Declarations::DeclareGeneric(decl->callable->name, 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) { void DeclarationVisitor::Visit(SpecializationDeclaration* decl) {
if ((decl->body != nullptr) == decl->external) { if ((decl->body != nullptr) == decl->external) {
std::stringstream stream; std::stringstream stream;
...@@ -241,21 +234,27 @@ void DeclarationVisitor::DeclareMethods( ...@@ -241,21 +234,27 @@ void DeclarationVisitor::DeclareMethods(
// Declare the class' methods // Declare the class' methods
IdentifierExpression* constructor_this = MakeNode<IdentifierExpression>( IdentifierExpression* constructor_this = MakeNode<IdentifierExpression>(
std::vector<std::string>{}, kThisParameterName); std::vector<std::string>{}, kThisParameterName);
AggregateType* constructor_this_type =
container_type->IsStructType()
? container_type
: ClassType::cast(container_type)->struct_type();
for (auto declaration : methods) { for (auto declaration : methods) {
CurrentSourcePosition::Scope pos_scope(declaration->pos);
StandardDeclaration* standard_declaration = StandardDeclaration* standard_declaration =
StandardDeclaration::DynamicCast(declaration); StandardDeclaration::DynamicCast(declaration);
DCHECK(standard_declaration); DCHECK(standard_declaration);
TorqueMacroDeclaration* method = TorqueMacroDeclaration* method =
TorqueMacroDeclaration::DynamicCast(standard_declaration->callable); TorqueMacroDeclaration::DynamicCast(standard_declaration->callable);
Signature signature = MakeSignature(method->signature.get()); Signature signature = MakeSignature(method->signature.get());
signature.parameter_names.insert(signature.parameter_names.begin(), signature.parameter_names.insert(
kThisParameterName); signature.parameter_names.begin() + signature.implicit_count,
signature.parameter_types.types.insert( kThisParameterName);
signature.parameter_types.types.begin(), container_type);
signature.implicit_count++;
Statement* body = *(standard_declaration->body); Statement* body = *(standard_declaration->body);
std::string method_name(method->name); std::string method_name(method->name);
if (method->name == kConstructMethodName) { if (method->name == kConstructMethodName) {
signature.parameter_types.types.insert(
signature.parameter_types.types.begin() + signature.implicit_count,
constructor_this_type);
// Constructor // Constructor
if (!signature.return_type->IsVoid()) { if (!signature.return_type->IsVoid()) {
ReportError("constructors musn't have a return type"); ReportError("constructors musn't have a return type");
...@@ -264,15 +263,15 @@ void DeclarationVisitor::DeclareMethods( ...@@ -264,15 +263,15 @@ void DeclarationVisitor::DeclareMethods(
ReportError("constructors musn't have labels"); ReportError("constructors musn't have labels");
} }
method_name = kConstructMethodName; method_name = kConstructMethodName;
signature.return_type = container_type; Declarations::CreateMethod(constructor_this_type, method_name, signature,
ReturnStatement* return_statement = MakeNode<ReturnStatement>( false, body);
MakeNode<IdentifierExpression>(kThisParameterName)); } else {
body = MakeNode<BlockStatement>( signature.parameter_types.types.insert(
false, std::vector<Statement*>{body, return_statement}); signature.parameter_types.types.begin() + signature.implicit_count,
body = WrapBodyWithNoThrow(body, "exception thrown from constructor"); 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; if (container_type->Constructors().size() != 0) return;
...@@ -280,7 +279,7 @@ void DeclarationVisitor::DeclareMethods( ...@@ -280,7 +279,7 @@ void DeclarationVisitor::DeclareMethods(
// Generate default constructor. // Generate default constructor.
Signature constructor_signature; Signature constructor_signature;
constructor_signature.parameter_types.var_args = false; 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<const AggregateType*> hierarchy = container_type->GetHierarchy();
std::vector<Statement*> statements; std::vector<Statement*> statements;
...@@ -288,8 +287,7 @@ void DeclarationVisitor::DeclareMethods( ...@@ -288,8 +287,7 @@ void DeclarationVisitor::DeclareMethods(
size_t parameter_number = 0; size_t parameter_number = 0;
constructor_signature.parameter_names.push_back(kThisParameterName); constructor_signature.parameter_names.push_back(kThisParameterName);
constructor_signature.parameter_types.types.push_back(container_type); constructor_signature.parameter_types.types.push_back(constructor_this_type);
constructor_signature.implicit_count = 1;
std::vector<Expression*> super_arguments; std::vector<Expression*> super_arguments;
for (auto current_type : hierarchy) { for (auto current_type : hierarchy) {
for (auto& f : current_type->fields()) { for (auto& f : current_type->fields()) {
...@@ -302,13 +300,7 @@ void DeclarationVisitor::DeclareMethods( ...@@ -302,13 +300,7 @@ void DeclarationVisitor::DeclareMethods(
if (container_type != current_type) { if (container_type != current_type) {
super_arguments.push_back(MakeNode<IdentifierExpression>( super_arguments.push_back(MakeNode<IdentifierExpression>(
std::vector<std::string>{}, parameter_name)); 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 { } else {
DCHECK(container_type->IsStructType());
LocationExpression* location = MakeNode<FieldAccessExpression>( LocationExpression* location = MakeNode<FieldAccessExpression>(
constructor_this, f.name_and_type.name); constructor_this, f.name_and_type.name);
Statement* statement = MakeNode<ExpressionStatement>( Statement* statement = MakeNode<ExpressionStatement>(
...@@ -321,26 +313,20 @@ void DeclarationVisitor::DeclareMethods( ...@@ -321,26 +313,20 @@ void DeclarationVisitor::DeclareMethods(
if (hierarchy.size() > 1) { if (hierarchy.size() > 1) {
IdentifierExpression* super_identifier = MakeNode<IdentifierExpression>( IdentifierExpression* super_identifier = MakeNode<IdentifierExpression>(
std::vector<std::string>{}, kSuperMethodName); std::vector<std::string>{}, kSuperMethodName);
Statement* super_call_statement = Statement* statement =
MakeNode<ExpressionStatement>(MakeNode<CallMethodExpression>( MakeNode<ExpressionStatement>(MakeNode<CallMethodExpression>(
constructor_this, super_identifier, super_arguments, constructor_this, super_identifier, super_arguments,
std::vector<std::string>{})); std::vector<std::string>{}));
statements.push_back(super_call_statement); statements.push_back(statement);
} }
for (auto s : initializer_statements) { for (auto s : initializer_statements) {
statements.push_back(s); statements.push_back(s);
} }
statements.push_back(MakeNode<ReturnStatement>(MakeNode<IdentifierExpression>(
std::vector<std::string>{}, kThisParameterName)));
Statement* constructor_body = MakeNode<BlockStatement>(false, statements); Statement* constructor_body = MakeNode<BlockStatement>(false, statements);
constructor_body = WrapBodyWithNoThrow(constructor_body, Declarations::CreateMethod(constructor_this_type, kConstructMethodName,
"exception thrown from constructor");
Declarations::CreateMethod(container_type, kConstructMethodName,
constructor_signature, false, constructor_body); constructor_signature, false, constructor_body);
} }
...@@ -348,8 +334,11 @@ void DeclarationVisitor::Visit(StructDeclaration* decl) { ...@@ -348,8 +334,11 @@ void DeclarationVisitor::Visit(StructDeclaration* decl) {
std::vector<Field> fields; std::vector<Field> fields;
size_t offset = 0; size_t offset = 0;
for (auto& field : decl->fields) { for (auto& field : decl->fields) {
const Type* field_type = Declarations::GetType(field.type); const Type* field_type = Declarations::GetType(field.name_and_type.type);
fields.push_back({{field.name, field_type}, offset, false}); fields.push_back({field.name_and_type.type->pos,
{field.name_and_type.name, field_type},
offset,
false});
offset += LoweredSlotCount(field_type); offset += LoweredSlotCount(field_type);
} }
StructType* struct_type = Declarations::DeclareStruct(decl->name, fields); StructType* struct_type = Declarations::DeclareStruct(decl->name, fields);
...@@ -360,17 +349,14 @@ void DeclarationVisitor::Visit(ClassDeclaration* decl) { ...@@ -360,17 +349,14 @@ void DeclarationVisitor::Visit(ClassDeclaration* decl) {
// Compute the offset of the class' first member. If the class extends // Compute the offset of the class' first member. If the class extends
// another class, it's the size of the extended class, otherwise zero. // another class, it's the size of the extended class, otherwise zero.
size_t first_field_offset = 0; size_t first_field_offset = 0;
if (decl->extends) { const Type* super_type = Declarations::LookupType(decl->super);
const Type* super_type = Declarations::LookupType(*decl->extends); if (super_type != TypeOracle::GetTaggedType()) {
if (super_type != TypeOracle::GetTaggedType()) { const ClassType* super_class = ClassType::DynamicCast(super_type);
const ClassType* super_class = ClassType::DynamicCast(super_type); if (!super_class) {
if (!super_class) { ReportError("class \"", decl->name,
ReportError( "\" must extend either Tagged or an already declared class");
"class \"", decl->name,
"\" must extend either Tagged or an already declared class");
}
first_field_offset = super_class->size();
} }
first_field_offset = super_class->size();
} }
// The generates clause must create a TNode<> // The generates clause must create a TNode<>
...@@ -385,7 +371,7 @@ void DeclarationVisitor::Visit(ClassDeclaration* decl) { ...@@ -385,7 +371,7 @@ void DeclarationVisitor::Visit(ClassDeclaration* decl) {
} }
std::vector<Field> fields; std::vector<Field> fields;
size_t offset = first_field_offset; size_t class_offset = first_field_offset;
bool seen_strong = false; bool seen_strong = false;
bool seen_weak = false; bool seen_weak = false;
for (ClassFieldExpression& field : decl->fields) { for (ClassFieldExpression& field : decl->fields) {
...@@ -412,13 +398,15 @@ void DeclarationVisitor::Visit(ClassDeclaration* decl) { ...@@ -412,13 +398,15 @@ void DeclarationVisitor::Visit(ClassDeclaration* decl) {
"field \"", field.name_and_type.name, "\" of class \"", decl->name, "field \"", field.name_and_type.name, "\" of class \"", decl->name,
"\" must be a subtype of Tagged (other types not yet supported)"); "\" must be a subtype of Tagged (other types not yet supported)");
} }
fields.push_back( fields.push_back({field.name_and_type.type->pos,
{{field.name_and_type.name, field_type}, offset, field.weak}); {field.name_and_type.name, field_type},
offset += kTaggedSize; class_offset,
field.weak});
class_offset += kTaggedSize;
} }
auto new_class = Declarations::DeclareClass( 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); DeclareMethods(new_class, decl->methods);
// For each field, construct AST snippits that implement a CSA accessor // For each field, construct AST snippits that implement a CSA accessor
......
...@@ -174,16 +174,43 @@ StructType* Declarations::DeclareStruct(const std::string& name, ...@@ -174,16 +174,43 @@ StructType* Declarations::DeclareStruct(const std::string& name,
return new_type; 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& name, bool transient,
const std::string& generates, const std::string& generates,
std::vector<Field> fields, size_t size) { std::vector<Field> fields, size_t size) {
const Type* parent_type = nullptr; std::vector<Field> this_struct_fields;
if (parent) { size_t struct_offset = 0;
parent_type = LookupType(QualifiedName{*parent}); 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( for (auto& field : fields) {
parent_type, name, transient, generates, std::move(fields), size); 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); DeclareType(name, new_type, false);
return new_type; return new_type;
} }
......
...@@ -84,9 +84,8 @@ class Declarations { ...@@ -84,9 +84,8 @@ class Declarations {
static StructType* DeclareStruct(const std::string& name, static StructType* DeclareStruct(const std::string& name,
const std::vector<Field>& fields); const std::vector<Field>& fields);
static ClassType* DeclareClass(base::Optional<std::string> parent, static ClassType* DeclareClass(const Type* super, const std::string& name,
const std::string& name, bool transient, bool transient, const std::string& generates,
const std::string& generates,
std::vector<Field> fields, size_t size); std::vector<Field> fields, size_t size);
static Macro* CreateMacro(std::string external_name, static Macro* CreateMacro(std::string external_name,
......
This diff is collapsed.
...@@ -212,6 +212,8 @@ class ImplementationVisitor : public FileVisitor { ...@@ -212,6 +212,8 @@ class ImplementationVisitor : public FileVisitor {
VisitResult Visit(Expression* expr); VisitResult Visit(Expression* expr);
const Type* Visit(Statement* stmt); const Type* Visit(Statement* stmt);
VisitResult TemporaryUninitializedStruct(const StructType* struct_type,
const std::string& reason);
VisitResult Visit(StructExpression* decl); VisitResult Visit(StructExpression* decl);
LocationReference GetLocationReference(Expression* location); LocationReference GetLocationReference(Expression* location);
...@@ -290,7 +292,6 @@ class ImplementationVisitor : public FileVisitor { ...@@ -290,7 +292,6 @@ class ImplementationVisitor : public FileVisitor {
struct ConstructorInfo { struct ConstructorInfo {
int super_calls; int super_calls;
bool accessed_this;
}; };
DECLARE_CONTEXTUAL_VARIABLE(ValueBindingsManager, DECLARE_CONTEXTUAL_VARIABLE(ValueBindingsManager,
...@@ -396,11 +397,29 @@ class ImplementationVisitor : public FileVisitor { ...@@ -396,11 +397,29 @@ class ImplementationVisitor : public FileVisitor {
Binding<LocalLabel>* LookupLabel(const std::string& name); Binding<LocalLabel>* LookupLabel(const std::string& name);
Block* LookupSimpleLabel(const std::string& name); Block* LookupSimpleLabel(const std::string& name);
template <class Container> template <class Container>
Callable* LookupCall(const QualifiedName& name, Callable* LookupCallable(const QualifiedName& name,
const Container& declaration_container, 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 Arguments& arguments,
const TypeVector& specialization_types); 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); const Type* GetCommonType(const Type* left, const Type* right);
VisitResult GenerateCopy(const VisitResult& to_copy); VisitResult GenerateCopy(const VisitResult& to_copy);
......
...@@ -42,8 +42,10 @@ enum class ParseResultHolderBase::TypeId { ...@@ -42,8 +42,10 @@ enum class ParseResultHolderBase::TypeId {
kOptionalLabelBlockPtr, kOptionalLabelBlockPtr,
kNameAndTypeExpression, kNameAndTypeExpression,
kClassFieldExpression, kClassFieldExpression,
kStructFieldExpression,
kStdVectorOfNameAndTypeExpression, kStdVectorOfNameAndTypeExpression,
kStdVectorOfClassFieldExpression, kStdVectorOfClassFieldExpression,
kStdVectorOfStructFieldExpression,
kIncrementDecrementOperator, kIncrementDecrementOperator,
kOptionalStdString, kOptionalStdString,
kStdVectorOfStatementPtr, kStdVectorOfStatementPtr,
...@@ -107,6 +109,10 @@ V8_EXPORT_PRIVATE const ParseResultTypeId ...@@ -107,6 +109,10 @@ V8_EXPORT_PRIVATE const ParseResultTypeId
ParseResultHolder<ClassFieldExpression>::id = ParseResultHolder<ClassFieldExpression>::id =
ParseResultTypeId::kClassFieldExpression; ParseResultTypeId::kClassFieldExpression;
template <> template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
ParseResultHolder<StructFieldExpression>::id =
ParseResultTypeId::kStructFieldExpression;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId V8_EXPORT_PRIVATE const ParseResultTypeId
ParseResultHolder<std::vector<NameAndTypeExpression>>::id = ParseResultHolder<std::vector<NameAndTypeExpression>>::id =
ParseResultTypeId::kStdVectorOfNameAndTypeExpression; ParseResultTypeId::kStdVectorOfNameAndTypeExpression;
...@@ -115,6 +121,10 @@ V8_EXPORT_PRIVATE const ParseResultTypeId ...@@ -115,6 +121,10 @@ V8_EXPORT_PRIVATE const ParseResultTypeId
ParseResultHolder<std::vector<ClassFieldExpression>>::id = ParseResultHolder<std::vector<ClassFieldExpression>>::id =
ParseResultTypeId::kStdVectorOfClassFieldExpression; ParseResultTypeId::kStdVectorOfClassFieldExpression;
template <> template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
ParseResultHolder<std::vector<StructFieldExpression>>::id =
ParseResultTypeId::kStdVectorOfStructFieldExpression;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId V8_EXPORT_PRIVATE const ParseResultTypeId
ParseResultHolder<IncrementDecrementOperator>::id = ParseResultHolder<IncrementDecrementOperator>::id =
ParseResultTypeId::kIncrementDecrementOperator; ParseResultTypeId::kIncrementDecrementOperator;
...@@ -581,7 +591,7 @@ base::Optional<ParseResult> MakeClassDeclaration( ...@@ -581,7 +591,7 @@ base::Optional<ParseResult> MakeClassDeclaration(
if (!IsValidTypeName(name)) { if (!IsValidTypeName(name)) {
NamingConventionError("Type", name, "UpperCamelCase"); 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 generates = child_results->NextAs<base::Optional<std::string>>();
auto methods = child_results->NextAs<std::vector<Declaration*>>(); auto methods = child_results->NextAs<std::vector<Declaration*>>();
auto fields = child_results->NextAs<std::vector<ClassFieldExpression>>(); auto fields = child_results->NextAs<std::vector<ClassFieldExpression>>();
...@@ -623,7 +633,7 @@ base::Optional<ParseResult> MakeStructDeclaration( ...@@ -623,7 +633,7 @@ base::Optional<ParseResult> MakeStructDeclaration(
ParseResultIterator* child_results) { ParseResultIterator* child_results) {
auto name = child_results->NextAs<std::string>(); auto name = child_results->NextAs<std::string>();
auto methods = child_results->NextAs<std::vector<Declaration*>>(); 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>( Declaration* result = MakeNode<StructDeclaration>(
std::move(name), std::move(methods), std::move(fields)); std::move(name), std::move(methods), std::move(fields));
return ParseResult{result}; return ParseResult{result};
...@@ -1119,6 +1129,13 @@ base::Optional<ParseResult> MakeClassField(ParseResultIterator* child_results) { ...@@ -1119,6 +1129,13 @@ base::Optional<ParseResult> MakeClassField(ParseResultIterator* child_results) {
return ParseResult{ClassFieldExpression{{std::move(name), type}, weak}}; 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( base::Optional<ParseResult> ExtractAssignmentOperator(
ParseResultIterator* child_results) { ParseResultIterator* child_results) {
auto op = child_results->NextAs<std::string>(); auto op = child_results->NextAs<std::string>();
...@@ -1309,6 +1326,9 @@ struct TorqueGrammar : Grammar { ...@@ -1309,6 +1326,9 @@ struct TorqueGrammar : Grammar {
Rule({CheckIf(Token("weak")), &identifier, Token(":"), &type, Token(";")}, Rule({CheckIf(Token("weak")), &identifier, Token(":"), &type, Token(";")},
MakeClassField)}; MakeClassField)};
Symbol structField = {
Rule({&identifier, Token(":"), &type, Token(";")}, MakeStructField)};
// Result: ParameterList // Result: ParameterList
Symbol parameterListNoVararg = { Symbol parameterListNoVararg = {
Rule({optionalImplicitParameterList, Token("("), Rule({optionalImplicitParameterList, Token("("),
...@@ -1589,7 +1609,7 @@ struct TorqueGrammar : Grammar { ...@@ -1589,7 +1609,7 @@ struct TorqueGrammar : Grammar {
&externalString, Token(";")}, &externalString, Token(";")},
MakeExternConstDeclaration), MakeExternConstDeclaration),
Rule({CheckIf(Token("transient")), Token("class"), &identifier, Rule({CheckIf(Token("transient")), Token("class"), &identifier,
Optional<std::string>(Sequence({Token("extends"), &identifier})), Sequence({Token("extends"), &identifier}),
Optional<std::string>( Optional<std::string>(
Sequence({Token("generates"), &externalString})), Sequence({Token("generates"), &externalString})),
Token("{"), List<Declaration*>(&method), Token("{"), List<Declaration*>(&method),
...@@ -1597,8 +1617,7 @@ struct TorqueGrammar : Grammar { ...@@ -1597,8 +1617,7 @@ struct TorqueGrammar : Grammar {
MakeClassDeclaration), MakeClassDeclaration),
Rule({Token("struct"), &identifier, Token("{"), Rule({Token("struct"), &identifier, Token("{"),
List<Declaration*>(&method), List<Declaration*>(&method),
List<NameAndTypeExpression>(Sequence({&nameAndType, Token(";")})), List<StructFieldExpression>(&structField), Token("}")},
Token("}")},
MakeStructDeclaration), MakeStructDeclaration),
Rule({CheckIf(Token("transient")), Token("type"), &identifier, Rule({CheckIf(Token("transient")), Token("type"), &identifier,
Optional<std::string>(Sequence({Token("extends"), &identifier})), Optional<std::string>(Sequence({Token("extends"), &identifier})),
......
...@@ -38,9 +38,10 @@ class TypeOracle : public ContextualClass<TypeOracle> { ...@@ -38,9 +38,10 @@ class TypeOracle : public ContextualClass<TypeOracle> {
static ClassType* GetClassType(const Type* parent, const std::string& name, static ClassType* GetClassType(const Type* parent, const std::string& name,
bool transient, const std::string& generates, bool transient, const std::string& generates,
const std::vector<Field>& fields, const std::vector<Field>& fields,
size_t size) { StructType* this_struct, size_t size) {
ClassType* result = new ClassType(parent, CurrentNamespace(), name, ClassType* result =
transient, generates, fields, size); new ClassType(parent, CurrentNamespace(), name, transient, generates,
fields, this_struct, size);
Get().struct_types_.push_back(std::unique_ptr<ClassType>(result)); Get().struct_types_.push_back(std::unique_ptr<ClassType>(result));
return result; return result;
} }
......
...@@ -184,6 +184,35 @@ const Type* SubtractType(const Type* a, const Type* b) { ...@@ -184,6 +184,35 @@ const Type* SubtractType(const Type* a, const Type* b) {
return TypeOracle::GetUnionType(result); 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*> AggregateType::GetHierarchy() {
std::vector<const AggregateType*> hierarchy; std::vector<const AggregateType*> hierarchy;
const AggregateType* current_container_type = this; const AggregateType* current_container_type = this;
...@@ -217,7 +246,7 @@ std::string StructType::GetGeneratedTypeName() const { ...@@ -217,7 +246,7 @@ std::string StructType::GetGeneratedTypeName() const {
std::vector<Method*> AggregateType::Methods(const std::string& name) const { std::vector<Method*> AggregateType::Methods(const std::string& name) const {
std::vector<Method*> result; std::vector<Method*> result;
std::copy_if(methods_.begin(), methods_.end(), std::back_inserter(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; return result;
} }
...@@ -343,19 +372,54 @@ bool operator<(const Type& a, const Type& b) { ...@@ -343,19 +372,54 @@ bool operator<(const Type& a, const Type& b) {
return a.MangledName() < b.MangledName(); return a.MangledName() < b.MangledName();
} }
VisitResult ProjectStructField(VisitResult structure, VisitResult ProjectStructField(const StructType* original_struct,
VisitResult structure,
const std::string& fieldname) { const std::string& fieldname) {
DCHECK(structure.IsOnStack());
BottomOffset begin = structure.stack_range().begin(); BottomOffset begin = structure.stack_range().begin();
// Check constructor this super classes for fields.
const StructType* type = StructType::cast(structure.type()); 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); BottomOffset end = begin + LoweredSlotCount(field.name_and_type.type);
if (field.name_and_type.name == fieldname) { if (field.name_and_type.name == fieldname) {
return VisitResult(field.name_and_type.type, StackRange{begin, end}); return VisitResult(field.name_and_type.type, StackRange{begin, end});
} }
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 { namespace {
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <vector> #include <vector>
#include "src/base/optional.h" #include "src/base/optional.h"
#include "src/torque/source-positions.h"
#include "src/torque/utils.h" #include "src/torque/utils.h"
namespace v8 { namespace v8 {
...@@ -43,6 +44,7 @@ static const char* const CONST_FLOAT64_TYPE_STRING = "constexpr float64"; ...@@ -43,6 +44,7 @@ static const char* const CONST_FLOAT64_TYPE_STRING = "constexpr float64";
class Macro; class Macro;
class Method; class Method;
class StructType; class StructType;
class ClassType;
class Value; class Value;
class Namespace; class Namespace;
...@@ -150,6 +152,7 @@ struct NameAndType { ...@@ -150,6 +152,7 @@ struct NameAndType {
std::ostream& operator<<(std::ostream& os, const NameAndType& name_and_type); std::ostream& operator<<(std::ostream& os, const NameAndType& name_and_type);
struct Field { struct Field {
SourcePosition pos;
NameAndType name_and_type; NameAndType name_and_type;
size_t offset; size_t offset;
bool is_weak; bool is_weak;
...@@ -409,6 +412,8 @@ class AggregateType : public Type { ...@@ -409,6 +412,8 @@ class AggregateType : public Type {
const std::string& name, const std::vector<Field>& fields) const std::string& name, const std::vector<Field>& fields)
: Type(kind, parent), namespace_(nspace), name_(name), fields_(fields) {} : Type(kind, parent), namespace_(nspace), name_(name), fields_(fields) {}
void CheckForDuplicateFields();
private: private:
Namespace* namespace_; Namespace* namespace_;
std::string name_; std::string name_;
...@@ -422,13 +427,24 @@ class StructType final : public AggregateType { ...@@ -422,13 +427,24 @@ class StructType final : public AggregateType {
std::string ToExplicitString() const override; std::string ToExplicitString() const override;
std::string GetGeneratedTypeName() 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: private:
friend class TypeOracle; friend class TypeOracle;
StructType(Namespace* nspace, const std::string& name, StructType(Namespace* nspace, const std::string& name,
const std::vector<Field>& fields) 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(); } const std::string& GetStructName() const { return name(); }
base::Optional<const ClassType*> derived_from_;
}; };
class ClassType final : public AggregateType { class ClassType final : public AggregateType {
...@@ -441,7 +457,9 @@ class ClassType final : public AggregateType { ...@@ -441,7 +457,9 @@ class ClassType final : public AggregateType {
std::string GetGeneratedTNodeTypeName() const override; std::string GetGeneratedTNodeTypeName() const override;
bool IsTransient() const override { return transient_; } bool IsTransient() const override { return transient_; }
size_t size() const { return size_; } size_t size() const { return size_; }
StructType* struct_type() const { return this_struct_; }
const ClassType* GetSuperClass() const { const ClassType* GetSuperClass() const {
if (parent() == nullptr) return nullptr;
return parent()->IsClassType() ? ClassType::DynamicCast(parent()) : nullptr; return parent()->IsClassType() ? ClassType::DynamicCast(parent()) : nullptr;
} }
...@@ -449,12 +467,17 @@ class ClassType final : public AggregateType { ...@@ -449,12 +467,17 @@ class ClassType final : public AggregateType {
friend class TypeOracle; friend class TypeOracle;
ClassType(const Type* parent, Namespace* nspace, const std::string& name, ClassType(const Type* parent, Namespace* nspace, const std::string& name,
bool transient, const std::string& generates, 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), : AggregateType(Kind::kClassType, parent, nspace, name, fields),
this_struct_(this_struct),
transient_(transient), transient_(transient),
size_(size), size_(size),
generates_(generates) {} generates_(generates) {
CheckForDuplicateFields();
}
StructType* this_struct_;
bool transient_; bool transient_;
size_t size_; size_t size_;
const std::string generates_; const std::string generates_;
......
...@@ -272,6 +272,8 @@ constexpr int kTaggedSize = sizeof(void*); ...@@ -272,6 +272,8 @@ constexpr int kTaggedSize = sizeof(void*);
static const char* const kConstructMethodName = "constructor"; static const char* const kConstructMethodName = "constructor";
static const char* const kSuperMethodName = "super"; 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 // 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 // std::set or std::list. Calling this on std::vector would have quadratic
......
...@@ -736,10 +736,36 @@ namespace test { ...@@ -736,10 +736,36 @@ namespace test {
c: int32; 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)() { 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); a.b.SetX(2);
assert(a.b.x == 2); assert(a.b.x == 2);
assert(a.b.GetX() == 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