[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:
parent
1a9d6c399e
commit
0979f724de
@ -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) {
|
||||||
|
@ -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)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user