[wasm-gc] Implement explicit-rtt array.init_from_data

Bug: v8:7748
Change-Id: If5027ac632438937407aeea0bb266b58cb1cbba2
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3422633
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Cr-Commit-Position: refs/heads/main@{#78865}
This commit is contained in:
Manos Koukoutos 2022-01-31 11:53:08 +00:00 committed by V8 LUCI CQ
parent 62bd0c9958
commit abd020fa67
5 changed files with 138 additions and 58 deletions

View File

@ -1862,6 +1862,7 @@ class WasmDecoder : public Decoder {
pc + length + dst_imm.length);
return length + dst_imm.length + src_imm.length;
}
case kExprArrayInitFromData:
case kExprArrayInitFromDataStatic: {
ArrayIndexImmediate<validate> array_imm(decoder, pc + length);
IndexImmediate<validate> data_imm(
@ -2069,6 +2070,7 @@ class WasmDecoder : public Decoder {
case kExprStructNewDefault:
return {0, 1};
case kExprArrayNewWithRtt:
case kExprArrayInitFromData:
return {3, 1};
case kExprStructNewWithRtt: {
StructIndexImmediate<validate> imm(this, pc + 2);
@ -4191,6 +4193,7 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
Push(value);
return opcode_length + imm.length;
}
case kExprArrayInitFromData:
case kExprArrayInitFromDataStatic: {
ArrayIndexImmediate<validate> array_imm(this,
this->pc_ + opcode_length);
@ -4217,12 +4220,17 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
"data segment");
if (!this->ValidateDataSegment(data_index_pc, data_segment)) return 0;
Value length = Peek(0, 1, kWasmI32);
Value offset = Peek(1, 0, kWasmI32);
ValueType rtt_type = ValueType::Rtt(array_imm.index);
Value rtt = opcode == kExprArrayInitFromDataStatic
? CreateValue(rtt_type)
: Peek(0, 2, rtt_type);
if (opcode == kExprArrayInitFromDataStatic) {
CALL_INTERFACE_IF_OK_AND_REACHABLE(RttCanon, array_imm.index, &rtt);
Push(rtt);
}
Value rtt = CreateValue(ValueType::Rtt(array_imm.index));
CALL_INTERFACE_IF_OK_AND_REACHABLE(RttCanon, array_imm.index, &rtt);
Push(rtt);
Value length = Peek(1, 1, kWasmI32);
Value offset = Peek(2, 0, kWasmI32);
Value array =
CreateValue(ValueType::Ref(array_imm.index, kNonNullable));

View File

@ -414,7 +414,8 @@ constexpr const char* WasmOpcodes::OpcodeName(WasmOpcode opcode) {
CASE_OP(ArrayCopy, "array.copy")
CASE_OP(ArrayInit, "array.init")
CASE_OP(ArrayInitStatic, "array.init_static")
CASE_OP(ArrayInitFromDataStatic, "array.init_from_data")
CASE_OP(ArrayInitFromData, "array.init_from_data")
CASE_OP(ArrayInitFromDataStatic, "array.init_from_data_static")
CASE_OP(I31New, "i31.new")
CASE_OP(I31GetS, "i31.get_s")
CASE_OP(I31GetU, "i31.get_u")

View File

@ -665,56 +665,57 @@ bool V8_EXPORT_PRIVATE IsJSCompatibleSignature(const FunctionSig* sig,
/* AtomicFence does not target a particular linear memory. */ \
V(AtomicFence, 0xfe03, v_v)
#define FOREACH_GC_OPCODE(V) \
V(StructNewWithRtt, 0xfb01, _) \
V(StructNewDefaultWithRtt, 0xfb02, _) \
V(StructGet, 0xfb03, _) \
V(StructGetS, 0xfb04, _) \
V(StructGetU, 0xfb05, _) \
V(StructSet, 0xfb06, _) \
V(StructNew, 0xfb07, _) \
V(StructNewDefault, 0xfb08, _) \
V(ArrayNewWithRtt, 0xfb11, _) \
V(ArrayNewDefaultWithRtt, 0xfb12, _) \
V(ArrayGet, 0xfb13, _) \
V(ArrayGetS, 0xfb14, _) \
V(ArrayGetU, 0xfb15, _) \
V(ArraySet, 0xfb16, _) \
V(ArrayLen, 0xfb17, _) \
V(ArrayCopy, 0xfb18, _) /* not standardized - V8 experimental */ \
V(ArrayInit, 0xfb19, _) /* not standardized - V8 experimental */ \
V(ArrayInitStatic, 0xfb1a, _) \
V(ArrayNew, 0xfb1b, _) \
V(ArrayNewDefault, 0xfb1c, _) \
V(ArrayInitFromDataStatic, 0xfb1d, _) /* n/st - V8 experimental */ \
V(I31New, 0xfb20, _) \
V(I31GetS, 0xfb21, _) \
V(I31GetU, 0xfb22, _) \
V(RttCanon, 0xfb30, _) \
V(RefTest, 0xfb40, _) \
V(RefCast, 0xfb41, _) \
V(BrOnCast, 0xfb42, _) \
V(BrOnCastFail, 0xfb43, _) \
V(RefTestStatic, 0xfb44, _) \
V(RefCastStatic, 0xfb45, _) \
V(BrOnCastStatic, 0xfb46, _) \
V(BrOnCastStaticFail, 0xfb47, _) \
V(RefIsFunc, 0xfb50, _) \
V(RefIsData, 0xfb51, _) \
V(RefIsI31, 0xfb52, _) \
V(RefIsArray, 0xfb53, _) /* not standardized - V8 experimental */ \
V(RefAsFunc, 0xfb58, _) \
V(RefAsData, 0xfb59, _) \
V(RefAsI31, 0xfb5a, _) \
V(RefAsArray, 0xfb5b, _) /* not standardized - V8 experimental */ \
V(BrOnFunc, 0xfb60, _) \
V(BrOnData, 0xfb61, _) \
V(BrOnI31, 0xfb62, _) \
V(BrOnArray, 0xfb66, _) /* not standardized - V8 experimental */ \
V(BrOnNonFunc, 0xfb63, _) \
V(BrOnNonData, 0xfb64, _) \
V(BrOnNonI31, 0xfb65, _) \
V(BrOnNonArray, 0xfb67, _) /* not standardized - V8 experimental */
#define FOREACH_GC_OPCODE(V) /* Force 80 columns */ \
V(StructNewWithRtt, 0xfb01, _) \
V(StructNewDefaultWithRtt, 0xfb02, _) \
V(StructGet, 0xfb03, _) \
V(StructGetS, 0xfb04, _) \
V(StructGetU, 0xfb05, _) \
V(StructSet, 0xfb06, _) \
V(StructNew, 0xfb07, _) \
V(StructNewDefault, 0xfb08, _) \
V(ArrayNewWithRtt, 0xfb11, _) \
V(ArrayNewDefaultWithRtt, 0xfb12, _) \
V(ArrayGet, 0xfb13, _) \
V(ArrayGetS, 0xfb14, _) \
V(ArrayGetU, 0xfb15, _) \
V(ArraySet, 0xfb16, _) \
V(ArrayLen, 0xfb17, _) \
V(ArrayCopy, 0xfb18, _) /* not standardized - V8 experimental */ \
V(ArrayInit, 0xfb19, _) /* not standardized - V8 experimental */ \
V(ArrayInitStatic, 0xfb1a, _) /* not standardized - V8 experimental */ \
V(ArrayNew, 0xfb1b, _) \
V(ArrayNewDefault, 0xfb1c, _) \
V(ArrayInitFromData, 0xfb1e, _) /* not stand. - V8 experimental */ \
V(ArrayInitFromDataStatic, 0xfb1d, _) /* not stand. - V8 experimental */ \
V(I31New, 0xfb20, _) \
V(I31GetS, 0xfb21, _) \
V(I31GetU, 0xfb22, _) \
V(RttCanon, 0xfb30, _) \
V(RefTest, 0xfb40, _) \
V(RefCast, 0xfb41, _) \
V(BrOnCast, 0xfb42, _) \
V(BrOnCastFail, 0xfb43, _) \
V(RefTestStatic, 0xfb44, _) \
V(RefCastStatic, 0xfb45, _) \
V(BrOnCastStatic, 0xfb46, _) \
V(BrOnCastStaticFail, 0xfb47, _) \
V(RefIsFunc, 0xfb50, _) \
V(RefIsData, 0xfb51, _) \
V(RefIsI31, 0xfb52, _) \
V(RefIsArray, 0xfb53, _) \
V(RefAsFunc, 0xfb58, _) \
V(RefAsData, 0xfb59, _) \
V(RefAsI31, 0xfb5a, _) \
V(RefAsArray, 0xfb5b, _) \
V(BrOnFunc, 0xfb60, _) \
V(BrOnData, 0xfb61, _) \
V(BrOnI31, 0xfb62, _) \
V(BrOnArray, 0xfb66, _) \
V(BrOnNonFunc, 0xfb63, _) \
V(BrOnNonData, 0xfb64, _) \
V(BrOnNonI31, 0xfb65, _) \
V(BrOnNonArray, 0xfb67, _)
// All opcodes.
#define FOREACH_OPCODE(V) \

View File

@ -70,7 +70,7 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
let global = builder.addGlobal(
wasmRefType(array_type_index), true,
WasmInitExpr.ArrayInitStaticFromData(
WasmInitExpr.ArrayInitFromDataStatic(
array_type_index, data_segment,
[WasmInitExpr.I32Const(1), WasmInitExpr.I32Const(2)], builder));
@ -112,3 +112,64 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
assertTraps(kTrapDataSegmentOutOfBounds, () => init(1, 2, 0));
})();
(function TestArrayInitFromData() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
builder.setNominal();
let array_type_index = builder.addArray(kWasmI16, true);
let dummy_byte = 0xff;
let element_0 = 1000;
let element_1 = -2222;
let data_segment = builder.addPassiveDataSegment(
[dummy_byte, element_0 & 0xff, (element_0 >> 8) & 0xff,
element_1 & 0xff, (element_1 >> 8) & 0xff]);
let global = builder.addGlobal(
wasmRefType(array_type_index), true,
WasmInitExpr.ArrayInitFromData(
array_type_index, data_segment,
[WasmInitExpr.I32Const(1), WasmInitExpr.I32Const(2),
WasmInitExpr.RttCanon(array_type_index)],
builder));
builder.addFunction("global_get", kSig_i_i)
.addBody([
kExprGlobalGet, global.index,
kExprLocalGet, 0,
kGCPrefix, kExprArrayGetS, array_type_index])
.exportFunc();
// parameters: (segment offset, array length, array index)
builder.addFunction("init_from_data", kSig_i_iii)
.addBody([
kExprLocalGet, 0, kExprLocalGet, 1,
kGCPrefix, kExprRttCanon, array_type_index,
kGCPrefix, kExprArrayInitFromData, array_type_index, data_segment,
kExprLocalGet, 2,
kGCPrefix, kExprArrayGetS, array_type_index])
.exportFunc();
builder.addFunction("drop_segment", kSig_v_v)
.addBody([kNumericPrefix, kExprDataDrop, data_segment])
.exportFunc();
let instance = builder.instantiate();
assertEquals(element_0, instance.exports.global_get(0));
assertEquals(element_1, instance.exports.global_get(1));
let init = instance.exports.init_from_data;
assertEquals(element_0, init(1, 2, 0));
assertEquals(element_1, init(1, 2, 1));
assertTraps(kTrapArrayTooLarge, () => init(1, 1000000000, 0));
assertTraps(kTrapDataSegmentOutOfBounds, () => init(2, 2, 0));
instance.exports.drop_segment();
assertTraps(kTrapDataSegmentOutOfBounds, () => init(1, 2, 0));
})();

View File

@ -489,6 +489,7 @@ let kExprArrayInit = 0x19;
let kExprArrayInitStatic = 0x1a;
let kExprArrayNew = 0x1b;
let kExprArrayNewDefault = 0x1c;
let kExprArrayInitFromData = 0x1e;
let kExprArrayInitFromDataStatic = 0x1d;
let kExprI31New = 0x20;
let kExprI31GetS = 0x21;
@ -1044,6 +1045,7 @@ class Binary {
this.emit_u32v(expr.value);
this.emit_u32v(expr.operands.length - 1);
break;
case kExprArrayInitFromData:
case kExprArrayInitFromDataStatic:
for (let operand of expr.operands) {
this.emit_init_expr_recursive(operand);
@ -1217,7 +1219,14 @@ class WasmInitExpr {
static ArrayInitStatic(type, args) {
return {kind: kExprArrayInitStatic, value: type, operands: args};
}
static ArrayInitStaticFromData(array_index, data_segment, args, builder) {
static ArrayInitFromData(array_index, data_segment, args, builder) {
// array.init_from_data means we need to pull the data count section before
// any section that may include init. expressions.
builder.early_data_count_section = true;
return {kind: kExprArrayInitFromData, array_index: array_index,
data_segment: data_segment, operands: args};
}
static ArrayInitFromDataStatic(array_index, data_segment, args, builder) {
// array.init_from_data means we need to pull the data count section before
// any section that may include init. expressions.
builder.early_data_count_section = true;