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

[torque]: Class declarations

Class declarations support structured heap data that is a subtype of
HeapObject. Only fields of Object subtypes (both strong and weak)
are currently supported (no scalar fields yet).

With this CL, both the field list macro used with the C++
DEFINE_FIELD_OFFSET_CONSTANTS macro (to make field offset constants) as
well as the Torque "operator '.field'" macros are generated for the
classes declared in Torque. This is a first step to removing the
substantial amount of duplication and boilerplate code
needed to declare heap object classes.

As a proof of concept, and handful of class field definitions,
including those for non trivial classes like JSFunction, have been
moved to Torque.

Bug: v8:7793
Change-Id: I2fa0b53db65fa6f5fe078fb94e1db3418f908753
Reviewed-on: https://chromium-review.googlesource.com/c/1373971
Commit-Queue: Daniel Clifford <danno@chromium.org>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#58704}
parent bb46048a
......@@ -17,7 +17,11 @@ type never;
type Tagged generates 'TNode<Object>' constexpr 'ObjectPtr';
type Smi extends Tagged generates 'TNode<Smi>' constexpr 'Smi';
type HeapObject extends Tagged generates 'TNode<HeapObject>';
class HeapObject extends Tagged {
map_untyped: Tagged;
}
type Object = Smi | HeapObject;
type int32 generates 'TNode<Int32T>' constexpr 'int32_t';
type uint32 generates 'TNode<Uint32T>' constexpr 'uint32_t';
......@@ -36,8 +40,6 @@ type RawPtr generates 'TNode<RawPtrT>' constexpr 'void*';
type AbstractCode extends HeapObject generates 'TNode<AbstractCode>';
type Code extends AbstractCode generates 'TNode<Code>';
type BuiltinPtr extends Smi generates 'TNode<BuiltinPtr>';
type JSReceiver extends HeapObject generates 'TNode<JSReceiver>';
type Constructor extends JSReceiver generates 'TNode<JSReceiver>';
type Context extends HeapObject generates 'TNode<Context>';
type NativeContext extends Context generates 'TNode<Context>';
type String extends HeapObject generates 'TNode<String>';
......@@ -46,12 +48,39 @@ type HeapNumber extends HeapObject generates 'TNode<HeapNumber>';
type Number = Smi | HeapNumber;
type BigInt extends HeapObject generates 'TNode<BigInt>';
type Numeric = Number | BigInt;
type Map extends HeapObject generates 'TNode<Map>';
// The accessors for HeapObject's map cannot be declared before Map
// is declared because forward declarations are not (yet) supported.
// TODO(danno): Make circular references in classes possible. One way to do that
// would be to pre-process all class declarations and create bindings for them
// with an uninitialized class type, and then process them later properly
extern operator '.map' macro LoadMap(HeapObject): Map;
extern transitioning operator '.map=' macro StoreMap(HeapObject, Map);
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 {
properties_or_hash: Object;
}
type Constructor extends JSReceiver generates 'TNode<JSReceiver>';
type JSProxy extends JSReceiver generates 'TNode<JSProxy>';
type JSObject extends JSReceiver generates 'TNode<JSObject>';
type JSArgumentsObjectWithLength extends JSObject
generates 'TNode<JSArgumentsObjectWithLength>';
type JSArray extends JSArgumentsObjectWithLength
generates 'TNode<JSArray>';
class JSObject extends JSReceiver {
elements: FixedArrayBase;
}
class JSArgumentsObjectWithLength extends JSObject {
length: Object;
}
class JSArray extends JSObject {
length: Number;
}
// A HeapObject with a JSArray map, and either fast packed elements, or fast
// holey elements when the global NoElementsProtector is not invalidated.
......@@ -69,19 +98,24 @@ transient type FastJSArrayWithNoCustomIteration extends FastJSArray
type SharedFunctionInfo extends HeapObject
generates 'TNode<SharedFunctionInfo>';
type JSFunction extends JSObject generates 'TNode<JSFunction>';
extern operator '.shared_function_info'
macro LoadJSFunctionSharedFunctionInfo(JSFunction): SharedFunctionInfo;
class JSFunction extends JSObject {
shared_function_info: SharedFunctionInfo;
context: Context;
feedback_cell: Smi;
weak code: Code;
weak prototype_or_initial_map: JSReceiver | Map;
}
extern operator '.formal_parameter_count'
macro LoadSharedFunctionInfoFormalParameterCount(SharedFunctionInfo): int32;
type JSBoundFunction extends JSObject generates 'TNode<JSBoundFunction>';
class JSBoundFunction extends JSObject {
bound_target_function: JSReceiver;
bound_this: Object;
bound_arguments: FixedArray;
}
type Callable = JSFunction | JSBoundFunction | JSProxy;
type Map extends HeapObject generates 'TNode<Map>';
type FixedArrayBase extends HeapObject generates 'TNode<FixedArrayBase>';
type FixedArray extends FixedArrayBase generates 'TNode<FixedArray>';
type FixedDoubleArray extends FixedArrayBase
generates 'TNode<FixedDoubleArray>';
type FixedTypedArrayBase extends FixedArrayBase
generates 'TNode<FixedTypedArrayBase>';
type FixedTypedArray extends FixedTypedArrayBase
......@@ -520,8 +554,6 @@ extern operator '!' macro ConstexprBoolNot(constexpr bool): constexpr bool;
extern operator '!' macro Word32BinaryNot(bool): bool;
extern operator '!' macro IsFalse(Boolean): bool;
extern operator '.map' macro LoadMap(HeapObject): Map;
extern transitioning operator '.map=' macro StoreMap(HeapObject, Map);
extern operator '.instanceType' macro LoadInstanceType(HeapObject):
InstanceType;
......@@ -1018,15 +1050,8 @@ extern operator '.elements_kind' macro LoadMapElementsKind(Map): ElementsKind;
extern operator '.elements_kind' macro LoadElementsKind(JSTypedArray):
ElementsKind;
extern operator '.elements' macro LoadElements(JSObject): FixedArrayBase;
extern operator '.elements=' macro StoreElements(JSObject, FixedArrayBase);
extern operator '.length' macro LoadJSTypedArrayLength(JSTypedArray): Smi;
extern operator '.length' macro LoadJSArrayLength(JSArray): Number;
extern operator '.length' macro LoadJSArgumentsObjectWithLength(
JSArgumentsObjectWithLength): Object;
extern operator '.length' macro LoadFastJSArrayLength(FastJSArray): Smi;
extern operator '.length=' macro StoreJSArrayLength(JSArray, Smi);
extern operator '.length' macro LoadFixedArrayBaseLength(FixedArrayBase): Smi;
extern operator '.length_intptr' macro LoadAndUntagFixedArrayBaseLength(
......@@ -1055,9 +1080,6 @@ extern macro StoreFixedArrayElementSmi(
extern operator '.instance_type' macro LoadMapInstanceType(Map): int32;
extern operator '.prototype_or_initial_map' macro
LoadJSFunctionPrototypeOrInitialMap(JSFunction): Object;
extern macro LoadFixedDoubleArrayElement(FixedDoubleArray, Smi): float64;
extern macro Float64SilenceNaN(float64): float64;
......
......@@ -1462,8 +1462,7 @@ TNode<BoolT> CodeStubAssembler::TaggedDoesntHaveInstanceType(
TNode<HeapObject> CodeStubAssembler::LoadFastProperties(
SloppyTNode<JSObject> object) {
CSA_SLOW_ASSERT(this, Word32BinaryNot(IsDictionaryMap(LoadMap(object))));
TNode<Object> properties =
LoadObjectField(object, JSObject::kPropertiesOrHashOffset);
TNode<Object> properties = LoadJSReceiverPropertiesOrHash(object);
return Select<HeapObject>(TaggedIsSmi(properties),
[=] { return EmptyFixedArrayConstant(); },
[=] { return CAST(properties); });
......@@ -1472,18 +1471,12 @@ TNode<HeapObject> CodeStubAssembler::LoadFastProperties(
TNode<HeapObject> CodeStubAssembler::LoadSlowProperties(
SloppyTNode<JSObject> object) {
CSA_SLOW_ASSERT(this, IsDictionaryMap(LoadMap(object)));
TNode<Object> properties =
LoadObjectField(object, JSObject::kPropertiesOrHashOffset);
TNode<Object> properties = LoadJSReceiverPropertiesOrHash(object);
return Select<HeapObject>(TaggedIsSmi(properties),
[=] { return EmptyPropertyDictionaryConstant(); },
[=] { return CAST(properties); });
}
TNode<FixedArrayBase> CodeStubAssembler::LoadElements(
SloppyTNode<JSObject> object) {
return CAST(LoadObjectField(object, JSObject::kElementsOffset));
}
TNode<Number> CodeStubAssembler::LoadJSArrayLength(SloppyTNode<JSArray> array) {
CSA_ASSERT(this, IsJSArray(array));
return CAST(LoadObjectField(array, JSArray::kLengthOffset));
......
......@@ -843,7 +843,9 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<HeapObject> LoadSlowProperties(SloppyTNode<JSObject> object);
TNode<HeapObject> LoadFastProperties(SloppyTNode<JSObject> object);
// Load the elements backing store of a JSObject.
TNode<FixedArrayBase> LoadElements(SloppyTNode<JSObject> object);
TNode<FixedArrayBase> LoadElements(SloppyTNode<JSObject> object) {
return LoadJSObjectElements(object);
}
// Load the length of a JSArray instance.
TNode<Object> LoadJSArgumentsObjectWithLength(
SloppyTNode<JSArgumentsObjectWithLength> array);
......@@ -1167,17 +1169,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<BytecodeArray> LoadSharedFunctionInfoBytecodeArray(
SloppyTNode<SharedFunctionInfo> shared);
TNode<Object> LoadJSFunctionPrototypeOrInitialMap(
TNode<JSFunction> function) {
return LoadObjectField(function, JSFunction::kPrototypeOrInitialMapOffset);
}
TNode<SharedFunctionInfo> LoadJSFunctionSharedFunctionInfo(
TNode<JSFunction> function) {
return CAST(
LoadObjectField(function, JSFunction::kSharedFunctionInfoOffset));
}
TNode<Int32T> LoadSharedFunctionInfoFormalParameterCount(
TNode<SharedFunctionInfo> function) {
return TNode<Int32T>::UncheckedCast(LoadObjectField(
......
......@@ -8,6 +8,7 @@
#include "src/objects/fixed-array.h"
#include "src/objects/js-objects.h"
#include "src/objects/struct.h"
#include "torque-generated/class-definitions-from-dsl.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
......@@ -35,7 +36,7 @@ class JSArgumentsObjectWithLength : public JSArgumentsObject {
V(kSize, 0)
DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize,
JS_ARGUMENTS_OBJECT_WITH_LENGTH_FIELDS)
JSARGUMENTS_OBJECT_WITH_LENGTH_FIELDS)
#undef JS_ARGUMENTS_OBJECT_WITH_LENGTH_FIELDS
// Indices of in-object properties.
......
......@@ -8,6 +8,7 @@
#include "src/objects/allocation-site.h"
#include "src/objects/fixed-array.h"
#include "src/objects/js-objects.h"
#include "torque-generated/class-definitions-from-dsl.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
......@@ -104,13 +105,7 @@ class JSArray : public JSObject {
// Number of element slots to pre-allocate for an empty array.
static const int kPreallocatedArrayElements = 4;
// Layout description.
#define JS_ARRAY_FIELDS(V) \
V(kLengthOffset, kTaggedSize) \
/* Header size. */ \
V(kSize, 0)
DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, JS_ARRAY_FIELDS)
DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, JSARRAY_FIELDS)
#undef JS_ARRAY_FIELDS
static const int kLengthDescriptorIndex = 0;
......
......@@ -8,6 +8,7 @@
#include "src/objects.h"
#include "src/objects/embedder-data-slot.h"
#include "src/objects/property-array.h"
#include "torque-generated/class-definitions-from-dsl.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
......@@ -256,14 +257,8 @@ class JSReceiver : public HeapObject {
static const int kHashMask = PropertyArray::HashField::kMask;
// Layout description.
#define JS_RECEIVER_FIELDS(V) \
V(kPropertiesOrHashOffset, kTaggedSize) \
/* Header size. */ \
V(kHeaderSize, 0)
DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize, JS_RECEIVER_FIELDS)
#undef JS_RECEIVER_FIELDS
DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize, JSRECEIVER_FIELDS)
static const int kHeaderSize = kSize;
bool HasProxyInPrototype(Isolate* isolate);
......@@ -936,15 +931,7 @@ class JSBoundFunction : public JSObject {
static Handle<String> ToString(Handle<JSBoundFunction> function);
// Layout description.
#define JS_BOUND_FUNCTION_FIELDS(V) \
V(kBoundTargetFunctionOffset, kTaggedSize) \
V(kBoundThisOffset, kTaggedSize) \
V(kBoundArgumentsOffset, kTaggedSize) \
/* Header size. */ \
V(kSize, 0)
DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, JS_BOUND_FUNCTION_FIELDS)
#undef JS_BOUND_FUNCTION_FIELDS
DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, JSBOUND_FUNCTION_FIELDS)
OBJECT_CONSTRUCTORS(JSBoundFunction, JSObject);
};
......@@ -1137,22 +1124,10 @@ class JSFunction : public JSObject {
// ES6 section 19.2.3.5 Function.prototype.toString ( ).
static Handle<String> ToString(Handle<JSFunction> function);
// Layout description.
#define JS_FUNCTION_FIELDS(V) \
/* Pointer fields. */ \
V(kSharedFunctionInfoOffset, kTaggedSize) \
V(kContextOffset, kTaggedSize) \
V(kFeedbackCellOffset, kTaggedSize) \
V(kEndOfStrongFieldsOffset, 0) \
V(kCodeOffset, kTaggedSize) \
/* Size of JSFunction object without prototype field. */ \
V(kSizeWithoutPrototype, 0) \
V(kPrototypeOrInitialMapOffset, kTaggedSize) \
/* Size of JSFunction object with prototype field. */ \
V(kSizeWithPrototype, 0)
DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, JS_FUNCTION_FIELDS)
#undef JS_FUNCTION_FIELDS
DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, JSFUNCTION_FIELDS)
static constexpr int kSizeWithoutPrototype = kPrototypeOrInitialMapOffset;
static constexpr int kSizeWithPrototype = kSize;
OBJECT_CONSTRUCTORS(JSFunction, JSObject);
};
......
......@@ -19,6 +19,8 @@ namespace torque {
#define AST_EXPRESSION_NODE_KIND_LIST(V) \
V(CallExpression) \
V(LoadObjectFieldExpression) \
V(StoreObjectFieldExpression) \
V(IntrinsicCallExpression) \
V(StructExpression) \
V(LogicalOrExpression) \
......@@ -63,6 +65,7 @@ namespace torque {
V(GenericDeclaration) \
V(SpecializationDeclaration) \
V(ExternConstDeclaration) \
V(ClassDeclaration) \
V(StructDeclaration) \
V(NamespaceDeclaration) \
V(ConstDeclaration) \
......@@ -204,6 +207,31 @@ struct IdentifierExpression : LocationExpression {
std::vector<TypeExpression*> generic_arguments;
};
struct LoadObjectFieldExpression : Expression {
DEFINE_AST_NODE_LEAF_BOILERPLATE(LoadObjectFieldExpression)
LoadObjectFieldExpression(SourcePosition pos, Expression* base,
std::string field_name)
: Expression(kKind, pos),
base(std::move(base)),
field_name(std::move(field_name)) {}
Expression* base;
std::string field_name;
};
struct StoreObjectFieldExpression : Expression {
DEFINE_AST_NODE_LEAF_BOILERPLATE(StoreObjectFieldExpression)
StoreObjectFieldExpression(SourcePosition pos, Expression* base,
std::string field_name, Expression* value)
: Expression(kKind, pos),
base(std::move(base)),
field_name(std::move(field_name)),
value(std::move(value)) {}
Expression* base;
std::string field_name;
Expression* value;
size_t offset;
};
struct IntrinsicCallExpression : Expression {
DEFINE_AST_NODE_LEAF_BOILERPLATE(IntrinsicCallExpression)
IntrinsicCallExpression(SourcePosition pos, std::string name,
......@@ -629,6 +657,11 @@ struct NameAndTypeExpression {
TypeExpression* type;
};
struct ClassFieldExpression {
NameAndTypeExpression name_and_type;
bool weak;
};
struct LabelAndTypes {
std::string name;
std::vector<TypeExpression*> types;
......@@ -826,6 +859,25 @@ struct StructDeclaration : Declaration {
std::vector<NameAndTypeExpression> fields;
};
struct ClassDeclaration : Declaration {
DEFINE_AST_NODE_LEAF_BOILERPLATE(ClassDeclaration)
ClassDeclaration(SourcePosition pos, std::string name, bool transient,
base::Optional<std::string> extends,
base::Optional<std::string> generates,
std::vector<ClassFieldExpression> fields)
: Declaration(kKind, pos),
name(std::move(name)),
transient(transient),
extends(std::move(extends)),
generates(std::move(generates)),
fields(std::move(fields)) {}
std::string name;
bool transient;
base::Optional<std::string> extends;
base::Optional<std::string> generates;
std::vector<ClassFieldExpression> fields;
};
struct CppIncludeDeclaration : Declaration {
DEFINE_AST_NODE_LEAF_BOILERPLATE(CppIncludeDeclaration)
CppIncludeDeclaration(SourcePosition pos, std::string include_path)
......@@ -857,6 +909,14 @@ inline bool IsDeferred(Statement* stmt) {
return false;
}
DECLARE_CONTEXTUAL_VARIABLE(CurrentAst, Ast);
template <class T, class... Args>
T* MakeNode(Args... args) {
return CurrentAst::Get().AddNode(std::unique_ptr<T>(
new T(CurrentSourcePosition::Get(), std::move(args)...)));
}
} // namespace torque
} // namespace internal
} // namespace v8
......
......@@ -657,6 +657,36 @@ void CSAGenerator::EmitInstruction(const UnsafeCastInstruction& instruction,
">(" + stack->Top() + ")");
}
void CSAGenerator::EmitInstruction(
const LoadObjectFieldInstruction& instruction, Stack<std::string>* stack) {
const Field& field =
instruction.class_type->LookupField(instruction.field_name);
std::string result_name = FreshNodeName();
std::string type_string =
field.name_and_type.type->IsSubtypeOf(TypeOracle::GetSmiType())
? "MachineType::TaggedSigned()"
: "MachineType::AnyTagged()";
out_ << field.name_and_type.type->GetGeneratedTypeName() << " " << result_name
<< " = "
<< "ca_.UncheckedCast<"
<< field.name_and_type.type->GetGeneratedTNodeTypeName()
<< ">(CodeStubAssembler(state_).LoadObjectField("
<< stack->Top() + ", " + std::to_string(field.offset) + ", "
<< type_string + "));\n";
stack->Poke(stack->AboveTop() - 1, result_name);
}
void CSAGenerator::EmitInstruction(
const StoreObjectFieldInstruction& instruction, Stack<std::string>* stack) {
auto value = stack->Pop();
auto object = stack->Pop();
stack->Push(value);
const Field& field =
instruction.class_type->LookupField(instruction.field_name);
out_ << " CodeStubAssembler(state_).StoreObjectField(" + object + ", " +
std::to_string(field.offset) + ", " + value + ");\n";
}
// static
void CSAGenerator::EmitCSAValue(VisitResult result,
const Stack<std::string>& values,
......@@ -671,7 +701,8 @@ void CSAGenerator::EmitCSAValue(VisitResult result,
out << ", ";
}
first = false;
EmitCSAValue(ProjectStructField(result, field.name), values, out);
EmitCSAValue(ProjectStructField(result, field.name_and_type.name), values,
out);
}
out << "}";
} else {
......
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "src/torque/declaration-visitor.h"
#include "src/torque/ast.h"
namespace v8 {
namespace internal {
......@@ -229,14 +230,124 @@ void DeclarationVisitor::Visit(ExternConstDeclaration* decl) {
}
void DeclarationVisitor::Visit(StructDeclaration* decl) {
std::vector<NameAndType> fields;
std::vector<Field> fields;
for (auto& field : decl->fields) {
const Type* field_type = Declarations::GetType(field.type);
fields.push_back({field.name, field_type});
fields.push_back({{field.name, field_type}, 0, false});
}
Declarations::DeclareStruct(decl->name, fields);
}
void DeclarationVisitor::Visit(ClassDeclaration* decl) {
// Compute the offset of the class' first member. If the class extends
// another class, it's the size of the extended class, otherwise zero.
size_t first_field_offset = 0;
if (decl->extends) {
const Type* extends_type = Declarations::LookupType(*decl->extends);
if (extends_type != TypeOracle::GetTaggedType()) {
if (!extends_type->IsClassType()) {
ReportError(
"class \"", decl->name,
"\" must extend either Tagged or an already declared class");
}
first_field_offset = ClassType::DynamicCast(extends_type)->size();
}
}
// 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);
}
std::vector<Field> fields;
size_t offset = first_field_offset;
bool seen_strong = false;
bool seen_weak = false;
for (ClassFieldExpression& field : decl->fields) {
const Type* field_type = Declarations::GetType(field.name_and_type.type);
if (field_type->IsSubtypeOf(TypeOracle::GetTaggedType())) {
if (field.weak) {
seen_weak = true;
} else {
if (seen_weak) {
ReportError("cannot declare strong field \"",
field.name_and_type.name,
"\" after weak Tagged references");
}
seen_strong = true;
}
} else {
if (seen_strong || seen_weak) {
ReportError("cannot declare scalar field \"", field.name_and_type.name,
"\" after strong or weak Tagged references");
}
}
if (!field_type->IsSubtypeOf(TypeOracle::GetTaggedType())) {
ReportError(
"field \"", field.name_and_type.name, "\" of class \"", decl->name,
"\" must be a subtype of Tagged (other types not yet supported)");
}
fields.push_back(
{{field.name_and_type.name, field_type}, offset, field.weak});
offset += kTaggedSize;
}
auto new_class = Declarations::DeclareClass(
decl->extends, decl->name, decl->transient, generates, fields, offset);
// For each field, construct AST snippits that implement a CSA accessor
// function and define a corresponding '.field' operator. The
// implementation iterator will turn the snippits into code.
for (auto& field : fields) {
CurrentSourcePosition::Scope source_position(decl->pos);
IdentifierExpression* parameter = MakeNode<IdentifierExpression>(
std::vector<std::string>{}, std::string{"o"});
// Load accessor
std::string load_macro_name =
"Load" + decl->name + CamelifyString(field.name_and_type.name);
std::string get_operator_name = "." + field.name_and_type.name;
Signature load_signature;
load_signature.parameter_names.push_back("o");
load_signature.parameter_types.types.push_back(new_class);
load_signature.parameter_types.var_args = false;
load_signature.return_type = field.name_and_type.type;
Statement* load_body =
MakeNode<ReturnStatement>(MakeNode<LoadObjectFieldExpression>(
parameter, field.name_and_type.name));
Declarations::DeclareMacro(load_macro_name, base::nullopt, load_signature,
false, load_body, get_operator_name);
// Store accessor
IdentifierExpression* value = MakeNode<IdentifierExpression>(
std::vector<std::string>{}, std::string{"v"});
std::string store_macro_name =
"Store" + decl->name + CamelifyString(field.name_and_type.name);
std::string store_operator_name = "." + field.name_and_type.name + "=";
Signature store_signature;
store_signature.parameter_names.push_back("o");
store_signature.parameter_names.push_back("v");
store_signature.parameter_types.types.push_back(new_class);
store_signature.parameter_types.types.push_back(field.name_and_type.type);
store_signature.parameter_types.var_args = false;
// TODO(danno): Store macros probably should return their value argument
store_signature.return_type = TypeOracle::GetVoidType();
Statement* store_body =
MakeNode<ExpressionStatement>(MakeNode<StoreObjectFieldExpression>(
parameter, field.name_and_type.name, value));
Declarations::DeclareMacro(store_macro_name, base::nullopt, store_signature,
false, store_body, store_operator_name);
}
GlobalContext::RegisterClass(decl->name, new_class);
}
void DeclarationVisitor::Visit(CppIncludeDeclaration* decl) {
GlobalContext::AddCppInclude(decl->include_path);
}
......
......@@ -44,6 +44,7 @@ class DeclarationVisitor : public FileVisitor {
}
void Visit(TypeDeclaration* decl);
void Visit(ClassDeclaration* decl);
void Visit(TypeAliasDeclaration* decl) {
const Type* type = Declarations::GetType(decl->type);
......
......@@ -168,11 +168,24 @@ void Declarations::DeclareType(const std::string& name, const Type* type,
}
void Declarations::DeclareStruct(const std::string& name,
const std::vector<NameAndType>& fields) {
const std::vector<Field>& fields) {
const StructType* new_type = TypeOracle::GetStructType(name, fields);
DeclareType(name, new_type, false);
}
const ClassType* Declarations::DeclareClass(
base::Optional<std::string> parent, const std::string& name, bool transient,
const std::string& generates, std::vector<Field> fields, size_t size) {
const Type* parent_type = nullptr;
if (parent) {
parent_type = LookupType(QualifiedName{*parent});
}
const ClassType* new_type = TypeOracle::GetClassType(
parent_type, name, transient, generates, std::move(fields), size);
DeclareType(name, new_type, false);
return new_type;
}
Macro* Declarations::CreateMacro(
std::string external_name, std::string readable_name,
base::Optional<std::string> external_assembler_name, Signature signature,
......
......@@ -82,7 +82,12 @@ class Declarations {
bool redeclaration);
static void DeclareStruct(const std::string& name,
const std::vector<NameAndType>& fields);
const std::vector<Field>& fields);
static const ClassType* DeclareClass(base::Optional<std::string> parent,
const std::string& name, bool transient,
const std::string& generates,
std::vector<Field> fields, size_t size);
static Macro* CreateMacro(std::string external_name,
std::string readable_name,
......
......@@ -5,6 +5,8 @@
#ifndef V8_TORQUE_GLOBAL_CONTEXT_H_
#define V8_TORQUE_GLOBAL_CONTEXT_H_
#include <map>
#include "src/torque/declarable.h"
#include "src/torque/declarations.h"
#include "src/torque/type-oracle.h"
......@@ -44,6 +46,15 @@ class GlobalContext : public ContextualClass<GlobalContext> {
return result;
}
static void RegisterClass(const std::string& name,
const ClassType* new_class) {
Get().classes_[name] = new_class;
}
static const std::map<std::string, const ClassType*>& GetClasses() {
return Get().classes_;
}
static void AddCppInclude(std::string include_path) {
Get().cpp_includes_.push_back(std::move(include_path));
}
......@@ -61,6 +72,7 @@ class GlobalContext : public ContextualClass<GlobalContext> {
Ast ast_;
std::vector<std::unique_ptr<Declarable>> declarables_;
std::vector<std::string> cpp_includes_;
std::map<std::string, const ClassType*> classes_;
};
template <class T>
......
......@@ -152,8 +152,8 @@ void ImplementationVisitor::Visit(TypeAlias* alias) {
const std::string& name = struct_type->name();
header_out() << " struct " << name << " {\n";
for (auto& field : struct_type->fields()) {
header_out() << " " << field.type->GetGeneratedTypeName();
header_out() << " " << field.name << ";\n";
header_out() << " " << field.name_and_type.type->GetGeneratedTypeName();
header_out() << " " << field.name_and_type.name << ";\n";
}
header_out() << "\n std::tuple<";
bool first = true;
......@@ -172,10 +172,10 @@ void ImplementationVisitor::Visit(TypeAlias* alias) {
header_out() << ", ";
}
first = false;
if (field.type->IsStructType()) {
header_out() << field.name << ".Flatten()";
if (field.name_and_type.type->IsStructType()) {
header_out() << field.name_and_type.name << ".Flatten()";
} else {
header_out() << "std::make_tuple(" << field.name << ")";
header_out() << "std::make_tuple(" << field.name_and_type.name << ")";
}
}
header_out() << ");\n";
......@@ -1466,10 +1466,10 @@ VisitResult ImplementationVisitor::Visit(StructExpression* decl) {
}
StackRange stack_range = assembler().TopRange(0);
for (size_t i = 0; i < struct_type->fields().size(); ++i) {
const NameAndType& field = struct_type->fields()[i];
const Field& field = struct_type->fields()[i];
StackScope scope(this);
VisitResult value = Visit(decl->expressions[i]);
value = GenerateImplicitConvert(field.type, value);
value = GenerateImplicitConvert(field.name_and_type.type, value);
stack_range.Extend(scope.Yield(value).stack_range());
}
return VisitResult(struct_type, stack_range);
......@@ -1908,6 +1908,35 @@ VisitResult ImplementationVisitor::Visit(CallExpression* expr,
}
}
VisitResult ImplementationVisitor::Visit(LoadObjectFieldExpression* expr) {
VisitResult result = Visit(expr->base);
auto class_type = ClassType::DynamicCast(result.type());
if (!class_type) {
ReportError(
"base expression for a LoadObjectFieldExpression is not a class type "
"but instead ",
*result.type());
}
assembler().Emit(LoadObjectFieldInstruction{class_type, expr->field_name});
const Field& field = class_type->LookupField(expr->field_name);
result.SetType(field.name_and_type.type);
return result;
}
VisitResult ImplementationVisitor::Visit(StoreObjectFieldExpression* expr) {
VisitResult base_result = Visit(expr->base);
auto class_type = ClassType::DynamicCast(base_result.type());
if (!class_type) {
ReportError(
"base expression for a StoreObjectFieldExpression is not a class type "
"but instead ",
*base_result.type());
}
VisitResult value = Visit(expr->value);
assembler().Emit(StoreObjectFieldInstruction{class_type, expr->field_name});
return VisitResult(value.type(), assembler().TopRange(0));
}
VisitResult ImplementationVisitor::Visit(IntrinsicCallExpression* expr) {
StackScope scope(this);
Arguments arguments;
......@@ -1997,7 +2026,8 @@ StackRange ImplementationVisitor::LowerParameter(
StackRange range = lowered_parameters->TopRange(0);
for (auto& field : struct_type->fields()) {
StackRange parameter_range = LowerParameter(
field.type, parameter_name + "." + field.name, lowered_parameters);
field.name_and_type.type,
parameter_name + "." + field.name_and_type.name, lowered_parameters);
range.Extend(parameter_range);
}
return range;
......@@ -2170,6 +2200,50 @@ void ImplementationVisitor::GenerateBuiltinDefinitions(std::string& file_name) {
ReplaceFileContentsIfDifferent(file_name, new_contents);
}
void ImplementationVisitor::GenerateClassDefinitions(std::string& file_name) {
std::stringstream new_contents_stream;
new_contents_stream << "#ifndef V8_CLASS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n"
"#define V8_CLASS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n"
"\n\n";
for (auto i : GlobalContext::GetClasses()) {
// TODO(danno): Ideally (and we've got several core V8 dev's feedback
// supporting this), Torque should generate the constants for the offsets
// directly and not go through the existing layer of macros, which actually
// currently just serves to additionally obfuscate where these values come
// from.
new_contents_stream << "#define ";
new_contents_stream << CapifyStringWithUnderscores(i.first)
<< "_FIELDS(V) \\\n";
const ClassType* type = i.second;
std::vector<Field> fields = type->fields();
new_contents_stream << "V(kStartOfStrongFieldsOffset, 0) \\\n";
for (auto f : fields) {
if (!f.is_weak) {
new_contents_stream << "V(k" << CamelifyString(f.name_and_type.name)
<< "Offset, kTaggedSize) \\\n";
}
}
new_contents_stream << "V(kEndOfStrongFieldsOffset, 0) \\\n";
new_contents_stream << "V(kStartOfWeakFieldsOffset, 0) \\\n";
for (auto f : fields) {
if (f.is_weak) {
new_contents_stream << "V(k" << CamelifyString(f.name_and_type.name)
<< "Offset, kTaggedSize) \\\n";
}
}
new_contents_stream << "V(kEndOfWeakFieldsOffset, 0) \\\n";
new_contents_stream << "V(kSize, 0) \\\n";
new_contents_stream << "\n";
}
new_contents_stream
<< "\n#endif // V8_CLASS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n";
std::string new_contents(new_contents_stream.str());
ReplaceFileContentsIfDifferent(file_name, new_contents);
}
} // namespace torque
} // namespace internal
} // namespace v8
......@@ -200,6 +200,7 @@ bool IsCompatibleSignature(const Signature& sig, const TypeVector& types,
class ImplementationVisitor : public FileVisitor {
public:
void GenerateBuiltinDefinitions(std::string& file_name);
void GenerateClassDefinitions(std::string& file_name);
VisitResult Visit(Expression* expr);
const Type* Visit(Statement* stmt);
......@@ -237,6 +238,8 @@ class ImplementationVisitor : public FileVisitor {
VisitResult Visit(CallExpression* expr, bool is_tail = false);
VisitResult Visit(IntrinsicCallExpression* intrinsic);
VisitResult Visit(LoadObjectFieldExpression* intrinsic);
VisitResult Visit(StoreObjectFieldExpression* intrinsic);
const Type* Visit(TailCallStatement* stmt);
VisitResult Visit(ConditionalExpression* expr);
......
......@@ -281,6 +281,41 @@ void UnsafeCastInstruction::TypeInstruction(Stack<const Type*>* stack,
stack->Poke(stack->AboveTop() - 1, destination_type);
}
void LoadObjectFieldInstruction::TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const {
const ClassType* stack_class_type = ClassType::DynamicCast(stack->Top());
if (!stack_class_type) {
ReportError(
"first argument to a LoadObjectFieldInstruction instruction isn't a "
"class");
}
if (stack_class_type != class_type) {
ReportError(
"first argument to a LoadObjectFieldInstruction doesn't match "
"instruction's type");
}
const Field& field = class_type->LookupField(field_name);
stack->Poke(stack->AboveTop() - 1, field.name_and_type.type);
}
void StoreObjectFieldInstruction::TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const {
auto value = stack->Pop();
const ClassType* stack_class_type = ClassType::DynamicCast(stack->Top());
if (!stack_class_type) {
ReportError(
"first argument to a StoreObjectFieldInstruction instruction isn't a "
"class");
}
if (stack_class_type != class_type) {
ReportError(
"first argument to a StoreObjectFieldInstruction doesn't match "
"instruction's type");
}
stack->Pop();
stack->Push(value);
}
bool CallRuntimeInstruction::IsBlockTerminator() const {
return is_tailcall || runtime_function->signature().return_type ==
TypeOracle::GetNeverType();
......
......@@ -30,6 +30,8 @@ class RuntimeFunction;
V(DeleteRangeInstruction) \
V(PushUninitializedInstruction) \
V(PushBuiltinPointerInstruction) \
V(LoadObjectFieldInstruction) \
V(StoreObjectFieldInstruction) \
V(CallCsaMacroInstruction) \
V(CallIntrinsicInstruction) \
V(NamespaceConstantInstruction) \
......@@ -109,9 +111,10 @@ class Instruction {
return nullptr;
}
Instruction(const Instruction& other)
: kind_(other.kind_), instruction_(other.instruction_->Clone()) {}
Instruction& operator=(const Instruction& other) {
Instruction(const Instruction& other) V8_NOEXCEPT
: kind_(other.kind_),
instruction_(other.instruction_->Clone()) {}
Instruction& operator=(const Instruction& other) V8_NOEXCEPT {
if (kind_ == other.kind_) {
instruction_->Assign(*other.instruction_);
} else {
......@@ -189,6 +192,30 @@ struct NamespaceConstantInstruction : InstructionBase {
NamespaceConstant* constant;
};
struct LoadObjectFieldInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE()
LoadObjectFieldInstruction(const ClassType* class_type,
std::string field_name)
: class_type(class_type) {
// The normal way to write this triggers a bug in Clang on Windows.
this->field_name = std::move(field_name);
}
const ClassType* class_type;
std::string field_name;
};
struct StoreObjectFieldInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE()
StoreObjectFieldInstruction(const ClassType* class_type,
std::string field_name)
: class_type(class_type) {
// The normal way to write this triggers a bug in Clang on Windows.
this->field_name = std::move(field_name);
}
const ClassType* class_type;
std::string field_name;
};
struct CallIntrinsicInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE()
CallIntrinsicInstruction(Intrinsic* intrinsic,
......
......@@ -41,7 +41,9 @@ enum class ParseResultHolderBase::TypeId {
kLabelBlockPtr,
kOptionalLabelBlockPtr,
kNameAndTypeExpression,
kClassFieldExpression,
kStdVectorOfNameAndTypeExpression,
kStdVectorOfClassFieldExpression,
kIncrementDecrementOperator,
kOptionalStdString,
kStdVectorOfStatementPtr,
......@@ -101,10 +103,18 @@ V8_EXPORT_PRIVATE const ParseResultTypeId
ParseResultHolder<NameAndTypeExpression>::id =
ParseResultTypeId::kNameAndTypeExpression;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
ParseResultHolder<ClassFieldExpression>::id =
ParseResultTypeId::kClassFieldExpression;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
ParseResultHolder<std::vector<NameAndTypeExpression>>::id =
ParseResultTypeId::kStdVectorOfNameAndTypeExpression;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
ParseResultHolder<std::vector<ClassFieldExpression>>::id =
ParseResultTypeId::kStdVectorOfClassFieldExpression;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
ParseResultHolder<IncrementDecrementOperator>::id =
ParseResultTypeId::kIncrementDecrementOperator;
......@@ -182,12 +192,6 @@ base::Optional<ParseResult> AddGlobalDeclaration(
return base::nullopt;
}
template <class T, class... Args>
T* MakeNode(Args... args) {
return CurrentAst::Get().AddNode(std::unique_ptr<T>(
new T(CurrentSourcePosition::Get(), std::move(args)...)));
}
void LintGenericParameters(const GenericParameters& parameters) {
for (const std::string& parameter : parameters) {
if (!IsUpperCamelCase(parameter)) {
......@@ -309,6 +313,7 @@ base::Optional<ParseResult> MakeParameterListFromTypes(
}
return ParseResult{std::move(result)};
}
template <bool has_varargs>
base::Optional<ParseResult> MakeParameterListFromNameAndTypeList(
ParseResultIterator* child_results) {
......@@ -516,6 +521,22 @@ base::Optional<ParseResult> MakeTypeDeclaration(
return ParseResult{result};
}
base::Optional<ParseResult> MakeClassDeclaration(
ParseResultIterator* child_results) {
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<base::Optional<std::string>>();
auto generates = child_results->NextAs<base::Optional<std::string>>();
auto fields = child_results->NextAs<std::vector<ClassFieldExpression>>();
Declaration* result =
MakeNode<ClassDeclaration>(std::move(name), transient, std::move(extends),
std::move(generates), fields);
return ParseResult{result};
}
base::Optional<ParseResult> MakeNamespaceDeclaration(
ParseResultIterator* child_results) {
auto name = child_results->NextAs<std::string>();
......@@ -1036,6 +1057,13 @@ base::Optional<ParseResult> MakeNameAndType(
return ParseResult{NameAndTypeExpression{std::move(name), type}};
}
base::Optional<ParseResult> MakeClassField(ParseResultIterator* child_results) {
auto weak = child_results->NextAs<bool>();
auto name = child_results->NextAs<std::string>();
auto type = child_results->NextAs<TypeExpression*>();
return ParseResult{ClassFieldExpression{{std::move(name), type}, weak}};
}
base::Optional<ParseResult> ExtractAssignmentOperator(
ParseResultIterator* child_results) {
auto op = child_results->NextAs<std::string>();
......@@ -1222,6 +1250,10 @@ struct TorqueGrammar : Grammar {
Symbol nameAndType = {
Rule({&identifier, Token(":"), &type}, MakeNameAndType)};
Symbol classField = {
Rule({CheckIf(Token("weak")), &identifier, Token(":"), &type, Token(";")},
MakeClassField)};
// Result: ParameterList
Symbol parameterListNoVararg = {
Rule({optionalImplicitParameterList, Token("("),
......@@ -1480,6 +1512,12 @@ struct TorqueGrammar : Grammar {
Rule({Token("const"), &identifier, Token(":"), &type, Token("generates"),
&externalString, Token(";")},
MakeExternConstDeclaration),
Rule({CheckIf(Token("transient")), Token("class"), &identifier,
Optional<std::string>(Sequence({Token("extends"), &identifier})),
Optional<std::string>(
Sequence({Token("generates"), &externalString})),
Token("{"), List<ClassFieldExpression>(&classField), Token("}")},
MakeClassDeclaration),
Rule({CheckIf(Token("transient")), Token("type"), &identifier,
Optional<std::string>(Sequence({Token("extends"), &identifier})),
Optional<std::string>(
......
......@@ -11,8 +11,6 @@ namespace v8 {
namespace internal {
namespace torque {
DECLARE_CONTEXTUAL_VARIABLE(CurrentAst, Ast);
// Adds the parsed input to {CurrentAst}
void ParseTorque(const std::string& input);
......
......@@ -68,6 +68,9 @@ int WrappedMain(int argc, const char** argv) {
output_header_path += "/builtin-definitions-from-dsl.h";
visitor.GenerateBuiltinDefinitions(output_header_path);
output_header_path = output_directory + "/class-definitions-from-dsl.h";
visitor.GenerateClassDefinitions(output_header_path);
for (Namespace* n : GlobalContext::Get().GetNamespaces()) {
visitor.EndNamespaceFile(n);
visitor.GenerateImplementation(output_directory, n);
......
......@@ -28,13 +28,24 @@ class TypeOracle : public ContextualClass<TypeOracle> {
return result;
}
static const StructType* GetStructType(
const std::string& name, const std::vector<NameAndType>& fields) {
static const StructType* GetStructType(const std::string& name,
const std::vector<Field>& fields) {
StructType* result = new StructType(CurrentNamespace(), name, fields);
Get().struct_types_.push_back(std::unique_ptr<StructType>(result));
return result;
}
static const ClassType* GetClassType(const Type* parent,
const std::string& name, bool transient,
const std::string& generates,
const std::vector<Field>& fields,
size_t size) {
ClassType* result = new ClassType(parent, CurrentNamespace(), name,
transient, generates, fields, size);
Get().struct_types_.push_back(std::unique_ptr<ClassType>(result));
return result;
}
static const BuiltinPointerType* GetBuiltinPointerType(
TypeVector argument_types, const Type* return_type) {
TypeOracle& self = Get();
......
......@@ -78,6 +78,8 @@ std::string AbstractType::GetGeneratedTNodeTypeName() const {
return generated_type_;
}
std::string ClassType::GetGeneratedTNodeTypeName() const { return generates_; }
std::string BuiltinPointerType::ToExplicitString() const {
std::stringstream result;
result << "builtin (";
......@@ -182,16 +184,36 @@ const Type* SubtractType(const Type* a, const Type* b) {
return TypeOracle::GetUnionType(result);
}
const Field& NameAndTypeListType::LookupField(const std::string& name) const {
for (auto& field : fields_) {
if (field.name_and_type.name == name) return field;
}
if (parent() != nullptr) {
if (auto parent_class = ClassType::DynamicCast(parent())) {
return parent_class->LookupField(name);
}
}
ReportError("no field ", name, "found");
}
std::string StructType::GetGeneratedTypeName() const {
return nspace()->ExternalName() + "::" + name();
}
std::string StructType::ToExplicitString() const {
std::stringstream result;
result << "{";
PrintCommaSeparatedList(result, fields_);
result << "struct " << name() << "{";
PrintCommaSeparatedList(result, fields());
result << "}";
return result.str();
}
std::string StructType::GetGeneratedTypeName() const {
return namespace_->ExternalName() + "::" + GetStructName();
std::string ClassType::ToExplicitString() const {
std::stringstream result;
result << "class " << name() << "{";
PrintCommaSeparatedList(result, fields());
result << "}";
return result.str();
}
void PrintSignature(std::ostream& os, const Signature& sig, bool with_names) {
......@@ -234,6 +256,14 @@ std::ostream& operator<<(std::ostream& os, const NameAndType& name_and_type) {
return os;
}
std::ostream& operator<<(std::ostream& os, const Field& field) {
os << field.name_and_type;
if (field.is_weak) {
os << " (weak)";
}
return os;
}
std::ostream& operator<<(std::ostream& os, const Signature& sig) {
PrintSignature(os, sig, true);
return os;
......@@ -294,9 +324,9 @@ VisitResult ProjectStructField(VisitResult structure,
BottomOffset begin = structure.stack_range().begin();
const StructType* type = StructType::cast(structure.type());
for (auto& field : type->fields()) {
BottomOffset end = begin + LoweredSlotCount(field.type);
if (field.name == fieldname) {
return VisitResult(field.type, StackRange{begin, end});
BottomOffset end = begin + LoweredSlotCount(field.name_and_type.type);
if (field.name_and_type.name == fieldname) {
return VisitResult(field.name_and_type.type, StackRange{begin, end});
}
begin = end;
}
......@@ -309,8 +339,8 @@ void AppendLoweredTypes(const Type* type, std::vector<const Type*>* result) {
if (type->IsConstexpr()) return;
if (type == TypeOracle::GetVoidType()) return;
if (auto* s = StructType::DynamicCast(type)) {
for (const NameAndType& field : s->fields()) {
AppendLoweredTypes(field.type, result);
for (const Field& field : s->fields()) {
AppendLoweredTypes(field.name_and_type.type, result);
}
} else {
result->push_back(type);
......
......@@ -50,7 +50,8 @@ class TypeBase {
kAbstractType,
kBuiltinPointerType,
kUnionType,
kStructType
kStructType,
kClassType
};
virtual ~TypeBase() = default;
bool IsTopType() const { return kind() == Kind::kTopType; }
......@@ -60,6 +61,7 @@ class TypeBase {
}
bool IsUnionType() const { return kind() == Kind::kUnionType; }
bool IsStructType() const { return kind() == Kind::kStructType; }
bool IsClassType() const { return kind() == Kind::kClassType; }
protected:
explicit TypeBase(Kind kind) : kind_(kind) {}
......@@ -143,6 +145,14 @@ struct NameAndType {
std::ostream& operator<<(std::ostream& os, const NameAndType& name_and_type);
struct Field {
NameAndType name_and_type;
size_t offset;
bool is_weak;
};
std::ostream& operator<<(std::ostream& os, const Field& name_and_type);
class TopType final : public Type {
public:
DECLARE_TYPE_BOILERPLATE(TopType);
......@@ -366,44 +376,71 @@ class UnionType final : public Type {
const Type* SubtractType(const Type* a, const Type* b);
class StructType final : public Type {
class NameAndTypeListType : public Type {
public:
DECLARE_TYPE_BOILERPLATE(StructType);
std::string ToExplicitString() const override;
std::string MangledName() const override { return name_; }
std::string GetGeneratedTypeName() const override;
std::string GetGeneratedTypeName() const override { UNREACHABLE(); };
std::string GetGeneratedTNodeTypeName() const override { UNREACHABLE(); }
const Type* NonConstexprVersion() const override { return this; }
bool IsConstexpr() const override { return false; }
const std::vector<NameAndType>& fields() const { return fields_; }
const Type* GetFieldType(const std::string& fieldname) const {
for (const NameAndType& field : fields()) {
if (field.name == fieldname) return field.type;
}
std::stringstream s;
s << "\"" << fieldname << "\" is not a field of struct type \"" << name()
<< "\"";
ReportError(s.str());
}
void SetFields(std::vector<Field> fields) { fields_ = std::move(fields); }
const std::vector<Field>& fields() const { return fields_; }
const Field& LookupField(const std::string& name) const;
const std::string& name() const { return name_; }
Namespace* nspace() const { return namespace_; }
protected:
NameAndTypeListType(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) {}
private:
Namespace* namespace_;
std::string name_;
std::vector<Field> fields_;
};
class StructType final : public NameAndTypeListType {
public:
DECLARE_TYPE_BOILERPLATE(StructType);
std::string ToExplicitString() const override;
std::string GetGeneratedTypeName() const override;
private:
friend class TypeOracle;
StructType(Namespace* nspace, const std::string& name,
const std::vector<NameAndType>& fields)
: Type(Kind::kStructType, nullptr),
namespace_(nspace),
name_(name),
fields_(fields) {}
const std::vector<Field>& fields)
: NameAndTypeListType(Kind::kStructType, nullptr, nspace, name, fields) {}
const std::string& GetStructName() const { return name_; }
const std::string& GetStructName() const { return name(); }
};
Namespace* namespace_;
std::string name_;
std::vector<NameAndType> fields_;
class ClassType final : public NameAndTypeListType {
public:
DECLARE_TYPE_BOILERPLATE(ClassType);
std::string ToExplicitString() const override;
std::string GetGeneratedTypeName() const override {
return IsConstexpr() ? generates_ : "compiler::TNode<" + generates_ + ">";
}
std::string GetGeneratedTNodeTypeName() const override;
bool IsTransient() const override { return transient_; }
size_t size() const { return size_; }
private:
friend class TypeOracle;
ClassType(const Type* parent, Namespace* nspace, const std::string& name,
bool transient, const std::string& generates,
const std::vector<Field>& fields, size_t size)
: NameAndTypeListType(Kind::kClassType, parent, nspace, name, fields),
transient_(transient),
size_(size),
generates_(generates) {}
bool transient_;
size_t size_;
const std::string generates_;
};
inline std::ostream& operator<<(std::ostream& os, const Type& t) {
......
......@@ -163,6 +163,19 @@ bool IsValidTypeName(const std::string& s) {
return IsUpperCamelCase(s);
}
std::string CapifyStringWithUnderscores(const std::string& camellified_string) {
std::string result;
bool previousWasLower = false;
for (auto current : camellified_string) {
if (previousWasLower && isupper(current)) {
result += "_";
}
result += toupper(current);
previousWasLower = (islower(current));
}
return result;
}
std::string CamelifyString(const std::string& underscore_string) {
std::string result;
bool word_beginning = true;
......
......@@ -53,6 +53,7 @@ template <class... Args>
ReportErrorString(s.str());
}
std::string CapifyStringWithUnderscores(const std::string& camellified_string);
std::string CamelifyString(const std::string& underscore_string);
std::string DashifyString(const std::string& underscore_string);
......@@ -263,6 +264,8 @@ class ToString {
std::stringstream s_;
};
constexpr int kTaggedSize = sizeof(void*);
} // namespace torque
} // namespace internal
} // namespace v8
......
......@@ -50,6 +50,7 @@ def postprocess(output):
output = re.sub(r'% RawPointerCast', r'%RawPointerCast', output)
output = re.sub(r'% RawConstexprCast', r'%RawConstexprCast', output)
output = re.sub(r'% FromConstexpr', r'%FromConstexpr', output)
output = re.sub(r'% Allocate', r'%Allocate ', output)
output = re.sub(r'\/\*COxp\*\/', r'constexpr', output)
output = re.sub(r'(\S+)\s*: type([,>])', r'\1: type\2', output)
output = re.sub(r'(\n\s*)labels( [A-Z])', r'\1 labels\2', output)
......
......@@ -30,14 +30,14 @@ syn keyword torqueFunction macro builtin runtime intrinsic
syn keyword torqueKeyword cast convert from_constexpr min max unsafe_cast
syn keyword torqueLabel case
syn keyword torqueMatching try label catch
syn keyword torqueModifier extern javascript constexpr transitioning transient
syn keyword torqueModifier extern javascript constexpr transitioning transient weak
syn match torqueNumber /\v<[0-9]+(\.[0-9]*)?>/
syn match torqueNumber /\v<0x[0-9a-fA-F]+>/
syn keyword torqueOperator operator
syn keyword torqueRel extends generates labels
syn keyword torqueRepeat while for of
syn keyword torqueStatement return tail
syn keyword torqueStructure module struct type
syn keyword torqueStructure module struct type class
syn keyword torqueVariable const let
syn match torqueType /\v(\<)@<=([A-Za-z][0-9A-Za-z_]*)(>)@=/
......
......@@ -65,7 +65,7 @@
},
{
"name": "keyword.other.torque",
"match": "\\b(constexpr|module|macro|builtin|runtime|intrinsic|javascript|implicit|deferred|label|labels|tail|let|generates|type|extends|extern|const|typeswitch|case|transient|transitioning)\\b"
"match": "\\b(constexpr|module|macro|builtin|runtime|intrinsic|javascript|implicit|deferred|label|labels|tail|let|generates|type|class|weak|extends|extern|const|typeswitch|case|transient|transitioning)\\b"
},
{
"name": "keyword.operator.torque",
......
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