[wasm-gc] Test improvements/additions.

Changes:
- Fix error message typo in function-body-decoder.
- Generalize wasm test macros related to reference types.
- Change wasm-gc test API to return bytes.
- Add unittests for ref.test/cast.

Bug: v8:7748
Change-Id: I361987e0b6ac90c4e89a49a8abc125757a5fc8d0
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2317319
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#69220}
This commit is contained in:
Manos Koukoutos 2020-08-04 09:13:30 +00:00 committed by Commit Bot
parent 09fcc0628a
commit 65530e72e1
4 changed files with 203 additions and 103 deletions

View File

@ -3646,7 +3646,7 @@ class WasmFullDecoder : public WasmDecoder<validate> {
ValueType::Ref(obj_type.type, kNonNullable),
this->module_))) {
this->errorf(this->pc_,
"ret.cast: rtt type must be subtype of object type");
"ref.cast: rtt type must be subtype of object type");
return 0;
}
Value rtt = Pop(1);

View File

@ -43,13 +43,12 @@ class WasmGCTester {
testing::SetupIsolateForWasmModule(isolate_);
}
uint32_t AddGlobal(ValueType type, bool mutability, WasmInitExpr init) {
byte AddGlobal(ValueType type, bool mutability, WasmInitExpr init) {
return builder_.AddGlobal(type, mutability, std::move(init));
}
uint32_t DefineFunction(FunctionSig* sig,
std::initializer_list<ValueType> locals,
std::initializer_list<byte> code) {
byte DefineFunction(FunctionSig* sig, std::initializer_list<ValueType> locals,
std::initializer_list<byte> code) {
WasmFunctionBuilder* fun = builder_.AddFunction(sig);
for (ValueType local : locals) {
fun->AddLocal(local);
@ -74,7 +73,7 @@ class WasmGCTester {
isolate_->factory()->undefined_value(), argc, args);
}
uint32_t DefineStruct(std::initializer_list<F> fields) {
byte DefineStruct(std::initializer_list<F> fields) {
StructType::Builder type_builder(&zone,
static_cast<uint32_t>(fields.size()));
for (F field : fields) {
@ -83,7 +82,7 @@ class WasmGCTester {
return builder_.AddStructType(type_builder.Build());
}
uint32_t DefineArray(ValueType element_type, bool mutability) {
byte DefineArray(ValueType element_type, bool mutability) {
return builder_.AddArrayType(zone.New<ArrayType>(element_type, mutability));
}
@ -177,14 +176,14 @@ ValueType optref(uint32_t type_index) {
// TODO(7748): Use WASM_EXEC_TEST once interpreter and liftoff are supported.
TEST(WasmBasicStruct) {
WasmGCTester tester;
uint32_t type_index =
const byte type_index =
tester.DefineStruct({F(kWasmI32, true), F(kWasmI32, true)});
ValueType kRefTypes[] = {ref(type_index)};
ValueType kOptRefType = optref(type_index);
FunctionSig sig_q_v(1, 0, kRefTypes);
// Test struct.new and struct.get.
const uint32_t kGet1 = tester.DefineFunction(
const byte kGet1 = tester.DefineFunction(
tester.sigs.i_v(), {},
{WASM_STRUCT_GET(
type_index, 0,
@ -193,7 +192,7 @@ TEST(WasmBasicStruct) {
kExprEnd});
// Test struct.new and struct.get.
const uint32_t kGet2 = tester.DefineFunction(
const byte kGet2 = tester.DefineFunction(
tester.sigs.i_v(), {},
{WASM_STRUCT_GET(
type_index, 1,
@ -202,16 +201,16 @@ TEST(WasmBasicStruct) {
kExprEnd});
// Test struct.new, returning struct reference.
const uint32_t kGetStruct = tester.DefineFunction(
const byte kGetStruct = tester.DefineFunction(
&sig_q_v, {},
{WASM_STRUCT_NEW_WITH_RTT(type_index, WASM_I32V(42), WASM_I32V(64),
WASM_RTT_CANON(type_index)),
kExprEnd});
// Test struct.set, struct refs types in locals.
uint32_t j_local_index = 0;
uint32_t j_field_index = 0;
const uint32_t kSet = tester.DefineFunction(
const byte j_local_index = 0;
const byte j_field_index = 0;
const byte kSet = tester.DefineFunction(
tester.sigs.i_v(), {kOptRefType},
{WASM_SET_LOCAL(
j_local_index,
@ -235,18 +234,18 @@ TEST(WasmBasicStruct) {
// struct refs types in globals and if-results.
TEST(WasmRefAsNonNull) {
WasmGCTester tester;
uint32_t type_index =
const byte type_index =
tester.DefineStruct({F(kWasmI32, true), F(kWasmI32, true)});
ValueType kRefTypes[] = {ref(type_index)};
ValueType kOptRefType = optref(type_index);
FunctionSig sig_q_v(1, 0, kRefTypes);
uint32_t global_index =
const byte global_index =
tester.AddGlobal(kOptRefType, true,
WasmInitExpr::RefNullConst(
static_cast<HeapType::Representation>(type_index)));
uint32_t field_index = 0;
const uint32_t kFunc = tester.DefineFunction(
const byte field_index = 0;
const byte kFunc = tester.DefineFunction(
tester.sigs.i_v(), {},
{WASM_SET_GLOBAL(
global_index,
@ -254,9 +253,9 @@ TEST(WasmRefAsNonNull) {
WASM_RTT_CANON(type_index))),
WASM_STRUCT_GET(
type_index, field_index,
WASM_REF_AS_NON_NULL(WASM_IF_ELSE_R(
kOptRefType, WASM_I32V(1), WASM_GET_GLOBAL(global_index),
WASM_REF_NULL(static_cast<byte>(type_index))))),
WASM_REF_AS_NON_NULL(WASM_IF_ELSE_R(kOptRefType, WASM_I32V(1),
WASM_GET_GLOBAL(global_index),
WASM_REF_NULL(type_index)))),
kExprEnd});
tester.CompileModule();
@ -265,13 +264,13 @@ TEST(WasmRefAsNonNull) {
TEST(WasmBrOnNull) {
WasmGCTester tester;
uint32_t type_index =
const byte type_index =
tester.DefineStruct({F(kWasmI32, true), F(kWasmI32, true)});
ValueType kRefTypes[] = {ref(type_index)};
ValueType kOptRefType = optref(type_index);
FunctionSig sig_q_v(1, 0, kRefTypes);
uint32_t l_local_index = 0;
const uint32_t kTaken = tester.DefineFunction(
const byte l_local_index = 0;
const byte kTaken = tester.DefineFunction(
tester.sigs.i_v(), {kOptRefType},
{WASM_BLOCK_I(WASM_I32V(42),
// Branch will be taken.
@ -280,8 +279,8 @@ TEST(WasmBrOnNull) {
WASM_I32V(52), WASM_BR(0)),
kExprEnd});
uint32_t m_field_index = 0;
const uint32_t kNotTaken = tester.DefineFunction(
const byte m_field_index = 0;
const byte kNotTaken = tester.DefineFunction(
tester.sigs.i_v(), {},
{WASM_BLOCK_I(
WASM_I32V(42),
@ -302,12 +301,12 @@ TEST(WasmBrOnNull) {
TEST(BrOnCast) {
WasmGCTester tester;
uint32_t type_index = tester.DefineStruct({F(kWasmI32, true)});
uint32_t rtt_index =
const byte type_index = tester.DefineStruct({F(kWasmI32, true)});
const byte rtt_index =
tester.AddGlobal(ValueType::Rtt(type_index, 1), false,
WasmInitExpr::RttCanon(
static_cast<HeapType::Representation>(type_index)));
const uint32_t kTestStruct = tester.DefineFunction(
const byte kTestStruct = tester.DefineFunction(
tester.sigs.i_v(), {kWasmI32, kWasmEqRef},
{WASM_BLOCK(WASM_SET_LOCAL(0, WASM_I32V(111)),
// Pipe a struct through a local so it's statically typed
@ -325,7 +324,7 @@ TEST(BrOnCast) {
WASM_DROP, WASM_SET_LOCAL(0, WASM_I32V(333))),
WASM_GET_LOCAL(0), kExprEnd});
const uint32_t kTestI31 = tester.DefineFunction(
const byte kTestI31 = tester.DefineFunction(
tester.sigs.i_v(), {kWasmI32, kWasmEqRef},
{WASM_BLOCK(WASM_SET_LOCAL(0, WASM_I32V(111)),
// Pipe an i31ref through a local so it's statically typed
@ -341,7 +340,7 @@ TEST(BrOnCast) {
WASM_DROP, WASM_SET_LOCAL(0, WASM_I32V(333))),
WASM_GET_LOCAL(0), kExprEnd});
const uint32_t kTestNull = tester.DefineFunction(
const byte kTestNull = tester.DefineFunction(
tester.sigs.i_v(), {kWasmI32, kWasmEqRef},
{WASM_BLOCK(WASM_SET_LOCAL(0, WASM_I32V(111)),
WASM_GET_LOCAL(1), // Put a nullref onto the value stack.
@ -352,7 +351,7 @@ TEST(BrOnCast) {
WASM_SET_LOCAL(0, WASM_I32V(333))), // Final result.
WASM_GET_LOCAL(0), kExprEnd});
const uint32_t kTypedAfterBranch = tester.DefineFunction(
const byte kTypedAfterBranch = tester.DefineFunction(
tester.sigs.i_v(), {kWasmI32, kWasmEqRef},
{WASM_SET_LOCAL(1, WASM_STRUCT_NEW_WITH_RTT(type_index, WASM_I32V(42),
WASM_GET_GLOBAL(rtt_index))),
@ -380,14 +379,13 @@ TEST(BrOnCast) {
TEST(WasmRefEq) {
WasmGCTester tester;
byte type_index = static_cast<byte>(
tester.DefineStruct({F(kWasmI32, true), F(kWasmI32, true)}));
byte type_index = tester.DefineStruct({F(kWasmI32, true), F(kWasmI32, true)});
ValueType kRefTypes[] = {ref(type_index)};
ValueType kOptRefType = optref(type_index);
FunctionSig sig_q_v(1, 0, kRefTypes);
byte local_index = 0;
const uint32_t kFunc = tester.DefineFunction(
const byte kFunc = tester.DefineFunction(
tester.sigs.i_v(), {kOptRefType},
{WASM_SET_LOCAL(local_index, WASM_STRUCT_NEW_WITH_RTT(
type_index, WASM_I32V(55), WASM_I32V(66),
@ -421,16 +419,16 @@ TEST(WasmRefEq) {
TEST(WasmPackedStructU) {
WasmGCTester tester;
uint32_t type_index = tester.DefineStruct(
const byte type_index = tester.DefineStruct(
{F(kWasmI8, true), F(kWasmI16, true), F(kWasmI32, true)});
ValueType struct_type = optref(type_index);
uint32_t local_index = 0;
const byte local_index = 0;
int32_t expected_output_0 = 0x1234;
int32_t expected_output_1 = -1;
const uint32_t kF0 = tester.DefineFunction(
const byte kF0 = tester.DefineFunction(
tester.sigs.i_v(), {struct_type},
{WASM_SET_LOCAL(local_index,
WASM_STRUCT_NEW_WITH_RTT(
@ -440,7 +438,7 @@ TEST(WasmPackedStructU) {
WASM_STRUCT_GET_U(type_index, 0, WASM_GET_LOCAL(local_index)),
kExprEnd});
const uint32_t kF1 = tester.DefineFunction(
const byte kF1 = tester.DefineFunction(
tester.sigs.i_v(), {struct_type},
{WASM_SET_LOCAL(local_index,
WASM_STRUCT_NEW_WITH_RTT(
@ -458,16 +456,16 @@ TEST(WasmPackedStructU) {
TEST(WasmPackedStructS) {
WasmGCTester tester;
uint32_t type_index = tester.DefineStruct(
const byte type_index = tester.DefineStruct(
{F(kWasmI8, true), F(kWasmI16, true), F(kWasmI32, true)});
ValueType struct_type = optref(type_index);
uint32_t local_index = 0;
const byte local_index = 0;
int32_t expected_output_0 = 0x80;
int32_t expected_output_1 = 42;
const uint32_t kF0 = tester.DefineFunction(
const byte kF0 = tester.DefineFunction(
tester.sigs.i_v(), {struct_type},
{WASM_SET_LOCAL(
local_index,
@ -477,7 +475,7 @@ TEST(WasmPackedStructS) {
WASM_STRUCT_GET_S(type_index, 0, WASM_GET_LOCAL(local_index)),
kExprEnd});
const uint32_t kF1 = tester.DefineFunction(
const byte kF1 = tester.DefineFunction(
tester.sigs.i_v(), {struct_type},
{WASM_SET_LOCAL(
local_index,
@ -495,27 +493,27 @@ TEST(WasmPackedStructS) {
TEST(WasmLetInstruction) {
WasmGCTester tester;
uint32_t type_index =
const byte type_index =
tester.DefineStruct({F(kWasmI32, true), F(kWasmI32, true)});
uint32_t let_local_index = 0;
uint32_t let_field_index = 0;
const uint32_t kLetTest1 = tester.DefineFunction(
const byte let_local_index = 0;
const byte let_field_index = 0;
const byte kLetTest1 = tester.DefineFunction(
tester.sigs.i_v(), {},
{WASM_LET_1_I(
WASM_SEQ(kLocalRef, static_cast<byte>(type_index)),
WASM_SEQ(kLocalRef, type_index),
WASM_STRUCT_NEW_WITH_RTT(type_index, WASM_I32V(42), WASM_I32V(52),
WASM_RTT_CANON(type_index)),
WASM_STRUCT_GET(type_index, let_field_index,
WASM_GET_LOCAL(let_local_index))),
kExprEnd});
uint32_t let_2_field_index = 0;
const uint32_t kLetTest2 = tester.DefineFunction(
const byte let_2_field_index = 0;
const byte kLetTest2 = tester.DefineFunction(
tester.sigs.i_v(), {},
{WASM_LET_2_I(
kLocalI32, WASM_I32_ADD(WASM_I32V(42), WASM_I32V(-32)),
WASM_SEQ(kLocalRef, static_cast<byte>(type_index)),
WASM_SEQ(kLocalRef, type_index),
WASM_STRUCT_NEW_WITH_RTT(type_index, WASM_I32V(42), WASM_I32V(52),
WASM_RTT_CANON(type_index)),
WASM_I32_MUL(WASM_STRUCT_GET(type_index, let_2_field_index,
@ -523,7 +521,7 @@ TEST(WasmLetInstruction) {
WASM_GET_LOCAL(0))),
kExprEnd});
const uint32_t kLetTestLocals = tester.DefineFunction(
const byte kLetTestLocals = tester.DefineFunction(
tester.sigs.i_i(), {kWasmI32},
{WASM_SET_LOCAL(1, WASM_I32V(100)),
WASM_LET_2_I(
@ -535,8 +533,8 @@ TEST(WasmLetInstruction) {
kExprEnd});
// Result: (1 + 1000) - (10 + 100) = 891
uint32_t let_erase_local_index = 0;
const uint32_t kLetTestErase = tester.DefineFunction(
const byte let_erase_local_index = 0;
const byte kLetTestErase = tester.DefineFunction(
tester.sigs.i_v(), {kWasmI32},
{WASM_SET_LOCAL(let_erase_local_index, WASM_I32V(0)),
WASM_LET_1_V(kLocalI32, WASM_I32V(1), WASM_NOP),
@ -554,14 +552,14 @@ TEST(WasmLetInstruction) {
TEST(WasmBasicArray) {
WasmGCTester tester;
uint32_t type_index = tester.DefineArray(wasm::kWasmI32, true);
const byte type_index = tester.DefineArray(wasm::kWasmI32, true);
ValueType kRefTypes[] = {ref(type_index)};
FunctionSig sig_q_v(1, 0, kRefTypes);
ValueType kOptRefType = optref(type_index);
// f: a = [12, 12, 12]; a[1] = 42; return a[arg0]
uint32_t local_index = 1;
const uint32_t kGetElem = tester.DefineFunction(
const byte local_index = 1;
const byte kGetElem = tester.DefineFunction(
tester.sigs.i_i(), {kOptRefType},
{WASM_SET_LOCAL(local_index, WASM_ARRAY_NEW_WITH_RTT(
type_index, WASM_I32V(12), WASM_I32V(3),
@ -573,7 +571,7 @@ TEST(WasmBasicArray) {
kExprEnd});
// Reads and returns an array's length.
const uint32_t kGetLength = tester.DefineFunction(
const byte kGetLength = tester.DefineFunction(
tester.sigs.i_v(), {},
{WASM_ARRAY_LEN(type_index, WASM_ARRAY_NEW_WITH_RTT(
type_index, WASM_I32V(0), WASM_I32V(42),
@ -581,7 +579,7 @@ TEST(WasmBasicArray) {
kExprEnd});
// Create an array of length 2, initialized to [42, 42].
const uint32_t kAllocate = tester.DefineFunction(
const byte kAllocate = tester.DefineFunction(
&sig_q_v, {},
{WASM_ARRAY_NEW_WITH_RTT(type_index, WASM_I32V(42), WASM_I32V(2),
WASM_RTT_CANON(type_index)),
@ -605,15 +603,15 @@ TEST(WasmBasicArray) {
TEST(WasmPackedArrayU) {
WasmGCTester tester;
uint32_t array_index = tester.DefineArray(kWasmI8, true);
const byte array_index = tester.DefineArray(kWasmI8, true);
ValueType array_type = optref(array_index);
uint32_t param_index = 0;
uint32_t local_index = 1;
const byte param_index = 0;
const byte local_index = 1;
int32_t expected_output_3 = 258;
const uint32_t kF = tester.DefineFunction(
const byte kF = tester.DefineFunction(
tester.sigs.i_i(), {array_type},
{WASM_SET_LOCAL(local_index, WASM_ARRAY_NEW_WITH_RTT(
array_index, WASM_I32V(0), WASM_I32V(4),
@ -640,14 +638,14 @@ TEST(WasmPackedArrayU) {
TEST(WasmPackedArrayS) {
WasmGCTester tester;
uint32_t array_index = tester.DefineArray(kWasmI16, true);
const byte array_index = tester.DefineArray(kWasmI16, true);
ValueType array_type = optref(array_index);
int32_t expected_outputs[] = {0x12345678, 10, 0xFEDC, 0xFF1234};
uint32_t param_index = 0;
uint32_t local_index = 1;
const uint32_t kF = tester.DefineFunction(
const byte param_index = 0;
const byte local_index = 1;
const byte kF = tester.DefineFunction(
tester.sigs.i_i(), {array_type},
{WASM_SET_LOCAL(
local_index,
@ -675,8 +673,8 @@ TEST(WasmPackedArrayS) {
TEST(BasicRTT) {
WasmGCTester tester;
uint32_t type_index = tester.DefineStruct({F(wasm::kWasmI32, true)});
uint32_t subtype_index =
const byte type_index = tester.DefineStruct({F(wasm::kWasmI32, true)});
const byte subtype_index =
tester.DefineStruct({F(wasm::kWasmI32, true), F(wasm::kWasmI32, true)});
ValueType kRttTypes[] = {ValueType::Rtt(type_index, 1)};
FunctionSig sig_t_v(1, 0, kRttTypes);
@ -688,15 +686,15 @@ TEST(BasicRTT) {
ValueType kRefTypes[] = {ref(type_index)};
FunctionSig sig_q_v(1, 0, kRefTypes);
const uint32_t kRttCanon = tester.DefineFunction(
const byte kRttCanon = tester.DefineFunction(
&sig_t_v, {}, {WASM_RTT_CANON(type_index), kExprEnd});
const uint32_t kRttSub = tester.DefineFunction(
const byte kRttSub = tester.DefineFunction(
&sig_t2_v, {},
{WASM_RTT_SUB(subtype_index, WASM_RTT_CANON(type_index)), kExprEnd});
const uint32_t kRttSubGeneric = tester.DefineFunction(
const byte kRttSubGeneric = tester.DefineFunction(
&sig_t3_v, {},
{WASM_RTT_SUB(type_index, WASM_RTT_CANON(kLocalEqRef)), kExprEnd});
const uint32_t kStructWithRtt = tester.DefineFunction(
const byte kStructWithRtt = tester.DefineFunction(
&sig_q_v, {},
{WASM_STRUCT_NEW_WITH_RTT(type_index, WASM_I32V(42),
WASM_RTT_CANON(type_index)),
@ -712,7 +710,7 @@ TEST(BasicRTT) {
// ((ref.cast local_struct local_rtt)[field0]);
// }
// The expected return value is 1+42 = 43.
const uint32_t kRefCast = tester.DefineFunction(
const byte kRefCast = tester.DefineFunction(
tester.sigs.i_v(), {optref(type_index)},
{WASM_LET_1_I(
WASM_RTT(2, subtype_index),
@ -770,11 +768,11 @@ TEST(BasicRTT) {
TEST(ArrayNewMap) {
WasmGCTester tester;
uint32_t type_index = tester.DefineArray(kWasmI32, true);
const byte type_index = tester.DefineArray(kWasmI32, true);
ValueType array_type = ValueType::Ref(type_index, kNonNullable);
FunctionSig sig(1, 0, &array_type);
const uint32_t array_new_with_rtt = tester.DefineFunction(
const byte array_new_with_rtt = tester.DefineFunction(
&sig, {},
{WASM_ARRAY_NEW_WITH_RTT(type_index, WASM_I32V(10), WASM_I32V(42),
WASM_RTT_CANON(type_index)),
@ -782,7 +780,7 @@ TEST(ArrayNewMap) {
ValueType rtt_type = ValueType::Rtt(type_index, 1);
FunctionSig rtt_canon_sig(1, 0, &rtt_type);
const uint32_t kRttCanon = tester.DefineFunction(
const byte kRttCanon = tester.DefineFunction(
&rtt_canon_sig, {}, {WASM_RTT_CANON(type_index), kExprEnd});
tester.CompileModule();
@ -797,16 +795,15 @@ TEST(ArrayNewMap) {
TEST(RefTestCastNull) {
WasmGCTester tester;
uint8_t type_index =
static_cast<uint8_t>(tester.DefineStruct({F(wasm::kWasmI32, true)}));
byte type_index = tester.DefineStruct({F(wasm::kWasmI32, true)});
const uint32_t kRefTestNull = tester.DefineFunction(
const byte kRefTestNull = tester.DefineFunction(
tester.sigs.i_v(), {},
{WASM_REF_TEST(type_index, type_index, WASM_REF_NULL(type_index),
WASM_RTT_CANON(type_index)),
kExprEnd});
const uint32_t kRefCastNull = tester.DefineFunction(
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),
@ -819,10 +816,10 @@ TEST(RefTestCastNull) {
TEST(BasicI31) {
WasmGCTester tester;
const uint32_t kSigned = tester.DefineFunction(
const byte kSigned = tester.DefineFunction(
tester.sigs.i_i(), {},
{WASM_I31_GET_S(WASM_I31_NEW(WASM_GET_LOCAL(0))), kExprEnd});
const uint32_t kUnsigned = tester.DefineFunction(
const byte kUnsigned = tester.DefineFunction(
tester.sigs.i_i(), {},
{WASM_I31_GET_U(WASM_I31_NEW(WASM_GET_LOCAL(0))), kExprEnd});
// TODO(7748): Support (rtt.canon i31), and add a test like:
@ -840,16 +837,17 @@ TEST(BasicI31) {
TEST(I31Casts) {
WasmGCTester tester;
uint32_t struct_type = tester.DefineStruct({F(wasm::kWasmI32, true)});
uint32_t i31_rtt = tester.AddGlobal(ValueType::Rtt(HeapType::kI31, 1), false,
WasmInitExpr::RttCanon(HeapType::kI31));
uint32_t struct_rtt =
const byte struct_type = tester.DefineStruct({F(wasm::kWasmI32, true)});
const byte i31_rtt =
tester.AddGlobal(ValueType::Rtt(HeapType::kI31, 1), false,
WasmInitExpr::RttCanon(HeapType::kI31));
const byte struct_rtt =
tester.AddGlobal(ValueType::Rtt(struct_type, 1), false,
WasmInitExpr::RttCanon(
static_cast<HeapType::Representation>(struct_type)));
// Adds the result of a successful typecheck to the untagged value, i.e.
// should return 1 + 42 = 43.
const uint32_t kTestAndCastSuccess = tester.DefineFunction(
const byte kTestAndCastSuccess = tester.DefineFunction(
tester.sigs.i_v(), {kWasmEqRef},
{WASM_SET_LOCAL(0, WASM_I31_NEW(WASM_I32V(42))),
WASM_I32_ADD(WASM_REF_TEST(kLocalEqRef, kLocalI31Ref, WASM_GET_LOCAL(0),
@ -860,7 +858,7 @@ TEST(I31Casts) {
kExprEnd});
// Adds the results of two unsuccessful type checks (an i31ref is not a
// struct, nor the other way round).
const uint32_t kTestFalse = tester.DefineFunction(
const byte kTestFalse = tester.DefineFunction(
tester.sigs.i_v(), {},
{WASM_I32_ADD(
WASM_REF_TEST(kLocalEqRef, kLocalI31Ref,
@ -871,7 +869,7 @@ TEST(I31Casts) {
WASM_GET_GLOBAL(struct_rtt))),
kExprEnd});
// Tries to cast an i31ref to a struct, which should trap.
const uint32_t kCastI31ToStruct = tester.DefineFunction(
const byte kCastI31ToStruct = tester.DefineFunction(
tester.sigs.i_i(), // Argument and return value ignored
{},
{WASM_STRUCT_GET(
@ -880,7 +878,7 @@ TEST(I31Casts) {
WASM_GET_GLOBAL(struct_rtt))),
kExprEnd});
// Tries to cast a struct to i31ref, which should trap.
const uint32_t kCastStructToI31 = tester.DefineFunction(
const byte kCastStructToI31 = tester.DefineFunction(
tester.sigs.i_i(), // Argument and return value ignored
{},
{WASM_I31_GET_S(
@ -898,7 +896,7 @@ TEST(I31Casts) {
TEST(JsAccess) {
WasmGCTester tester;
uint32_t type_index = tester.DefineStruct({F(wasm::kWasmI32, true)});
const byte type_index = tester.DefineStruct({F(wasm::kWasmI32, true)});
ValueType kRefTypes[] = {ref(type_index)};
ValueType kEqRefTypes[] = {kWasmEqRef};
ValueType kEqToI[] = {kWasmI32, kWasmEqRef};

View File

@ -83,12 +83,11 @@
#define DEPTH_2 2
#define ARITY_2 2
#define WASM_HEAP_TYPE(heap_type) static_cast<byte>(0x7F & heap_type.code())
#define WASM_HEAP_TYPE(heap_type) static_cast<byte>((heap_type).code() & 0x7f)
#define WASM_REF_TYPE(type) \
static_cast<byte>(type.kind() == ValueType::kRef ? kLocalRef \
: kLocalOptRef), \
WASM_HEAP_TYPE(type.heap_type())
#define WASM_REF_TYPE(type) \
(type).kind() == ValueType::kRef ? kLocalRef : kLocalOptRef, \
WASM_HEAP_TYPE((type).heap_type())
#define WASM_BLOCK(...) kExprBlock, kLocalVoid, __VA_ARGS__, kExprEnd
#define WASM_BLOCK_I(...) kExprBlock, kLocalI32, __VA_ARGS__, kExprEnd
@ -447,12 +446,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), static_cast<byte>(obj_type), \
static_cast<byte>(rtt_type)
#define WASM_REF_CAST(obj_type, rtt_type, ref, rtt) \
ref, rtt, WASM_GC_OP(kExprRefCast), static_cast<byte>(obj_type), \
static_cast<byte>(rtt_type)
#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
// Takes a reference value from the value stack to allow sequences of
// conditional branches.
#define WASM_BR_ON_CAST(depth, rtt) \

View File

@ -4061,6 +4061,111 @@ TEST_F(FunctionBodyDecoderTest, RttSub) {
}
}
TEST_F(FunctionBodyDecoderTest, RefTestCast) {
WASM_FEATURE_SCOPE(reftypes);
WASM_FEATURE_SCOPE(typed_funcref);
WASM_FEATURE_SCOPE(gc);
WASM_FEATURE_SCOPE(eh);
TestModuleBuilder builder;
module = builder.module();
HeapType::Representation array_heap =
static_cast<HeapType::Representation>(builder.AddArray(kWasmI8, true));
HeapType::Representation super_struct_heap =
static_cast<HeapType::Representation>(
builder.AddStruct({F(kWasmI16, true)}));
HeapType::Representation sub_struct_heap =
static_cast<HeapType::Representation>(
builder.AddStruct({F(kWasmI16, true), F(kWasmI32, false)}));
// Passing/failing tests due to static subtyping.
std::pair<HeapType::Representation, HeapType::Representation> valid_pairs[] =
{{HeapType::kEq, HeapType::kI31},
{HeapType::kFunc, HeapType::kFunc},
{HeapType::kEq, array_heap},
{HeapType::kEq, super_struct_heap},
{super_struct_heap, sub_struct_heap}};
for (auto pair : valid_pairs) {
HeapType from_heap = HeapType(pair.first);
HeapType to_heap = HeapType(pair.second);
ValueType test_reps[] = {kWasmI32, ValueType::Ref(from_heap, kNullable)};
FunctionSig test_sig(1, 1, test_reps);
ValueType cast_reps[] = {ValueType::Ref(to_heap, kNonNullable),
ValueType::Ref(from_heap, 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_GET_LOCAL(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_GET_LOCAL(0),
WASM_RTT_CANON(WASM_HEAP_TYPE(to_heap)))});
}
std::pair<HeapType::Representation, HeapType::Representation>
invalid_pairs[] = {{HeapType::kI31, HeapType::kEq},
{array_heap, super_struct_heap},
{array_heap, HeapType::kEq},
{HeapType::kExtern, HeapType::kExn}};
for (auto pair : invalid_pairs) {
HeapType from_heap = HeapType(pair.first);
HeapType to_heap = HeapType(pair.second);
ValueType test_reps[] = {kWasmI32, ValueType::Ref(from_heap, kNullable)};
FunctionSig test_sig(1, 1, test_reps);
ValueType cast_reps[] = {ValueType::Ref(to_heap, kNonNullable),
ValueType::Ref(from_heap, kNullable)};
FunctionSig cast_sig(1, 1, cast_reps);
ExpectFailure(&test_sig,
{WASM_REF_TEST(WASM_HEAP_TYPE(from_heap),
WASM_HEAP_TYPE(to_heap), WASM_GET_LOCAL(0),
WASM_RTT_CANON(WASM_HEAP_TYPE(to_heap)))},
kAppendEnd,
"ref.test: rtt type must be subtype of object type");
ExpectFailure(&cast_sig,
{WASM_REF_CAST(WASM_HEAP_TYPE(from_heap),
WASM_HEAP_TYPE(to_heap), WASM_GET_LOCAL(0),
WASM_RTT_CANON(WASM_HEAP_TYPE(to_heap)))},
kAppendEnd,
"ref.cast: rtt type must be subtype of object type");
}
// Trivial type error.
ExpectFailure(sigs.v_v(),
{WASM_REF_TEST(kLocalEqRef, kLocalI31Ref, WASM_I32V(1),
WASM_RTT_CANON(kLocalI31Ref)),
kExprDrop},
kAppendEnd,
"ref.test[0] expected type eqref, found i32.const of type i32");
ExpectFailure(sigs.v_v(),
{WASM_REF_CAST(kLocalEqRef, kLocalI31Ref, WASM_I32V(1),
WASM_RTT_CANON(kLocalI31Ref)),
kExprDrop},
kAppendEnd,
"ref.cast[0] expected type eqref, found i32.const of type i32");
// Mismached object heap immediate.
{
ValueType arg_type = ValueType::Ref(HeapType::kEq, kNonNullable);
FunctionSig sig(0, 1, &arg_type);
ExpectFailure(
&sig,
{WASM_REF_TEST(kLocalEqRef, static_cast<byte>(array_heap),
WASM_GET_LOCAL(0), WASM_RTT_CANON(kLocalI31Ref)),
kExprDrop},
kAppendEnd, "ref.test: expected rtt for type 0 but got (rtt 1 i31)");
ExpectFailure(
&sig,
{WASM_REF_CAST(kLocalEqRef, static_cast<byte>(array_heap),
WASM_GET_LOCAL(0), WASM_RTT_CANON(kLocalI31Ref)),
kExprDrop},
kAppendEnd, "ref.cast: expected rtt for type 0 but got (rtt 1 i31)");
}
}
class BranchTableIteratorTest : public TestWithZone {
public:
BranchTableIteratorTest() : TestWithZone() {}