node/deps/v8/test/mjsunit/wasm/multi-memory64.js
Michaël Zasso 9d7cd9b864
deps: update V8 to 12.8.374.13
PR-URL: https://github.com/nodejs/node/pull/54077
Reviewed-By: Jiawen Geng <technicalcute@gmail.com>
Reviewed-By: Richard Lau <rlau@redhat.com>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com>
2024-08-16 16:03:01 +02:00

253 lines
9.7 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.
// Flags: --experimental-wasm-multi-memory --experimental-wasm-memory64
d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
function assertMemoryEquals(expected, memory) {
assertInstanceof(memory, WebAssembly.Memory);
assertInstanceof(expected, Uint8Array);
const buf = new Uint8Array(memory.buffer);
// For better output, check the first 50 bytes separately first.
assertEquals(expected.slice(0, 50), buf.slice(0, 50));
// Now also check the full memory content.
assertEquals(expected, buf);
}
(function testBasicMultiMemory() {
print(arguments.callee.name);
// Test two memories: One 32-bit and one 64-bit, in both orders.
for (let mem64_idx of [0, 1]) {
const builder = new WasmModuleBuilder();
const mem32_idx = 1 - mem64_idx;
const mem32_pages = 1;
const mem32_size = mem32_pages * kPageSize;
const mem64_pages = 3;
const mem64_size = mem64_pages * kPageSize;
if (mem32_idx == 0) {
builder.addMemory(mem32_pages, mem32_pages);
builder.addMemory64(mem64_pages, mem64_pages);
} else {
builder.addMemory64(mem64_pages, mem64_pages);
builder.addMemory(mem32_pages, mem32_pages);
}
builder.exportMemoryAs('mem32', mem32_idx);
builder.exportMemoryAs('mem64', mem64_idx);
builder.addFunction('load32', kSig_i_i)
.addBody([kExprLocalGet, 0, kExprI32LoadMem, 0x40, mem32_idx, 0])
.exportFunc();
builder.addFunction('load64', kSig_i_l)
.addBody([kExprLocalGet, 0, kExprI32LoadMem, 0x40, mem64_idx, 0])
.exportFunc();
const instance = builder.instantiate();
const mem32_offset = 48;
const mem64_offset = 16;
const value = 13;
const view32 = new DataView(instance.exports.mem32.buffer);
const view64 = new DataView(instance.exports.mem64.buffer);
view32.setInt32(mem32_offset, value, true);
view64.setInt32(mem64_offset, value, true);
const {load32, load64} = instance.exports;
assertEquals(value, load32(mem32_offset));
assertEquals(0, load32(mem64_offset));
assertEquals(0, load64(BigInt(mem32_offset)));
assertEquals(value, load64(BigInt(mem64_offset)));
assertEquals(0, load32(mem32_size - 4));
assertEquals(0, load64(BigInt(mem64_size - 4)));
assertTraps(kTrapMemOutOfBounds, () => load32(mem32_size - 3));
assertTraps(kTrapMemOutOfBounds, () => load64(BigInt(mem64_size - 3)));
}
})();
(function testMultiMemoryInit() {
print(arguments.callee.name);
// Test two memories: One 32-bit and one 64-bit, in both orders.
for (let mem64_idx of [0, 1]) {
const builder = new WasmModuleBuilder();
const mem32_idx = 1 - mem64_idx;
const mem32_pages = 1;
const mem32_size = mem32_pages * kPageSize;
const mem64_pages = 3;
const mem64_size = mem64_pages * kPageSize;
if (mem32_idx == 0) {
builder.addMemory(mem32_pages, mem32_pages);
builder.addMemory64(mem64_pages, mem64_pages);
} else {
builder.addMemory64(mem64_pages, mem64_pages);
builder.addMemory(mem32_pages, mem32_pages);
}
builder.exportMemoryAs('mem32', mem32_idx);
builder.exportMemoryAs('mem64', mem64_idx);
const data = [1, 2, 3, 4, 5];
const seg_id = builder.addPassiveDataSegment(data);
builder.addFunction('init32', kSig_v_iii)
.addBody([
kExprLocalGet, 0, // dst
kExprLocalGet, 1, // offset
kExprLocalGet, 2, // size
kNumericPrefix, kExprMemoryInit, seg_id, mem32_idx
])
.exportFunc();
builder.addFunction('init64', kSig_v_lii)
.addBody([
kExprLocalGet, 0, // dst
kExprLocalGet, 1, // offset
kExprLocalGet, 2, // size
kNumericPrefix, kExprMemoryInit, seg_id, mem64_idx
])
.exportFunc();
const instance = builder.instantiate();
const {init32, init64} = instance.exports;
const expected_mem32 = new Uint8Array(mem32_size);
const expected_mem64 = new Uint8Array(mem64_size);
assertMemoryEquals(expected_mem32, instance.exports.mem32);
assertMemoryEquals(expected_mem64, instance.exports.mem64);
init32(7, 1, 3); // dst, (data) offset, size
expected_mem32.set(data.slice(1, 4), 7);
assertMemoryEquals(expected_mem32, instance.exports.mem32);
assertMemoryEquals(expected_mem64, instance.exports.mem64);
init64(11n, 3, 2); // dst, (data) offset, size
expected_mem64.set(data.slice(3, 5), 11);
assertMemoryEquals(expected_mem32, instance.exports.mem32);
assertMemoryEquals(expected_mem64, instance.exports.mem64);
// Test bounds checks.
init32(mem32_size - 1, 0, 1); // dst, (data) offset, size
assertTraps(kTrapMemOutOfBounds, () => init32(mem32_size - 1, 0, 2));
init64(BigInt(mem64_size - 1), 0, 1); // dst, (data) offset, size
assertTraps(
kTrapMemOutOfBounds, () => init64(BigInt(mem64_size - 1), 0, 2));
}
})();
(function testTypingForCopyBetween32And64Bit() {
print(arguments.callee.name);
for (let [src, dst, src_type, dst_type, size_type, expect_valid] of [
// Copy from 32 to 64 bit with correct types.
[32, 64, kWasmI32, kWasmI64, kWasmI32, true],
// Copy from 64 to 32 bit with correct types.
[64, 32, kWasmI64, kWasmI32, kWasmI32, true],
// Copy from 32 to 64 bit with always one type wrong.
[32, 64, kWasmI64, kWasmI64, kWasmI32, false],
[32, 64, kWasmI32, kWasmI32, kWasmI32, false],
[32, 64, kWasmI32, kWasmI64, kWasmI64, false],
// Copy from 64 to 32 bit with always one type wrong.
[64, 32, kWasmI32, kWasmI32, kWasmI32, false],
[64, 32, kWasmI64, kWasmI64, kWasmI32, false],
[64, 32, kWasmI64, kWasmI32, kWasmI64, false],
]) {
let type_str = type => type == kWasmI32 ? 'i32' : 'i64';
print(`- copy from ${src} to ${dst} using types src=${
type_str(src_type)}, dst=${type_str(dst_type)}, size=${
type_str(size_type)}`);
let builder = new WasmModuleBuilder();
const kMemSizeInPages = 10;
const kMemSize = kMemSizeInPages * kPageSize;
let mem64_index = builder.addMemory64(kMemSizeInPages, kMemSizeInPages);
let mem32_index = builder.addMemory(kMemSizeInPages, kMemSizeInPages);
builder.exportMemoryAs('mem64', mem64_index);
builder.exportMemoryAs('mem32', mem32_index);
let src_index = src == 32 ? mem32_index : mem64_index;
let dst_index = dst == 32 ? mem32_index : mem64_index;
builder.addFunction('copy', makeSig([dst_type, src_type, size_type], []))
.addBody([
kExprLocalGet, 0, // dst
kExprLocalGet, 1, // src
kExprLocalGet, 2, // size
kNumericPrefix, kExprMemoryCopy, dst_index, src_index // memcpy
])
.exportFunc();
if (expect_valid) {
builder.toModule();
} else {
assertThrows(
() => builder.toModule(), WebAssembly.CompileError,
/expected type i(32|64), found local.get of type i(32|64)/);
}
}
})();
(function testCopyBetween32And64Bit() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
const kMemSizeInPages = 10;
const kMemSize = kMemSizeInPages * kPageSize;
let mem64_index = builder.addMemory64(kMemSizeInPages, kMemSizeInPages);
let mem32_index = builder.addMemory(kMemSizeInPages, kMemSizeInPages);
builder.exportMemoryAs('mem64', mem64_index);
builder.exportMemoryAs('mem32', mem32_index);
builder
.addFunction('copy_32_to_64', makeSig([kWasmI64, kWasmI32, kWasmI32], []))
.addBody([
kExprLocalGet, 0, // dst
kExprLocalGet, 1, // src
kExprLocalGet, 2, // size
kNumericPrefix, kExprMemoryCopy, mem64_index, mem32_index // memcpy
])
.exportFunc();
builder
.addFunction('copy_64_to_32', makeSig([kWasmI32, kWasmI64, kWasmI32], []))
.addBody([
kExprLocalGet, 0, // dst
kExprLocalGet, 1, // src
kExprLocalGet, 2, // size
kNumericPrefix, kExprMemoryCopy, mem32_index, mem64_index // memcpy
])
.exportFunc();
let instance = builder.instantiate();
let {mem32, mem64, copy_32_to_64, copy_64_to_32} = instance.exports;
// These helpers extract the memory at [offset, offset+size)] into an Array.
let memory32 = (offset, size) =>
Array.from(new Uint8Array(mem32.buffer.slice(offset, offset + size)));
let memory64 = (offset, size) =>
Array.from(new Uint8Array(mem64.buffer.slice(offset, offset + size)));
// Init mem32[3] to 11.
new Uint8Array(mem32.buffer)[3] = 11;
// Copy mem32[2..4] to mem64[1..3].
copy_32_to_64(1n, 2, 3);
assertEquals([0, 0, 0, 11, 0], memory32(0, 5));
assertEquals([0, 0, 11, 0, 0], memory64(0, 5));
// Copy mem64[2..3] to mem32[1..2].
copy_64_to_32(1, 2n, 2);
assertEquals([0, 11, 0, 11, 0], memory32(0, 5));
assertEquals([0, 0, 11, 0, 0], memory64(0, 5));
// Just before OOB.
copy_32_to_64(BigInt(kMemSize), 0, 0);
copy_64_to_32(kMemSize, 0n, 0);
copy_32_to_64(BigInt(kMemSize - 3), 0, 3);
copy_64_to_32(kMemSize - 3, 0n, 3);
assertEquals([0, 11, 0], memory64(kMemSize - 3, 3));
// OOB.
assertTraps(
kTrapMemOutOfBounds, () => copy_32_to_64(BigInt(kMemSize + 1), 0, 0));
assertTraps(
kTrapMemOutOfBounds, () => copy_64_to_32(kMemSize + 1, 0n, 0));
assertTraps(
kTrapMemOutOfBounds, () => copy_32_to_64(BigInt(kMemSize - 2), 0, 3));
assertTraps(
kTrapMemOutOfBounds, () => copy_64_to_32(kMemSize - 2, 0n, 3));
})();