[wasm-gc] Implement optional-depth rtts
As per the latest wasm-gc spec, rtts now have optional depth, with (rtt n type) <: (rtt type) for every depth n. Liftoff compilation for type checks without depth are not supported yet. Bug: v8:7748 Change-Id: I4971875e6a42db6d333b61ca5e2996e875f39f60 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2649043 Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Commit-Queue: Manos Koukoutos <manoskouk@chromium.org> Cr-Commit-Position: refs/heads/master@{#72395}
This commit is contained in:
parent
7cc78c535d
commit
3a2ae154f9
@ -2321,6 +2321,7 @@ Node* WasmGraphBuilder::Throw(uint32_t exception_index,
|
||||
++index;
|
||||
break;
|
||||
case wasm::ValueType::kRtt: // TODO(7748): Implement.
|
||||
case wasm::ValueType::kRttWithDepth:
|
||||
case wasm::ValueType::kI8:
|
||||
case wasm::ValueType::kI16:
|
||||
case wasm::ValueType::kStmt:
|
||||
@ -2469,6 +2470,7 @@ Node* WasmGraphBuilder::GetExceptionValues(Node* except_obj,
|
||||
++index;
|
||||
break;
|
||||
case wasm::ValueType::kRtt: // TODO(7748): Implement.
|
||||
case wasm::ValueType::kRttWithDepth:
|
||||
case wasm::ValueType::kI8:
|
||||
case wasm::ValueType::kI16:
|
||||
case wasm::ValueType::kStmt:
|
||||
@ -5837,12 +5839,16 @@ void WasmGraphBuilder::TypeCheck(
|
||||
}
|
||||
Node* type_info = gasm_->LoadWasmTypeInfo(map);
|
||||
Node* supertypes = gasm_->LoadSupertypes(type_info);
|
||||
Node* length =
|
||||
Node* supertypes_length =
|
||||
BuildChangeSmiToInt32(gasm_->LoadFixedArrayLengthAsSmi(supertypes));
|
||||
callbacks.fail_if_not(
|
||||
gasm_->Uint32LessThan(gasm_->Int32Constant(config.rtt_depth), length));
|
||||
Node* rtt_depth =
|
||||
config.rtt_depth >= 0
|
||||
? gasm_->Int32Constant(config.rtt_depth)
|
||||
: BuildChangeSmiToInt32(gasm_->LoadFixedArrayLengthAsSmi(
|
||||
gasm_->LoadSupertypes(gasm_->LoadWasmTypeInfo(rtt))));
|
||||
callbacks.fail_if_not(gasm_->Uint32LessThan(rtt_depth, supertypes_length));
|
||||
Node* maybe_match = gasm_->LoadFixedArrayElement(
|
||||
supertypes, config.rtt_depth, MachineType::TaggedPointer());
|
||||
supertypes, rtt_depth, MachineType::TaggedPointer());
|
||||
|
||||
callbacks.fail_if_not(gasm_->TaggedEqual(maybe_match, rtt));
|
||||
}
|
||||
@ -6261,6 +6267,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
|
||||
UNREACHABLE();
|
||||
}
|
||||
case wasm::ValueType::kRtt:
|
||||
case wasm::ValueType::kRttWithDepth:
|
||||
// TODO(7748): Figure out what to do for RTTs.
|
||||
UNIMPLEMENTED();
|
||||
case wasm::ValueType::kI8:
|
||||
@ -6414,6 +6421,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
|
||||
return BuildChangeBigIntToInt64(input, js_context);
|
||||
|
||||
case wasm::ValueType::kRtt: // TODO(7748): Implement.
|
||||
case wasm::ValueType::kRttWithDepth:
|
||||
case wasm::ValueType::kS128:
|
||||
case wasm::ValueType::kI8:
|
||||
case wasm::ValueType::kI16:
|
||||
@ -6470,6 +6478,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
|
||||
case wasm::ValueType::kOptRef:
|
||||
case wasm::ValueType::kI64:
|
||||
case wasm::ValueType::kRtt:
|
||||
case wasm::ValueType::kRttWithDepth:
|
||||
case wasm::ValueType::kS128:
|
||||
case wasm::ValueType::kI8:
|
||||
case wasm::ValueType::kI16:
|
||||
@ -6609,6 +6618,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
|
||||
case wasm::ValueType::kOptRef:
|
||||
case wasm::ValueType::kI64:
|
||||
case wasm::ValueType::kRtt:
|
||||
case wasm::ValueType::kRttWithDepth:
|
||||
case wasm::ValueType::kS128:
|
||||
case wasm::ValueType::kI8:
|
||||
case wasm::ValueType::kI16:
|
||||
@ -6659,6 +6669,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
|
||||
case wasm::ValueType::kOptRef:
|
||||
case wasm::ValueType::kI64:
|
||||
case wasm::ValueType::kRtt:
|
||||
case wasm::ValueType::kRttWithDepth:
|
||||
case wasm::ValueType::kS128:
|
||||
case wasm::ValueType::kI8:
|
||||
case wasm::ValueType::kI16:
|
||||
|
@ -169,7 +169,7 @@ class WasmGraphBuilder {
|
||||
bool object_can_be_null;
|
||||
bool object_must_be_data_ref;
|
||||
bool object_can_be_i31;
|
||||
uint8_t rtt_depth;
|
||||
int8_t rtt_depth;
|
||||
};
|
||||
enum EnforceBoundsCheck : bool { // --
|
||||
kNeedsBoundsCheck = true,
|
||||
|
@ -1750,6 +1750,7 @@ void WasmStruct::WasmStructPrint(std::ostream& os) { // NOLINT
|
||||
case wasm::ValueType::kRef:
|
||||
case wasm::ValueType::kOptRef:
|
||||
case wasm::ValueType::kRtt:
|
||||
case wasm::ValueType::kRttWithDepth:
|
||||
case wasm::ValueType::kBottom:
|
||||
case wasm::ValueType::kStmt:
|
||||
os << "UNIMPLEMENTED"; // TODO(7748): Implement.
|
||||
@ -1789,6 +1790,7 @@ void WasmArray::WasmArrayPrint(std::ostream& os) { // NOLINT
|
||||
case wasm::ValueType::kRef:
|
||||
case wasm::ValueType::kOptRef:
|
||||
case wasm::ValueType::kRtt:
|
||||
case wasm::ValueType::kRttWithDepth:
|
||||
case wasm::ValueType::kBottom:
|
||||
case wasm::ValueType::kStmt:
|
||||
os << "\n Printing elements of this type is unimplemented, sorry";
|
||||
|
@ -304,6 +304,7 @@ inline void Store(LiftoffAssembler* assm, LiftoffRegister src, MemOperand dst,
|
||||
case ValueType::kOptRef:
|
||||
case ValueType::kRef:
|
||||
case ValueType::kRtt:
|
||||
case ValueType::kRttWithDepth:
|
||||
assm->str(src.gp(), dst);
|
||||
break;
|
||||
case ValueType::kI64:
|
||||
@ -338,6 +339,7 @@ inline void Load(LiftoffAssembler* assm, LiftoffRegister dst, MemOperand src,
|
||||
case ValueType::kOptRef:
|
||||
case ValueType::kRef:
|
||||
case ValueType::kRtt:
|
||||
case ValueType::kRttWithDepth:
|
||||
assm->ldr(dst.gp(), src);
|
||||
break;
|
||||
case ValueType::kI64:
|
||||
|
@ -80,6 +80,7 @@ inline CPURegister GetRegFromType(const LiftoffRegister& reg, ValueType type) {
|
||||
case ValueType::kRef:
|
||||
case ValueType::kOptRef:
|
||||
case ValueType::kRtt:
|
||||
case ValueType::kRttWithDepth:
|
||||
return reg.gp().X();
|
||||
case ValueType::kF32:
|
||||
return reg.fp().S();
|
||||
@ -1503,6 +1504,7 @@ void LiftoffAssembler::emit_cond_jump(LiftoffCondition liftoff_cond,
|
||||
case ValueType::kRef:
|
||||
case ValueType::kOptRef:
|
||||
case ValueType::kRtt:
|
||||
case ValueType::kRttWithDepth:
|
||||
DCHECK(rhs.is_valid());
|
||||
DCHECK(liftoff_cond == kEqual || liftoff_cond == kUnequal);
|
||||
V8_FALLTHROUGH;
|
||||
|
@ -72,6 +72,7 @@ inline void Load(LiftoffAssembler* assm, LiftoffRegister dst, Register base,
|
||||
case ValueType::kOptRef:
|
||||
case ValueType::kRef:
|
||||
case ValueType::kRtt:
|
||||
case ValueType::kRttWithDepth:
|
||||
assm->mov(dst.gp(), src);
|
||||
break;
|
||||
case ValueType::kI64:
|
||||
@ -1130,6 +1131,7 @@ void LiftoffAssembler::Spill(int offset, LiftoffRegister reg, ValueType type) {
|
||||
case ValueType::kOptRef:
|
||||
case ValueType::kRef:
|
||||
case ValueType::kRtt:
|
||||
case ValueType::kRttWithDepth:
|
||||
mov(dst, reg.gp());
|
||||
break;
|
||||
case ValueType::kI64:
|
||||
@ -2394,6 +2396,7 @@ void LiftoffAssembler::emit_cond_jump(LiftoffCondition liftoff_cond,
|
||||
case ValueType::kRef:
|
||||
case ValueType::kOptRef:
|
||||
case ValueType::kRtt:
|
||||
case ValueType::kRttWithDepth:
|
||||
DCHECK(liftoff_cond == kEqual || liftoff_cond == kUnequal);
|
||||
V8_FALLTHROUGH;
|
||||
case ValueType::kI32:
|
||||
|
@ -494,6 +494,7 @@ class LiftoffCompiler {
|
||||
case ValueType::kRef:
|
||||
case ValueType::kOptRef:
|
||||
case ValueType::kRtt:
|
||||
case ValueType::kRttWithDepth:
|
||||
case ValueType::kI8:
|
||||
case ValueType::kI16:
|
||||
if (FLAG_experimental_liftoff_extern_ref) return true;
|
||||
@ -4452,8 +4453,13 @@ class LiftoffCompiler {
|
||||
// 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());
|
||||
if (rtt.type.has_depth()) {
|
||||
__ emit_i32_cond_jumpi(kUnsignedLessEqual, no_match, list_length.gp(),
|
||||
rtt.type.depth());
|
||||
} else {
|
||||
unsupported(decoder, kGC, "rtt without depth");
|
||||
}
|
||||
|
||||
// Step 4: load the candidate list slot into {tmp1}, and compare it.
|
||||
__ LoadTaggedPointer(
|
||||
tmp1.gp(), tmp1.gp(), no_reg,
|
||||
@ -5011,6 +5017,7 @@ class LiftoffCompiler {
|
||||
case ValueType::kOptRef:
|
||||
return LoadNullValue(reg.gp(), pinned);
|
||||
case ValueType::kRtt:
|
||||
case ValueType::kRttWithDepth:
|
||||
case ValueType::kStmt:
|
||||
case ValueType::kBottom:
|
||||
case ValueType::kRef:
|
||||
|
@ -69,6 +69,7 @@ static inline constexpr RegClass reg_class_for(ValueType::Kind kind) {
|
||||
case ValueType::kRef:
|
||||
case ValueType::kOptRef:
|
||||
case ValueType::kRtt:
|
||||
case ValueType::kRttWithDepth:
|
||||
return kGpReg;
|
||||
default:
|
||||
return kNoReg; // unsupported type
|
||||
|
@ -91,6 +91,7 @@ inline void Load(LiftoffAssembler* assm, LiftoffRegister dst, Register base,
|
||||
case ValueType::kRef:
|
||||
case ValueType::kOptRef:
|
||||
case ValueType::kRtt:
|
||||
case ValueType::kRttWithDepth:
|
||||
assm->lw(dst.gp(), src);
|
||||
break;
|
||||
case ValueType::kI64:
|
||||
@ -118,6 +119,7 @@ inline void Store(LiftoffAssembler* assm, Register base, int32_t offset,
|
||||
case ValueType::kOptRef:
|
||||
case ValueType::kRef:
|
||||
case ValueType::kRtt:
|
||||
case ValueType::kRttWithDepth:
|
||||
assm->Usw(src.gp(), dst);
|
||||
break;
|
||||
case ValueType::kI64:
|
||||
@ -722,6 +724,7 @@ void LiftoffAssembler::Spill(int offset, LiftoffRegister reg, ValueType type) {
|
||||
case ValueType::kRef:
|
||||
case ValueType::kOptRef:
|
||||
case ValueType::kRtt:
|
||||
case ValueType::kRttWithDepth:
|
||||
sw(reg.gp(), dst);
|
||||
break;
|
||||
case ValueType::kI64:
|
||||
|
@ -102,6 +102,7 @@ inline void Load(LiftoffAssembler* assm, LiftoffRegister dst, MemOperand src,
|
||||
case ValueType::kRef:
|
||||
case ValueType::kOptRef:
|
||||
case ValueType::kRtt:
|
||||
case ValueType::kRttWithDepth:
|
||||
assm->Ld(dst.gp(), src);
|
||||
break;
|
||||
case ValueType::kF32:
|
||||
@ -129,6 +130,7 @@ inline void Store(LiftoffAssembler* assm, Register base, int32_t offset,
|
||||
case ValueType::kOptRef:
|
||||
case ValueType::kRef:
|
||||
case ValueType::kRtt:
|
||||
case ValueType::kRttWithDepth:
|
||||
assm->Usd(src.gp(), dst);
|
||||
break;
|
||||
case ValueType::kF32:
|
||||
@ -661,6 +663,7 @@ void LiftoffAssembler::Spill(int offset, LiftoffRegister reg, ValueType type) {
|
||||
case ValueType::kRef:
|
||||
case ValueType::kOptRef:
|
||||
case ValueType::kRtt:
|
||||
case ValueType::kRttWithDepth:
|
||||
Sd(reg.gp(), dst);
|
||||
break;
|
||||
case ValueType::kF32:
|
||||
|
@ -93,6 +93,7 @@ inline void Load(LiftoffAssembler* assm, LiftoffRegister dst, Operand src,
|
||||
case ValueType::kOptRef:
|
||||
case ValueType::kRef:
|
||||
case ValueType::kRtt:
|
||||
case ValueType::kRttWithDepth:
|
||||
assm->movq(dst.gp(), src);
|
||||
break;
|
||||
case ValueType::kF32:
|
||||
@ -828,6 +829,7 @@ void LiftoffAssembler::Spill(int offset, LiftoffRegister reg, ValueType type) {
|
||||
case ValueType::kOptRef:
|
||||
case ValueType::kRef:
|
||||
case ValueType::kRtt:
|
||||
case ValueType::kRttWithDepth:
|
||||
movq(dst, reg.gp());
|
||||
break;
|
||||
case ValueType::kF32:
|
||||
@ -2043,6 +2045,7 @@ void LiftoffAssembler::emit_cond_jump(LiftoffCondition liftoff_cond,
|
||||
case ValueType::kRef:
|
||||
case ValueType::kOptRef:
|
||||
case ValueType::kRtt:
|
||||
case ValueType::kRttWithDepth:
|
||||
DCHECK(liftoff_cond == kEqual || liftoff_cond == kUnequal);
|
||||
V8_FALLTHROUGH;
|
||||
case ValueType::kI64:
|
||||
|
@ -1420,6 +1420,7 @@ void PushArgs(const i::wasm::FunctionSig* sig, const Val args[],
|
||||
packer->Push(WasmRefToV8(store->i_isolate(), args[i].ref())->ptr());
|
||||
break;
|
||||
case i::wasm::ValueType::kRtt:
|
||||
case i::wasm::ValueType::kRttWithDepth:
|
||||
case i::wasm::ValueType::kS128:
|
||||
// TODO(7748): Implement.
|
||||
UNIMPLEMENTED();
|
||||
@ -1460,6 +1461,7 @@ void PopArgs(const i::wasm::FunctionSig* sig, Val results[],
|
||||
break;
|
||||
}
|
||||
case i::wasm::ValueType::kRtt:
|
||||
case i::wasm::ValueType::kRttWithDepth:
|
||||
case i::wasm::ValueType::kS128:
|
||||
// TODO(7748): Implement.
|
||||
UNIMPLEMENTED();
|
||||
@ -1724,6 +1726,7 @@ auto Global::get() const -> Val {
|
||||
return Val(V8RefValueToWasm(store, v8_global->GetRef()));
|
||||
}
|
||||
case i::wasm::ValueType::kRtt:
|
||||
case i::wasm::ValueType::kRttWithDepth:
|
||||
case i::wasm::ValueType::kS128:
|
||||
// TODO(7748): Implement these.
|
||||
UNIMPLEMENTED();
|
||||
|
@ -317,7 +317,7 @@ ValueType read_value_type(Decoder* decoder, const byte* pc,
|
||||
return heap_type.is_bottom() ? kWasmBottom
|
||||
: ValueType::Ref(heap_type, nullability);
|
||||
}
|
||||
case kRttCode: {
|
||||
case kRttWithDepthCode: {
|
||||
if (!VALIDATE(enabled.has_gc())) {
|
||||
DecodeError<validate>(
|
||||
decoder, pc,
|
||||
@ -355,6 +355,32 @@ ValueType read_value_type(Decoder* decoder, const byte* pc,
|
||||
}
|
||||
return ValueType::Rtt(type_index, depth);
|
||||
}
|
||||
case kRttCode: {
|
||||
if (!VALIDATE(enabled.has_gc())) {
|
||||
DecodeError<validate>(
|
||||
decoder, pc,
|
||||
"invalid value type 'rtt', enable with --experimental-wasm-gc");
|
||||
return kWasmBottom;
|
||||
}
|
||||
uint32_t type_index = decoder->read_u32v<validate>(pc + 1, length);
|
||||
*length += 1;
|
||||
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);
|
||||
}
|
||||
case kS128Code: {
|
||||
if (!VALIDATE(enabled.has_simd())) {
|
||||
DecodeError<validate>(
|
||||
@ -3797,8 +3823,9 @@ 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.ref_index() == imm.index)) {
|
||||
if (!VALIDATE(
|
||||
rtt.type.is_bottom() ||
|
||||
(rtt.type.ref_index() == imm.index && rtt.type.has_depth()))) {
|
||||
PopTypeError(imm.struct_type->field_count(), rtt,
|
||||
"rtt for type " + std::to_string(imm.index));
|
||||
return 0;
|
||||
@ -3831,8 +3858,9 @@ 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.ref_index() == imm.index)) {
|
||||
if (!VALIDATE(
|
||||
rtt.type.is_bottom() ||
|
||||
(rtt.type.ref_index() == imm.index && rtt.type.has_depth()))) {
|
||||
PopTypeError(0, rtt, "rtt for type " + std::to_string(imm.index));
|
||||
return 0;
|
||||
}
|
||||
@ -3904,8 +3932,9 @@ 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.ref_index() == imm.index)) {
|
||||
if (!VALIDATE(
|
||||
rtt.type.is_bottom() ||
|
||||
(rtt.type.ref_index() == imm.index && rtt.type.has_depth()))) {
|
||||
PopTypeError(2, rtt, "rtt for type " + std::to_string(imm.index));
|
||||
return 0;
|
||||
}
|
||||
@ -3933,8 +3962,9 @@ 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.ref_index() == imm.index)) {
|
||||
if (!VALIDATE(
|
||||
rtt.type.is_bottom() ||
|
||||
(rtt.type.ref_index() == imm.index && rtt.type.has_depth()))) {
|
||||
PopTypeError(1, rtt, "rtt for type " + std::to_string(imm.index));
|
||||
return 0;
|
||||
}
|
||||
|
@ -990,7 +990,7 @@ 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_depth = rtt_type.depth();
|
||||
result.rtt_depth = rtt_type.has_depth() ? rtt_type.depth() : -1;
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1142,6 +1142,7 @@ class WasmGraphBuildingInterface {
|
||||
case ValueType::kOptRef:
|
||||
return builder_->RefNull();
|
||||
case ValueType::kRtt:
|
||||
case ValueType::kRttWithDepth:
|
||||
case ValueType::kStmt:
|
||||
case ValueType::kBottom:
|
||||
case ValueType::kRef:
|
||||
|
@ -41,6 +41,9 @@ size_t LocalDeclEncoder::Emit(byte* buffer) const {
|
||||
*pos = locals_type.depth();
|
||||
++pos;
|
||||
}
|
||||
if (locals_type.is_rtt()) {
|
||||
LEBHelper::write_u32v(&pos, locals_type.ref_index());
|
||||
}
|
||||
if (locals_type.encoding_needs_heap_type()) {
|
||||
LEBHelper::write_i32v(&pos, locals_type.heap_type().code());
|
||||
}
|
||||
@ -66,12 +69,14 @@ uint32_t LocalDeclEncoder::AddLocals(uint32_t count, ValueType type) {
|
||||
size_t LocalDeclEncoder::Size() const {
|
||||
size_t size = LEBHelper::sizeof_u32v(local_decls.size());
|
||||
for (auto p : local_decls) {
|
||||
size += LEBHelper::sizeof_u32v(p.first) + // number of locals
|
||||
1 + // Opcode
|
||||
(p.second.has_depth() ? 1 : 0) + // Inheritance depth
|
||||
(p.second.encoding_needs_heap_type()
|
||||
? LEBHelper::sizeof_i32v(p.second.heap_type().code())
|
||||
: 0); // ref. index
|
||||
size +=
|
||||
LEBHelper::sizeof_u32v(p.first) + // number of locals
|
||||
1 + // Opcode
|
||||
(p.second.has_depth() ? 1 : 0) + // Inheritance depth
|
||||
(p.second.encoding_needs_heap_type()
|
||||
? LEBHelper::sizeof_i32v(p.second.heap_type().code())
|
||||
: 0) +
|
||||
(p.second.is_rtt() ? LEBHelper::sizeof_u32v(p.second.ref_index()) : 0);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
@ -912,6 +912,7 @@ void InstanceBuilder::WriteGlobalValue(const WasmGlobal& global,
|
||||
break;
|
||||
}
|
||||
case ValueType::kRtt:
|
||||
case ValueType::kRttWithDepth:
|
||||
case ValueType::kRef:
|
||||
case ValueType::kOptRef: {
|
||||
tagged_globals_->set(global.offset, *value->GetRef());
|
||||
|
@ -35,12 +35,13 @@ class Simd128;
|
||||
V(I8, 0, I8, Int8, 'b', "i8") \
|
||||
V(I16, 1, I16, Int16, 'h', "i16")
|
||||
|
||||
#define FOREACH_VALUE_TYPE(V) \
|
||||
V(Stmt, -1, Void, None, 'v', "<stmt>") \
|
||||
FOREACH_NUMERIC_VALUE_TYPE(V) \
|
||||
V(Rtt, kTaggedSizeLog2, Rtt, TaggedPointer, 't', "rtt") \
|
||||
V(Ref, kTaggedSizeLog2, Ref, AnyTagged, 'r', "ref") \
|
||||
V(OptRef, kTaggedSizeLog2, OptRef, AnyTagged, 'n', "ref null") \
|
||||
#define FOREACH_VALUE_TYPE(V) \
|
||||
V(Stmt, -1, Void, None, 'v', "<stmt>") \
|
||||
FOREACH_NUMERIC_VALUE_TYPE(V) \
|
||||
V(Rtt, kTaggedSizeLog2, Rtt, TaggedPointer, 't', "rtt") \
|
||||
V(RttWithDepth, kTaggedSizeLog2, RttWithDepth, TaggedPointer, 'k', "rtt") \
|
||||
V(Ref, kTaggedSizeLog2, Ref, AnyTagged, 'r', "ref") \
|
||||
V(OptRef, kTaggedSizeLog2, OptRef, AnyTagged, 'n', "ref null") \
|
||||
V(Bottom, -1, Void, None, '*', "<bot>")
|
||||
|
||||
// Represents a WebAssembly heap type, as per the typed-funcref and gc
|
||||
@ -194,10 +195,16 @@ class ValueType {
|
||||
return Ref(heap_type.representation(), nullability);
|
||||
}
|
||||
|
||||
static constexpr ValueType Rtt(uint32_t type_index) {
|
||||
CONSTEXPR_DCHECK(HeapType(type_index).is_index());
|
||||
return ValueType(KindField::encode(kRtt) |
|
||||
HeapTypeField::encode(type_index));
|
||||
}
|
||||
|
||||
static constexpr ValueType Rtt(uint32_t type_index,
|
||||
uint8_t inheritance_depth) {
|
||||
CONSTEXPR_DCHECK(HeapType(type_index).is_index());
|
||||
return ValueType(KindField::encode(kRtt) |
|
||||
return ValueType(KindField::encode(kRttWithDepth) |
|
||||
HeapTypeField::encode(type_index) |
|
||||
DepthField::encode(inheritance_depth));
|
||||
}
|
||||
@ -209,7 +216,8 @@ class ValueType {
|
||||
|
||||
/******************************** Type checks *******************************/
|
||||
constexpr bool is_reference_type() const {
|
||||
return kind() == kRef || kind() == kOptRef || kind() == kRtt;
|
||||
return kind() == kRef || kind() == kOptRef || kind() == kRtt ||
|
||||
kind() == kRttWithDepth;
|
||||
}
|
||||
|
||||
constexpr bool is_object_reference_type() const {
|
||||
@ -223,8 +231,10 @@ class ValueType {
|
||||
heap_representation() == htype;
|
||||
}
|
||||
|
||||
constexpr bool is_rtt() const { return kind() == kRtt; }
|
||||
constexpr bool has_depth() const { return is_rtt(); }
|
||||
constexpr bool is_rtt() const {
|
||||
return kind() == kRtt || kind() == kRttWithDepth;
|
||||
}
|
||||
constexpr bool has_depth() const { return kind() == kRttWithDepth; }
|
||||
|
||||
constexpr bool has_index() const {
|
||||
return is_rtt() || (is_object_reference_type() && heap_type().is_index());
|
||||
@ -232,7 +242,7 @@ class ValueType {
|
||||
|
||||
constexpr bool is_defaultable() const {
|
||||
CONSTEXPR_DCHECK(kind() != kBottom && kind() != kStmt);
|
||||
return kind() != kRef && kind() != kRtt;
|
||||
return kind() != kRef && !is_rtt();
|
||||
}
|
||||
|
||||
constexpr bool is_bottom() const { return kind() == kBottom; }
|
||||
@ -377,6 +387,8 @@ class ValueType {
|
||||
return kVoidCode;
|
||||
case kRtt:
|
||||
return kRttCode;
|
||||
case kRttWithDepth:
|
||||
return kRttWithDepthCode;
|
||||
#define NUMERIC_TYPE_CASE(kind, ...) \
|
||||
case k##kind: \
|
||||
return k##kind##Code;
|
||||
@ -392,7 +404,6 @@ class ValueType {
|
||||
// binary format, taking into account available type shorthands.
|
||||
constexpr bool encoding_needs_heap_type() const {
|
||||
return (kind() == kRef && heap_representation() != HeapType::kI31) ||
|
||||
kind() == kRtt ||
|
||||
(kind() == kOptRef && (!heap_type().is_generic() ||
|
||||
heap_representation() == HeapType::kI31));
|
||||
}
|
||||
@ -429,10 +440,13 @@ class ValueType {
|
||||
buf << "(ref null " << heap_type().name() << ")";
|
||||
}
|
||||
break;
|
||||
case kRtt:
|
||||
case kRttWithDepth:
|
||||
buf << "(rtt " << static_cast<uint32_t>(depth()) << " " << ref_index()
|
||||
<< ")";
|
||||
break;
|
||||
case kRtt:
|
||||
buf << "(rtt " << ref_index() << ")";
|
||||
break;
|
||||
default:
|
||||
buf << kind_name();
|
||||
}
|
||||
|
@ -38,7 +38,8 @@ enum ValueTypeCode : uint8_t {
|
||||
kOptRefCode = 0x6c,
|
||||
kRefCode = 0x6b,
|
||||
kI31RefCode = 0x6a,
|
||||
kRttCode = 0x69,
|
||||
kRttWithDepthCode = 0x69,
|
||||
kRttCode = 0x68,
|
||||
};
|
||||
// Binary encoding of other types.
|
||||
constexpr uint8_t kWasmFunctionTypeCode = 0x60;
|
||||
|
@ -1376,6 +1376,7 @@ void WebAssemblyGlobal(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
break;
|
||||
}
|
||||
case i::wasm::ValueType::kRtt:
|
||||
case i::wasm::ValueType::kRttWithDepth:
|
||||
// TODO(7748): Implement.
|
||||
UNIMPLEMENTED();
|
||||
case i::wasm::ValueType::kI8:
|
||||
@ -1847,6 +1848,7 @@ void WebAssemblyGlobalGetValueCommon(
|
||||
}
|
||||
break;
|
||||
case i::wasm::ValueType::kRtt:
|
||||
case i::wasm::ValueType::kRttWithDepth:
|
||||
UNIMPLEMENTED(); // TODO(7748): Implement.
|
||||
break;
|
||||
case i::wasm::ValueType::kI8:
|
||||
@ -1939,6 +1941,7 @@ void WebAssemblyGlobalSetValue(
|
||||
}
|
||||
break;
|
||||
case i::wasm::ValueType::kRtt:
|
||||
case i::wasm::ValueType::kRttWithDepth:
|
||||
// TODO(7748): Implement.
|
||||
UNIMPLEMENTED();
|
||||
break;
|
||||
|
@ -414,11 +414,11 @@ void WasmModuleBuilder::SetHasSharedMemory() { has_shared_memory_ = true; }
|
||||
namespace {
|
||||
void WriteValueType(ZoneBuffer* buffer, const ValueType& type) {
|
||||
buffer->write_u8(type.value_type_code());
|
||||
if (type.is_object_reference_type() && type.encoding_needs_heap_type()) {
|
||||
if (type.encoding_needs_heap_type()) {
|
||||
buffer->write_i32v(type.heap_type().code());
|
||||
}
|
||||
if (type.is_rtt()) {
|
||||
buffer->write_u32v(type.depth());
|
||||
if (type.has_depth()) buffer->write_u32v(type.depth());
|
||||
buffer->write_u32v(type.ref_index());
|
||||
}
|
||||
}
|
||||
@ -490,6 +490,7 @@ void WriteGlobalInitializer(ZoneBuffer* buffer, const WasmInitExpr& init,
|
||||
case ValueType::kBottom:
|
||||
case ValueType::kRef:
|
||||
case ValueType::kRtt:
|
||||
case ValueType::kRttWithDepth:
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
|
@ -1745,6 +1745,7 @@ uint32_t WasmExceptionPackage::GetEncodedSize(
|
||||
encoded_size += 1;
|
||||
break;
|
||||
case wasm::ValueType::kRtt:
|
||||
case wasm::ValueType::kRttWithDepth:
|
||||
case wasm::ValueType::kStmt:
|
||||
case wasm::ValueType::kBottom:
|
||||
case wasm::ValueType::kI8:
|
||||
|
@ -274,12 +274,34 @@ V8_NOINLINE V8_EXPORT_PRIVATE bool IsSubtypeOfImpl(
|
||||
const WasmModule* super_module) {
|
||||
DCHECK(subtype != supertype || sub_module != super_module);
|
||||
|
||||
if (!subtype.is_reference_type()) return subtype == supertype;
|
||||
|
||||
if (subtype.is_rtt()) {
|
||||
return supertype.is_rtt() && subtype.depth() == supertype.depth() &&
|
||||
EquivalentIndices(subtype.ref_index(), supertype.ref_index(),
|
||||
sub_module, super_module);
|
||||
switch (subtype.kind()) {
|
||||
case ValueType::kI32:
|
||||
case ValueType::kI64:
|
||||
case ValueType::kF32:
|
||||
case ValueType::kF64:
|
||||
case ValueType::kS128:
|
||||
case ValueType::kI8:
|
||||
case ValueType::kI16:
|
||||
case ValueType::kStmt:
|
||||
case ValueType::kBottom:
|
||||
return subtype == supertype;
|
||||
case ValueType::kRtt:
|
||||
return supertype.kind() == ValueType::kRtt &&
|
||||
EquivalentIndices(subtype.ref_index(), supertype.ref_index(),
|
||||
sub_module, super_module);
|
||||
case ValueType::kRttWithDepth:
|
||||
return (supertype.kind() == ValueType::kRtt &&
|
||||
((sub_module == super_module &&
|
||||
subtype.ref_index() == supertype.ref_index()) ||
|
||||
EquivalentIndices(subtype.ref_index(), supertype.ref_index(),
|
||||
sub_module, super_module))) ||
|
||||
(supertype.kind() == ValueType::kRttWithDepth &&
|
||||
supertype.depth() == subtype.depth() &&
|
||||
EquivalentIndices(subtype.ref_index(), supertype.ref_index(),
|
||||
sub_module, super_module));
|
||||
case ValueType::kRef:
|
||||
case ValueType::kOptRef:
|
||||
break;
|
||||
}
|
||||
|
||||
DCHECK(subtype.is_object_reference_type());
|
||||
|
@ -798,11 +798,13 @@ WASM_COMPILED_EXEC_TEST(NewDefault) {
|
||||
tester.CheckResult(allocate_array, 0);
|
||||
}
|
||||
|
||||
TEST(BasicRTT) {
|
||||
TEST(BasicRtt) {
|
||||
WasmGCTester tester;
|
||||
|
||||
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, 0)};
|
||||
FunctionSig sig_t_v(1, 0, kRttTypes);
|
||||
ValueType kRttSubtypes[] = {ValueType::Rtt(subtype_index, 1)};
|
||||
@ -822,6 +824,7 @@ TEST(BasicRTT) {
|
||||
{WASM_STRUCT_NEW_WITH_RTT(type_index, WASM_I32V(42),
|
||||
WASM_RTT_CANON(type_index)),
|
||||
kExprEnd});
|
||||
|
||||
const int kFieldIndex = 1;
|
||||
const int kStructIndexCode = 1; // Shifted in 'let' block.
|
||||
const int kRttIndexCode = 0; // Let-bound, hence first local.
|
||||
@ -836,20 +839,20 @@ TEST(BasicRTT) {
|
||||
const byte kRefCast = tester.DefineFunction(
|
||||
tester.sigs.i_v(), {optref(type_index)},
|
||||
{WASM_LET_1_I(
|
||||
WASM_RTT(1, subtype_index),
|
||||
WASM_RTT_SUB(subtype_index, WASM_RTT_CANON(type_index)),
|
||||
WASM_LOCAL_SET(kStructIndexCode,
|
||||
WASM_STRUCT_NEW_WITH_RTT(
|
||||
subtype_index, WASM_I32V(11), WASM_I32V(42),
|
||||
WASM_LOCAL_GET(kRttIndexCode))),
|
||||
WASM_I32_ADD(
|
||||
WASM_REF_TEST(subtype_index, WASM_LOCAL_GET(kStructIndexCode),
|
||||
WASM_LOCAL_GET(kRttIndexCode)),
|
||||
WASM_STRUCT_GET(
|
||||
subtype_index, kFieldIndex,
|
||||
WASM_REF_CAST(subtype_index, WASM_LOCAL_GET(kStructIndexCode),
|
||||
WASM_LOCAL_GET(kRttIndexCode)))),
|
||||
kExprEnd)});
|
||||
WASM_RTT_WITH_DEPTH(1, subtype_index),
|
||||
WASM_RTT_SUB(subtype_index, WASM_RTT_CANON(type_index)),
|
||||
WASM_LOCAL_SET(kStructIndexCode,
|
||||
WASM_STRUCT_NEW_WITH_RTT(
|
||||
subtype_index, WASM_I32V(11), WASM_I32V(42),
|
||||
WASM_LOCAL_GET(kRttIndexCode))),
|
||||
WASM_I32_ADD(
|
||||
WASM_REF_TEST(subtype_index, WASM_LOCAL_GET(kStructIndexCode),
|
||||
WASM_LOCAL_GET(kRttIndexCode)),
|
||||
WASM_STRUCT_GET(subtype_index, kFieldIndex,
|
||||
WASM_REF_CAST(subtype_index,
|
||||
WASM_LOCAL_GET(kStructIndexCode),
|
||||
WASM_LOCAL_GET(kRttIndexCode))))),
|
||||
kExprEnd});
|
||||
|
||||
tester.CompileModule();
|
||||
|
||||
@ -881,6 +884,89 @@ TEST(BasicRTT) {
|
||||
tester.CheckResult(kRefCast, 43);
|
||||
}
|
||||
|
||||
TEST(NoDepthRtt) {
|
||||
WasmGCTester tester;
|
||||
|
||||
const byte type_index = tester.DefineStruct({F(wasm::kWasmI32, true)});
|
||||
const byte subtype_index =
|
||||
tester.DefineStruct({F(wasm::kWasmI32, true), F(wasm::kWasmI32, true)});
|
||||
const byte empty_struct_index = tester.DefineStruct({});
|
||||
|
||||
ValueType kRttSubtypeNoDepth = ValueType::Rtt(subtype_index);
|
||||
FunctionSig sig_t2_v_nd(1, 0, &kRttSubtypeNoDepth);
|
||||
|
||||
const byte kRttSubtypeCanon = tester.DefineFunction(
|
||||
&sig_t2_v_nd, {}, {WASM_RTT_CANON(subtype_index), kExprEnd});
|
||||
const byte kRttSubtypeSub = tester.DefineFunction(
|
||||
&sig_t2_v_nd, {},
|
||||
{WASM_RTT_SUB(subtype_index, WASM_RTT_CANON(type_index)), kExprEnd});
|
||||
|
||||
const byte kTestCanon = tester.DefineFunction(
|
||||
tester.sigs.i_v(), {optref(type_index)},
|
||||
{WASM_LOCAL_SET(0, WASM_STRUCT_NEW_WITH_RTT(
|
||||
subtype_index, WASM_I32V(11), WASM_I32V(42),
|
||||
WASM_RTT_CANON(subtype_index))),
|
||||
WASM_REF_TEST(subtype_index, WASM_LOCAL_GET(0),
|
||||
WASM_CALL_FUNCTION0(kRttSubtypeCanon)),
|
||||
kExprEnd});
|
||||
|
||||
const byte kTestSub = tester.DefineFunction(
|
||||
tester.sigs.i_v(), {optref(type_index)},
|
||||
{WASM_LOCAL_SET(
|
||||
0, WASM_STRUCT_NEW_WITH_RTT(
|
||||
subtype_index, WASM_I32V(11), WASM_I32V(42),
|
||||
WASM_RTT_SUB(subtype_index, WASM_RTT_CANON(type_index)))),
|
||||
WASM_REF_TEST(subtype_index, WASM_LOCAL_GET(0),
|
||||
WASM_CALL_FUNCTION0(kRttSubtypeSub)),
|
||||
kExprEnd});
|
||||
|
||||
const byte kTestSubVsEmpty = tester.DefineFunction(
|
||||
tester.sigs.i_v(), {optref(type_index)},
|
||||
{WASM_LOCAL_SET(0, WASM_STRUCT_NEW_WITH_RTT(
|
||||
subtype_index, WASM_I32V(11), WASM_I32V(42),
|
||||
WASM_RTT_SUB(subtype_index,
|
||||
WASM_RTT_CANON(empty_struct_index)))),
|
||||
WASM_REF_TEST(subtype_index, WASM_LOCAL_GET(0),
|
||||
WASM_CALL_FUNCTION0(kRttSubtypeSub)),
|
||||
kExprEnd});
|
||||
|
||||
const byte kTestSubVsCanon = tester.DefineFunction(
|
||||
tester.sigs.i_v(), {optref(type_index)},
|
||||
{WASM_LOCAL_SET(0, WASM_STRUCT_NEW_WITH_RTT(
|
||||
subtype_index, WASM_I32V(11), WASM_I32V(42),
|
||||
WASM_RTT_CANON(subtype_index))),
|
||||
WASM_REF_TEST(subtype_index, WASM_LOCAL_GET(0),
|
||||
WASM_CALL_FUNCTION0(kRttSubtypeSub)),
|
||||
kExprEnd});
|
||||
|
||||
const byte kTestCanonVsSub = tester.DefineFunction(
|
||||
tester.sigs.i_v(), {optref(type_index)},
|
||||
{WASM_LOCAL_SET(
|
||||
0, WASM_STRUCT_NEW_WITH_RTT(
|
||||
subtype_index, WASM_I32V(11), WASM_I32V(42),
|
||||
WASM_RTT_SUB(subtype_index, WASM_RTT_CANON(type_index)))),
|
||||
WASM_REF_TEST(subtype_index, WASM_LOCAL_GET(0),
|
||||
WASM_CALL_FUNCTION0(kRttSubtypeCanon)),
|
||||
kExprEnd});
|
||||
|
||||
const byte kTestSuperVsSub = tester.DefineFunction(
|
||||
tester.sigs.i_v(), {optref(type_index)},
|
||||
{WASM_LOCAL_SET(0, WASM_STRUCT_NEW_WITH_RTT(type_index, WASM_I32V(42),
|
||||
WASM_RTT_CANON(type_index))),
|
||||
WASM_REF_TEST(subtype_index, WASM_LOCAL_GET(0),
|
||||
WASM_CALL_FUNCTION0(kRttSubtypeCanon)),
|
||||
kExprEnd});
|
||||
|
||||
tester.CompileModule();
|
||||
|
||||
tester.CheckResult(kTestCanon, 1);
|
||||
tester.CheckResult(kTestSub, 1);
|
||||
tester.CheckResult(kTestSubVsEmpty, 0);
|
||||
tester.CheckResult(kTestSubVsCanon, 0);
|
||||
tester.CheckResult(kTestCanonVsSub, 0);
|
||||
tester.CheckResult(kTestSuperVsSub, 0);
|
||||
}
|
||||
|
||||
WASM_COMPILED_EXEC_TEST(ArrayNewMap) {
|
||||
WasmGCTester tester(execution_tier);
|
||||
FLAG_experimental_liftoff_extern_ref = true;
|
||||
|
@ -1256,8 +1256,9 @@ class WasmInterpreterInternals {
|
||||
val = WasmValue(isolate_->factory()->null_value());
|
||||
break;
|
||||
}
|
||||
case ValueType::kRef:
|
||||
case ValueType::kRtt: // TODO(7748): Implement.
|
||||
case ValueType::kRef: // TODO(7748): Implement.
|
||||
case ValueType::kRtt:
|
||||
case ValueType::kRttWithDepth:
|
||||
case ValueType::kStmt:
|
||||
case ValueType::kBottom:
|
||||
case ValueType::kI8:
|
||||
@ -3034,6 +3035,7 @@ class WasmInterpreterInternals {
|
||||
break;
|
||||
}
|
||||
case ValueType::kRtt: // TODO(7748): Implement.
|
||||
case ValueType::kRttWithDepth:
|
||||
case ValueType::kI8:
|
||||
case ValueType::kI16:
|
||||
case ValueType::kStmt:
|
||||
@ -3151,6 +3153,7 @@ class WasmInterpreterInternals {
|
||||
break;
|
||||
}
|
||||
case ValueType::kRtt: // TODO(7748): Implement.
|
||||
case ValueType::kRttWithDepth:
|
||||
case ValueType::kI8:
|
||||
case ValueType::kI16:
|
||||
case ValueType::kStmt:
|
||||
@ -3522,6 +3525,7 @@ class WasmInterpreterInternals {
|
||||
break;
|
||||
}
|
||||
case ValueType::kRtt: // TODO(7748): Implement.
|
||||
case ValueType::kRttWithDepth:
|
||||
case ValueType::kI8:
|
||||
case ValueType::kI16:
|
||||
case ValueType::kStmt:
|
||||
@ -3933,6 +3937,7 @@ class WasmInterpreterInternals {
|
||||
break;
|
||||
}
|
||||
case ValueType::kRtt:
|
||||
case ValueType::kRttWithDepth:
|
||||
// TODO(7748): Implement properly.
|
||||
PrintF("rtt");
|
||||
break;
|
||||
|
@ -526,7 +526,9 @@ inline WasmOpcode LoadStoreOpcodeOf(MachineType type, bool store) {
|
||||
#define WASM_ARRAY_LEN(typeidx, array) \
|
||||
array, WASM_GC_OP(kExprArrayLen), static_cast<byte>(typeidx)
|
||||
|
||||
#define WASM_RTT(depth, typeidx) kRttCode, U32V_1(depth), U32V_1(typeidx)
|
||||
#define WASM_RTT_WITH_DEPTH(depth, typeidx) \
|
||||
kRttWithDepthCode, U32V_1(depth), U32V_1(typeidx)
|
||||
#define WASM_RTT(typeidx) kRttCode, U32V_1(typeidx)
|
||||
#define WASM_RTT_CANON(typeidx) \
|
||||
WASM_GC_OP(kExprRttCanon), static_cast<byte>(typeidx)
|
||||
#define WASM_RTT_SUB(typeidx, supertype) \
|
||||
|
@ -70,6 +70,7 @@ OwnedVector<WasmValue> MakeDefaultInterpreterArguments(Isolate* isolate,
|
||||
break;
|
||||
case ValueType::kRef:
|
||||
case ValueType::kRtt:
|
||||
case ValueType::kRttWithDepth:
|
||||
case ValueType::kI8:
|
||||
case ValueType::kI16:
|
||||
case ValueType::kStmt:
|
||||
@ -104,6 +105,7 @@ OwnedVector<Handle<Object>> MakeDefaultArguments(Isolate* isolate,
|
||||
break;
|
||||
case ValueType::kRef:
|
||||
case ValueType::kRtt:
|
||||
case ValueType::kRttWithDepth:
|
||||
case ValueType::kI8:
|
||||
case ValueType::kI16:
|
||||
case ValueType::kStmt:
|
||||
|
@ -4230,55 +4230,61 @@ TEST_F(FunctionBodyDecoderTest, RefTestCast) {
|
||||
builder.AddStruct({F(kWasmI16, true), F(kWasmI32, false)}));
|
||||
|
||||
// Passing/failing tests due to static subtyping.
|
||||
std::pair<HeapType::Representation, HeapType::Representation> valid_pairs[] =
|
||||
{{HeapType::kAny, array_heap},
|
||||
{HeapType::kAny, super_struct_heap},
|
||||
{HeapType::kEq, array_heap},
|
||||
{HeapType::kEq, super_struct_heap},
|
||||
{super_struct_heap, sub_struct_heap}};
|
||||
std::tuple<HeapType::Representation, HeapType::Representation, bool> tests[] =
|
||||
{{HeapType::kAny, array_heap, true},
|
||||
{HeapType::kAny, super_struct_heap, true},
|
||||
{HeapType::kEq, array_heap, true},
|
||||
{HeapType::kEq, super_struct_heap, true},
|
||||
{super_struct_heap, sub_struct_heap, true},
|
||||
{sub_struct_heap, super_struct_heap, false},
|
||||
{sub_struct_heap, array_heap, false},
|
||||
{HeapType::kFunc, array_heap, false}};
|
||||
|
||||
for (auto test : tests) {
|
||||
HeapType from_heap = HeapType(std::get<0>(test));
|
||||
HeapType to_heap = HeapType(std::get<1>(test));
|
||||
bool should_pass = std::get<2>(test);
|
||||
|
||||
for (auto pair : valid_pairs) {
|
||||
HeapType from_heap = HeapType(pair.first);
|
||||
HeapType to_heap = HeapType(pair.second);
|
||||
ValueType test_reps[] = {kWasmI32, ValueType::Ref(from_heap, kNullable)};
|
||||
FunctionSig test_sig(1, 1, test_reps);
|
||||
ValueType cast_reps[] = {ValueType::Ref(to_heap, kNonNullable),
|
||||
ValueType::Ref(from_heap, kNonNullable)};
|
||||
FunctionSig cast_sig(1, 1, cast_reps);
|
||||
ExpectValidates(&test_sig,
|
||||
{WASM_REF_TEST(WASM_HEAP_TYPE(to_heap), WASM_LOCAL_GET(0),
|
||||
WASM_RTT_CANON(WASM_HEAP_TYPE(to_heap)))});
|
||||
ExpectValidates(&cast_sig,
|
||||
{WASM_REF_CAST(WASM_HEAP_TYPE(to_heap), WASM_LOCAL_GET(0),
|
||||
WASM_RTT_CANON(WASM_HEAP_TYPE(to_heap)))});
|
||||
}
|
||||
|
||||
std::pair<HeapType::Representation, HeapType::Representation>
|
||||
invalid_pairs[] = {{sub_struct_heap, super_struct_heap},
|
||||
{sub_struct_heap, array_heap},
|
||||
{HeapType::kFunc, array_heap}};
|
||||
ValueType cast_reps_with_depth[] = {ValueType::Ref(to_heap, kNullable),
|
||||
ValueType::Ref(from_heap, kNullable)};
|
||||
FunctionSig cast_sig_with_depth(1, 1, cast_reps_with_depth);
|
||||
|
||||
for (auto pair : invalid_pairs) {
|
||||
HeapType from_heap = HeapType(pair.first);
|
||||
HeapType to_heap = HeapType(pair.second);
|
||||
ValueType test_reps[] = {kWasmI32, ValueType::Ref(from_heap, kNullable)};
|
||||
FunctionSig test_sig(1, 1, test_reps);
|
||||
ValueType cast_reps[] = {ValueType::Ref(to_heap, kNullable),
|
||||
ValueType::Ref(from_heap, kNullable)};
|
||||
FunctionSig cast_sig(1, 1, cast_reps);
|
||||
ValueType::Ref(from_heap, kNullable),
|
||||
ValueType::Rtt(to_heap.ref_index())};
|
||||
FunctionSig cast_sig(1, 2, cast_reps);
|
||||
|
||||
std::string error_message = "[0] expected supertype 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),
|
||||
WASM_RTT_CANON(WASM_HEAP_TYPE(to_heap)))},
|
||||
kAppendEnd, ("ref.test" + error_message).c_str());
|
||||
ExpectFailure(&cast_sig,
|
||||
{WASM_REF_CAST(WASM_HEAP_TYPE(to_heap), WASM_LOCAL_GET(0),
|
||||
WASM_RTT_CANON(WASM_HEAP_TYPE(to_heap)))},
|
||||
kAppendEnd, ("ref.cast" + error_message).c_str());
|
||||
if (should_pass) {
|
||||
ExpectValidates(&test_sig,
|
||||
{WASM_REF_TEST(WASM_HEAP_TYPE(to_heap), WASM_LOCAL_GET(0),
|
||||
WASM_RTT_CANON(WASM_HEAP_TYPE(to_heap)))});
|
||||
ExpectValidates(&cast_sig_with_depth,
|
||||
{WASM_REF_CAST(WASM_HEAP_TYPE(to_heap), WASM_LOCAL_GET(0),
|
||||
WASM_RTT_CANON(WASM_HEAP_TYPE(to_heap)))});
|
||||
ExpectValidates(&cast_sig,
|
||||
{WASM_REF_CAST(WASM_HEAP_TYPE(to_heap), WASM_LOCAL_GET(0),
|
||||
WASM_LOCAL_GET(1))});
|
||||
} else {
|
||||
std::string error_message = "[0] expected supertype 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),
|
||||
WASM_RTT_CANON(WASM_HEAP_TYPE(to_heap)))},
|
||||
kAppendEnd, ("ref.test" + error_message).c_str());
|
||||
ExpectFailure(&cast_sig_with_depth,
|
||||
{WASM_REF_CAST(WASM_HEAP_TYPE(to_heap), WASM_LOCAL_GET(0),
|
||||
WASM_RTT_CANON(WASM_HEAP_TYPE(to_heap)))},
|
||||
kAppendEnd, ("ref.cast" + error_message).c_str());
|
||||
ExpectFailure(&cast_sig,
|
||||
{WASM_REF_CAST(WASM_HEAP_TYPE(to_heap), WASM_LOCAL_GET(0),
|
||||
WASM_LOCAL_GET(1))},
|
||||
kAppendEnd, ("ref.cast" + error_message).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// Trivial type error.
|
||||
|
@ -569,12 +569,12 @@ TEST_F(WasmModuleVerifyTest, GlobalInitializer) {
|
||||
static const byte referencing_undefined_global_nested[] = {
|
||||
SECTION(Type, ENTRY_COUNT(1), WASM_ARRAY_DEF(kI32Code, true)),
|
||||
SECTION(Global, ENTRY_COUNT(2), // --
|
||||
WASM_RTT(1, 0), // type
|
||||
WASM_RTT_WITH_DEPTH(1, 0), // type
|
||||
0, // mutable
|
||||
WASM_RTT_SUB(0, // init value
|
||||
WASM_GLOBAL_GET(1)), // --
|
||||
kExprEnd, // --
|
||||
WASM_RTT(0, 0), // type
|
||||
WASM_RTT_WITH_DEPTH(0, 0), // type
|
||||
0, // mutable
|
||||
WASM_RTT_CANON(0), kExprEnd) // init value
|
||||
};
|
||||
@ -796,8 +796,8 @@ 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(0, 0), 0, WASM_RTT_CANON(0),
|
||||
kExprEnd)};
|
||||
SECTION(Global, ENTRY_COUNT(1), WASM_RTT_WITH_DEPTH(0, 0), 0,
|
||||
WASM_RTT_CANON(0), kExprEnd)};
|
||||
ModuleResult result = DecodeModule(data, data + sizeof(data));
|
||||
EXPECT_OK(result);
|
||||
}
|
||||
@ -809,8 +809,8 @@ TEST_F(WasmModuleVerifyTest, RttCanonGlobalTypeError) {
|
||||
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)};
|
||||
SECTION(Global, ENTRY_COUNT(1), WASM_RTT_WITH_DEPTH(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 0), got "
|
||||
@ -826,7 +826,7 @@ TEST_F(WasmModuleVerifyTest, GlobalRttSubOfCanon) {
|
||||
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,
|
||||
SECTION(Global, ENTRY_COUNT(1), WASM_RTT_WITH_DEPTH(1, 1), 1,
|
||||
WASM_RTT_SUB(1, WASM_RTT_CANON(0)), kExprEnd)};
|
||||
ModuleResult result = DecodeModule(data, data + sizeof(data));
|
||||
WasmInitExpr expected = WasmInitExpr::RttSub(1, WasmInitExpr::RttCanon(0));
|
||||
@ -843,7 +843,7 @@ TEST_F(WasmModuleVerifyTest, GlobalRttSubOfSubOfCanon) {
|
||||
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,
|
||||
SECTION(Global, ENTRY_COUNT(1), WASM_RTT_WITH_DEPTH(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(
|
||||
@ -861,14 +861,14 @@ TEST_F(WasmModuleVerifyTest, GlobalRttSubOfGlobal) {
|
||||
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,
|
||||
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_WITH_DEPTH(0, 0), // type
|
||||
0), // mutability
|
||||
SECTION(Global, ENTRY_COUNT(1), WASM_RTT_WITH_DEPTH(1, 1), 1,
|
||||
WASM_RTT_SUB(1, WASM_GLOBAL_GET(0)), kExprEnd)};
|
||||
ModuleResult result = DecodeModule(data, data + sizeof(data));
|
||||
WasmInitExpr expected = WasmInitExpr::RttSub(1, WasmInitExpr::GlobalGet(0));
|
||||
@ -890,7 +890,7 @@ TEST_F(WasmModuleVerifyTest, GlobalRttSubOfGlobalTypeError) {
|
||||
kExternalGlobal, // import kind
|
||||
kI32Code, // type
|
||||
0), // mutability
|
||||
SECTION(Global, ENTRY_COUNT(1), WASM_RTT(1, 0), 1,
|
||||
SECTION(Global, ENTRY_COUNT(1), WASM_RTT_WITH_DEPTH(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");
|
||||
@ -904,7 +904,7 @@ TEST_F(WasmModuleVerifyTest, GlobalRttSubIllegalParent) {
|
||||
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,
|
||||
SECTION(Global, ENTRY_COUNT(1), WASM_RTT_WITH_DEPTH(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");
|
||||
@ -917,7 +917,7 @@ TEST_F(WasmModuleVerifyTest, RttSubGlobalTypeError) {
|
||||
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,
|
||||
SECTION(Global, ENTRY_COUNT(1), WASM_RTT_WITH_DEPTH(0, 0), 1,
|
||||
WASM_RTT_SUB(0, WASM_RTT_CANON(0)), kExprEnd)};
|
||||
ModuleResult result = DecodeModule(data, data + sizeof(data));
|
||||
EXPECT_NOT_OK(result,
|
||||
@ -1982,7 +1982,7 @@ TEST_F(WasmModuleVerifyTest, IllegalTableTypes) {
|
||||
{kOptRefCode, 1},
|
||||
{kOptRefCode, kI31RefCode},
|
||||
{kI31RefCode},
|
||||
{kRttCode, 2, 0}};
|
||||
{kRttWithDepthCode, 2, 0}};
|
||||
|
||||
for (Vec type : table_types) {
|
||||
Vec data = {
|
||||
|
@ -131,6 +131,13 @@ TEST_F(WasmSubtypingTest, Subtyping) {
|
||||
// Identical rtts are subtypes of each other.
|
||||
CHECK(IsSubtypeOf(ValueType::Rtt(5, 3), ValueType::Rtt(5, 3), module1,
|
||||
module2));
|
||||
CHECK(IsSubtypeOf(ValueType::Rtt(5), ValueType::Rtt(5), module1, module2));
|
||||
// Rtts of unrelated types are unrelated.
|
||||
CHECK(!IsSubtypeOf(ValueType::Rtt(1, 1), ValueType::Rtt(2, 1), module1,
|
||||
module2));
|
||||
CHECK(!IsSubtypeOf(ValueType::Rtt(1), ValueType::Rtt(2), module1, module2));
|
||||
CHECK(!IsSubtypeOf(ValueType::Rtt(1, 0), ValueType::Rtt(2), module1,
|
||||
module2));
|
||||
// Rtts of different depth are unrelated.
|
||||
CHECK(!IsSubtypeOf(ValueType::Rtt(5, 1), ValueType::Rtt(5, 3), module1,
|
||||
module2));
|
||||
@ -139,9 +146,16 @@ TEST_F(WasmSubtypingTest, Subtyping) {
|
||||
// Rtts of identical types are subtype-related.
|
||||
CHECK(IsSubtypeOf(ValueType::Rtt(8, 1), ValueType::Rtt(9, 1), module1,
|
||||
module));
|
||||
CHECK(IsSubtypeOf(ValueType::Rtt(8), ValueType::Rtt(9), module1, module));
|
||||
// Rtts of subtypes are not related.
|
||||
CHECK(!IsSubtypeOf(ValueType::Rtt(1, 1), ValueType::Rtt(0, 1), module1,
|
||||
module));
|
||||
CHECK(!IsSubtypeOf(ValueType::Rtt(1), ValueType::Rtt(0), module1, module));
|
||||
// rtt(t, d) <: rtt(t)
|
||||
for (uint8_t depth : {0, 1, 5}) {
|
||||
CHECK(IsSubtypeOf(ValueType::Rtt(1, depth), ValueType::Rtt(1), module1,
|
||||
module));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user