[torque] add internal classes that map to FixedArray instances
Bug: v8:7793 Change-Id: Ifc2bf26e9d3bc13d4f2455d6d04ce5e2682626db Reviewed-on: https://chromium-review.googlesource.com/c/1454600 Reviewed-by: Daniel Clifford <danno@chromium.org> Commit-Queue: Tobias Tebbi <tebbi@chromium.org> Cr-Commit-Position: refs/heads/master@{#59404}
This commit is contained in:
parent
d09bea1b6f
commit
6c3c952d8d
@ -21,9 +21,7 @@ type Smi extends Tagged generates 'TNode<Smi>' constexpr 'Smi';
|
||||
// A Smi that is greater than or equal to 0. See TaggedIsPositiveSmi.
|
||||
type PositiveSmi extends Smi generates 'TNode<Smi>';
|
||||
|
||||
class HeapObject extends Tagged {
|
||||
map: Map;
|
||||
}
|
||||
extern class HeapObject extends Tagged { map: Map; }
|
||||
|
||||
type Object = Smi | HeapObject;
|
||||
type int32 generates 'TNode<Int32T>' constexpr 'int32_t';
|
||||
@ -69,25 +67,26 @@ type RootIndex generates 'TNode<Int32T>' constexpr 'RootIndex';
|
||||
|
||||
type Map extends HeapObject generates 'TNode<Map>';
|
||||
|
||||
// These intrinsics should never be called from Torque code. They're used
|
||||
// internally by the 'new' operator and only declared here because it's simpler
|
||||
// than building the definition from C++.
|
||||
intrinsic %GetAllocationBaseSize<Class: type>(map: Map): intptr;
|
||||
intrinsic %Allocate<Class: type>(size: intptr): Class;
|
||||
|
||||
type FixedArrayBase extends HeapObject generates 'TNode<FixedArrayBase>';
|
||||
type FixedArray extends FixedArrayBase generates 'TNode<FixedArray>';
|
||||
type FixedDoubleArray extends FixedArrayBase
|
||||
generates 'TNode<FixedDoubleArray>';
|
||||
|
||||
class JSReceiver extends HeapObject {
|
||||
// These intrinsics should never be called from Torque code. They're used
|
||||
// internally by the 'new' operator and only declared here because it's simpler
|
||||
// than building the definition from C++.
|
||||
intrinsic %GetAllocationBaseSize<Class: type>(map: Map): intptr;
|
||||
intrinsic %Allocate<Class: type>(size: intptr): Class;
|
||||
intrinsic %AllocateInternalClass<Class: type>(slotCount: constexpr intptr): Class;
|
||||
|
||||
extern class JSReceiver extends HeapObject {
|
||||
properties_or_hash: FixedArrayBase | Smi;
|
||||
}
|
||||
|
||||
type Constructor extends JSReceiver generates 'TNode<JSReceiver>';
|
||||
type JSProxy extends JSReceiver generates 'TNode<JSProxy>';
|
||||
|
||||
class JSObject extends JSReceiver {
|
||||
extern class JSObject extends JSReceiver {
|
||||
constructor(
|
||||
map: Map, properties: FixedArrayBase | Smi, elements: FixedArrayBase) {
|
||||
super(map, properties);
|
||||
@ -103,11 +102,9 @@ class JSObject extends JSReceiver {
|
||||
elements: FixedArrayBase;
|
||||
}
|
||||
|
||||
class JSArgumentsObjectWithLength extends JSObject {
|
||||
length: Object;
|
||||
}
|
||||
extern class JSArgumentsObjectWithLength extends JSObject { length: Object; }
|
||||
|
||||
class JSArray extends JSObject {
|
||||
extern class JSArray extends JSObject {
|
||||
constructor(implicit context: Context)() {
|
||||
super(
|
||||
GetFastPackedSmiElementsJSArrayMap(), kEmptyFixedArray,
|
||||
@ -143,7 +140,7 @@ type DebugInfo extends HeapObject;
|
||||
|
||||
type ScopeInfo extends Object generates 'TNode<ScopeInfo>';
|
||||
|
||||
class SharedFunctionInfo extends HeapObject {
|
||||
extern class SharedFunctionInfo extends HeapObject {
|
||||
weak function_data: Object;
|
||||
name_or_scope_info: String | NoSharedNameSentinel | ScopeInfo;
|
||||
outer_scope_info_or_feedback_metadata: HeapObject;
|
||||
@ -156,11 +153,11 @@ class SharedFunctionInfo extends HeapObject {
|
||||
flags: int32;
|
||||
}
|
||||
|
||||
class SharedFunctionInfoWithID extends SharedFunctionInfo {
|
||||
extern class SharedFunctionInfoWithID extends SharedFunctionInfo {
|
||||
unique_id: int32;
|
||||
}
|
||||
|
||||
class JSFunction extends JSObject {
|
||||
extern class JSFunction extends JSObject {
|
||||
shared_function_info: SharedFunctionInfo;
|
||||
context: Context;
|
||||
feedback_cell: Smi;
|
||||
@ -168,7 +165,7 @@ class JSFunction extends JSObject {
|
||||
weak prototype_or_initial_map: JSReceiver | Map;
|
||||
}
|
||||
|
||||
class JSBoundFunction extends JSObject {
|
||||
extern class JSBoundFunction extends JSObject {
|
||||
bound_target_function: JSReceiver;
|
||||
bound_this: Object;
|
||||
bound_arguments: FixedArray;
|
||||
@ -213,18 +210,18 @@ extern operator '[]=' macro StoreContextElement(
|
||||
extern operator '[]' macro LoadContextElement(Context, intptr): Object;
|
||||
extern operator '[]' macro LoadContextElement(Context, Smi): Object;
|
||||
|
||||
class JSArrayBuffer extends JSObject {
|
||||
extern class JSArrayBuffer extends JSObject {
|
||||
byte_length: uintptr;
|
||||
backing_store: RawPtr;
|
||||
}
|
||||
|
||||
class JSArrayBufferView extends JSObject {
|
||||
extern class JSArrayBufferView extends JSObject {
|
||||
buffer: JSArrayBuffer;
|
||||
byte_offset: uintptr;
|
||||
byte_length: uintptr;
|
||||
}
|
||||
|
||||
class JSTypedArray extends JSArrayBufferView {}
|
||||
extern class JSTypedArray extends JSArrayBufferView {}
|
||||
|
||||
type JSDataView extends JSArrayBufferView generates 'TNode<JSDataView>';
|
||||
|
||||
|
@ -1217,6 +1217,12 @@ TNode<HeapObject> CodeStubAssembler::Allocate(TNode<IntPtrT> size_in_bytes,
|
||||
AllocationFlags flags) {
|
||||
Comment("Allocate");
|
||||
bool const new_space = !(flags & kPretenured);
|
||||
if (!(flags & kAllowLargeObjectAllocation)) {
|
||||
intptr_t size_constant;
|
||||
if (ToIntPtrConstant(size_in_bytes, size_constant)) {
|
||||
CHECK_LE(size_constant, kMaxRegularHeapObjectSize);
|
||||
}
|
||||
}
|
||||
if (!(flags & kDoubleAlignment) && !(flags & kAllowLargeObjectAllocation)) {
|
||||
return OptimizedAllocate(size_in_bytes, new_space
|
||||
? PretenureFlag::NOT_TENURED
|
||||
|
@ -1535,6 +1535,11 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
|
||||
fixed_array_map);
|
||||
}
|
||||
|
||||
TNode<FixedArray> AllocateUninitializedFixedArray(intptr_t capacity) {
|
||||
return UncheckedCast<FixedArray>(AllocateFixedArray(
|
||||
PACKED_ELEMENTS, IntPtrConstant(capacity), AllocationFlag::kNone));
|
||||
}
|
||||
|
||||
TNode<FixedArray> AllocateZeroedFixedArray(TNode<IntPtrT> capacity) {
|
||||
TNode<FixedArray> result = UncheckedCast<FixedArray>(
|
||||
AllocateFixedArray(PACKED_ELEMENTS, capacity,
|
||||
|
@ -899,20 +899,23 @@ struct StructDeclaration : Declaration {
|
||||
|
||||
struct ClassDeclaration : Declaration {
|
||||
DEFINE_AST_NODE_LEAF_BOILERPLATE(ClassDeclaration)
|
||||
ClassDeclaration(SourcePosition pos, std::string name, bool transient,
|
||||
std::string super, base::Optional<std::string> generates,
|
||||
ClassDeclaration(SourcePosition pos, std::string name, bool is_extern,
|
||||
bool transient, base::Optional<std::string> super,
|
||||
base::Optional<std::string> generates,
|
||||
std::vector<Declaration*> methods,
|
||||
std::vector<ClassFieldExpression> fields)
|
||||
: Declaration(kKind, pos),
|
||||
name(std::move(name)),
|
||||
is_extern(is_extern),
|
||||
transient(transient),
|
||||
super(std::move(super)),
|
||||
generates(std::move(generates)),
|
||||
methods(std::move(methods)),
|
||||
fields(std::move(fields)) {}
|
||||
std::string name;
|
||||
bool is_extern;
|
||||
bool transient;
|
||||
std::string super;
|
||||
base::Optional<std::string> super;
|
||||
base::Optional<std::string> generates;
|
||||
std::vector<Declaration*> methods;
|
||||
std::vector<ClassFieldExpression> fields;
|
||||
|
@ -244,6 +244,9 @@ void CSAGenerator::EmitInstruction(const CallIntrinsicInstruction& instruction,
|
||||
} else if (instruction.intrinsic->ExternalName() == "%Allocate") {
|
||||
out_ << "ca_.UncheckedCast<" << return_type->GetGeneratedTNodeTypeName()
|
||||
<< ">(CodeStubAssembler(state_).Allocate";
|
||||
} else if (instruction.intrinsic->ExternalName() ==
|
||||
"%AllocateInternalClass") {
|
||||
out_ << "CodeStubAssembler(state_).AllocateUninitializedFixedArray";
|
||||
} else {
|
||||
ReportError("no built in intrinsic with name " +
|
||||
instruction.intrinsic->ExternalName());
|
||||
@ -690,14 +693,21 @@ void CSAGenerator::EmitInstruction(
|
||||
std::tie(field_size, size_string, machine_type) =
|
||||
field.GetFieldSizeInformation();
|
||||
|
||||
out_ << field.name_and_type.type->GetGeneratedTypeName() << " " << result_name
|
||||
<< " = "
|
||||
<< "ca_.UncheckedCast<"
|
||||
<< field.name_and_type.type->GetGeneratedTNodeTypeName()
|
||||
<< ">(CodeStubAssembler(state_).LoadObjectField("
|
||||
<< stack->Top() + ", " + field.aggregate->GetGeneratedTNodeTypeName() +
|
||||
"::k" + CamelifyString(field.name_and_type.name) + "Offset, "
|
||||
<< machine_type + "));\n";
|
||||
if (instruction.class_type->IsExtern()) {
|
||||
out_ << field.name_and_type.type->GetGeneratedTypeName() << " "
|
||||
<< result_name << " = ca_.UncheckedCast<"
|
||||
<< field.name_and_type.type->GetGeneratedTNodeTypeName()
|
||||
<< ">(CodeStubAssembler(state_).LoadObjectField(" << stack->Top()
|
||||
<< ", " << field.aggregate->GetGeneratedTNodeTypeName() << "::k"
|
||||
<< CamelifyString(field.name_and_type.name) << "Offset, "
|
||||
<< machine_type + "));\n";
|
||||
} else {
|
||||
out_ << field.name_and_type.type->GetGeneratedTypeName() << " "
|
||||
<< result_name << " = ca_.UncheckedCast<"
|
||||
<< field.name_and_type.type->GetGeneratedTNodeTypeName()
|
||||
<< ">(CodeStubAssembler(state_).LoadFixedArrayElement(" << stack->Top()
|
||||
<< ", " << (field.offset / kTaggedSize) << "));\n";
|
||||
}
|
||||
stack->Poke(stack->AboveTop() - 1, result_name);
|
||||
}
|
||||
|
||||
@ -708,26 +718,31 @@ void CSAGenerator::EmitInstruction(
|
||||
stack->Push(value);
|
||||
const Field& field =
|
||||
instruction.class_type->LookupField(instruction.field_name);
|
||||
if (field.name_and_type.type->IsSubtypeOf(TypeOracle::GetTaggedType())) {
|
||||
if (field.offset == 0) {
|
||||
out_ << " CodeStubAssembler(state_).StoreMap(" + object + ", " +
|
||||
value + ");\n";
|
||||
if (instruction.class_type->IsExtern()) {
|
||||
if (field.name_and_type.type->IsSubtypeOf(TypeOracle::GetTaggedType())) {
|
||||
if (field.offset == 0) {
|
||||
out_ << " CodeStubAssembler(state_).StoreMap(" << object << ", "
|
||||
<< value << ");\n";
|
||||
} else {
|
||||
out_ << " CodeStubAssembler(state_).StoreObjectField(" << object
|
||||
<< ", " << field.offset << ", " << value << ");\n";
|
||||
}
|
||||
} else {
|
||||
out_ << " CodeStubAssembler(state_).StoreObjectField(" + object +
|
||||
", " + std::to_string(field.offset) + ", " + value + ");\n";
|
||||
size_t field_size;
|
||||
std::string size_string;
|
||||
std::string machine_type;
|
||||
std::tie(field_size, size_string, machine_type) =
|
||||
field.GetFieldSizeInformation();
|
||||
if (field.offset == 0) {
|
||||
ReportError("the first field in a class object must be a map");
|
||||
}
|
||||
out_ << " CodeStubAssembler(state_).StoreObjectFieldNoWriteBarrier("
|
||||
<< object << ", " << field.offset << ", " << value << ", "
|
||||
<< machine_type << ".representation());\n";
|
||||
}
|
||||
} else {
|
||||
size_t field_size;
|
||||
std::string size_string;
|
||||
std::string machine_type;
|
||||
std::tie(field_size, size_string, machine_type) =
|
||||
field.GetFieldSizeInformation();
|
||||
if (field.offset == 0) {
|
||||
ReportError("the first field in a class object must be a map");
|
||||
}
|
||||
out_ << " CodeStubAssembler(state_).StoreObjectFieldNoWriteBarrier("
|
||||
<< object << ", " << std::to_string(field.offset) + ", " << value
|
||||
<< ", " << machine_type << ".representation());\n";
|
||||
out_ << " CodeStubAssembler(state_).StoreFixedArrayElement(" << object
|
||||
<< ", " << (field.offset / kTaggedSize) << ", " << value << ");\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -348,30 +348,47 @@ void DeclarationVisitor::Visit(StructDeclaration* decl) {
|
||||
}
|
||||
|
||||
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.
|
||||
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");
|
||||
ClassType* new_class;
|
||||
if (decl->is_extern) {
|
||||
if (!decl->super) {
|
||||
ReportError("Extern class must extend another type.");
|
||||
}
|
||||
}
|
||||
|
||||
// The generates clause must create a TNode<>
|
||||
std::string generates = decl->name;
|
||||
if (decl->generates) {
|
||||
if (generates.length() < 7 || generates.substr(0, 6) != "TNode<" ||
|
||||
generates.substr(generates.length() - 1, 1) != ">") {
|
||||
ReportError("generated type \"", generates,
|
||||
"\" should be of the form \"TNode<...>\"");
|
||||
// Compute the offset of the class' first member. If the class extends
|
||||
// another class, it's the size of the extended class, otherwise zero.
|
||||
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");
|
||||
}
|
||||
}
|
||||
generates = generates.substr(6, generates.length() - 7);
|
||||
}
|
||||
|
||||
auto new_class = Declarations::DeclareClass(super_type, decl->name,
|
||||
decl->transient, generates);
|
||||
// The generates clause must create a TNode<>
|
||||
std::string generates = decl->name;
|
||||
if (decl->generates) {
|
||||
if (generates.length() < 7 || generates.substr(0, 6) != "TNode<" ||
|
||||
generates.substr(generates.length() - 1, 1) != ">") {
|
||||
ReportError("generated type \"", generates,
|
||||
"\" should be of the form \"TNode<...>\"");
|
||||
}
|
||||
generates = generates.substr(6, generates.length() - 7);
|
||||
}
|
||||
|
||||
new_class = Declarations::DeclareClass(
|
||||
super_type, decl->name, decl->is_extern, decl->transient, generates);
|
||||
} else {
|
||||
if (decl->super) {
|
||||
ReportError("Only extern classes can inherit.");
|
||||
}
|
||||
if (decl->generates) {
|
||||
ReportError("Only extern classes can specify a generated type.");
|
||||
}
|
||||
new_class = Declarations::DeclareClass(TypeOracle::GetTaggedType(),
|
||||
decl->name, decl->is_extern,
|
||||
decl->transient, "FixedArray");
|
||||
}
|
||||
GlobalContext::RegisterClass(decl->name, new_class);
|
||||
class_declarations_.push_back(
|
||||
std::make_tuple(CurrentScope::Get(), decl, new_class));
|
||||
@ -534,6 +551,14 @@ void DeclarationVisitor::FinalizeClassFieldsAndMethods(
|
||||
field_expression.name_and_type.type->pos);
|
||||
const Type* field_type =
|
||||
Declarations::GetType(field_expression.name_and_type.type);
|
||||
if (!class_declaration->is_extern) {
|
||||
if (!field_type->IsSubtypeOf(TypeOracle::GetTaggedType())) {
|
||||
ReportError("Non-extern classes do not support untagged fields.");
|
||||
}
|
||||
if (field_expression.weak) {
|
||||
ReportError("Non-extern classes do not support weak fields.");
|
||||
}
|
||||
}
|
||||
const Field& field = class_type->RegisterField(
|
||||
{field_expression.name_and_type.type->pos,
|
||||
class_type,
|
||||
|
@ -174,10 +174,11 @@ StructType* Declarations::DeclareStruct(const std::string& name) {
|
||||
}
|
||||
|
||||
ClassType* Declarations::DeclareClass(const Type* super_type,
|
||||
const std::string& name, bool transient,
|
||||
const std::string& name, bool is_extern,
|
||||
bool transient,
|
||||
const std::string& generates) {
|
||||
ClassType* new_type =
|
||||
TypeOracle::GetClassType(super_type, name, transient, generates);
|
||||
ClassType* new_type = TypeOracle::GetClassType(super_type, name, is_extern,
|
||||
transient, generates);
|
||||
DeclareType(name, new_type, false);
|
||||
return new_type;
|
||||
}
|
||||
|
@ -84,7 +84,8 @@ class Declarations {
|
||||
static StructType* DeclareStruct(const std::string& name);
|
||||
|
||||
static ClassType* DeclareClass(const Type* super, const std::string& name,
|
||||
bool transient, const std::string& generates);
|
||||
bool is_extern, bool transient,
|
||||
const std::string& generates);
|
||||
|
||||
static Macro* CreateMacro(std::string external_name,
|
||||
std::string readable_name,
|
||||
|
@ -150,7 +150,7 @@ void ImplementationVisitor::Visit(NamespaceConstant* decl) {
|
||||
void ImplementationVisitor::Visit(TypeAlias* alias) {
|
||||
if (alias->IsRedeclaration()) return;
|
||||
const ClassType* class_type = ClassType::DynamicCast(alias->type());
|
||||
if (class_type) {
|
||||
if (class_type && class_type->IsExtern()) {
|
||||
// Classes that are in the default namespace are defined in the C++
|
||||
// world and all of their fields and methods are declared explicitly.
|
||||
// Internal classes (e.g. ones used for testing that are not in the default
|
||||
@ -170,7 +170,7 @@ void ImplementationVisitor::Visit(TypeAlias* alias) {
|
||||
header_out() << " };\n";
|
||||
} else if (!class_type->nspace()->IsDefaultNamespace()) {
|
||||
ReportError(
|
||||
"classes are currently only supported in the default and test "
|
||||
"extern classes are currently only supported in the default and test "
|
||||
"namespaces");
|
||||
}
|
||||
return;
|
||||
@ -1281,16 +1281,26 @@ VisitResult ImplementationVisitor::Visit(NewExpression* expr) {
|
||||
|
||||
// Output the code to generate an unitialized object of the class size in the
|
||||
// GC heap.
|
||||
VisitResult object_map = ProjectStructField(new_struct_result, "map");
|
||||
Arguments size_arguments;
|
||||
size_arguments.parameters.push_back(object_map);
|
||||
VisitResult object_size = GenerateCall("%GetAllocationBaseSize",
|
||||
size_arguments, {class_type}, false);
|
||||
Arguments allocate_arguments;
|
||||
allocate_arguments.parameters.push_back(object_size);
|
||||
VisitResult allocate_result =
|
||||
GenerateCall("%Allocate", allocate_arguments, {class_type}, false);
|
||||
DCHECK(allocate_result.IsOnStack());
|
||||
VisitResult allocate_result;
|
||||
if (class_type->IsExtern()) {
|
||||
VisitResult object_map = ProjectStructField(new_struct_result, "map");
|
||||
Arguments size_arguments;
|
||||
size_arguments.parameters.push_back(object_map);
|
||||
VisitResult object_size = GenerateCall("%GetAllocationBaseSize",
|
||||
size_arguments, {class_type}, false);
|
||||
Arguments allocate_arguments;
|
||||
allocate_arguments.parameters.push_back(object_size);
|
||||
allocate_result =
|
||||
GenerateCall("%Allocate", allocate_arguments, {class_type}, false);
|
||||
DCHECK(allocate_result.IsOnStack());
|
||||
} else {
|
||||
Arguments allocate_arguments;
|
||||
allocate_arguments.parameters.push_back(
|
||||
VisitResult(TypeOracle::GetConstexprIntPtrType(),
|
||||
std::to_string(class_type->size() / kTaggedSize)));
|
||||
allocate_result = GenerateCall("%AllocateInternalClass", allocate_arguments,
|
||||
{class_type}, false);
|
||||
}
|
||||
|
||||
// Fill in the fields of the newly allocated class by copying the values
|
||||
// from the struct that was built by the constructor. So that the generaeted
|
||||
|
@ -591,18 +591,19 @@ base::Optional<ParseResult> MakeMethodDeclaration(
|
||||
|
||||
base::Optional<ParseResult> MakeClassDeclaration(
|
||||
ParseResultIterator* child_results) {
|
||||
auto is_extern = child_results->NextAs<bool>();
|
||||
auto transient = child_results->NextAs<bool>();
|
||||
auto name = child_results->NextAs<std::string>();
|
||||
if (!IsValidTypeName(name)) {
|
||||
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 methods = child_results->NextAs<std::vector<Declaration*>>();
|
||||
auto fields = child_results->NextAs<std::vector<ClassFieldExpression>>();
|
||||
Declaration* result = MakeNode<ClassDeclaration>(
|
||||
std::move(name), transient, std::move(extends), std::move(generates),
|
||||
std::move(methods), fields);
|
||||
std::move(name), is_extern, transient, std::move(extends),
|
||||
std::move(generates), std::move(methods), fields);
|
||||
return ParseResult{result};
|
||||
}
|
||||
|
||||
@ -1619,8 +1620,9 @@ struct TorqueGrammar : Grammar {
|
||||
Rule({Token("const"), &identifier, Token(":"), &type, Token("generates"),
|
||||
&externalString, Token(";")},
|
||||
MakeExternConstDeclaration),
|
||||
Rule({CheckIf(Token("transient")), Token("class"), &identifier,
|
||||
Sequence({Token("extends"), &identifier}),
|
||||
Rule({CheckIf(Token("extern")), CheckIf(Token("transient")),
|
||||
Token("class"), &identifier,
|
||||
Optional<std::string>(Sequence({Token("extends"), &identifier})),
|
||||
Optional<std::string>(
|
||||
Sequence({Token("generates"), &externalString})),
|
||||
Token("{"), List<Declaration*>(&method),
|
||||
|
@ -35,9 +35,10 @@ class TypeOracle : public ContextualClass<TypeOracle> {
|
||||
}
|
||||
|
||||
static ClassType* GetClassType(const Type* parent, const std::string& name,
|
||||
bool transient, const std::string& generates) {
|
||||
ClassType* result =
|
||||
new ClassType(parent, CurrentNamespace(), name, transient, generates);
|
||||
bool is_extern, bool transient,
|
||||
const std::string& generates) {
|
||||
ClassType* result = new ClassType(parent, CurrentNamespace(), name,
|
||||
is_extern, transient, generates);
|
||||
Get().struct_types_.push_back(std::unique_ptr<ClassType>(result));
|
||||
return result;
|
||||
}
|
||||
@ -95,6 +96,10 @@ class TypeOracle : public ContextualClass<TypeOracle> {
|
||||
return Get().GetBuiltinType(CONSTEXPR_BOOL_TYPE_STRING);
|
||||
}
|
||||
|
||||
static const Type* GetConstexprIntPtrType() {
|
||||
return Get().GetBuiltinType(CONSTEXPR_INTPTR_TYPE_STRING);
|
||||
}
|
||||
|
||||
static const Type* GetVoidType() {
|
||||
return Get().GetBuiltinType(VOID_TYPE_STRING);
|
||||
}
|
||||
|
@ -262,6 +262,7 @@ std::string StructType::ToExplicitString() const {
|
||||
}
|
||||
|
||||
std::string ClassType::GetGeneratedTNodeTypeName() const {
|
||||
if (!IsExtern()) return generates_;
|
||||
std::string prefix = nspace()->IsDefaultNamespace()
|
||||
? std::string{}
|
||||
: (nspace()->ExternalName() + "::");
|
||||
@ -282,7 +283,7 @@ std::string ClassType::ToExplicitString() const {
|
||||
}
|
||||
|
||||
bool ClassType::AllowInstantiation() const {
|
||||
return nspace()->IsDefaultNamespace();
|
||||
return !IsExtern() || nspace()->IsDefaultNamespace();
|
||||
}
|
||||
|
||||
void PrintSignature(std::ostream& os, const Signature& sig, bool with_names) {
|
||||
|
@ -22,6 +22,7 @@ namespace torque {
|
||||
static const char* const CONSTEXPR_TYPE_PREFIX = "constexpr ";
|
||||
static const char* const NEVER_TYPE_STRING = "never";
|
||||
static const char* const CONSTEXPR_BOOL_TYPE_STRING = "constexpr bool";
|
||||
static const char* const CONSTEXPR_INTPTR_TYPE_STRING = "constexpr intptr";
|
||||
static const char* const BOOL_TYPE_STRING = "bool";
|
||||
static const char* const VOID_TYPE_STRING = "void";
|
||||
static const char* const ARGUMENTS_TYPE_STRING = "constexpr Arguments";
|
||||
@ -471,6 +472,7 @@ class ClassType final : public AggregateType {
|
||||
std::string ToExplicitString() const override;
|
||||
std::string GetGeneratedTypeName() const override;
|
||||
std::string GetGeneratedTNodeTypeName() const override;
|
||||
bool IsExtern() const { return is_extern_; }
|
||||
bool IsTransient() const override { return transient_; }
|
||||
size_t size() const { return size_; }
|
||||
StructType* struct_type() const { return this_struct_; }
|
||||
@ -485,9 +487,10 @@ class ClassType final : public AggregateType {
|
||||
private:
|
||||
friend class TypeOracle;
|
||||
ClassType(const Type* parent, Namespace* nspace, const std::string& name,
|
||||
bool transient, const std::string& generates)
|
||||
bool is_extern, bool transient, const std::string& generates)
|
||||
: AggregateType(Kind::kClassType, parent, nspace, name),
|
||||
this_struct_(nullptr),
|
||||
is_extern_(is_extern),
|
||||
transient_(transient),
|
||||
size_(0),
|
||||
generates_(generates) {
|
||||
@ -495,6 +498,7 @@ class ClassType final : public AggregateType {
|
||||
}
|
||||
|
||||
StructType* this_struct_;
|
||||
bool is_extern_;
|
||||
bool transient_;
|
||||
size_t size_;
|
||||
const std::string generates_;
|
||||
|
@ -423,6 +423,22 @@ TEST(TestStructConstructor) {
|
||||
ft.Call();
|
||||
}
|
||||
|
||||
TEST(TestInternalClass) {
|
||||
CcTest::InitializeVM();
|
||||
Isolate* isolate(CcTest::i_isolate());
|
||||
i::HandleScope scope(isolate);
|
||||
Handle<Context> context =
|
||||
Utils::OpenHandle(*v8::Isolate::GetCurrent()->GetCurrentContext());
|
||||
CodeAssemblerTester asm_tester(isolate);
|
||||
TestTorqueAssembler m(asm_tester.state());
|
||||
{
|
||||
m.TestInternalClass(m.UncheckedCast<Context>(m.HeapConstant(context)));
|
||||
m.Return(m.UndefinedConstant());
|
||||
}
|
||||
FunctionTester ft(asm_tester.GenerateCode(), 0);
|
||||
ft.Call();
|
||||
}
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -774,7 +774,7 @@ namespace test {
|
||||
assert(w.d == 2);
|
||||
}
|
||||
|
||||
class TestClassWithAllTypes extends JSObject {
|
||||
extern class TestClassWithAllTypes extends JSObject {
|
||||
a: int8;
|
||||
b: uint8;
|
||||
b2: uint8;
|
||||
@ -810,4 +810,25 @@ namespace test {
|
||||
t.h = t.h;
|
||||
t.i = t.i;
|
||||
}
|
||||
|
||||
class InternalClass {
|
||||
constructor(x: Smi) {
|
||||
this.a = x;
|
||||
this.b = x + 1;
|
||||
}
|
||||
Flip() labels NotASmi {
|
||||
const tmp = Cast<Smi>(this.b) otherwise NotASmi;
|
||||
this.b = this.a;
|
||||
this.a = tmp;
|
||||
}
|
||||
a: Smi;
|
||||
b: Number;
|
||||
}
|
||||
|
||||
macro TestInternalClass(implicit context: Context)() {
|
||||
const o = new InternalClass{5};
|
||||
o.Flip() otherwise unreachable;
|
||||
check(o.a == 6);
|
||||
check(o.b == 5);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user