node/deps/v8/test/mjsunit/wasm/array-bulk-operations.js
Michaël Zasso 1d29d81c69 deps: update V8 to 12.3.219.16
PR-URL: https://github.com/nodejs/node/pull/52293
Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
Reviewed-By: Richard Lau <rlau@redhat.com>
2024-04-19 08:39:47 +00:00

463 lines
17 KiB
JavaScript

// Copyright 2023 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
(function TestArrayFillImmutable() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let array = builder.addArray(kWasmI32, false);
// Parameters: array, starting index, value, length.
builder.addFunction(
"array_fill",
makeSig([wasmRefNullType(array), kWasmI32, kWasmI32, kWasmI32], []))
.addBody([kExprLocalGet, 0, kExprLocalGet, 1,
kExprLocalGet, 2, kExprLocalGet, 3,
kGCPrefix, kExprArrayFill, array])
.exportFunc();
assertThrows(() => builder.instantiate(), WebAssembly.CompileError,
/immediate array type #0 is immutable/);
})();
(function TestArrayFill() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let struct = builder.addStruct([makeField(kWasmI32, true)]);
let array = builder.addArray(wasmRefNullType(struct), true);
let array16 = builder.addArray(kWasmI16, true);
builder.addFunction(
"make_array", makeSig([kWasmI32], [wasmRefType(array)]))
.addBody([kExprLocalGet, 0, kGCPrefix, kExprArrayNewDefault, array])
.exportFunc();
builder.addFunction(
"array_get", makeSig([wasmRefNullType(array), kWasmI32], [kWasmI32]))
.addBody([kExprLocalGet, 0, kExprLocalGet, 1,
kGCPrefix, kExprArrayGet, array,
kGCPrefix, kExprStructGet, struct, 0])
.exportFunc();
// Parameters: array, starting index, value in struct, length.
builder.addFunction(
"array_fill",
makeSig([wasmRefNullType(array), kWasmI32, kWasmI32, kWasmI32], []))
.addBody([kExprLocalGet, 0, kExprLocalGet, 1,
kExprLocalGet, 2, kGCPrefix, kExprStructNew, struct,
kExprLocalGet, 3, kGCPrefix, kExprArrayFill, array])
.exportFunc();
builder.addFunction("array_fill_i16", kSig_i_v).exportFunc()
.addLocals(wasmRefType(array16), 1)
.addBody([
kExprI32Const, 4, // Array length for allocation.
kGCPrefix, kExprArrayNewDefault, array16,
kExprLocalTee, 0, // Array (for fill).
kExprI32Const, 0, // Offset (for fill).
kExprI32Const, 42, // Value (for fill).
kExprI32Const, 4, // Length (for fill).
kGCPrefix, kExprArrayFill, array16,
kExprLocalGet, 0, // Array (for get).
kExprI32Const, 0, // Index (for get).
kGCPrefix, kExprArrayGetS, array16,
]);
let wasm = builder.instantiate().exports;
assertTraps(kTrapNullDereference, () => wasm.array_fill(null, 10, 20, 30));
let array_obj = wasm.make_array(8);
assertTraps(kTrapArrayOutOfBounds,
() => wasm.array_fill(array_obj, 5, 42, 4));
// Out-of-bounds array.fill traps even if length is 0, if the index is greater
// than array.len.
assertTraps(kTrapArrayOutOfBounds,
() => wasm.array_fill(array_obj, 10, 42, 0));
// Overflow of (index + length) traps.
assertTraps(kTrapArrayOutOfBounds,
() => wasm.array_fill(array_obj, 5, 42, -1));
wasm.array_fill(array_obj, 2, 42, 3);
assertTraps(kTrapNullDereference, () => wasm.array_get(array_obj, 0));
assertTraps(kTrapNullDereference, () => wasm.array_get(array_obj, 1));
assertEquals(42, wasm.array_get(array_obj, 2));
assertEquals(42, wasm.array_get(array_obj, 3));
assertEquals(42, wasm.array_get(array_obj, 4));
assertTraps(kTrapNullDereference, () => wasm.array_get(array_obj, 5));
assertTraps(kTrapNullDereference, () => wasm.array_get(array_obj, 6));
assertTraps(kTrapNullDereference, () => wasm.array_get(array_obj, 7));
// Index = array.len and length = 0 works, it just does nothing.
wasm.array_fill(array_obj, 8, 42, 0)
wasm.array_fill(array_obj, 4, 54, 2);
assertTraps(kTrapNullDereference, () => wasm.array_get(array_obj, 0));
assertTraps(kTrapNullDereference, () => wasm.array_get(array_obj, 1));
assertEquals(42, wasm.array_get(array_obj, 2));
assertEquals(42, wasm.array_get(array_obj, 3));
assertEquals(54, wasm.array_get(array_obj, 4));
assertEquals(54, wasm.array_get(array_obj, 5));
assertTraps(kTrapNullDereference, () => wasm.array_get(array_obj, 6));
assertTraps(kTrapNullDereference, () => wasm.array_get(array_obj, 7));
assertEquals(42, wasm.array_fill_i16());
})();
(function TestArrayNewNonNullable() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let struct = builder.addStruct([makeField(kWasmI32, true)]);
let array = builder.addArray(wasmRefType(struct), true);
builder.addFunction(
"make_array", makeSig([wasmRefType(struct), kWasmI32],
[wasmRefType(array)]))
.addBody([kExprLocalGet, 0, kExprLocalGet, 1,
kGCPrefix, kExprArrayNew, array])
.exportFunc();
builder.addFunction(
"array_get", makeSig([wasmRefNullType(array), kWasmI32],
[wasmRefType(struct)]))
.addBody([kExprLocalGet, 0, kExprLocalGet, 1,
kGCPrefix, kExprArrayGet, array])
.exportFunc();
builder.addFunction(
"make_struct", makeSig([], [wasmRefType(struct)]))
.addBody([kGCPrefix, kExprStructNewDefault, struct])
.exportFunc();
let wasm = builder.instantiate().exports;
let length = 50; // Enough to go through initialization builtin.
let struct_obj = wasm.make_struct();
let array_obj = wasm.make_array(struct_obj, length);
for (let i = 0; i < length; i++) {
assertEquals(struct_obj, wasm.array_get(array_obj, i));
}
})();
(function TestArrayInitData() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let array = builder.addArray(kWasmI16, true);
builder.addMemory(10, 10);
let passive = builder.addPassiveDataSegment([0, 1, 2, 3, 4, 5]);
let active = builder.addActiveDataSegment(0, [kExprI32Const, 0],
[6, 7, 8, 9]);
builder.addFunction(
"make_array", makeSig([kWasmI32], [wasmRefType(array)]))
.addBody([kExprLocalGet, 0, kGCPrefix, kExprArrayNewDefault, array])
.exportFunc();
builder.addFunction(
"init_passive",
makeSig([wasmRefNullType(array), kWasmI32, kWasmI32, kWasmI32], []))
.addBody([kExprLocalGet, 0, kExprLocalGet, 1, kExprLocalGet, 2,
kExprLocalGet, 3, kGCPrefix, kExprArrayInitData, array, passive])
.exportFunc();
builder.addFunction(
"init_active",
makeSig([wasmRefNullType(array), kWasmI32, kWasmI32, kWasmI32], []))
.addBody([kExprLocalGet, 0, kExprLocalGet, 1, kExprLocalGet, 2,
kExprLocalGet, 3, kGCPrefix, kExprArrayInitData, array, active])
.exportFunc();
builder.addFunction(
"array_get", makeSig([wasmRefNullType(array), kWasmI32], [kWasmI32]))
.addBody([kExprLocalGet, 0, kExprLocalGet, 1,
kGCPrefix, kExprArrayGetS, array])
.exportFunc();
builder.addFunction("data_drop", kSig_v_v)
.addBody([kNumericPrefix, kExprDataDrop, passive])
.exportFunc();
let wasm = builder.instantiate().exports;
let array_length = 10;
assertTraps(kTrapNullDereference, () => wasm.init_passive(null, 0, 0, 0));
let array_obj = wasm.make_array(array_length);
for (i = 0; i < array_length; i++) {
assertEquals(0, wasm.array_get(array_obj, i));
}
// Does nothing.
wasm.init_active(array_obj, 0, 0, 0);
// Active segments count as dropped.
assertTraps(kTrapDataSegmentOutOfBounds,
() => wasm.init_active(array_obj, 0, 0, 1));
// Loading 0 bytes from the end of data segment does nothing.
wasm.init_passive(array_obj, 0, 6, 0);
// Loading 0 bytes to the end of the array does nothing.
wasm.init_passive(array_obj, array_length, 0, 0);
// Loading 0 bytes beyond the end of data segment traps.
assertTraps(kTrapDataSegmentOutOfBounds,
() => wasm.init_passive(array_obj, 0, 7, 0));
// Loading 0 bytes beyond the end of array traps.
assertTraps(kTrapArrayOutOfBounds,
() => wasm.init_passive(array_obj, array_length + 1, 1, 1));
// Out-of-bounds data segment.
assertTraps(kTrapDataSegmentOutOfBounds,
() => wasm.init_passive(array_obj, 1, 2, 3));
// Out-of-bounds data segment with out-of-smi-range segment offset.
assertTraps(kTrapDataSegmentOutOfBounds,
() => wasm.init_passive(array_obj, 1, 0x80000000, 0));
// Out-of-bounds array.
assertTraps(kTrapArrayOutOfBounds,
() => wasm.init_passive(array_obj, array_length - 1, 0, 2));
// Out-of-bounds array with out-of-smi-range length.
assertTraps(kTrapArrayOutOfBounds,
() => wasm.init_passive(array_obj, 0, 0, 0x80000000));
// Load [[1, 2], [3, 4]] at index 5 of array.
wasm.init_passive(array_obj, 5, 1, 2);
assertEquals(0, wasm.array_get(array_obj, 0));
assertEquals(0, wasm.array_get(array_obj, 1));
assertEquals(0, wasm.array_get(array_obj, 2));
assertEquals(0, wasm.array_get(array_obj, 3));
assertEquals(0, wasm.array_get(array_obj, 4));
// Bytes will be loaded in little-endian order.
assertEquals(0x0201, wasm.array_get(array_obj, 5));
assertEquals(0x0403, wasm.array_get(array_obj, 6));
assertEquals(0, wasm.array_get(array_obj, 7));
assertEquals(0, wasm.array_get(array_obj, 8));
assertEquals(0, wasm.array_get(array_obj, 9));
// Now drop the segment.
wasm.data_drop();
assertTraps(kTrapDataSegmentOutOfBounds,
() => wasm.init_passive(array_obj, 5, 1, 2));
})();
(function TestArrayInitDataLengthOverflow() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let array = builder.addArray(kWasmI64, true);
let passive = builder.addPassiveDataSegment([0, 1, 2, 3, 4, 5]);
builder.addFunction(
"make_array", makeSig([kWasmI32], [wasmRefType(array)]))
.addBody([kExprLocalGet, 0, kGCPrefix, kExprArrayNewDefault, array])
.exportFunc();
builder.addFunction(
"init_passive",
makeSig([wasmRefNullType(array), kWasmI32, kWasmI32, kWasmI32], []))
.addBody([kExprLocalGet, 0, kExprLocalGet, 1, kExprLocalGet, 2,
kExprLocalGet, 3, kGCPrefix, kExprArrayInitData, array, passive])
.exportFunc();
let wasm = builder.instantiate().exports;
let array_length = 10;
let array_obj = wasm.make_array(array_length);
// Out-of-bounds array: length is within Smi range, but computation of length
// in bytes causes 32-bit overflow.
assertTraps(kTrapArrayOutOfBounds,
() => wasm.init_passive(array_obj, array_length - 1, 0,
0x20000000));
})();
(function TestArrayInitDataImmutable() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let array = builder.addArray(kWasmI16, false);
let passive = builder.addPassiveDataSegment([0, 1, 2, 3, 4, 5]);
builder.addFunction(
"init_passive",
makeSig([wasmRefNullType(array), kWasmI32, kWasmI32, kWasmI32], []))
.addBody([kExprLocalGet, 0, kExprLocalGet, 1, kExprLocalGet, 2,
kExprLocalGet, 3, kGCPrefix, kExprArrayInitData, array, passive])
.exportFunc();
assertThrows(() => builder.instantiate(), WebAssembly.CompileError,
/array.init_data can only be used with mutable arrays/);
})();
(function TestArrayInitElem() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let sig = builder.addType(kSig_i_i);
let array = builder.addArray(wasmRefNullType(sig), true);
let table = builder.addTable(wasmRefNullType(sig), 10, 10);
let elem1 = builder.addFunction("succ", kSig_i_i)
.addBody([kExprLocalGet, 0, kExprI32Const, 1, kExprI32Add]);
let elem2 = builder.addFunction("pred", kSig_i_i)
.addBody([kExprLocalGet, 0, kExprI32Const, 1, kExprI32Sub]);
let passive = builder.addPassiveElementSegment(
[[kExprRefNull, sig], [kExprRefFunc, elem1.index],
[kExprRefFunc, elem2.index], [kExprRefFunc, elem1.index]],
wasmRefNullType(sig));
let active = builder.addActiveElementSegment(
table, [kExprI32Const, 0], [[kExprRefFunc, elem1.index]],
wasmRefNullType(sig));
builder.addFunction(
"make_array", makeSig([kWasmI32], [wasmRefType(array)]))
.addBody([kExprLocalGet, 0, kGCPrefix, kExprArrayNewDefault, array])
.exportFunc();
builder.addFunction(
"init_passive",
makeSig([wasmRefNullType(array), kWasmI32, kWasmI32, kWasmI32], []))
.addBody([kExprLocalGet, 0, kExprLocalGet, 1, kExprLocalGet, 2,
kExprLocalGet, 3, kGCPrefix, kExprArrayInitElem, array, passive])
.exportFunc();
builder.addFunction(
"init_active",
makeSig([wasmRefNullType(array), kWasmI32, kWasmI32, kWasmI32], []))
.addBody([kExprLocalGet, 0, kExprLocalGet, 1, kExprLocalGet, 2,
kExprLocalGet, 3, kGCPrefix, kExprArrayInitElem, array, active])
.exportFunc();
builder.addFunction(
"array_get", makeSig([wasmRefNullType(array), kWasmI32],
[wasmRefNullType(sig)]))
.addBody([kExprLocalGet, 0, kExprLocalGet, 1,
kGCPrefix, kExprArrayGet, array])
.exportFunc();
builder.addFunction("elem_drop", kSig_v_v)
.addBody([kNumericPrefix, kExprElemDrop, passive])
.exportFunc();
let wasm = builder.instantiate().exports;
let array_length = 10;
assertTraps(kTrapNullDereference, () => wasm.init_passive(null, 0, 0, 0));
let array_obj = wasm.make_array(array_length);
for (i = 0; i < array_length; i++) {
assertEquals(null, wasm.array_get(array_obj, i));
}
// Does nothing.
wasm.init_active(array_obj, 0, 0, 0);
// Active segments count as dropped.
assertTraps(kTrapElementSegmentOutOfBounds,
() => wasm.init_active(array_obj, 0, 0, 1));
// Loading 0 elements from the end of element segment does nothing.
wasm.init_passive(array_obj, 0, 4, 0);
// Loading 0 elements to the end of the array does nothing.
wasm.init_passive(array_obj, array_length, 0, 0);
// Loading 0 elements beyond the end of data segment traps.
assertTraps(kTrapElementSegmentOutOfBounds,
() => wasm.init_passive(array_obj, 0, 5, 0));
// Loading 0 elements beyond the end of array traps.
assertTraps(kTrapArrayOutOfBounds,
() => wasm.init_passive(array_obj, array_length + 1, 1, 1));
// Out-of-bounds element segment.
assertTraps(kTrapElementSegmentOutOfBounds,
() => wasm.init_passive(array_obj, 1, 2, 3));
// Out-of-bounds element segment with out-of-smi-bounds segment offset.
assertTraps(kTrapElementSegmentOutOfBounds,
() => wasm.init_passive(array_obj, 1, 0x80000000, 0));
// Out-of-bounds array.
assertTraps(kTrapArrayOutOfBounds,
() => wasm.init_passive(array_obj, array_length - 1, 0, 2));
// Out-of-bounds array with out-of-smi-bounds length
assertTraps(kTrapArrayOutOfBounds,
() => wasm.init_passive(array_obj, array_length - 1, 0,
0x80000000));
// Load the last three elements of the element segment at index 5.
wasm.init_passive(array_obj, 5, 1, 3);
assertEquals(null, wasm.array_get(array_obj, 0));
assertEquals(null, wasm.array_get(array_obj, 1));
assertEquals(null, wasm.array_get(array_obj, 2));
assertEquals(null, wasm.array_get(array_obj, 3));
assertEquals(null, wasm.array_get(array_obj, 4));
assertEquals(11, wasm.array_get(array_obj, 5)(10));
assertEquals(9, wasm.array_get(array_obj, 6)(10));
assertEquals(11, wasm.array_get(array_obj, 7)(10));
assertEquals(null, wasm.array_get(array_obj, 8));
assertEquals(null, wasm.array_get(array_obj, 9));
// Now drop the segment.
wasm.elem_drop();
assertTraps(kTrapElementSegmentOutOfBounds,
() => wasm.init_passive(array_obj, 5, 1, 3));
})();
(function TestArrayInitElemImmutable() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let array = builder.addArray(kWasmFuncRef, false);
let elem1 = builder.addFunction("succ", kSig_i_i)
.addBody([kExprLocalGet, 0, kExprI32Const, 1, kExprI32Add]);
let elem2 = builder.addFunction("pred", kSig_i_i)
.addBody([kExprLocalGet, 0, kExprI32Const, 1, kExprI32Sub]);
let passive = builder.addPassiveDataSegment([elem1.index, elem2.index,
elem1.index, elem2.index]);
builder.addFunction(
"init_passive",
makeSig([wasmRefNullType(array), kWasmI32, kWasmI32, kWasmI32], []))
.addBody([kExprLocalGet, 0, kExprLocalGet, 1, kExprLocalGet, 2,
kExprLocalGet, 3, kGCPrefix, kExprArrayInitElem, array, passive])
.exportFunc();
assertThrows(() => builder.instantiate(), WebAssembly.CompileError,
/array.init_elem can only be used with mutable arrays/);
})();
(function TestArrayCopyLargeI64Array() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let array = builder.addArray(kWasmI64, true);
builder.addFunction(
// initial value, length, index to check
"main", makeSig([kWasmI64, kWasmI32, kWasmI32], [kWasmI64]))
.addBody([kExprLocalGet, 0, kExprLocalGet, 1,
kGCPrefix, kExprArrayNew, array,
kExprLocalGet, 2, kGCPrefix, kExprArrayGet, array])
.exportFunc();
let instance = builder.instantiate();
assertEquals(1234n, instance.exports.main(1234n, 1000, 0));
assertEquals(-2345n, instance.exports.main(-2345n, 2000, 1000));
assertEquals(42n, instance.exports.main(42n, 2000, 1999));
})();