%PDF- %PDF-
Direktori : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/test/mjsunit/wasm/ |
Current File : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/test/mjsunit/wasm/multi-memory.js |
// 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 d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); // Add a {loadN} and {storeN} function for memory N. function addLoadAndStoreFunctions(builder, mem_index) { builder.addFunction(`load${mem_index}`, kSig_i_i) .addBody([kExprLocalGet, 0, kExprI32LoadMem, 0x40, mem_index, 0]) .exportFunc(); builder.addFunction(`store${mem_index}`, kSig_v_ii) .addBody([ kExprLocalGet, 1, kExprLocalGet, 0, kExprI32StoreMem, 0x40, mem_index, 0 ]) .exportFunc(); } // Add a {growN} and {sizeN} function for memory N. function addGrowAndSizeFunctions(builder, mem_index) { builder.addFunction(`grow${mem_index}`, kSig_i_i) .addBody([kExprLocalGet, 0, kExprMemoryGrow, mem_index]) .exportFunc(); builder.addFunction(`size${mem_index}`, kSig_i_v) .addBody([kExprMemorySize, mem_index]) .exportFunc(); } // Add a {initN_M} function for memory N and data segment M. function addMemoryInitFunction(builder, data_segment, mem_index) { builder.addFunction(`init${mem_index}_${data_segment}`, kSig_v_iii) .addBody([ kExprLocalGet, 0, // dst kExprLocalGet, 1, // offset kExprLocalGet, 2, // size kNumericPrefix, kExprMemoryInit, data_segment, mem_index ]) .exportFunc(); } // Add a {fillN} function for memory N. function addMemoryFillFunction(builder, mem_index) { builder.addFunction(`fill${mem_index}`, kSig_v_iii) .addBody([ kExprLocalGet, 0, // dst kExprLocalGet, 1, // value kExprLocalGet, 2, // size kNumericPrefix, kExprMemoryFill, mem_index ]) .exportFunc(); } // Add a {copyN_M} function for copying from memory M to memory N. function addMemoryCopyFunction(builder, mem_dst_index, mem_src_index) { builder.addFunction(`copy${mem_dst_index}_${mem_src_index}`, kSig_v_iii) .addBody([ kExprLocalGet, 0, // dst kExprLocalGet, 1, // src kExprLocalGet, 2, // size kNumericPrefix, kExprMemoryCopy, mem_dst_index, mem_src_index ]) .exportFunc(); } // Helper to test that two memories can be accessed independently. function testTwoMemories(instance, mem0_size, mem1_size) { const {load0, load1, store0, store1} = instance.exports; assertEquals(0, load0(0)); assertEquals(0, load1(0)); store0(47, 0); assertEquals(47, load0(0)); assertEquals(0, load1(0)); store1(11, 0); assertEquals(47, load0(0)); assertEquals(11, load1(0)); store1(22, 1); assertEquals(47, load0(0)); assertEquals(22, load1(1)); // The 22 is in the second byte when loading from 0. assertEquals(22 * 256 + 11, load1(0)); const mem0_bytes = mem0_size * kPageSize; load0(mem0_bytes - 4); // should not trap. for (const offset of [-3, -1, mem0_bytes - 3, mem0_bytes - 1, mem0_bytes]) { assertTraps(kTrapMemOutOfBounds, () => load0(offset)); assertTraps(kTrapMemOutOfBounds, () => store0(0, offset)); } const mem1_bytes = mem1_size * kPageSize; load1(mem1_bytes - 4); // should not trap. for (const offset of [-3, -1, mem1_bytes - 3, mem1_bytes - 1, mem1_bytes]) { assertTraps(kTrapMemOutOfBounds, () => load1(offset)); assertTraps(kTrapMemOutOfBounds, () => store1(0, offset)); } } 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); const builder = new WasmModuleBuilder(); const mem0_idx = builder.addMemory(1, 1); const mem1_idx = builder.addMemory(1, 1); addLoadAndStoreFunctions(builder, mem0_idx); addLoadAndStoreFunctions(builder, mem1_idx); const instance = builder.instantiate(); testTwoMemories(instance, 1, 1); })(); (function testMemoryIndexDecodedAsU32() { print(arguments.callee.name); for (let leb_length = 1; leb_length <= 6; ++leb_length) { // Create the array [0x80, 0x80, ..., 0x0] of length `leb_length`. This // encodes `0` using `leb_length` bytes. const leb = new Array(leb_length).fill(0x80).with(leb_length - 1, 0); const builder = new WasmModuleBuilder(); builder.addMemory(1, 1); builder.addFunction('load', kSig_i_i) .addBody([kExprLocalGet, 0, kExprI32LoadMem, 0x40, ...leb, 0]) .exportFunc(); builder.addFunction('store', kSig_v_ii) .addBody([ kExprLocalGet, 0, kExprLocalGet, 1, kExprI32StoreMem, 0x40, ...leb, 0 ]) .exportFunc(); builder.exportMemoryAs('mem'); if (leb_length == 6) { assertThrows( () => builder.instantiate(), WebAssembly.CompileError, /length overflow while decoding memory index/); continue; } const instance = builder.instantiate(); assertEquals(0, instance.exports.load(7)); instance.exports.store(7, 11); assertEquals(11, instance.exports.load(7)); assertEquals(0, instance.exports.load(11)); const expected_memory = new Uint8Array(kPageSize); expected_memory[7] = 11; assertMemoryEquals(expected_memory, instance.exports.mem); } })(); (function testImportedAndDeclaredMemories() { print(arguments.callee.name); const builder = new WasmModuleBuilder(); builder.addImportedMemory('imp', 'mem0'); builder.addMemory(1, 1); addLoadAndStoreFunctions(builder, 0); addLoadAndStoreFunctions(builder, 1); const mem0 = new WebAssembly.Memory({initial: 3, maximum: 4}); const instance = builder.instantiate({imp: {mem0: mem0}}); testTwoMemories(instance, 3, 1); })(); (function testTwoImportedMemories() { print(arguments.callee.name); const builder = new WasmModuleBuilder(); builder.addImportedMemory('imp', 'mem0'); builder.addImportedMemory('imp', 'mem1'); addLoadAndStoreFunctions(builder, 0); addLoadAndStoreFunctions(builder, 1); const mem0 = new WebAssembly.Memory({initial: 2, maximum: 3}); const mem1 = new WebAssembly.Memory({initial: 3, maximum: 4}); const instance = builder.instantiate({imp: {mem0: mem0, mem1: mem1}}); testTwoMemories(instance, 2, 3); })(); (function testTwoExportedMemories() { print(arguments.callee.name); const builder = new WasmModuleBuilder(); const mem0_idx = builder.addMemory(1, 1); const mem1_idx = builder.addMemory(1, 1); addLoadAndStoreFunctions(builder, mem0_idx); addLoadAndStoreFunctions(builder, mem1_idx); builder.exportMemoryAs('mem0', mem0_idx); builder.exportMemoryAs('mem1', mem1_idx); const instance = builder.instantiate(); const mem0 = new Uint8Array(instance.exports.mem0.buffer); const mem1 = new Uint8Array(instance.exports.mem1.buffer); assertEquals(0, mem0[11]); assertEquals(0, mem1[11]); instance.exports.store0(47, 11); assertEquals(47, mem0[11]); assertEquals(0, mem1[11]); instance.exports.store1(49, 11); assertEquals(47, mem0[11]); assertEquals(49, mem1[11]); })(); (function testMultiMemoryDataSegments() { print(arguments.callee.name); var builder = new WasmModuleBuilder(); const mem0_idx = builder.addMemory(1, 1); const mem1_idx = builder.addMemory(1, 1); addLoadAndStoreFunctions(builder, mem0_idx); addLoadAndStoreFunctions(builder, mem1_idx); const mem0_offset = 11; const mem1_offset = 23; builder.addDataSegment(mem1_offset, [7, 7], false, 1); builder.addDataSegment(mem0_offset, [9, 9], false, 0); builder.exportMemoryAs('mem0', 0); builder.exportMemoryAs('mem1', 1); const instance = builder.instantiate(); const expected_memory0 = new Uint8Array(kPageSize); expected_memory0.set([9, 9], mem0_offset); const expected_memory1 = new Uint8Array(kPageSize); expected_memory1.set([7, 7], mem1_offset); assertMemoryEquals(expected_memory0, instance.exports.mem0); assertMemoryEquals(expected_memory1, instance.exports.mem1); })(); (function testMultiMemoryDataSegmentsOutOfBounds() { print(arguments.callee.name); // Check that we use the right memory size for the bounds check. for (let [mem0_size, mem1_size] of [[1, 2], [2, 1]]) { for (let [mem0_offset, mem1_offset] of [[0, 0], [1, 2], [0, 2], [1, 0]]) { var builder = new WasmModuleBuilder(); const mem0_idx = builder.addMemory(mem0_size, mem0_size); const mem1_idx = builder.addMemory(mem1_size, mem1_size); builder.addDataSegment(mem0_offset * kPageSize, [0], false, mem0_idx); builder.addDataSegment(mem1_offset * kPageSize, [0], false, mem1_idx); if (mem0_offset < mem0_size && mem1_offset < mem1_size) { builder.instantiate(); // should not throw. continue; } const oob = mem0_offset >= mem0_size ? 0 : 1; const expected_offset = [mem0_offset, mem1_offset][oob] * kPageSize; const expected_mem_size = [mem0_size, mem1_size][oob] * kPageSize; const expected_msg = `WebAssembly.Instance(): data segment ${oob} is out of bounds ` + `(offset ${expected_offset}, length 1, ` + `memory size ${expected_mem_size})`; assertThrows( () => builder.instantiate(), WebAssembly.RuntimeError, expected_msg); } } })(); (function testMultiMemoryInit() { print(arguments.callee.name); var builder = new WasmModuleBuilder(); const mem0_idx = builder.addMemory(1, 1); const mem1_idx = builder.addMemory(1, 1); const mem0_offset = 11; const mem1_offset = 23; const seg0_init = [5, 4, 3]; const seg0_id = builder.addPassiveDataSegment(seg0_init); const seg1_init = [11, 10, 9, 8, 7]; const seg1_id = builder.addPassiveDataSegment(seg1_init); builder.exportMemoryAs('mem0', mem0_idx); builder.exportMemoryAs('mem1', mem1_idx); // Initialize memory 1 from data segment 0 and vice versa. addMemoryInitFunction(builder, mem0_idx, seg1_id); addMemoryInitFunction(builder, mem1_idx, seg0_id); const instance = builder.instantiate(); const expected_memory0 = new Uint8Array(kPageSize); const expected_memory1 = new Uint8Array(kPageSize); assertMemoryEquals(expected_memory0, instance.exports.mem0); assertMemoryEquals(expected_memory1, instance.exports.mem1); instance.exports.init0_1(3, 1, 3); expected_memory0.set(seg1_init.slice(1, 4), 3); assertMemoryEquals(expected_memory0, instance.exports.mem0); assertMemoryEquals(expected_memory1, instance.exports.mem1); instance.exports.init1_0(17, 0, 2); expected_memory1.set(seg0_init.slice(0, 2), 17); assertMemoryEquals(expected_memory0, instance.exports.mem0); assertMemoryEquals(expected_memory1, instance.exports.mem1); assertTraps(kTrapMemOutOfBounds, () => instance.exports.init0_1(0, 5, 1)); assertTraps(kTrapMemOutOfBounds, () => instance.exports.init1_0(0, 3, 1)); })(); (function testMultiMemoryFill() { print(arguments.callee.name); var builder = new WasmModuleBuilder(); const mem0_idx = builder.addMemory(1, 1); const mem1_idx = builder.addMemory(2, 2); builder.exportMemoryAs('mem0', mem0_idx); builder.exportMemoryAs('mem1', mem1_idx); addMemoryFillFunction(builder, mem0_idx); addMemoryFillFunction(builder, mem1_idx); const instance = builder.instantiate(); const expected_memory0 = new Uint8Array(kPageSize); const expected_memory1 = new Uint8Array(2 * kPageSize); assertMemoryEquals(expected_memory0, instance.exports.mem0); assertMemoryEquals(expected_memory1, instance.exports.mem1); // Fill [3..4] in mem0 with value 7. instance.exports.fill0(3, 7, 2); // dst, value, size expected_memory0.fill(7, 3, 5); // value, start, end assertMemoryEquals(expected_memory0, instance.exports.mem0); assertMemoryEquals(expected_memory1, instance.exports.mem1); // Fill [4..11] in mem0 with value 17. instance.exports.fill1(4, 17, 8); // dst, value, size expected_memory1.fill(17, 4, 12); // value, start, end assertMemoryEquals(expected_memory0, instance.exports.mem0); assertMemoryEquals(expected_memory1, instance.exports.mem1); // mem0 has size 1. instance.exports.fill0(kPageSize - 1, 1, 1); assertTraps( kTrapMemOutOfBounds, () => instance.exports.fill0(kPageSize - 1, 1, 2)); assertTraps( kTrapMemOutOfBounds, () => instance.exports.fill0(kPageSize, 1, 1)); // mem1 has size 2. instance.exports.fill1(2 * kPageSize - 1, 1, 1); assertTraps( kTrapMemOutOfBounds, () => instance.exports.fill1(2 * kPageSize - 1, 1, 2)); assertTraps( kTrapMemOutOfBounds, () => instance.exports.fill1(2 * kPageSize, 1, 1)); })(); (function testMultiMemoryCopy() { print(arguments.callee.name); var builder = new WasmModuleBuilder(); const mem0_id = 0; builder.addMemory(1, 1); const mem1_id = 1; builder.addMemory(2, 2); builder.exportMemoryAs('mem0', mem0_id); builder.exportMemoryAs('mem1', mem1_id); addMemoryCopyFunction(builder, mem0_id, mem0_id); addMemoryCopyFunction(builder, mem0_id, mem1_id); addMemoryCopyFunction(builder, mem1_id, mem0_id); addMemoryCopyFunction(builder, mem1_id, mem1_id); const instance = builder.instantiate(); const expected_memory0 = new Uint8Array(kPageSize); const expected_memory1 = new Uint8Array(2 * kPageSize); // Set some initial bytes that we can then copy around. new Uint8Array(instance.exports.mem0.buffer).set([1, 2, 3, 4, 5]); expected_memory0.set([1, 2, 3, 4, 5], 0); assertMemoryEquals(expected_memory0, instance.exports.mem0); // Copy [3..5] to [7..9] in mem0. instance.exports.copy0_0(7, 3, 3); // dst, src, size expected_memory0.set([1, 2, 3, 4, 5, 0, 0, 4, 5, 0]); assertMemoryEquals(expected_memory0, instance.exports.mem0); // Copy [3..7] from mem0 to [2..6] in mem1. instance.exports.copy1_0(2, 3, 5); // dst, src, size expected_memory1.set([0, 0, 4, 5, 0, 0, 4]); assertMemoryEquals(expected_memory0, instance.exports.mem0); assertMemoryEquals(expected_memory1, instance.exports.mem1); // Copy [3..4] from mem1 to [1..3] in mem0. instance.exports.copy0_1(1, 3, 2); // dst, src, size expected_memory0.set([5, 0], 1); assertMemoryEquals(expected_memory0, instance.exports.mem0); assertMemoryEquals(expected_memory1, instance.exports.mem1); // Copy [2..4] to [0..2] in mem1. instance.exports.copy1_1(0, 2, 3); // dst, src, size expected_memory1.set([4, 5, 0]); assertMemoryEquals(expected_memory0, instance.exports.mem0); assertMemoryEquals(expected_memory1, instance.exports.mem1); const mem0_size = kPageSize; const mem1_size = 2 * kPageSize; for ([method, dst_size, src_size] of [ [instance.exports.copy0_0, mem0_size, mem0_size], [instance.exports.copy0_1, mem0_size, mem1_size], [instance.exports.copy1_0, mem1_size, mem0_size], [instance.exports.copy1_1, mem1_size, mem1_size]]) { print(`- ${method}`); // Test at the boundary. method(dst_size - 1, src_size - 1, 1); // Then test one byte further. assertTraps(kTrapMemOutOfBounds, () => method(dst_size, src_size - 1, 1)); assertTraps(kTrapMemOutOfBounds, () => method(dst_size - 1, src_size, 1)); assertTraps( kTrapMemOutOfBounds, () => method(dst_size - 1, src_size - 2, 2)); assertTraps( kTrapMemOutOfBounds, () => method(dst_size - 2, src_size - 1, 2)); } })(); (function testGrowMultipleMemories() { print(arguments.callee.name); var builder = new WasmModuleBuilder(); const mem0_idx = builder.addMemory(1, 4); const mem1_idx = builder.addMemory(1, 5); addGrowAndSizeFunctions(builder, mem0_idx); addGrowAndSizeFunctions(builder, mem1_idx); builder.exportMemoryAs('mem0', mem0_idx); builder.exportMemoryAs('mem1', mem1_idx); const instance = builder.instantiate(); assertEquals(1, instance.exports.grow0(2)); assertEquals(3, instance.exports.grow0(1)); assertEquals(4, instance.exports.size0()); assertEquals(-1, instance.exports.grow0(1)); assertEquals(4, instance.exports.size0()); assertEquals(1, instance.exports.grow1(2)); assertEquals(3, instance.exports.grow1(2)); assertEquals(5, instance.exports.size1()); assertEquals(-1, instance.exports.grow1(1)); assertEquals(5, instance.exports.size1()); })(); (function testGrowDecodesMemoryIndexAsU32() { print(arguments.callee.name); for (let leb_length = 1; leb_length <= 6; ++leb_length) { // Create the array [0x80, 0x80, ..., 0x0] of length `leb_length`. This // encodes `0` using `leb_length` bytes. const leb = new Array(leb_length).fill(0x80).with(leb_length - 1, 0); var builder = new WasmModuleBuilder(); builder.addMemory(1, 4); builder.addFunction('grow', kSig_i_i) .addBody([kExprLocalGet, 0, kExprMemoryGrow, ...leb]) .exportFunc(); builder.exportMemoryAs('mem', 0); if (leb_length == 6) { assertThrows( () => builder.instantiate(), WebAssembly.CompileError, /length overflow while decoding memory index/); continue; } const instance = builder.instantiate(); assertEquals(1, instance.exports.grow(2)); assertEquals(-1, instance.exports.grow(2)); assertEquals(3, instance.exports.grow(1)); } })(); (function testMultipleMemoriesInOneFunction() { print(arguments.callee.name); // Some "interesting" access patterns. const mem_indexes_list = [[0, 1, 0, 1], [1, 0, 1, 0], [0, 0, 1, 1], [1, 1, 0, 0]]; const builder = new WasmModuleBuilder(); const mem0_idx = builder.addMemory(1, 1); const mem1_idx = builder.addMemory(1, 1); for (let [idx, mem_indexes] of mem_indexes_list.entries()) { let sig = makeSig(new Array(4).fill(kWasmI32), [kWasmI32]); builder.addFunction(`load${idx}`, sig) .addBody([ kExprLocalGet, 0, kExprI32LoadMem, 0x40, mem_indexes[0], 0, // load 1 kExprLocalGet, 1, kExprI32LoadMem, 0x40, mem_indexes[1], 0, // load 2 kExprI32Add, // add kExprLocalGet, 2, kExprI32LoadMem, 0x40, mem_indexes[2], 0, // load 3 kExprI32Add, // add kExprLocalGet, 3, kExprI32LoadMem, 0x40, mem_indexes[3], 0, // load 4 kExprI32Add, // add ]) .exportFunc(); } builder.exportMemoryAs('mem0', mem0_idx); builder.exportMemoryAs('mem1', mem1_idx); const instance = builder.instantiate(); // Create random memory contents. let buf0 = new DataView(instance.exports.mem0.buffer); let buf1 = new DataView(instance.exports.mem1.buffer); for (let i = 0; i < kPageSize; ++i) { buf0.setUint8(i, Math.floor(Math.random() * 0xff)); buf1.setUint8(i, Math.floor(Math.random() * 0xff)); } for (let run = 0; run < 10; ++run) { // Return a random index in [0, kPageSize - 3) such that we can read four // bytes from there. let get_random_offset = () => Math.floor(Math.random() * (kPageSize - 3)); let inputs = new Array(4).fill(0).map(get_random_offset); for (let [func_idx, mem_indexes] of mem_indexes_list.entries()) { let expected = 0; for (let i = 0; i < 4; ++i) { let buf = mem_indexes[i] == 0 ? buf0 : buf1; expected += buf.getInt32(inputs[i], true); } expected >>= 0; // Truncate to 32 bit. assertEquals(expected, instance.exports[`load${func_idx}`](...inputs)); } } })(); (function testAtomicsOnMultiMemory() { print(arguments.callee.name); const builder = new WasmModuleBuilder(); const mem0_idx = builder.addMemory(1, 1, true); const mem1_idx = builder.addMemory(2, 2, true); builder.exportMemoryAs('mem0', mem0_idx); builder.exportMemoryAs('mem1', mem1_idx); for (let mem_idx of [mem0_idx, mem1_idx]) { builder.addFunction(`load${mem_idx}`, kSig_i_i) .addBody([ kExprLocalGet, 0, // - kAtomicPrefix, kExprI32AtomicLoad, 0x42, mem_idx, 0 // - ]) .exportFunc(); builder.addFunction(`store${mem_idx}`, kSig_v_ii) .addBody([ kExprLocalGet, 0, // - kExprLocalGet, 1, // - kAtomicPrefix, kExprI32AtomicStore, 0x42, mem_idx, 0 // - ]) .exportFunc(); builder.addFunction(`cmpxchg${mem_idx}`, kSig_i_iii) .addBody([ kExprLocalGet, 0, // - kExprLocalGet, 1, // - kExprLocalGet, 2, // - kAtomicPrefix, kExprI32AtomicCompareExchange, 0x42, mem_idx, 0 // - ]) .exportFunc(); } const instance = builder.instantiate(); const {mem0, load0, store0, cmpxchg0, mem1, load1, store1, cmpxchg1} = instance.exports; const data0 = new DataView(mem0.buffer); const data1 = new DataView(mem1.buffer); const offset0 = 16; const value0 = 13; store0(offset0, value0); assertEquals(value0, load0(offset0)); assertEquals(0, load1(offset0)); const offset1 = 24; const value1 = 11; store1(offset1, value1); assertEquals(value1, load1(offset1)); assertEquals(0, load0(offset1)); assertEquals(value0, cmpxchg0(offset0, -1, -1)); assertEquals(value0, cmpxchg0(offset0, value0, value1)); assertEquals(value1, load0(offset0)); assertEquals(value1, cmpxchg1(offset1, -1, -1)); assertEquals(value1, cmpxchg1(offset1, value1, value0)); assertEquals(value0, load1(offset1)); assertEquals(0, load0(offset1)); assertEquals(0, load1(offset0)); // Test traps. assertEquals(0, load0(kPageSize - 4)); assertEquals(0, load1(2 * kPageSize - 4)); assertTraps(kTrapMemOutOfBounds, () => load0(kPageSize)); assertTraps(kTrapMemOutOfBounds, () => load1(2 * kPageSize)); })();