Commit 7ae8c713 authored by Manos Koukoutos's avatar Manos Koukoutos Committed by Commit Bot

[wasm-gc] Remove excess immediate from ref.cast/test

According to the latest wasm-gc spec, the type immediate for the
argument's heap type is no longer required. This CL also adds a missing
check that the rtt immediate is a subtype of the argument's type.

Bug: v8:7742
Change-Id: I627002d1c4bdb4ca3f2181d2f4b659ce3e95cb2d
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2642246
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#72287}
parent c44d7ffb
......@@ -1909,11 +1909,9 @@ class WasmDecoder : public Decoder {
return length;
case kExprRefTest:
case kExprRefCast: {
HeapTypeImmediate<validate> ht1(WasmFeatures::All(), decoder,
pc + length, nullptr);
HeapTypeImmediate<validate> ht2(WasmFeatures::All(), decoder,
pc + length + ht1.length, nullptr);
return length + ht1.length + ht2.length;
HeapTypeImmediate<validate> ht(WasmFeatures::All(), decoder,
pc + length, nullptr);
return length + ht.length;
}
default:
// This is unreachable except for malformed modules.
......@@ -4012,12 +4010,6 @@ class WasmFullDecoder : public WasmDecoder<validate> {
return opcode_length + imm.length;
}
case kExprRttSub: {
// TODO(7748): The proposal currently includes additional immediates
// here: the subtyping depth <n> and the "parent type", see:
// https://github.com/WebAssembly/gc/commit/20a80e34 .
// If these immediates don't get dropped (in the spirit of
// https://github.com/WebAssembly/function-references/pull/31 ),
// implement them here.
HeapTypeImmediate<validate> imm(
this->enabled_, this, this->pc_ + opcode_length, this->module_);
if (!VALIDATE(this->ok())) return 0;
......@@ -4049,23 +4041,9 @@ class WasmFullDecoder : public WasmDecoder<validate> {
}
case kExprRefTest: {
// "Tests whether {obj}'s runtime type is a runtime subtype of {rtt}."
HeapTypeImmediate<validate> obj_type(
HeapTypeImmediate<validate> rtt_type(
this->enabled_, this, this->pc_ + opcode_length, this->module_);
int len = opcode_length + obj_type.length;
HeapTypeImmediate<validate> rtt_type(this->enabled_, this,
this->pc_ + len, this->module_);
len += rtt_type.length;
if (!VALIDATE(this->ok())) return 0;
// The static type of {obj} must be a supertype of the {rtt}'s type.
if (!VALIDATE(
IsHeapSubtypeOf(rtt_type.type, obj_type.type, this->module_))) {
this->DecodeError(
"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) ||
......@@ -4073,28 +4051,22 @@ class WasmFullDecoder : public WasmDecoder<validate> {
PopTypeError(1, rtt, "rtt for type " + rtt_type.type.name());
return 0;
}
Value obj = Pop(0, ValueType::Ref(obj_type.type, kNullable));
Value obj = Pop(0, kWasmAnyRef);
Value* value = Push(kWasmI32);
CALL_INTERFACE_IF_REACHABLE(RefTest, obj, rtt, value);
return len;
if (obj.type != kWasmBottom) {
if (!VALIDATE(IsSubtypeOf(ValueType::Ref(rtt_type.type, kNonNullable),
obj.type, this->module_))) {
PopTypeError(0, obj, "supertype of type " + rtt_type.type.name());
return 0;
}
CALL_INTERFACE_IF_REACHABLE(RefTest, obj, rtt, value);
}
return opcode_length + rtt_type.length;
}
case kExprRefCast: {
HeapTypeImmediate<validate> obj_type(
HeapTypeImmediate<validate> rtt_type(
this->enabled_, this, this->pc_ + opcode_length, this->module_);
int len = opcode_length + obj_type.length;
HeapTypeImmediate<validate> rtt_type(this->enabled_, this,
this->pc_ + len, this->module_);
len += rtt_type.length;
if (!VALIDATE(this->ok())) return 0;
if (!VALIDATE(
IsHeapSubtypeOf(rtt_type.type, obj_type.type, this->module_))) {
this->DecodeError(
"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) ||
......@@ -4102,10 +4074,17 @@ class WasmFullDecoder : public WasmDecoder<validate> {
PopTypeError(1, rtt, "rtt for type " + rtt_type.type.name());
return 0;
}
Value obj = Pop(0, ValueType::Ref(obj_type.type, kNullable));
Value obj = Pop(0, kWasmAnyRef);
Value* value = Push(ValueType::Ref(rtt_type.type, kNonNullable));
CALL_INTERFACE_IF_REACHABLE(RefCast, obj, rtt, value);
return len;
if (obj.type != kWasmBottom) {
if (!VALIDATE(IsSubtypeOf(ValueType::Ref(rtt_type.type, kNonNullable),
obj.type, this->module_))) {
PopTypeError(0, obj, "supertype of type " + rtt_type.type.name());
return 0;
}
CALL_INTERFACE_IF_REACHABLE(RefCast, obj, rtt, value);
}
return opcode_length + rtt_type.length;
}
case kExprBrOnCast: {
BranchDepthImmediate<validate> branch_depth(this,
......
......@@ -850,13 +850,12 @@ TEST(BasicRTT) {
subtype_index, WASM_I32V(11), WASM_I32V(42),
WASM_LOCAL_GET(kRttIndexCode))),
WASM_I32_ADD(
WASM_REF_TEST(type_index, subtype_index,
WASM_LOCAL_GET(kStructIndexCode),
WASM_REF_TEST(subtype_index, WASM_LOCAL_GET(kStructIndexCode),
WASM_LOCAL_GET(kRttIndexCode)),
WASM_STRUCT_GET(subtype_index, kFieldIndex,
WASM_REF_CAST(type_index, 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();
......@@ -933,15 +932,14 @@ WASM_COMPILED_EXEC_TEST(AnyRefRtt) {
tester.sigs.i_v(), {kWasmAnyRef},
{WASM_LOCAL_SET(0, WASM_ARRAY_NEW_DEFAULT(type_index, WASM_I32V(5),
WASM_RTT_CANON(type_index))),
WASM_REF_TEST(kAnyRefCode, type_index, WASM_LOCAL_GET(0),
WASM_RTT_CANON(type_index)),
WASM_REF_TEST(type_index, WASM_LOCAL_GET(0), WASM_RTT_CANON(type_index)),
kExprEnd});
byte kCheckAnyAgainstAny = tester.DefineFunction(
tester.sigs.i_v(), {kWasmAnyRef},
{WASM_LOCAL_SET(0, WASM_ARRAY_NEW_DEFAULT(type_index, WASM_I32V(5),
WASM_RTT_CANON(type_index))),
WASM_REF_TEST(kAnyRefCode, kAnyRefCode, WASM_LOCAL_GET(0),
WASM_REF_TEST(kAnyRefCode, WASM_LOCAL_GET(0),
WASM_RTT_CANON(kAnyRefCode)),
kExprEnd});
......@@ -1030,19 +1028,18 @@ WASM_COMPILED_EXEC_TEST(FunctionRefs) {
const byte cast = tester.DefineFunction(
&sig_func, {kWasmFuncRef},
{WASM_LOCAL_SET(0, WASM_REF_FUNC(func_index)),
WASM_REF_CAST(kFuncRefCode, sig_index, WASM_LOCAL_GET(0),
WASM_RTT_CANON(sig_index)),
WASM_REF_CAST(sig_index, WASM_LOCAL_GET(0), WASM_RTT_CANON(sig_index)),
kExprEnd});
const byte cast_reference = tester.DefineFunction(
&sig_func, {}, {WASM_REF_FUNC(sig_index), kExprEnd});
const byte test = tester.DefineFunction(
tester.sigs.i_v(), {kWasmFuncRef},
{WASM_LOCAL_SET(0, WASM_REF_FUNC(func_index)),
WASM_REF_TEST(kFuncRefCode, other_sig_index, WASM_LOCAL_GET(0),
WASM_RTT_CANON(other_sig_index)),
kExprEnd});
const byte test =
tester.DefineFunction(tester.sigs.i_v(), {kWasmFuncRef},
{WASM_LOCAL_SET(0, WASM_REF_FUNC(func_index)),
WASM_REF_TEST(other_sig_index, WASM_LOCAL_GET(0),
WASM_RTT_CANON(other_sig_index)),
kExprEnd});
tester.CompileModule();
......@@ -1100,14 +1097,14 @@ WASM_COMPILED_EXEC_TEST(RefTestCastNull) {
const byte kRefTestNull = tester.DefineFunction(
tester.sigs.i_v(), {},
{WASM_REF_TEST(type_index, type_index, WASM_REF_NULL(type_index),
{WASM_REF_TEST(type_index, WASM_REF_NULL(type_index),
WASM_RTT_CANON(type_index)),
kExprEnd});
const byte kRefCastNull = tester.DefineFunction(
tester.sigs.i_i(), // Argument and return value ignored
{},
{WASM_REF_CAST(type_index, type_index, WASM_REF_NULL(type_index),
{WASM_REF_CAST(type_index, WASM_REF_NULL(type_index),
WASM_RTT_CANON(type_index)),
kExprDrop, WASM_I32V(0), kExprEnd});
tester.CompileModule();
......@@ -1151,43 +1148,42 @@ WASM_COMPILED_EXEC_TEST(I31Casts) {
const byte kTestAndCastSuccess = tester.DefineFunction(
tester.sigs.i_v(), {kWasmEqRef},
{WASM_LOCAL_SET(0, WASM_I31_NEW(WASM_I32V(42))),
WASM_I32_ADD(WASM_REF_TEST(kEqRefCode, kI31RefCode, WASM_LOCAL_GET(0),
WASM_I32_ADD(WASM_REF_TEST(kI31RefCode, WASM_LOCAL_GET(0),
WASM_GLOBAL_GET(i31_rtt)),
WASM_I31_GET_S(WASM_REF_CAST(kEqRefCode, kI31RefCode,
WASM_LOCAL_GET(0),
WASM_I31_GET_S(WASM_REF_CAST(kI31RefCode, WASM_LOCAL_GET(0),
WASM_GLOBAL_GET(i31_rtt)))),
kExprEnd});
// Adds the results of two unsuccessful type checks (an i31ref is not a
// struct, nor the other way round).
const byte kTestFalse = tester.DefineFunction(
tester.sigs.i_v(), {},
{WASM_I32_ADD(
WASM_REF_TEST(kEqRefCode, kI31RefCode,
WASM_STRUCT_NEW_WITH_RTT(struct_type, WASM_I32V(42),
WASM_GLOBAL_GET(struct_rtt)),
WASM_GLOBAL_GET(i31_rtt)),
WASM_REF_TEST(kEqRefCode, struct_type, WASM_I31_NEW(WASM_I32V(23)),
WASM_GLOBAL_GET(struct_rtt))),
tester.sigs.i_v(), {kWasmAnyRef},
{WASM_LOCAL_SET(0, WASM_STRUCT_NEW_WITH_RTT(struct_type, WASM_I32V(42),
WASM_GLOBAL_GET(struct_rtt))),
WASM_I32_ADD(WASM_REF_TEST(kI31RefCode, WASM_LOCAL_GET(0),
WASM_GLOBAL_GET(i31_rtt)),
WASM_SEQ(WASM_LOCAL_SET(0, WASM_I31_NEW(WASM_I32V(23))),
WASM_REF_TEST(struct_type, WASM_LOCAL_GET(0),
WASM_GLOBAL_GET(struct_rtt)))),
kExprEnd});
// Tries to cast an i31ref to a struct, which should trap.
const byte kCastI31ToStruct = tester.DefineFunction(
tester.sigs.i_i(), // Argument and return value ignored
{},
{WASM_STRUCT_GET(
struct_type, 0,
WASM_REF_CAST(kEqRefCode, struct_type, WASM_I31_NEW(WASM_I32V(42)),
WASM_GLOBAL_GET(struct_rtt))),
{kWasmAnyRef},
{WASM_LOCAL_SET(1, WASM_I31_NEW(WASM_I32V(42))),
WASM_STRUCT_GET(struct_type, 0,
WASM_REF_CAST(struct_type, WASM_LOCAL_GET(1),
WASM_GLOBAL_GET(struct_rtt))),
kExprEnd});
// Tries to cast a struct to i31ref, which should trap.
const byte kCastStructToI31 = tester.DefineFunction(
tester.sigs.i_i(), // Argument and return value ignored
{},
{WASM_I31_GET_S(
WASM_REF_CAST(kEqRefCode, kI31RefCode,
WASM_STRUCT_NEW_WITH_RTT(struct_type, WASM_I32V(42),
WASM_GLOBAL_GET(struct_rtt)),
WASM_GLOBAL_GET(i31_rtt))),
{kWasmAnyRef},
{WASM_LOCAL_SET(1, WASM_STRUCT_NEW_WITH_RTT(struct_type, WASM_I32V(42),
WASM_GLOBAL_GET(struct_rtt))),
WASM_I31_GET_S(WASM_REF_CAST(kI31RefCode, WASM_LOCAL_GET(1),
WASM_GLOBAL_GET(i31_rtt))),
kExprEnd});
tester.CompileModule();
tester.CheckResult(kTestAndCastSuccess, 43);
tester.CheckResult(kTestFalse, 0);
......@@ -1275,7 +1271,7 @@ WASM_COMPILED_EXEC_TEST(CastsBenchmark) {
WASM_STRUCT_GET(
SuperType, 0,
WASM_REF_CAST(
kEqRefCode, SuperType,
SuperType,
WASM_ARRAY_GET(
ListType, WASM_LOCAL_GET(list),
WASM_I32_AND(WASM_LOCAL_GET(i),
......@@ -1350,10 +1346,9 @@ TEST(JsAccess) {
kExprEnd});
tester.DefineExportedFunction(
"consumer", &sig_i_super,
{WASM_STRUCT_GET(
type_index, 0,
WASM_REF_CAST(supertype.value_type_code(), type_index,
WASM_LOCAL_GET(0), WASM_RTT_CANON(type_index))),
{WASM_STRUCT_GET(type_index, 0,
WASM_REF_CAST(type_index, WASM_LOCAL_GET(0),
WASM_RTT_CANON(type_index))),
kExprEnd});
tester.CompileModule();
......
......@@ -501,10 +501,10 @@ inline WasmOpcode LoadStoreOpcodeOf(MachineType type, bool store) {
#define WASM_REF_IS_NULL(val) val, kExprRefIsNull
#define WASM_REF_AS_NON_NULL(val) val, kExprRefAsNonNull
#define WASM_REF_EQ(lhs, rhs) lhs, rhs, kExprRefEq
#define WASM_REF_TEST(obj_type, rtt_type, ref, rtt) \
ref, rtt, WASM_GC_OP(kExprRefTest), obj_type, rtt_type
#define WASM_REF_CAST(obj_type, rtt_type, ref, rtt) \
ref, rtt, WASM_GC_OP(kExprRefCast), obj_type, rtt_type
#define WASM_REF_TEST(rtt_type, ref, rtt) \
ref, rtt, WASM_GC_OP(kExprRefTest), rtt_type
#define WASM_REF_CAST(rtt_type, ref, rtt) \
ref, rtt, WASM_GC_OP(kExprRefCast), rtt_type
// Takes a reference value from the value stack to allow sequences of
// conditional branches.
#define WASM_BR_ON_CAST(depth, rtt) \
......
......@@ -4300,12 +4300,10 @@ TEST_F(FunctionBodyDecoderTest, RefTestCast) {
ValueType::Ref(from_heap, kNullable)};
FunctionSig cast_sig(1, 1, cast_reps);
ExpectValidates(&test_sig,
{WASM_REF_TEST(WASM_HEAP_TYPE(from_heap),
WASM_HEAP_TYPE(to_heap), WASM_LOCAL_GET(0),
{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(from_heap),
WASM_HEAP_TYPE(to_heap), WASM_LOCAL_GET(0),
{WASM_REF_CAST(WASM_HEAP_TYPE(to_heap), WASM_LOCAL_GET(0),
WASM_RTT_CANON(WASM_HEAP_TYPE(to_heap)))});
}
......@@ -4324,31 +4322,33 @@ TEST_F(FunctionBodyDecoderTest, RefTestCast) {
ValueType cast_reps[] = {ValueType::Ref(to_heap, kNonNullable),
ValueType::Ref(from_heap, kNullable)};
FunctionSig cast_sig(1, 1, cast_reps);
std::string error_message = "[0] expected supertype of type " +
to_heap.name() + ", found local.get of type " +
test_reps[1].name();
ExpectFailure(&test_sig,
{WASM_REF_TEST(WASM_HEAP_TYPE(from_heap),
WASM_HEAP_TYPE(to_heap), WASM_LOCAL_GET(0),
{WASM_REF_TEST(WASM_HEAP_TYPE(to_heap), WASM_LOCAL_GET(0),
WASM_RTT_CANON(WASM_HEAP_TYPE(to_heap)))},
kAppendEnd, "is not a subtype of immediate object type");
kAppendEnd, ("ref.test" + error_message).c_str());
ExpectFailure(&cast_sig,
{WASM_REF_CAST(WASM_HEAP_TYPE(from_heap),
WASM_HEAP_TYPE(to_heap), WASM_LOCAL_GET(0),
{WASM_REF_CAST(WASM_HEAP_TYPE(to_heap), WASM_LOCAL_GET(0),
WASM_RTT_CANON(WASM_HEAP_TYPE(to_heap)))},
kAppendEnd, "is not a subtype of immediate object type");
kAppendEnd, ("ref.cast" + error_message).c_str());
}
// Trivial type error.
ExpectFailure(sigs.v_v(),
{WASM_REF_TEST(kEqRefCode, kI31RefCode, WASM_I32V(1),
WASM_RTT_CANON(kI31RefCode)),
kExprDrop},
kAppendEnd,
"ref.test[0] expected type eqref, found i32.const of type i32");
ExpectFailure(sigs.v_v(),
{WASM_REF_CAST(kEqRefCode, kI31RefCode, WASM_I32V(1),
WASM_RTT_CANON(kI31RefCode)),
kExprDrop},
kAppendEnd,
"ref.cast[0] expected type eqref, found i32.const of type i32");
ExpectFailure(
sigs.v_v(),
{WASM_REF_TEST(kI31RefCode, WASM_I32V(1), WASM_RTT_CANON(kI31RefCode)),
kExprDrop},
kAppendEnd,
"ref.test[0] expected type anyref, found i32.const of type i32");
ExpectFailure(
sigs.v_v(),
{WASM_REF_CAST(kI31RefCode, WASM_I32V(1), WASM_RTT_CANON(kI31RefCode)),
kExprDrop},
kAppendEnd,
"ref.cast[0] expected type anyref, found i32.const of type i32");
// Mismached object heap immediate.
{
......@@ -4356,16 +4356,16 @@ TEST_F(FunctionBodyDecoderTest, RefTestCast) {
FunctionSig sig(0, 1, &arg_type);
ExpectFailure(
&sig,
{WASM_REF_TEST(kEqRefCode, static_cast<byte>(array_heap),
WASM_LOCAL_GET(0), WASM_RTT_CANON(kI31RefCode)),
{WASM_REF_TEST(static_cast<byte>(array_heap), WASM_LOCAL_GET(0),
WASM_RTT_CANON(kI31RefCode)),
kExprDrop},
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)),
{WASM_REF_CAST(static_cast<byte>(array_heap), WASM_LOCAL_GET(0),
WASM_RTT_CANON(kI31RefCode)),
kExprDrop},
kAppendEnd,
"ref.cast[1] expected rtt for type 0, found rtt.canon of type (rtt 1 "
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment