[wasm-gc] Implement anyref
Bug: v8:7748 Change-Id: I5d0cc06fafbe7fc05549a4b8fd7f602eaf838bba Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2526382 Commit-Queue: Manos Koukoutos <manoskouk@chromium.org> Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Cr-Commit-Position: refs/heads/master@{#71283}
This commit is contained in:
parent
b0295b8c65
commit
ba5fa195ed
@ -5665,32 +5665,35 @@ Node* WasmGraphBuilder::ArrayNewWithRtt(uint32_t array_index,
|
||||
}
|
||||
|
||||
Node* WasmGraphBuilder::RttCanon(wasm::HeapType type) {
|
||||
if (type.is_generic()) {
|
||||
RootIndex index;
|
||||
switch (type.representation()) {
|
||||
case wasm::HeapType::kEq:
|
||||
return LOAD_FULL_POINTER(
|
||||
BuildLoadIsolateRoot(),
|
||||
IsolateData::root_slot_offset(RootIndex::kWasmRttEqrefMap));
|
||||
index = RootIndex::kWasmRttEqrefMap;
|
||||
break;
|
||||
case wasm::HeapType::kExtern:
|
||||
return LOAD_FULL_POINTER(
|
||||
BuildLoadIsolateRoot(),
|
||||
IsolateData::root_slot_offset(RootIndex::kWasmRttExternrefMap));
|
||||
index = RootIndex::kWasmRttExternrefMap;
|
||||
break;
|
||||
case wasm::HeapType::kFunc:
|
||||
return LOAD_FULL_POINTER(
|
||||
BuildLoadIsolateRoot(),
|
||||
IsolateData::root_slot_offset(RootIndex::kWasmRttFuncrefMap));
|
||||
index = RootIndex::kWasmRttFuncrefMap;
|
||||
break;
|
||||
case wasm::HeapType::kI31:
|
||||
return LOAD_FULL_POINTER(
|
||||
BuildLoadIsolateRoot(),
|
||||
IsolateData::root_slot_offset(RootIndex::kWasmRttI31refMap));
|
||||
default:
|
||||
index = RootIndex::kWasmRttI31refMap;
|
||||
break;
|
||||
case wasm::HeapType::kAny:
|
||||
index = RootIndex::kWasmRttAnyrefMap;
|
||||
break;
|
||||
case wasm::HeapType::kBottom:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
default: {
|
||||
// User-defined type.
|
||||
Node* maps_list =
|
||||
LOAD_INSTANCE_FIELD(ManagedObjectMaps, MachineType::TaggedPointer());
|
||||
return LOAD_FIXED_ARRAY_SLOT_PTR(maps_list, type.ref_index());
|
||||
}
|
||||
}
|
||||
return LOAD_FULL_POINTER(BuildLoadIsolateRoot(),
|
||||
IsolateData::root_slot_offset(index));
|
||||
}
|
||||
|
||||
Node* WasmGraphBuilder::RttSub(wasm::HeapType type, Node* parent_rtt) {
|
||||
return CALL_BUILTIN(
|
||||
@ -5731,6 +5734,7 @@ Node* WasmGraphBuilder::RefTest(Node* object, Node* rtt,
|
||||
|
||||
Node* map = gasm_->LoadMap(object);
|
||||
gasm_->GotoIf(gasm_->TaggedEqual(map, rtt), &done, gasm_->Int32Constant(1));
|
||||
|
||||
if (!config.object_must_be_data_ref) {
|
||||
gasm_->GotoIfNot(gasm_->IsDataRefMap(map), &done, gasm_->Int32Constant(0));
|
||||
}
|
||||
@ -6235,12 +6239,17 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
|
||||
if (representation == wasm::HeapType::kEq) {
|
||||
return BuildAllocateObjectWrapper(node);
|
||||
}
|
||||
if (representation == wasm::HeapType::kAny) {
|
||||
// TODO(7748): Add wrapping for arrays/structs, or proper JS API when
|
||||
// available.
|
||||
return node;
|
||||
}
|
||||
if (type.has_index() && module_->has_signature(type.ref_index())) {
|
||||
// Typed function
|
||||
return node;
|
||||
}
|
||||
// TODO(7748): Figure out a JS interop story for arrays and structs.
|
||||
// If this is reached, then IsJSCompatibleSignature() is too permissive.
|
||||
// TODO(7748): Figure out a JS interop story for arrays and structs.
|
||||
UNREACHABLE();
|
||||
}
|
||||
case wasm::ValueType::kRtt:
|
||||
@ -6354,6 +6363,9 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
|
||||
switch (type.heap_representation()) {
|
||||
case wasm::HeapType::kExtern:
|
||||
case wasm::HeapType::kExn:
|
||||
// TODO(7748): Possibly implement different cases for 'any' when the
|
||||
// JS API has settled.
|
||||
case wasm::HeapType::kAny:
|
||||
return input;
|
||||
case wasm::HeapType::kFunc:
|
||||
BuildCheckValidRefValue(input, js_context, type);
|
||||
|
@ -511,6 +511,7 @@ bool Heap::CreateInitialMaps() {
|
||||
ALLOCATE_MAP(WASM_STRUCT_TYPE, 0, wasm_rttcanon_externref)
|
||||
ALLOCATE_MAP(WASM_STRUCT_TYPE, 0, wasm_rttcanon_funcref)
|
||||
ALLOCATE_MAP(WASM_STRUCT_TYPE, 0, wasm_rttcanon_i31ref)
|
||||
ALLOCATE_MAP(WASM_STRUCT_TYPE, 0, wasm_rttcanon_anyref)
|
||||
ALLOCATE_MAP(WASM_TYPE_INFO_TYPE, WasmTypeInfo::kSize, wasm_type_info)
|
||||
|
||||
ALLOCATE_MAP(WEAK_CELL_TYPE, WeakCell::kSize, weak_cell)
|
||||
@ -611,8 +612,36 @@ bool Heap::CreateInitialMaps() {
|
||||
}
|
||||
|
||||
// Set up the WasmTypeInfo objects for built-in generic Wasm RTTs.
|
||||
// anyref:
|
||||
{
|
||||
/* Subtypes. We do not cache subtypes for (rtt.canon any). */
|
||||
int slot_count = ArrayList::kHeaderFields;
|
||||
if (!AllocateRaw(ArrayList::SizeFor(slot_count), AllocationType::kOld)
|
||||
.To(&obj)) {
|
||||
return false;
|
||||
}
|
||||
obj.set_map_after_allocation(roots.array_list_map());
|
||||
ArrayList subtypes = ArrayList::cast(obj);
|
||||
subtypes.set_length(slot_count);
|
||||
subtypes.SetLength(0);
|
||||
/* TypeInfo */
|
||||
if (!AllocateRaw(WasmTypeInfo::kSize, AllocationType::kOld).To(&obj)) {
|
||||
return false;
|
||||
}
|
||||
obj.set_map_after_allocation(roots.wasm_type_info_map(),
|
||||
SKIP_WRITE_BARRIER);
|
||||
WasmTypeInfo type_info = WasmTypeInfo::cast(obj);
|
||||
type_info.set_subtypes(subtypes);
|
||||
type_info.set_supertypes(roots.empty_fixed_array());
|
||||
type_info.set_parent(roots.null_map());
|
||||
type_info.clear_foreign_address(isolate());
|
||||
wasm_rttcanon_anyref_map().set_wasm_type_info(type_info);
|
||||
}
|
||||
|
||||
// Rest of builtin types:
|
||||
#define ALLOCATE_TYPE_INFO(which) \
|
||||
{ \
|
||||
/* Subtypes */ \
|
||||
int slot_count = ArrayList::kHeaderFields; \
|
||||
if (!AllocateRaw(ArrayList::SizeFor(slot_count), AllocationType::kOld) \
|
||||
.To(&obj)) { \
|
||||
@ -622,6 +651,15 @@ bool Heap::CreateInitialMaps() {
|
||||
ArrayList subtypes = ArrayList::cast(obj); \
|
||||
subtypes.set_length(slot_count); \
|
||||
subtypes.SetLength(0); \
|
||||
/* Supertypes */ \
|
||||
if (!AllocateRaw(FixedArray::SizeFor(1), AllocationType::kOld).To(&obj)) { \
|
||||
return false; \
|
||||
} \
|
||||
obj.set_map_after_allocation(roots.fixed_array_map(), SKIP_WRITE_BARRIER); \
|
||||
FixedArray supertypes = FixedArray::cast(obj); \
|
||||
supertypes.set_length(1); \
|
||||
supertypes.set(0, wasm_rttcanon_anyref_map()); \
|
||||
/* TypeInfo */ \
|
||||
if (!AllocateRaw(WasmTypeInfo::kSize, AllocationType::kOld).To(&obj)) { \
|
||||
return false; \
|
||||
} \
|
||||
@ -629,8 +667,8 @@ bool Heap::CreateInitialMaps() {
|
||||
SKIP_WRITE_BARRIER); \
|
||||
WasmTypeInfo type_info = WasmTypeInfo::cast(obj); \
|
||||
type_info.set_subtypes(subtypes); \
|
||||
type_info.set_supertypes(roots.empty_fixed_array()); \
|
||||
type_info.set_parent(roots.null_map()); \
|
||||
type_info.set_supertypes(supertypes); \
|
||||
type_info.set_parent(wasm_rttcanon_anyref_map()); \
|
||||
type_info.clear_foreign_address(isolate()); \
|
||||
wasm_rttcanon_##which##_map().set_wasm_type_info(type_info); \
|
||||
}
|
||||
|
@ -205,6 +205,7 @@ class Symbol;
|
||||
V(Map, wasm_rttcanon_externref_map, WasmRttExternrefMap) \
|
||||
V(Map, wasm_rttcanon_funcref_map, WasmRttFuncrefMap) \
|
||||
V(Map, wasm_rttcanon_i31ref_map, WasmRttI31refMap) \
|
||||
V(Map, wasm_rttcanon_anyref_map, WasmRttAnyrefMap) \
|
||||
/* Canonical empty values */ \
|
||||
V(Script, empty_script, EmptyScript) \
|
||||
V(FeedbackCell, many_closures_cell, ManyClosuresCell) \
|
||||
|
@ -187,7 +187,9 @@ V8_INLINE WasmFeature feature_for_heap_type(HeapType heap_type) {
|
||||
return WasmFeature::kFeature_eh;
|
||||
case HeapType::kEq:
|
||||
case HeapType::kI31:
|
||||
case HeapType::kAny:
|
||||
return WasmFeature::kFeature_gc;
|
||||
case HeapType::kBottom:
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
@ -211,7 +213,8 @@ HeapType read_heap_type(Decoder* decoder, const byte* pc,
|
||||
case kExnRefCode:
|
||||
case kEqRefCode:
|
||||
case kExternRefCode:
|
||||
case kI31RefCode: {
|
||||
case kI31RefCode:
|
||||
case kAnyRefCode: {
|
||||
HeapType result = HeapType::from_code(code);
|
||||
if (!VALIDATE(enabled.contains(feature_for_heap_type(result)))) {
|
||||
DecodeError<validate>(
|
||||
@ -269,7 +272,8 @@ ValueType read_value_type(Decoder* decoder, const byte* pc,
|
||||
case kExnRefCode:
|
||||
case kEqRefCode:
|
||||
case kExternRefCode:
|
||||
case kI31RefCode: {
|
||||
case kI31RefCode:
|
||||
case kAnyRefCode: {
|
||||
HeapType heap_type = HeapType::from_code(code);
|
||||
ValueType result = ValueType::Ref(
|
||||
heap_type, code == kI31RefCode ? kNonNullable : kNullable);
|
||||
@ -3875,7 +3879,8 @@ class WasmFullDecoder : public WasmDecoder<validate> {
|
||||
HeapTypeImmediate<validate> imm(this->enabled_, this,
|
||||
this->pc_ + opcode_length);
|
||||
if (!this->Validate(this->pc_ + opcode_length, imm)) return 0;
|
||||
Value* value = Push(ValueType::Rtt(imm.type, 1));
|
||||
Value* value =
|
||||
Push(ValueType::Rtt(imm.type, imm.type == HeapType::kAny ? 0 : 1));
|
||||
CALL_INTERFACE_IF_REACHABLE(RttCanon, imm, value);
|
||||
return opcode_length + imm.length;
|
||||
}
|
||||
@ -3905,8 +3910,17 @@ class WasmFullDecoder : public WasmDecoder<validate> {
|
||||
}
|
||||
Value* value =
|
||||
Push(ValueType::Rtt(imm.type, parent.type.depth() + 1));
|
||||
// (rtt.sub $t (rtt.canon any)) is reduced to (rtt.canon $t),
|
||||
// unless t == any.
|
||||
// This is important because other canonical rtts are not cached in
|
||||
// (rtt.canon any)'s subtype list.
|
||||
if (parent.type == ValueType::Rtt(HeapType::kAny, 0) &&
|
||||
imm.type != HeapType::kAny) {
|
||||
CALL_INTERFACE_IF_REACHABLE(RttCanon, imm, value);
|
||||
} else {
|
||||
CALL_INTERFACE_IF_REACHABLE(RttSub, imm, parent, value);
|
||||
}
|
||||
}
|
||||
return opcode_length + imm.length;
|
||||
}
|
||||
case kExprRefTest: {
|
||||
|
@ -1358,10 +1358,10 @@ class ModuleDecoderImpl : public Decoder {
|
||||
}
|
||||
case WasmInitExpr::kRefNullConst:
|
||||
return ValueType::Ref(expr.immediate().heap_type, kNullable);
|
||||
case WasmInitExpr::kRttCanon:
|
||||
// TODO(7748): If heaptype is "anyref" (not introduced yet),
|
||||
// then this should be uint8_t{0}.
|
||||
return ValueType::Rtt(expr.immediate().heap_type, uint8_t{1});
|
||||
case WasmInitExpr::kRttCanon: {
|
||||
uint8_t depth = expr.immediate().heap_type == HeapType::kAny ? 0 : 1;
|
||||
return ValueType::Rtt(expr.immediate().heap_type, depth);
|
||||
}
|
||||
case WasmInitExpr::kRttSub: {
|
||||
ValueType operand_type = TypeOf(*expr.operand());
|
||||
if (operand_type.is_rtt()) {
|
||||
|
@ -603,24 +603,24 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
|
||||
//--------------------------------------------------------------------------
|
||||
// Create maps for managed objects (GC proposal).
|
||||
// Must happen before {InitGlobals} because globals can refer to these maps.
|
||||
// We do not need to cache the canonical rtts to (rtt.canon any)'s subtype
|
||||
// list.
|
||||
//--------------------------------------------------------------------------
|
||||
if (enabled_.has_gc()) {
|
||||
Handle<FixedArray> maps = isolate_->factory()->NewUninitializedFixedArray(
|
||||
static_cast<int>(module_->type_kinds.size()));
|
||||
// TODO(7748): Do we want a different sentinel here?
|
||||
Handle<Map> anyref_sentinel_map = isolate_->factory()->null_map();
|
||||
Handle<Map> anyref_map =
|
||||
Handle<Map>::cast(isolate_->root_handle(RootIndex::kWasmRttAnyrefMap));
|
||||
for (int map_index = 0;
|
||||
map_index < static_cast<int>(module_->type_kinds.size());
|
||||
map_index++) {
|
||||
Handle<Map> map;
|
||||
switch (module_->type_kinds[map_index]) {
|
||||
case kWasmStructTypeCode:
|
||||
map = CreateStructMap(isolate_, module_, map_index,
|
||||
anyref_sentinel_map);
|
||||
map = CreateStructMap(isolate_, module_, map_index, anyref_map);
|
||||
break;
|
||||
case kWasmArrayTypeCode:
|
||||
map =
|
||||
CreateArrayMap(isolate_, module_, map_index, anyref_sentinel_map);
|
||||
map = CreateArrayMap(isolate_, module_, map_index, anyref_map);
|
||||
break;
|
||||
case kWasmFunctionTypeCode:
|
||||
// TODO(7748): Think about canonicalizing rtts to make them work for
|
||||
@ -1599,6 +1599,8 @@ Handle<Object> InstanceBuilder::RecursivelyEvaluateGlobalInitializer(
|
||||
return isolate_->root_handle(RootIndex::kWasmRttFuncrefMap);
|
||||
case wasm::HeapType::kI31:
|
||||
return isolate_->root_handle(RootIndex::kWasmRttI31refMap);
|
||||
case wasm::HeapType::kAny:
|
||||
return isolate_->root_handle(RootIndex::kWasmRttAnyrefMap);
|
||||
case wasm::HeapType::kExn:
|
||||
UNIMPLEMENTED(); // TODO(jkummerow): This is going away?
|
||||
case wasm::HeapType::kBottom:
|
||||
|
@ -57,6 +57,7 @@ class HeapType {
|
||||
kEq, // shorthand: q
|
||||
kExn, // shorthand: x
|
||||
kI31, // shorthand: j
|
||||
kAny, // shorthand: a
|
||||
// This value is used to represent failures in the parsing of heap types and
|
||||
// does not correspond to a wasm heap type.
|
||||
kBottom
|
||||
@ -64,7 +65,7 @@ class HeapType {
|
||||
// Internal use only; defined in the public section to make it easy to
|
||||
// check that they are defined correctly:
|
||||
static constexpr Representation kFirstSentinel = kFunc;
|
||||
static constexpr Representation kLastSentinel = kI31;
|
||||
static constexpr Representation kLastSentinel = kAny;
|
||||
|
||||
static constexpr HeapType from_code(uint8_t code) {
|
||||
switch (code) {
|
||||
@ -78,6 +79,8 @@ class HeapType {
|
||||
return HeapType(kExn);
|
||||
case ValueTypeCode::kI31RefCode:
|
||||
return HeapType(kI31);
|
||||
case ValueTypeCode::kAnyRefCode:
|
||||
return HeapType(kAny);
|
||||
default:
|
||||
return HeapType(kBottom);
|
||||
}
|
||||
@ -130,6 +133,8 @@ class HeapType {
|
||||
return std::string("exn");
|
||||
case kI31:
|
||||
return std::string("i31");
|
||||
case kAny:
|
||||
return std::string("any");
|
||||
default:
|
||||
return std::to_string(representation_);
|
||||
}
|
||||
@ -151,6 +156,8 @@ class HeapType {
|
||||
return mask | kEqRefCode;
|
||||
case kI31:
|
||||
return mask | kI31RefCode;
|
||||
case kAny:
|
||||
return mask | kAnyRefCode;
|
||||
default:
|
||||
return static_cast<int32_t>(representation_);
|
||||
}
|
||||
@ -366,6 +373,8 @@ class ValueType {
|
||||
return kEqRefCode;
|
||||
case HeapType::kExn:
|
||||
return kExnRefCode;
|
||||
case HeapType::kAny:
|
||||
return kAnyRefCode;
|
||||
default:
|
||||
return kOptRefCode;
|
||||
}
|
||||
@ -503,6 +512,7 @@ constexpr ValueType kWasmExternRef =
|
||||
ValueType::Ref(HeapType::kExtern, kNullable);
|
||||
constexpr ValueType kWasmEqRef = ValueType::Ref(HeapType::kEq, kNullable);
|
||||
constexpr ValueType kWasmI31Ref = ValueType::Ref(HeapType::kI31, kNonNullable);
|
||||
constexpr ValueType kWasmAnyRef = ValueType::Ref(HeapType::kAny, kNullable);
|
||||
|
||||
#define FOREACH_WASMVALUE_CTYPES(V) \
|
||||
V(kI32, int32_t) \
|
||||
|
@ -33,7 +33,7 @@ enum ValueTypeCode : uint8_t {
|
||||
kI16Code = 0x79,
|
||||
kFuncRefCode = 0x70,
|
||||
kExternRefCode = 0x6f,
|
||||
// kAnyCode = 0x6e, // TODO(7748): Implement
|
||||
kAnyRefCode = 0x6e,
|
||||
kEqRefCode = 0x6d,
|
||||
kOptRefCode = 0x6c,
|
||||
kRefCode = 0x6b,
|
||||
|
@ -1351,7 +1351,8 @@ void WebAssemblyGlobal(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
case i::wasm::ValueType::kOptRef: {
|
||||
switch (type.heap_representation()) {
|
||||
case i::wasm::HeapType::kExtern:
|
||||
case i::wasm::HeapType::kExn: {
|
||||
case i::wasm::HeapType::kExn:
|
||||
case i::wasm::HeapType::kAny: {
|
||||
if (args.Length() < 2) {
|
||||
// When no initial value is provided, we have to use the WebAssembly
|
||||
// default value 'null', and not the JS default value 'undefined'.
|
||||
@ -1851,6 +1852,7 @@ void WebAssemblyGlobalGetValueCommon(
|
||||
case i::wasm::HeapType::kExtern:
|
||||
case i::wasm::HeapType::kFunc:
|
||||
case i::wasm::HeapType::kExn:
|
||||
case i::wasm::HeapType::kAny:
|
||||
return_value.Set(Utils::ToLocal(receiver->GetRef()));
|
||||
break;
|
||||
case i::wasm::HeapType::kEq:
|
||||
@ -1939,6 +1941,7 @@ void WebAssemblyGlobalSetValue(
|
||||
switch (receiver->type().heap_representation()) {
|
||||
case i::wasm::HeapType::kExtern:
|
||||
case i::wasm::HeapType::kExn:
|
||||
case i::wasm::HeapType::kAny:
|
||||
receiver->SetExternRef(Utils::OpenHandle(*args[0]));
|
||||
break;
|
||||
case i::wasm::HeapType::kFunc: {
|
||||
|
@ -189,9 +189,9 @@ void WasmGlobalObject::SetF64(double value) {
|
||||
}
|
||||
|
||||
void WasmGlobalObject::SetExternRef(Handle<Object> value) {
|
||||
// We use this getter externref and exnref.
|
||||
DCHECK(type().is_reference_to(wasm::HeapType::kExtern) ||
|
||||
type().is_reference_to(wasm::HeapType::kExn));
|
||||
type().is_reference_to(wasm::HeapType::kExn) ||
|
||||
type().is_reference_to(wasm::HeapType::kAny));
|
||||
tagged_buffer().set(offset(), *value);
|
||||
}
|
||||
|
||||
|
@ -446,6 +446,7 @@ void WasmTableObject::Set(Isolate* isolate, Handle<WasmTableObject> table,
|
||||
switch (table->type().heap_representation()) {
|
||||
case wasm::HeapType::kExtern:
|
||||
case wasm::HeapType::kExn:
|
||||
case wasm::HeapType::kAny:
|
||||
entries->set(entry_index, *entry);
|
||||
return;
|
||||
case wasm::HeapType::kFunc:
|
||||
@ -500,6 +501,7 @@ Handle<Object> WasmTableObject::Get(Isolate* isolate,
|
||||
break;
|
||||
case wasm::HeapType::kEq:
|
||||
case wasm::HeapType::kI31:
|
||||
case wasm::HeapType::kAny:
|
||||
// TODO(7748): Implement once we have a story for struct/arrays/i31ref in
|
||||
// JS.
|
||||
UNIMPLEMENTED();
|
||||
@ -2155,6 +2157,7 @@ bool TypecheckJSObject(Isolate* isolate, const WasmModule* module,
|
||||
}
|
||||
case HeapType::kExtern:
|
||||
case HeapType::kExn:
|
||||
case HeapType::kAny:
|
||||
return true;
|
||||
case HeapType::kEq: {
|
||||
// TODO(7748): Change this when we have a decision on the JS API for
|
||||
|
@ -269,29 +269,26 @@ bool FunctionIsSubtypeOf(uint32_t subtype_index, uint32_t supertype_index,
|
||||
|
||||
} // namespace
|
||||
|
||||
// TODO(7748): Extend this with any-heap subtyping.
|
||||
V8_NOINLINE V8_EXPORT_PRIVATE bool IsSubtypeOfImpl(
|
||||
ValueType subtype, ValueType supertype, const WasmModule* sub_module,
|
||||
const WasmModule* super_module) {
|
||||
DCHECK(subtype != supertype || sub_module != super_module);
|
||||
|
||||
// This function checks for subtyping based on the kind of subtype.
|
||||
|
||||
if (!subtype.is_reference_type()) return subtype == supertype;
|
||||
|
||||
if (subtype.kind() == ValueType::kRtt) {
|
||||
if (subtype.is_rtt()) {
|
||||
return subtype.heap_type().is_generic()
|
||||
? subtype == supertype
|
||||
: (supertype.kind() == ValueType::kRtt &&
|
||||
subtype.depth() == supertype.depth() &&
|
||||
: (supertype.is_rtt() && subtype.depth() == supertype.depth() &&
|
||||
supertype.has_index() &&
|
||||
EquivalentIndices(subtype.ref_index(), supertype.ref_index(),
|
||||
sub_module, super_module));
|
||||
}
|
||||
|
||||
DCHECK(subtype.is_object_reference_type());
|
||||
|
||||
bool compatible_references = subtype.kind() == ValueType::kOptRef
|
||||
? supertype.kind() == ValueType::kOptRef
|
||||
bool compatible_references = subtype.is_nullable()
|
||||
? supertype.is_nullable()
|
||||
: supertype.is_object_reference_type();
|
||||
if (!compatible_references) return false;
|
||||
|
||||
@ -302,23 +299,43 @@ V8_NOINLINE V8_EXPORT_PRIVATE bool IsSubtypeOfImpl(
|
||||
HeapType sub_heap = subtype.heap_type();
|
||||
HeapType super_heap = supertype.heap_type();
|
||||
|
||||
if (sub_heap.representation() == HeapType::kI31 &&
|
||||
super_heap.representation() == HeapType::kEq) {
|
||||
return true;
|
||||
switch (sub_heap.representation()) {
|
||||
case HeapType::kFunc:
|
||||
case HeapType::kExtern:
|
||||
case HeapType::kEq:
|
||||
case HeapType::kExn:
|
||||
return sub_heap == super_heap || super_heap == HeapType::kAny;
|
||||
case HeapType::kAny:
|
||||
return super_heap == HeapType::kAny;
|
||||
case HeapType::kI31:
|
||||
return super_heap == HeapType::kI31 || super_heap == HeapType::kEq ||
|
||||
super_heap == HeapType::kAny;
|
||||
case HeapType::kBottom:
|
||||
UNREACHABLE();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (sub_heap.is_generic()) return sub_heap == super_heap;
|
||||
|
||||
DCHECK(sub_heap.is_index());
|
||||
uint32_t sub_index = sub_heap.ref_index();
|
||||
DCHECK(sub_module->has_type(sub_index));
|
||||
|
||||
if (super_heap.representation() == HeapType::kEq) {
|
||||
return !sub_module->has_signature(sub_heap.ref_index());
|
||||
switch (super_heap.representation()) {
|
||||
case HeapType::kFunc:
|
||||
return sub_module->has_signature(sub_index);
|
||||
case HeapType::kEq:
|
||||
return !sub_module->has_signature(sub_index);
|
||||
case HeapType::kExtern:
|
||||
case HeapType::kExn:
|
||||
case HeapType::kI31:
|
||||
return false;
|
||||
case HeapType::kAny:
|
||||
return true;
|
||||
case HeapType::kBottom:
|
||||
UNREACHABLE();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (super_heap.representation() == HeapType::kFunc) {
|
||||
return sub_module->has_signature(sub_heap.ref_index());
|
||||
}
|
||||
if (super_heap.is_generic()) return false;
|
||||
|
||||
DCHECK(super_heap.is_index());
|
||||
uint32_t super_index = super_heap.ref_index();
|
||||
@ -358,7 +375,7 @@ V8_NOINLINE bool EquivalentTypes(ValueType type1, ValueType type2,
|
||||
DCHECK(type1.has_index() && type2.has_index() &&
|
||||
(type1 != type2 || module1 != module2));
|
||||
|
||||
DCHECK_IMPLIES(type1.has_depth(), type2.has_depth()); // Due to 'if' above
|
||||
DCHECK_IMPLIES(type1.has_depth(), type2.has_depth()); // Due to 'if' above.
|
||||
if (type1.has_depth() && type1.depth() != type2.depth()) return false;
|
||||
|
||||
DCHECK(type1.has_index() && module1->has_type(type1.ref_index()) &&
|
||||
|
@ -21,7 +21,7 @@ V8_NOINLINE V8_EXPORT_PRIVATE bool IsSubtypeOfImpl(
|
||||
// module2.
|
||||
// Type equivalence (~) is described by the following rules (structural
|
||||
// equivalence):
|
||||
// - Two numeric types are equivalent if they are equal.
|
||||
// - Two numeric types are equivalent iff they are equal.
|
||||
// - optref(ht1) ~ optref(ht2) iff ht1 ~ ht2.
|
||||
// - ref(ht1) ~ ref(ht2) iff ht1 ~ ht2.
|
||||
// - rtt(d1, ht1) ~ rtt(d2, ht2) iff (d1 = d2 and ht1 ~ ht2).
|
||||
@ -46,6 +46,7 @@ V8_NOINLINE bool EquivalentTypes(ValueType type1, ValueType type2,
|
||||
// - rtt1 <: rtt2 iff rtt1 ~ rtt2.
|
||||
// For heap types, the following subtyping rules hold:
|
||||
// - Each generic heap type is a subtype of itself.
|
||||
// - All heap types are subtypes of any.
|
||||
// - All functions are subtypes of func.
|
||||
// - i31, structs and arrays are subtypes of eq.
|
||||
// - Struct subtyping: Subtype must have at least as many fields as supertype,
|
||||
|
@ -853,6 +853,80 @@ TEST(BasicRTT) {
|
||||
tester.CheckResult(kRefCast, 43);
|
||||
}
|
||||
|
||||
TEST(AnyRefRtt) {
|
||||
WasmGCTester tester;
|
||||
|
||||
ValueType any_rtt_0_type = ValueType::Rtt(HeapType::kAny, 0);
|
||||
FunctionSig sig_any_canon(1, 0, &any_rtt_0_type);
|
||||
byte kAnyRttCanon = tester.DefineFunction(
|
||||
&sig_any_canon, {}, {WASM_RTT_CANON(kAnyRefCode), kExprEnd});
|
||||
|
||||
ValueType any_rtt_1_type = ValueType::Rtt(HeapType::kAny, 1);
|
||||
FunctionSig sig_any_sub(1, 0, &any_rtt_1_type);
|
||||
byte kAnyRttSub = tester.DefineFunction(
|
||||
&sig_any_sub, {},
|
||||
{WASM_RTT_SUB(kAnyRefCode, WASM_RTT_CANON(kAnyRefCode)), kExprEnd});
|
||||
|
||||
ValueType func_rtt_1_type = ValueType::Rtt(HeapType::kFunc, 1);
|
||||
FunctionSig sig_func_sub(1, 0, &func_rtt_1_type);
|
||||
byte kFuncRttSub = tester.DefineFunction(
|
||||
&sig_func_sub, {},
|
||||
{WASM_RTT_SUB(kFuncRefCode, WASM_RTT_CANON(kAnyRefCode)), kExprEnd});
|
||||
|
||||
ValueType eq_rtt_1_type = ValueType::Rtt(HeapType::kEq, 1);
|
||||
FunctionSig sig_eq_sub(1, 0, &eq_rtt_1_type);
|
||||
byte kEqRttSub = tester.DefineFunction(
|
||||
&sig_eq_sub, {},
|
||||
{WASM_RTT_SUB(kEqRefCode, WASM_RTT_CANON(kAnyRefCode)), kExprEnd});
|
||||
|
||||
const byte type_index = tester.DefineArray(kWasmI32, true);
|
||||
ValueType array_rtt_type = ValueType::Rtt(type_index, 1);
|
||||
FunctionSig sig_array_canon(1, 0, &array_rtt_type);
|
||||
byte kArrayRttCanon = tester.DefineFunction(
|
||||
&sig_array_canon, {}, {WASM_RTT_CANON(type_index), kExprEnd});
|
||||
|
||||
byte kCheckArrayAgainstAny = tester.DefineFunction(
|
||||
tester.sigs.i_v(), {kWasmAnyRef},
|
||||
{WASM_SET_LOCAL(0, WASM_ARRAY_NEW_DEFAULT(type_index, WASM_I32V(5),
|
||||
WASM_RTT_CANON(type_index))),
|
||||
WASM_REF_TEST(kAnyRefCode, type_index, WASM_GET_LOCAL(0),
|
||||
WASM_RTT_CANON(type_index)),
|
||||
kExprEnd});
|
||||
|
||||
byte kCheckAnyAgainstAny = tester.DefineFunction(
|
||||
tester.sigs.i_v(), {kWasmAnyRef},
|
||||
{WASM_SET_LOCAL(0, WASM_ARRAY_NEW_DEFAULT(type_index, WASM_I32V(5),
|
||||
WASM_RTT_CANON(type_index))),
|
||||
WASM_REF_TEST(kAnyRefCode, kAnyRefCode, WASM_GET_LOCAL(0),
|
||||
WASM_RTT_CANON(kAnyRefCode)),
|
||||
kExprEnd});
|
||||
|
||||
tester.CompileModule();
|
||||
|
||||
// Check (rtt.canon any).
|
||||
Handle<Object> result_any_canon =
|
||||
tester.GetResultObject(kAnyRttCanon).ToHandleChecked();
|
||||
CHECK(result_any_canon->IsMap());
|
||||
Handle<Map> any_map = Handle<Map>::cast(result_any_canon);
|
||||
CHECK_EQ(any_map->wasm_type_info().parent(),
|
||||
tester.isolate()->root(RootIndex::kNullMap));
|
||||
CHECK_EQ(any_map->wasm_type_info().supertypes().length(), 0);
|
||||
|
||||
for (byte func_index : {kArrayRttCanon, kAnyRttSub, kFuncRttSub, kEqRttSub}) {
|
||||
Handle<Object> result =
|
||||
tester.GetResultObject(func_index).ToHandleChecked();
|
||||
CHECK(result->IsMap());
|
||||
Handle<Map> map = Handle<Map>::cast(result);
|
||||
// Its parent should be (rtt.canon any).
|
||||
CHECK_EQ(map->wasm_type_info().parent(), *any_map);
|
||||
CHECK_EQ(map->wasm_type_info().supertypes().get(0), *any_map);
|
||||
CHECK_EQ(map->wasm_type_info().supertypes().length(), 1);
|
||||
}
|
||||
|
||||
tester.CheckResult(kCheckArrayAgainstAny, 1);
|
||||
tester.CheckResult(kCheckAnyAgainstAny, 1);
|
||||
}
|
||||
|
||||
TEST(ArrayNewMap) {
|
||||
WasmGCTester tester;
|
||||
const byte type_index = tester.DefineArray(kWasmI32, true);
|
||||
|
@ -3045,7 +3045,8 @@ class WasmInterpreterInternals {
|
||||
switch (sig->GetParam(i).heap_representation()) {
|
||||
case HeapType::kExtern:
|
||||
case HeapType::kExn:
|
||||
case HeapType::kFunc: {
|
||||
case HeapType::kFunc:
|
||||
case HeapType::kAny: {
|
||||
Handle<Object> externref = value.to_externref();
|
||||
encoded_values->set(encoded_index++, *externref);
|
||||
break;
|
||||
@ -3162,7 +3163,8 @@ class WasmInterpreterInternals {
|
||||
switch (sig->GetParam(i).heap_representation()) {
|
||||
case HeapType::kExtern:
|
||||
case HeapType::kExn:
|
||||
case HeapType::kFunc: {
|
||||
case HeapType::kFunc:
|
||||
case HeapType::kAny: {
|
||||
Handle<Object> externref(encoded_values->get(encoded_index++),
|
||||
isolate_);
|
||||
value = WasmValue(externref);
|
||||
|
@ -133,7 +133,11 @@ const char* ValueTypeToConstantName(ValueType type) {
|
||||
return "kWasmFuncRef";
|
||||
case HeapType::kExn:
|
||||
return "kWasmExnRef";
|
||||
case HeapType::kAny:
|
||||
case HeapType::kI31:
|
||||
case HeapType::kBottom:
|
||||
default:
|
||||
// TODO(7748): Implement these if fuzzing for them is enabled.
|
||||
UNREACHABLE();
|
||||
}
|
||||
default:
|
||||
|
@ -3617,6 +3617,7 @@ TEST_F(FunctionBodyDecoderTest, RefEq) {
|
||||
kWasmExnRef,
|
||||
kWasmExternRef,
|
||||
kWasmFuncRef,
|
||||
kWasmAnyRef,
|
||||
ValueType::Ref(HeapType::kExn, kNonNullable),
|
||||
ValueType::Ref(HeapType::kExtern, kNonNullable),
|
||||
ValueType::Ref(HeapType::kFunc, kNonNullable)};
|
||||
@ -3655,7 +3656,7 @@ TEST_F(FunctionBodyDecoderTest, RefAsNonNull) {
|
||||
byte array_type_index = builder.AddArray(kWasmI32, true);
|
||||
uint32_t heap_types[] = {
|
||||
struct_type_index, array_type_index, HeapType::kExn, HeapType::kFunc,
|
||||
HeapType::kEq, HeapType::kExtern, HeapType::kI31};
|
||||
HeapType::kEq, HeapType::kExtern, HeapType::kI31, HeapType::kAny};
|
||||
|
||||
ValueType non_compatible_types[] = {kWasmI32, kWasmI64, kWasmF32, kWasmF64,
|
||||
kWasmS128};
|
||||
@ -3698,7 +3699,7 @@ TEST_F(FunctionBodyDecoderTest, RefNull) {
|
||||
byte array_type_index = builder.AddArray(kWasmI32, true);
|
||||
uint32_t type_reprs[] = {
|
||||
struct_type_index, array_type_index, HeapType::kExn, HeapType::kFunc,
|
||||
HeapType::kEq, HeapType::kExtern, HeapType::kI31};
|
||||
HeapType::kEq, HeapType::kExtern, HeapType::kI31, HeapType::kAny};
|
||||
// It works with heap types.
|
||||
for (uint32_t type_repr : type_reprs) {
|
||||
const ValueType type = ValueType::Ref(type_repr, kNullable);
|
||||
@ -3728,7 +3729,7 @@ TEST_F(FunctionBodyDecoderTest, RefIsNull) {
|
||||
byte array_type_index = builder.AddArray(kWasmI32, true);
|
||||
uint32_t heap_types[] = {
|
||||
struct_type_index, array_type_index, HeapType::kExn, HeapType::kFunc,
|
||||
HeapType::kEq, HeapType::kExtern, HeapType::kI31};
|
||||
HeapType::kEq, HeapType::kExtern, HeapType::kI31, HeapType::kAny};
|
||||
|
||||
for (uint32_t heap_type : heap_types) {
|
||||
const ValueType types[] = {kWasmI32, ValueType::Ref(heap_type, kNullable)};
|
||||
@ -4148,13 +4149,16 @@ TEST_F(FunctionBodyDecoderTest, RttCanon) {
|
||||
|
||||
for (HeapType::Representation heap :
|
||||
{HeapType::kExtern, HeapType::kEq, HeapType::kExn, HeapType::kI31,
|
||||
static_cast<HeapType::Representation>(array_type_index),
|
||||
HeapType::kAny, static_cast<HeapType::Representation>(array_type_index),
|
||||
static_cast<HeapType::Representation>(struct_type_index)}) {
|
||||
ValueType rtt1 = ValueType::Rtt(HeapType(heap), 1);
|
||||
ValueType rtt1 =
|
||||
ValueType::Rtt(HeapType(heap), heap == HeapType::kAny ? 0 : 1);
|
||||
FunctionSig sig1(1, 0, &rtt1);
|
||||
ExpectValidates(&sig1, {WASM_RTT_CANON(rtt1.heap_type().code() & 0x7F)});
|
||||
|
||||
ValueType rtt2 = ValueType::Rtt(HeapType(heap), 2);
|
||||
// rtt.canon should fail for incorrect depth.
|
||||
ValueType rtt2 =
|
||||
ValueType::Rtt(HeapType(heap), heap == HeapType::kAny ? 1 : 2);
|
||||
FunctionSig sig2(1, 0, &rtt2);
|
||||
ExpectFailure(&sig2, {WASM_RTT_CANON(rtt2.heap_type().code() & 0x7F)},
|
||||
kAppendEnd, "type error in merge[0]");
|
||||
@ -4182,6 +4186,43 @@ TEST_F(FunctionBodyDecoderTest, RttSub) {
|
||||
{WASM_RTT_SUB(kFuncRefCode, WASM_RTT_CANON(kFuncRefCode))});
|
||||
}
|
||||
|
||||
{
|
||||
// Can build an rtt.sub from a generic type with itself.
|
||||
ValueType type = ValueType::Rtt(HeapType::kAny, 1);
|
||||
FunctionSig sig(1, 0, &type);
|
||||
ExpectValidates(&sig,
|
||||
{WASM_RTT_SUB(kAnyRefCode, WASM_RTT_CANON(kAnyRefCode))});
|
||||
}
|
||||
|
||||
// Can build an rtt.sub between related generic types.
|
||||
{
|
||||
ValueType type = ValueType::Rtt(HeapType::kFunc, 1);
|
||||
FunctionSig sig(1, 0, &type);
|
||||
ExpectValidates(&sig,
|
||||
{WASM_RTT_SUB(kFuncRefCode, WASM_RTT_CANON(kAnyRefCode))});
|
||||
}
|
||||
{
|
||||
ValueType type = ValueType::Rtt(HeapType::kEq, 1);
|
||||
FunctionSig sig(1, 0, &type);
|
||||
ExpectValidates(&sig,
|
||||
{WASM_RTT_SUB(kEqRefCode, WASM_RTT_CANON(kAnyRefCode))});
|
||||
}
|
||||
{
|
||||
ValueType type = ValueType::Rtt(HeapType::kI31, 2);
|
||||
FunctionSig sig(1, 0, &type);
|
||||
ExpectValidates(&sig,
|
||||
{WASM_RTT_SUB(kI31RefCode, WASM_RTT_CANON(kEqRefCode))});
|
||||
}
|
||||
|
||||
// Cannot build an rtt.sub between unrelated generic types.
|
||||
{
|
||||
ValueType type = ValueType::Rtt(HeapType::kFunc, 2);
|
||||
FunctionSig sig(1, 0, &type);
|
||||
ExpectFailure(&sig,
|
||||
{WASM_RTT_SUB(kFuncRefCode, WASM_RTT_CANON(kI31RefCode))},
|
||||
kAppendEnd, "rtt.sub requires a supertype rtt on stack");
|
||||
}
|
||||
|
||||
// Trivial type error.
|
||||
ExpectFailure(sigs.v_v(),
|
||||
{WASM_RTT_SUB(kFuncRefCode, WASM_I32V(42)), kExprDrop},
|
||||
@ -4254,10 +4295,10 @@ TEST_F(FunctionBodyDecoderTest, RefTestCast) {
|
||||
|
||||
// Passing/failing tests due to static subtyping.
|
||||
std::pair<HeapType::Representation, HeapType::Representation> valid_pairs[] =
|
||||
{{HeapType::kEq, HeapType::kI31},
|
||||
{HeapType::kFunc, HeapType::kFunc},
|
||||
{HeapType::kEq, array_heap},
|
||||
{HeapType::kEq, super_struct_heap},
|
||||
{{HeapType::kAny, HeapType::kI31}, {HeapType::kAny, HeapType::kFunc},
|
||||
{HeapType::kAny, array_heap}, {HeapType::kAny, super_struct_heap},
|
||||
{HeapType::kEq, HeapType::kI31}, {HeapType::kFunc, HeapType::kFunc},
|
||||
{HeapType::kEq, array_heap}, {HeapType::kEq, super_struct_heap},
|
||||
{super_struct_heap, sub_struct_heap}};
|
||||
|
||||
for (auto pair : valid_pairs) {
|
||||
@ -4279,10 +4320,10 @@ TEST_F(FunctionBodyDecoderTest, RefTestCast) {
|
||||
}
|
||||
|
||||
std::pair<HeapType::Representation, HeapType::Representation>
|
||||
invalid_pairs[] = {{HeapType::kI31, HeapType::kEq},
|
||||
{array_heap, super_struct_heap},
|
||||
{array_heap, HeapType::kEq},
|
||||
{HeapType::kExtern, HeapType::kExn}};
|
||||
invalid_pairs[] = {
|
||||
{array_heap, HeapType::kAny}, {HeapType::kEq, HeapType::kAny},
|
||||
{HeapType::kI31, HeapType::kEq}, {array_heap, super_struct_heap},
|
||||
{array_heap, HeapType::kEq}, {HeapType::kExtern, HeapType::kExn}};
|
||||
|
||||
for (auto pair : invalid_pairs) {
|
||||
HeapType from_heap = HeapType(pair.first);
|
||||
|
@ -57,9 +57,9 @@ TEST_F(WasmSubtypingTest, Subtyping) {
|
||||
|
||||
ValueType numeric_types[] = {kWasmI32, kWasmI64, kWasmF32, kWasmF64,
|
||||
kWasmS128};
|
||||
ValueType ref_types[] = {kWasmExternRef, kWasmFuncRef, kWasmExnRef,
|
||||
kWasmEqRef, kWasmI31Ref, optRef(0),
|
||||
ref(0), optRef(2), ref(2)};
|
||||
ValueType ref_types[] = {
|
||||
kWasmExternRef, kWasmFuncRef, kWasmExnRef, kWasmEqRef, kWasmI31Ref,
|
||||
kWasmAnyRef, optRef(0), ref(0), optRef(2), ref(2)};
|
||||
|
||||
// Type judgements across modules should work the same as within one module.
|
||||
for (WasmModule* module : {module1, module2}) {
|
||||
@ -81,12 +81,17 @@ TEST_F(WasmSubtypingTest, Subtyping) {
|
||||
|
||||
for (ValueType ref_type : ref_types) {
|
||||
// Concrete reference types and i31ref are subtypes of eqref,
|
||||
// exnref/externref/funcref are not.
|
||||
// exnref/externref/funcref/anyref are not.
|
||||
CHECK_EQ(IsSubtypeOf(ref_type, kWasmEqRef, module1, module),
|
||||
ref_type != kWasmFuncRef && ref_type != kWasmExternRef &&
|
||||
ref_type != kWasmExnRef);
|
||||
ref_type != kWasmExnRef && ref_type != kWasmAnyRef);
|
||||
// Each reference type is a subtype of itself.
|
||||
CHECK(IsSubtypeOf(ref_type, ref_type, module1, module));
|
||||
// Each reference type is a subtype of anyref.
|
||||
CHECK(IsSubtypeOf(ref_type, kWasmAnyRef, module1, module));
|
||||
// Only anyref is a subtype of anyref.
|
||||
CHECK_EQ(IsSubtypeOf(kWasmAnyRef, ref_type, module1, module),
|
||||
ref_type == kWasmAnyRef);
|
||||
}
|
||||
|
||||
// The rest of ref. types are unrelated.
|
||||
|
@ -362,9 +362,10 @@ KNOWN_MAPS = {
|
||||
("map_space", 0x02115): (1057, "ExternalMap"),
|
||||
("map_space", 0x0213d): (1072, "JSMessageObjectMap"),
|
||||
("map_space", 0x02165): (182, "WasmRttEqrefMap"),
|
||||
("map_space", 0x0218d): (182, "WasmRttExternrefMap"),
|
||||
("map_space", 0x021b5): (182, "WasmRttFuncrefMap"),
|
||||
("map_space", 0x021dd): (182, "WasmRttI31refMap"),
|
||||
("map_space", 0x0218d): (182, "WasmRttAnyrefMap"),
|
||||
("map_space", 0x021b5): (182, "WasmRttExternrefMap"),
|
||||
("map_space", 0x021dd): (182, "WasmRttFuncrefMap"),
|
||||
("map_space", 0x02205): (182, "WasmRttI31refMap"),
|
||||
}
|
||||
|
||||
# List of known V8 objects.
|
||||
@ -427,49 +428,49 @@ KNOWN_OBJECTS = {
|
||||
("old_space", 0x023bd): "RegExpResultIndicesAccessor",
|
||||
("old_space", 0x02401): "StringLengthAccessor",
|
||||
("old_space", 0x02445): "InvalidPrototypeValidityCell",
|
||||
("old_space", 0x024dd): "EmptyScript",
|
||||
("old_space", 0x0251d): "ManyClosuresCell",
|
||||
("old_space", 0x02529): "ArrayConstructorProtector",
|
||||
("old_space", 0x0253d): "NoElementsProtector",
|
||||
("old_space", 0x02551): "IsConcatSpreadableProtector",
|
||||
("old_space", 0x02565): "ArraySpeciesProtector",
|
||||
("old_space", 0x02579): "TypedArraySpeciesProtector",
|
||||
("old_space", 0x0258d): "PromiseSpeciesProtector",
|
||||
("old_space", 0x025a1): "RegExpSpeciesProtector",
|
||||
("old_space", 0x025b5): "StringLengthProtector",
|
||||
("old_space", 0x025c9): "ArrayIteratorProtector",
|
||||
("old_space", 0x025dd): "ArrayBufferDetachingProtector",
|
||||
("old_space", 0x025f1): "PromiseHookProtector",
|
||||
("old_space", 0x02605): "PromiseResolveProtector",
|
||||
("old_space", 0x02619): "MapIteratorProtector",
|
||||
("old_space", 0x0262d): "PromiseThenProtector",
|
||||
("old_space", 0x02641): "SetIteratorProtector",
|
||||
("old_space", 0x02655): "StringIteratorProtector",
|
||||
("old_space", 0x02669): "SingleCharacterStringCache",
|
||||
("old_space", 0x02a71): "StringSplitCache",
|
||||
("old_space", 0x02e79): "RegExpMultipleCache",
|
||||
("old_space", 0x03281): "BuiltinsConstantsTable",
|
||||
("old_space", 0x03669): "AsyncFunctionAwaitRejectSharedFun",
|
||||
("old_space", 0x03691): "AsyncFunctionAwaitResolveSharedFun",
|
||||
("old_space", 0x036b9): "AsyncGeneratorAwaitRejectSharedFun",
|
||||
("old_space", 0x036e1): "AsyncGeneratorAwaitResolveSharedFun",
|
||||
("old_space", 0x03709): "AsyncGeneratorYieldResolveSharedFun",
|
||||
("old_space", 0x03731): "AsyncGeneratorReturnResolveSharedFun",
|
||||
("old_space", 0x03759): "AsyncGeneratorReturnClosedRejectSharedFun",
|
||||
("old_space", 0x03781): "AsyncGeneratorReturnClosedResolveSharedFun",
|
||||
("old_space", 0x037a9): "AsyncIteratorValueUnwrapSharedFun",
|
||||
("old_space", 0x037d1): "PromiseAllResolveElementSharedFun",
|
||||
("old_space", 0x037f9): "PromiseAllSettledResolveElementSharedFun",
|
||||
("old_space", 0x03821): "PromiseAllSettledRejectElementSharedFun",
|
||||
("old_space", 0x03849): "PromiseAnyRejectElementSharedFun",
|
||||
("old_space", 0x03871): "PromiseCapabilityDefaultRejectSharedFun",
|
||||
("old_space", 0x03899): "PromiseCapabilityDefaultResolveSharedFun",
|
||||
("old_space", 0x038c1): "PromiseCatchFinallySharedFun",
|
||||
("old_space", 0x038e9): "PromiseGetCapabilitiesExecutorSharedFun",
|
||||
("old_space", 0x03911): "PromiseThenFinallySharedFun",
|
||||
("old_space", 0x03939): "PromiseThrowerFinallySharedFun",
|
||||
("old_space", 0x03961): "PromiseValueThunkFinallySharedFun",
|
||||
("old_space", 0x03989): "ProxyRevokeSharedFun",
|
||||
("old_space", 0x02531): "EmptyScript",
|
||||
("old_space", 0x02571): "ManyClosuresCell",
|
||||
("old_space", 0x0257d): "ArrayConstructorProtector",
|
||||
("old_space", 0x02591): "NoElementsProtector",
|
||||
("old_space", 0x025a5): "IsConcatSpreadableProtector",
|
||||
("old_space", 0x025b9): "ArraySpeciesProtector",
|
||||
("old_space", 0x025cd): "TypedArraySpeciesProtector",
|
||||
("old_space", 0x025e1): "PromiseSpeciesProtector",
|
||||
("old_space", 0x025f5): "RegExpSpeciesProtector",
|
||||
("old_space", 0x02609): "StringLengthProtector",
|
||||
("old_space", 0x0261d): "ArrayIteratorProtector",
|
||||
("old_space", 0x02631): "ArrayBufferDetachingProtector",
|
||||
("old_space", 0x02645): "PromiseHookProtector",
|
||||
("old_space", 0x02659): "PromiseResolveProtector",
|
||||
("old_space", 0x0266d): "MapIteratorProtector",
|
||||
("old_space", 0x02681): "PromiseThenProtector",
|
||||
("old_space", 0x02695): "SetIteratorProtector",
|
||||
("old_space", 0x026a9): "StringIteratorProtector",
|
||||
("old_space", 0x026bd): "SingleCharacterStringCache",
|
||||
("old_space", 0x02ac5): "StringSplitCache",
|
||||
("old_space", 0x02ecd): "RegExpMultipleCache",
|
||||
("old_space", 0x032d5): "BuiltinsConstantsTable",
|
||||
("old_space", 0x036bd): "AsyncFunctionAwaitRejectSharedFun",
|
||||
("old_space", 0x036e5): "AsyncFunctionAwaitResolveSharedFun",
|
||||
("old_space", 0x0370d): "AsyncGeneratorAwaitRejectSharedFun",
|
||||
("old_space", 0x03735): "AsyncGeneratorAwaitResolveSharedFun",
|
||||
("old_space", 0x0375d): "AsyncGeneratorYieldResolveSharedFun",
|
||||
("old_space", 0x03785): "AsyncGeneratorReturnResolveSharedFun",
|
||||
("old_space", 0x037ad): "AsyncGeneratorReturnClosedRejectSharedFun",
|
||||
("old_space", 0x037d5): "AsyncGeneratorReturnClosedResolveSharedFun",
|
||||
("old_space", 0x037fd): "AsyncIteratorValueUnwrapSharedFun",
|
||||
("old_space", 0x03825): "PromiseAllResolveElementSharedFun",
|
||||
("old_space", 0x0384d): "PromiseAllSettledResolveElementSharedFun",
|
||||
("old_space", 0x03875): "PromiseAllSettledRejectElementSharedFun",
|
||||
("old_space", 0x0389d): "PromiseAnyRejectElementSharedFun",
|
||||
("old_space", 0x038c5): "PromiseCapabilityDefaultRejectSharedFun",
|
||||
("old_space", 0x038ed): "PromiseCapabilityDefaultResolveSharedFun",
|
||||
("old_space", 0x03915): "PromiseCatchFinallySharedFun",
|
||||
("old_space", 0x0393d): "PromiseGetCapabilitiesExecutorSharedFun",
|
||||
("old_space", 0x03965): "PromiseThenFinallySharedFun",
|
||||
("old_space", 0x0398d): "PromiseThrowerFinallySharedFun",
|
||||
("old_space", 0x039b5): "PromiseValueThunkFinallySharedFun",
|
||||
("old_space", 0x039dd): "ProxyRevokeSharedFun",
|
||||
}
|
||||
|
||||
# Lower 32 bits of first page addresses for various heap spaces.
|
||||
|
Loading…
Reference in New Issue
Block a user