Commit 8c17e114 authored by Daniel Clifford's avatar Daniel Clifford Committed by Commit Bot

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

This reverts commit d11a0648.

Reason for revert: <INSERT REASONING HERE>

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}

TBR=danno@chromium.org,tebbi@chromium.org

Change-Id: Id6c46c175f53c5a77db1e6ca242586fba34cd02e
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: v8:7793
Reviewed-on: https://chromium-review.googlesource.com/c/1426121Reviewed-by: 's avatarDaniel Clifford <danno@chromium.org>
Commit-Queue: Daniel Clifford <danno@chromium.org>
Cr-Commit-Position: refs/heads/master@{#58980}
parent d11a0648
...@@ -688,10 +688,6 @@ struct NameAndTypeExpression { ...@@ -688,10 +688,6 @@ 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;
...@@ -887,32 +883,33 @@ struct StructDeclaration : Declaration { ...@@ -887,32 +883,33 @@ 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<StructFieldExpression> fields) std::vector<NameAndTypeExpression> 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<StructFieldExpression> fields; std::vector<NameAndTypeExpression> 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,
std::string super, base::Optional<std::string> generates, base::Optional<std::string> extends,
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),
super(std::move(super)), extends(std::move(extends)),
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;
std::string super; base::Optional<std::string> extends;
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,9 +326,7 @@ class Method : public Macro { ...@@ -326,9 +326,7 @@ 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() signature().parameter_types.types[0]->IsStructType();
.parameter_types.types[signature().implicit_count]
->IsStructType();
} }
AggregateType* aggregate_type() const { return aggregate_type_; } AggregateType* aggregate_type() const { return aggregate_type_; }
......
...@@ -163,6 +163,13 @@ void DeclarationVisitor::Visit(GenericDeclaration* decl) { ...@@ -163,6 +163,13 @@ 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;
...@@ -234,27 +241,21 @@ void DeclarationVisitor::DeclareMethods( ...@@ -234,27 +241,21 @@ 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.insert(signature.parameter_names.begin(),
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");
...@@ -263,23 +264,23 @@ void DeclarationVisitor::DeclareMethods( ...@@ -263,23 +264,23 @@ void DeclarationVisitor::DeclareMethods(
ReportError("constructors musn't have labels"); ReportError("constructors musn't have labels");
} }
method_name = kConstructMethodName; method_name = kConstructMethodName;
Declarations::CreateMethod(constructor_this_type, method_name, signature, signature.return_type = container_type;
false, body); ReturnStatement* return_statement = MakeNode<ReturnStatement>(
} else { MakeNode<IdentifierExpression>(kThisParameterName));
signature.parameter_types.types.insert( body = MakeNode<BlockStatement>(
signature.parameter_types.types.begin() + signature.implicit_count, false, std::vector<Statement*>{body, return_statement});
container_type); body = WrapBodyWithNoThrow(body, "exception thrown from constructor");
}
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 = TypeOracle::GetVoidType(); constructor_signature.return_type = container_type;
std::vector<const AggregateType*> hierarchy = container_type->GetHierarchy(); std::vector<const AggregateType*> hierarchy = container_type->GetHierarchy();
std::vector<Statement*> statements; std::vector<Statement*> statements;
...@@ -287,7 +288,8 @@ void DeclarationVisitor::DeclareMethods( ...@@ -287,7 +288,8 @@ 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(constructor_this_type); constructor_signature.parameter_types.types.push_back(container_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()) {
...@@ -300,7 +302,13 @@ void DeclarationVisitor::DeclareMethods( ...@@ -300,7 +302,13 @@ 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>(
...@@ -313,20 +321,26 @@ void DeclarationVisitor::DeclareMethods( ...@@ -313,20 +321,26 @@ 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* statement = Statement* super_call_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(statement); statements.push_back(super_call_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);
Declarations::CreateMethod(constructor_this_type, kConstructMethodName, constructor_body = WrapBodyWithNoThrow(constructor_body,
"exception thrown from constructor");
Declarations::CreateMethod(container_type, kConstructMethodName,
constructor_signature, false, constructor_body); constructor_signature, false, constructor_body);
} }
...@@ -334,11 +348,8 @@ void DeclarationVisitor::Visit(StructDeclaration* decl) { ...@@ -334,11 +348,8 @@ 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.name_and_type.type); const Type* field_type = Declarations::GetType(field.type);
fields.push_back({field.name_and_type.type->pos, fields.push_back({{field.name, field_type}, offset, false});
{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);
...@@ -349,15 +360,18 @@ void DeclarationVisitor::Visit(ClassDeclaration* decl) { ...@@ -349,15 +360,18 @@ 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;
const Type* super_type = Declarations::LookupType(decl->super); if (decl->extends) {
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(
"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;
...@@ -371,7 +385,7 @@ void DeclarationVisitor::Visit(ClassDeclaration* decl) { ...@@ -371,7 +385,7 @@ void DeclarationVisitor::Visit(ClassDeclaration* decl) {
} }
std::vector<Field> fields; std::vector<Field> fields;
size_t class_offset = first_field_offset; size_t 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) {
...@@ -398,15 +412,13 @@ void DeclarationVisitor::Visit(ClassDeclaration* decl) { ...@@ -398,15 +412,13 @@ 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({field.name_and_type.type->pos, fields.push_back(
{field.name_and_type.name, field_type}, {{field.name_and_type.name, field_type}, offset, field.weak});
class_offset, offset += kTaggedSize;
field.weak});
class_offset += kTaggedSize;
} }
auto new_class = Declarations::DeclareClass( auto new_class = Declarations::DeclareClass(
super_type, decl->name, decl->transient, generates, fields, class_offset); decl->extends, decl->name, decl->transient, generates, fields, 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,43 +174,16 @@ StructType* Declarations::DeclareStruct(const std::string& name, ...@@ -174,43 +174,16 @@ StructType* Declarations::DeclareStruct(const std::string& name,
return new_type; return new_type;
} }
ClassType* Declarations::DeclareClass(const Type* super_class, ClassType* Declarations::DeclareClass(base::Optional<std::string> parent,
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) {
std::vector<Field> this_struct_fields; const Type* parent_type = nullptr;
size_t struct_offset = 0; if (parent) {
const StructType* super_struct_type = nullptr; parent_type = LookupType(QualifiedName{*parent});
// 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);
}
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( ClassType* new_type = TypeOracle::GetClassType(
kClassConstructorThisStructPrefix + name, this_struct_fields); parent_type, name, transient, generates, std::move(fields), size);
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,8 +84,9 @@ class Declarations { ...@@ -84,8 +84,9 @@ 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(const Type* super, const std::string& name, static ClassType* DeclareClass(base::Optional<std::string> parent,
bool transient, const std::string& generates, const std::string& name, bool transient,
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,
......
...@@ -195,16 +195,14 @@ VisitResult ImplementationVisitor::InlineMacro( ...@@ -195,16 +195,14 @@ VisitResult ImplementationVisitor::InlineMacro(
const Type* return_type = macro->signature().return_type; const Type* return_type = macro->signature().return_type;
bool can_return = return_type != TypeOracle::GetNeverType(); bool can_return = return_type != TypeOracle::GetNeverType();
CurrentConstructorInfo::Scope current_constructor;
if (macro->IsConstructor())
CurrentConstructorInfo::Get() = ConstructorInfo{0};
BlockBindings<LocalValue> parameter_bindings(&ValueBindingsManager::Get()); BlockBindings<LocalValue> parameter_bindings(&ValueBindingsManager::Get());
BlockBindings<LocalLabel> label_bindings(&LabelBindingsManager::Get()); BlockBindings<LocalLabel> label_bindings(&LabelBindingsManager::Get());
DCHECK_EQ(macro->signature().parameter_names.size(), DCHECK_EQ(macro->signature().parameter_names.size(),
arguments.size() + (this_reference ? 1 : 0)); arguments.size() + (this_reference ? 1 : 0));
DCHECK_EQ(this_reference.has_value(), macro->IsMethod()); DCHECK_EQ(this_reference.has_value(), macro->IsMethod());
{
size_t i = 0;
// Bind the this for methods. Methods that modify a struct-type "this" must // Bind the this for methods. Methods that modify a struct-type "this" must
// only be called if the this is in a variable, in which case the // only be called if the this is in a variable, in which case the
// LocalValue is non-const. Otherwise, the LocalValue used for the parameter // LocalValue is non-const. Otherwise, the LocalValue used for the parameter
...@@ -217,14 +215,14 @@ VisitResult ImplementationVisitor::InlineMacro( ...@@ -217,14 +215,14 @@ VisitResult ImplementationVisitor::InlineMacro(
LocalValue this_value = LocalValue{!this_reference->IsVariableAccess(), LocalValue this_value = LocalValue{!this_reference->IsVariableAccess(),
this_reference->GetVisitResult()}; this_reference->GetVisitResult()};
parameter_bindings.Add(kThisParameterName, this_value); parameter_bindings.Add(kThisParameterName, this_value);
i++;
} }
size_t i = 0;
for (auto arg : arguments) { for (auto arg : arguments) {
if (this_reference && i == signature.implicit_count) i++;
const std::string& name = macro->parameter_names()[i++]; const std::string& name = macro->parameter_names()[i++];
parameter_bindings.Add(name, LocalValue{true, arg}); parameter_bindings.Add(name, LocalValue{true, arg});
} }
}
DCHECK_EQ(label_blocks.size(), signature.labels.size()); DCHECK_EQ(label_blocks.size(), signature.labels.size());
for (size_t i = 0; i < signature.labels.size(); ++i) { for (size_t i = 0; i < signature.labels.size(); ++i) {
...@@ -243,16 +241,6 @@ VisitResult ImplementationVisitor::InlineMacro( ...@@ -243,16 +241,6 @@ VisitResult ImplementationVisitor::InlineMacro(
SetReturnValue(VisitResult(return_type, SetReturnValue(VisitResult(return_type,
stack.TopRange(lowered_return_types.size()))); stack.TopRange(lowered_return_types.size())));
} }
// The stack copy used to initialize the _macro_end block is only used
// as a template for the actual gotos generated by return statements. It
// doesn't correspond to any real return values, and thus shouldn't contain
// top types, because these would pollute actual return value types that get
// unioned with them for return statements, erroneously forcing them to top.
for (auto i = stack.begin(); i != stack.end(); ++i) {
if ((*i)->IsTopType()) {
*i = TopType::cast(*i)->source_type();
}
}
macro_end = assembler().NewBlock(std::move(stack)); macro_end = assembler().NewBlock(std::move(stack));
macro_end_binding.emplace(&LabelBindingsManager::Get(), "_macro_end", macro_end_binding.emplace(&LabelBindingsManager::Get(), "_macro_end",
LocalLabel{macro_end, {return_type}}); LocalLabel{macro_end, {return_type}});
...@@ -295,11 +283,6 @@ VisitResult ImplementationVisitor::InlineMacro( ...@@ -295,11 +283,6 @@ VisitResult ImplementationVisitor::InlineMacro(
} }
void ImplementationVisitor::VisitMacroCommon(Macro* macro) { void ImplementationVisitor::VisitMacroCommon(Macro* macro) {
// Do not generate code for inlined macros.
if (macro->ShouldBeInlined()) {
return;
}
CurrentCallable::Scope current_callable(macro); CurrentCallable::Scope current_callable(macro);
const Signature& signature = macro->signature(); const Signature& signature = macro->signature();
const Type* return_type = macro->signature().return_type; const Type* return_type = macro->signature().return_type;
...@@ -324,6 +307,7 @@ void ImplementationVisitor::VisitMacroCommon(Macro* macro) { ...@@ -324,6 +307,7 @@ void ImplementationVisitor::VisitMacroCommon(Macro* macro) {
std::vector<VisitResult> arguments; std::vector<VisitResult> arguments;
size_t i = 0;
base::Optional<LocationReference> this_reference; base::Optional<LocationReference> this_reference;
if (Method* method = Method::DynamicCast(macro)) { if (Method* method = Method::DynamicCast(macro)) {
const Type* this_type = method->aggregate_type(); const Type* this_type = method->aggregate_type();
...@@ -335,10 +319,10 @@ void ImplementationVisitor::VisitMacroCommon(Macro* macro) { ...@@ -335,10 +319,10 @@ void ImplementationVisitor::VisitMacroCommon(Macro* macro) {
// Mark the this as a temporary to prevent assignment to it. // Mark the this as a temporary to prevent assignment to it.
this_reference = this_reference =
LocationReference::Temporary(this_result, "this parameter"); LocationReference::Temporary(this_result, "this parameter");
++i;
} }
for (size_t i = 0; i < macro->signature().parameter_names.size(); ++i) { for (; i < macro->signature().parameter_names.size(); ++i) {
if (this_reference && i == macro->signature().implicit_count) continue;
const std::string& name = macro->parameter_names()[i]; const std::string& name = macro->parameter_names()[i];
std::string external_name = ExternalParameterName(name); std::string external_name = ExternalParameterName(name);
const Type* type = macro->signature().types()[i]; const Type* type = macro->signature().types()[i];
...@@ -405,11 +389,19 @@ void ImplementationVisitor::VisitMacroCommon(Macro* macro) { ...@@ -405,11 +389,19 @@ void ImplementationVisitor::VisitMacroCommon(Macro* macro) {
void ImplementationVisitor::Visit(Macro* macro) { void ImplementationVisitor::Visit(Macro* macro) {
if (macro->IsExternal()) return; if (macro->IsExternal()) return;
// Do not generate code for inlined macros.
if (macro->ShouldBeInlined()) return;
VisitMacroCommon(macro); VisitMacroCommon(macro);
} }
void ImplementationVisitor::Visit(Method* method) { void ImplementationVisitor::Visit(Method* method) {
DCHECK(!method->IsExternal()); DCHECK(!method->IsExternal());
// Do not generate code for inlined methods, they have to be inlined in order
// to get reference semantics for the 'this' argument.
if (method->ShouldBeInlined()) return;
CurrentConstructorInfo::Scope current_constructor;
if (method->IsConstructor())
CurrentConstructorInfo::Get() = ConstructorInfo{0, false};
VisitMacroCommon(method); VisitMacroCommon(method);
} }
...@@ -1118,29 +1110,6 @@ const Type* ImplementationVisitor::Visit(ForOfLoopStatement* stmt) { ...@@ -1118,29 +1110,6 @@ const Type* ImplementationVisitor::Visit(ForOfLoopStatement* stmt) {
return TypeOracle::GetVoidType(); return TypeOracle::GetVoidType();
} }
VisitResult ImplementationVisitor::TemporaryUninitializedStruct(
const StructType* struct_type, const std::string& reason) {
StackRange range = assembler().TopRange(0);
for (const Field& f : struct_type->fields()) {
if (const StructType* struct_type =
StructType::DynamicCast(f.name_and_type.type)) {
range.Extend(
TemporaryUninitializedStruct(struct_type, reason).stack_range());
} else {
std::string descriptor = "unitialized field '" + f.name_and_type.name +
"' declared at " + PositionAsString(f.pos) +
" (" + reason + ")";
TypeVector lowered_types = LowerType(f.name_and_type.type);
for (const Type* type : lowered_types) {
assembler().Emit(PushUninitializedInstruction{
TypeOracle::GetTopType(descriptor, type)});
}
range.Extend(assembler().TopRange(lowered_types.size()));
}
}
return VisitResult(struct_type, range);
}
VisitResult ImplementationVisitor::Visit(TryLabelExpression* expr) { VisitResult ImplementationVisitor::Visit(TryLabelExpression* expr) {
size_t parameter_count = expr->label_block->parameters.names.size(); size_t parameter_count = expr->label_block->parameters.names.size();
std::vector<VisitResult> parameters; std::vector<VisitResult> parameters;
...@@ -1227,70 +1196,23 @@ VisitResult ImplementationVisitor::Visit(NewExpression* expr) { ...@@ -1227,70 +1196,23 @@ VisitResult ImplementationVisitor::Visit(NewExpression* expr) {
ReportError("type for new expression must be a class, \"", *type, ReportError("type for new expression must be a class, \"", *type,
"\" is not"); "\" is not");
} }
// 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 unitialized struct and pass it to the
// matching class constructor with the arguments that were passed to new{}
StructType* class_this_struct = class_type->struct_type();
VisitResult unitialized_struct = TemporaryUninitializedStruct(
class_this_struct,
"it's not set in the constructor for class " + class_type->name());
Arguments constructor_arguments;
for (auto p : expr->parameters) {
constructor_arguments.parameters.push_back(Visit(p));
}
LocationReference unitialized_struct_ref =
LocationReference::VariableAccess(unitialized_struct);
Callable* callable =
LookupConstructor(unitialized_struct_ref, constructor_arguments, {});
GenerateCall(callable, unitialized_struct_ref, constructor_arguments,
{class_type}, false);
VisitResult new_struct_result = unitialized_struct;
// Output the code to generate an unitialized object of the class size in the
// GC heap.
Arguments allocate_arguments; Arguments allocate_arguments;
allocate_arguments.parameters.push_back(VisitResult( allocate_arguments.parameters.push_back(VisitResult(
TypeOracle::GetConstInt31Type(), std::to_string(class_type->size()))); TypeOracle::GetConstInt31Type(), std::to_string(class_type->size())));
VisitResult allocate_result = VisitResult allocate_result =
GenerateCall("%Allocate", allocate_arguments, {class_type}, false); GenerateCall("%Allocate", allocate_arguments, {class_type}, false);
DCHECK(allocate_result.IsOnStack()); Arguments constructor_arguments;
for (auto p : expr->parameters) {
// Fill in the fields of the newly allocated class by copying the values constructor_arguments.parameters.push_back(Visit(p));
// from the struct that was built by the constructor. So that the generaeted
// code is a bit more readable, assign the values from the first class
// member to the last, in order. To do this, first build a list of fields
// to assign to in reverse order by visiting the class heirarchy.
std::vector<std::pair<const Field*, VisitResult>> store_pairs;
const ClassType* current_class = class_type;
while (current_class != nullptr) {
auto& fields = current_class->fields();
for (auto i = fields.rbegin(); i != fields.rend(); ++i) {
store_pairs.push_back(std::make_pair(
&*i, ProjectStructField(new_struct_result, i->name_and_type.name)));
}
current_class = current_class->GetSuperClass();
if (current_class) {
new_struct_result = ProjectStructField(new_struct_result,
kConstructorStructSuperFieldName);
}
}
// Now that the reversed list of fields and the assignment VisitResults are
// available, emit the copies in reverse order of the reversed list to
// produce the class field assignments in the expected order.
for (auto i = store_pairs.rbegin(); i != store_pairs.rend(); ++i) {
assembler().Emit(
PeekInstruction(allocate_result.stack_range().begin(), class_type));
assembler().Emit(PeekInstruction(i->second.stack_range().begin(),
i->first->name_and_type.type));
assembler().Emit(
StoreObjectFieldInstruction(class_type, i->first->name_and_type.name));
} }
Callable* callable =
return stack_scope.Yield(allocate_result); LookupCall({{}, kConstructMethodName}, class_type->Constructors(),
constructor_arguments, {});
return stack_scope.Yield(
GenerateCall(callable,
LocationReference::Temporary(allocate_result,
"unitialized object from new"),
constructor_arguments, {class_type}, false));
} }
const Type* ImplementationVisitor::Visit(BreakStatement* stmt) { const Type* ImplementationVisitor::Visit(BreakStatement* stmt) {
...@@ -1435,15 +1357,17 @@ void ImplementationVisitor::GenerateFunctionDeclaration( ...@@ -1435,15 +1357,17 @@ void ImplementationVisitor::GenerateFunctionDeclaration(
namespace { namespace {
void FailCallableLookup(const std::string& reason, const QualifiedName& name, void FailCallableLookup(const std::string& reason, const QualifiedName& name,
const TypeVector& parameter_types, const Arguments& arguments,
const std::vector<Binding<LocalLabel>*>& labels,
const std::vector<Signature>& candidates) { const std::vector<Signature>& candidates) {
std::stringstream stream; std::stringstream stream;
stream << "\n" << reason << ": \n " << name << "(" << parameter_types << ")"; stream << "\n"
if (labels.size() != 0) { << reason << ": \n " << name << "("
<< arguments.parameters.GetTypeVector() << ")";
if (arguments.labels.size() != 0) {
stream << " labels "; stream << " labels ";
for (size_t i = 0; i < labels.size(); ++i) { for (size_t i = 0; i < arguments.labels.size(); ++i) {
stream << labels[i]->name() << "(" << labels[i]->parameter_types << ")"; stream << arguments.labels[i]->name() << "("
<< arguments.labels[i]->parameter_types << ")";
} }
} }
stream << "\ncandidates are:"; stream << "\ncandidates are:";
...@@ -1492,12 +1416,11 @@ Block* ImplementationVisitor::LookupSimpleLabel(const std::string& name) { ...@@ -1492,12 +1416,11 @@ Block* ImplementationVisitor::LookupSimpleLabel(const std::string& name) {
} }
template <class Container> template <class Container>
Callable* ImplementationVisitor::LookupCallable( Callable* ImplementationVisitor::LookupCall(
const QualifiedName& name, const Container& declaration_container, const QualifiedName& name, const Container& declaration_container,
const TypeVector& parameter_types, const Arguments& arguments, const TypeVector& specialization_types) {
const std::vector<Binding<LocalLabel>*>& labels,
const TypeVector& specialization_types) {
Callable* result = nullptr; Callable* result = nullptr;
TypeVector parameter_types(arguments.parameters.GetTypeVector());
std::vector<Declarable*> overloads; std::vector<Declarable*> overloads;
std::vector<Signature> overload_signatures; std::vector<Signature> overload_signatures;
...@@ -1520,7 +1443,7 @@ Callable* ImplementationVisitor::LookupCallable( ...@@ -1520,7 +1443,7 @@ Callable* ImplementationVisitor::LookupCallable(
std::vector<size_t> candidates; std::vector<size_t> candidates;
for (size_t i = 0; i < overloads.size(); ++i) { for (size_t i = 0; i < overloads.size(); ++i) {
const Signature& signature = overload_signatures[i]; const Signature& signature = overload_signatures[i];
bool try_bool_context = labels.size() == 0 && bool try_bool_context = arguments.labels.size() == 0 &&
signature.return_type == TypeOracle::GetNeverType(); signature.return_type == TypeOracle::GetNeverType();
base::Optional<Binding<LocalLabel>*> true_label; base::Optional<Binding<LocalLabel>*> true_label;
base::Optional<Binding<LocalLabel>*> false_label; base::Optional<Binding<LocalLabel>*> false_label;
...@@ -1528,7 +1451,7 @@ Callable* ImplementationVisitor::LookupCallable( ...@@ -1528,7 +1451,7 @@ Callable* ImplementationVisitor::LookupCallable(
true_label = TryLookupLabel(kTrueLabelName); true_label = TryLookupLabel(kTrueLabelName);
false_label = TryLookupLabel(kFalseLabelName); false_label = TryLookupLabel(kFalseLabelName);
} }
if (IsCompatibleSignature(signature, parameter_types, labels) || if (IsCompatibleSignature(signature, parameter_types, arguments.labels) ||
(true_label && false_label && (true_label && false_label &&
IsCompatibleSignature(signature, parameter_types, IsCompatibleSignature(signature, parameter_types,
{*true_label, *false_label}))) { {*true_label, *false_label}))) {
...@@ -1542,7 +1465,7 @@ Callable* ImplementationVisitor::LookupCallable( ...@@ -1542,7 +1465,7 @@ Callable* ImplementationVisitor::LookupCallable(
ReportError(stream.str()); ReportError(stream.str());
} else if (candidates.empty()) { } else if (candidates.empty()) {
FailCallableLookup("cannot find suitable callable with name", name, FailCallableLookup("cannot find suitable callable with name", name,
parameter_types, labels, overload_signatures); arguments, overload_signatures);
} }
auto is_better_candidate = [&](size_t a, size_t b) { auto is_better_candidate = [&](size_t a, size_t b) {
...@@ -1562,7 +1485,7 @@ Callable* ImplementationVisitor::LookupCallable( ...@@ -1562,7 +1485,7 @@ Callable* ImplementationVisitor::LookupCallable(
for (size_t i : candidates) { for (size_t i : candidates) {
candidate_signatures.push_back(overload_signatures[i]); candidate_signatures.push_back(overload_signatures[i]);
} }
FailCallableLookup("ambiguous callable ", name, parameter_types, labels, FailCallableLookup("ambiguous callable", name, arguments,
candidate_signatures); candidate_signatures);
} }
} }
...@@ -1590,27 +1513,6 @@ Callable* ImplementationVisitor::LookupCallable( ...@@ -1590,27 +1513,6 @@ Callable* ImplementationVisitor::LookupCallable(
return result; return result;
} }
template <class Container>
Callable* ImplementationVisitor::LookupCallable(
const QualifiedName& name, const Container& declaration_container,
const Arguments& arguments, const TypeVector& specialization_types) {
return LookupCallable(name, declaration_container,
arguments.parameters.GetTypeVector(), arguments.labels,
specialization_types);
}
Method* ImplementationVisitor::LookupMethod(
const std::string& name, LocationReference this_reference,
const Arguments& arguments, const TypeVector& specialization_types) {
TypeVector types(arguments.parameters.GetTypeVector());
types.insert(types.begin(), this_reference.GetVisitResult().type());
return Method::cast(
LookupCallable({{}, name},
AggregateType::cast(this_reference.GetVisitResult().type())
->Methods(name),
types, arguments.labels, specialization_types));
}
const Type* ImplementationVisitor::GetCommonType(const Type* left, const Type* ImplementationVisitor::GetCommonType(const Type* left,
const Type* right) { const Type* right) {
const Type* common_type; const Type* common_type;
...@@ -1643,19 +1545,31 @@ VisitResult ImplementationVisitor::Visit(StructExpression* decl) { ...@@ -1643,19 +1545,31 @@ VisitResult ImplementationVisitor::Visit(StructExpression* decl) {
ReportError(s.str()); ReportError(s.str());
} }
const StructType* struct_type = StructType::cast(raw_type); const StructType* struct_type = StructType::cast(raw_type);
// Push unitialized 'this' if (struct_type->fields().size() != decl->expressions.size()) {
VisitResult uninitialized_struct = TemporaryUninitializedStruct( std::stringstream s;
struct_type, s << "initializer count mismatch for struct " << decl->name << " (expected "
"it's not set in the constructor for struct " + struct_type->name()); << struct_type->fields().size() << ", found " << decl->expressions.size()
<< ")";
ReportError(s.str());
}
// Push uninitialized 'this'
TypeVector lowered_types = LowerType(struct_type);
for (const Type* type : lowered_types) {
assembler().Emit(PushUninitializedInstruction{TypeOracle::GetTopType(
"unitialized struct field at " + PositionAsString(decl->pos), type)});
}
VisitResult uninitialized_struct =
VisitResult(struct_type, assembler().TopRange(lowered_types.size()));
Arguments constructor_arguments; Arguments constructor_arguments;
for (auto p : decl->expressions) { for (auto p : decl->expressions) {
constructor_arguments.parameters.push_back(Visit(p)); constructor_arguments.parameters.push_back(Visit(p));
} }
LocationReference this_ref = Callable* callable =
LocationReference::VariableAccess(uninitialized_struct); LookupCall({{}, kConstructMethodName}, struct_type->Constructors(),
Callable* callable = LookupConstructor(this_ref, constructor_arguments, {}); constructor_arguments, {});
GenerateCall(callable, this_ref, constructor_arguments, {}, false); return stack_scope.Yield(GenerateCall(
return stack_scope.Yield(uninitialized_struct); callable, LocationReference::VariableAccess(uninitialized_struct),
constructor_arguments, {}, false));
} }
LocationReference ImplementationVisitor::GetLocationReference( LocationReference ImplementationVisitor::GetLocationReference(
...@@ -1701,6 +1615,11 @@ LocationReference ImplementationVisitor::GetLocationReference( ...@@ -1701,6 +1615,11 @@ LocationReference ImplementationVisitor::GetLocationReference(
LocationReference ImplementationVisitor::GetLocationReference( LocationReference ImplementationVisitor::GetLocationReference(
IdentifierExpression* expr) { IdentifierExpression* expr) {
if (expr->namespace_qualification.empty()) { if (expr->namespace_qualification.empty()) {
if (expr->IsThis()) {
if (CurrentConstructorInfo::Get()) {
CurrentConstructorInfo::Get()->accessed_this = true;
}
}
if (base::Optional<Binding<LocalValue>*> value = if (base::Optional<Binding<LocalValue>*> value =
TryLookupLocalValue(expr->name)) { TryLookupLocalValue(expr->name)) {
if (expr->generic_arguments.size() != 0) { if (expr->generic_arguments.size() != 0) {
...@@ -1878,21 +1797,6 @@ VisitResult ImplementationVisitor::GenerateCall( ...@@ -1878,21 +1797,6 @@ VisitResult ImplementationVisitor::GenerateCall(
std::vector<std::string> constexpr_arguments; std::vector<std::string> constexpr_arguments;
size_t current = 0; size_t current = 0;
for (; current < callable->signature().implicit_count; ++current) {
std::string implicit_name = callable->signature().parameter_names[current];
base::Optional<Binding<LocalValue>*> val =
TryLookupLocalValue(implicit_name);
if (!val) {
ReportError("implicit parameter '", implicit_name,
"' required for call to '", callable->ReadableName(),
"' is not defined");
}
AddCallParameter(callable, (*val)->value,
callable->signature().parameter_types.types[current],
&converted_arguments, &argument_range,
&constexpr_arguments);
}
if (this_reference) { if (this_reference) {
DCHECK(callable->IsMethod()); DCHECK(callable->IsMethod());
Method* method = Method::cast(callable); Method* method = Method::cast(callable);
...@@ -1902,8 +1806,7 @@ VisitResult ImplementationVisitor::GenerateCall( ...@@ -1902,8 +1806,7 @@ VisitResult ImplementationVisitor::GenerateCall(
if (method->ShouldBeInlined()) { if (method->ShouldBeInlined()) {
if (!this_value.type()->IsSubtypeOf(method->aggregate_type())) { if (!this_value.type()->IsSubtypeOf(method->aggregate_type())) {
ReportError("this parameter must be a subtype of ", ReportError("this parameter must be a subtype of ",
*method->aggregate_type(), " but it is of type ", *method->aggregate_type());
this_value.type());
} }
} else { } else {
AddCallParameter(callable, this_value, method->aggregate_type(), AddCallParameter(callable, this_value, method->aggregate_type(),
...@@ -1913,6 +1816,21 @@ VisitResult ImplementationVisitor::GenerateCall( ...@@ -1913,6 +1816,21 @@ VisitResult ImplementationVisitor::GenerateCall(
++current; ++current;
} }
for (; current < callable->signature().implicit_count; ++current) {
std::string implicit_name = callable->signature().parameter_names[current];
base::Optional<Binding<LocalValue>*> val =
TryLookupLocalValue(implicit_name);
if (!val) {
ReportError("implicit parameter '", implicit_name,
"' required for call to '", callable->ReadableName(),
"' is not defined");
}
AddCallParameter(callable, (*val)->value,
callable->signature().parameter_types.types[current],
&converted_arguments, &argument_range,
&constexpr_arguments);
}
for (auto arg : arguments.parameters) { for (auto arg : arguments.parameters) {
const Type* to_type = (current >= callable->signature().types().size()) const Type* to_type = (current >= callable->signature().types().size())
? TypeOracle::GetObjectType() ? TypeOracle::GetObjectType()
...@@ -2098,8 +2016,8 @@ VisitResult ImplementationVisitor::GenerateCall( ...@@ -2098,8 +2016,8 @@ VisitResult ImplementationVisitor::GenerateCall(
const QualifiedName& callable_name, Arguments arguments, const QualifiedName& callable_name, Arguments arguments,
const TypeVector& specialization_types, bool is_tailcall) { const TypeVector& specialization_types, bool is_tailcall) {
Callable* callable = Callable* callable =
LookupCallable(callable_name, Declarations::Lookup(callable_name), LookupCall(callable_name, Declarations::Lookup(callable_name), arguments,
arguments, specialization_types); specialization_types);
return GenerateCall(callable, base::nullopt, arguments, specialization_types, return GenerateCall(callable, base::nullopt, arguments, specialization_types,
is_tailcall); is_tailcall);
} }
...@@ -2132,35 +2050,17 @@ VisitResult ImplementationVisitor::Visit(CallMethodExpression* expr) { ...@@ -2132,35 +2050,17 @@ VisitResult ImplementationVisitor::Visit(CallMethodExpression* expr) {
std::string method_name = expr->method->name; std::string method_name = expr->method->name;
TypeVector specialization_types = TypeVector specialization_types =
GetTypeVector(expr->method->generic_arguments); GetTypeVector(expr->method->generic_arguments);
LocationReference target = GetLocationReference(expr->target);
if (!target.IsVariableAccess()) {
VisitResult result = GenerateFetchFromLocation(target);
target = LocationReference::Temporary(result, "method target result");
}
const AggregateType* target_type =
AggregateType::DynamicCast(target.GetVisitResult().type());
if (!target_type) {
ReportError("target of method call not a struct or class type");
}
if (method_name == kConstructMethodName || method_name == kSuperMethodName) { if (method_name == kConstructMethodName || method_name == kSuperMethodName) {
if (CurrentConstructorInfo::Get()) { if (CurrentConstructorInfo::Get()) {
ConstructorInfo& info = *CurrentConstructorInfo::Get(); ConstructorInfo& info = *CurrentConstructorInfo::Get();
if (method_name == kSuperMethodName) { if (method_name == kSuperMethodName) {
if (info.accessed_this) {
ReportError("cannot call super after accessing \"this\"");
}
if (info.super_calls != 0) { if (info.super_calls != 0) {
ReportError("\"super\" can only be called once from a constructor"); ReportError("\"super\" can only be called once from a constructor");
} }
++info.super_calls; ++info.super_calls;
CHECK(target_type->IsStructType());
base::Optional<const ClassType*> derived_from =
StructType::cast(target_type)->GetDerivedFrom();
if (!derived_from) {
ReportError("\"super\" can only be called from class constructors");
}
if ((*derived_from)->GetSuperClass() == nullptr) {
ReportError(
"\"super\" can only be called in constructors for derived "
"classes");
}
} else { } else {
ReportError("cannot call a constructor from a constructor"); ReportError("cannot call a constructor from a constructor");
} }
...@@ -2169,26 +2069,41 @@ VisitResult ImplementationVisitor::Visit(CallMethodExpression* expr) { ...@@ -2169,26 +2069,41 @@ VisitResult ImplementationVisitor::Visit(CallMethodExpression* expr) {
"cannot call a constructor or \"super\" from a non-constructor"); "cannot call a constructor or \"super\" from a non-constructor");
} }
} }
for (Expression* arg : expr->arguments) { const AggregateType* target_type;
arguments.parameters.push_back(Visit(arg)); LocationReference target = GetLocationReference(expr->target);
if (target.IsVariableAccess()) {
target_type = AggregateType::DynamicCast(target.variable().type());
} else {
VisitResult result = GenerateFetchFromLocation(target);
target = LocationReference::Temporary(result, "method target result");
target_type = AggregateType::DynamicCast(result.type());
}
if (!target_type) {
ReportError("target of method call not a struct or class type");
} }
for (Expression* arg : expr->arguments)
arguments.parameters.push_back(Visit(arg));
arguments.labels = LabelsFromIdentifiers(expr->labels); arguments.labels = LabelsFromIdentifiers(expr->labels);
TypeVector argument_types = arguments.parameters.GetTypeVector(); TypeVector argument_types = arguments.parameters.GetTypeVector();
DCHECK_EQ(expr->method->namespace_qualification.size(), 0); DCHECK_EQ(expr->method->namespace_qualification.size(), 0);
QualifiedName qualified_name = QualifiedName(method_name); QualifiedName qualified_name = QualifiedName(method_name);
Callable* callable = nullptr; Callable* callable = nullptr;
if (method_name == kConstructMethodName) { if (method_name == kConstructMethodName) {
callable = LookupConstructor(target, arguments, {}); callable =
LookupCall(qualified_name, target_type->Constructors(), arguments, {});
} else if (method_name == kSuperMethodName) { } else if (method_name == kSuperMethodName) {
LocationReference super_this = if (!target_type->IsClassType()) {
LocationReference::VariableAccess(ProjectStructField( ReportError("cannot call super in struct constructor");
target.GetVisitResult(), kConstructorStructSuperFieldName)); }
callable = LookupConstructor(super_this, arguments, {}); target_type = ClassType::cast(target_type)->GetSuperClass();
VisitResult super_result = if (!target_type) {
GenerateCall(callable, super_this, arguments, {}, false); ReportError("cannot call \"super\" on a class with no superclass");
return scope.Yield(super_result); }
callable = LookupCall(QualifiedName(kConstructMethodName),
target_type->Constructors(), arguments, {});
} else { } else {
callable = LookupMethod(method_name, target, arguments, {}); callable = LookupCall(qualified_name, target_type->Methods(method_name),
arguments, {});
} }
return scope.Yield(GenerateCall(callable, target, arguments, {}, false)); return scope.Yield(GenerateCall(callable, target, arguments, {}, false));
} }
......
...@@ -212,8 +212,6 @@ class ImplementationVisitor : public FileVisitor { ...@@ -212,8 +212,6 @@ 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);
...@@ -292,6 +290,7 @@ class ImplementationVisitor : public FileVisitor { ...@@ -292,6 +290,7 @@ 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,
...@@ -397,29 +396,11 @@ class ImplementationVisitor : public FileVisitor { ...@@ -397,29 +396,11 @@ 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* LookupCallable(const QualifiedName& name, Callable* LookupCall(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,10 +42,8 @@ enum class ParseResultHolderBase::TypeId { ...@@ -42,10 +42,8 @@ enum class ParseResultHolderBase::TypeId {
kOptionalLabelBlockPtr, kOptionalLabelBlockPtr,
kNameAndTypeExpression, kNameAndTypeExpression,
kClassFieldExpression, kClassFieldExpression,
kStructFieldExpression,
kStdVectorOfNameAndTypeExpression, kStdVectorOfNameAndTypeExpression,
kStdVectorOfClassFieldExpression, kStdVectorOfClassFieldExpression,
kStdVectorOfStructFieldExpression,
kIncrementDecrementOperator, kIncrementDecrementOperator,
kOptionalStdString, kOptionalStdString,
kStdVectorOfStatementPtr, kStdVectorOfStatementPtr,
...@@ -109,10 +107,6 @@ V8_EXPORT_PRIVATE const ParseResultTypeId ...@@ -109,10 +107,6 @@ 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;
...@@ -121,10 +115,6 @@ V8_EXPORT_PRIVATE const ParseResultTypeId ...@@ -121,10 +115,6 @@ 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;
...@@ -591,7 +581,7 @@ base::Optional<ParseResult> MakeClassDeclaration( ...@@ -591,7 +581,7 @@ base::Optional<ParseResult> MakeClassDeclaration(
if (!IsValidTypeName(name)) { if (!IsValidTypeName(name)) {
NamingConventionError("Type", name, "UpperCamelCase"); NamingConventionError("Type", name, "UpperCamelCase");
} }
auto extends = child_results->NextAs<std::string>(); auto extends = child_results->NextAs<base::Optional<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>>();
...@@ -633,7 +623,7 @@ base::Optional<ParseResult> MakeStructDeclaration( ...@@ -633,7 +623,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<StructFieldExpression>>(); auto fields = child_results->NextAs<std::vector<NameAndTypeExpression>>();
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};
...@@ -1129,13 +1119,6 @@ base::Optional<ParseResult> MakeClassField(ParseResultIterator* child_results) { ...@@ -1129,13 +1119,6 @@ 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>();
...@@ -1326,9 +1309,6 @@ struct TorqueGrammar : Grammar { ...@@ -1326,9 +1309,6 @@ 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("("),
...@@ -1609,7 +1589,7 @@ struct TorqueGrammar : Grammar { ...@@ -1609,7 +1589,7 @@ struct TorqueGrammar : Grammar {
&externalString, Token(";")}, &externalString, Token(";")},
MakeExternConstDeclaration), MakeExternConstDeclaration),
Rule({CheckIf(Token("transient")), Token("class"), &identifier, Rule({CheckIf(Token("transient")), Token("class"), &identifier,
Sequence({Token("extends"), &identifier}), Optional<std::string>(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),
...@@ -1617,7 +1597,8 @@ struct TorqueGrammar : Grammar { ...@@ -1617,7 +1597,8 @@ struct TorqueGrammar : Grammar {
MakeClassDeclaration), MakeClassDeclaration),
Rule({Token("struct"), &identifier, Token("{"), Rule({Token("struct"), &identifier, Token("{"),
List<Declaration*>(&method), List<Declaration*>(&method),
List<StructFieldExpression>(&structField), Token("}")}, List<NameAndTypeExpression>(Sequence({&nameAndType, 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,10 +38,9 @@ class TypeOracle : public ContextualClass<TypeOracle> { ...@@ -38,10 +38,9 @@ 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,
StructType* this_struct, size_t size) { size_t size) {
ClassType* result = ClassType* result = new ClassType(parent, CurrentNamespace(), name,
new ClassType(parent, CurrentNamespace(), name, transient, generates, transient, generates, fields, size);
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,38 +184,6 @@ const Type* SubtractType(const Type* a, const Type* b) { ...@@ -184,38 +184,6 @@ 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;
...@@ -249,7 +217,7 @@ std::string StructType::GetGeneratedTypeName() const { ...@@ -249,7 +217,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),
[name](Macro* macro) { return macro->ReadableName() == name; }); [&](Macro* macro) { return macro->ReadableName() == name; });
return result; return result;
} }
...@@ -375,53 +343,19 @@ bool operator<(const Type& a, const Type& b) { ...@@ -375,53 +343,19 @@ bool operator<(const Type& a, const Type& b) {
return a.MangledName() < b.MangledName(); return a.MangledName() < b.MangledName();
} }
VisitResult ProjectStructField(const StructType* original_struct, VisitResult ProjectStructField(VisitResult structure,
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());
auto& fields = type->fields(); for (auto& field : 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,7 +12,6 @@ ...@@ -12,7 +12,6 @@
#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 {
...@@ -44,7 +43,6 @@ static const char* const CONST_FLOAT64_TYPE_STRING = "constexpr float64"; ...@@ -44,7 +43,6 @@ 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;
...@@ -152,7 +150,6 @@ struct NameAndType { ...@@ -152,7 +150,6 @@ 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,7 +406,8 @@ class AggregateType : public Type { ...@@ -409,7 +406,8 @@ 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_;
...@@ -424,13 +422,6 @@ class StructType final : public AggregateType { ...@@ -424,13 +422,6 @@ 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,
...@@ -438,8 +429,6 @@ class StructType final : public AggregateType { ...@@ -438,8 +429,6 @@ 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 {
...@@ -452,9 +441,7 @@ class ClassType final : public AggregateType { ...@@ -452,9 +441,7 @@ 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;
} }
...@@ -462,15 +449,12 @@ class ClassType final : public AggregateType { ...@@ -462,15 +449,12 @@ 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, StructType* this_struct, const std::vector<Field>& fields, size_t size)
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,8 +272,6 @@ constexpr int kTaggedSize = sizeof(void*); ...@@ -272,8 +272,6 @@ 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,36 +736,10 @@ namespace test { ...@@ -736,36 +736,10 @@ 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)() {
// Test default constructor let a: TestOuter = TestOuter{0, TestInner{0, 0}, 0};
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