diff --git a/src/wasm/function-body-decoder-impl.h b/src/wasm/function-body-decoder-impl.h index f8b314d4fc..475f8f7bbd 100644 --- a/src/wasm/function-body-decoder-impl.h +++ b/src/wasm/function-body-decoder-impl.h @@ -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 array_imm(decoder, pc + length); IndexImmediate 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 imm(this, pc + 2); @@ -4191,6 +4193,7 @@ class WasmFullDecoder : public WasmDecoder { Push(value); return opcode_length + imm.length; } + case kExprArrayInitFromData: case kExprArrayInitFromDataStatic: { ArrayIndexImmediate array_imm(this, this->pc_ + opcode_length); @@ -4217,12 +4220,17 @@ class WasmFullDecoder : public WasmDecoder { "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)); diff --git a/src/wasm/wasm-opcodes-inl.h b/src/wasm/wasm-opcodes-inl.h index 8e191e5e18..a0bd15705b 100644 --- a/src/wasm/wasm-opcodes-inl.h +++ b/src/wasm/wasm-opcodes-inl.h @@ -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") diff --git a/src/wasm/wasm-opcodes.h b/src/wasm/wasm-opcodes.h index 59ee645dfd..aaa1d0e55a 100644 --- a/src/wasm/wasm-opcodes.h +++ b/src/wasm/wasm-opcodes.h @@ -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) \ diff --git a/test/mjsunit/wasm/gc-nominal.js b/test/mjsunit/wasm/gc-nominal.js index 49221c398d..30f5ab684e 100644 --- a/test/mjsunit/wasm/gc-nominal.js +++ b/test/mjsunit/wasm/gc-nominal.js @@ -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)); +})(); diff --git a/test/mjsunit/wasm/wasm-module-builder.js b/test/mjsunit/wasm/wasm-module-builder.js index 5757ecd0c8..688b4516ac 100644 --- a/test/mjsunit/wasm/wasm-module-builder.js +++ b/test/mjsunit/wasm/wasm-module-builder.js @@ -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;