[torque] Generate GC object visitors for Torque classes
In the process: * Augment C++-generated Torque classes with SizeFor methods to calculate size of instances. * Add a new "@generateBodyDescriptor" annotation that causes Torque to generate C++ BodyDescriptors code that can be used to visit objects compatible with existing V8 mechanisms, e.g. GC * Fully automate C++ macro machinery so that adding non-extern Torque class doesn't require any C++ changes, including ensuring generation of instance types and proper boilerplate for validators and printers. * Make handling of @export a true annotation, allowing the modifier to be used on class declarations. * Add functionality such that classes with the @export annotation are available to be used from C++. Field accessors for exported classes are public and factory methods are generated to create instances of the objects from C++. * Change the Torque compiler such that Non-exported classes implicitly have the @generateBodyDescriptor annotation added and causes both verifiers and printers to be generated. * Switch non-extern Torque classes from using existing Struct-based machinery to being first-class classes that support more existing Torque class features. Change-Id: Ic60e60c2c6bd7acd57f949bce086898ad14a3b03 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2007490 Commit-Queue: Tobias Tebbi <tebbi@chromium.org> Reviewed-by: Tobias Tebbi <tebbi@chromium.org> Cr-Commit-Position: refs/heads/master@{#66621}
This commit is contained in:
parent
f830171093
commit
4f4d73f225
4
BUILD.gn
4
BUILD.gn
@ -1176,11 +1176,14 @@ template("run_torque") {
|
||||
"bit-fields-tq.h",
|
||||
"builtin-definitions-tq.h",
|
||||
"interface-descriptors-tq.inc",
|
||||
"factory-tq.cc",
|
||||
"factory-tq.inc",
|
||||
"field-offsets-tq.h",
|
||||
"class-verifiers-tq.cc",
|
||||
"class-verifiers-tq.h",
|
||||
"enum-verifiers-tq.cc",
|
||||
"objects-printer-tq.cc",
|
||||
"objects-body-descriptors-tq-inl.h",
|
||||
"class-definitions-tq.cc",
|
||||
"class-definitions-tq-inl.h",
|
||||
"class-definitions-tq.h",
|
||||
@ -1302,6 +1305,7 @@ v8_source_set("torque_generated_definitions") {
|
||||
"$target_gen_dir/torque-generated/class-definitions-tq.cc",
|
||||
"$target_gen_dir/torque-generated/class-verifiers-tq.cc",
|
||||
"$target_gen_dir/torque-generated/class-verifiers-tq.h",
|
||||
"$target_gen_dir/torque-generated/factory-tq.cc",
|
||||
"$target_gen_dir/torque-generated/objects-printer-tq.cc",
|
||||
]
|
||||
|
||||
|
@ -148,7 +148,7 @@ namespace torque_internal {
|
||||
type UninitializedHeapObject extends HeapObject;
|
||||
|
||||
extern macro AllocateAllowLOS(intptr): UninitializedHeapObject;
|
||||
extern macro GetStructMap(constexpr InstanceType): Map;
|
||||
extern macro GetInstanceTypeMap(constexpr InstanceType): Map;
|
||||
|
||||
macro Allocate(sizeInBytes: intptr, map: Map): UninitializedHeapObject {
|
||||
assert(ValidAllocationSize(sizeInBytes, map));
|
||||
|
@ -1635,9 +1635,10 @@ TNode<Float64T> CodeStubAssembler::LoadHeapNumberValue(
|
||||
object, HeapNumber::kValueOffset, MachineType::Float64()));
|
||||
}
|
||||
|
||||
TNode<Map> CodeStubAssembler::GetStructMap(InstanceType instance_type) {
|
||||
TNode<Map> CodeStubAssembler::GetInstanceTypeMap(InstanceType instance_type) {
|
||||
Handle<Map> map_handle(
|
||||
Map::GetStructMap(ReadOnlyRoots(isolate()), instance_type), isolate());
|
||||
Map::GetInstanceTypeMap(ReadOnlyRoots(isolate()), instance_type),
|
||||
isolate());
|
||||
return HeapConstant(map_handle);
|
||||
}
|
||||
|
||||
|
@ -53,6 +53,9 @@ enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol };
|
||||
V(TypedArraySpeciesProtector, typed_array_species_protector, \
|
||||
TypedArraySpeciesProtector)
|
||||
|
||||
#define TORQUE_INTERNAL_CLASS_LIST_CSA_ADAPTER(V, NAME, Name, name) \
|
||||
V(Name##Map, name##_map, Name##Map)
|
||||
|
||||
#define HEAP_IMMUTABLE_IMMOVABLE_OBJECT_LIST(V) \
|
||||
V(AccessorInfoMap, accessor_info_map, AccessorInfoMap) \
|
||||
V(AccessorPairMap, accessor_pair_map, AccessorPairMap) \
|
||||
@ -174,7 +177,9 @@ enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol };
|
||||
V(UndefinedValue, undefined_value, Undefined) \
|
||||
V(uninitialized_symbol, uninitialized_symbol, UninitializedSymbol) \
|
||||
V(WeakFixedArrayMap, weak_fixed_array_map, WeakFixedArrayMap) \
|
||||
V(zero_string, zero_string, ZeroString)
|
||||
V(zero_string, zero_string, ZeroString) \
|
||||
TORQUE_INTERNAL_CLASS_LIST_GENERATOR(TORQUE_INTERNAL_CLASS_LIST_CSA_ADAPTER, \
|
||||
V)
|
||||
|
||||
#define HEAP_IMMOVABLE_OBJECT_LIST(V) \
|
||||
HEAP_MUTABLE_IMMOVABLE_OBJECT_LIST(V) \
|
||||
@ -1942,7 +1947,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
|
||||
Label* if_bailout);
|
||||
TNode<Object> GetConstructor(TNode<Map> map);
|
||||
|
||||
TNode<Map> GetStructMap(InstanceType instance_type);
|
||||
TNode<Map> GetInstanceTypeMap(InstanceType instance_type);
|
||||
|
||||
TNode<FixedArray> AllocateUninitializedFixedArray(intptr_t capacity) {
|
||||
return UncheckedCast<FixedArray>(AllocateFixedArray(
|
||||
|
@ -77,7 +77,7 @@ class PromiseRejectReactionJobTask;
|
||||
class WasmDebugInfo;
|
||||
class Zone;
|
||||
#define MAKE_FORWARD_DECLARATION(V, NAME, Name, name) class Name;
|
||||
TORQUE_STRUCT_LIST_GENERATOR(MAKE_FORWARD_DECLARATION, UNUSED)
|
||||
TORQUE_INTERNAL_CLASS_LIST_GENERATOR(MAKE_FORWARD_DECLARATION, UNUSED)
|
||||
#undef MAKE_FORWARD_DECLARATION
|
||||
|
||||
template <typename T>
|
||||
|
@ -369,7 +369,7 @@ Type::bitset BitsetType::Lub(const MapRefLike& map) {
|
||||
case PROMISE_REJECT_REACTION_JOB_TASK_TYPE:
|
||||
case PROMISE_RESOLVE_THENABLE_JOB_TASK_TYPE:
|
||||
#define MAKE_TORQUE_CLASS_TYPE(V) case V:
|
||||
TORQUE_INTERNAL_INSTANCE_TYPES(MAKE_TORQUE_CLASS_TYPE)
|
||||
TORQUE_INSTANCE_TYPES(MAKE_TORQUE_CLASS_TYPE)
|
||||
#undef MAKE_TORQUE_CLASS_TYPE
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
@ -247,6 +247,7 @@ void HeapObject::HeapObjectVerify(Isolate* isolate) {
|
||||
// Every class that has its fields defined in a .tq file and corresponds
|
||||
// to exactly one InstanceType value is included in the following list.
|
||||
TORQUE_INSTANCE_CHECKERS_SINGLE_FULLY_DEFINED(MAKE_TORQUE_CASE)
|
||||
TORQUE_INSTANCE_CHECKERS_MULTIPLE_FULLY_DEFINED(MAKE_TORQUE_CASE)
|
||||
#undef MAKE_TORQUE_CASE
|
||||
|
||||
case ALLOCATION_SITE_TYPE:
|
||||
|
@ -207,6 +207,7 @@ void HeapObject::HeapObjectPrint(std::ostream& os) { // NOLINT
|
||||
// Every class that has its fields defined in a .tq file and corresponds
|
||||
// to exactly one InstanceType value is included in the following list.
|
||||
TORQUE_INSTANCE_CHECKERS_SINGLE_FULLY_DEFINED(MAKE_TORQUE_CASE)
|
||||
TORQUE_INSTANCE_CHECKERS_MULTIPLE_FULLY_DEFINED(MAKE_TORQUE_CASE)
|
||||
#undef MAKE_TORQUE_CASE
|
||||
|
||||
case ALLOCATION_SITE_TYPE:
|
||||
|
@ -47,7 +47,7 @@ FactoryBase<OffThreadFactory>::NewHeapNumber<AllocationType::kOld>();
|
||||
template <typename Impl>
|
||||
Handle<Struct> FactoryBase<Impl>::NewStruct(InstanceType type,
|
||||
AllocationType allocation) {
|
||||
Map map = Map::GetStructMap(read_only_roots(), type);
|
||||
Map map = Map::GetInstanceTypeMap(read_only_roots(), type);
|
||||
int size = map.instance_size();
|
||||
HeapObject result = AllocateRawWithImmortalMap(size, allocation, map);
|
||||
Handle<Struct> str = handle(Struct::cast(result), isolate());
|
||||
|
@ -103,6 +103,13 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> {
|
||||
public:
|
||||
inline ReadOnlyRoots read_only_roots();
|
||||
|
||||
template <typename T>
|
||||
Handle<T> MakeHandle(T obj) {
|
||||
return handle(obj, isolate());
|
||||
}
|
||||
|
||||
#include "torque-generated/factory-tq.inc"
|
||||
|
||||
Handle<Oddball> NewOddball(Handle<Map> map, const char* to_string,
|
||||
Handle<Object> to_number, const char* type_of,
|
||||
byte kind);
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "src/objects/oddball.h"
|
||||
#include "src/objects/ordered-hash-table.h"
|
||||
#include "src/wasm/wasm-objects.h"
|
||||
#include "torque-generated/objects-body-descriptors-tq-inl.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
@ -43,6 +44,7 @@ ResultType HeapVisitor<ResultType, ConcreteVisitor>::Visit(Map map,
|
||||
return visitor->Visit##TypeName( \
|
||||
map, ConcreteVisitor::template Cast<TypeName>(object));
|
||||
TYPED_VISITOR_ID_LIST(CASE)
|
||||
TORQUE_VISITOR_ID_LIST(CASE)
|
||||
#undef CASE
|
||||
case kVisitShortcutCandidate:
|
||||
return visitor->VisitShortcutCandidate(
|
||||
@ -96,6 +98,7 @@ void HeapVisitor<ResultType, ConcreteVisitor>::VisitMapPointer(
|
||||
return static_cast<ResultType>(size); \
|
||||
}
|
||||
TYPED_VISITOR_ID_LIST(VISIT)
|
||||
TORQUE_VISITOR_ID_LIST(VISIT)
|
||||
#undef VISIT
|
||||
|
||||
template <typename ResultType, typename ConcreteVisitor>
|
||||
|
@ -68,6 +68,7 @@ namespace internal {
|
||||
|
||||
#define FORWARD_DECLARE(TypeName) class TypeName;
|
||||
TYPED_VISITOR_ID_LIST(FORWARD_DECLARE)
|
||||
TORQUE_VISITOR_ID_LIST(FORWARD_DECLARE)
|
||||
#undef FORWARD_DECLARE
|
||||
|
||||
// The base class for visitors that need to dispatch on object type. The default
|
||||
@ -103,6 +104,7 @@ class HeapVisitor : public ObjectVisitor {
|
||||
#define VISIT(TypeName) \
|
||||
V8_INLINE ResultType Visit##TypeName(Map map, TypeName object);
|
||||
TYPED_VISITOR_ID_LIST(VISIT)
|
||||
TORQUE_VISITOR_ID_LIST(VISIT)
|
||||
#undef VISIT
|
||||
V8_INLINE ResultType VisitShortcutCandidate(Map map, ConsString object);
|
||||
V8_INLINE ResultType VisitDataObject(Map map, HeapObject object);
|
||||
|
@ -403,6 +403,18 @@ bool Heap::CreateInitialMaps() {
|
||||
ALLOCATE_VARSIZE_MAP(SMALL_ORDERED_NAME_DICTIONARY_TYPE,
|
||||
small_ordered_name_dictionary)
|
||||
|
||||
#define TORQUE_INTERNAL_CLASS_LIST_MAP_ALLOCATOR(V, NAME, Name, name) \
|
||||
ALLOCATE_MAP(NAME, Name::kSize, name)
|
||||
TORQUE_INTERNAL_FIXED_CLASS_LIST_GENERATOR(
|
||||
TORQUE_INTERNAL_CLASS_LIST_MAP_ALLOCATOR, _);
|
||||
#undef TORQUE_INTERNAL_CLASS_LIST_MAP_ALLOCATOR
|
||||
|
||||
#define TORQUE_INTERNAL_CLASS_LIST_MAP_ALLOCATOR(V, NAME, Name, name) \
|
||||
ALLOCATE_VARSIZE_MAP(NAME, name)
|
||||
TORQUE_INTERNAL_VARSIZE_CLASS_LIST_GENERATOR(
|
||||
TORQUE_INTERNAL_CLASS_LIST_MAP_ALLOCATOR, _);
|
||||
#undef TORQUE_INTERNAL_CLASS_LIST_MAP_ALLOCATOR
|
||||
|
||||
ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, sloppy_arguments_elements)
|
||||
|
||||
ALLOCATE_VARSIZE_MAP(CODE_TYPE, code)
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "src/roots/roots.h"
|
||||
#include "src/utils/ostreams.h"
|
||||
#include "src/zone/zone-containers.h"
|
||||
#include "torque-generated/field-offsets-tq.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
@ -74,7 +75,7 @@ void Map::PrintReconfiguration(Isolate* isolate, FILE* file,
|
||||
os << "]\n";
|
||||
}
|
||||
|
||||
Map Map::GetStructMap(ReadOnlyRoots roots, InstanceType type) {
|
||||
Map Map::GetInstanceTypeMap(ReadOnlyRoots roots, InstanceType type) {
|
||||
Map map;
|
||||
switch (type) {
|
||||
#define MAKE_CASE(TYPE, Name, name) \
|
||||
@ -82,6 +83,12 @@ Map Map::GetStructMap(ReadOnlyRoots roots, InstanceType type) {
|
||||
map = roots.name##_map(); \
|
||||
break;
|
||||
STRUCT_LIST(MAKE_CASE)
|
||||
#undef MAKE_CASE
|
||||
#define MAKE_CASE(_, TYPE, Name, name) \
|
||||
case TYPE: \
|
||||
map = roots.name##_map(); \
|
||||
break;
|
||||
TORQUE_INTERNAL_CLASS_LIST_GENERATOR(MAKE_CASE, _)
|
||||
#undef MAKE_CASE
|
||||
default:
|
||||
UNREACHABLE();
|
||||
@ -360,6 +367,12 @@ VisitorId Map::GetVisitorId(Map map) {
|
||||
case SYNTHETIC_MODULE_TYPE:
|
||||
return kVisitSyntheticModule;
|
||||
|
||||
#define MAKE_TQ_CASE(TYPE, Name) \
|
||||
case TYPE: \
|
||||
return kVisit##Name;
|
||||
TORQUE_BODY_DESCRIPTOR_LIST(MAKE_TQ_CASE)
|
||||
#undef MAKE_TQ_CASE
|
||||
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
@ -84,6 +84,13 @@ enum InstanceType : uint16_t;
|
||||
V(WeakArray) \
|
||||
V(WeakCell)
|
||||
|
||||
#define TORQUE_OBJECT_BODY_TO_VISITOR_ID_LIST_ADAPTER(V, TYPE, TypeName) \
|
||||
V(TypeName)
|
||||
|
||||
#define TORQUE_VISITOR_ID_LIST(V) \
|
||||
TORQUE_BODY_DESCRIPTOR_LIST_GENERATOR( \
|
||||
TORQUE_OBJECT_BODY_TO_VISITOR_ID_LIST_ADAPTER, V)
|
||||
|
||||
// Objects with the same visitor id are processed in the same way by
|
||||
// the heap visitors. The visitor ids for data only objects must precede
|
||||
// other visitor ids. We rely on kDataOnlyVisitorIdCount for quick check
|
||||
@ -92,8 +99,9 @@ enum VisitorId {
|
||||
#define VISITOR_ID_ENUM_DECL(id) kVisit##id,
|
||||
DATA_ONLY_VISITOR_ID_LIST(VISITOR_ID_ENUM_DECL) kDataOnlyVisitorIdCount,
|
||||
POINTER_VISITOR_ID_LIST(VISITOR_ID_ENUM_DECL)
|
||||
TORQUE_VISITOR_ID_LIST(VISITOR_ID_ENUM_DECL)
|
||||
#undef VISITOR_ID_ENUM_DECL
|
||||
kVisitorIdCount
|
||||
kVisitorIdCount
|
||||
};
|
||||
|
||||
enum class ObjectFields {
|
||||
@ -794,7 +802,7 @@ class Map : public HeapObject {
|
||||
|
||||
inline bool CanTransition() const;
|
||||
|
||||
static Map GetStructMap(ReadOnlyRoots roots, InstanceType type);
|
||||
static Map GetInstanceTypeMap(ReadOnlyRoots roots, InstanceType type);
|
||||
|
||||
#define DECL_TESTER(Type, ...) inline bool Is##Type##Map() const;
|
||||
INSTANCE_TYPE_CHECKERS(DECL_TESTER)
|
||||
|
@ -5,6 +5,10 @@
|
||||
#ifndef V8_OBJECTS_OBJECT_LIST_MACROS_H_
|
||||
#define V8_OBJECTS_OBJECT_LIST_MACROS_H_
|
||||
|
||||
#include "torque-generated/instance-types-tq.h"
|
||||
|
||||
#define TORQUE_INTERNAL_CLASS_NAMES_ADAPTER(V, NAME, Name, name) V(Name)
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
@ -233,7 +237,8 @@ class ZoneForwardList;
|
||||
V(WasmTableObject) \
|
||||
V(WeakFixedArray) \
|
||||
V(WeakArrayList) \
|
||||
V(WeakCell)
|
||||
V(WeakCell) \
|
||||
TORQUE_INTERNAL_CLASS_LIST_GENERATOR(TORQUE_INTERNAL_CLASS_NAMES_ADAPTER, V)
|
||||
|
||||
#ifdef V8_INTL_SUPPORT
|
||||
#define HEAP_OBJECT_ORDINARY_TYPE_LIST(V) \
|
||||
|
@ -1100,6 +1100,12 @@ ReturnType BodyDescriptorApply(InstanceType type, T1 p1, T2 p2, T3 p3, T4 p4) {
|
||||
case SYNTHETIC_MODULE_TYPE:
|
||||
return Op::template apply<SyntheticModule::BodyDescriptor>(p1, p2, p3,
|
||||
p4);
|
||||
#define MAKE_TORQUE_BODY_DESCRIPTOR_APPLY(TYPE, TypeName) \
|
||||
case TYPE: \
|
||||
return Op::template apply<TypeName::BodyDescriptor>(p1, p2, p3, p4);
|
||||
TORQUE_BODY_DESCRIPTOR_LIST(MAKE_TORQUE_BODY_DESCRIPTOR_APPLY)
|
||||
#undef MAKE_TORQUE_BODY_DESCRIPTOR_APPLY
|
||||
|
||||
default:
|
||||
PrintF("Unknown type: %d\n", type);
|
||||
UNREACHABLE();
|
||||
|
@ -180,6 +180,10 @@ class SubclassBodyDescriptor final : public BodyDescriptorBase {
|
||||
}
|
||||
};
|
||||
|
||||
#define TORQUE_BODY_DESCRIPTOR_LIST_ADAPTER(V, TYPE, TypeName) V(TYPE, TypeName)
|
||||
#define TORQUE_BODY_DESCRIPTOR_LIST(V) \
|
||||
TORQUE_BODY_DESCRIPTOR_LIST_GENERATOR(TORQUE_BODY_DESCRIPTOR_LIST_ADAPTER, V)
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
|
@ -159,9 +159,7 @@ namespace internal {
|
||||
wasm_indirect_function_table) \
|
||||
V(_, WASM_JS_FUNCTION_DATA_TYPE, WasmJSFunctionData, wasm_js_function_data)
|
||||
|
||||
#define STRUCT_LIST_GENERATOR(V, _) \
|
||||
STRUCT_LIST_GENERATOR_BASE(V, _) \
|
||||
TORQUE_STRUCT_LIST_GENERATOR(V, _)
|
||||
#define STRUCT_LIST_GENERATOR(V, _) STRUCT_LIST_GENERATOR_BASE(V, _)
|
||||
|
||||
// Adapts one STRUCT_LIST_GENERATOR entry to the STRUCT_LIST entry
|
||||
#define STRUCT_LIST_ADAPTER(V, NAME, Name, name) V(NAME, Name, name)
|
||||
@ -176,6 +174,15 @@ namespace internal {
|
||||
// Produces (Map, struct_name_map, StructNameMap) entries
|
||||
#define STRUCT_MAPS_LIST(V) STRUCT_LIST_GENERATOR(STRUCT_MAPS_LIST_ADAPTER, V)
|
||||
|
||||
// Adapts one STRUCT_LIST_GENERATOR entry to the STRUCT_LIST entry
|
||||
#define TORQUE_INTERNAL_CLASS_LIST_MAPS_ADAPTER(V, NAME, Name, name) \
|
||||
V(Map, name##_map, Name##Map)
|
||||
|
||||
// Produces (NAME, Name, name) entries.
|
||||
#define TORQUE_INTERNAL_CLASS_MAPS_LIST(V) \
|
||||
TORQUE_INTERNAL_CLASS_LIST_GENERATOR( \
|
||||
TORQUE_INTERNAL_CLASS_LIST_MAPS_ADAPTER, V)
|
||||
|
||||
//
|
||||
// The following macros define list of allocation size objects and list of
|
||||
// their maps.
|
||||
|
@ -125,6 +125,7 @@
|
||||
|
||||
#include "torque-generated/class-definitions-tq-inl.h"
|
||||
#include "torque-generated/internal-class-definitions-tq-inl.h"
|
||||
#include "torque-generated/objects-body-descriptors-tq-inl.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
@ -2276,6 +2277,14 @@ int HeapObject::SizeFromMap(Map map) const {
|
||||
PreparseData data = PreparseData::unchecked_cast(*this);
|
||||
return PreparseData::SizeFor(data.data_length(), data.children_length());
|
||||
}
|
||||
#define MAKE_TORQUE_SIZE_FOR(TYPE, TypeName) \
|
||||
if (instance_type == TYPE) { \
|
||||
TypeName instance = TypeName::unchecked_cast(*this); \
|
||||
return TypeName::SizeFor(instance); \
|
||||
}
|
||||
TORQUE_BODY_DESCRIPTOR_LIST(MAKE_TORQUE_SIZE_FOR)
|
||||
#undef MAKE_TORQUE_SIZE_FOR
|
||||
|
||||
if (instance_type == CODE_TYPE) {
|
||||
return Code::unchecked_cast(*this).CodeSize();
|
||||
}
|
||||
|
@ -302,14 +302,15 @@ class Symbol;
|
||||
#define ACCESSOR_INFO_ROOT_LIST(V) \
|
||||
ACCESSOR_INFO_LIST_GENERATOR(ACCESSOR_INFO_ROOT_LIST_ADAPTER, V)
|
||||
|
||||
#define READ_ONLY_ROOT_LIST(V) \
|
||||
STRONG_READ_ONLY_ROOT_LIST(V) \
|
||||
INTERNALIZED_STRING_ROOT_LIST(V) \
|
||||
PRIVATE_SYMBOL_ROOT_LIST(V) \
|
||||
PUBLIC_SYMBOL_ROOT_LIST(V) \
|
||||
WELL_KNOWN_SYMBOL_ROOT_LIST(V) \
|
||||
STRUCT_MAPS_LIST(V) \
|
||||
ALLOCATION_SITE_MAPS_LIST(V) \
|
||||
#define READ_ONLY_ROOT_LIST(V) \
|
||||
STRONG_READ_ONLY_ROOT_LIST(V) \
|
||||
INTERNALIZED_STRING_ROOT_LIST(V) \
|
||||
PRIVATE_SYMBOL_ROOT_LIST(V) \
|
||||
PUBLIC_SYMBOL_ROOT_LIST(V) \
|
||||
WELL_KNOWN_SYMBOL_ROOT_LIST(V) \
|
||||
STRUCT_MAPS_LIST(V) \
|
||||
TORQUE_INTERNAL_CLASS_MAPS_LIST(V) \
|
||||
ALLOCATION_SITE_MAPS_LIST(V) \
|
||||
DATA_HANDLER_MAPS_LIST(V)
|
||||
|
||||
#define MUTABLE_ROOT_LIST(V) \
|
||||
|
@ -552,8 +552,7 @@ void ImplementationVisitor::GenerateClassDebugReaders(
|
||||
std::stringstream class_names;
|
||||
|
||||
std::unordered_set<const ClassType*> done;
|
||||
for (const TypeAlias* alias : GlobalContext::GetClasses()) {
|
||||
const ClassType* type = ClassType::DynamicCast(alias->type());
|
||||
for (const ClassType* type : TypeOracle::GetClasses()) {
|
||||
GenerateClassDebugReader(*type, h_contents, cc_contents, visitor,
|
||||
class_names, &done);
|
||||
}
|
||||
|
@ -71,6 +71,7 @@ static const char* const UNINITIALIZED_ITERATOR_TYPE_STRING =
|
||||
"UninitializedIterator";
|
||||
static const char* const GENERIC_TYPE_INSTANTIATION_NAMESPACE_STRING =
|
||||
"_generic_type_instantiation_namespace";
|
||||
static const char* const FIXED_ARRAY_BASE_TYPE_STRING = "FixedArrayBase";
|
||||
|
||||
static const char* const ANNOTATION_GENERATE_PRINT = "@generatePrint";
|
||||
static const char* const ANNOTATION_NO_VERIFIER = "@noVerifier";
|
||||
@ -88,6 +89,9 @@ static const char* const ANNOTATION_INSTANCE_TYPE_VALUE =
|
||||
"@apiExposedInstanceTypeValue";
|
||||
static const char* const ANNOTATION_IF = "@if";
|
||||
static const char* const ANNOTATION_IFNOT = "@ifnot";
|
||||
static const char* const ANNOTATION_GENERATE_BODY_DESCRIPTOR =
|
||||
"@generateBodyDescriptor";
|
||||
static const char* const ANNOTATION_EXPORT_CPP_CLASS = "@export";
|
||||
|
||||
inline bool IsConstexprName(const std::string& name) {
|
||||
return name.substr(0, std::strlen(CONSTEXPR_TYPE_PREFIX)) ==
|
||||
@ -125,6 +129,8 @@ enum class ClassFlag {
|
||||
kHighestInstanceTypeWithinParent = 1 << 9,
|
||||
kLowestInstanceTypeWithinParent = 1 << 10,
|
||||
kUndefinedLayout = 1 << 11,
|
||||
kGenerateBodyDescriptor = 1 << 12,
|
||||
kExport = 1 << 13,
|
||||
};
|
||||
using ClassFlags = base::Flags<ClassFlag>;
|
||||
|
||||
|
@ -35,15 +35,6 @@ class GlobalContext : public ContextualClass<GlobalContext> {
|
||||
return Get().declarables_;
|
||||
}
|
||||
|
||||
static void RegisterClass(const TypeAlias* alias) {
|
||||
DCHECK(alias->ParentScope()->IsNamespace());
|
||||
Get().classes_.push_back(alias);
|
||||
}
|
||||
|
||||
using GlobalClassList = std::vector<const TypeAlias*>;
|
||||
|
||||
static const GlobalClassList& GetClasses() { return Get().classes_; }
|
||||
|
||||
static void AddCppInclude(std::string include_path) {
|
||||
Get().cpp_includes_.insert(std::move(include_path));
|
||||
}
|
||||
@ -84,7 +75,6 @@ class GlobalContext : public ContextualClass<GlobalContext> {
|
||||
std::vector<std::unique_ptr<Declarable>> declarables_;
|
||||
std::set<std::string> cpp_includes_;
|
||||
std::map<SourceId, PerFileStreams> generated_per_file_;
|
||||
GlobalClassList classes_;
|
||||
std::map<std::string, size_t> fresh_ids_;
|
||||
|
||||
friend class LanguageServerData;
|
||||
|
@ -1482,7 +1482,7 @@ VisitResult ImplementationVisitor::Visit(NewExpression* expr) {
|
||||
VisitResult(TypeOracle::GetConstexprInstanceTypeType(),
|
||||
CapifyStringWithUnderscores(class_type->name()) + "_TYPE"));
|
||||
object_map = GenerateCall(
|
||||
QualifiedName({TORQUE_INTERNAL_NAMESPACE_STRING}, "GetStructMap"),
|
||||
QualifiedName({TORQUE_INTERNAL_NAMESPACE_STRING}, "GetInstanceTypeMap"),
|
||||
get_struct_map_arguments, {}, false);
|
||||
CurrentSourcePosition::Scope current_pos(expr->pos);
|
||||
initializer_results.names.insert(initializer_results.names.begin(),
|
||||
@ -3061,9 +3061,9 @@ class FieldOffsetsGenerator {
|
||||
UpdateSection(f);
|
||||
|
||||
// Emit kHeaderSize before any indexed field.
|
||||
// TODO(tebbi): Generalize this code to work with multiple indexed fields.
|
||||
if (f.index.has_value()) {
|
||||
if (f.index.has_value() && !header_size_emitted_) {
|
||||
WriteMarker("kHeaderSize");
|
||||
header_size_emitted_ = true;
|
||||
}
|
||||
|
||||
// We don't know statically how much space an indexed field takes, so report
|
||||
@ -3165,6 +3165,7 @@ class FieldOffsetsGenerator {
|
||||
FieldSectionType current_section_ = FieldSectionType::kNoSection;
|
||||
FieldSections completed_sections_ = FieldSectionType::kNoSection;
|
||||
bool is_finished_ = false;
|
||||
bool header_size_emitted_ = false;
|
||||
};
|
||||
|
||||
class MacroFieldOffsetsGenerator : public FieldOffsetsGenerator {
|
||||
@ -3187,48 +3188,23 @@ class MacroFieldOffsetsGenerator : public FieldOffsetsGenerator {
|
||||
std::ostream& out_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
void ImplementationVisitor::GenerateCppForInternalClasses(
|
||||
const std::string& output_directory) {
|
||||
std::stringstream header;
|
||||
std::stringstream inl;
|
||||
std::string base_name = "internal-class-definitions-tq";
|
||||
{
|
||||
IncludeGuardScope header_guard(header, base_name + ".h");
|
||||
header << "#include \"src/objects/objects.h\"\n";
|
||||
header << "#include \"src/objects/struct.h\"\n";
|
||||
header << "#include \"src/objects/js-objects.h\"\n";
|
||||
header << "#include \"src/utils/utils.h\"\n";
|
||||
header << "#include \"torque-generated/class-definitions-tq.h\"\n";
|
||||
IncludeObjectMacrosScope header_macros(header);
|
||||
NamespaceScope header_namespaces(header, {"v8", "internal"});
|
||||
|
||||
IncludeGuardScope inl_guard(inl, base_name + "-inl.h");
|
||||
inl << "#include \"torque-generated/" << base_name << ".h\"\n";
|
||||
inl << "#include \"torque-generated/class-definitions-tq-inl.h\"\n";
|
||||
IncludeObjectMacrosScope inl_macros(inl);
|
||||
NamespaceScope inl_namespaces(inl, {"v8", "internal"});
|
||||
|
||||
for (const TypeAlias* alias : GlobalContext::GetClasses()) {
|
||||
const ClassType* type = ClassType::DynamicCast(alias->type());
|
||||
if (type->IsExtern()) continue;
|
||||
const ClassType* super = type->GetSuperClass();
|
||||
std::string parent = "TorqueGenerated" + type->name() + "<" +
|
||||
type->name() + ", " + super->name() + ">";
|
||||
header << "class " << type->name() << ": public " << parent << " {\n";
|
||||
header << " public:\n";
|
||||
header << " TQ_OBJECT_CONSTRUCTORS(" << type->name() << ")\n";
|
||||
header << "};\n\n";
|
||||
|
||||
inl << "TQ_OBJECT_CONSTRUCTORS_IMPL(" << type->name() << ")\n";
|
||||
}
|
||||
void GenerateClassExport(const ClassType* type, std::ostream& header,
|
||||
std::ostream& inl_header) {
|
||||
const ClassType* super = type->GetSuperClass();
|
||||
std::string parent = "TorqueGenerated" + type->name() + "<" + type->name() +
|
||||
", " + super->name() + ">";
|
||||
header << "class " << type->name() << " : public " << parent << " {\n";
|
||||
header << " public:\n";
|
||||
if (type->ShouldGenerateBodyDescriptor()) {
|
||||
header << " class BodyDescriptor;\n";
|
||||
}
|
||||
std::string dir_basename = output_directory + "/" + base_name;
|
||||
WriteFile(dir_basename + ".h", header.str());
|
||||
WriteFile(dir_basename + "-inl.h", inl.str());
|
||||
header << " TQ_OBJECT_CONSTRUCTORS(" << type->name() << ")\n";
|
||||
header << "};\n\n";
|
||||
inl_header << "TQ_OBJECT_CONSTRUCTORS_IMPL(" << type->name() << ")\n";
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void ImplementationVisitor::GenerateClassFieldOffsets(
|
||||
const std::string& output_directory) {
|
||||
std::stringstream header;
|
||||
@ -3236,9 +3212,7 @@ void ImplementationVisitor::GenerateClassFieldOffsets(
|
||||
{
|
||||
IncludeGuardScope include_guard(header, file_name);
|
||||
|
||||
for (const TypeAlias* alias : GlobalContext::GetClasses()) {
|
||||
const ClassType* type = ClassType::DynamicCast(alias->type());
|
||||
|
||||
for (const ClassType* type : TypeOracle::GetClasses()) {
|
||||
// TODO(danno): Remove this once all classes use ClassFieldOffsetGenerator
|
||||
// to generate field offsets without the use of macros.
|
||||
if (!type->GenerateCppClassDefinitions() && !type->HasUndefinedLayout()) {
|
||||
@ -3251,6 +3225,16 @@ void ImplementationVisitor::GenerateClassFieldOffsets(
|
||||
header << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
header << "#define TORQUE_BODY_DESCRIPTOR_LIST_GENERATOR(V, _)\\\n";
|
||||
for (const ClassType* type : TypeOracle::GetClasses()) {
|
||||
if (type->ShouldGenerateBodyDescriptor()) {
|
||||
std::string type_name =
|
||||
CapifyStringWithUnderscores(type->name()) + "_TYPE";
|
||||
header << "V(_, " << type_name << ", " << type->name() << ")\\\n";
|
||||
}
|
||||
}
|
||||
header << "\n";
|
||||
}
|
||||
const std::string output_header_path = output_directory + "/" + file_name;
|
||||
WriteFile(output_header_path, header.str());
|
||||
@ -3366,6 +3350,29 @@ class CppClassGenerator {
|
||||
std::ostream& impl_;
|
||||
};
|
||||
|
||||
base::Optional<std::vector<Field>> GetOrderedUniqueIndexFields(
|
||||
const ClassType& type) {
|
||||
std::vector<Field> result;
|
||||
std::set<std::string> index_names;
|
||||
for (const Field& field : type.ComputeAllFields()) {
|
||||
if (field.index) {
|
||||
auto name_and_type = ExtractSimpleFieldArraySize(type, *field.index);
|
||||
if (!name_and_type) {
|
||||
return base::nullopt;
|
||||
}
|
||||
index_names.insert(name_and_type->name);
|
||||
}
|
||||
}
|
||||
|
||||
for (const Field& field : type.ComputeAllFields()) {
|
||||
if (index_names.count(field.name_and_type.name) != 0) {
|
||||
result.push_back(field);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void CppClassGenerator::GenerateClass() {
|
||||
hdr_ << template_decl() << "\n";
|
||||
hdr_ << "class " << gen_name_ << " : public P {\n";
|
||||
@ -3375,10 +3382,16 @@ void CppClassGenerator::GenerateClass() {
|
||||
<< " \"Pass in " << super_->name()
|
||||
<< " as second template parameter for " << gen_name_ << ".\");\n";
|
||||
hdr_ << " public: \n";
|
||||
hdr_ << " using Super = P;\n";
|
||||
hdr_ << " using Super = P;\n\n";
|
||||
if (!type_->ShouldExport() && !type_->IsExtern()) {
|
||||
hdr_ << " protected: // not extern or @export\n";
|
||||
}
|
||||
for (const Field& f : type_->fields()) {
|
||||
GenerateFieldAccessor(f);
|
||||
}
|
||||
if (!type_->ShouldExport() && !type_->IsExtern()) {
|
||||
hdr_ << " public:\n";
|
||||
}
|
||||
|
||||
GenerateClassCasts();
|
||||
|
||||
@ -3410,9 +3423,82 @@ void CppClassGenerator::GenerateClass() {
|
||||
g.Finish();
|
||||
hdr_ << "\n";
|
||||
|
||||
auto index_fields = GetOrderedUniqueIndexFields(*type_);
|
||||
|
||||
if (!index_fields.has_value()) {
|
||||
hdr_ << " // SizeFor implementations not generated due to complex array "
|
||||
"lengths\n\n";
|
||||
} else if (!type_->IsAbstract() &&
|
||||
!type_->IsSubtypeOf(TypeOracle::GetJSObjectType())) {
|
||||
hdr_ << " V8_INLINE static constexpr int32_t SizeFor(";
|
||||
bool first = true;
|
||||
for (const Field& field : *index_fields) {
|
||||
if (!first) hdr_ << ", ";
|
||||
hdr_ << field.name_and_type.type->HandlifiedCppTypeName() << " "
|
||||
<< field.name_and_type.name;
|
||||
first = false;
|
||||
}
|
||||
hdr_ << ") {\n";
|
||||
if (index_fields->empty()) {
|
||||
hdr_ << " DCHECK(kHeaderSize == kSize && kHeaderSize == "
|
||||
<< *type_->size().SingleValue() << ");\n";
|
||||
}
|
||||
hdr_ << " int32_t size = kHeaderSize;\n";
|
||||
for (const Field& field : type_->ComputeAllFields()) {
|
||||
if (field.index) {
|
||||
auto index_name_and_type =
|
||||
*ExtractSimpleFieldArraySize(*type_, *field.index);
|
||||
size_t field_size = 0;
|
||||
std::tie(field_size, std::ignore) = field.GetFieldSizeInformation();
|
||||
hdr_ << " size += ";
|
||||
auto index_field = std::find_if(
|
||||
index_fields->begin(), index_fields->end(),
|
||||
[&](const Field& field) {
|
||||
return field.name_and_type.name == index_name_and_type.name;
|
||||
});
|
||||
if (index_field->name_and_type.type->IsSubtypeOf(
|
||||
TypeOracle::GetSmiType())) {
|
||||
hdr_ << "Smi::ToInt(" << index_name_and_type.name << ")";
|
||||
} else {
|
||||
hdr_ << index_name_and_type.name;
|
||||
}
|
||||
hdr_ << " * " << field_size << ";\n";
|
||||
}
|
||||
}
|
||||
hdr_ << " return size;\n";
|
||||
hdr_ << " }\n\n";
|
||||
hdr_ << " V8_INLINE static constexpr int32_t SizeFor(D o) {\n";
|
||||
hdr_ << " return SizeFor(";
|
||||
first = true;
|
||||
for (auto field : *index_fields) {
|
||||
if (!first) hdr_ << ", ";
|
||||
// Subclasses of FixedArrayBase need to use the synchronized length
|
||||
// accessor to be consistent (theoretically, FixedArrayBase classes
|
||||
// can concurrently change size e.g. through left-trimming, although
|
||||
// in practice this won't happen for Torque-generated classes) as well as
|
||||
// explicitly convert to a Smi, since the C++-side accessors are
|
||||
// int-based.
|
||||
if (field.aggregate == TypeOracle::GetFixedArrayBaseType() &&
|
||||
field.name_and_type.name == "length") {
|
||||
hdr_ << "Smi::FromInt(o.synchronized_length())";
|
||||
} else {
|
||||
hdr_ << "o." << field.name_and_type.name << "()";
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
hdr_ << ");\n }\n";
|
||||
hdr_ << "\n";
|
||||
}
|
||||
|
||||
hdr_ << " friend class Factory;\n\n";
|
||||
|
||||
GenerateClassConstructors();
|
||||
|
||||
hdr_ << "};\n\n";
|
||||
|
||||
if (!type_->IsExtern()) {
|
||||
GenerateClassExport(type_, hdr_, inl_);
|
||||
}
|
||||
}
|
||||
|
||||
void CppClassGenerator::GenerateClassCasts() {
|
||||
@ -3448,7 +3534,11 @@ void CppClassGenerator::GenerateClassConstructors() {
|
||||
// TODO(sigurds): Keep in sync with DECL_ACCESSORS and ACCESSORS macro.
|
||||
void CppClassGenerator::GenerateFieldAccessor(const Field& f) {
|
||||
const Type* field_type = f.name_and_type.type;
|
||||
if (field_type == TypeOracle::GetVoidType() || f.index.has_value()) return;
|
||||
if (field_type == TypeOracle::GetVoidType()) return;
|
||||
|
||||
// TODO(danno): Support generation of struct accessors
|
||||
if (f.name_and_type.type->IsStructType()) return;
|
||||
|
||||
if (!f.name_and_type.type->IsSubtypeOf(TypeOracle::GetTaggedType())) {
|
||||
return GenerateFieldAccessorForUntagged(f);
|
||||
}
|
||||
@ -3460,7 +3550,8 @@ void CppClassGenerator::GenerateFieldAccessor(const Field& f) {
|
||||
}
|
||||
|
||||
Error("Generation of field accessor for ", type_->name(),
|
||||
":: ", f.name_and_type.name, " : ", *field_type, " is not supported.")
|
||||
"::", f.name_and_type.name, " failed (type ", *field_type,
|
||||
" is not supported).")
|
||||
.Position(f.pos);
|
||||
}
|
||||
|
||||
@ -3479,24 +3570,53 @@ void CppClassGenerator::GenerateFieldAccessorForUntagged(const Field& f) {
|
||||
}
|
||||
const std::string& name = f.name_and_type.name;
|
||||
const std::string type = constexpr_version->GetGeneratedTypeName();
|
||||
const std::string offset = "k" + CamelifyString(name) + "Offset";
|
||||
std::string offset = "k" + CamelifyString(name) + "Offset";
|
||||
|
||||
// Generate declarations in header.
|
||||
hdr_ << " inline " << type << " " << name << "() const;\n";
|
||||
hdr_ << " inline void set_" << name << "(" << type << " value);\n\n";
|
||||
if (f.index) {
|
||||
hdr_ << " inline " << type << " " << name << "(int i) const;\n";
|
||||
hdr_ << " inline void set_" << name << "(int i, " << type
|
||||
<< " value);\n\n";
|
||||
} else {
|
||||
hdr_ << " inline " << type << " " << name << "() const;\n";
|
||||
hdr_ << " inline void set_" << name << "(" << type << " value);\n\n";
|
||||
}
|
||||
|
||||
// Generate implementation in inline header.
|
||||
inl_ << "template <class D, class P>\n";
|
||||
inl_ << type << " " << gen_name_ << "<D, P>::" << name << "() const {\n";
|
||||
inl_ << " return this->template ReadField<" << type << ">(" << offset
|
||||
<< ");\n";
|
||||
inl_ << type << " " << gen_name_ << "<D, P>::" << name << "(";
|
||||
if (f.index) {
|
||||
inl_ << "int i";
|
||||
}
|
||||
inl_ << ") const {\n";
|
||||
if (f.index) {
|
||||
size_t field_size;
|
||||
std::string size_string;
|
||||
std::tie(field_size, size_string) = f.GetFieldSizeInformation();
|
||||
inl_ << " int offset = " << offset << " + i * " << field_size << ";\n";
|
||||
inl_ << " return this->template ReadField<" << type << ">(offset);\n";
|
||||
} else {
|
||||
inl_ << " return this->template ReadField<" << type << ">(" << offset
|
||||
<< ");\n";
|
||||
}
|
||||
inl_ << "}\n";
|
||||
|
||||
inl_ << "template <class D, class P>\n";
|
||||
inl_ << "void " << gen_name_ << "<D, P>::set_" << name << "(" << type
|
||||
<< " value) {\n";
|
||||
inl_ << " this->template WriteField<" << type << ">(" << offset
|
||||
<< ", value);\n";
|
||||
inl_ << "void " << gen_name_ << "<D, P>::set_" << name << "(";
|
||||
if (f.index) {
|
||||
inl_ << "int i, ";
|
||||
}
|
||||
inl_ << type << " value) {\n";
|
||||
if (f.index) {
|
||||
size_t field_size;
|
||||
std::string size_string;
|
||||
std::tie(field_size, size_string) = f.GetFieldSizeInformation();
|
||||
inl_ << " int offset = " << offset << " + i * " << field_size << ";\n";
|
||||
inl_ << " this->template WriteField<" << type << ">(offset, value);\n";
|
||||
} else {
|
||||
inl_ << " this->template WriteField<" << type << ">(" << offset
|
||||
<< ", value);\n";
|
||||
}
|
||||
inl_ << "}\n\n";
|
||||
}
|
||||
|
||||
@ -3507,20 +3627,43 @@ void CppClassGenerator::GenerateFieldAccessorForSmi(const Field& f) {
|
||||
const std::string offset = "k" + CamelifyString(name) + "Offset";
|
||||
|
||||
// Generate declarations in header.
|
||||
if (f.index) {
|
||||
hdr_ << " inline " << type << " " << name << "(int i) const;\n";
|
||||
hdr_ << " inline void set_" << name << "(int i, " << type
|
||||
<< " value);\n\n";
|
||||
}
|
||||
hdr_ << " inline " << type << " " << name << "() const;\n";
|
||||
hdr_ << " inline void set_" << name << "(" << type << " value);\n\n";
|
||||
|
||||
// Generate implementation in inline header.
|
||||
inl_ << "template <class D, class P>\n";
|
||||
inl_ << type << " " << gen_name_ << "<D, P>::" << name << "() const {\n";
|
||||
inl_ << " return TaggedField<Smi, " << offset << ">::load(*this);\n";
|
||||
inl_ << "}\n";
|
||||
inl_ << type << " " << gen_name_ << "<D, P>::" << name << "(";
|
||||
if (f.index) {
|
||||
inl_ << "int i";
|
||||
}
|
||||
inl_ << ") const {\n";
|
||||
if (f.index) {
|
||||
inl_ << " int offset = " << offset << " + i * kTaggedSize;\n";
|
||||
inl_ << " return this->template ReadField<Smi>(offset);\n";
|
||||
inl_ << "}\n";
|
||||
} else {
|
||||
inl_ << " return TaggedField<Smi, " << offset << ">::load(*this);\n";
|
||||
inl_ << "}\n";
|
||||
}
|
||||
|
||||
inl_ << "template <class D, class P>\n";
|
||||
inl_ << "void " << gen_name_ << "<D, P>::set_" << name << "(" << type
|
||||
<< " value) {\n";
|
||||
inl_ << "void " << gen_name_ << "<D, P>::set_" << name << "(";
|
||||
if (f.index) {
|
||||
inl_ << "int i, ";
|
||||
}
|
||||
inl_ << type << " value) {\n";
|
||||
inl_ << " DCHECK(value.IsSmi());\n";
|
||||
inl_ << " WRITE_FIELD(*this, " << offset << ", value);\n";
|
||||
if (f.index) {
|
||||
inl_ << " int offset = " << offset << " + i * kTaggedSize;\n";
|
||||
inl_ << " WRITE_FIELD(*this, offset, value);\n";
|
||||
} else {
|
||||
inl_ << " WRITE_FIELD(*this, " << offset << ", value);\n";
|
||||
}
|
||||
inl_ << "}\n\n";
|
||||
}
|
||||
|
||||
@ -3538,11 +3681,13 @@ void CppClassGenerator::GenerateFieldAccessorForObject(const Field& f) {
|
||||
if (!class_type && field_type != TypeOracle::GetObjectType()) {
|
||||
hdr_ << " // Torque type: " << field_type->ToString() << "\n";
|
||||
}
|
||||
hdr_ << " inline " << type << " " << name << "() const;\n";
|
||||
hdr_ << " inline " << type << " " << name
|
||||
<< "(const Isolate* isolate) const;\n";
|
||||
hdr_ << " inline void set_" << name << "(" << type
|
||||
<< " value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER);\n\n";
|
||||
|
||||
hdr_ << " inline " << type << " " << name << "(" << (f.index ? "int i" : "")
|
||||
<< ") const;\n";
|
||||
hdr_ << " inline " << type << " " << name << "(const Isolate* isolates"
|
||||
<< (f.index ? ", int i" : "") << ") const;\n";
|
||||
hdr_ << " inline void set_" << name << "(" << (f.index ? "int i, " : "")
|
||||
<< type << " value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER);\n\n";
|
||||
|
||||
std::string type_check;
|
||||
for (const RuntimeType& runtime_type : field_type->GetRuntimeTypes()) {
|
||||
@ -3552,36 +3697,89 @@ void CppClassGenerator::GenerateFieldAccessorForObject(const Field& f) {
|
||||
|
||||
// Generate implementation in inline header.
|
||||
inl_ << "template <class D, class P>\n";
|
||||
inl_ << type << " " << gen_name_ << "<D, P>::" << name << "() const {\n";
|
||||
inl_ << type << " " << gen_name_ << "<D, P>::" << name << "("
|
||||
<< (f.index ? "int i" : "") << ") const {\n";
|
||||
inl_ << " const Isolate* isolate = GetIsolateForPtrCompr(*this);\n";
|
||||
inl_ << " return " << gen_name_ << "::" << name << "(isolate);\n";
|
||||
inl_ << " return " << gen_name_ << "::" << name << "(isolate"
|
||||
<< (f.index ? ", i" : "") << ");\n";
|
||||
inl_ << "}\n";
|
||||
|
||||
inl_ << "template <class D, class P>\n";
|
||||
inl_ << type << " " << gen_name_ << "<D, P>::" << name
|
||||
<< "(const Isolate* isolate) const {\n";
|
||||
<< "(const Isolate* isolate" << (f.index ? ", int i" : "")
|
||||
<< ") const {\n";
|
||||
|
||||
if (class_type) {
|
||||
inl_ << " return TaggedField<" << type << ", " << offset
|
||||
<< ">::load(isolate, *this);\n";
|
||||
if (f.index) {
|
||||
inl_ << " int offset = " << offset << " + i * kTaggedSize;\n";
|
||||
inl_ << " return " << type
|
||||
<< "::cast(RELAXED_READ_FIELD(*this, offset));\n";
|
||||
} else {
|
||||
inl_ << " return TaggedField<" << type << ", " << offset
|
||||
<< ">::load(isolate, *this);\n";
|
||||
}
|
||||
} else {
|
||||
// TODO(tebbi): load value as HeapObject when possible
|
||||
inl_ << " Object value = TaggedField<Object, " << offset
|
||||
<< ">::load(isolate, *this);\n";
|
||||
if (f.index) {
|
||||
inl_ << " int offset = " << offset << " + i * kTaggedSize;\n";
|
||||
inl_ << " Object value = Object::cast(RELAXED_READ_FIELD(*this, "
|
||||
"offset));\n";
|
||||
} else {
|
||||
inl_ << " Object value = TaggedField<Object, " << offset
|
||||
<< ">::load(isolate, *this);\n";
|
||||
}
|
||||
inl_ << " DCHECK(" << type_check << ");\n";
|
||||
inl_ << " return value;\n";
|
||||
}
|
||||
inl_ << "}\n";
|
||||
|
||||
inl_ << "template <class D, class P>\n";
|
||||
inl_ << "void " << gen_name_ << "<D, P>::set_" << name << "(" << type
|
||||
<< " value, WriteBarrierMode mode) {\n";
|
||||
inl_ << "void " << gen_name_ << "<D, P>::set_" << name << "(";
|
||||
if (f.index) {
|
||||
inl_ << "int i, ";
|
||||
}
|
||||
inl_ << type << " value, WriteBarrierMode mode) {\n";
|
||||
inl_ << " SLOW_DCHECK(" << type_check << ");\n";
|
||||
inl_ << " WRITE_FIELD(*this, " << offset << ", value);\n";
|
||||
if (f.index) {
|
||||
inl_ << " int offset = " << offset << " + i * kTaggedSize;\n";
|
||||
inl_ << " WRITE_FIELD(*this, offset, value);\n";
|
||||
} else {
|
||||
inl_ << " WRITE_FIELD(*this, " << offset << ", value);\n";
|
||||
}
|
||||
inl_ << " CONDITIONAL_WRITE_BARRIER(*this, " << offset
|
||||
<< ", value, mode);\n";
|
||||
inl_ << "}\n\n";
|
||||
}
|
||||
|
||||
void EmitClassDefinitionHeadersIncludes(const std::string& basename,
|
||||
std::stringstream& header,
|
||||
std::stringstream& inline_header) {
|
||||
header << "#include \"src/objects/fixed-array.h\"\n";
|
||||
header << "#include \"src/objects/objects.h\"\n";
|
||||
header << "#include \"src/objects/smi.h\"\n";
|
||||
header << "#include \"torque-generated/field-offsets-tq.h\"\n";
|
||||
header << "#include <type_traits>\n\n";
|
||||
|
||||
inline_header << "#include \"torque-generated/class-definitions-tq.h\"\n";
|
||||
inline_header << "#include "
|
||||
"\"torque-generated/objects-body-descriptors-tq-inl.h\"\n\n";
|
||||
inline_header << "#include \"src/objects/js-promise.h\"\n";
|
||||
inline_header << "#include \"src/objects/js-weak-refs.h\"\n";
|
||||
inline_header << "#include \"src/objects/module.h\"\n";
|
||||
inline_header << "#include \"src/objects/objects-inl.h\"\n";
|
||||
inline_header << "#include \"src/objects/script.h\"\n";
|
||||
inline_header << "#include \"src/objects/shared-function-info.h\"\n";
|
||||
inline_header << "#include \"src/objects/tagged-field.h\"\n\n";
|
||||
}
|
||||
|
||||
void EmitClassDefinitionHeadersForwardDeclarations(std::stringstream& header) {
|
||||
// Generate forward declarations for every class.
|
||||
for (const ClassType* type : TypeOracle::GetClasses()) {
|
||||
header << "class " << type->GetGeneratedTNodeTypeName() << ";\n";
|
||||
}
|
||||
header << "using BuiltinPtr = Smi;\n\n";
|
||||
}
|
||||
|
||||
void GenerateStructLayoutDescription(std::ostream& header,
|
||||
const StructType* type) {
|
||||
header << "struct TorqueGenerated" << CamelifyString(type->name())
|
||||
@ -3599,32 +3797,70 @@ void GenerateStructLayoutDescription(std::ostream& header,
|
||||
|
||||
void ImplementationVisitor::GenerateClassDefinitions(
|
||||
const std::string& output_directory) {
|
||||
std::stringstream header;
|
||||
std::stringstream inline_header;
|
||||
std::stringstream external_header;
|
||||
std::stringstream inline_external_header;
|
||||
std::stringstream internal_header;
|
||||
std::stringstream inline_internal_header;
|
||||
std::stringstream implementation;
|
||||
std::stringstream factory_header;
|
||||
std::stringstream factory_impl;
|
||||
std::string basename = "class-definitions-tq";
|
||||
std::string internal_basename = "internal-" + basename;
|
||||
std::string file_basename = output_directory + "/" + basename;
|
||||
std::string internal_file_basename =
|
||||
output_directory + "/" + internal_basename;
|
||||
std::string factory_basename = "factory-tq";
|
||||
std::string factory_file_basename = output_directory + "/" + factory_basename;
|
||||
|
||||
{
|
||||
IncludeGuardScope header_guard(header, basename + ".h");
|
||||
header << "#include \"src/objects/objects.h\"\n";
|
||||
header << "#include \"src/objects/smi.h\"\n";
|
||||
header << "#include \"torque-generated/field-offsets-tq.h\"\n";
|
||||
header << "#include <type_traits>\n\n";
|
||||
IncludeObjectMacrosScope header_macros(header);
|
||||
NamespaceScope header_namespaces(header, {"v8", "internal"});
|
||||
header << "using BuiltinPtr = Smi;\n\n";
|
||||
IncludeGuardScope header_guard(external_header, basename + ".h");
|
||||
|
||||
IncludeGuardScope inline_header_guard(inline_header, basename + "-inl.h");
|
||||
inline_header << "#include \"torque-generated/class-definitions-tq.h\"\n\n";
|
||||
inline_header << "#include \"src/objects/js-promise.h\"\n";
|
||||
inline_header << "#include \"src/objects/js-weak-refs.h\"\n";
|
||||
inline_header << "#include \"src/objects/module.h\"\n";
|
||||
inline_header << "#include \"src/objects/objects-inl.h\"\n";
|
||||
inline_header << "#include \"src/objects/script.h\"\n";
|
||||
inline_header << "#include \"src/objects/shared-function-info.h\"\n\n";
|
||||
IncludeObjectMacrosScope inline_header_macros(inline_header);
|
||||
NamespaceScope inline_header_namespaces(inline_header, {"v8", "internal"});
|
||||
IncludeGuardScope inline_header_guard(inline_external_header,
|
||||
basename + "-inl.h");
|
||||
|
||||
IncludeGuardScope internal_header_guard(internal_header,
|
||||
internal_basename + ".h");
|
||||
|
||||
IncludeGuardScope internal_inline_header_guard(
|
||||
inline_internal_header, internal_basename + "-inl.h");
|
||||
|
||||
external_header
|
||||
<< "#include \"torque-generated/internal-class-definitions-tq.h\"\n";
|
||||
|
||||
EmitClassDefinitionHeadersIncludes(basename, external_header,
|
||||
inline_external_header);
|
||||
|
||||
EmitClassDefinitionHeadersIncludes(internal_basename, internal_header,
|
||||
inline_internal_header);
|
||||
|
||||
IncludeObjectMacrosScope header_macros(external_header);
|
||||
IncludeObjectMacrosScope inline_header_macros(inline_external_header);
|
||||
|
||||
IncludeObjectMacrosScope internal_header_macros(internal_header);
|
||||
IncludeObjectMacrosScope internal_inline_header_macros(
|
||||
inline_internal_header);
|
||||
|
||||
NamespaceScope header_namespaces(external_header, {"v8", "internal"});
|
||||
NamespaceScope inline_header_namespaces(inline_external_header,
|
||||
{"v8", "internal"});
|
||||
NamespaceScope internal_header_namespaces(internal_header,
|
||||
{"v8", "internal"});
|
||||
NamespaceScope internal_inline_header_namespaces(inline_internal_header,
|
||||
{"v8", "internal"});
|
||||
|
||||
EmitClassDefinitionHeadersForwardDeclarations(external_header);
|
||||
EmitClassDefinitionHeadersForwardDeclarations(internal_header);
|
||||
|
||||
factory_impl << "#include \"src/heap/factory.h\"\n";
|
||||
factory_impl << "#include \"src/heap/factory-inl.h\"\n";
|
||||
factory_impl << "#include \"src/heap/heap.h\"\n";
|
||||
factory_impl << "#include \"src/heap/heap-inl.h\"\n";
|
||||
factory_impl << "#include \"src/execution/isolate.h\"\n\n";
|
||||
factory_impl
|
||||
<< "#include "
|
||||
"\"torque-generated/internal-class-definitions-tq-inl.h\"\n\n";
|
||||
NamespaceScope factory_impl_namespaces(factory_impl, {"v8", "internal"});
|
||||
factory_impl << "\n";
|
||||
|
||||
implementation
|
||||
<< "#include \"torque-generated/class-definitions-tq.h\"\n\n";
|
||||
@ -3652,16 +3888,16 @@ void ImplementationVisitor::GenerateClassDefinitions(
|
||||
NamespaceScope implementation_namespaces(implementation,
|
||||
{"v8", "internal"});
|
||||
|
||||
// Generate forward declarations for every class.
|
||||
for (const TypeAlias* alias : GlobalContext::GetClasses()) {
|
||||
const ClassType* type = ClassType::DynamicCast(alias->type());
|
||||
header << "class " << type->GetGeneratedTNodeTypeName() << ";\n";
|
||||
}
|
||||
|
||||
std::unordered_set<const StructType*> structs_used_in_classes;
|
||||
|
||||
for (const TypeAlias* alias : GlobalContext::GetClasses()) {
|
||||
const ClassType* type = ClassType::DynamicCast(alias->type());
|
||||
for (const ClassType* type : TypeOracle::GetClasses()) {
|
||||
std::stringstream& header = (type->IsExtern() || type->ShouldExport())
|
||||
? external_header
|
||||
: internal_header;
|
||||
std::stringstream& inline_header =
|
||||
(type->IsExtern() || type->ShouldExport()) ? inline_external_header
|
||||
: inline_internal_header;
|
||||
|
||||
if (type->GenerateCppClassDefinitions()) {
|
||||
CppClassGenerator g(type, header, inline_header, implementation);
|
||||
g.GenerateClass();
|
||||
@ -3673,17 +3909,92 @@ void ImplementationVisitor::GenerateClassDefinitions(
|
||||
structs_used_in_classes.insert(field_as_struct);
|
||||
}
|
||||
}
|
||||
if (type->ShouldExport()) {
|
||||
factory_header << type->HandlifiedCppTypeName() << " New"
|
||||
<< type->name() << "(";
|
||||
factory_impl << type->HandlifiedCppTypeName() << " Factory::New"
|
||||
<< type->name() << "(";
|
||||
|
||||
for (const Field& f : type->ComputeAllFields()) {
|
||||
if (f.name_and_type.name == "map") continue;
|
||||
if (!f.index) {
|
||||
std::string type_string =
|
||||
f.name_and_type.type->HandlifiedCppTypeName();
|
||||
factory_header << type_string << " " << f.name_and_type.name
|
||||
<< ", ";
|
||||
factory_impl << type_string << " " << f.name_and_type.name << ", ";
|
||||
}
|
||||
}
|
||||
|
||||
factory_header << "AllocationType allocation_type);\n";
|
||||
factory_impl << "AllocationType allocation_type) {\n";
|
||||
|
||||
factory_impl << " int size = ";
|
||||
const ClassType* super = type->GetSuperClass();
|
||||
std::string gen_name = "TorqueGenerated" + type->name();
|
||||
std::string gen_name_T =
|
||||
gen_name + "<" + type->name() + ", " + super->name() + ">";
|
||||
factory_impl << gen_name_T << "::SizeFor(";
|
||||
|
||||
bool first = true;
|
||||
auto index_fields = GetOrderedUniqueIndexFields(*type);
|
||||
CHECK(index_fields.has_value());
|
||||
for (auto index_field : *index_fields) {
|
||||
if (!first) {
|
||||
factory_impl << ", ";
|
||||
}
|
||||
factory_impl << index_field.name_and_type.name;
|
||||
first = false;
|
||||
}
|
||||
|
||||
factory_impl << ");\n";
|
||||
factory_impl << " ReadOnlyRoots roots(isolate());\n";
|
||||
factory_impl << " HeapObject result =\n";
|
||||
factory_impl << " "
|
||||
"isolate()->heap()->AllocateRawWith<Heap::kRetryOrFail>"
|
||||
"(size, allocation_type);\n";
|
||||
factory_impl << " result.set_map_after_allocation(roots."
|
||||
<< SnakeifyString(type->name())
|
||||
<< "_map(), SKIP_WRITE_BARRIER);\n";
|
||||
factory_impl << " " << type->HandlifiedCppTypeName()
|
||||
<< " result_handle(" << type->name()
|
||||
<< "::cast(result), isolate());\n";
|
||||
|
||||
for (const Field& f : type->ComputeAllFields()) {
|
||||
if (f.name_and_type.name == "map") continue;
|
||||
if (!f.index) {
|
||||
factory_impl << " result_handle->set_"
|
||||
<< SnakeifyString(f.name_and_type.name) << "(";
|
||||
if (f.name_and_type.type->IsSubtypeOf(
|
||||
TypeOracle::GetTaggedType()) &&
|
||||
!f.name_and_type.type->IsSubtypeOf(TypeOracle::GetSmiType())) {
|
||||
factory_impl << "*" << f.name_and_type.name
|
||||
<< ", SKIP_WRITE_BARRIER";
|
||||
} else {
|
||||
factory_impl << f.name_and_type.name;
|
||||
}
|
||||
factory_impl << ");\n";
|
||||
}
|
||||
}
|
||||
|
||||
factory_impl << " return result_handle;\n";
|
||||
factory_impl << "}\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
for (const StructType* type : structs_used_in_classes) {
|
||||
if (type != TypeOracle::GetFloat64OrHoleType()) {
|
||||
GenerateStructLayoutDescription(header, type);
|
||||
GenerateStructLayoutDescription(external_header, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
WriteFile(file_basename + ".h", header.str());
|
||||
WriteFile(file_basename + "-inl.h", inline_header.str());
|
||||
WriteFile(file_basename + ".h", external_header.str());
|
||||
WriteFile(file_basename + "-inl.h", inline_external_header.str());
|
||||
WriteFile(file_basename + ".cc", implementation.str());
|
||||
WriteFile(internal_file_basename + ".h", internal_header.str());
|
||||
WriteFile(internal_file_basename + "-inl.h", inline_internal_header.str());
|
||||
WriteFile(factory_file_basename + ".inc", factory_header.str());
|
||||
WriteFile(factory_file_basename + ".cc", factory_impl.str());
|
||||
}
|
||||
|
||||
namespace {
|
||||
@ -3700,8 +4011,17 @@ void GeneratePrintDefinitionsForClass(std::ostream& impl, const ClassType* type,
|
||||
for (const AggregateType* aggregate_type : hierarchy) {
|
||||
for (const Field& f : aggregate_type->fields()) {
|
||||
if (f.name_and_type.name == "map") continue;
|
||||
impl << " os << \"\\n - " << f.name_and_type.name << ": \" << "
|
||||
<< "Brief(this->" << f.name_and_type.name << "());\n";
|
||||
if (!f.index.has_value()) {
|
||||
if ((aggregate_type == TypeOracle::GetFixedArrayBaseType() &&
|
||||
f.name_and_type.name == "length") ||
|
||||
!f.name_and_type.type->IsSubtypeOf(TypeOracle::GetTaggedType())) {
|
||||
impl << " os << \"\\n - " << f.name_and_type.name << ": \" << "
|
||||
<< "this->" << f.name_and_type.name << "();\n";
|
||||
} else {
|
||||
impl << " os << \"\\n - " << f.name_and_type.name << ": \" << "
|
||||
<< "Brief(this->" << f.name_and_type.name << "());\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
impl << " os << \"\\n\";\n";
|
||||
@ -3725,8 +4045,7 @@ void ImplementationVisitor::GeneratePrintDefinitions(
|
||||
|
||||
NamespaceScope impl_namespaces(impl, {"v8", "internal"});
|
||||
|
||||
for (const TypeAlias* alias : GlobalContext::GetClasses()) {
|
||||
const ClassType* type = ClassType::DynamicCast(alias->type());
|
||||
for (const ClassType* type : TypeOracle::GetClasses()) {
|
||||
if (!type->ShouldGeneratePrint()) continue;
|
||||
|
||||
if (type->GenerateCppClassDefinitions()) {
|
||||
@ -3748,6 +4067,142 @@ void ImplementationVisitor::GeneratePrintDefinitions(
|
||||
WriteFile(output_directory + "/" + file_name, new_contents);
|
||||
}
|
||||
|
||||
void ImplementationVisitor::GenerateBodyDescriptors(
|
||||
const std::string& output_directory) {
|
||||
std::string file_name = "objects-body-descriptors-tq-inl";
|
||||
std::stringstream h_contents;
|
||||
{
|
||||
IncludeGuardScope include_guard(h_contents, file_name + ".h");
|
||||
|
||||
h_contents << "\n#include \"src/objects/objects-body-descriptors.h\"\n";
|
||||
h_contents << "\n#include \"torque-generated/class-definitions-tq.h\"\n";
|
||||
h_contents
|
||||
<< "\n#include \"torque-generated/internal-class-definitions-tq.h\"\n";
|
||||
h_contents << "\n#include "
|
||||
"\"torque-generated/internal-class-definitions-tq-inl.h\"\n";
|
||||
|
||||
NamespaceScope h_namespaces(h_contents, {"v8", "internal"});
|
||||
|
||||
for (const ClassType* type : TypeOracle::GetClasses()) {
|
||||
std::string name = type->name();
|
||||
if (!type->ShouldGenerateBodyDescriptor()) continue;
|
||||
|
||||
const ClassType* super_class = type->GetSuperClass();
|
||||
std::string super_name = super_class->name();
|
||||
h_contents << "class " << name
|
||||
<< "::BodyDescriptor final : public BodyDescriptorBase {\n";
|
||||
|
||||
h_contents << " public:\n";
|
||||
|
||||
h_contents << " static bool IsValidSlot(Map map, HeapObject obj, int "
|
||||
"offset) {\n";
|
||||
|
||||
if (super_class == TypeOracle::GetHeapObjectType() ||
|
||||
super_class == TypeOracle::GetFixedArrayBaseType()) {
|
||||
h_contents << " if (offset < " << super_name
|
||||
<< "::kHeaderSize) return true;\n";
|
||||
} else {
|
||||
h_contents << " if (" << super_name
|
||||
<< "::BodyDescriptor::IsValidSlot(map, obj, offset)) return "
|
||||
"true;\n";
|
||||
}
|
||||
|
||||
h_contents << " return offset >= " << name
|
||||
<< "::kStartOfStrongFieldsOffset"
|
||||
<< " && offset < " << name << ""
|
||||
<< "::kEndOfStrongFieldsOffset;\n";
|
||||
h_contents << " }\n\n";
|
||||
|
||||
h_contents << " template <typename ObjectVisitor>\n";
|
||||
h_contents << " static inline void IterateBody(Map map, HeapObject obj, "
|
||||
"int object_size, ObjectVisitor* v) {\n";
|
||||
|
||||
// There may be MaybeObjects embedded in the strong pointer section, which
|
||||
// are not suppored.
|
||||
for (auto& f : type->fields()) {
|
||||
for (const Type* t : LowerType(f.name_and_type.type)) {
|
||||
if (t->IsSubtypeOf(TypeOracle::GetTaggedType()) &&
|
||||
!t->IsSubtypeOf(TypeOracle::GetObjectType())) {
|
||||
Error("Cannot generate body descriptor for field ",
|
||||
f.name_and_type.name, " of class ", name, " because ", *t,
|
||||
" can contain tagged weak pointers.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (super_class != TypeOracle::GetHeapObjectType() &&
|
||||
super_class != TypeOracle::GetFixedArrayBaseType()) {
|
||||
h_contents
|
||||
<< " " << super_name
|
||||
<< "::BodyDescriptor::IterateBody(map, obj, object_size, v);\n";
|
||||
}
|
||||
|
||||
h_contents << " if (" << name
|
||||
<< "::kStartOfStrongFieldsOffset != " << name
|
||||
<< "::kEndOfStrongFieldsOffset) {\n";
|
||||
h_contents << " IteratePointers(obj, " << name
|
||||
<< "::kStartOfStrongFieldsOffset, " << name
|
||||
<< "::kEndOfStrongFieldsOffset, v);\n";
|
||||
h_contents << " }\n";
|
||||
|
||||
h_contents << " if (" << name
|
||||
<< "::kStartOfWeakFieldsOffset != " << name
|
||||
<< "::kEndOfWeakFieldsOffset) {\n";
|
||||
h_contents << " IterateCustomWeakPointers(obj, " << name
|
||||
<< "::kStartOfWeakFieldsOffset, " << name
|
||||
<< "::kEndOfWeakFieldsOffset, v);\n";
|
||||
h_contents << " }\n";
|
||||
|
||||
// Since all of the index fields are at the end of the object and must
|
||||
// only be Tagged values, emit only a single IteratePointers from the
|
||||
// beginning of the first indexed field to the end of the object.
|
||||
bool first_index_seen = false;
|
||||
for (const Field& field : type->ComputeAllFields()) {
|
||||
if (field.index && !first_index_seen) {
|
||||
std::string indexed_field_name =
|
||||
CamelifyString(field.name_and_type.name);
|
||||
if (field.name_and_type.type->IsSubtypeOf(
|
||||
TypeOracle::GetObjectType())) {
|
||||
h_contents << " BodyDescriptorBase::IteratePointers(obj, "
|
||||
<< name << "::k" << indexed_field_name << "Offset, "
|
||||
<< name << "::SizeFor(" << name << "::cast(obj)), v);\n";
|
||||
} else {
|
||||
Error(
|
||||
"generating body descriptors for indexed fields not subtype of "
|
||||
"Object isn't (yet) supported");
|
||||
}
|
||||
first_index_seen = true;
|
||||
}
|
||||
if (first_index_seen) {
|
||||
for (const Type* t : LowerType(field.name_and_type.type)) {
|
||||
if (!t->IsSubtypeOf(TypeOracle::GetObjectType())) {
|
||||
Error("cannot generate class body descriptor for \"",
|
||||
type->name(),
|
||||
"\", all fields of including and after the first indexed "
|
||||
"member must no comprised only of subtypes of Object "
|
||||
"(field \"",
|
||||
field.name_and_type.name, "\" is not)");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
h_contents << " }\n\n";
|
||||
|
||||
h_contents
|
||||
<< " static inline int SizeOf(Map map, HeapObject raw_object) {\n";
|
||||
h_contents << " " << name << " object = " << name
|
||||
<< "::cast(raw_object);\n";
|
||||
h_contents << " return " << name << "::SizeFor(object);\n";
|
||||
h_contents << " }\n\n";
|
||||
|
||||
h_contents << "};\n";
|
||||
}
|
||||
}
|
||||
|
||||
WriteFile(output_directory + "/" + file_name + ".h", h_contents.str());
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// Generate verification code for a single piece of class data, which might be
|
||||
@ -3909,8 +4364,7 @@ void ImplementationVisitor::GenerateClassVerifiers(
|
||||
|
||||
// Generate forward declarations to avoid including any headers.
|
||||
h_contents << "class Isolate;\n";
|
||||
for (const TypeAlias* alias : GlobalContext::GetClasses()) {
|
||||
const ClassType* type = ClassType::DynamicCast(alias->type());
|
||||
for (const ClassType* type : TypeOracle::GetClasses()) {
|
||||
if (!type->ShouldGenerateVerify()) continue;
|
||||
h_contents << "class " << type->name() << ";\n";
|
||||
}
|
||||
@ -3920,8 +4374,7 @@ void ImplementationVisitor::GenerateClassVerifiers(
|
||||
h_contents << "class " << verifier_class << "{\n";
|
||||
h_contents << " public:\n";
|
||||
|
||||
for (const TypeAlias* alias : GlobalContext::GetClasses()) {
|
||||
const ClassType* type = ClassType::DynamicCast(alias->type());
|
||||
for (const ClassType* type : TypeOracle::GetClasses()) {
|
||||
std::string name = type->name();
|
||||
if (!type->ShouldGenerateVerify()) continue;
|
||||
|
||||
|
@ -388,13 +388,13 @@ class ImplementationVisitor {
|
||||
void GenerateBitFields(const std::string& output_directory);
|
||||
void GeneratePrintDefinitions(const std::string& output_directory);
|
||||
void GenerateClassDefinitions(const std::string& output_directory);
|
||||
void GenerateBodyDescriptors(const std::string& output_directory);
|
||||
void GenerateInstanceTypes(const std::string& output_directory);
|
||||
void GenerateClassVerifiers(const std::string& output_directory);
|
||||
void GenerateEnumVerifiers(const std::string& output_directory);
|
||||
void GenerateClassDebugReaders(const std::string& output_directory);
|
||||
void GenerateExportedMacrosAssembler(const std::string& output_directory);
|
||||
void GenerateCSATypes(const std::string& output_directory);
|
||||
void GenerateCppForInternalClasses(const std::string& output_directory);
|
||||
|
||||
VisitResult Visit(Expression* expr);
|
||||
const Type* Visit(Statement* stmt);
|
||||
|
@ -289,6 +289,8 @@ std::unique_ptr<InstanceTypeTree> AssignInstanceTypes() {
|
||||
// - fully_defined_single_instance_types: This list is pairs of class name and
|
||||
// instance type, for classes which have defined layouts and a single
|
||||
// corresponding instance type.
|
||||
// - fully_defined_multiple_instance_types: This list is pairs of class name and
|
||||
// instance type, for classes which have defined layouts and subclasses.
|
||||
// - only_declared_single_instance_types: This list is pairs of class name and
|
||||
// instance type, for classes which have a single corresponding instance type
|
||||
// and do not have layout definitions in Torque.
|
||||
@ -302,6 +304,7 @@ std::unique_ptr<InstanceTypeTree> AssignInstanceTypes() {
|
||||
void PrintInstanceTypes(InstanceTypeTree* root, std::ostream& definitions,
|
||||
std::ostream& values,
|
||||
std::ostream& fully_defined_single_instance_types,
|
||||
std::ostream& fully_defined_multiple_instance_types,
|
||||
std::ostream& only_declared_single_instance_types,
|
||||
std::ostream& fully_defined_range_instance_types,
|
||||
std::ostream& only_declared_range_instance_types,
|
||||
@ -331,6 +334,7 @@ void PrintInstanceTypes(InstanceTypeTree* root, std::ostream& definitions,
|
||||
for (auto& child : root->children) {
|
||||
PrintInstanceTypes(
|
||||
child.get(), definitions, values, fully_defined_single_instance_types,
|
||||
fully_defined_multiple_instance_types,
|
||||
only_declared_single_instance_types, fully_defined_range_instance_types,
|
||||
only_declared_range_instance_types, inner_indent);
|
||||
}
|
||||
@ -351,6 +355,11 @@ void PrintInstanceTypes(InstanceTypeTree* root, std::ostream& definitions,
|
||||
: fully_defined_range_instance_types;
|
||||
range_instance_types << " V(" << root->type->name() << ", FIRST_"
|
||||
<< type_name << ", LAST_" << type_name << ") \\\n";
|
||||
if (!root->type->IsExtern() && !root->type->IsAbstract() &&
|
||||
!root->type->HasUndefinedLayout()) {
|
||||
fully_defined_multiple_instance_types << " V(" << root->type->name()
|
||||
<< ", " << type_name << ") \\\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -370,12 +379,14 @@ void ImplementationVisitor::GenerateInstanceTypes(
|
||||
std::unique_ptr<InstanceTypeTree> instance_types = AssignInstanceTypes();
|
||||
std::stringstream values_list;
|
||||
std::stringstream fully_defined_single_instance_types;
|
||||
std::stringstream fully_defined_multiple_instance_types;
|
||||
std::stringstream only_declared_single_instance_types;
|
||||
std::stringstream fully_defined_range_instance_types;
|
||||
std::stringstream only_declared_range_instance_types;
|
||||
if (instance_types != nullptr) {
|
||||
PrintInstanceTypes(instance_types.get(), header, values_list,
|
||||
fully_defined_single_instance_types,
|
||||
fully_defined_multiple_instance_types,
|
||||
only_declared_single_instance_types,
|
||||
fully_defined_range_instance_types,
|
||||
only_declared_range_instance_types, " ");
|
||||
@ -394,6 +405,12 @@ void ImplementationVisitor::GenerateInstanceTypes(
|
||||
header << fully_defined_single_instance_types.str();
|
||||
header << "\n";
|
||||
|
||||
header << "// Pairs of (ClassName, INSTANCE_TYPE) for classes that have\n";
|
||||
header << "// full Torque definitions and subclasses.\n";
|
||||
header << "#define TORQUE_INSTANCE_CHECKERS_MULTIPLE_FULLY_DEFINED(V) \\\n";
|
||||
header << fully_defined_multiple_instance_types.str();
|
||||
header << "\n";
|
||||
|
||||
header << "// Pairs of (ClassName, INSTANCE_TYPE) for classes that are\n";
|
||||
header << "// declared but not defined in Torque. These classes may\n";
|
||||
header << "// correspond with actual C++ classes, but they are not\n";
|
||||
@ -416,10 +433,9 @@ void ImplementationVisitor::GenerateInstanceTypes(
|
||||
header << only_declared_range_instance_types.str();
|
||||
header << "\n";
|
||||
|
||||
header << "// Instance types for Torque-internal classes.\n";
|
||||
header << "#define TORQUE_INTERNAL_INSTANCE_TYPES(V) \\\n";
|
||||
for (const TypeAlias* alias : GlobalContext::GetClasses()) {
|
||||
const ClassType* type = ClassType::DynamicCast(alias->type());
|
||||
header << "// Instance types for non-extern Torque classes.\n";
|
||||
header << "#define TORQUE_INSTANCE_TYPES(V) \\\n";
|
||||
for (const ClassType* type : TypeOracle::GetClasses()) {
|
||||
if (type->IsExtern()) continue;
|
||||
std::string type_name =
|
||||
CapifyStringWithUnderscores(type->name()) + "_TYPE";
|
||||
@ -427,11 +443,11 @@ void ImplementationVisitor::GenerateInstanceTypes(
|
||||
}
|
||||
header << "\n";
|
||||
|
||||
header << "// Struct list entries for Torque-internal classes.\n";
|
||||
header << "#define TORQUE_STRUCT_LIST_GENERATOR(V, _) \\\n";
|
||||
for (const TypeAlias* alias : GlobalContext::GetClasses()) {
|
||||
const ClassType* type = ClassType::DynamicCast(alias->type());
|
||||
header << "// Map list macros for non-extern Torque classes.\n";
|
||||
header << "#define TORQUE_INTERNAL_VARSIZE_CLASS_LIST_GENERATOR(V, _) \\\n";
|
||||
for (const ClassType* type : TypeOracle::GetClasses()) {
|
||||
if (type->IsExtern()) continue;
|
||||
if (!type->HasIndexedField()) continue;
|
||||
std::string type_name =
|
||||
CapifyStringWithUnderscores(type->name()) + "_TYPE";
|
||||
std::string variable_name = SnakeifyString(type->name());
|
||||
@ -439,6 +455,21 @@ void ImplementationVisitor::GenerateInstanceTypes(
|
||||
<< variable_name << ") \\\n";
|
||||
}
|
||||
header << "\n";
|
||||
header << "#define TORQUE_INTERNAL_FIXED_CLASS_LIST_GENERATOR(V, _) \\\n";
|
||||
for (const ClassType* type : TypeOracle::GetClasses()) {
|
||||
if (type->IsExtern()) continue;
|
||||
if (type->HasIndexedField()) continue;
|
||||
std::string type_name =
|
||||
CapifyStringWithUnderscores(type->name()) + "_TYPE";
|
||||
std::string variable_name = SnakeifyString(type->name());
|
||||
header << " V(_, " << type_name << ", " << type->name() << ", "
|
||||
<< variable_name << ") \\\n";
|
||||
}
|
||||
header << "\n";
|
||||
header << "#define TORQUE_INTERNAL_CLASS_LIST_GENERATOR(V, _) \\\n";
|
||||
header << " TORQUE_INTERNAL_VARSIZE_CLASS_LIST_GENERATOR(V, _) \\\n";
|
||||
header << " TORQUE_INTERNAL_FIXED_CLASS_LIST_GENERATOR(V, _)\n";
|
||||
header << "\n";
|
||||
}
|
||||
std::string output_header_path = output_directory + "/" + file_name;
|
||||
WriteFile(output_header_path, header.str());
|
||||
|
@ -88,10 +88,10 @@ void CompileCurrentAst(TorqueCompilerOptions options) {
|
||||
implementation_visitor.GenerateClassVerifiers(output_directory);
|
||||
implementation_visitor.GenerateClassDebugReaders(output_directory);
|
||||
implementation_visitor.GenerateEnumVerifiers(output_directory);
|
||||
implementation_visitor.GenerateBodyDescriptors(output_directory);
|
||||
implementation_visitor.GenerateExportedMacrosAssembler(output_directory);
|
||||
implementation_visitor.GenerateCSATypes(output_directory);
|
||||
implementation_visitor.GenerateInstanceTypes(output_directory);
|
||||
implementation_visitor.GenerateCppForInternalClasses(output_directory);
|
||||
|
||||
implementation_visitor.EndCSAFiles();
|
||||
implementation_visitor.GenerateImplementation(output_directory);
|
||||
|
@ -549,9 +549,24 @@ base::Optional<ParseResult> MakeIntrinsicDeclaration(
|
||||
return ParseResult{result};
|
||||
}
|
||||
|
||||
namespace {
|
||||
bool HasExportAnnotation(ParseResultIterator* child_results,
|
||||
const char* declaration) {
|
||||
auto annotations = child_results->NextAs<std::vector<Annotation>>();
|
||||
if (annotations.size()) {
|
||||
if (annotations.size() > 1 || annotations[0].name->value != "@export") {
|
||||
Error(declaration,
|
||||
" declarations only support a single @export annotation");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
base::Optional<ParseResult> MakeTorqueMacroDeclaration(
|
||||
ParseResultIterator* child_results) {
|
||||
auto export_to_csa = child_results->NextAs<bool>();
|
||||
bool export_to_csa = HasExportAnnotation(child_results, "macro");
|
||||
auto transitioning = child_results->NextAs<bool>();
|
||||
auto operator_name = child_results->NextAs<base::Optional<std::string>>();
|
||||
auto name = child_results->NextAs<Identifier*>();
|
||||
@ -835,7 +850,8 @@ base::Optional<ParseResult> MakeClassDeclaration(
|
||||
child_results,
|
||||
{ANNOTATION_GENERATE_PRINT, ANNOTATION_NO_VERIFIER, ANNOTATION_ABSTRACT,
|
||||
ANNOTATION_HAS_SAME_INSTANCE_TYPE_AS_PARENT,
|
||||
ANNOTATION_GENERATE_CPP_CLASS,
|
||||
ANNOTATION_GENERATE_CPP_CLASS, ANNOTATION_GENERATE_BODY_DESCRIPTOR,
|
||||
ANNOTATION_EXPORT_CPP_CLASS,
|
||||
ANNOTATION_HIGHEST_INSTANCE_TYPE_WITHIN_PARENT,
|
||||
ANNOTATION_LOWEST_INSTANCE_TYPE_WITHIN_PARENT},
|
||||
{ANNOTATION_RESERVE_BITS_IN_INSTANCE_TYPE,
|
||||
@ -854,6 +870,12 @@ base::Optional<ParseResult> MakeClassDeclaration(
|
||||
if (annotations.Contains(ANNOTATION_GENERATE_CPP_CLASS)) {
|
||||
flags |= ClassFlag::kGenerateCppClassDefinitions;
|
||||
}
|
||||
if (annotations.Contains(ANNOTATION_GENERATE_BODY_DESCRIPTOR)) {
|
||||
flags |= ClassFlag::kGenerateBodyDescriptor;
|
||||
}
|
||||
if (annotations.Contains(ANNOTATION_EXPORT_CPP_CLASS)) {
|
||||
flags |= ClassFlag::kExport;
|
||||
}
|
||||
if (annotations.Contains(ANNOTATION_HIGHEST_INSTANCE_TYPE_WITHIN_PARENT)) {
|
||||
flags |= ClassFlag::kHighestInstanceTypeWithinParent;
|
||||
}
|
||||
@ -945,7 +967,8 @@ base::Optional<ParseResult> MakeSpecializationDeclaration(
|
||||
|
||||
base::Optional<ParseResult> MakeStructDeclaration(
|
||||
ParseResultIterator* child_results) {
|
||||
bool is_export = child_results->NextAs<bool>();
|
||||
bool is_export = HasExportAnnotation(child_results, "Struct");
|
||||
|
||||
StructFlags flags = StructFlag::kNone;
|
||||
if (is_export) flags |= StructFlag::kExport;
|
||||
|
||||
@ -2322,7 +2345,7 @@ struct TorqueGrammar : Grammar {
|
||||
Sequence({Token("generates"), &externalString})),
|
||||
&optionalClassBody},
|
||||
AsSingletonVector<Declaration*, MakeClassDeclaration>()),
|
||||
Rule({CheckIf(Token("@export")), Token("struct"), &name,
|
||||
Rule({annotations, Token("struct"), &name,
|
||||
TryOrDefault<GenericParameters>(&genericParameters), Token("{"),
|
||||
List<Declaration*>(&method),
|
||||
List<StructFieldExpression>(&structField), Token("}")},
|
||||
@ -2363,7 +2386,7 @@ struct TorqueGrammar : Grammar {
|
||||
Rule({Token("extern"), CheckIf(Token("transitioning")), Token("runtime"),
|
||||
&name, &typeListMaybeVarArgs, &optionalReturnType, Token(";")},
|
||||
AsSingletonVector<Declaration*, MakeExternalRuntime>()),
|
||||
Rule({CheckIf(Token("@export")), CheckIf(Token("transitioning")),
|
||||
Rule({annotations, CheckIf(Token("transitioning")),
|
||||
Optional<std::string>(
|
||||
Sequence({Token("operator"), &externalString})),
|
||||
Token("macro"), &name,
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "src/torque/type-oracle.h"
|
||||
#include "src/torque/type-visitor.h"
|
||||
#include "src/torque/types.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
@ -68,6 +69,17 @@ Namespace* TypeOracle::CreateGenericTypeInstantiationNamespace() {
|
||||
return Get().generic_type_instantiation_namespaces_.back().get();
|
||||
}
|
||||
|
||||
// static
|
||||
std::vector<const ClassType*> TypeOracle::GetClasses() {
|
||||
std::vector<const ClassType*> result;
|
||||
for (const std::unique_ptr<AggregateType>& t : Get().aggregate_types_) {
|
||||
if (auto* class_type = ClassType::DynamicCast(t.get())) {
|
||||
result.push_back(class_type);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace torque
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -293,6 +293,10 @@ class TypeOracle : public ContextualClass<TypeOracle> {
|
||||
return Get().GetBuiltinType(UNINITIALIZED_ITERATOR_TYPE_STRING);
|
||||
}
|
||||
|
||||
static const Type* GetFixedArrayBaseType() {
|
||||
return Get().GetBuiltinType(FIXED_ARRAY_BASE_TYPE_STRING);
|
||||
}
|
||||
|
||||
static base::Optional<const Type*> ImplicitlyConvertableFrom(
|
||||
const Type* to, const Type* from) {
|
||||
while (from != nullptr) {
|
||||
@ -315,6 +319,10 @@ class TypeOracle : public ContextualClass<TypeOracle> {
|
||||
static const std::vector<std::unique_ptr<BitFieldStructType>>&
|
||||
GetBitFieldStructTypes();
|
||||
|
||||
// By construction, this list of all classes is topologically sorted w.r.t.
|
||||
// inheritance.
|
||||
static std::vector<const ClassType*> GetClasses();
|
||||
|
||||
static void FinalizeAggregateTypes();
|
||||
|
||||
static size_t FreshTypeId() { return Get().next_type_id_++; }
|
||||
|
@ -244,81 +244,83 @@ const StructType* TypeVisitor::ComputeType(
|
||||
|
||||
const ClassType* TypeVisitor::ComputeType(
|
||||
ClassDeclaration* decl, MaybeSpecializationKey specialized_from) {
|
||||
ClassType* new_class;
|
||||
// TODO(sigurds): Remove this hack by introducing a declarable for classes.
|
||||
const TypeAlias* alias =
|
||||
Declarations::LookupTypeAlias(QualifiedName(decl->name->value));
|
||||
GlobalContext::RegisterClass(alias);
|
||||
DCHECK_EQ(*alias->delayed_, decl);
|
||||
bool is_shape = decl->flags & ClassFlag::kIsShape;
|
||||
if (is_shape && !(decl->flags & ClassFlag::kExtern)) {
|
||||
ReportError("Shapes must be extern, add \"extern\" to the declaration.");
|
||||
ClassFlags flags = decl->flags;
|
||||
bool is_shape = flags & ClassFlag::kIsShape;
|
||||
std::string generates = decl->name->value;
|
||||
const Type* super_type = TypeVisitor::ComputeType(*decl->super);
|
||||
if (is_shape) {
|
||||
if (!(flags & ClassFlag::kExtern)) {
|
||||
ReportError("Shapes must be extern, add \"extern\" to the declaration.");
|
||||
}
|
||||
if (flags & ClassFlag::kUndefinedLayout) {
|
||||
ReportError("Shapes need to define their layout.");
|
||||
}
|
||||
const ClassType* super_class = ClassType::DynamicCast(super_type);
|
||||
if (!super_class ||
|
||||
!super_class->IsSubtypeOf(TypeOracle::GetJSObjectType())) {
|
||||
Error("Shapes need to extend a subclass of ",
|
||||
*TypeOracle::GetJSObjectType())
|
||||
.Throw();
|
||||
}
|
||||
// Shapes use their super class in CSA code since they have incomplete
|
||||
// support for type-checks on the C++ side.
|
||||
generates = super_class->name();
|
||||
}
|
||||
if (is_shape && decl->flags & ClassFlag::kUndefinedLayout) {
|
||||
ReportError("Shapes need to define their layout.");
|
||||
if (!decl->super) {
|
||||
ReportError("Extern class must extend another type.");
|
||||
}
|
||||
if (decl->flags & ClassFlag::kExtern) {
|
||||
if (!decl->super) {
|
||||
ReportError("Extern class must extend another type.");
|
||||
if (super_type != TypeOracle::GetStrongTaggedType()) {
|
||||
const ClassType* super_class = ClassType::DynamicCast(super_type);
|
||||
if (!super_class) {
|
||||
ReportError(
|
||||
"class \"", decl->name->value,
|
||||
"\" must extend either StrongTagged or an already declared class");
|
||||
}
|
||||
const Type* super_type = TypeVisitor::ComputeType(*decl->super);
|
||||
if (super_type != TypeOracle::GetStrongTaggedType()) {
|
||||
const ClassType* super_class = ClassType::DynamicCast(super_type);
|
||||
if (!super_class) {
|
||||
ReportError(
|
||||
"class \"", decl->name->value,
|
||||
"\" must extend either StrongTagged or an already declared class");
|
||||
}
|
||||
if (super_class->HasUndefinedLayout() &&
|
||||
!(decl->flags & ClassFlag::kUndefinedLayout)) {
|
||||
Error("Class \"", decl->name->value,
|
||||
"\" defines its layout but extends a class which does not")
|
||||
.Position(decl->pos);
|
||||
}
|
||||
if (super_class->HasUndefinedLayout() &&
|
||||
!(flags & ClassFlag::kUndefinedLayout)) {
|
||||
Error("Class \"", decl->name->value,
|
||||
"\" defines its layout but extends a class which does not")
|
||||
.Position(decl->pos);
|
||||
}
|
||||
|
||||
std::string generates = decl->name->value;
|
||||
if (is_shape) {
|
||||
const ClassType* super_class = ClassType::DynamicCast(super_type);
|
||||
if (!super_class ||
|
||||
!super_class->IsSubtypeOf(TypeOracle::GetJSObjectType())) {
|
||||
Error("Shapes need to extend a subclass of ",
|
||||
*TypeOracle::GetJSObjectType())
|
||||
.Throw();
|
||||
}
|
||||
// Shapes use their super class in CSA code since they have incomplete
|
||||
// support for type-checks on the C++ side.
|
||||
generates = super_class->name();
|
||||
if ((flags & ClassFlag::kExport) &&
|
||||
!(super_class->ShouldExport() || super_class->IsExtern())) {
|
||||
Error("cannot export class ", decl->name,
|
||||
" because superclass is neither @export or extern");
|
||||
}
|
||||
}
|
||||
if ((flags & ClassFlag::kGenerateBodyDescriptor ||
|
||||
flags & ClassFlag::kExport) &&
|
||||
flags & ClassFlag::kUndefinedLayout) {
|
||||
Error("Class \"", decl->name->value,
|
||||
"\" requires a layout but doesn't have one");
|
||||
}
|
||||
if (flags & ClassFlag::kExtern) {
|
||||
if (decl->generates) {
|
||||
bool enforce_tnode_type = true;
|
||||
generates = ComputeGeneratesType(decl->generates, enforce_tnode_type);
|
||||
}
|
||||
|
||||
new_class = TypeOracle::GetClassType(super_type, decl->name->value,
|
||||
decl->flags, generates, decl, alias);
|
||||
if (flags & ClassFlag::kExport) {
|
||||
Error("cannot export a class that is marked extern");
|
||||
}
|
||||
} else {
|
||||
if (!decl->super) {
|
||||
ReportError("Intern class ", decl->name->value,
|
||||
" must extend class Struct.");
|
||||
}
|
||||
const Type* super_type = TypeVisitor::ComputeType(*decl->super);
|
||||
const ClassType* super_class = ClassType::DynamicCast(super_type);
|
||||
const Type* struct_type =
|
||||
Declarations::LookupGlobalType(QualifiedName("Struct"));
|
||||
if (!super_class || super_class != struct_type) {
|
||||
ReportError("Intern class ", decl->name->value,
|
||||
" must extend class Struct.");
|
||||
}
|
||||
if (decl->generates) {
|
||||
ReportError("Only extern classes can specify a generated type.");
|
||||
}
|
||||
new_class = TypeOracle::GetClassType(
|
||||
super_type, decl->name->value,
|
||||
decl->flags | ClassFlag::kGeneratePrint | ClassFlag::kGenerateVerify,
|
||||
decl->name->value, decl, alias);
|
||||
if (super_type != TypeOracle::GetStrongTaggedType()) {
|
||||
if (flags & ClassFlag::kUndefinedLayout) {
|
||||
Error("non-external classes must have defined layouts");
|
||||
}
|
||||
}
|
||||
flags = flags | ClassFlag::kGeneratePrint | ClassFlag::kGenerateVerify |
|
||||
ClassFlag::kGenerateBodyDescriptor;
|
||||
}
|
||||
return new_class;
|
||||
|
||||
return TypeOracle::GetClassType(super_type, decl->name->value, flags,
|
||||
generates, decl, alias);
|
||||
}
|
||||
|
||||
const Type* TypeVisitor::ComputeType(TypeExpression* type_expression) {
|
||||
@ -406,17 +408,6 @@ void TypeVisitor::VisitClassFieldsAndMethods(
|
||||
ReportError("in-object properties cannot be weak");
|
||||
}
|
||||
}
|
||||
if (!(class_declaration->flags & ClassFlag::kExtern)) {
|
||||
if (!field_type->IsSubtypeOf(TypeOracle::GetObjectType())) {
|
||||
ReportError(
|
||||
"non-extern classes only support subtypes of type Object, but "
|
||||
"found type ",
|
||||
*field_type);
|
||||
}
|
||||
if (field_expression.weak) {
|
||||
ReportError("non-extern classes do not support weak fields");
|
||||
}
|
||||
}
|
||||
base::Optional<Expression*> array_length = field_expression.index;
|
||||
const Field& field = class_type->RegisterField(
|
||||
{field_expression.name_and_type.name->pos,
|
||||
|
@ -67,6 +67,20 @@ std::string Type::SimpleName() const {
|
||||
return *aliases_.begin();
|
||||
}
|
||||
|
||||
// TODO(danno): HandlifiedCppTypeName should be used universally in Torque
|
||||
// where the C++ type of a Torque object is required.
|
||||
std::string Type::HandlifiedCppTypeName() const {
|
||||
if (IsSubtypeOf(TypeOracle::GetTaggedType()) &&
|
||||
!IsSubtypeOf(TypeOracle::GetSmiType())) {
|
||||
base::Optional<const ClassType*> class_type = ClassSupertype();
|
||||
std::string type =
|
||||
class_type ? (*class_type)->GetGeneratedTNodeTypeName() : "Object";
|
||||
return "Handle<" + type + ">";
|
||||
} else {
|
||||
return ConstexprVersion()->GetGeneratedTypeName();
|
||||
}
|
||||
}
|
||||
|
||||
bool Type::IsSubtypeOf(const Type* supertype) const {
|
||||
if (supertype->IsTopType()) return true;
|
||||
if (IsNever()) return true;
|
||||
@ -517,24 +531,43 @@ void ClassType::GenerateAccessors() {
|
||||
// For each field, construct AST snippets that implement a CSA accessor
|
||||
// function. The implementation iterator will turn the snippets into code.
|
||||
for (auto& field : fields_) {
|
||||
if (field.index || field.name_and_type.type == TypeOracle::GetVoidType()) {
|
||||
if (field.name_and_type.type == TypeOracle::GetVoidType()) {
|
||||
continue;
|
||||
}
|
||||
CurrentSourcePosition::Scope position_activator(field.pos);
|
||||
|
||||
IdentifierExpression* parameter =
|
||||
MakeNode<IdentifierExpression>(MakeNode<Identifier>(std::string{"o"}));
|
||||
IdentifierExpression* index =
|
||||
MakeNode<IdentifierExpression>(MakeNode<Identifier>(std::string{"i"}));
|
||||
|
||||
// Load accessor
|
||||
std::string camel_field_name = CamelifyString(field.name_and_type.name);
|
||||
std::string load_macro_name = "Load" + this->name() + camel_field_name;
|
||||
|
||||
// For now, only generate indexed accessors for simple types
|
||||
if (field.index.has_value() && field.name_and_type.type->IsStructType()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Signature load_signature;
|
||||
load_signature.parameter_names.push_back(MakeNode<Identifier>("o"));
|
||||
load_signature.parameter_types.types.push_back(this);
|
||||
if (field.index) {
|
||||
load_signature.parameter_names.push_back(MakeNode<Identifier>("i"));
|
||||
load_signature.parameter_types.types.push_back(
|
||||
TypeOracle::GetIntPtrType());
|
||||
}
|
||||
load_signature.parameter_types.var_args = false;
|
||||
load_signature.return_type = field.name_and_type.type;
|
||||
Statement* load_body =
|
||||
MakeNode<ReturnStatement>(MakeNode<FieldAccessExpression>(
|
||||
parameter, MakeNode<Identifier>(field.name_and_type.name)));
|
||||
|
||||
Expression* load_expression = MakeNode<FieldAccessExpression>(
|
||||
parameter, MakeNode<Identifier>(field.name_and_type.name));
|
||||
if (field.index) {
|
||||
load_expression =
|
||||
MakeNode<ElementAccessExpression>(load_expression, index);
|
||||
}
|
||||
Statement* load_body = MakeNode<ReturnStatement>(load_expression);
|
||||
Declarations::DeclareMacro(load_macro_name, true, base::nullopt,
|
||||
load_signature, load_body, base::nullopt);
|
||||
|
||||
@ -544,17 +577,25 @@ void ClassType::GenerateAccessors() {
|
||||
std::string store_macro_name = "Store" + this->name() + camel_field_name;
|
||||
Signature store_signature;
|
||||
store_signature.parameter_names.push_back(MakeNode<Identifier>("o"));
|
||||
store_signature.parameter_names.push_back(MakeNode<Identifier>("v"));
|
||||
store_signature.parameter_types.types.push_back(this);
|
||||
if (field.index) {
|
||||
store_signature.parameter_names.push_back(MakeNode<Identifier>("i"));
|
||||
store_signature.parameter_types.types.push_back(
|
||||
TypeOracle::GetIntPtrType());
|
||||
}
|
||||
store_signature.parameter_names.push_back(MakeNode<Identifier>("v"));
|
||||
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<AssignmentExpression>(
|
||||
MakeNode<FieldAccessExpression>(
|
||||
parameter, MakeNode<Identifier>(field.name_and_type.name)),
|
||||
value));
|
||||
Expression* store_expression = MakeNode<FieldAccessExpression>(
|
||||
parameter, MakeNode<Identifier>(field.name_and_type.name));
|
||||
if (field.index) {
|
||||
store_expression =
|
||||
MakeNode<ElementAccessExpression>(store_expression, index);
|
||||
}
|
||||
Statement* store_body = MakeNode<ExpressionStatement>(
|
||||
MakeNode<AssignmentExpression>(store_expression, value));
|
||||
Declarations::DeclareMacro(store_macro_name, true, base::nullopt,
|
||||
store_signature, store_body, base::nullopt,
|
||||
false);
|
||||
|
@ -113,6 +113,8 @@ class V8_EXPORT_PRIVATE Type : public TypeBase {
|
||||
// Used for naming generated code.
|
||||
virtual std::string SimpleName() const;
|
||||
|
||||
std::string HandlifiedCppTypeName() const;
|
||||
|
||||
const Type* parent() const { return parent_; }
|
||||
bool IsVoid() const { return IsAbstractName(VOID_TYPE_STRING); }
|
||||
bool IsNever() const { return IsAbstractName(NEVER_TYPE_STRING); }
|
||||
@ -611,12 +613,15 @@ class ClassType final : public AggregateType {
|
||||
std::string GetGeneratedTNodeTypeNameImpl() const override;
|
||||
bool IsExtern() const { return flags_ & ClassFlag::kExtern; }
|
||||
bool ShouldGeneratePrint() const {
|
||||
return (flags_ & ClassFlag::kGeneratePrint || !IsExtern()) &&
|
||||
!HasUndefinedLayout();
|
||||
return !IsExtern() ||
|
||||
((flags_ & ClassFlag::kGeneratePrint) && !HasUndefinedLayout());
|
||||
}
|
||||
bool ShouldGenerateVerify() const {
|
||||
return (flags_ & ClassFlag::kGenerateVerify || !IsExtern()) &&
|
||||
!HasUndefinedLayout() && !IsShape();
|
||||
return !IsExtern() || ((flags_ & ClassFlag::kGenerateVerify) &&
|
||||
(!HasUndefinedLayout() && !IsShape()));
|
||||
}
|
||||
bool ShouldGenerateBodyDescriptor() const {
|
||||
return flags_ & ClassFlag::kGenerateBodyDescriptor || !IsExtern();
|
||||
}
|
||||
bool IsTransient() const override { return flags_ & ClassFlag::kTransient; }
|
||||
bool IsAbstract() const { return flags_ & ClassFlag::kAbstract; }
|
||||
@ -624,8 +629,10 @@ class ClassType final : public AggregateType {
|
||||
return flags_ & ClassFlag::kHasSameInstanceTypeAsParent;
|
||||
}
|
||||
bool GenerateCppClassDefinitions() const {
|
||||
return flags_ & ClassFlag::kGenerateCppClassDefinitions || !IsExtern();
|
||||
return flags_ & ClassFlag::kGenerateCppClassDefinitions || !IsExtern() ||
|
||||
ShouldGenerateBodyDescriptor();
|
||||
}
|
||||
bool ShouldExport() const { return flags_ & ClassFlag::kExport; }
|
||||
bool IsShape() const { return flags_ & ClassFlag::kIsShape; }
|
||||
bool HasStaticSize() const;
|
||||
bool HasIndexedField() const override;
|
||||
|
@ -736,6 +736,35 @@ TEST(TestTestParentFrameArguments) {
|
||||
asm_tester.GenerateCode();
|
||||
}
|
||||
|
||||
TEST(TestFullyGeneratedClassFromCpp) {
|
||||
CcTest::InitializeVM();
|
||||
Isolate* isolate(CcTest::i_isolate());
|
||||
i::HandleScope scope(isolate);
|
||||
CodeAssemblerTester asm_tester(isolate, 1);
|
||||
TestTorqueAssembler m(asm_tester.state());
|
||||
{ m.Return(m.TestFullyGeneratedClassFromCpp()); }
|
||||
FunctionTester ft(asm_tester.GenerateCode(), 0);
|
||||
Handle<ExportedSubClass> result =
|
||||
Handle<ExportedSubClass>::cast(ft.Call().ToHandleChecked());
|
||||
CHECK_EQ(result->c_field(), 7);
|
||||
CHECK_EQ(result->d_field(), 8);
|
||||
CHECK_EQ(Smi::ToInt(result->e_field()), 9);
|
||||
}
|
||||
|
||||
TEST(TestFullyGeneratedClassWithElements) {
|
||||
CcTest::InitializeVM();
|
||||
Isolate* isolate(CcTest::i_isolate());
|
||||
i::HandleScope scope(isolate);
|
||||
CodeAssemblerTester asm_tester(isolate, 1);
|
||||
TestTorqueAssembler m(asm_tester.state());
|
||||
{
|
||||
m.TestFullyGeneratedClassWithElements();
|
||||
m.Return(m.UndefinedConstant());
|
||||
}
|
||||
FunctionTester ft(asm_tester.GenerateCode(), 0);
|
||||
ft.Call();
|
||||
}
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -767,7 +767,7 @@ namespace test {
|
||||
check(a.b.GetX() == 2);
|
||||
}
|
||||
|
||||
class InternalClass extends Struct {
|
||||
class InternalClass extends HeapObject {
|
||||
macro Flip() labels NotASmi {
|
||||
const tmp = Cast<Smi>(this.b) otherwise NotASmi;
|
||||
this.b = this.a;
|
||||
@ -833,7 +833,7 @@ namespace test {
|
||||
return new FixedArray{map: kFixedArrayMap, length: 5, objects: ...i};
|
||||
}
|
||||
|
||||
class SmiPair extends Struct {
|
||||
class SmiPair extends HeapObject {
|
||||
macro GetA():&Smi {
|
||||
return & this.a;
|
||||
}
|
||||
@ -920,7 +920,7 @@ namespace test {
|
||||
StaticAssert(1 + 2 == 3);
|
||||
}
|
||||
|
||||
class SmiBox extends Struct {
|
||||
class SmiBox extends HeapObject {
|
||||
value: Smi;
|
||||
unrelated: Smi;
|
||||
}
|
||||
@ -1120,4 +1120,108 @@ namespace test {
|
||||
check(val3.d == 99);
|
||||
check(val3.e == 1234);
|
||||
}
|
||||
|
||||
@export
|
||||
class ExportedSubClass extends ExportedSubClassBase {
|
||||
c_field: int32;
|
||||
d_field: int32;
|
||||
e_field: Smi;
|
||||
}
|
||||
|
||||
@export
|
||||
class ExportedSubClassBase extends HeapObject {
|
||||
a: HeapObject;
|
||||
b: HeapObject;
|
||||
}
|
||||
|
||||
class InternalClassWithSmiElements extends FixedArrayBase {
|
||||
data: Smi;
|
||||
object: Oddball;
|
||||
entries[length]: Smi;
|
||||
}
|
||||
|
||||
struct InternalClassStructElement {
|
||||
a: Smi;
|
||||
b: Smi;
|
||||
}
|
||||
|
||||
class InternalClassWithStructElements extends HeapObject {
|
||||
dummy1: int32;
|
||||
dummy2: int32;
|
||||
count: Smi;
|
||||
data: Smi;
|
||||
object: Object;
|
||||
entries[count]: Smi;
|
||||
more_entries[count]: InternalClassStructElement;
|
||||
}
|
||||
|
||||
struct SmiGeneratorIterator {
|
||||
macro Next(): Smi labels _NoMore {
|
||||
return this.value++;
|
||||
}
|
||||
value: Smi;
|
||||
}
|
||||
|
||||
struct InternalClassStructElementGeneratorIterator {
|
||||
macro Next(): InternalClassStructElement labels _NoMore {
|
||||
return InternalClassStructElement{a: this.value++, b: this.value++};
|
||||
}
|
||||
value: Smi;
|
||||
}
|
||||
|
||||
@export
|
||||
macro TestFullyGeneratedClassWithElements() {
|
||||
// Test creation, initialization and access of a fully generated class with
|
||||
// simple (Smi) elements
|
||||
const length: Smi = Convert<Smi>(3);
|
||||
const object1 = new InternalClassWithSmiElements{
|
||||
length,
|
||||
data: 0,
|
||||
object: Undefined,
|
||||
entries: ...SmiGeneratorIterator {
|
||||
value: 11
|
||||
}
|
||||
};
|
||||
assert(object1.length == 3);
|
||||
assert(object1.data == 0);
|
||||
assert(object1.object == Undefined);
|
||||
assert(object1.entries[0] == 11);
|
||||
assert(object1.entries[1] == 12);
|
||||
assert(object1.entries[2] == 13);
|
||||
|
||||
// Test creation, initialization and access of a fully generated class
|
||||
// with elements that are a struct.
|
||||
const object2 = new InternalClassWithStructElements{
|
||||
dummy1: 44,
|
||||
dummy2: 45,
|
||||
count: length,
|
||||
data: 55,
|
||||
object: Undefined,
|
||||
entries: ...SmiGeneratorIterator{value: 3},
|
||||
more_entries: ...InternalClassStructElementGeneratorIterator {
|
||||
value: 1
|
||||
}
|
||||
};
|
||||
|
||||
assert(object2.dummy1 == 44);
|
||||
assert(object2.dummy2 == 45);
|
||||
assert(object2.count == 3);
|
||||
assert(object2.data == 55);
|
||||
assert(object2.object == Undefined);
|
||||
assert(object2.entries[0] == 3);
|
||||
assert(object2.entries[1] == 4);
|
||||
assert(object2.entries[2] == 5);
|
||||
assert(object2.more_entries[0].a == 1);
|
||||
assert(object2.more_entries[0].b == 2);
|
||||
assert(object2.more_entries[1].a == 3);
|
||||
assert(object2.more_entries[1].b == 4);
|
||||
assert(object2.more_entries[2].a == 5);
|
||||
assert(object2.more_entries[2].b == 6);
|
||||
}
|
||||
|
||||
@export
|
||||
macro TestFullyGeneratedClassFromCpp(): ExportedSubClass {
|
||||
return new
|
||||
ExportedSubClass{a: Null, b: Null, c_field: 7, d_field: 8, e_field: 9};
|
||||
}
|
||||
}
|
||||
|
2
third_party/v8/builtins/array-sort.tq
vendored
2
third_party/v8/builtins/array-sort.tq
vendored
@ -14,7 +14,7 @@
|
||||
// https://github.com/python/cpython/blob/master/Objects/listsort.txt
|
||||
|
||||
namespace array {
|
||||
class SortState extends Struct {
|
||||
class SortState extends HeapObject {
|
||||
macro Compare(implicit context: Context)(x: JSAny, y: JSAny): Number {
|
||||
const sortCompare: CompareBuiltinFn = this.sortComparePtr;
|
||||
return sortCompare(context, this.userCmpFn, x, y);
|
||||
|
@ -69,6 +69,7 @@ v8_component("v8_debug_helper") {
|
||||
sources = [
|
||||
"$target_gen_dir/../../torque-generated/class-debug-readers-tq.cc",
|
||||
"$target_gen_dir/../../torque-generated/class-debug-readers-tq.h",
|
||||
"$target_gen_dir/../../torque-generated/instance-types-tq.h",
|
||||
"$target_gen_dir/heap-constants-gen.cc",
|
||||
"debug-helper-internal.cc",
|
||||
"debug-helper-internal.h",
|
||||
|
@ -104,6 +104,7 @@ TypedObject GetTypedObjectByInstanceType(uintptr_t address,
|
||||
case i::INSTANCE_TYPE: \
|
||||
return {type_source, std::make_unique<Tq##ClassName>(address)};
|
||||
TORQUE_INSTANCE_CHECKERS_SINGLE_FULLY_DEFINED(INSTANCE_TYPE_CASE)
|
||||
TORQUE_INSTANCE_CHECKERS_MULTIPLE_FULLY_DEFINED(INSTANCE_TYPE_CASE)
|
||||
#undef INSTANCE_TYPE_CASE
|
||||
|
||||
default:
|
||||
|
@ -29,8 +29,8 @@ INSTANCE_TYPES = {
|
||||
65: "BIG_INT_BASE_TYPE",
|
||||
66: "HEAP_NUMBER_TYPE",
|
||||
67: "ODDBALL_TYPE",
|
||||
68: "SOURCE_TEXT_MODULE_TYPE",
|
||||
69: "SYNTHETIC_MODULE_TYPE",
|
||||
68: "EXPORTED_SUB_CLASS_BASE_TYPE",
|
||||
69: "EXPORTED_SUB_CLASS_TYPE",
|
||||
70: "FOREIGN_TYPE",
|
||||
71: "PROMISE_FULFILL_REACTION_JOB_TASK_TYPE",
|
||||
72: "PROMISE_REJECT_REACTION_JOB_TASK_TYPE",
|
||||
@ -60,84 +60,88 @@ INSTANCE_TYPES = {
|
||||
96: "FEEDBACK_CELL_TYPE",
|
||||
97: "FUNCTION_TEMPLATE_RARE_DATA_TYPE",
|
||||
98: "INTERCEPTOR_INFO_TYPE",
|
||||
99: "INTERNAL_CLASS_TYPE",
|
||||
100: "INTERPRETER_DATA_TYPE",
|
||||
101: "PROMISE_CAPABILITY_TYPE",
|
||||
102: "PROMISE_REACTION_TYPE",
|
||||
103: "PROPERTY_DESCRIPTOR_OBJECT_TYPE",
|
||||
104: "PROTOTYPE_INFO_TYPE",
|
||||
105: "SCRIPT_TYPE",
|
||||
106: "SMI_BOX_TYPE",
|
||||
107: "SMI_PAIR_TYPE",
|
||||
108: "SORT_STATE_TYPE",
|
||||
109: "SOURCE_TEXT_MODULE_INFO_ENTRY_TYPE",
|
||||
110: "STACK_FRAME_INFO_TYPE",
|
||||
111: "STACK_TRACE_FRAME_TYPE",
|
||||
112: "TEMPLATE_OBJECT_DESCRIPTION_TYPE",
|
||||
113: "TUPLE2_TYPE",
|
||||
114: "WASM_CAPI_FUNCTION_DATA_TYPE",
|
||||
115: "WASM_DEBUG_INFO_TYPE",
|
||||
116: "WASM_EXCEPTION_TAG_TYPE",
|
||||
117: "WASM_EXPORTED_FUNCTION_DATA_TYPE",
|
||||
118: "WASM_INDIRECT_FUNCTION_TABLE_TYPE",
|
||||
119: "WASM_JS_FUNCTION_DATA_TYPE",
|
||||
120: "FIXED_ARRAY_TYPE",
|
||||
121: "HASH_TABLE_TYPE",
|
||||
122: "EPHEMERON_HASH_TABLE_TYPE",
|
||||
123: "GLOBAL_DICTIONARY_TYPE",
|
||||
124: "NAME_DICTIONARY_TYPE",
|
||||
125: "NUMBER_DICTIONARY_TYPE",
|
||||
126: "ORDERED_HASH_MAP_TYPE",
|
||||
127: "ORDERED_HASH_SET_TYPE",
|
||||
128: "ORDERED_NAME_DICTIONARY_TYPE",
|
||||
129: "SIMPLE_NUMBER_DICTIONARY_TYPE",
|
||||
130: "STRING_TABLE_TYPE",
|
||||
131: "CLOSURE_FEEDBACK_CELL_ARRAY_TYPE",
|
||||
132: "OBJECT_BOILERPLATE_DESCRIPTION_TYPE",
|
||||
133: "SCOPE_INFO_TYPE",
|
||||
134: "SCRIPT_CONTEXT_TABLE_TYPE",
|
||||
135: "BYTE_ARRAY_TYPE",
|
||||
136: "BYTECODE_ARRAY_TYPE",
|
||||
137: "FIXED_DOUBLE_ARRAY_TYPE",
|
||||
138: "AWAIT_CONTEXT_TYPE",
|
||||
139: "BLOCK_CONTEXT_TYPE",
|
||||
140: "CATCH_CONTEXT_TYPE",
|
||||
141: "DEBUG_EVALUATE_CONTEXT_TYPE",
|
||||
142: "EVAL_CONTEXT_TYPE",
|
||||
143: "FUNCTION_CONTEXT_TYPE",
|
||||
144: "MODULE_CONTEXT_TYPE",
|
||||
145: "NATIVE_CONTEXT_TYPE",
|
||||
146: "SCRIPT_CONTEXT_TYPE",
|
||||
147: "WITH_CONTEXT_TYPE",
|
||||
148: "SMALL_ORDERED_HASH_MAP_TYPE",
|
||||
149: "SMALL_ORDERED_HASH_SET_TYPE",
|
||||
150: "SMALL_ORDERED_NAME_DICTIONARY_TYPE",
|
||||
151: "UNCOMPILED_DATA_WITH_PREPARSE_DATA_TYPE",
|
||||
152: "UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_TYPE",
|
||||
153: "WEAK_FIXED_ARRAY_TYPE",
|
||||
154: "TRANSITION_ARRAY_TYPE",
|
||||
155: "CELL_TYPE",
|
||||
156: "CODE_TYPE",
|
||||
157: "CODE_DATA_CONTAINER_TYPE",
|
||||
158: "COVERAGE_INFO_TYPE",
|
||||
159: "DESCRIPTOR_ARRAY_TYPE",
|
||||
160: "EMBEDDER_DATA_ARRAY_TYPE",
|
||||
161: "FEEDBACK_METADATA_TYPE",
|
||||
162: "FEEDBACK_VECTOR_TYPE",
|
||||
163: "FILLER_TYPE",
|
||||
164: "FREE_SPACE_TYPE",
|
||||
165: "MAP_TYPE",
|
||||
166: "PREPARSE_DATA_TYPE",
|
||||
167: "PROPERTY_ARRAY_TYPE",
|
||||
168: "PROPERTY_CELL_TYPE",
|
||||
169: "SHARED_FUNCTION_INFO_TYPE",
|
||||
170: "WEAK_ARRAY_LIST_TYPE",
|
||||
171: "WEAK_CELL_TYPE",
|
||||
172: "JS_PROXY_TYPE",
|
||||
99: "INTERPRETER_DATA_TYPE",
|
||||
100: "PROMISE_CAPABILITY_TYPE",
|
||||
101: "PROMISE_REACTION_TYPE",
|
||||
102: "PROPERTY_DESCRIPTOR_OBJECT_TYPE",
|
||||
103: "PROTOTYPE_INFO_TYPE",
|
||||
104: "SCRIPT_TYPE",
|
||||
105: "SOURCE_TEXT_MODULE_INFO_ENTRY_TYPE",
|
||||
106: "STACK_FRAME_INFO_TYPE",
|
||||
107: "STACK_TRACE_FRAME_TYPE",
|
||||
108: "TEMPLATE_OBJECT_DESCRIPTION_TYPE",
|
||||
109: "TUPLE2_TYPE",
|
||||
110: "WASM_CAPI_FUNCTION_DATA_TYPE",
|
||||
111: "WASM_DEBUG_INFO_TYPE",
|
||||
112: "WASM_EXCEPTION_TAG_TYPE",
|
||||
113: "WASM_EXPORTED_FUNCTION_DATA_TYPE",
|
||||
114: "WASM_INDIRECT_FUNCTION_TABLE_TYPE",
|
||||
115: "WASM_JS_FUNCTION_DATA_TYPE",
|
||||
116: "FIXED_ARRAY_TYPE",
|
||||
117: "HASH_TABLE_TYPE",
|
||||
118: "EPHEMERON_HASH_TABLE_TYPE",
|
||||
119: "GLOBAL_DICTIONARY_TYPE",
|
||||
120: "NAME_DICTIONARY_TYPE",
|
||||
121: "NUMBER_DICTIONARY_TYPE",
|
||||
122: "ORDERED_HASH_MAP_TYPE",
|
||||
123: "ORDERED_HASH_SET_TYPE",
|
||||
124: "ORDERED_NAME_DICTIONARY_TYPE",
|
||||
125: "SIMPLE_NUMBER_DICTIONARY_TYPE",
|
||||
126: "STRING_TABLE_TYPE",
|
||||
127: "CLOSURE_FEEDBACK_CELL_ARRAY_TYPE",
|
||||
128: "OBJECT_BOILERPLATE_DESCRIPTION_TYPE",
|
||||
129: "SCOPE_INFO_TYPE",
|
||||
130: "SCRIPT_CONTEXT_TABLE_TYPE",
|
||||
131: "BYTE_ARRAY_TYPE",
|
||||
132: "BYTECODE_ARRAY_TYPE",
|
||||
133: "FIXED_DOUBLE_ARRAY_TYPE",
|
||||
134: "INTERNAL_CLASS_WITH_SMI_ELEMENTS_TYPE",
|
||||
135: "AWAIT_CONTEXT_TYPE",
|
||||
136: "BLOCK_CONTEXT_TYPE",
|
||||
137: "CATCH_CONTEXT_TYPE",
|
||||
138: "DEBUG_EVALUATE_CONTEXT_TYPE",
|
||||
139: "EVAL_CONTEXT_TYPE",
|
||||
140: "FUNCTION_CONTEXT_TYPE",
|
||||
141: "MODULE_CONTEXT_TYPE",
|
||||
142: "NATIVE_CONTEXT_TYPE",
|
||||
143: "SCRIPT_CONTEXT_TYPE",
|
||||
144: "WITH_CONTEXT_TYPE",
|
||||
145: "SMALL_ORDERED_HASH_MAP_TYPE",
|
||||
146: "SMALL_ORDERED_HASH_SET_TYPE",
|
||||
147: "SMALL_ORDERED_NAME_DICTIONARY_TYPE",
|
||||
148: "SOURCE_TEXT_MODULE_TYPE",
|
||||
149: "SYNTHETIC_MODULE_TYPE",
|
||||
150: "UNCOMPILED_DATA_WITH_PREPARSE_DATA_TYPE",
|
||||
151: "UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_TYPE",
|
||||
152: "WEAK_FIXED_ARRAY_TYPE",
|
||||
153: "TRANSITION_ARRAY_TYPE",
|
||||
154: "CELL_TYPE",
|
||||
155: "CODE_TYPE",
|
||||
156: "CODE_DATA_CONTAINER_TYPE",
|
||||
157: "COVERAGE_INFO_TYPE",
|
||||
158: "DESCRIPTOR_ARRAY_TYPE",
|
||||
159: "EMBEDDER_DATA_ARRAY_TYPE",
|
||||
160: "FEEDBACK_METADATA_TYPE",
|
||||
161: "FEEDBACK_VECTOR_TYPE",
|
||||
162: "FILLER_TYPE",
|
||||
163: "FREE_SPACE_TYPE",
|
||||
164: "INTERNAL_CLASS_TYPE",
|
||||
165: "INTERNAL_CLASS_WITH_STRUCT_ELEMENTS_TYPE",
|
||||
166: "MAP_TYPE",
|
||||
167: "PREPARSE_DATA_TYPE",
|
||||
168: "PROPERTY_ARRAY_TYPE",
|
||||
169: "PROPERTY_CELL_TYPE",
|
||||
170: "SHARED_FUNCTION_INFO_TYPE",
|
||||
171: "SMI_BOX_TYPE",
|
||||
172: "SMI_PAIR_TYPE",
|
||||
173: "SORT_STATE_TYPE",
|
||||
174: "WEAK_ARRAY_LIST_TYPE",
|
||||
175: "WEAK_CELL_TYPE",
|
||||
176: "JS_PROXY_TYPE",
|
||||
1057: "JS_OBJECT_TYPE",
|
||||
173: "JS_GLOBAL_OBJECT_TYPE",
|
||||
174: "JS_GLOBAL_PROXY_TYPE",
|
||||
175: "JS_MODULE_NAMESPACE_TYPE",
|
||||
177: "JS_GLOBAL_OBJECT_TYPE",
|
||||
178: "JS_GLOBAL_PROXY_TYPE",
|
||||
179: "JS_MODULE_NAMESPACE_TYPE",
|
||||
1040: "JS_SPECIAL_API_OBJECT_TYPE",
|
||||
1041: "JS_PRIMITIVE_WRAPPER_TYPE",
|
||||
1042: "JS_MAP_KEY_ITERATOR_TYPE",
|
||||
@ -194,78 +198,78 @@ INSTANCE_TYPES = {
|
||||
|
||||
# List of known V8 maps.
|
||||
KNOWN_MAPS = {
|
||||
("read_only_space", 0x00121): (164, "FreeSpaceMap"),
|
||||
("read_only_space", 0x00149): (165, "MetaMap"),
|
||||
("read_only_space", 0x00121): (163, "FreeSpaceMap"),
|
||||
("read_only_space", 0x00149): (166, "MetaMap"),
|
||||
("read_only_space", 0x0018d): (67, "NullMap"),
|
||||
("read_only_space", 0x001c5): (159, "DescriptorArrayMap"),
|
||||
("read_only_space", 0x001f5): (153, "WeakFixedArrayMap"),
|
||||
("read_only_space", 0x0021d): (163, "OnePointerFillerMap"),
|
||||
("read_only_space", 0x00245): (163, "TwoPointerFillerMap"),
|
||||
("read_only_space", 0x001c5): (158, "DescriptorArrayMap"),
|
||||
("read_only_space", 0x001f5): (152, "WeakFixedArrayMap"),
|
||||
("read_only_space", 0x0021d): (162, "OnePointerFillerMap"),
|
||||
("read_only_space", 0x00245): (162, "TwoPointerFillerMap"),
|
||||
("read_only_space", 0x00289): (67, "UninitializedMap"),
|
||||
("read_only_space", 0x002cd): (8, "OneByteInternalizedStringMap"),
|
||||
("read_only_space", 0x00329): (67, "UndefinedMap"),
|
||||
("read_only_space", 0x0035d): (66, "HeapNumberMap"),
|
||||
("read_only_space", 0x003a1): (67, "TheHoleMap"),
|
||||
("read_only_space", 0x00401): (67, "BooleanMap"),
|
||||
("read_only_space", 0x00489): (135, "ByteArrayMap"),
|
||||
("read_only_space", 0x004b1): (120, "FixedArrayMap"),
|
||||
("read_only_space", 0x004d9): (120, "FixedCOWArrayMap"),
|
||||
("read_only_space", 0x00501): (121, "HashTableMap"),
|
||||
("read_only_space", 0x00489): (131, "ByteArrayMap"),
|
||||
("read_only_space", 0x004b1): (116, "FixedArrayMap"),
|
||||
("read_only_space", 0x004d9): (116, "FixedCOWArrayMap"),
|
||||
("read_only_space", 0x00501): (117, "HashTableMap"),
|
||||
("read_only_space", 0x00529): (64, "SymbolMap"),
|
||||
("read_only_space", 0x00551): (40, "OneByteStringMap"),
|
||||
("read_only_space", 0x00579): (133, "ScopeInfoMap"),
|
||||
("read_only_space", 0x005a1): (169, "SharedFunctionInfoMap"),
|
||||
("read_only_space", 0x005c9): (156, "CodeMap"),
|
||||
("read_only_space", 0x005f1): (155, "CellMap"),
|
||||
("read_only_space", 0x00619): (168, "GlobalPropertyCellMap"),
|
||||
("read_only_space", 0x00579): (129, "ScopeInfoMap"),
|
||||
("read_only_space", 0x005a1): (170, "SharedFunctionInfoMap"),
|
||||
("read_only_space", 0x005c9): (155, "CodeMap"),
|
||||
("read_only_space", 0x005f1): (154, "CellMap"),
|
||||
("read_only_space", 0x00619): (169, "GlobalPropertyCellMap"),
|
||||
("read_only_space", 0x00641): (70, "ForeignMap"),
|
||||
("read_only_space", 0x00669): (154, "TransitionArrayMap"),
|
||||
("read_only_space", 0x00669): (153, "TransitionArrayMap"),
|
||||
("read_only_space", 0x00691): (45, "ThinOneByteStringMap"),
|
||||
("read_only_space", 0x006b9): (162, "FeedbackVectorMap"),
|
||||
("read_only_space", 0x006b9): (161, "FeedbackVectorMap"),
|
||||
("read_only_space", 0x0070d): (67, "ArgumentsMarkerMap"),
|
||||
("read_only_space", 0x0076d): (67, "ExceptionMap"),
|
||||
("read_only_space", 0x007c9): (67, "TerminationExceptionMap"),
|
||||
("read_only_space", 0x00831): (67, "OptimizedOutMap"),
|
||||
("read_only_space", 0x00891): (67, "StaleRegisterMap"),
|
||||
("read_only_space", 0x008d5): (134, "ScriptContextTableMap"),
|
||||
("read_only_space", 0x008fd): (131, "ClosureFeedbackCellArrayMap"),
|
||||
("read_only_space", 0x00925): (161, "FeedbackMetadataArrayMap"),
|
||||
("read_only_space", 0x0094d): (120, "ArrayListMap"),
|
||||
("read_only_space", 0x008d5): (130, "ScriptContextTableMap"),
|
||||
("read_only_space", 0x008fd): (127, "ClosureFeedbackCellArrayMap"),
|
||||
("read_only_space", 0x00925): (160, "FeedbackMetadataArrayMap"),
|
||||
("read_only_space", 0x0094d): (116, "ArrayListMap"),
|
||||
("read_only_space", 0x00975): (65, "BigIntMap"),
|
||||
("read_only_space", 0x0099d): (132, "ObjectBoilerplateDescriptionMap"),
|
||||
("read_only_space", 0x009c5): (136, "BytecodeArrayMap"),
|
||||
("read_only_space", 0x009ed): (157, "CodeDataContainerMap"),
|
||||
("read_only_space", 0x00a15): (158, "CoverageInfoMap"),
|
||||
("read_only_space", 0x00a3d): (137, "FixedDoubleArrayMap"),
|
||||
("read_only_space", 0x00a65): (123, "GlobalDictionaryMap"),
|
||||
("read_only_space", 0x0099d): (128, "ObjectBoilerplateDescriptionMap"),
|
||||
("read_only_space", 0x009c5): (132, "BytecodeArrayMap"),
|
||||
("read_only_space", 0x009ed): (156, "CodeDataContainerMap"),
|
||||
("read_only_space", 0x00a15): (157, "CoverageInfoMap"),
|
||||
("read_only_space", 0x00a3d): (133, "FixedDoubleArrayMap"),
|
||||
("read_only_space", 0x00a65): (119, "GlobalDictionaryMap"),
|
||||
("read_only_space", 0x00a8d): (96, "ManyClosuresCellMap"),
|
||||
("read_only_space", 0x00ab5): (120, "ModuleInfoMap"),
|
||||
("read_only_space", 0x00add): (124, "NameDictionaryMap"),
|
||||
("read_only_space", 0x00ab5): (116, "ModuleInfoMap"),
|
||||
("read_only_space", 0x00add): (120, "NameDictionaryMap"),
|
||||
("read_only_space", 0x00b05): (96, "NoClosuresCellMap"),
|
||||
("read_only_space", 0x00b2d): (125, "NumberDictionaryMap"),
|
||||
("read_only_space", 0x00b2d): (121, "NumberDictionaryMap"),
|
||||
("read_only_space", 0x00b55): (96, "OneClosureCellMap"),
|
||||
("read_only_space", 0x00b7d): (126, "OrderedHashMapMap"),
|
||||
("read_only_space", 0x00ba5): (127, "OrderedHashSetMap"),
|
||||
("read_only_space", 0x00bcd): (128, "OrderedNameDictionaryMap"),
|
||||
("read_only_space", 0x00bf5): (166, "PreparseDataMap"),
|
||||
("read_only_space", 0x00c1d): (167, "PropertyArrayMap"),
|
||||
("read_only_space", 0x00b7d): (122, "OrderedHashMapMap"),
|
||||
("read_only_space", 0x00ba5): (123, "OrderedHashSetMap"),
|
||||
("read_only_space", 0x00bcd): (124, "OrderedNameDictionaryMap"),
|
||||
("read_only_space", 0x00bf5): (167, "PreparseDataMap"),
|
||||
("read_only_space", 0x00c1d): (168, "PropertyArrayMap"),
|
||||
("read_only_space", 0x00c45): (92, "SideEffectCallHandlerInfoMap"),
|
||||
("read_only_space", 0x00c6d): (92, "SideEffectFreeCallHandlerInfoMap"),
|
||||
("read_only_space", 0x00c95): (92, "NextCallSideEffectFreeCallHandlerInfoMap"),
|
||||
("read_only_space", 0x00cbd): (129, "SimpleNumberDictionaryMap"),
|
||||
("read_only_space", 0x00ce5): (120, "SloppyArgumentsElementsMap"),
|
||||
("read_only_space", 0x00d0d): (148, "SmallOrderedHashMapMap"),
|
||||
("read_only_space", 0x00d35): (149, "SmallOrderedHashSetMap"),
|
||||
("read_only_space", 0x00d5d): (150, "SmallOrderedNameDictionaryMap"),
|
||||
("read_only_space", 0x00d85): (68, "SourceTextModuleMap"),
|
||||
("read_only_space", 0x00dad): (130, "StringTableMap"),
|
||||
("read_only_space", 0x00dd5): (69, "SyntheticModuleMap"),
|
||||
("read_only_space", 0x00dfd): (152, "UncompiledDataWithoutPreparseDataMap"),
|
||||
("read_only_space", 0x00e25): (151, "UncompiledDataWithPreparseDataMap"),
|
||||
("read_only_space", 0x00e4d): (170, "WeakArrayListMap"),
|
||||
("read_only_space", 0x00e75): (122, "EphemeronHashTableMap"),
|
||||
("read_only_space", 0x00e9d): (160, "EmbedderDataArrayMap"),
|
||||
("read_only_space", 0x00ec5): (171, "WeakCellMap"),
|
||||
("read_only_space", 0x00cbd): (125, "SimpleNumberDictionaryMap"),
|
||||
("read_only_space", 0x00ce5): (116, "SloppyArgumentsElementsMap"),
|
||||
("read_only_space", 0x00d0d): (145, "SmallOrderedHashMapMap"),
|
||||
("read_only_space", 0x00d35): (146, "SmallOrderedHashSetMap"),
|
||||
("read_only_space", 0x00d5d): (147, "SmallOrderedNameDictionaryMap"),
|
||||
("read_only_space", 0x00d85): (148, "SourceTextModuleMap"),
|
||||
("read_only_space", 0x00dad): (126, "StringTableMap"),
|
||||
("read_only_space", 0x00dd5): (149, "SyntheticModuleMap"),
|
||||
("read_only_space", 0x00dfd): (151, "UncompiledDataWithoutPreparseDataMap"),
|
||||
("read_only_space", 0x00e25): (150, "UncompiledDataWithPreparseDataMap"),
|
||||
("read_only_space", 0x00e4d): (174, "WeakArrayListMap"),
|
||||
("read_only_space", 0x00e75): (118, "EphemeronHashTableMap"),
|
||||
("read_only_space", 0x00e9d): (159, "EmbedderDataArrayMap"),
|
||||
("read_only_space", 0x00ec5): (175, "WeakCellMap"),
|
||||
("read_only_space", 0x00eed): (32, "StringMap"),
|
||||
("read_only_space", 0x00f15): (41, "ConsOneByteStringMap"),
|
||||
("read_only_space", 0x00f3d): (33, "ConsStringMap"),
|
||||
@ -305,36 +309,40 @@ KNOWN_MAPS = {
|
||||
("read_only_space", 0x0357d): (93, "ClassPositionsMap"),
|
||||
("read_only_space", 0x035a5): (94, "DebugInfoMap"),
|
||||
("read_only_space", 0x035cd): (97, "FunctionTemplateRareDataMap"),
|
||||
("read_only_space", 0x035f5): (100, "InterpreterDataMap"),
|
||||
("read_only_space", 0x0361d): (101, "PromiseCapabilityMap"),
|
||||
("read_only_space", 0x03645): (102, "PromiseReactionMap"),
|
||||
("read_only_space", 0x0366d): (103, "PropertyDescriptorObjectMap"),
|
||||
("read_only_space", 0x03695): (104, "PrototypeInfoMap"),
|
||||
("read_only_space", 0x036bd): (105, "ScriptMap"),
|
||||
("read_only_space", 0x036e5): (109, "SourceTextModuleInfoEntryMap"),
|
||||
("read_only_space", 0x0370d): (110, "StackFrameInfoMap"),
|
||||
("read_only_space", 0x03735): (111, "StackTraceFrameMap"),
|
||||
("read_only_space", 0x0375d): (112, "TemplateObjectDescriptionMap"),
|
||||
("read_only_space", 0x03785): (113, "Tuple2Map"),
|
||||
("read_only_space", 0x037ad): (114, "WasmCapiFunctionDataMap"),
|
||||
("read_only_space", 0x037d5): (115, "WasmDebugInfoMap"),
|
||||
("read_only_space", 0x037fd): (116, "WasmExceptionTagMap"),
|
||||
("read_only_space", 0x03825): (117, "WasmExportedFunctionDataMap"),
|
||||
("read_only_space", 0x0384d): (118, "WasmIndirectFunctionTableMap"),
|
||||
("read_only_space", 0x03875): (119, "WasmJSFunctionDataMap"),
|
||||
("read_only_space", 0x0389d): (99, "InternalClassMap"),
|
||||
("read_only_space", 0x038c5): (107, "SmiPairMap"),
|
||||
("read_only_space", 0x038ed): (106, "SmiBoxMap"),
|
||||
("read_only_space", 0x03915): (108, "SortStateMap"),
|
||||
("read_only_space", 0x0393d): (85, "AllocationSiteWithWeakNextMap"),
|
||||
("read_only_space", 0x03965): (85, "AllocationSiteWithoutWeakNextMap"),
|
||||
("read_only_space", 0x0398d): (76, "LoadHandler1Map"),
|
||||
("read_only_space", 0x039b5): (76, "LoadHandler2Map"),
|
||||
("read_only_space", 0x039dd): (76, "LoadHandler3Map"),
|
||||
("read_only_space", 0x03a05): (77, "StoreHandler0Map"),
|
||||
("read_only_space", 0x03a2d): (77, "StoreHandler1Map"),
|
||||
("read_only_space", 0x03a55): (77, "StoreHandler2Map"),
|
||||
("read_only_space", 0x03a7d): (77, "StoreHandler3Map"),
|
||||
("read_only_space", 0x035f5): (99, "InterpreterDataMap"),
|
||||
("read_only_space", 0x0361d): (100, "PromiseCapabilityMap"),
|
||||
("read_only_space", 0x03645): (101, "PromiseReactionMap"),
|
||||
("read_only_space", 0x0366d): (102, "PropertyDescriptorObjectMap"),
|
||||
("read_only_space", 0x03695): (103, "PrototypeInfoMap"),
|
||||
("read_only_space", 0x036bd): (104, "ScriptMap"),
|
||||
("read_only_space", 0x036e5): (105, "SourceTextModuleInfoEntryMap"),
|
||||
("read_only_space", 0x0370d): (106, "StackFrameInfoMap"),
|
||||
("read_only_space", 0x03735): (107, "StackTraceFrameMap"),
|
||||
("read_only_space", 0x0375d): (108, "TemplateObjectDescriptionMap"),
|
||||
("read_only_space", 0x03785): (109, "Tuple2Map"),
|
||||
("read_only_space", 0x037ad): (110, "WasmCapiFunctionDataMap"),
|
||||
("read_only_space", 0x037d5): (111, "WasmDebugInfoMap"),
|
||||
("read_only_space", 0x037fd): (112, "WasmExceptionTagMap"),
|
||||
("read_only_space", 0x03825): (113, "WasmExportedFunctionDataMap"),
|
||||
("read_only_space", 0x0384d): (114, "WasmIndirectFunctionTableMap"),
|
||||
("read_only_space", 0x03875): (115, "WasmJSFunctionDataMap"),
|
||||
("read_only_space", 0x0389d): (134, "InternalClassWithSmiElementsMap"),
|
||||
("read_only_space", 0x038c5): (165, "InternalClassWithStructElementsMap"),
|
||||
("read_only_space", 0x038ed): (164, "InternalClassMap"),
|
||||
("read_only_space", 0x03915): (172, "SmiPairMap"),
|
||||
("read_only_space", 0x0393d): (171, "SmiBoxMap"),
|
||||
("read_only_space", 0x03965): (68, "ExportedSubClassBaseMap"),
|
||||
("read_only_space", 0x0398d): (69, "ExportedSubClassMap"),
|
||||
("read_only_space", 0x039b5): (173, "SortStateMap"),
|
||||
("read_only_space", 0x039dd): (85, "AllocationSiteWithWeakNextMap"),
|
||||
("read_only_space", 0x03a05): (85, "AllocationSiteWithoutWeakNextMap"),
|
||||
("read_only_space", 0x03a2d): (76, "LoadHandler1Map"),
|
||||
("read_only_space", 0x03a55): (76, "LoadHandler2Map"),
|
||||
("read_only_space", 0x03a7d): (76, "LoadHandler3Map"),
|
||||
("read_only_space", 0x03aa5): (77, "StoreHandler0Map"),
|
||||
("read_only_space", 0x03acd): (77, "StoreHandler1Map"),
|
||||
("read_only_space", 0x03af5): (77, "StoreHandler2Map"),
|
||||
("read_only_space", 0x03b1d): (77, "StoreHandler3Map"),
|
||||
("map_space", 0x00121): (1057, "ExternalMap"),
|
||||
("map_space", 0x00149): (1073, "JSMessageObjectMap"),
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user