[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:
Manos Koukoutos 2021-01-26 13:01:41 +00:00 committed by Commit Bot
parent 4adf55a004
commit b77deeca4b
24 changed files with 410 additions and 794 deletions

View File

@ -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);
}

View File

@ -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);

View File

@ -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";
}

View File

@ -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;

View File

@ -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(

View File

@ -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(

View File

@ -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);
}

View File

@ -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) \

View File

@ -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);

View File

@ -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,

View File

@ -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;
}

View File

@ -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: {

View File

@ -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,

View File

@ -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();

View File

@ -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;
}
}

View File

@ -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);

View File

@ -106,7 +106,6 @@ extern class AsmWasmData extends Struct {
@generateCppClass
extern class WasmTypeInfo extends Foreign {
parent: Map;
supertypes: FixedArray;
subtypes: ArrayList;
}

View File

@ -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();
}
}

View File

@ -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());

View File

@ -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).

View File

@ -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;

View File

@ -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

View File

@ -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 = {

View File

@ -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.