[wasm-gc] Remove abstract rtts
In the latest wasm-gc spec, rtts of abstract types are no longer allowed. Consequently, canonical rtts of concrete types always have a depth of 0. Changes: - Change the immediate argument of rtts to a type index over a heap type. Abstract it with TypeIndexImmediate in function body decoding. This affects: value_type.h, read_value_type(), decoding of relevant opcodes, wasm subtyping, WasmInitExpr, consume_init_expr(), and wasm-module-builder.cc. - In function-body-decoder-impl.h, update rtt.canon to always produce an rtt of depth 0. - Pass a unit32_t type index over a HeapType to all rtt-related utilities. - Remove infrastructure for abstract-type rtts from the wasm compilers, setup-heap-internal.cc, roots.h, and module-instantiate.cc. - Remove ObjectReferenceKnowledge::rtt_is_i31. Remove related branches from ref.test, ref.cast and br_on_cast implementations in the wasm compilers. - Remove unused 'parent' field from WasmTypeInfo. - Make the parent argument optional in NewWasmTypeInfo, CreateStructMap, and CreateArrayMap. - Use more convenient arguments in IsHeapSubtypeOf. - Update tests. Bug: v8:7748 Change-Id: Ib45efe0741e6558c9b291fc8b4a75ae303146bdc Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2642248 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@{#72321}
This commit is contained in:
parent
4adf55a004
commit
b77deeca4b
@ -5719,42 +5719,17 @@ Node* WasmGraphBuilder::ArrayNewWithRtt(uint32_t array_index,
|
||||
return a;
|
||||
}
|
||||
|
||||
Node* WasmGraphBuilder::RttCanon(wasm::HeapType type) {
|
||||
RootIndex index;
|
||||
switch (type.representation()) {
|
||||
case wasm::HeapType::kEq:
|
||||
index = RootIndex::kWasmRttEqrefMap;
|
||||
break;
|
||||
case wasm::HeapType::kExtern:
|
||||
index = RootIndex::kWasmRttExternrefMap;
|
||||
break;
|
||||
case wasm::HeapType::kFunc:
|
||||
index = RootIndex::kWasmRttFuncrefMap;
|
||||
break;
|
||||
case wasm::HeapType::kI31:
|
||||
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::RttCanon(uint32_t type_index) {
|
||||
Node* maps_list =
|
||||
LOAD_INSTANCE_FIELD(ManagedObjectMaps, MachineType::TaggedPointer());
|
||||
return LOAD_FIXED_ARRAY_SLOT_PTR(maps_list, type_index);
|
||||
}
|
||||
|
||||
Node* WasmGraphBuilder::RttSub(wasm::HeapType type, Node* parent_rtt) {
|
||||
return CALL_BUILTIN(WasmAllocateRtt,
|
||||
graph()->NewNode(mcgraph()->common()->Int32Constant(
|
||||
type.representation())),
|
||||
parent_rtt);
|
||||
Node* WasmGraphBuilder::RttSub(uint32_t type_index, Node* parent_rtt) {
|
||||
return CALL_BUILTIN(
|
||||
WasmAllocateRtt,
|
||||
graph()->NewNode(mcgraph()->common()->Int32Constant(type_index)),
|
||||
parent_rtt);
|
||||
}
|
||||
|
||||
void AssertFalse(MachineGraph* mcgraph, GraphAssembler* gasm, Node* condition) {
|
||||
@ -5773,9 +5748,6 @@ Node* WasmGraphBuilder::RefTest(Node* object, Node* rtt,
|
||||
ObjectReferenceKnowledge config) {
|
||||
auto done = gasm_->MakeLabel(MachineRepresentation::kWord32);
|
||||
if (config.object_can_be_i31) {
|
||||
if (config.rtt_is_i31) {
|
||||
return gasm_->IsI31(object);
|
||||
}
|
||||
gasm_->GotoIf(gasm_->IsI31(object), &done, gasm_->Int32Constant(0));
|
||||
} else {
|
||||
AssertFalse(mcgraph(), gasm_.get(), gasm_->IsI31(object));
|
||||
@ -5810,12 +5782,7 @@ Node* WasmGraphBuilder::RefCast(Node* object, Node* rtt,
|
||||
ObjectReferenceKnowledge config,
|
||||
wasm::WasmCodePosition position) {
|
||||
if (config.object_can_be_i31) {
|
||||
if (config.rtt_is_i31) {
|
||||
TrapIfFalse(wasm::kTrapIllegalCast, gasm_->IsI31(object), position);
|
||||
return object;
|
||||
} else {
|
||||
TrapIfTrue(wasm::kTrapIllegalCast, gasm_->IsI31(object), position);
|
||||
}
|
||||
TrapIfTrue(wasm::kTrapIllegalCast, gasm_->IsI31(object), position);
|
||||
} else {
|
||||
AssertFalse(mcgraph(), gasm_.get(), gasm_->IsI31(object));
|
||||
}
|
||||
@ -5861,17 +5828,12 @@ Node* WasmGraphBuilder::BrOnCast(Node* object, Node* rtt,
|
||||
|
||||
Node* is_i31 = gasm_->IsI31(object);
|
||||
if (config.object_can_be_i31) {
|
||||
if (config.rtt_is_i31) {
|
||||
BranchExpectFalse(is_i31, match_control, no_match_control);
|
||||
return nullptr;
|
||||
} else {
|
||||
Node* i31_branch = graph()->NewNode(
|
||||
mcgraph()->common()->Branch(BranchHint::kFalse), is_i31, control());
|
||||
SetControl(graph()->NewNode(mcgraph()->common()->IfFalse(), i31_branch));
|
||||
no_match_controls.emplace_back(
|
||||
graph()->NewNode(mcgraph()->common()->IfTrue(), i31_branch));
|
||||
no_match_effects.emplace_back(effect());
|
||||
}
|
||||
Node* i31_branch = graph()->NewNode(
|
||||
mcgraph()->common()->Branch(BranchHint::kFalse), is_i31, control());
|
||||
SetControl(graph()->NewNode(mcgraph()->common()->IfFalse(), i31_branch));
|
||||
no_match_controls.emplace_back(
|
||||
graph()->NewNode(mcgraph()->common()->IfTrue(), i31_branch));
|
||||
no_match_effects.emplace_back(effect());
|
||||
} else {
|
||||
AssertFalse(mcgraph(), gasm_.get(), is_i31);
|
||||
}
|
||||
|
@ -166,7 +166,6 @@ class WasmGraphBuilder {
|
||||
bool object_can_be_null;
|
||||
bool object_must_be_data_ref;
|
||||
bool object_can_be_i31;
|
||||
bool rtt_is_i31;
|
||||
uint8_t rtt_depth;
|
||||
};
|
||||
enum EnforceBoundsCheck : bool { // --
|
||||
@ -434,8 +433,8 @@ class WasmGraphBuilder {
|
||||
Node* I31New(Node* input);
|
||||
Node* I31GetS(Node* input);
|
||||
Node* I31GetU(Node* input);
|
||||
Node* RttCanon(wasm::HeapType type);
|
||||
Node* RttSub(wasm::HeapType type, Node* parent_rtt);
|
||||
Node* RttCanon(uint32_t type_index);
|
||||
Node* RttSub(uint32_t type_index, Node* parent_rtt);
|
||||
Node* RefTest(Node* object, Node* rtt, ObjectReferenceKnowledge config);
|
||||
Node* RefCast(Node* object, Node* rtt, ObjectReferenceKnowledge config,
|
||||
wasm::WasmCodePosition position);
|
||||
|
@ -1716,7 +1716,6 @@ void AsmWasmData::AsmWasmDataPrint(std::ostream& os) { // NOLINT
|
||||
void WasmTypeInfo::WasmTypeInfoPrint(std::ostream& os) { // NOLINT
|
||||
PrintHeader(os, "WasmTypeInfo");
|
||||
os << "\n - type address: " << reinterpret_cast<void*>(foreign_address());
|
||||
os << "\n - parent: " << Brief(parent());
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
|
@ -1308,16 +1308,15 @@ Handle<Foreign> Factory::NewForeign(Address addr) {
|
||||
}
|
||||
|
||||
Handle<WasmTypeInfo> Factory::NewWasmTypeInfo(Address type_address,
|
||||
Handle<Map> parent) {
|
||||
Handle<Map> opt_parent) {
|
||||
Handle<ArrayList> subtypes = ArrayList::New(isolate(), 0);
|
||||
Handle<FixedArray> supertypes;
|
||||
if (parent->IsWasmStructMap() || parent->IsWasmArrayMap()) {
|
||||
supertypes = CopyFixedArrayAndGrow(
|
||||
handle(parent->wasm_type_info().supertypes(), isolate()), 1);
|
||||
supertypes->set(supertypes->length() - 1, *parent);
|
||||
if (opt_parent.is_null()) {
|
||||
supertypes = NewUninitializedFixedArray(0);
|
||||
} else {
|
||||
supertypes = NewUninitializedFixedArray(1);
|
||||
supertypes->set(0, *parent);
|
||||
supertypes = CopyFixedArrayAndGrow(
|
||||
handle(opt_parent->wasm_type_info().supertypes(), isolate()), 1);
|
||||
supertypes->set(supertypes->length() - 1, *opt_parent);
|
||||
}
|
||||
Map map = *wasm_type_info_map();
|
||||
HeapObject result = AllocateRawWithImmortalMap(map.instance_size(),
|
||||
@ -1325,7 +1324,6 @@ Handle<WasmTypeInfo> Factory::NewWasmTypeInfo(Address type_address,
|
||||
Handle<WasmTypeInfo> info(WasmTypeInfo::cast(result), isolate());
|
||||
info->AllocateExternalPointerEntries(isolate());
|
||||
info->set_foreign_address(isolate(), type_address);
|
||||
info->set_parent(*parent);
|
||||
info->set_supertypes(*supertypes);
|
||||
info->set_subtypes(*subtypes);
|
||||
return info;
|
||||
|
@ -548,7 +548,7 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> {
|
||||
Handle<JSModuleNamespace> NewJSModuleNamespace();
|
||||
|
||||
Handle<WasmTypeInfo> NewWasmTypeInfo(Address type_address,
|
||||
Handle<Map> parent);
|
||||
Handle<Map> opt_parent);
|
||||
|
||||
Handle<SourceTextModule> NewSourceTextModule(Handle<SharedFunctionInfo> code);
|
||||
Handle<SyntheticModule> NewSyntheticModule(
|
||||
|
@ -504,14 +504,6 @@ bool Heap::CreateInitialMaps() {
|
||||
ALLOCATE_MAP(CODE_DATA_CONTAINER_TYPE, CodeDataContainer::kSize,
|
||||
code_data_container)
|
||||
|
||||
// The wasm_rttcanon_* maps are never used for real objects, only as
|
||||
// sentinels. They are maps so that they fit in with their subtype maps
|
||||
// (which are real maps).
|
||||
ALLOCATE_MAP(WASM_STRUCT_TYPE, 0, wasm_rttcanon_eqref)
|
||||
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)
|
||||
@ -621,74 +613,6 @@ bool Heap::CreateInitialMaps() {
|
||||
set_empty_closure_feedback_cell_array(ClosureFeedbackCellArray::cast(obj));
|
||||
}
|
||||
|
||||
// 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)) { \
|
||||
return false; \
|
||||
} \
|
||||
obj.set_map_after_allocation(roots.array_list_map()); \
|
||||
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; \
|
||||
} \
|
||||
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(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); \
|
||||
}
|
||||
|
||||
ALLOCATE_TYPE_INFO(eqref)
|
||||
ALLOCATE_TYPE_INFO(externref)
|
||||
ALLOCATE_TYPE_INFO(funcref)
|
||||
ALLOCATE_TYPE_INFO(i31ref)
|
||||
#undef ALLOCATE_TYPE_INFO
|
||||
|
||||
DCHECK(!InYoungGeneration(roots.empty_fixed_array()));
|
||||
|
||||
roots.bigint_map().SetConstructorFunctionIndex(
|
||||
|
@ -563,7 +563,6 @@ class WasmTypeInfo::BodyDescriptor final : public BodyDescriptorBase {
|
||||
ObjectVisitor* v) {
|
||||
Foreign::BodyDescriptor::IterateBody<ObjectVisitor>(map, obj, object_size,
|
||||
v);
|
||||
IteratePointer(obj, kParentOffset, v);
|
||||
IteratePointer(obj, kSupertypesOffset, v);
|
||||
IteratePointer(obj, kSubtypesOffset, v);
|
||||
}
|
||||
|
@ -200,11 +200,6 @@ class Symbol;
|
||||
/* Maps */ \
|
||||
V(Map, external_map, ExternalMap) \
|
||||
V(Map, message_object_map, JSMessageObjectMap) \
|
||||
V(Map, wasm_rttcanon_eqref_map, WasmRttEqrefMap) \
|
||||
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) \
|
||||
|
@ -4359,50 +4359,20 @@ class LiftoffCompiler {
|
||||
__ PushRegister(kWasmI32, dst);
|
||||
}
|
||||
|
||||
void RttCanon(FullDecoder* decoder, const HeapTypeImmediate<validate>& imm,
|
||||
Value* result) {
|
||||
void RttCanon(FullDecoder* decoder, uint32_t type_index, Value* result) {
|
||||
LiftoffRegister rtt = __ GetUnusedRegister(kGpReg, {});
|
||||
RootIndex index;
|
||||
switch (imm.type.representation()) {
|
||||
case wasm::HeapType::kEq:
|
||||
index = RootIndex::kWasmRttEqrefMap;
|
||||
break;
|
||||
case wasm::HeapType::kExtern:
|
||||
index = RootIndex::kWasmRttExternrefMap;
|
||||
break;
|
||||
case wasm::HeapType::kFunc:
|
||||
index = RootIndex::kWasmRttFuncrefMap;
|
||||
break;
|
||||
case wasm::HeapType::kI31:
|
||||
index = RootIndex::kWasmRttI31refMap;
|
||||
break;
|
||||
case wasm::HeapType::kAny:
|
||||
index = RootIndex::kWasmRttAnyrefMap;
|
||||
break;
|
||||
case wasm::HeapType::kBottom:
|
||||
UNREACHABLE();
|
||||
default:
|
||||
// User-defined type.
|
||||
LOAD_TAGGED_PTR_INSTANCE_FIELD(rtt.gp(), ManagedObjectMaps);
|
||||
__ LoadTaggedPointer(
|
||||
rtt.gp(), rtt.gp(), no_reg,
|
||||
wasm::ObjectAccess::ElementOffsetInTaggedFixedArray(
|
||||
imm.type.ref_index()),
|
||||
{});
|
||||
__ PushRegister(ValueType::Rtt(imm.type, 1), rtt);
|
||||
return;
|
||||
}
|
||||
LOAD_INSTANCE_FIELD(rtt.gp(), IsolateRoot, kSystemPointerSize);
|
||||
__ LoadTaggedPointer(rtt.gp(), rtt.gp(), no_reg,
|
||||
IsolateData::root_slot_offset(index), {});
|
||||
__ PushRegister(ValueType::Rtt(imm.type, 1), rtt);
|
||||
LOAD_TAGGED_PTR_INSTANCE_FIELD(rtt.gp(), ManagedObjectMaps);
|
||||
__ LoadTaggedPointer(
|
||||
rtt.gp(), rtt.gp(), no_reg,
|
||||
wasm::ObjectAccess::ElementOffsetInTaggedFixedArray(type_index), {});
|
||||
__ PushRegister(ValueType::Rtt(type_index, 1), rtt);
|
||||
}
|
||||
|
||||
void RttSub(FullDecoder* decoder, const HeapTypeImmediate<validate>& imm,
|
||||
const Value& parent, Value* result) {
|
||||
void RttSub(FullDecoder* decoder, uint32_t type_index, const Value& parent,
|
||||
Value* result) {
|
||||
ValueType parent_value_type = parent.type;
|
||||
ValueType rtt_value_type =
|
||||
ValueType::Rtt(imm.type, parent_value_type.depth() + 1);
|
||||
ValueType::Rtt(type_index, parent_value_type.depth() + 1);
|
||||
WasmCode::RuntimeStubId target = WasmCode::kWasmAllocateRtt;
|
||||
compiler::CallDescriptor* call_descriptor =
|
||||
GetBuiltinCallDescriptor<WasmAllocateRttDescriptor>(compilation_zone_);
|
||||
@ -4411,7 +4381,7 @@ class LiftoffCompiler {
|
||||
LiftoffAssembler::VarState parent_var =
|
||||
__ cache_state()->stack_state.end()[-1];
|
||||
LiftoffRegister type_reg = __ GetUnusedRegister(kGpReg, {});
|
||||
__ LoadConstant(type_reg, WasmValue(imm.type.representation()));
|
||||
__ LoadConstant(type_reg, WasmValue(type_index));
|
||||
LiftoffAssembler::VarState type_var(kWasmI32, type_reg, 0);
|
||||
__ PrepareBuiltinCall(&sig, call_descriptor, {type_var, parent_var});
|
||||
__ CallRuntimeStub(target);
|
||||
@ -4432,66 +4402,57 @@ class LiftoffCompiler {
|
||||
LiftoffRegister obj_reg = pinned.set(__ PopToRegister(pinned));
|
||||
|
||||
bool obj_can_be_i31 = IsSubtypeOf(kWasmI31Ref, obj.type, decoder->module_);
|
||||
bool rtt_is_i31 = rtt.type.heap_representation() == HeapType::kI31;
|
||||
bool i31_check_only = obj_can_be_i31 && rtt_is_i31;
|
||||
if (i31_check_only) {
|
||||
__ emit_smi_check(obj_reg.gp(), no_match,
|
||||
LiftoffAssembler::kJumpOnNotSmi);
|
||||
// Emit no further code, just fall through to {match}.
|
||||
} else {
|
||||
// Reserve all temporary registers up front, so that the cache state
|
||||
// tracking doesn't get confused by the following conditional jumps.
|
||||
LiftoffRegister tmp1 =
|
||||
opt_scratch != no_reg
|
||||
? LiftoffRegister(opt_scratch)
|
||||
: pinned.set(__ GetUnusedRegister(kGpReg, pinned));
|
||||
LiftoffRegister tmp2 = pinned.set(__ GetUnusedRegister(kGpReg, pinned));
|
||||
if (obj_can_be_i31) {
|
||||
DCHECK(!rtt_is_i31);
|
||||
__ emit_smi_check(obj_reg.gp(), no_match, LiftoffAssembler::kJumpOnSmi);
|
||||
}
|
||||
if (obj.type.is_nullable()) {
|
||||
LoadNullValue(tmp1.gp(), pinned);
|
||||
__ emit_cond_jump(kEqual, no_match, obj.type, obj_reg.gp(), tmp1.gp());
|
||||
}
|
||||
|
||||
// At this point, the object is neither null nor an i31ref. Perform
|
||||
// a regular type check. Check for exact match first.
|
||||
__ LoadMap(tmp1.gp(), obj_reg.gp());
|
||||
// {tmp1} now holds the object's map.
|
||||
__ emit_cond_jump(kEqual, &match, rtt.type, tmp1.gp(), rtt_reg.gp());
|
||||
|
||||
// If the object isn't guaranteed to be an array or struct, check that.
|
||||
// Subsequent code wouldn't handle e.g. funcrefs.
|
||||
if (!is_data_ref_type(obj.type, decoder->module_)) {
|
||||
EmitDataRefCheck(tmp1.gp(), no_match, tmp2, pinned);
|
||||
}
|
||||
|
||||
// Constant-time subtyping check: load exactly one candidate RTT from the
|
||||
// supertypes list.
|
||||
// Step 1: load the WasmTypeInfo into {tmp1}.
|
||||
constexpr int kTypeInfoOffset = wasm::ObjectAccess::ToTagged(
|
||||
Map::kConstructorOrBackPointerOrNativeContextOffset);
|
||||
__ LoadTaggedPointer(tmp1.gp(), tmp1.gp(), no_reg, kTypeInfoOffset,
|
||||
pinned);
|
||||
// Step 2: load the super types list into {tmp1}.
|
||||
constexpr int kSuperTypesOffset =
|
||||
wasm::ObjectAccess::ToTagged(WasmTypeInfo::kSupertypesOffset);
|
||||
__ LoadTaggedPointer(tmp1.gp(), tmp1.gp(), no_reg, kSuperTypesOffset,
|
||||
pinned);
|
||||
// Step 3: check the list's length.
|
||||
LiftoffRegister list_length = tmp2;
|
||||
__ LoadFixedArrayLengthAsInt32(list_length, tmp1.gp(), pinned);
|
||||
__ emit_i32_cond_jumpi(kUnsignedLessEqual, no_match, list_length.gp(),
|
||||
rtt.type.depth());
|
||||
// Step 4: load the candidate list slot into {tmp1}, and compare it.
|
||||
__ LoadTaggedPointer(
|
||||
tmp1.gp(), tmp1.gp(), no_reg,
|
||||
wasm::ObjectAccess::ElementOffsetInTaggedFixedArray(rtt.type.depth()),
|
||||
pinned);
|
||||
__ emit_cond_jump(kUnequal, no_match, rtt.type, tmp1.gp(), rtt_reg.gp());
|
||||
// Fall through to {match}.
|
||||
// Reserve all temporary registers up front, so that the cache state
|
||||
// tracking doesn't get confused by the following conditional jumps.
|
||||
LiftoffRegister tmp1 =
|
||||
opt_scratch != no_reg
|
||||
? LiftoffRegister(opt_scratch)
|
||||
: pinned.set(__ GetUnusedRegister(kGpReg, pinned));
|
||||
LiftoffRegister tmp2 = pinned.set(__ GetUnusedRegister(kGpReg, pinned));
|
||||
if (obj_can_be_i31) {
|
||||
__ emit_smi_check(obj_reg.gp(), no_match, LiftoffAssembler::kJumpOnSmi);
|
||||
}
|
||||
if (obj.type.is_nullable()) {
|
||||
LoadNullValue(tmp1.gp(), pinned);
|
||||
__ emit_cond_jump(kEqual, no_match, obj.type, obj_reg.gp(), tmp1.gp());
|
||||
}
|
||||
|
||||
// At this point, the object is neither null nor an i31ref. Perform
|
||||
// a regular type check. Check for exact match first.
|
||||
__ LoadMap(tmp1.gp(), obj_reg.gp());
|
||||
// {tmp1} now holds the object's map.
|
||||
__ emit_cond_jump(kEqual, &match, rtt.type, tmp1.gp(), rtt_reg.gp());
|
||||
|
||||
// If the object isn't guaranteed to be an array or struct, check that.
|
||||
// Subsequent code wouldn't handle e.g. funcrefs.
|
||||
if (!is_data_ref_type(obj.type, decoder->module_)) {
|
||||
EmitDataRefCheck(tmp1.gp(), no_match, tmp2, pinned);
|
||||
}
|
||||
|
||||
// Constant-time subtyping check: load exactly one candidate RTT from the
|
||||
// supertypes list.
|
||||
// Step 1: load the WasmTypeInfo into {tmp1}.
|
||||
constexpr int kTypeInfoOffset = wasm::ObjectAccess::ToTagged(
|
||||
Map::kConstructorOrBackPointerOrNativeContextOffset);
|
||||
__ LoadTaggedPointer(tmp1.gp(), tmp1.gp(), no_reg, kTypeInfoOffset, pinned);
|
||||
// Step 2: load the super types list into {tmp1}.
|
||||
constexpr int kSuperTypesOffset =
|
||||
wasm::ObjectAccess::ToTagged(WasmTypeInfo::kSupertypesOffset);
|
||||
__ LoadTaggedPointer(tmp1.gp(), tmp1.gp(), no_reg, kSuperTypesOffset,
|
||||
pinned);
|
||||
// Step 3: check the list's length.
|
||||
LiftoffRegister list_length = tmp2;
|
||||
__ LoadFixedArrayLengthAsInt32(list_length, tmp1.gp(), pinned);
|
||||
__ emit_i32_cond_jumpi(kUnsignedLessEqual, no_match, list_length.gp(),
|
||||
rtt.type.depth());
|
||||
// Step 4: load the candidate list slot into {tmp1}, and compare it.
|
||||
__ LoadTaggedPointer(
|
||||
tmp1.gp(), tmp1.gp(), no_reg,
|
||||
wasm::ObjectAccess::ElementOffsetInTaggedFixedArray(rtt.type.depth()),
|
||||
pinned);
|
||||
__ emit_cond_jump(kUnequal, no_match, rtt.type, tmp1.gp(), rtt_reg.gp());
|
||||
// Fall through to {match}.
|
||||
|
||||
__ bind(&match);
|
||||
return obj_reg;
|
||||
}
|
||||
@ -4519,7 +4480,7 @@ class LiftoffCompiler {
|
||||
Label* trap_label = AddOutOfLineTrap(decoder->position(),
|
||||
WasmCode::kThrowWasmTrapIllegalCast);
|
||||
LiftoffRegister obj_reg = SubtypeCheck(decoder, obj, rtt, trap_label);
|
||||
__ PushRegister(ValueType::Ref(rtt.type.heap_type(), kNonNullable),
|
||||
__ PushRegister(ValueType::Ref(rtt.type.ref_index(), kNonNullable),
|
||||
obj_reg);
|
||||
}
|
||||
|
||||
@ -4537,7 +4498,7 @@ class LiftoffCompiler {
|
||||
|
||||
__ PushRegister(rtt.type.is_bottom()
|
||||
? kWasmBottom
|
||||
: ValueType::Ref(rtt.type.heap_type(), kNonNullable),
|
||||
: ValueType::Ref(rtt.type.ref_index(), kNonNullable),
|
||||
obj_reg);
|
||||
BrOrRet(decoder, depth);
|
||||
|
||||
|
@ -334,12 +334,26 @@ ValueType read_value_type(Decoder* decoder, const byte* pc,
|
||||
depth, kV8MaxRttSubtypingDepth);
|
||||
return kWasmBottom;
|
||||
}
|
||||
uint32_t heap_type_length;
|
||||
HeapType heap_type = read_heap_type<validate>(
|
||||
decoder, pc + *length, &heap_type_length, module, enabled);
|
||||
*length += heap_type_length;
|
||||
return heap_type.is_bottom() ? kWasmBottom
|
||||
: ValueType::Rtt(heap_type, depth);
|
||||
uint32_t type_index_length;
|
||||
uint32_t type_index =
|
||||
decoder->read_u32v<validate>(pc + *length, &type_index_length);
|
||||
*length += type_index_length;
|
||||
if (!VALIDATE(type_index < kV8MaxWasmTypes)) {
|
||||
DecodeError<validate>(
|
||||
decoder, pc,
|
||||
"Type index %u is greater than the maximum number %zu "
|
||||
"of type definitions supported by V8",
|
||||
type_index, kV8MaxWasmTypes);
|
||||
return kWasmBottom;
|
||||
}
|
||||
// We use capacity over size so this works mid-DecodeTypeSection.
|
||||
if (!VALIDATE(module == nullptr ||
|
||||
type_index < module->types.capacity())) {
|
||||
DecodeError<validate>(decoder, pc, "Type index %u is out of bounds",
|
||||
type_index);
|
||||
return kWasmBottom;
|
||||
}
|
||||
return ValueType::Rtt(type_index, depth);
|
||||
}
|
||||
case kS128Code: {
|
||||
if (!VALIDATE(enabled.has_simd())) {
|
||||
@ -578,6 +592,15 @@ struct TableIndexImmediate {
|
||||
}
|
||||
};
|
||||
|
||||
template <Decoder::ValidateFlag validate>
|
||||
struct TypeIndexImmediate {
|
||||
uint32_t index = 0;
|
||||
uint32_t length = 1;
|
||||
inline TypeIndexImmediate(Decoder* decoder, const byte* pc) {
|
||||
index = decoder->read_u32v<validate>(pc, &length, "type index");
|
||||
}
|
||||
};
|
||||
|
||||
// TODO(jkummerow): Introduce a common superclass for StructIndexImmediate and
|
||||
// ArrayIndexImmediate? Maybe even FunctionIndexImmediate too?
|
||||
template <Decoder::ValidateFlag validate>
|
||||
@ -1095,9 +1118,8 @@ struct ControlBase : public PcForErrors<validate> {
|
||||
F(I31New, const Value& input, Value* result) \
|
||||
F(I31GetS, const Value& input, Value* result) \
|
||||
F(I31GetU, const Value& input, Value* result) \
|
||||
F(RttCanon, const HeapTypeImmediate<validate>& imm, Value* result) \
|
||||
F(RttSub, const HeapTypeImmediate<validate>& imm, const Value& parent, \
|
||||
Value* result) \
|
||||
F(RttCanon, uint32_t type_index, Value* result) \
|
||||
F(RttSub, uint32_t type_index, const Value& parent, Value* result) \
|
||||
F(RefTest, const Value& obj, const Value& rtt, Value* result) \
|
||||
F(RefCast, const Value& obj, const Value& rtt, Value* result) \
|
||||
F(BrOnCast, const Value& obj, const Value& rtt, Value* result_on_branch, \
|
||||
@ -1331,6 +1353,14 @@ class WasmDecoder : public Decoder {
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool Validate(const byte* pc, TypeIndexImmediate<validate>& imm) {
|
||||
if (!VALIDATE(module_->has_type(imm.index))) {
|
||||
DecodeError(pc, "invalid type index: %u", imm.index);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool Complete(ArrayIndexImmediate<validate>& imm) {
|
||||
if (!VALIDATE(module_->has_array(imm.index))) return false;
|
||||
imm.array_type = module_->array_type(imm.index);
|
||||
@ -1897,10 +1927,7 @@ class WasmDecoder : public Decoder {
|
||||
}
|
||||
case kExprRttCanon:
|
||||
case kExprRttSub: {
|
||||
// TODO(7748): Account for rtt.sub's additional immediates if
|
||||
// they stick.
|
||||
HeapTypeImmediate<validate> imm(WasmFeatures::All(), decoder,
|
||||
pc + length, nullptr);
|
||||
TypeIndexImmediate<validate> imm(decoder, pc + length);
|
||||
return length + imm.length;
|
||||
}
|
||||
case kExprI31New:
|
||||
@ -1909,8 +1936,7 @@ class WasmDecoder : public Decoder {
|
||||
return length;
|
||||
case kExprRefTest:
|
||||
case kExprRefCast: {
|
||||
HeapTypeImmediate<validate> ht(WasmFeatures::All(), decoder,
|
||||
pc + length, nullptr);
|
||||
TypeIndexImmediate<validate> ht(decoder, pc + length);
|
||||
return length + ht.length;
|
||||
}
|
||||
default:
|
||||
@ -3779,7 +3805,7 @@ class WasmFullDecoder : public WasmDecoder<validate> {
|
||||
// TODO(7748): Drop this check if {imm} is dropped from the proposal
|
||||
// à la https://github.com/WebAssembly/function-references/pull/31.
|
||||
if (!VALIDATE(rtt.type.is_bottom() ||
|
||||
rtt.type.heap_representation() == imm.index)) {
|
||||
rtt.type.ref_index() == imm.index)) {
|
||||
PopTypeError(imm.struct_type->field_count(), rtt,
|
||||
"rtt for type " + std::to_string(imm.index));
|
||||
return 0;
|
||||
@ -3813,7 +3839,7 @@ class WasmFullDecoder : public WasmDecoder<validate> {
|
||||
// TODO(7748): Drop this check if {imm} is dropped from the proposal
|
||||
// à la https://github.com/WebAssembly/function-references/pull/31.
|
||||
if (!VALIDATE(rtt.type.is_bottom() ||
|
||||
rtt.type.heap_representation() == imm.index)) {
|
||||
rtt.type.ref_index() == imm.index)) {
|
||||
PopTypeError(0, rtt, "rtt for type " + std::to_string(imm.index));
|
||||
return 0;
|
||||
}
|
||||
@ -3886,7 +3912,7 @@ class WasmFullDecoder : public WasmDecoder<validate> {
|
||||
// TODO(7748): Drop this check if {imm} is dropped from the proposal
|
||||
// à la https://github.com/WebAssembly/function-references/pull/31.
|
||||
if (!VALIDATE(rtt.type.is_bottom() ||
|
||||
rtt.type.heap_representation() == imm.index)) {
|
||||
rtt.type.ref_index() == imm.index)) {
|
||||
PopTypeError(2, rtt, "rtt for type " + std::to_string(imm.index));
|
||||
return 0;
|
||||
}
|
||||
@ -3915,7 +3941,7 @@ class WasmFullDecoder : public WasmDecoder<validate> {
|
||||
// TODO(7748): Drop this check if {imm} is dropped from the proposal
|
||||
// à la https://github.com/WebAssembly/function-references/pull/31.
|
||||
if (!VALIDATE(rtt.type.is_bottom() ||
|
||||
rtt.type.heap_representation() == imm.index)) {
|
||||
rtt.type.ref_index() == imm.index)) {
|
||||
PopTypeError(1, rtt, "rtt for type " + std::to_string(imm.index));
|
||||
return 0;
|
||||
}
|
||||
@ -4001,90 +4027,80 @@ class WasmFullDecoder : public WasmDecoder<validate> {
|
||||
return opcode_length;
|
||||
}
|
||||
case kExprRttCanon: {
|
||||
HeapTypeImmediate<validate> imm(
|
||||
this->enabled_, this, this->pc_ + opcode_length, this->module_);
|
||||
if (!VALIDATE(this->ok())) return 0;
|
||||
Value* value =
|
||||
Push(ValueType::Rtt(imm.type, imm.type == HeapType::kAny ? 0 : 1));
|
||||
CALL_INTERFACE_IF_REACHABLE(RttCanon, imm, value);
|
||||
TypeIndexImmediate<validate> imm(this, this->pc_ + opcode_length);
|
||||
if (!this->Validate(this->pc_ + opcode_length, imm)) return 0;
|
||||
Value* value = Push(ValueType::Rtt(imm.index, 0));
|
||||
CALL_INTERFACE_IF_REACHABLE(RttCanon, imm.index, value);
|
||||
return opcode_length + imm.length;
|
||||
}
|
||||
case kExprRttSub: {
|
||||
HeapTypeImmediate<validate> imm(
|
||||
this->enabled_, this, this->pc_ + opcode_length, this->module_);
|
||||
if (!VALIDATE(this->ok())) return 0;
|
||||
TypeIndexImmediate<validate> imm(this, this->pc_ + opcode_length);
|
||||
if (!this->Validate(this->pc_ + opcode_length, imm)) return 0;
|
||||
Value parent = Pop(0);
|
||||
if (parent.type.is_bottom()) {
|
||||
Push(kWasmBottom);
|
||||
} else {
|
||||
if (!VALIDATE(parent.type.is_rtt() &&
|
||||
IsHeapSubtypeOf(imm.type, parent.type.heap_type(),
|
||||
IsHeapSubtypeOf(imm.index, parent.type.ref_index(),
|
||||
this->module_))) {
|
||||
PopTypeError(0, parent,
|
||||
"rtt for a supertype of type " + imm.type.name());
|
||||
PopTypeError(
|
||||
0, parent,
|
||||
"rtt for a supertype of type " + std::to_string(imm.index));
|
||||
return 0;
|
||||
}
|
||||
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);
|
||||
}
|
||||
Push(ValueType::Rtt(imm.index, parent.type.depth() + 1));
|
||||
|
||||
CALL_INTERFACE_IF_REACHABLE(RttSub, imm.index, parent, value);
|
||||
}
|
||||
return opcode_length + imm.length;
|
||||
}
|
||||
case kExprRefTest: {
|
||||
// "Tests whether {obj}'s runtime type is a runtime subtype of {rtt}."
|
||||
HeapTypeImmediate<validate> rtt_type(
|
||||
this->enabled_, this, this->pc_ + opcode_length, this->module_);
|
||||
if (!VALIDATE(this->ok())) return 0;
|
||||
TypeIndexImmediate<validate> imm(this, this->pc_ + opcode_length);
|
||||
if (!this->Validate(this->pc_ + opcode_length, imm)) return 0;
|
||||
Value rtt = Pop(1);
|
||||
if (!VALIDATE(
|
||||
(rtt.type.is_rtt() && rtt.type.heap_type() == rtt_type.type) ||
|
||||
(rtt.type.is_rtt() && rtt.type.ref_index() == imm.index) ||
|
||||
rtt.type == kWasmBottom)) {
|
||||
PopTypeError(1, rtt, "rtt for type " + rtt_type.type.name());
|
||||
PopTypeError(1, rtt, "rtt for type " + std::to_string(imm.index));
|
||||
return 0;
|
||||
}
|
||||
Value obj = Pop(0, kWasmAnyRef);
|
||||
Value* value = Push(kWasmI32);
|
||||
if (obj.type != kWasmBottom) {
|
||||
if (!VALIDATE(IsSubtypeOf(ValueType::Ref(rtt_type.type, kNonNullable),
|
||||
if (!VALIDATE(IsSubtypeOf(ValueType::Ref(imm.index, kNonNullable),
|
||||
obj.type, this->module_))) {
|
||||
PopTypeError(0, obj, "supertype of type " + rtt_type.type.name());
|
||||
PopTypeError(0, obj,
|
||||
"supertype of type " + std::to_string(imm.index));
|
||||
return 0;
|
||||
}
|
||||
CALL_INTERFACE_IF_REACHABLE(RefTest, obj, rtt, value);
|
||||
}
|
||||
return opcode_length + rtt_type.length;
|
||||
return opcode_length + imm.length;
|
||||
}
|
||||
case kExprRefCast: {
|
||||
HeapTypeImmediate<validate> rtt_type(
|
||||
this->enabled_, this, this->pc_ + opcode_length, this->module_);
|
||||
if (!VALIDATE(this->ok())) return 0;
|
||||
TypeIndexImmediate<validate> imm(this, this->pc_ + opcode_length);
|
||||
if (!this->Validate(this->pc_ + opcode_length, imm)) return 0;
|
||||
Value rtt = Pop(1);
|
||||
if (!VALIDATE(
|
||||
(rtt.type.is_rtt() && rtt.type.heap_type() == rtt_type.type) ||
|
||||
(rtt.type.is_rtt() && rtt.type.ref_index() == imm.index) ||
|
||||
rtt.type == kWasmBottom)) {
|
||||
PopTypeError(1, rtt, "rtt for type " + rtt_type.type.name());
|
||||
PopTypeError(1, rtt, "rtt for type " + std::to_string(imm.index));
|
||||
return 0;
|
||||
}
|
||||
Value obj = Pop(0, kWasmAnyRef);
|
||||
Value* value = Push(ValueType::Ref(rtt_type.type, kNonNullable));
|
||||
Value* value = Push(ValueType::Ref(imm.index, kNonNullable));
|
||||
if (obj.type != kWasmBottom) {
|
||||
if (!VALIDATE(IsSubtypeOf(ValueType::Ref(rtt_type.type, kNonNullable),
|
||||
if (!VALIDATE(IsSubtypeOf(ValueType::Ref(imm.index, kNonNullable),
|
||||
obj.type, this->module_))) {
|
||||
PopTypeError(0, obj, "supertype of type " + rtt_type.type.name());
|
||||
PopTypeError(0, obj,
|
||||
"supertype of type " + std::to_string(imm.index));
|
||||
return 0;
|
||||
}
|
||||
CALL_INTERFACE_IF_REACHABLE(RefCast, obj, rtt, value);
|
||||
}
|
||||
return opcode_length + rtt_type.length;
|
||||
return opcode_length + imm.length;
|
||||
}
|
||||
case kExprBrOnCast: {
|
||||
BranchDepthImmediate<validate> branch_depth(this,
|
||||
@ -4093,8 +4109,6 @@ class WasmFullDecoder : public WasmDecoder<validate> {
|
||||
control_.size())) {
|
||||
return 0;
|
||||
}
|
||||
// TODO(7748): If the heap type immediates remain in the spec, read
|
||||
// them here.
|
||||
Value rtt = Pop(1);
|
||||
if (!VALIDATE(rtt.type.is_rtt() || rtt.type.is_bottom())) {
|
||||
PopTypeError(1, rtt, "rtt");
|
||||
@ -4108,8 +4122,9 @@ class WasmFullDecoder : public WasmDecoder<validate> {
|
||||
}
|
||||
// The static type of {obj} must be a supertype of {rtt}'s type.
|
||||
if (!VALIDATE(rtt.type.is_bottom() || obj.type.is_bottom() ||
|
||||
IsHeapSubtypeOf(rtt.type.heap_type(),
|
||||
obj.type.heap_type(), this->module_))) {
|
||||
IsHeapSubtypeOf(rtt.type.ref_index(),
|
||||
obj.type.heap_representation(),
|
||||
this->module_))) {
|
||||
PopTypeError(1, rtt, obj.type);
|
||||
return 0;
|
||||
}
|
||||
@ -4117,7 +4132,7 @@ class WasmFullDecoder : public WasmDecoder<validate> {
|
||||
Value* result_on_branch =
|
||||
Push(rtt.type.is_bottom()
|
||||
? kWasmBottom
|
||||
: ValueType::Ref(rtt.type.heap_type(), kNonNullable));
|
||||
: ValueType::Ref(rtt.type.ref_index(), kNonNullable));
|
||||
TypeCheckBranchResult check_result = TypeCheckBranch(c, true);
|
||||
if (V8_LIKELY(check_result == kReachableBranch)) {
|
||||
CALL_INTERFACE(BrOnCast, obj, rtt, result_on_branch,
|
||||
|
@ -971,14 +971,13 @@ class WasmGraphBuildingInterface {
|
||||
result->node = BUILD(I31GetU, input.node);
|
||||
}
|
||||
|
||||
void RttCanon(FullDecoder* decoder, const HeapTypeImmediate<validate>& imm,
|
||||
Value* result) {
|
||||
result->node = BUILD(RttCanon, imm.type);
|
||||
void RttCanon(FullDecoder* decoder, uint32_t type_index, Value* result) {
|
||||
result->node = BUILD(RttCanon, type_index);
|
||||
}
|
||||
|
||||
void RttSub(FullDecoder* decoder, const HeapTypeImmediate<validate>& imm,
|
||||
const Value& parent, Value* result) {
|
||||
result->node = BUILD(RttSub, imm.type, parent.node);
|
||||
void RttSub(FullDecoder* decoder, uint32_t type_index, const Value& parent,
|
||||
Value* result) {
|
||||
result->node = BUILD(RttSub, type_index, parent.node);
|
||||
}
|
||||
|
||||
using StaticKnowledge = compiler::WasmGraphBuilder::ObjectReferenceKnowledge;
|
||||
@ -991,7 +990,6 @@ class WasmGraphBuildingInterface {
|
||||
DCHECK(object_type.is_object_reference_type()); // Checked by validation.
|
||||
result.object_must_be_data_ref = is_data_ref_type(object_type, module);
|
||||
result.object_can_be_i31 = IsSubtypeOf(kWasmI31Ref, object_type, module);
|
||||
result.rtt_is_i31 = rtt_type.heap_representation() == HeapType::kI31;
|
||||
result.rtt_depth = rtt_type.depth();
|
||||
return result;
|
||||
}
|
||||
|
@ -1369,8 +1369,7 @@ class ModuleDecoderImpl : public Decoder {
|
||||
case WasmInitExpr::kRefNullConst:
|
||||
return ValueType::Ref(expr.immediate().heap_type, kNullable);
|
||||
case WasmInitExpr::kRttCanon: {
|
||||
uint8_t depth = expr.immediate().heap_type == HeapType::kAny ? 0 : 1;
|
||||
return ValueType::Rtt(expr.immediate().heap_type, depth);
|
||||
return ValueType::Rtt(expr.immediate().heap_type, 0);
|
||||
}
|
||||
case WasmInitExpr::kRttSub: {
|
||||
ValueType operand_type = TypeOf(*expr.operand());
|
||||
@ -1768,18 +1767,21 @@ class ModuleDecoderImpl : public Decoder {
|
||||
opcode = read_prefixed_opcode<validate>(pc(), &len);
|
||||
switch (opcode) {
|
||||
case kExprRttCanon: {
|
||||
HeapTypeImmediate<validate> imm(enabled_features_, this, pc() + 2,
|
||||
module_.get());
|
||||
if (V8_UNLIKELY(failed())) return {};
|
||||
TypeIndexImmediate<validate> imm(this, pc() + 2);
|
||||
if (V8_UNLIKELY(imm.index >= module_->types.capacity())) {
|
||||
errorf(pc() + 2, "type index %u is out of bounds", imm.index);
|
||||
return {};
|
||||
}
|
||||
len += imm.length;
|
||||
stack.push_back(
|
||||
WasmInitExpr::RttCanon(imm.type.representation()));
|
||||
stack.push_back(WasmInitExpr::RttCanon(imm.index));
|
||||
break;
|
||||
}
|
||||
case kExprRttSub: {
|
||||
HeapTypeImmediate<validate> imm(enabled_features_, this, pc() + 2,
|
||||
module_.get());
|
||||
if (V8_UNLIKELY(failed())) return {};
|
||||
TypeIndexImmediate<validate> imm(this, pc() + 2);
|
||||
if (V8_UNLIKELY(imm.index >= module_->types.capacity())) {
|
||||
errorf(pc() + 2, "type index %u is out of bounds", imm.index);
|
||||
return {};
|
||||
}
|
||||
len += imm.length;
|
||||
if (stack.empty()) {
|
||||
error(pc(), "calling rtt.sub without arguments");
|
||||
@ -1788,17 +1790,15 @@ class ModuleDecoderImpl : public Decoder {
|
||||
WasmInitExpr parent = std::move(stack.back());
|
||||
stack.pop_back();
|
||||
ValueType parent_type = TypeOf(parent);
|
||||
if (V8_UNLIKELY(
|
||||
parent_type.kind() != ValueType::kRtt ||
|
||||
!IsSubtypeOf(
|
||||
ValueType::Ref(imm.type, kNonNullable),
|
||||
ValueType::Ref(parent_type.heap_type(), kNonNullable),
|
||||
module_.get()))) {
|
||||
if (V8_UNLIKELY(!parent_type.is_rtt() ||
|
||||
!IsHeapSubtypeOf(imm.index,
|
||||
parent_type.ref_index(),
|
||||
module_.get()))) {
|
||||
error(pc(), "rtt.sub requires a supertype rtt on stack");
|
||||
return {};
|
||||
}
|
||||
stack.push_back(WasmInitExpr::RttSub(imm.type.representation(),
|
||||
std::move(parent)));
|
||||
stack.push_back(
|
||||
WasmInitExpr::RttSub(imm.index, std::move(parent)));
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
|
@ -119,7 +119,7 @@ class CompileImportWrapperJob final : public JobTask {
|
||||
|
||||
// TODO(jkummerow): Move these elsewhere.
|
||||
Handle<Map> CreateStructMap(Isolate* isolate, const WasmModule* module,
|
||||
int struct_index, Handle<Map> rtt_parent) {
|
||||
int struct_index, Handle<Map> opt_rtt_parent) {
|
||||
const wasm::StructType* type = module->struct_type(struct_index);
|
||||
const int inobject_properties = 0;
|
||||
DCHECK_LE(type->total_fields_size(), kMaxInt - WasmStruct::kHeaderSize);
|
||||
@ -129,7 +129,7 @@ Handle<Map> CreateStructMap(Isolate* isolate, const WasmModule* module,
|
||||
// TODO(jkummerow): If NO_ELEMENTS were supported, we could use that here.
|
||||
const ElementsKind elements_kind = TERMINAL_FAST_ELEMENTS_KIND;
|
||||
Handle<WasmTypeInfo> type_info = isolate->factory()->NewWasmTypeInfo(
|
||||
reinterpret_cast<Address>(type), rtt_parent);
|
||||
reinterpret_cast<Address>(type), opt_rtt_parent);
|
||||
Handle<Map> map = isolate->factory()->NewMap(
|
||||
instance_type, instance_size, elements_kind, inobject_properties);
|
||||
map->set_wasm_type_info(*type_info);
|
||||
@ -137,28 +137,14 @@ Handle<Map> CreateStructMap(Isolate* isolate, const WasmModule* module,
|
||||
}
|
||||
|
||||
Handle<Map> CreateArrayMap(Isolate* isolate, const WasmModule* module,
|
||||
int array_index, Handle<Map> rtt_parent) {
|
||||
int array_index, Handle<Map> opt_rtt_parent) {
|
||||
const wasm::ArrayType* type = module->array_type(array_index);
|
||||
const int inobject_properties = 0;
|
||||
const int instance_size = kVariableSizeSentinel;
|
||||
const InstanceType instance_type = WASM_ARRAY_TYPE;
|
||||
const ElementsKind elements_kind = TERMINAL_FAST_ELEMENTS_KIND;
|
||||
Handle<WasmTypeInfo> type_info = isolate->factory()->NewWasmTypeInfo(
|
||||
reinterpret_cast<Address>(type), rtt_parent);
|
||||
Handle<Map> map = isolate->factory()->NewMap(
|
||||
instance_type, instance_size, elements_kind, inobject_properties);
|
||||
map->set_wasm_type_info(*type_info);
|
||||
return map;
|
||||
}
|
||||
|
||||
Handle<Map> CreateGenericRtt(Isolate* isolate, const WasmModule* module,
|
||||
Handle<Map> rtt_parent) {
|
||||
const int inobject_properties = 0;
|
||||
const int instance_size = 0;
|
||||
const InstanceType instance_type = WASM_STRUCT_TYPE; // Fake; good enough.
|
||||
const ElementsKind elements_kind = TERMINAL_FAST_ELEMENTS_KIND;
|
||||
Handle<WasmTypeInfo> type_info =
|
||||
isolate->factory()->NewWasmTypeInfo(0, rtt_parent);
|
||||
reinterpret_cast<Address>(type), opt_rtt_parent);
|
||||
Handle<Map> map = isolate->factory()->NewMap(
|
||||
instance_type, instance_size, elements_kind, inobject_properties);
|
||||
map->set_wasm_type_info(*type_info);
|
||||
@ -207,9 +193,7 @@ Handle<Map> AllocateSubRtt(Isolate* isolate,
|
||||
// Allocate a fresh RTT otherwise.
|
||||
const wasm::WasmModule* module = instance->module();
|
||||
Handle<Map> rtt;
|
||||
if (wasm::HeapType(type).is_generic()) {
|
||||
rtt = wasm::CreateGenericRtt(isolate, module, parent);
|
||||
} else if (module->has_struct(type)) {
|
||||
if (module->has_struct(type)) {
|
||||
rtt = wasm::CreateStructMap(isolate, module, type, parent);
|
||||
} else if (module->has_array(type)) {
|
||||
rtt = wasm::CreateArrayMap(isolate, module, type, parent);
|
||||
@ -628,18 +612,16 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
|
||||
if (enabled_.has_gc()) {
|
||||
Handle<FixedArray> maps = isolate_->factory()->NewUninitializedFixedArray(
|
||||
static_cast<int>(module_->type_kinds.size()));
|
||||
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_map);
|
||||
map = CreateStructMap(isolate_, module_, map_index, Handle<Map>());
|
||||
break;
|
||||
case kWasmArrayTypeCode:
|
||||
map = CreateArrayMap(isolate_, module_, map_index, anyref_map);
|
||||
map = CreateArrayMap(isolate_, module_, map_index, Handle<Map>());
|
||||
break;
|
||||
case kWasmFunctionTypeCode:
|
||||
// TODO(7748): Think about canonicalizing rtts to make them work for
|
||||
@ -1553,26 +1535,11 @@ Handle<Object> InstanceBuilder::RecursivelyEvaluateGlobalInitializer(
|
||||
return handle(tagged_globals_->get(old_offset), isolate_);
|
||||
}
|
||||
case WasmInitExpr::kRttCanon: {
|
||||
switch (init.immediate().heap_type) {
|
||||
case wasm::HeapType::kEq:
|
||||
return isolate_->root_handle(RootIndex::kWasmRttEqrefMap);
|
||||
case wasm::HeapType::kExtern:
|
||||
return isolate_->root_handle(RootIndex::kWasmRttExternrefMap);
|
||||
case wasm::HeapType::kFunc:
|
||||
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::kBottom:
|
||||
UNREACHABLE();
|
||||
}
|
||||
// Non-generic types fall through.
|
||||
int map_index = init.immediate().heap_type;
|
||||
int map_index = init.immediate().index;
|
||||
return handle(instance->managed_object_maps().get(map_index), isolate_);
|
||||
}
|
||||
case WasmInitExpr::kRttSub: {
|
||||
uint32_t type = static_cast<uint32_t>(init.immediate().heap_type);
|
||||
uint32_t type = init.immediate().index;
|
||||
Handle<Object> parent =
|
||||
RecursivelyEvaluateGlobalInitializer(*init.operand(), instance);
|
||||
return AllocateSubRtt(isolate_, instance, type,
|
||||
|
@ -194,17 +194,13 @@ class ValueType {
|
||||
return Ref(heap_type.representation(), nullability);
|
||||
}
|
||||
|
||||
static constexpr ValueType Rtt(uint32_t heap_type,
|
||||
static constexpr ValueType Rtt(uint32_t type_index,
|
||||
uint8_t inheritance_depth) {
|
||||
CONSTEXPR_DCHECK(HeapType(heap_type).is_valid());
|
||||
CONSTEXPR_DCHECK(HeapType(type_index).is_index());
|
||||
return ValueType(KindField::encode(kRtt) |
|
||||
HeapTypeField::encode(heap_type) |
|
||||
HeapTypeField::encode(type_index) |
|
||||
DepthField::encode(inheritance_depth));
|
||||
}
|
||||
static constexpr ValueType Rtt(HeapType heap_type,
|
||||
uint8_t inheritance_depth) {
|
||||
return Rtt(heap_type.representation(), inheritance_depth);
|
||||
}
|
||||
|
||||
// Useful when deserializing a type stored in a runtime object.
|
||||
static constexpr ValueType FromRawBitField(uint32_t bit_field) {
|
||||
@ -231,7 +227,7 @@ class ValueType {
|
||||
constexpr bool has_depth() const { return is_rtt(); }
|
||||
|
||||
constexpr bool has_index() const {
|
||||
return is_reference_type() && heap_type().is_index();
|
||||
return is_rtt() || (is_object_reference_type() && heap_type().is_index());
|
||||
}
|
||||
|
||||
constexpr bool is_defaultable() const {
|
||||
@ -250,11 +246,12 @@ class ValueType {
|
||||
/***************************** Field Accessors ******************************/
|
||||
constexpr Kind kind() const { return KindField::decode(bit_field_); }
|
||||
constexpr HeapType::Representation heap_representation() const {
|
||||
CONSTEXPR_DCHECK(is_reference_type());
|
||||
CONSTEXPR_DCHECK(is_object_reference_type());
|
||||
return static_cast<HeapType::Representation>(
|
||||
HeapTypeField::decode(bit_field_));
|
||||
}
|
||||
constexpr HeapType heap_type() const {
|
||||
CONSTEXPR_DCHECK(is_object_reference_type());
|
||||
return HeapType(heap_representation());
|
||||
}
|
||||
constexpr uint8_t depth() const {
|
||||
@ -263,7 +260,7 @@ class ValueType {
|
||||
}
|
||||
constexpr uint32_t ref_index() const {
|
||||
CONSTEXPR_DCHECK(has_index());
|
||||
return heap_type().ref_index();
|
||||
return HeapTypeField::decode(bit_field_);
|
||||
}
|
||||
|
||||
// Useful when serializing this type to store it into a runtime object.
|
||||
@ -429,8 +426,8 @@ class ValueType {
|
||||
}
|
||||
break;
|
||||
case kRtt:
|
||||
buf << "(rtt " << static_cast<uint32_t>(depth()) << " "
|
||||
<< heap_type().name() << ")";
|
||||
buf << "(rtt " << static_cast<uint32_t>(depth()) << " " << ref_index()
|
||||
<< ")";
|
||||
break;
|
||||
default:
|
||||
buf << kind_name();
|
||||
|
@ -414,12 +414,13 @@ void WasmModuleBuilder::SetHasSharedMemory() { has_shared_memory_ = true; }
|
||||
namespace {
|
||||
void WriteValueType(ZoneBuffer* buffer, const ValueType& type) {
|
||||
buffer->write_u8(type.value_type_code());
|
||||
if (type.has_depth()) {
|
||||
buffer->write_u32v(type.depth());
|
||||
}
|
||||
if (type.encoding_needs_heap_type()) {
|
||||
if (type.is_object_reference_type() && type.encoding_needs_heap_type()) {
|
||||
buffer->write_i32v(type.heap_type().code());
|
||||
}
|
||||
if (type.is_rtt()) {
|
||||
buffer->write_u32v(type.depth());
|
||||
buffer->write_u32v(type.ref_index());
|
||||
}
|
||||
}
|
||||
|
||||
void WriteGlobalInitializer(ZoneBuffer* buffer, const WasmInitExpr& init,
|
||||
@ -497,7 +498,7 @@ void WriteGlobalInitializer(ZoneBuffer* buffer, const WasmInitExpr& init,
|
||||
STATIC_ASSERT((kExprRttCanon >> 8) == kGCPrefix);
|
||||
buffer->write_u8(kGCPrefix);
|
||||
buffer->write_u8(static_cast<uint8_t>(kExprRttCanon));
|
||||
buffer->write_i32v(HeapType(init.immediate().heap_type).code());
|
||||
buffer->write_i32v(static_cast<int32_t>(init.immediate().index));
|
||||
break;
|
||||
case WasmInitExpr::kRttSub:
|
||||
// The operand to rtt.sub must be emitted first.
|
||||
@ -507,7 +508,7 @@ void WriteGlobalInitializer(ZoneBuffer* buffer, const WasmInitExpr& init,
|
||||
STATIC_ASSERT((kExprRttSub >> 8) == kGCPrefix);
|
||||
buffer->write_u8(kGCPrefix);
|
||||
buffer->write_u8(static_cast<uint8_t>(kExprRttSub));
|
||||
buffer->write_i32v(HeapType(init.immediate().heap_type).code());
|
||||
buffer->write_i32v(static_cast<int32_t>(init.immediate().index));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -933,11 +933,9 @@ class WasmArray : public TorqueGeneratedWasmArray<WasmArray, HeapObject> {
|
||||
namespace wasm {
|
||||
|
||||
Handle<Map> CreateStructMap(Isolate* isolate, const WasmModule* module,
|
||||
int struct_index, Handle<Map> rtt_parent);
|
||||
int struct_index, MaybeHandle<Map> rtt_parent);
|
||||
Handle<Map> CreateArrayMap(Isolate* isolate, const WasmModule* module,
|
||||
int array_index, Handle<Map> rtt_parent);
|
||||
Handle<Map> CreateGenericRtt(Isolate* isolate, const WasmModule* module,
|
||||
Handle<Map> rtt_parent);
|
||||
int array_index, MaybeHandle<Map> rtt_parent);
|
||||
Handle<Map> AllocateSubRtt(Isolate* isolate,
|
||||
Handle<WasmInstanceObject> instance, uint32_t type,
|
||||
Handle<Map> parent);
|
||||
|
@ -106,7 +106,6 @@ extern class AsmWasmData extends Struct {
|
||||
|
||||
@generateCppClass
|
||||
extern class WasmTypeInfo extends Foreign {
|
||||
parent: Map;
|
||||
supertypes: FixedArray;
|
||||
subtypes: ArrayList;
|
||||
}
|
||||
|
@ -864,18 +864,17 @@ class WasmInitExpr {
|
||||
return expr;
|
||||
}
|
||||
|
||||
static WasmInitExpr RttCanon(HeapType::Representation heap_type) {
|
||||
static WasmInitExpr RttCanon(uint32_t index) {
|
||||
WasmInitExpr expr;
|
||||
expr.kind_ = kRttCanon;
|
||||
expr.immediate_.heap_type = heap_type;
|
||||
expr.immediate_.index = index;
|
||||
return expr;
|
||||
}
|
||||
|
||||
static WasmInitExpr RttSub(HeapType::Representation heap_type,
|
||||
WasmInitExpr supertype) {
|
||||
static WasmInitExpr RttSub(uint32_t index, WasmInitExpr supertype) {
|
||||
WasmInitExpr expr;
|
||||
expr.kind_ = kRttSub;
|
||||
expr.immediate_.heap_type = heap_type;
|
||||
expr.immediate_.index = index;
|
||||
expr.operand_ = std::make_unique<WasmInitExpr>(std::move(supertype));
|
||||
return expr;
|
||||
}
|
||||
@ -891,6 +890,7 @@ class WasmInitExpr {
|
||||
return true;
|
||||
case kGlobalGet:
|
||||
case kRefFuncConst:
|
||||
case kRttCanon:
|
||||
return immediate().index == other.immediate().index;
|
||||
case kI32Const:
|
||||
return immediate().i32_const == other.immediate().i32_const;
|
||||
@ -903,10 +903,9 @@ class WasmInitExpr {
|
||||
case kS128Const:
|
||||
return immediate().s128_const == other.immediate().s128_const;
|
||||
case kRefNullConst:
|
||||
case kRttCanon:
|
||||
return immediate().heap_type == other.immediate().heap_type;
|
||||
case kRttSub:
|
||||
return immediate().heap_type == other.immediate().heap_type &&
|
||||
return immediate().index == other.immediate().index &&
|
||||
*operand() == *other.operand();
|
||||
}
|
||||
}
|
||||
|
@ -277,12 +277,9 @@ V8_NOINLINE V8_EXPORT_PRIVATE bool IsSubtypeOfImpl(
|
||||
if (!subtype.is_reference_type()) return subtype == supertype;
|
||||
|
||||
if (subtype.is_rtt()) {
|
||||
return subtype.heap_type().is_generic()
|
||||
? subtype == supertype
|
||||
: (supertype.is_rtt() && subtype.depth() == supertype.depth() &&
|
||||
supertype.has_index() &&
|
||||
EquivalentIndices(subtype.ref_index(), supertype.ref_index(),
|
||||
sub_module, super_module));
|
||||
return supertype.is_rtt() && subtype.depth() == supertype.depth() &&
|
||||
EquivalentIndices(subtype.ref_index(), supertype.ref_index(),
|
||||
sub_module, super_module);
|
||||
}
|
||||
|
||||
DCHECK(subtype.is_object_reference_type());
|
||||
|
@ -70,12 +70,18 @@ V8_INLINE bool IsSubtypeOf(ValueType subtype, ValueType supertype,
|
||||
}
|
||||
|
||||
// We have this function call IsSubtypeOf instead of the opposite because type
|
||||
// checks are much more common than heap type checks.
|
||||
V8_INLINE bool IsHeapSubtypeOf(HeapType subtype, HeapType supertype,
|
||||
// checks are much more common than heap type checks.}
|
||||
V8_INLINE bool IsHeapSubtypeOf(uint32_t subtype_index,
|
||||
HeapType::Representation supertype,
|
||||
const WasmModule* module) {
|
||||
return IsSubtypeOf(ValueType::Ref(subtype, kNonNullable),
|
||||
return IsSubtypeOf(ValueType::Ref(subtype_index, kNonNullable),
|
||||
ValueType::Ref(supertype, kNonNullable), module);
|
||||
}
|
||||
V8_INLINE bool IsHeapSubtypeOf(uint32_t subtype_index, uint32_t supertype_index,
|
||||
const WasmModule* module) {
|
||||
return IsSubtypeOf(ValueType::Ref(subtype_index, kNonNullable),
|
||||
ValueType::Ref(supertype_index, kNonNullable), module);
|
||||
}
|
||||
|
||||
// Returns the weakest type that is a subtype of both a and b
|
||||
// (which is currently always one of a, b, or kWasmBottom).
|
||||
|
@ -348,8 +348,9 @@ WASM_COMPILED_EXEC_TEST(BrOnCast) {
|
||||
WasmGCTester tester(execution_tier);
|
||||
FLAG_experimental_liftoff_extern_ref = true;
|
||||
const byte type_index = tester.DefineStruct({F(kWasmI32, true)});
|
||||
const byte other_type_index = tester.DefineStruct({F(kWasmF32, true)});
|
||||
const byte rtt_index =
|
||||
tester.AddGlobal(ValueType::Rtt(type_index, 1), false,
|
||||
tester.AddGlobal(ValueType::Rtt(type_index, 0), false,
|
||||
WasmInitExpr::RttCanon(
|
||||
static_cast<HeapType::Representation>(type_index)));
|
||||
const byte kTestStruct = tester.DefineFunction(
|
||||
@ -361,8 +362,8 @@ WASM_COMPILED_EXEC_TEST(BrOnCast) {
|
||||
1, WASM_STRUCT_NEW_WITH_RTT(type_index, WASM_I32V(1),
|
||||
WASM_GLOBAL_GET(rtt_index))),
|
||||
WASM_LOCAL_GET(1),
|
||||
// The struct is not an i31, so this branch isn't taken.
|
||||
WASM_BR_ON_CAST(0, WASM_RTT_CANON(kI31RefCode)),
|
||||
// The type check fails, so this branch isn't taken.
|
||||
WASM_BR_ON_CAST(0, WASM_RTT_CANON(other_type_index)),
|
||||
WASM_LOCAL_SET(0, WASM_I32V(222)), // Final result.
|
||||
// This branch is taken.
|
||||
WASM_BR_ON_CAST(0, WASM_GLOBAL_GET(rtt_index)),
|
||||
@ -378,12 +379,8 @@ WASM_COMPILED_EXEC_TEST(BrOnCast) {
|
||||
WASM_LOCAL_SET(1, WASM_I31_NEW(WASM_I32V(42))),
|
||||
WASM_LOCAL_GET(1),
|
||||
// The i31 is not a struct, so this branch isn't taken.
|
||||
WASM_BR_ON_CAST(0, WASM_GLOBAL_GET(rtt_index)),
|
||||
WASM_LOCAL_SET(0, WASM_I32V(222)), // Final result.
|
||||
// This branch is taken.
|
||||
WASM_BR_ON_CAST(0, WASM_RTT_CANON(kI31RefCode)),
|
||||
// Not executed due to the branch.
|
||||
WASM_DROP, WASM_LOCAL_SET(0, WASM_I32V(333))),
|
||||
WASM_BR_ON_CAST(0, WASM_GLOBAL_GET(rtt_index)), WASM_DROP,
|
||||
WASM_LOCAL_SET(0, WASM_I32V(222))), // Final result.
|
||||
WASM_LOCAL_GET(0), kExprEnd});
|
||||
|
||||
const byte kTestNull = tester.DefineFunction(
|
||||
@ -391,7 +388,7 @@ WASM_COMPILED_EXEC_TEST(BrOnCast) {
|
||||
{WASM_BLOCK(WASM_LOCAL_SET(0, WASM_I32V(111)),
|
||||
WASM_LOCAL_GET(1), // Put a nullref onto the value stack.
|
||||
// Neither of these branches is taken for nullref.
|
||||
WASM_BR_ON_CAST(0, WASM_RTT_CANON(kI31RefCode)),
|
||||
WASM_BR_ON_CAST(0, WASM_RTT_CANON(other_type_index)),
|
||||
WASM_LOCAL_SET(0, WASM_I32V(222)),
|
||||
WASM_BR_ON_CAST(0, WASM_GLOBAL_GET(rtt_index)), WASM_DROP,
|
||||
WASM_LOCAL_SET(0, WASM_I32V(333))), // Final result.
|
||||
@ -806,12 +803,11 @@ TEST(BasicRTT) {
|
||||
const byte type_index = tester.DefineStruct({F(wasm::kWasmI32, true)});
|
||||
const byte subtype_index =
|
||||
tester.DefineStruct({F(wasm::kWasmI32, true), F(wasm::kWasmI32, true)});
|
||||
ValueType kRttTypes[] = {ValueType::Rtt(type_index, 1)};
|
||||
ValueType kRttTypes[] = {ValueType::Rtt(type_index, 0)};
|
||||
FunctionSig sig_t_v(1, 0, kRttTypes);
|
||||
ValueType kRttSubtypes[] = {
|
||||
ValueType::Rtt(static_cast<HeapType>(subtype_index), 2)};
|
||||
ValueType kRttSubtypes[] = {ValueType::Rtt(subtype_index, 1)};
|
||||
FunctionSig sig_t2_v(1, 0, kRttSubtypes);
|
||||
ValueType kRttTypesDeeper[] = {ValueType::Rtt(type_index, 2)};
|
||||
ValueType kRttTypesDeeper[] = {ValueType::Rtt(type_index, 1)};
|
||||
FunctionSig sig_t3_v(1, 0, kRttTypesDeeper);
|
||||
ValueType kRefTypes[] = {ref(type_index)};
|
||||
FunctionSig sig_q_v(1, 0, kRefTypes);
|
||||
@ -821,9 +817,6 @@ TEST(BasicRTT) {
|
||||
const byte kRttSub = tester.DefineFunction(
|
||||
&sig_t2_v, {},
|
||||
{WASM_RTT_SUB(subtype_index, WASM_RTT_CANON(type_index)), kExprEnd});
|
||||
const byte kRttSubGeneric = tester.DefineFunction(
|
||||
&sig_t3_v, {},
|
||||
{WASM_RTT_SUB(type_index, WASM_RTT_CANON(kEqRefCode)), kExprEnd});
|
||||
const byte kStructWithRtt = tester.DefineFunction(
|
||||
&sig_q_v, {},
|
||||
{WASM_STRUCT_NEW_WITH_RTT(type_index, WASM_I32V(42),
|
||||
@ -843,7 +836,7 @@ TEST(BasicRTT) {
|
||||
const byte kRefCast = tester.DefineFunction(
|
||||
tester.sigs.i_v(), {optref(type_index)},
|
||||
{WASM_LET_1_I(
|
||||
WASM_RTT(2, subtype_index),
|
||||
WASM_RTT(1, subtype_index),
|
||||
WASM_RTT_SUB(subtype_index, WASM_RTT_CANON(type_index)),
|
||||
WASM_LOCAL_SET(kStructIndexCode,
|
||||
WASM_STRUCT_NEW_WITH_RTT(
|
||||
@ -874,7 +867,6 @@ TEST(BasicRTT) {
|
||||
tester.GetResultObject(kRttSub).ToHandleChecked();
|
||||
CHECK(subref_result->IsMap());
|
||||
Handle<Map> submap = Handle<Map>::cast(subref_result);
|
||||
CHECK_EQ(*map, submap->wasm_type_info().parent());
|
||||
CHECK_EQ(reinterpret_cast<Address>(
|
||||
tester.instance()->module()->struct_type(subtype_index)),
|
||||
submap->wasm_type_info().foreign_address());
|
||||
@ -882,12 +874,6 @@ TEST(BasicRTT) {
|
||||
tester.GetResultObject(kRttSub).ToHandleChecked();
|
||||
CHECK(subref_result.is_identical_to(subref_result_canonicalized));
|
||||
|
||||
Handle<Object> sub_generic_1 =
|
||||
tester.GetResultObject(kRttSubGeneric).ToHandleChecked();
|
||||
Handle<Object> sub_generic_2 =
|
||||
tester.GetResultObject(kRttSubGeneric).ToHandleChecked();
|
||||
CHECK(sub_generic_1.is_identical_to(sub_generic_2));
|
||||
|
||||
Handle<Object> s = tester.GetResultObject(kStructWithRtt).ToHandleChecked();
|
||||
CHECK(s->IsWasmStruct());
|
||||
CHECK_EQ(Handle<WasmStruct>::cast(s)->map(), *map);
|
||||
@ -895,80 +881,6 @@ TEST(BasicRTT) {
|
||||
tester.CheckResult(kRefCast, 43);
|
||||
}
|
||||
|
||||
WASM_COMPILED_EXEC_TEST(AnyRefRtt) {
|
||||
WasmGCTester tester(execution_tier);
|
||||
FLAG_experimental_liftoff_extern_ref = true;
|
||||
|
||||
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_LOCAL_SET(0, WASM_ARRAY_NEW_DEFAULT(type_index, WASM_I32V(5),
|
||||
WASM_RTT_CANON(type_index))),
|
||||
WASM_REF_TEST(type_index, WASM_LOCAL_GET(0), WASM_RTT_CANON(type_index)),
|
||||
kExprEnd});
|
||||
|
||||
byte kCheckAnyAgainstAny = tester.DefineFunction(
|
||||
tester.sigs.i_v(), {kWasmAnyRef},
|
||||
{WASM_LOCAL_SET(0, WASM_ARRAY_NEW_DEFAULT(type_index, WASM_I32V(5),
|
||||
WASM_RTT_CANON(type_index))),
|
||||
WASM_REF_TEST(kAnyRefCode, WASM_LOCAL_GET(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);
|
||||
}
|
||||
|
||||
WASM_COMPILED_EXEC_TEST(ArrayNewMap) {
|
||||
WasmGCTester tester(execution_tier);
|
||||
FLAG_experimental_liftoff_extern_ref = true;
|
||||
@ -983,7 +895,7 @@ WASM_COMPILED_EXEC_TEST(ArrayNewMap) {
|
||||
WASM_RTT_CANON(type_index)),
|
||||
kExprEnd});
|
||||
|
||||
ValueType rtt_type = ValueType::Rtt(type_index, 1);
|
||||
ValueType rtt_type = ValueType::Rtt(type_index, 0);
|
||||
FunctionSig rtt_canon_sig(1, 0, &rtt_type);
|
||||
const byte kRttCanon = tester.DefineFunction(
|
||||
&rtt_canon_sig, {}, {WASM_RTT_CANON(type_index), kExprEnd});
|
||||
@ -1014,16 +926,10 @@ WASM_COMPILED_EXEC_TEST(FunctionRefs) {
|
||||
ValueType func_type = ValueType::Ref(sig_index, kNonNullable);
|
||||
FunctionSig sig_func(1, 0, &func_type);
|
||||
|
||||
ValueType rtt1 = ValueType::Rtt(sig_index, 1);
|
||||
FunctionSig sig_rtt1(1, 0, &rtt1);
|
||||
ValueType rtt0 = ValueType::Rtt(sig_index, 0);
|
||||
FunctionSig sig_rtt0(1, 0, &rtt0);
|
||||
const byte rtt_canon = tester.DefineFunction(
|
||||
&sig_rtt1, {}, {WASM_RTT_CANON(sig_index), kExprEnd});
|
||||
|
||||
ValueType rtt2 = ValueType::Rtt(sig_index, 2);
|
||||
FunctionSig sig_rtt2(1, 0, &rtt2);
|
||||
const byte rtt_sub = tester.DefineFunction(
|
||||
&sig_rtt2, {},
|
||||
{WASM_RTT_SUB(sig_index, WASM_RTT_CANON(kFuncRefCode)), kExprEnd});
|
||||
&sig_rtt0, {}, {WASM_RTT_CANON(sig_index), kExprEnd});
|
||||
|
||||
const byte cast = tester.DefineFunction(
|
||||
&sig_func, {kWasmFuncRef},
|
||||
@ -1049,11 +955,6 @@ WASM_COMPILED_EXEC_TEST(FunctionRefs) {
|
||||
Handle<Map> map_canon = Handle<Map>::cast(result_canon);
|
||||
CHECK(map_canon->IsJSFunctionMap());
|
||||
|
||||
Handle<Object> result_sub = tester.GetResultObject(rtt_sub).ToHandleChecked();
|
||||
CHECK(result_sub->IsMap());
|
||||
Handle<Map> map_sub = Handle<Map>::cast(result_sub);
|
||||
CHECK(map_sub->IsJSFunctionMap());
|
||||
|
||||
Handle<Object> result_cast = tester.GetResultObject(cast).ToHandleChecked();
|
||||
CHECK(result_cast->IsJSFunction());
|
||||
Handle<JSFunction> cast_function = Handle<JSFunction>::cast(result_cast);
|
||||
@ -1132,65 +1033,6 @@ WASM_COMPILED_EXEC_TEST(BasicI31) {
|
||||
tester.CheckResult(kUnsigned, 0x7FFFFFFF, 0x7FFFFFFF);
|
||||
}
|
||||
|
||||
WASM_COMPILED_EXEC_TEST(I31Casts) {
|
||||
WasmGCTester tester(execution_tier);
|
||||
FLAG_experimental_liftoff_extern_ref = true;
|
||||
const byte struct_type = tester.DefineStruct({F(wasm::kWasmI32, true)});
|
||||
const byte i31_rtt =
|
||||
tester.AddGlobal(ValueType::Rtt(HeapType::kI31, 1), false,
|
||||
WasmInitExpr::RttCanon(HeapType::kI31));
|
||||
const byte struct_rtt =
|
||||
tester.AddGlobal(ValueType::Rtt(struct_type, 1), false,
|
||||
WasmInitExpr::RttCanon(
|
||||
static_cast<HeapType::Representation>(struct_type)));
|
||||
// Adds the result of a successful typecheck to the untagged value, i.e.
|
||||
// should return 1 + 42 = 43.
|
||||
const byte kTestAndCastSuccess = tester.DefineFunction(
|
||||
tester.sigs.i_v(), {kWasmEqRef},
|
||||
{WASM_LOCAL_SET(0, WASM_I31_NEW(WASM_I32V(42))),
|
||||
WASM_I32_ADD(WASM_REF_TEST(kI31RefCode, WASM_LOCAL_GET(0),
|
||||
WASM_GLOBAL_GET(i31_rtt)),
|
||||
WASM_I31_GET_S(WASM_REF_CAST(kI31RefCode, WASM_LOCAL_GET(0),
|
||||
WASM_GLOBAL_GET(i31_rtt)))),
|
||||
kExprEnd});
|
||||
// Adds the results of two unsuccessful type checks (an i31ref is not a
|
||||
// struct, nor the other way round).
|
||||
const byte kTestFalse = tester.DefineFunction(
|
||||
tester.sigs.i_v(), {kWasmAnyRef},
|
||||
{WASM_LOCAL_SET(0, WASM_STRUCT_NEW_WITH_RTT(struct_type, WASM_I32V(42),
|
||||
WASM_GLOBAL_GET(struct_rtt))),
|
||||
WASM_I32_ADD(WASM_REF_TEST(kI31RefCode, WASM_LOCAL_GET(0),
|
||||
WASM_GLOBAL_GET(i31_rtt)),
|
||||
WASM_SEQ(WASM_LOCAL_SET(0, WASM_I31_NEW(WASM_I32V(23))),
|
||||
WASM_REF_TEST(struct_type, WASM_LOCAL_GET(0),
|
||||
WASM_GLOBAL_GET(struct_rtt)))),
|
||||
kExprEnd});
|
||||
|
||||
const byte kCastI31ToStruct = tester.DefineFunction(
|
||||
tester.sigs.i_i(), // Argument and return value ignored
|
||||
{kWasmAnyRef},
|
||||
{WASM_LOCAL_SET(1, WASM_I31_NEW(WASM_I32V(42))),
|
||||
WASM_STRUCT_GET(struct_type, 0,
|
||||
WASM_REF_CAST(struct_type, WASM_LOCAL_GET(1),
|
||||
WASM_GLOBAL_GET(struct_rtt))),
|
||||
kExprEnd});
|
||||
// Tries to cast a struct to i31ref, which should trap.
|
||||
const byte kCastStructToI31 = tester.DefineFunction(
|
||||
tester.sigs.i_i(), // Argument and return value ignored
|
||||
{kWasmAnyRef},
|
||||
{WASM_LOCAL_SET(1, WASM_STRUCT_NEW_WITH_RTT(struct_type, WASM_I32V(42),
|
||||
WASM_GLOBAL_GET(struct_rtt))),
|
||||
WASM_I31_GET_S(WASM_REF_CAST(kI31RefCode, WASM_LOCAL_GET(1),
|
||||
WASM_GLOBAL_GET(i31_rtt))),
|
||||
kExprEnd});
|
||||
|
||||
tester.CompileModule();
|
||||
tester.CheckResult(kTestAndCastSuccess, 43);
|
||||
tester.CheckResult(kTestFalse, 0);
|
||||
tester.CheckHasThrown(kCastI31ToStruct, 0);
|
||||
tester.CheckHasThrown(kCastStructToI31, 0);
|
||||
}
|
||||
|
||||
// This flushed out a few bugs, so it serves as a regression test. It can also
|
||||
// be modified (made to run longer) to measure performance of casts.
|
||||
WASM_COMPILED_EXEC_TEST(CastsBenchmark) {
|
||||
@ -1206,14 +1048,14 @@ WASM_COMPILED_EXEC_TEST(CastsBenchmark) {
|
||||
WasmInitExpr::RefNullConst(
|
||||
static_cast<HeapType::Representation>(ListType)));
|
||||
const byte RttSuper = tester.AddGlobal(
|
||||
ValueType::Rtt(SuperType, 1), false,
|
||||
ValueType::Rtt(SuperType, 0), false,
|
||||
WasmInitExpr::RttCanon(static_cast<HeapType::Representation>(SuperType)));
|
||||
const byte RttSub = tester.AddGlobal(
|
||||
ValueType::Rtt(SubType, 2), false,
|
||||
ValueType::Rtt(SubType, 1), false,
|
||||
WasmInitExpr::RttSub(static_cast<HeapType::Representation>(SubType),
|
||||
WasmInitExpr::GlobalGet(RttSuper)));
|
||||
const byte RttList = tester.AddGlobal(
|
||||
ValueType::Rtt(ListType, 1), false,
|
||||
ValueType::Rtt(ListType, 0), false,
|
||||
WasmInitExpr::RttCanon(static_cast<HeapType::Representation>(ListType)));
|
||||
|
||||
const uint32_t kListLength = 1024;
|
||||
|
@ -3812,7 +3812,7 @@ TEST_F(FunctionBodyDecoderTest, GCStruct) {
|
||||
kExprDrop},
|
||||
kAppendEnd,
|
||||
"struct.new_with_rtt[1] expected rtt for type 0, found "
|
||||
"rtt.canon of type (rtt 1 1)");
|
||||
"rtt.canon of type (rtt 0 1)");
|
||||
// Out-of-bounds index.
|
||||
ExpectFailure(sigs.v_v(),
|
||||
{WASM_STRUCT_NEW_WITH_RTT(42, WASM_I32V(0),
|
||||
@ -3945,7 +3945,7 @@ TEST_F(FunctionBodyDecoderTest, GCArray) {
|
||||
WASM_RTT_CANON(struct_type_index))},
|
||||
kAppendEnd,
|
||||
"array.new_with_rtt[2] expected rtt for type 0, found "
|
||||
"rtt.canon of type (rtt 1 1)");
|
||||
"rtt.canon of type (rtt 0 1)");
|
||||
// Wrong type index.
|
||||
ExpectFailure(
|
||||
sigs.v_v(),
|
||||
@ -4135,21 +4135,16 @@ TEST_F(FunctionBodyDecoderTest, RttCanon) {
|
||||
uint8_t array_type_index = builder.AddArray(kWasmI32, true);
|
||||
uint8_t struct_type_index = builder.AddStruct({F(kWasmI64, true)});
|
||||
|
||||
for (HeapType::Representation heap :
|
||||
{HeapType::kExtern, HeapType::kEq, HeapType::kI31, HeapType::kAny,
|
||||
static_cast<HeapType::Representation>(array_type_index),
|
||||
static_cast<HeapType::Representation>(struct_type_index)}) {
|
||||
ValueType rtt1 =
|
||||
ValueType::Rtt(HeapType(heap), heap == HeapType::kAny ? 0 : 1);
|
||||
for (uint32_t type_index : {array_type_index, struct_type_index}) {
|
||||
ValueType rtt1 = ValueType::Rtt(type_index, 0);
|
||||
FunctionSig sig1(1, 0, &rtt1);
|
||||
ExpectValidates(&sig1, {WASM_RTT_CANON(rtt1.heap_type().code() & 0x7F)});
|
||||
ExpectValidates(&sig1, {WASM_RTT_CANON(type_index)});
|
||||
|
||||
// rtt.canon should fail for incorrect depth.
|
||||
ValueType rtt2 =
|
||||
ValueType::Rtt(HeapType(heap), heap == HeapType::kAny ? 1 : 2);
|
||||
ValueType rtt2 = ValueType::Rtt(type_index, 1);
|
||||
FunctionSig sig2(1, 0, &rtt2);
|
||||
ExpectFailure(&sig2, {WASM_RTT_CANON(rtt2.heap_type().code() & 0x7F)},
|
||||
kAppendEnd, "type error in merge[0]");
|
||||
ExpectFailure(&sig2, {WASM_RTT_CANON(type_index)}, kAppendEnd,
|
||||
"type error in merge[0]");
|
||||
}
|
||||
}
|
||||
|
||||
@ -4166,82 +4161,33 @@ TEST_F(FunctionBodyDecoderTest, RttSub) {
|
||||
uint8_t sub_struct_type_index =
|
||||
builder.AddStruct({F(kWasmI16, true), F(kWasmI32, false)});
|
||||
|
||||
{
|
||||
// Can build an rtt.sub with self type for a generic heap type.
|
||||
ValueType type = ValueType::Rtt(HeapType::kFunc, 2);
|
||||
FunctionSig sig(1, 0, &type);
|
||||
ExpectValidates(&sig,
|
||||
{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[0] expected rtt for a supertype of type func");
|
||||
}
|
||||
|
||||
// Trivial type error.
|
||||
ExpectFailure(
|
||||
sigs.v_v(), {WASM_RTT_SUB(kFuncRefCode, WASM_I32V(42)), kExprDrop},
|
||||
kAppendEnd, "rtt.sub[0] expected rtt for a supertype of type func");
|
||||
sigs.v_v(), {WASM_RTT_SUB(array_type_index, WASM_I32V(42)), kExprDrop},
|
||||
kAppendEnd, "rtt.sub[0] expected rtt for a supertype of type 0");
|
||||
|
||||
{
|
||||
ValueType type = ValueType::Rtt(array_type_index, 2);
|
||||
ValueType type = ValueType::Rtt(array_type_index, 1);
|
||||
FunctionSig sig(1, 0, &type);
|
||||
// Can build an rtt.sub with self type for an array type.
|
||||
ExpectValidates(&sig, {WASM_RTT_SUB(array_type_index,
|
||||
WASM_RTT_CANON(array_type_index))});
|
||||
// Can build an rtt.sub for an array from eqref.
|
||||
ExpectValidates(
|
||||
&sig, {WASM_RTT_SUB(array_type_index, WASM_RTT_CANON(kEqRefCode))});
|
||||
// Fails when argument to rtt.sub is not a supertype.
|
||||
ExpectFailure(
|
||||
sigs.v_v(),
|
||||
{WASM_RTT_SUB(kEqRefCode, WASM_RTT_CANON(array_type_index)), kExprDrop},
|
||||
kAppendEnd, "rtt.sub[0] expected rtt for a supertype of type eq");
|
||||
ExpectFailure(sigs.v_v(),
|
||||
{WASM_RTT_SUB(super_struct_type_index,
|
||||
WASM_RTT_CANON(array_type_index)),
|
||||
kExprDrop},
|
||||
kAppendEnd,
|
||||
"rtt.sub[0] expected rtt for a supertype of type 1");
|
||||
}
|
||||
|
||||
{
|
||||
ValueType type = ValueType::Rtt(super_struct_type_index, 2);
|
||||
ValueType type = ValueType::Rtt(super_struct_type_index, 1);
|
||||
FunctionSig sig(1, 0, &type);
|
||||
// Can build an rtt.sub with self type for a struct type.
|
||||
ExpectValidates(&sig,
|
||||
{WASM_RTT_SUB(super_struct_type_index,
|
||||
WASM_RTT_CANON(super_struct_type_index))});
|
||||
// Can build an rtt.sub for a struct from eqref.
|
||||
ExpectValidates(&sig, {WASM_RTT_SUB(super_struct_type_index,
|
||||
WASM_RTT_CANON(kEqRefCode))});
|
||||
// Fails when argument to rtt.sub is not a supertype.
|
||||
ExpectFailure(sigs.v_v(),
|
||||
{WASM_RTT_SUB(super_struct_type_index,
|
||||
@ -4257,7 +4203,7 @@ TEST_F(FunctionBodyDecoderTest, RttSub) {
|
||||
|
||||
{
|
||||
// Can build an rtt from a stuct supertype.
|
||||
ValueType type = ValueType::Rtt(sub_struct_type_index, 2);
|
||||
ValueType type = ValueType::Rtt(sub_struct_type_index, 1);
|
||||
FunctionSig sig(1, 0, &type);
|
||||
ExpectValidates(&sig,
|
||||
{WASM_RTT_SUB(sub_struct_type_index,
|
||||
@ -4285,10 +4231,10 @@ TEST_F(FunctionBodyDecoderTest, RefTestCast) {
|
||||
|
||||
// Passing/failing tests due to static subtyping.
|
||||
std::pair<HeapType::Representation, HeapType::Representation> valid_pairs[] =
|
||||
{{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},
|
||||
{{HeapType::kAny, array_heap},
|
||||
{HeapType::kAny, super_struct_heap},
|
||||
{HeapType::kEq, array_heap},
|
||||
{HeapType::kEq, super_struct_heap},
|
||||
{super_struct_heap, sub_struct_heap}};
|
||||
|
||||
for (auto pair : valid_pairs) {
|
||||
@ -4308,11 +4254,9 @@ TEST_F(FunctionBodyDecoderTest, RefTestCast) {
|
||||
}
|
||||
|
||||
std::pair<HeapType::Representation, HeapType::Representation>
|
||||
invalid_pairs[] = {{array_heap, HeapType::kAny},
|
||||
{HeapType::kEq, HeapType::kAny},
|
||||
{HeapType::kI31, HeapType::kEq},
|
||||
{array_heap, super_struct_heap},
|
||||
{array_heap, HeapType::kEq}};
|
||||
invalid_pairs[] = {{sub_struct_heap, super_struct_heap},
|
||||
{sub_struct_heap, array_heap},
|
||||
{HeapType::kFunc, array_heap}};
|
||||
|
||||
for (auto pair : invalid_pairs) {
|
||||
HeapType from_heap = HeapType(pair.first);
|
||||
@ -4324,7 +4268,8 @@ TEST_F(FunctionBodyDecoderTest, RefTestCast) {
|
||||
FunctionSig cast_sig(1, 1, cast_reps);
|
||||
|
||||
std::string error_message = "[0] expected supertype of type " +
|
||||
to_heap.name() + ", found local.get of type " +
|
||||
std::to_string(to_heap.ref_index()) +
|
||||
", found local.get of type " +
|
||||
test_reps[1].name();
|
||||
ExpectFailure(&test_sig,
|
||||
{WASM_REF_TEST(WASM_HEAP_TYPE(to_heap), WASM_LOCAL_GET(0),
|
||||
@ -4339,13 +4284,13 @@ TEST_F(FunctionBodyDecoderTest, RefTestCast) {
|
||||
// Trivial type error.
|
||||
ExpectFailure(
|
||||
sigs.v_v(),
|
||||
{WASM_REF_TEST(kI31RefCode, WASM_I32V(1), WASM_RTT_CANON(kI31RefCode)),
|
||||
{WASM_REF_TEST(array_heap, WASM_I32V(1), WASM_RTT_CANON(array_heap)),
|
||||
kExprDrop},
|
||||
kAppendEnd,
|
||||
"ref.test[0] expected type anyref, found i32.const of type i32");
|
||||
ExpectFailure(
|
||||
sigs.v_v(),
|
||||
{WASM_REF_CAST(kI31RefCode, WASM_I32V(1), WASM_RTT_CANON(kI31RefCode)),
|
||||
{WASM_REF_CAST(array_heap, WASM_I32V(1), WASM_RTT_CANON(array_heap)),
|
||||
kExprDrop},
|
||||
kAppendEnd,
|
||||
"ref.cast[0] expected type anyref, found i32.const of type i32");
|
||||
@ -4357,20 +4302,34 @@ TEST_F(FunctionBodyDecoderTest, RefTestCast) {
|
||||
ExpectFailure(
|
||||
&sig,
|
||||
{WASM_REF_TEST(static_cast<byte>(array_heap), WASM_LOCAL_GET(0),
|
||||
WASM_RTT_CANON(kI31RefCode)),
|
||||
WASM_RTT_CANON(sub_struct_heap)),
|
||||
kExprDrop},
|
||||
kAppendEnd,
|
||||
"ref.test[1] expected rtt for type 0, found rtt.canon of type (rtt 1 "
|
||||
"i31)");
|
||||
"ref.test[1] expected rtt for type 0, found rtt.canon of type (rtt 0 "
|
||||
"2)");
|
||||
ExpectFailure(
|
||||
&sig,
|
||||
{WASM_REF_CAST(static_cast<byte>(array_heap), WASM_LOCAL_GET(0),
|
||||
WASM_RTT_CANON(kI31RefCode)),
|
||||
WASM_RTT_CANON(sub_struct_heap)),
|
||||
kExprDrop},
|
||||
kAppendEnd,
|
||||
"ref.cast[1] expected rtt for type 0, found rtt.canon of type (rtt 1 "
|
||||
"i31)");
|
||||
"ref.cast[1] expected rtt for type 0, found rtt.canon of type (rtt 0 "
|
||||
"2)");
|
||||
}
|
||||
|
||||
// Trivial type error.
|
||||
ExpectFailure(
|
||||
sigs.v_v(),
|
||||
{WASM_REF_TEST(array_heap, WASM_I32V(1), WASM_RTT_CANON(array_heap)),
|
||||
kExprDrop},
|
||||
kAppendEnd,
|
||||
"ref.test[0] expected type anyref, found i32.const of type i32");
|
||||
ExpectFailure(
|
||||
sigs.v_v(),
|
||||
{WASM_REF_CAST(array_heap, WASM_I32V(1), WASM_RTT_CANON(array_heap)),
|
||||
kExprDrop},
|
||||
kAppendEnd,
|
||||
"ref.cast[0] expected type anyref, found i32.const of type i32");
|
||||
}
|
||||
|
||||
// This tests that num_locals_ in decoder remains consistent, even if we fail
|
||||
|
@ -567,15 +567,16 @@ TEST_F(WasmModuleVerifyTest, GlobalInitializer) {
|
||||
WASM_FEATURE_SCOPE(typed_funcref);
|
||||
WASM_FEATURE_SCOPE(gc);
|
||||
static const byte referencing_undefined_global_nested[] = {
|
||||
SECTION(Global, ENTRY_COUNT(2), // --
|
||||
WASM_RTT(2, kFuncRefCode), // type
|
||||
0, // mutable
|
||||
WASM_RTT_SUB(kFuncRefCode, // init value
|
||||
WASM_GLOBAL_GET(1)), // --
|
||||
kExprEnd, // --
|
||||
WASM_RTT(1, kFuncRefCode), // type
|
||||
0, // mutable
|
||||
WASM_RTT_CANON(kFuncRefCode), kExprEnd) // init value
|
||||
SECTION(Type, ENTRY_COUNT(1), WASM_ARRAY_DEF(kI32Code, true)),
|
||||
SECTION(Global, ENTRY_COUNT(2), // --
|
||||
WASM_RTT(1, 0), // type
|
||||
0, // mutable
|
||||
WASM_RTT_SUB(0, // init value
|
||||
WASM_GLOBAL_GET(1)), // --
|
||||
kExprEnd, // --
|
||||
WASM_RTT(0, 0), // type
|
||||
0, // mutable
|
||||
WASM_RTT_CANON(0), kExprEnd) // init value
|
||||
};
|
||||
EXPECT_FAILURE_WITH_MSG(referencing_undefined_global_nested,
|
||||
"global #1 is not defined yet");
|
||||
@ -788,17 +789,6 @@ TEST_F(WasmModuleVerifyTest, RefNullGlobalInvalid2) {
|
||||
"of type definitions supported by V8");
|
||||
}
|
||||
|
||||
TEST_F(WasmModuleVerifyTest, RttCanonGlobalGeneric) {
|
||||
WASM_FEATURE_SCOPE(reftypes);
|
||||
WASM_FEATURE_SCOPE(typed_funcref);
|
||||
WASM_FEATURE_SCOPE(gc);
|
||||
static const byte data[] = {SECTION(Global, ENTRY_COUNT(1),
|
||||
WASM_RTT(1, kFuncRefCode), 1,
|
||||
WASM_RTT_CANON(kFuncRefCode), kExprEnd)};
|
||||
ModuleResult result = DecodeModule(data, data + sizeof(data));
|
||||
EXPECT_OK(result);
|
||||
}
|
||||
|
||||
TEST_F(WasmModuleVerifyTest, RttCanonGlobalStruct) {
|
||||
WASM_FEATURE_SCOPE(reftypes);
|
||||
WASM_FEATURE_SCOPE(typed_funcref);
|
||||
@ -806,7 +796,7 @@ TEST_F(WasmModuleVerifyTest, RttCanonGlobalStruct) {
|
||||
static const byte data[] = {
|
||||
SECTION(Type, ENTRY_COUNT(1),
|
||||
WASM_STRUCT_DEF(FIELD_COUNT(1), STRUCT_FIELD(kI32Code, true))),
|
||||
SECTION(Global, ENTRY_COUNT(1), WASM_RTT(1, 0), 0, WASM_RTT_CANON(0),
|
||||
SECTION(Global, ENTRY_COUNT(1), WASM_RTT(0, 0), 0, WASM_RTT_CANON(0),
|
||||
kExprEnd)};
|
||||
ModuleResult result = DecodeModule(data, data + sizeof(data));
|
||||
EXPECT_OK(result);
|
||||
@ -816,13 +806,15 @@ TEST_F(WasmModuleVerifyTest, RttCanonGlobalTypeError) {
|
||||
WASM_FEATURE_SCOPE(reftypes);
|
||||
WASM_FEATURE_SCOPE(typed_funcref);
|
||||
WASM_FEATURE_SCOPE(gc);
|
||||
static const byte data[] = {SECTION(Global, ENTRY_COUNT(1),
|
||||
WASM_RTT(1, kExternRefCode), 1,
|
||||
WASM_RTT_CANON(kFuncRefCode), kExprEnd)};
|
||||
static const byte data[] = {
|
||||
SECTION(Type, ENTRY_COUNT(1),
|
||||
WASM_STRUCT_DEF(FIELD_COUNT(1), STRUCT_FIELD(kI32Code, true))),
|
||||
SECTION(Global, ENTRY_COUNT(1), WASM_RTT(1, 0), 1, WASM_RTT_CANON(0),
|
||||
kExprEnd)};
|
||||
ModuleResult result = DecodeModule(data, data + sizeof(data));
|
||||
EXPECT_NOT_OK(result,
|
||||
"type error in init expression, expected (rtt 1 extern), got "
|
||||
"(rtt 1 func)");
|
||||
"type error in init expression, expected (rtt 1 0), got "
|
||||
"(rtt 0 0)");
|
||||
}
|
||||
|
||||
TEST_F(WasmModuleVerifyTest, GlobalRttSubOfCanon) {
|
||||
@ -830,11 +822,14 @@ TEST_F(WasmModuleVerifyTest, GlobalRttSubOfCanon) {
|
||||
WASM_FEATURE_SCOPE(typed_funcref);
|
||||
WASM_FEATURE_SCOPE(gc);
|
||||
static const byte data[] = {
|
||||
SECTION(Global, ENTRY_COUNT(1), WASM_RTT(2, kI31RefCode), 1,
|
||||
WASM_RTT_SUB(kI31RefCode, WASM_RTT_CANON(kEqRefCode)), kExprEnd)};
|
||||
SECTION(Type, ENTRY_COUNT(2),
|
||||
WASM_STRUCT_DEF(FIELD_COUNT(1), STRUCT_FIELD(kI32Code, true)),
|
||||
WASM_STRUCT_DEF(FIELD_COUNT(2), STRUCT_FIELD(kI32Code, true),
|
||||
STRUCT_FIELD(kI32Code, true))),
|
||||
SECTION(Global, ENTRY_COUNT(1), WASM_RTT(1, 1), 1,
|
||||
WASM_RTT_SUB(1, WASM_RTT_CANON(0)), kExprEnd)};
|
||||
ModuleResult result = DecodeModule(data, data + sizeof(data));
|
||||
WasmInitExpr expected = WasmInitExpr::RttSub(
|
||||
HeapType::kI31, WasmInitExpr::RttCanon(HeapType::kEq));
|
||||
WasmInitExpr expected = WasmInitExpr::RttSub(1, WasmInitExpr::RttCanon(0));
|
||||
EXPECT_OK(result);
|
||||
EXPECT_EQ(result.value()->globals.front().init, expected);
|
||||
}
|
||||
@ -843,15 +838,16 @@ TEST_F(WasmModuleVerifyTest, GlobalRttSubOfSubOfCanon) {
|
||||
WASM_FEATURE_SCOPE(reftypes);
|
||||
WASM_FEATURE_SCOPE(typed_funcref);
|
||||
WASM_FEATURE_SCOPE(gc);
|
||||
static const byte data[] = {SECTION(
|
||||
Global, ENTRY_COUNT(1), WASM_RTT(3, kEqRefCode), 1,
|
||||
WASM_RTT_SUB(kEqRefCode,
|
||||
WASM_RTT_SUB(kEqRefCode, WASM_RTT_CANON(kEqRefCode))),
|
||||
kExprEnd)};
|
||||
static const byte data[] = {
|
||||
SECTION(Type, ENTRY_COUNT(2),
|
||||
WASM_STRUCT_DEF(FIELD_COUNT(1), STRUCT_FIELD(kI32Code, true)),
|
||||
WASM_STRUCT_DEF(FIELD_COUNT(2), STRUCT_FIELD(kI32Code, true),
|
||||
STRUCT_FIELD(kI32Code, true))),
|
||||
SECTION(Global, ENTRY_COUNT(1), WASM_RTT(2, 1), 1,
|
||||
WASM_RTT_SUB(1, WASM_RTT_SUB(1, WASM_RTT_CANON(0))), kExprEnd)};
|
||||
ModuleResult result = DecodeModule(data, data + sizeof(data));
|
||||
WasmInitExpr expected = WasmInitExpr::RttSub(
|
||||
HeapType::kEq, WasmInitExpr::RttSub(
|
||||
HeapType::kEq, WasmInitExpr::RttCanon(HeapType::kEq)));
|
||||
1, WasmInitExpr::RttSub(1, WasmInitExpr::RttCanon(0)));
|
||||
EXPECT_OK(result);
|
||||
EXPECT_EQ(result.value()->globals.front().init, expected);
|
||||
}
|
||||
@ -861,18 +857,21 @@ TEST_F(WasmModuleVerifyTest, GlobalRttSubOfGlobal) {
|
||||
WASM_FEATURE_SCOPE(typed_funcref);
|
||||
WASM_FEATURE_SCOPE(gc);
|
||||
static const byte data[] = {
|
||||
SECTION(Import, // section header
|
||||
ENTRY_COUNT(1), // number of imports
|
||||
ADD_COUNT('m'), // module name
|
||||
ADD_COUNT('f'), // global name
|
||||
kExternalGlobal, // import kind
|
||||
WASM_RTT(1, kEqRefCode), // type
|
||||
0), // mutability
|
||||
SECTION(Global, ENTRY_COUNT(1), WASM_RTT(2, kI31RefCode), 1,
|
||||
WASM_RTT_SUB(kI31RefCode, WASM_GLOBAL_GET(0)), kExprEnd)};
|
||||
SECTION(Type, ENTRY_COUNT(2),
|
||||
WASM_STRUCT_DEF(FIELD_COUNT(1), STRUCT_FIELD(kI32Code, true)),
|
||||
WASM_STRUCT_DEF(FIELD_COUNT(2), STRUCT_FIELD(kI32Code, true),
|
||||
STRUCT_FIELD(kI32Code, true))),
|
||||
SECTION(Import, // section header
|
||||
ENTRY_COUNT(1), // number of imports
|
||||
ADD_COUNT('m'), // module name
|
||||
ADD_COUNT('f'), // global name
|
||||
kExternalGlobal, // import kind
|
||||
WASM_RTT(0, 0), // type
|
||||
0), // mutability
|
||||
SECTION(Global, ENTRY_COUNT(1), WASM_RTT(1, 1), 1,
|
||||
WASM_RTT_SUB(1, WASM_GLOBAL_GET(0)), kExprEnd)};
|
||||
ModuleResult result = DecodeModule(data, data + sizeof(data));
|
||||
WasmInitExpr expected =
|
||||
WasmInitExpr::RttSub(HeapType::kI31, WasmInitExpr::GlobalGet(0));
|
||||
WasmInitExpr expected = WasmInitExpr::RttSub(1, WasmInitExpr::GlobalGet(0));
|
||||
EXPECT_OK(result);
|
||||
EXPECT_EQ(result.value()->globals[1].init, expected);
|
||||
}
|
||||
@ -882,6 +881,8 @@ TEST_F(WasmModuleVerifyTest, GlobalRttSubOfGlobalTypeError) {
|
||||
WASM_FEATURE_SCOPE(typed_funcref);
|
||||
WASM_FEATURE_SCOPE(gc);
|
||||
static const byte data[] = {
|
||||
SECTION(Type, ENTRY_COUNT(1),
|
||||
WASM_STRUCT_DEF(FIELD_COUNT(1), STRUCT_FIELD(kI32Code, true))),
|
||||
SECTION(Import, // section header
|
||||
ENTRY_COUNT(1), // number of imports
|
||||
ADD_COUNT('m'), // module name
|
||||
@ -889,8 +890,8 @@ TEST_F(WasmModuleVerifyTest, GlobalRttSubOfGlobalTypeError) {
|
||||
kExternalGlobal, // import kind
|
||||
kI32Code, // type
|
||||
0), // mutability
|
||||
SECTION(Global, ENTRY_COUNT(1), WASM_RTT(2, kExternRefCode), 1,
|
||||
WASM_RTT_SUB(kExternRefCode, WASM_GLOBAL_GET(0)), kExprEnd)};
|
||||
SECTION(Global, ENTRY_COUNT(1), WASM_RTT(1, 0), 1,
|
||||
WASM_RTT_SUB(0, WASM_GLOBAL_GET(0)), kExprEnd)};
|
||||
ModuleResult result = DecodeModule(data, data + sizeof(data));
|
||||
EXPECT_NOT_OK(result, "rtt.sub requires a supertype rtt on stack");
|
||||
}
|
||||
@ -899,9 +900,12 @@ TEST_F(WasmModuleVerifyTest, GlobalRttSubIllegalParent) {
|
||||
WASM_FEATURE_SCOPE(reftypes);
|
||||
WASM_FEATURE_SCOPE(typed_funcref);
|
||||
WASM_FEATURE_SCOPE(gc);
|
||||
static const byte data[] = {SECTION(
|
||||
Global, ENTRY_COUNT(1), WASM_RTT(2, kEqRefCode), 1,
|
||||
WASM_RTT_SUB(kEqRefCode, WASM_RTT_CANON(kExternRefCode)), kExprEnd)};
|
||||
static const byte data[] = {
|
||||
SECTION(Type, ENTRY_COUNT(2),
|
||||
WASM_STRUCT_DEF(FIELD_COUNT(1), STRUCT_FIELD(kI32Code, true)),
|
||||
WASM_STRUCT_DEF(FIELD_COUNT(1), STRUCT_FIELD(kF32Code, true))),
|
||||
SECTION(Global, ENTRY_COUNT(1), WASM_RTT(1, 1), 1,
|
||||
WASM_RTT_SUB(1, WASM_RTT_CANON(0)), kExprEnd)};
|
||||
ModuleResult result = DecodeModule(data, data + sizeof(data));
|
||||
EXPECT_NOT_OK(result, "rtt.sub requires a supertype rtt on stack");
|
||||
}
|
||||
@ -910,13 +914,15 @@ TEST_F(WasmModuleVerifyTest, RttSubGlobalTypeError) {
|
||||
WASM_FEATURE_SCOPE(reftypes);
|
||||
WASM_FEATURE_SCOPE(typed_funcref);
|
||||
WASM_FEATURE_SCOPE(gc);
|
||||
static const byte data[] = {SECTION(
|
||||
Global, ENTRY_COUNT(1), WASM_RTT(1 /* Should be 2 */, kI31RefCode), 1,
|
||||
WASM_RTT_SUB(kI31RefCode, WASM_RTT_CANON(kEqRefCode)), kExprEnd)};
|
||||
static const byte data[] = {
|
||||
SECTION(Type, ENTRY_COUNT(1),
|
||||
WASM_STRUCT_DEF(FIELD_COUNT(1), STRUCT_FIELD(kI32Code, true))),
|
||||
SECTION(Global, ENTRY_COUNT(1), WASM_RTT(0, 0), 1,
|
||||
WASM_RTT_SUB(0, WASM_RTT_CANON(0)), kExprEnd)};
|
||||
ModuleResult result = DecodeModule(data, data + sizeof(data));
|
||||
EXPECT_NOT_OK(result,
|
||||
"type error in init expression, expected (rtt 1 i31), got "
|
||||
"(rtt 2 i31)");
|
||||
"type error in init expression, expected (rtt 0 0), got "
|
||||
"(rtt 1 0)");
|
||||
}
|
||||
|
||||
TEST_F(WasmModuleVerifyTest, EmptyStruct) {
|
||||
@ -1976,7 +1982,7 @@ TEST_F(WasmModuleVerifyTest, IllegalTableTypes) {
|
||||
{kOptRefCode, 1},
|
||||
{kOptRefCode, kI31RefCode},
|
||||
{kI31RefCode},
|
||||
{kRttCode, 2, kFuncRefCode}};
|
||||
{kRttCode, 2, 0}};
|
||||
|
||||
for (Vec type : table_types) {
|
||||
Vec data = {
|
||||
|
@ -383,11 +383,6 @@ KNOWN_MAPS = {
|
||||
("read_only_space", 0x05d4d): (78, "StoreHandler3Map"),
|
||||
("map_space", 0x02119): (1057, "ExternalMap"),
|
||||
("map_space", 0x02141): (1098, "JSMessageObjectMap"),
|
||||
("map_space", 0x02169): (181, "WasmRttEqrefMap"),
|
||||
("map_space", 0x02191): (181, "WasmRttAnyrefMap"),
|
||||
("map_space", 0x021b9): (181, "WasmRttExternrefMap"),
|
||||
("map_space", 0x021e1): (181, "WasmRttFuncrefMap"),
|
||||
("map_space", 0x02209): (181, "WasmRttI31refMap"),
|
||||
}
|
||||
|
||||
# List of known V8 objects.
|
||||
@ -448,49 +443,49 @@ KNOWN_OBJECTS = {
|
||||
("old_space", 0x0237d): "FunctionPrototypeAccessor",
|
||||
("old_space", 0x023c1): "StringLengthAccessor",
|
||||
("old_space", 0x02405): "InvalidPrototypeValidityCell",
|
||||
("old_space", 0x024f1): "EmptyScript",
|
||||
("old_space", 0x02531): "ManyClosuresCell",
|
||||
("old_space", 0x0253d): "ArrayConstructorProtector",
|
||||
("old_space", 0x02551): "NoElementsProtector",
|
||||
("old_space", 0x02565): "IsConcatSpreadableProtector",
|
||||
("old_space", 0x02579): "ArraySpeciesProtector",
|
||||
("old_space", 0x0258d): "TypedArraySpeciesProtector",
|
||||
("old_space", 0x025a1): "PromiseSpeciesProtector",
|
||||
("old_space", 0x025b5): "RegExpSpeciesProtector",
|
||||
("old_space", 0x025c9): "StringLengthProtector",
|
||||
("old_space", 0x025dd): "ArrayIteratorProtector",
|
||||
("old_space", 0x025f1): "ArrayBufferDetachingProtector",
|
||||
("old_space", 0x02605): "PromiseHookProtector",
|
||||
("old_space", 0x02619): "PromiseResolveProtector",
|
||||
("old_space", 0x0262d): "MapIteratorProtector",
|
||||
("old_space", 0x02641): "PromiseThenProtector",
|
||||
("old_space", 0x02655): "SetIteratorProtector",
|
||||
("old_space", 0x02669): "StringIteratorProtector",
|
||||
("old_space", 0x0267d): "SingleCharacterStringCache",
|
||||
("old_space", 0x02a85): "StringSplitCache",
|
||||
("old_space", 0x02e8d): "RegExpMultipleCache",
|
||||
("old_space", 0x03295): "BuiltinsConstantsTable",
|
||||
("old_space", 0x0368d): "AsyncFunctionAwaitRejectSharedFun",
|
||||
("old_space", 0x036b1): "AsyncFunctionAwaitResolveSharedFun",
|
||||
("old_space", 0x036d5): "AsyncGeneratorAwaitRejectSharedFun",
|
||||
("old_space", 0x036f9): "AsyncGeneratorAwaitResolveSharedFun",
|
||||
("old_space", 0x0371d): "AsyncGeneratorYieldResolveSharedFun",
|
||||
("old_space", 0x03741): "AsyncGeneratorReturnResolveSharedFun",
|
||||
("old_space", 0x03765): "AsyncGeneratorReturnClosedRejectSharedFun",
|
||||
("old_space", 0x03789): "AsyncGeneratorReturnClosedResolveSharedFun",
|
||||
("old_space", 0x037ad): "AsyncIteratorValueUnwrapSharedFun",
|
||||
("old_space", 0x037d1): "PromiseAllResolveElementSharedFun",
|
||||
("old_space", 0x037f5): "PromiseAllSettledResolveElementSharedFun",
|
||||
("old_space", 0x03819): "PromiseAllSettledRejectElementSharedFun",
|
||||
("old_space", 0x0383d): "PromiseAnyRejectElementSharedFun",
|
||||
("old_space", 0x03861): "PromiseCapabilityDefaultRejectSharedFun",
|
||||
("old_space", 0x03885): "PromiseCapabilityDefaultResolveSharedFun",
|
||||
("old_space", 0x038a9): "PromiseCatchFinallySharedFun",
|
||||
("old_space", 0x038cd): "PromiseGetCapabilitiesExecutorSharedFun",
|
||||
("old_space", 0x038f1): "PromiseThenFinallySharedFun",
|
||||
("old_space", 0x03915): "PromiseThrowerFinallySharedFun",
|
||||
("old_space", 0x03939): "PromiseValueThunkFinallySharedFun",
|
||||
("old_space", 0x0395d): "ProxyRevokeSharedFun",
|
||||
("old_space", 0x0240d): "EmptyScript",
|
||||
("old_space", 0x0244d): "ManyClosuresCell",
|
||||
("old_space", 0x02459): "ArrayConstructorProtector",
|
||||
("old_space", 0x0246d): "NoElementsProtector",
|
||||
("old_space", 0x02481): "IsConcatSpreadableProtector",
|
||||
("old_space", 0x02495): "ArraySpeciesProtector",
|
||||
("old_space", 0x024a9): "TypedArraySpeciesProtector",
|
||||
("old_space", 0x024bd): "PromiseSpeciesProtector",
|
||||
("old_space", 0x024d1): "RegExpSpeciesProtector",
|
||||
("old_space", 0x024e5): "StringLengthProtector",
|
||||
("old_space", 0x024f9): "ArrayIteratorProtector",
|
||||
("old_space", 0x0250d): "ArrayBufferDetachingProtector",
|
||||
("old_space", 0x02521): "PromiseHookProtector",
|
||||
("old_space", 0x02535): "PromiseResolveProtector",
|
||||
("old_space", 0x02549): "MapIteratorProtector",
|
||||
("old_space", 0x0255d): "PromiseThenProtector",
|
||||
("old_space", 0x02571): "SetIteratorProtector",
|
||||
("old_space", 0x02585): "StringIteratorProtector",
|
||||
("old_space", 0x02599): "SingleCharacterStringCache",
|
||||
("old_space", 0x029a1): "StringSplitCache",
|
||||
("old_space", 0x02da9): "RegExpMultipleCache",
|
||||
("old_space", 0x031b1): "BuiltinsConstantsTable",
|
||||
("old_space", 0x035a9): "AsyncFunctionAwaitRejectSharedFun",
|
||||
("old_space", 0x035cd): "AsyncFunctionAwaitResolveSharedFun",
|
||||
("old_space", 0x035f1): "AsyncGeneratorAwaitRejectSharedFun",
|
||||
("old_space", 0x03615): "AsyncGeneratorAwaitResolveSharedFun",
|
||||
("old_space", 0x03639): "AsyncGeneratorYieldResolveSharedFun",
|
||||
("old_space", 0x0365d): "AsyncGeneratorReturnResolveSharedFun",
|
||||
("old_space", 0x03681): "AsyncGeneratorReturnClosedRejectSharedFun",
|
||||
("old_space", 0x036a5): "AsyncGeneratorReturnClosedResolveSharedFun",
|
||||
("old_space", 0x036c9): "AsyncIteratorValueUnwrapSharedFun",
|
||||
("old_space", 0x036ed): "PromiseAllResolveElementSharedFun",
|
||||
("old_space", 0x03711): "PromiseAllSettledResolveElementSharedFun",
|
||||
("old_space", 0x03735): "PromiseAllSettledRejectElementSharedFun",
|
||||
("old_space", 0x03759): "PromiseAnyRejectElementSharedFun",
|
||||
("old_space", 0x0377d): "PromiseCapabilityDefaultRejectSharedFun",
|
||||
("old_space", 0x037a1): "PromiseCapabilityDefaultResolveSharedFun",
|
||||
("old_space", 0x037c5): "PromiseCatchFinallySharedFun",
|
||||
("old_space", 0x037e9): "PromiseGetCapabilitiesExecutorSharedFun",
|
||||
("old_space", 0x0380d): "PromiseThenFinallySharedFun",
|
||||
("old_space", 0x03831): "PromiseThrowerFinallySharedFun",
|
||||
("old_space", 0x03855): "PromiseValueThunkFinallySharedFun",
|
||||
("old_space", 0x03879): "ProxyRevokeSharedFun",
|
||||
}
|
||||
|
||||
# Lower 32 bits of first page addresses for various heap spaces.
|
||||
|
Loading…
Reference in New Issue
Block a user