[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:
parent
62bd0c9958
commit
abd020fa67
@ -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));
|
||||
|
@ -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")
|
||||
|
@ -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) \
|
||||
|
@ -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));
|
||||
})();
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user