[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:
parent
09fcc0628a
commit
65530e72e1
@ -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);
|
||||
|
@ -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};
|
||||
|
@ -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) \
|
||||
|
@ -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() {}
|
||||
|
Loading…
Reference in New Issue
Block a user