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

View File

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