[wasm][refactor] Tidy up errors in decoding

Changes:
- Add two additional PopTypeError overloads which take a C++/C-style
  string as argument over a ValueType.
- Change type errors in decoding to use PopTypeError. This improves
  consistency of error formatting as well as code readability.
- Improve some immediate argument errors.
- Adapt decoding unit tests.

Change-Id: Ifd54712965049a80692dbc3fde1ef489596e8662
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2614059
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Reviewed-by: Clemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#71998}
This commit is contained in:
Manos Koukoutos 2021-01-11 08:29:58 +00:00 committed by Commit Bot
parent 1a9d6c399e
commit 0979f724de
2 changed files with 111 additions and 127 deletions

View File

@ -2551,9 +2551,7 @@ class WasmFullDecoder : public WasmDecoder<validate> {
break;
}
default:
this->DecodeError(
"br_on_null[0]: Expected object reference, found %s of type %s",
SafeOpcodeNameAt(ref_object.pc()), ref_object.type.name().c_str());
PopTypeError(0, ref_object, "object reference");
return 0;
}
return 1 + imm.length;
@ -2872,10 +2870,7 @@ class WasmFullDecoder : public WasmDecoder<validate> {
return 1;
default:
if (validate) {
this->DecodeError(
"invalid argument type to ref.is_null. Expected reference type, "
"got %s",
value.type.name().c_str());
PopTypeError(0, value, "reference type");
return 0;
}
UNREACHABLE();
@ -2913,10 +2908,7 @@ class WasmFullDecoder : public WasmDecoder<validate> {
}
default:
if (validate) {
this->DecodeError(
"invalid agrument type to ref.as_non_null: Expected reference "
"type, got %s",
value.type.name().c_str());
PopTypeError(0, value, "reference type");
}
return 0;
}
@ -3111,10 +3103,7 @@ class WasmFullDecoder : public WasmDecoder<validate> {
if (!VALIDATE(func_type.is_object_reference_type() &&
func_type.has_index() &&
this->module_->has_signature(func_type.ref_index()))) {
this->DecodeError(
"call_ref: Expected function reference on top of stack, found %s of "
"type %s instead",
SafeOpcodeNameAt(func_ref.pc()), func_type.name().c_str());
PopTypeError(0, func_ref, "function reference");
return 0;
}
const FunctionSig* sig = this->module_->signature(func_type.ref_index());
@ -3137,10 +3126,7 @@ class WasmFullDecoder : public WasmDecoder<validate> {
if (!VALIDATE(func_type.is_object_reference_type() &&
func_type.has_index() &&
this->module_->has_signature(func_type.ref_index()))) {
this->DecodeError(
"return_call_ref: Expected function reference on top of stack, found "
"%s of type %s instead",
SafeOpcodeNameAt(func_ref.pc()), func_type.name().c_str());
PopTypeError(0, func_ref, "function reference");
return 0;
}
const FunctionSig* sig = this->module_->signature(func_type.ref_index());
@ -3770,19 +3756,15 @@ class WasmFullDecoder : public WasmDecoder<validate> {
if (!this->Validate(this->pc_ + opcode_length, imm)) return 0;
Value rtt = Pop(imm.struct_type->field_count());
if (!VALIDATE(rtt.type.is_rtt() || rtt.type.is_bottom())) {
this->DecodeError(
"struct.new_with_rtt expected rtt, found %s of type %s",
SafeOpcodeNameAt(rtt.pc()), rtt.type.name().c_str());
PopTypeError(imm.struct_type->field_count(), rtt, "rtt");
return 0;
}
// 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)) {
this->DecodeError(
"struct.new_with_rtt expected rtt for type %d, found rtt for "
"type %s",
imm.index, rtt.type.heap_type().name().c_str());
PopTypeError(imm.struct_type->field_count(), rtt,
"rtt for type " + std::to_string(imm.index));
return 0;
}
ArgVector args = PopArgs(imm.struct_type);
@ -3799,28 +3781,23 @@ class WasmFullDecoder : public WasmDecoder<validate> {
ValueType ftype = imm.struct_type->field(i);
if (!VALIDATE(ftype.is_defaultable())) {
this->DecodeError(
"struct.new_default_with_rtt: struct type %d has "
"non-defaultable type %s for field %d",
imm.index, ftype.name().c_str(), i);
"struct.new_default_with_rtt: immediate struct type %d has "
"field %d of non-defaultable type %s",
imm.index, i, ftype.name().c_str());
return 0;
}
}
}
Value rtt = Pop(0);
if (!VALIDATE(rtt.type.is_rtt() || rtt.type.is_bottom())) {
this->DecodeError(
"struct.new_default_with_rtt expected rtt, found %s of type %s",
SafeOpcodeNameAt(rtt.pc()), rtt.type.name().c_str());
PopTypeError(0, rtt, "rtt");
return 0;
}
// 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)) {
this->DecodeError(
"struct.new_default_with_rtt expected rtt for type %d, found rtt "
"for type %s",
imm.index, rtt.type.heap_type().name().c_str());
PopTypeError(0, rtt, "rtt for type " + std::to_string(imm.index));
return 0;
}
Value* value = Push(ValueType::Ref(imm.index, kNonNullable));
@ -3834,8 +3811,9 @@ class WasmFullDecoder : public WasmDecoder<validate> {
field.struct_index.struct_type->field(field.index);
if (!VALIDATE(!field_type.is_packed())) {
this->DecodeError(
"struct.get used with a field of packed type. Use struct.get_s "
"or struct.get_u instead.");
"struct.get: Immediate field %d of type %d has packed type %s. "
"Use struct.get_s or struct.get_u instead.",
field.index, field.struct_index.index, field_type.name().c_str());
return 0;
}
Value struct_obj =
@ -3852,9 +3830,10 @@ class WasmFullDecoder : public WasmDecoder<validate> {
field.struct_index.struct_type->field(field.index);
if (!VALIDATE(field_type.is_packed())) {
this->DecodeError(
"%s is only valid for packed struct fields. Use struct.get "
"instead.",
WasmOpcodes::OpcodeName(opcode));
"%s: Immediate field %d of type %d has non-packed type %s. Use "
"struct.get instead.",
WasmOpcodes::OpcodeName(opcode), field.index,
field.struct_index.index, field_type.name().c_str());
return 0;
}
Value struct_obj =
@ -3869,7 +3848,8 @@ class WasmFullDecoder : public WasmDecoder<validate> {
if (!this->Validate(this->pc_ + opcode_length, field)) return 0;
const StructType* struct_type = field.struct_index.struct_type;
if (!VALIDATE(struct_type->mutability(field.index))) {
this->DecodeError("setting immutable struct field");
this->DecodeError("struct.set: Field %d of type %d is immutable.",
field.index, field.struct_index.index);
return 0;
}
Value field_value = Pop(1, struct_type->field(field.index).Unpacked());
@ -3883,21 +3863,14 @@ class WasmFullDecoder : public WasmDecoder<validate> {
if (!this->Validate(this->pc_ + opcode_length, imm)) return 0;
Value rtt = Pop(2);
if (!VALIDATE(rtt.type.is_rtt() || rtt.type.is_bottom())) {
this->DecodeError(
this->pc_ + opcode_length,
"array.new_with_rtt expected rtt, found %s of type %s",
SafeOpcodeNameAt(rtt.pc()), rtt.type.name().c_str());
PopTypeError(2, rtt, "rtt");
return 0;
}
// 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)) {
this->DecodeError(
this->pc_ + opcode_length,
"array.new_with_rtt expected rtt for type %d, found "
"rtt for type %s",
imm.index, rtt.type.heap_type().name().c_str());
PopTypeError(2, rtt, "rtt for type " + std::to_string(imm.index));
return 0;
}
Value length = Pop(1, kWasmI32);
@ -3912,27 +3885,21 @@ class WasmFullDecoder : public WasmDecoder<validate> {
if (!this->Validate(this->pc_ + opcode_length, imm)) return 0;
if (!VALIDATE(imm.array_type->element_type().is_defaultable())) {
this->DecodeError(
"array.new_default_with_rtt: array type %d has "
"array.new_default_with_rtt: immediate array type %d has "
"non-defaultable element type %s",
imm.index, imm.array_type->element_type().name().c_str());
return 0;
}
Value rtt = Pop(1);
if (!VALIDATE(rtt.type.is_rtt() || rtt.type.is_bottom())) {
this->DecodeError(
this->pc_ + opcode_length,
"array.new_default_with_rtt expected rtt, found %s of type %s",
SafeOpcodeNameAt(rtt.pc()), rtt.type.name().c_str());
PopTypeError(1, rtt, "rtt");
return 0;
}
// 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)) {
this->DecodeError(this->pc_ + opcode_length,
"array.new_default_with_rtt expected rtt for type "
"%d, found rtt for type %s",
imm.index, rtt.type.heap_type().name().c_str());
PopTypeError(1, rtt, "rtt for type " + std::to_string(imm.index));
return 0;
}
Value length = Pop(0, kWasmI32);
@ -3946,8 +3913,10 @@ class WasmFullDecoder : public WasmDecoder<validate> {
if (!this->Validate(this->pc_ + opcode_length, imm)) return 0;
if (!VALIDATE(imm.array_type->element_type().is_packed())) {
this->DecodeError(
"%s is only valid for packed arrays. Use array.get instead.",
WasmOpcodes::OpcodeName(opcode));
"%s: Immediate array type %d has non-packed type %s. Use "
"array.get instead.",
WasmOpcodes::OpcodeName(opcode), imm.index,
imm.array_type->element_type().name().c_str());
return 0;
}
Value index = Pop(1, kWasmI32);
@ -3962,8 +3931,9 @@ class WasmFullDecoder : public WasmDecoder<validate> {
if (!this->Validate(this->pc_ + opcode_length, imm)) return 0;
if (!VALIDATE(!imm.array_type->element_type().is_packed())) {
this->DecodeError(
"array.get used with a field of packed type. Use array.get_s or "
"array.get_u instead.");
"array.get: Immediate array type %d has packed type %s. Use "
"array.get_s or array.get_u instead.",
imm.index, imm.array_type->element_type().name().c_str());
return 0;
}
Value index = Pop(1, kWasmI32);
@ -3977,7 +3947,8 @@ class WasmFullDecoder : public WasmDecoder<validate> {
ArrayIndexImmediate<validate> imm(this, this->pc_ + opcode_length);
if (!this->Validate(this->pc_ + opcode_length, imm)) return 0;
if (!VALIDATE(imm.array_type->mutability())) {
this->DecodeError("setting element of immutable array");
this->DecodeError("array.set: immediate array type %d is immutable",
imm.index);
return 0;
}
Value value = Pop(2, imm.array_type->element_type().Unpacked());
@ -4042,7 +4013,8 @@ class WasmFullDecoder : public WasmDecoder<validate> {
ValueType::Ref(parent.type.heap_type(),
kNonNullable),
this->module_))) {
this->DecodeError("rtt.sub requires a supertype rtt on stack");
PopTypeError(0, parent,
"rtt for a supertype of type " + imm.type.name());
return 0;
}
Value* value =
@ -4075,16 +4047,16 @@ class WasmFullDecoder : public WasmDecoder<validate> {
ValueType::Ref(obj_type.type, kNonNullable),
this->module_))) {
this->DecodeError(
"ref.test: rtt type must be subtype of object type");
"ref.test: immediate rtt type %s is not a subtype of immediate "
"object type %s",
rtt_type.type.name().c_str(), obj_type.type.name().c_str());
return 0;
}
Value rtt = Pop(1);
if (!VALIDATE(
(rtt.type.is_rtt() && rtt.type.heap_type() == rtt_type.type) ||
rtt.type == kWasmBottom)) {
this->DecodeError("ref.test: expected rtt for type %s but got %s",
rtt_type.type.name().c_str(),
rtt.type.name().c_str());
PopTypeError(1, rtt, "rtt for type " + rtt_type.type.name());
return 0;
}
Value obj = Pop(0, ValueType::Ref(obj_type.type, kNullable));
@ -4105,16 +4077,16 @@ class WasmFullDecoder : public WasmDecoder<validate> {
ValueType::Ref(obj_type.type, kNonNullable),
this->module_))) {
this->DecodeError(
"ref.cast: rtt type must be subtype of object type");
"ref.test: immediate rtt type %s is not a subtype of immediate "
"object type %s",
rtt_type.type.name().c_str(), obj_type.type.name().c_str());
return 0;
}
Value rtt = Pop(1);
if (!VALIDATE(
(rtt.type.is_rtt() && rtt.type.heap_type() == rtt_type.type) ||
rtt.type == kWasmBottom)) {
this->DecodeError("ref.cast: expected rtt for type %s but got %s",
rtt_type.type.name().c_str(),
rtt.type.name().c_str());
PopTypeError(1, rtt, "rtt for type " + rtt_type.type.name());
return 0;
}
Value obj = Pop(0, ValueType::Ref(obj_type.type, kNullable));
@ -4133,13 +4105,13 @@ class WasmFullDecoder : public WasmDecoder<validate> {
// them here.
Value rtt = Pop(1);
if (!VALIDATE(rtt.type.is_rtt() || rtt.type.is_bottom())) {
this->DecodeError("br_on_cast[1]: expected rtt on stack");
PopTypeError(1, rtt, "rtt");
return 0;
}
Value obj = Pop(0);
if (!VALIDATE(obj.type.is_object_reference_type() ||
rtt.type.is_bottom())) {
this->DecodeError("br_on_cast[0]: expected reference on stack");
PopTypeError(0, obj, "reference");
return 0;
}
// The static type of {obj} must be a supertype of {rtt}'s type.
@ -4148,8 +4120,7 @@ class WasmFullDecoder : public WasmDecoder<validate> {
IsSubtypeOf(ValueType::Ref(rtt.type.heap_type(), kNonNullable),
ValueType::Ref(obj.type.heap_type(), kNonNullable),
this->module_))) {
this->DecodeError(
"br_on_cast: rtt type must be a subtype of object type");
PopTypeError(1, rtt, obj.type);
return 0;
}
Control* c = control_at(branch_depth.depth);
@ -4401,11 +4372,18 @@ class WasmFullDecoder : public WasmDecoder<validate> {
// We do not inline these functions because doing so causes a large binary
// size increase. Not inlining them should not create a performance
// degradation, because their invocations are guarded by V8_LIKELY.
V8_NOINLINE void PopTypeError(int index, Value val, const char* expected) {
this->DecodeError(val.pc(), "%s[%d] expected %s, found %s of type %s",
SafeOpcodeNameAt(this->pc_), index, expected,
SafeOpcodeNameAt(val.pc()), val.type.name().c_str());
}
V8_NOINLINE void PopTypeError(int index, Value val, std::string expected) {
PopTypeError(index, val, expected.c_str());
}
V8_NOINLINE void PopTypeError(int index, Value val, ValueType expected) {
this->DecodeError(val.pc(), "%s[%d] expected type %s, found %s of type %s",
SafeOpcodeNameAt(this->pc_), index,
expected.name().c_str(), SafeOpcodeNameAt(val.pc()),
val.type.name().c_str());
PopTypeError(index, val, ("type " + expected.name()).c_str());
}
V8_NOINLINE void NotEnoughArgumentsError(int index) {

View File

@ -1167,7 +1167,7 @@ TEST_F(FunctionBodyDecoderTest, UnreachableRefTypes) {
ExpectFailure(
sigs.v_v(), {WASM_UNREACHABLE, WASM_I32V(42), kExprBrOnNull, 0},
kAppendEnd,
"br_on_null[0]: Expected object reference, found i32.const of type i32");
"br_on_null[0] expected object reference, found i32.const of type i32");
}
TEST_F(FunctionBodyDecoderTest, If1) {
@ -3706,8 +3706,7 @@ TEST_F(FunctionBodyDecoderTest, RefAsNonNull) {
FunctionSig sig(0, 1, &type);
ExpectFailure(
&sig, {WASM_REF_AS_NON_NULL(WASM_LOCAL_GET(0)), kExprDrop}, kAppendEnd,
"invalid agrument type to ref.as_non_null: Expected reference type, "
"got");
"ref.as_non_null[0] expected reference type, found local.get of type");
}
}
@ -3745,7 +3744,7 @@ TEST_F(FunctionBodyDecoderTest, RefIsNull) {
{WASM_REF_IS_NULL(WASM_REF_NULL(kExternRefCode))});
ExpectFailure(
sigs.i_i(), {WASM_REF_IS_NULL(WASM_LOCAL_GET(0))}, kAppendEnd,
"invalid argument type to ref.is_null. Expected reference type, got i32");
"ref.is_null[0] expected reference type, found local.get of type i32");
TestModuleBuilder builder;
module = builder.module();
@ -3768,7 +3767,7 @@ TEST_F(FunctionBodyDecoderTest, RefIsNull) {
// It fails if the argument type is not a reference type.
ExpectFailure(
sigs.v_v(), {WASM_REF_IS_NULL(WASM_I32V(0)), kExprDrop}, kAppendEnd,
"invalid argument type to ref.is_null. Expected reference type, got ");
"ref.is_null[0] expected reference type, found i32.const of type i32");
}
TEST_F(FunctionBodyDecoderTest, BrOnNull) {
@ -3845,13 +3844,13 @@ TEST_F(FunctionBodyDecoderTest, GCStruct) {
kExprDrop},
kAppendEnd, "invalid struct index: 1");
// Wrongly typed rtt.
ExpectFailure(
sigs.v_v(),
ExpectFailure(sigs.v_v(),
{WASM_STRUCT_NEW_WITH_RTT(struct_type_index, WASM_I32V(0),
WASM_RTT_CANON(array_type_index)),
kExprDrop},
kAppendEnd,
"struct.new_with_rtt expected rtt for type 0, found rtt for type 1");
"struct.new_with_rtt[1] expected rtt for type 0, found "
"rtt.canon of type (rtt 1 1)");
// Out-of-bounds index.
ExpectFailure(sigs.v_v(),
{WASM_STRUCT_NEW_WITH_RTT(42, WASM_I32V(0),
@ -3911,21 +3910,22 @@ TEST_F(FunctionBodyDecoderTest, GCStruct) {
WASM_STRUCT_NEW_WITH_RTT(immutable_struct_type_index, WASM_I32V(42),
WASM_RTT_CANON(immutable_struct_type_index)),
WASM_I32V(0))},
kAppendEnd, "setting immutable struct field");
kAppendEnd, "struct.set: Field 0 of type 2 is immutable.");
// struct.get_s/u fail
ExpectFailure(
&sig_i_r,
{WASM_STRUCT_GET_S(struct_type_index, field_index, WASM_LOCAL_GET(0))},
kAppendEnd,
"struct.get_s is only valid for packed struct fields. Use struct.get "
"instead.");
"struct.get_s: Immediate field 0 of type 0 has non-packed type i32. Use "
"struct.get instead.");
ExpectFailure(
&sig_i_r,
{WASM_STRUCT_GET_U(struct_type_index, field_index, WASM_LOCAL_GET(0))},
kAppendEnd,
"struct.get_u is only valid for packed struct fields. Use struct.get "
"instead.");
"struct.get_u: Immediate field 0 of type 0 has non-packed type i32. Use "
"struct.get instead.");
}
TEST_F(FunctionBodyDecoderTest, GCArray) {
@ -3977,13 +3977,13 @@ TEST_F(FunctionBodyDecoderTest, GCArray) {
kAppendEnd,
"array.new_with_rtt[1] expected type i32, found i64.const of type i64");
// Mistyped rtt.
ExpectFailure(
&sig_r_v,
{WASM_ARRAY_NEW_WITH_RTT(array_type_index, WASM_REF_NULL(kFuncRefCode),
WASM_I32V(5),
ExpectFailure(&sig_r_v,
{WASM_ARRAY_NEW_WITH_RTT(
array_type_index, WASM_REF_NULL(kFuncRefCode), WASM_I32V(5),
WASM_RTT_CANON(struct_type_index))},
kAppendEnd,
"array.new_with_rtt expected rtt for type 0, found rtt for type 1");
"array.new_with_rtt[2] expected rtt for type 0, found "
"rtt.canon of type (rtt 1 1)");
// Wrong type index.
ExpectFailure(
sigs.v_v(),
@ -4018,12 +4018,14 @@ TEST_F(FunctionBodyDecoderTest, GCArray) {
&sig_c_r,
{WASM_ARRAY_GET_S(array_type_index, WASM_LOCAL_GET(0), WASM_I32V(5))},
kAppendEnd,
"array.get_s is only valid for packed arrays. Use array.get instead.");
"array.get_s: Immediate array type 0 has non-packed type funcref. Use "
"array.get instead.");
ExpectFailure(
&sig_c_r,
{WASM_ARRAY_GET_U(array_type_index, WASM_LOCAL_GET(0), WASM_I32V(5))},
kAppendEnd,
"array.get_u is only valid for packed arrays. Use array.get instead.");
"array.get_u: Immediate array type 0 has non-packed type funcref. Use "
"array.get instead.");
/** array.set **/
ExpectValidates(&sig_v_r,
@ -4142,14 +4144,14 @@ TEST_F(FunctionBodyDecoderTest, PackedFields) {
{WASM_ARRAY_GET(array_type_index,
WASM_REF_NULL(array_type_index), WASM_I32V(0))},
kAppendEnd,
"array.get used with a field of packed type. Use array.get_s "
"or array.get_u instead.");
"array.get: Immediate array type 0 has packed type i8. Use "
"array.get_s or array.get_u instead.");
ExpectFailure(sigs.i_v(),
{WASM_STRUCT_GET(struct_type_index, field_index,
WASM_REF_NULL(struct_type_index))},
kAppendEnd,
"struct.get used with a field of packed type. Use struct.get_s "
"or struct.get_u instead.");
"struct.get: Immediate field 0 of type 1 has packed type i16. "
"Use struct.get_s or struct.get_u instead.");
}
TEST_F(FunctionBodyDecoderTest, PackedTypesAsLocals) {
@ -4242,15 +4244,15 @@ TEST_F(FunctionBodyDecoderTest, RttSub) {
{
ValueType type = ValueType::Rtt(HeapType::kFunc, 2);
FunctionSig sig(1, 0, &type);
ExpectFailure(&sig,
{WASM_RTT_SUB(kFuncRefCode, WASM_RTT_CANON(kI31RefCode))},
kAppendEnd, "rtt.sub requires a supertype rtt on stack");
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 requires a supertype rtt on stack");
ExpectFailure(
sigs.v_v(), {WASM_RTT_SUB(kFuncRefCode, WASM_I32V(42)), kExprDrop},
kAppendEnd, "rtt.sub[0] expected rtt for a supertype of type func");
{
ValueType type = ValueType::Rtt(array_type_index, 2);
@ -4265,7 +4267,7 @@ TEST_F(FunctionBodyDecoderTest, RttSub) {
ExpectFailure(
sigs.v_v(),
{WASM_RTT_SUB(kEqRefCode, WASM_RTT_CANON(array_type_index)), kExprDrop},
kAppendEnd, "rtt.sub requires a supertype rtt on stack");
kAppendEnd, "rtt.sub[0] expected rtt for a supertype of type eq");
}
{
@ -4282,11 +4284,13 @@ TEST_F(FunctionBodyDecoderTest, RttSub) {
ExpectFailure(sigs.v_v(),
{WASM_RTT_SUB(super_struct_type_index,
WASM_RTT_CANON(array_type_index))},
kAppendEnd, "rtt.sub requires a supertype rtt on stack");
kAppendEnd,
"rtt.sub[0] expected rtt for a supertype of type 1");
ExpectFailure(sigs.v_v(),
{WASM_RTT_SUB(super_struct_type_index,
WASM_RTT_CANON(sub_struct_type_index))},
kAppendEnd, "rtt.sub requires a supertype rtt on stack");
kAppendEnd,
"rtt.sub[0] expected rtt for a supertype of type 1");
}
{
@ -4361,14 +4365,12 @@ TEST_F(FunctionBodyDecoderTest, RefTestCast) {
{WASM_REF_TEST(WASM_HEAP_TYPE(from_heap),
WASM_HEAP_TYPE(to_heap), WASM_LOCAL_GET(0),
WASM_RTT_CANON(WASM_HEAP_TYPE(to_heap)))},
kAppendEnd,
"ref.test: rtt type must be subtype of object type");
kAppendEnd, "is not a subtype of immediate object type");
ExpectFailure(&cast_sig,
{WASM_REF_CAST(WASM_HEAP_TYPE(from_heap),
WASM_HEAP_TYPE(to_heap), WASM_LOCAL_GET(0),
WASM_RTT_CANON(WASM_HEAP_TYPE(to_heap)))},
kAppendEnd,
"ref.cast: rtt type must be subtype of object type");
kAppendEnd, "is not a subtype of immediate object type");
}
// Trivial type error.
@ -4394,13 +4396,17 @@ TEST_F(FunctionBodyDecoderTest, RefTestCast) {
{WASM_REF_TEST(kEqRefCode, static_cast<byte>(array_heap),
WASM_LOCAL_GET(0), WASM_RTT_CANON(kI31RefCode)),
kExprDrop},
kAppendEnd, "ref.test: expected rtt for type 0 but got (rtt 1 i31)");
kAppendEnd,
"ref.test[1] expected rtt for type 0, found rtt.canon of type (rtt 1 "
"i31)");
ExpectFailure(
&sig,
{WASM_REF_CAST(kEqRefCode, static_cast<byte>(array_heap),
WASM_LOCAL_GET(0), WASM_RTT_CANON(kI31RefCode)),
kExprDrop},
kAppendEnd, "ref.cast: expected rtt for type 0 but got (rtt 1 i31)");
kAppendEnd,
"ref.cast[1] expected rtt for type 0, found rtt.canon of type (rtt 1 "
"i31)");
}
}