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 {
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_class,
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 (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(
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_class, 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,38 @@ const Type* SubtractType(const Type* a, const Type* b) {
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*> hierarchy;
const AggregateType* current_container_type = this;
......@@ -217,7 +249,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 +375,53 @@ 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());
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;
......@@ -406,8 +409,7 @@ class AggregateType : public Type {
protected:
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) {}
const std::string& name, const std::vector<Field>& fields);
private:
Namespace* namespace_;
......@@ -422,6 +424,13 @@ 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,
......@@ -429,6 +438,8 @@ class StructType final : public AggregateType {
: AggregateType(Kind::kStructType, nullptr, nspace, name, fields) {}
const std::string& GetStructName() const { return name(); }
base::Optional<const ClassType*> derived_from_;
};
class ClassType final : public AggregateType {
......@@ -441,7 +452,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 +462,15 @@ 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) {}
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