Commit e9cdb2a7 authored by Manos Koukoutos's avatar Manos Koukoutos Committed by Commit Bot

[wasm-gc] Implement packed arrays/structs

Bug: v8:7748
Change-Id: I461b68f1950847271a92e7b52f3d4d8b520eccfe
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2231349
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#68218}
parent 840b7609
......@@ -3281,6 +3281,27 @@ class WasmFullDecoder : public WasmDecoder<validate> {
CALL_INTERFACE_IF_REACHABLE(StructGet, struct_obj, field, true, value);
break;
}
case kExprStructGetU:
case kExprStructGetS: {
FieldIndexImmediate<validate> field(this, this->pc_ + len);
if (!this->Validate(this->pc_ + len, field)) break;
len += field.length;
ValueType field_type =
field.struct_index.struct_type->field(field.index);
if (!field_type.IsPacked()) {
this->errorf(this->pc_,
"%s is only valid for packed struct fields. "
"Use struct.get instead.",
WasmOpcodes::OpcodeName(opcode));
break;
}
Value struct_obj =
Pop(0, ValueType(ValueType::kOptRef, field.struct_index.index));
Value* value = Push(field_type.Unpack());
CALL_INTERFACE_IF_REACHABLE(StructGet, struct_obj, field,
opcode == kExprStructGetS, value);
break;
}
case kExprStructSet: {
FieldIndexImmediate<validate> field(this, this->pc_ + len);
if (!this->Validate(this->pc_ + len, field)) break;
......@@ -3308,6 +3329,26 @@ class WasmFullDecoder : public WasmDecoder<validate> {
value);
break;
}
case kExprArrayGetS:
case kExprArrayGetU: {
ArrayIndexImmediate<validate> imm(this, this->pc_ + len);
len += imm.length;
if (!this->Validate(this->pc_ + len, imm)) break;
if (!imm.array_type->element_type().IsPacked()) {
this->errorf(this->pc_,
"%s is only valid for packed arrays. "
"Use or array.get instead.",
WasmOpcodes::OpcodeName(opcode));
break;
}
Value index = Pop(1, kWasmI32);
Value array_obj = Pop(0, ValueType(ValueType::kOptRef, imm.index));
Value* value = Push(imm.array_type->element_type().Unpack());
// TODO(7748): Optimize this when array_obj is non-nullable ref.
CALL_INTERFACE_IF_REACHABLE(ArrayGet, array_obj, imm, index,
opcode == kExprArrayGetS, value);
break;
}
case kExprArrayGet: {
ArrayIndexImmediate<validate> imm(this, this->pc_ + len);
len += imm.length;
......
......@@ -269,6 +269,76 @@ TEST(WasmBasicStruct) {
tester.CheckResult("n", 0b1001, {});
}
TEST(WasmPackedStructU) {
WasmGCTester tester;
uint32_t type_index = tester.DefineStruct(
{F(kWasmI8, true), F(kWasmI16, true), F(kWasmI32, true)});
ValueType struct_type = ValueType(ValueType::kOptRef, type_index);
uint32_t local_index = 0;
int32_t expected_output_0 = 0x1234;
int32_t expected_output_1 = -1;
tester.DefineFunction(
"f_0", tester.sigs.i_v(), {struct_type},
{WASM_SET_LOCAL(local_index,
WASM_STRUCT_NEW(type_index, WASM_I32V(expected_output_0),
WASM_I32V(expected_output_1),
WASM_I32V(0x12345678))),
WASM_STRUCT_GET_U(type_index, 0, WASM_GET_LOCAL(local_index)),
kExprEnd});
tester.DefineFunction(
"f_1", tester.sigs.i_v(), {struct_type},
{WASM_SET_LOCAL(local_index,
WASM_STRUCT_NEW(type_index, WASM_I32V(expected_output_0),
WASM_I32V(expected_output_1),
WASM_I32V(0x12345678))),
WASM_STRUCT_GET_U(type_index, 1, WASM_GET_LOCAL(local_index)),
kExprEnd});
tester.CompileModule();
tester.CheckResult("f_0", static_cast<uint8_t>(expected_output_0), {});
tester.CheckResult("f_1", static_cast<uint16_t>(expected_output_1), {});
}
TEST(WasmPackedStructS) {
WasmGCTester tester;
uint32_t type_index = tester.DefineStruct(
{F(kWasmI8, true), F(kWasmI16, true), F(kWasmI32, true)});
ValueType struct_type = ValueType(ValueType::kOptRef, type_index);
uint32_t local_index = 0;
int32_t expected_output_0 = 0x80;
int32_t expected_output_1 = 42;
tester.DefineFunction(
"f_0", tester.sigs.i_v(), {struct_type},
{WASM_SET_LOCAL(
local_index,
WASM_STRUCT_NEW(type_index, WASM_I32V(expected_output_0),
WASM_I32V(expected_output_1), WASM_I32V(0))),
WASM_STRUCT_GET_S(type_index, 0, WASM_GET_LOCAL(local_index)),
kExprEnd});
tester.DefineFunction(
"f_1", tester.sigs.i_v(), {struct_type},
{WASM_SET_LOCAL(local_index, WASM_STRUCT_NEW(type_index, WASM_I32V(0x80),
WASM_I32V(expected_output_1),
WASM_I32V(0))),
WASM_STRUCT_GET_S(type_index, 1, WASM_GET_LOCAL(local_index)),
kExprEnd});
tester.CompileModule();
tester.CheckResult("f_0", static_cast<int8_t>(expected_output_0), {});
tester.CheckResult("f_1", static_cast<int16_t>(expected_output_1), {});
}
TEST(WasmLetInstruction) {
WasmGCTester tester;
uint32_t type_index =
......@@ -370,6 +440,79 @@ TEST(WasmBasicArray) {
#endif
}
TEST(WasmPackedArrayU) {
WasmGCTester tester;
uint32_t array_index = tester.DefineArray(kWasmI8, true);
ValueType array_type = ValueType(ValueType::kOptRef, array_index);
uint32_t param_index = 0;
uint32_t local_index = 1;
int32_t expected_output_3 = 258;
tester.DefineFunction(
"f", tester.sigs.i_i(), {array_type},
{WASM_SET_LOCAL(local_index,
WASM_ARRAY_NEW(array_index, WASM_I32V(0), WASM_I32V(4))),
WASM_ARRAY_SET(array_index, WASM_GET_LOCAL(local_index), WASM_I32V(0),
WASM_I32V(1)),
WASM_ARRAY_SET(array_index, WASM_GET_LOCAL(local_index), WASM_I32V(1),
WASM_I32V(10)),
WASM_ARRAY_SET(array_index, WASM_GET_LOCAL(local_index), WASM_I32V(2),
WASM_I32V(200)),
WASM_ARRAY_SET(array_index, WASM_GET_LOCAL(local_index), WASM_I32V(3),
WASM_I32V(expected_output_3)),
WASM_ARRAY_GET_U(array_index, WASM_GET_LOCAL(local_index),
WASM_GET_LOCAL(param_index)),
kExprEnd});
tester.CompileModule();
tester.CheckResult("f", 1, {Smi::FromInt(0)});
tester.CheckResult("f", 10, {Smi::FromInt(1)});
tester.CheckResult("f", 200, {Smi::FromInt(2)});
// Only the 2 lsb's of 258 should be stored in the array.
tester.CheckResult("f", static_cast<uint8_t>(expected_output_3),
{Smi::FromInt(3)});
}
TEST(WasmPackedArrayS) {
WasmGCTester tester;
uint32_t array_index = tester.DefineArray(kWasmI16, true);
ValueType array_type = ValueType(ValueType::kOptRef, array_index);
int32_t expected_outputs[] = {0x12345678, 10, 0xFEDC, 0xFF1234};
uint32_t param_index = 0;
uint32_t local_index = 1;
tester.DefineFunction(
"f", tester.sigs.i_i(), {array_type},
{WASM_SET_LOCAL(
local_index,
WASM_ARRAY_NEW(array_index, WASM_I32V(0x12345678), WASM_I32V(4))),
WASM_ARRAY_SET(array_index, WASM_GET_LOCAL(local_index), WASM_I32V(1),
WASM_I32V(10)),
WASM_ARRAY_SET(array_index, WASM_GET_LOCAL(local_index), WASM_I32V(2),
WASM_I32V(0xFEDC)),
WASM_ARRAY_SET(array_index, WASM_GET_LOCAL(local_index), WASM_I32V(3),
WASM_I32V(0xFF1234)),
WASM_ARRAY_GET_S(array_index, WASM_GET_LOCAL(local_index),
WASM_GET_LOCAL(param_index)),
kExprEnd});
tester.CompileModule();
// Exactly the 2 lsb's should be stored by array.new.
tester.CheckResult("f", static_cast<int16_t>(expected_outputs[0]),
{Smi::FromInt(0)});
tester.CheckResult("f", static_cast<int16_t>(expected_outputs[1]),
{Smi::FromInt(1)});
// Sign should be extended.
tester.CheckResult("f", static_cast<int16_t>(expected_outputs[2]),
{Smi::FromInt(2)});
// Exactly the 2 lsb's should be stored by array.set.
tester.CheckResult("f", static_cast<int16_t>(expected_outputs[3]),
{Smi::FromInt(3)});
}
} // namespace test_gc
} // namespace wasm
} // namespace internal
......
......@@ -429,6 +429,12 @@ inline WasmOpcode LoadStoreOpcodeOf(MachineType type, bool store) {
#define WASM_STRUCT_GET(typeidx, fieldidx, struct_obj) \
struct_obj, WASM_GC_OP(kExprStructGet), static_cast<byte>(typeidx), \
static_cast<byte>(fieldidx)
#define WASM_STRUCT_GET_S(typeidx, fieldidx, struct_obj) \
struct_obj, WASM_GC_OP(kExprStructGetS), static_cast<byte>(typeidx), \
static_cast<byte>(fieldidx)
#define WASM_STRUCT_GET_U(typeidx, fieldidx, struct_obj) \
struct_obj, WASM_GC_OP(kExprStructGetU), static_cast<byte>(typeidx), \
static_cast<byte>(fieldidx)
#define WASM_STRUCT_SET(typeidx, fieldidx, struct_obj, value) \
struct_obj, value, WASM_GC_OP(kExprStructSet), static_cast<byte>(typeidx), \
static_cast<byte>(fieldidx)
......@@ -444,6 +450,10 @@ inline WasmOpcode LoadStoreOpcodeOf(MachineType type, bool store) {
default_value, length, WASM_GC_OP(kExprArrayNew), static_cast<byte>(index)
#define WASM_ARRAY_GET(typeidx, array, index) \
array, index, WASM_GC_OP(kExprArrayGet), static_cast<byte>(typeidx)
#define WASM_ARRAY_GET_U(typeidx, array, index) \
array, index, WASM_GC_OP(kExprArrayGetU), static_cast<byte>(typeidx)
#define WASM_ARRAY_GET_S(typeidx, array, index) \
array, index, WASM_GC_OP(kExprArrayGetS), static_cast<byte>(typeidx)
#define WASM_ARRAY_SET(typeidx, array, index, value) \
array, index, value, WASM_GC_OP(kExprArraySet), static_cast<byte>(typeidx)
#define WASM_ARRAY_LEN(typeidx, array) \
......
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