Commit d11a0648 authored by Daniel Clifford's avatar Daniel Clifford Committed by Commit Bot

[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: 's avatarTobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#58979}
parent f6549baf
...@@ -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(
signature.parameter_names.begin() + signature.implicit_count,
kThisParameterName); kThisParameterName);
signature.parameter_types.types.insert(
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,23 +263,23 @@ void DeclarationVisitor::DeclareMethods( ...@@ -264,23 +263,23 @@ 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, Declarations::CreateMethod(container_type, method_name, signature, false,
body); body);
} }
}
if (container_type->Constructors().size() != 0) return; if (container_type->Constructors().size() != 0) return;
// 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,18 +349,15 @@ void DeclarationVisitor::Visit(ClassDeclaration* decl) { ...@@ -360,18 +349,15 @@ 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( ReportError("class \"", decl->name,
"class \"", decl->name,
"\" must extend either Tagged or an already declared class"); "\" 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<>
std::string generates = decl->name; std::string generates = decl->name;
...@@ -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_class,
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 (super_class->IsClassType()) {
super_struct_type = ClassType::cast(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_class, 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,38 @@ const Type* SubtractType(const Type* a, const Type* b) { ...@@ -184,6 +184,38 @@ const Type* SubtractType(const Type* a, const Type* b) {
return TypeOracle::GetUnionType(result); return TypeOracle::GetUnionType(result);
} }
AggregateType::AggregateType(Kind kind, const Type* parent, Namespace* nspace,
const std::string& name,
const std::vector<Field>& fields)
: Type(kind, parent), namespace_(nspace), name_(name), fields_(fields) {
// 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 +249,7 @@ std::string StructType::GetGeneratedTypeName() const { ...@@ -217,7 +249,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 +375,53 @@ bool operator<(const Type& a, const Type& b) { ...@@ -343,19 +375,53 @@ 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());
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;
...@@ -406,8 +409,7 @@ class AggregateType : public Type { ...@@ -406,8 +409,7 @@ class AggregateType : public Type {
protected: protected:
AggregateType(Kind kind, const Type* parent, Namespace* nspace, AggregateType(Kind kind, const Type* parent, Namespace* nspace,
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) {}
private: private:
Namespace* namespace_; Namespace* namespace_;
...@@ -422,6 +424,13 @@ class StructType final : public AggregateType { ...@@ -422,6 +424,13 @@ 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,
...@@ -429,6 +438,8 @@ class StructType final : public AggregateType { ...@@ -429,6 +438,8 @@ class StructType final : public AggregateType {
: AggregateType(Kind::kStructType, nullptr, nspace, name, fields) {} : AggregateType(Kind::kStructType, nullptr, nspace, name, fields) {}
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 +452,9 @@ class ClassType final : public AggregateType { ...@@ -441,7 +452,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 +462,15 @@ class ClassType final : public AggregateType { ...@@ -449,12 +462,15 @@ 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) {}
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