| // Copyright 2019 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. |
| |
| // TODO(v8:8832): Enable --stress-opt on these tests |
| // Flags: --wasm-grow-shared-memory |
| // Flags: --experimental-wasm-threads --no-stress-opt |
| |
| load("test/mjsunit/wasm/wasm-module-builder.js"); |
| |
| (function TestGrowSharedMemoryWithoutPostMessage() { |
| print(arguments.callee.name); |
| let memory = new WebAssembly.Memory({initial: 1, maximum: 5, shared: true}); |
| assertEquals(memory.buffer.byteLength, kPageSize); |
| assertEquals(1, memory.grow(1)); |
| assertEquals(memory.buffer.byteLength, 2 * kPageSize); |
| })(); |
| |
| function assertIsWasmSharedMemory(memory) { |
| assertTrue(memory instanceof Object, |
| "Memory is not an object"); |
| assertTrue(memory instanceof WebAssembly.Memory, |
| "Object is not WebAssembly.Memory" ); |
| assertTrue(memory.buffer instanceof SharedArrayBuffer, |
| "Memory.buffer is not a SharedArrayBuffer"); |
| assertTrue(Object.isFrozen(memory.buffer), |
| "Memory.buffer not frozen"); |
| } |
| |
| function assertTrue(value, msg) { |
| if (!value) { |
| postMessage("Error: " + msg); |
| throw new Error("Exit"); // To stop testing. |
| } |
| } |
| |
| let workerHelpers = assertTrue.toString() + assertIsWasmSharedMemory.toString(); |
| |
| (function TestPostMessageWithGrow() { |
| print(arguments.callee.name); |
| let worker = new Worker(workerHelpers + |
| `onmessage = function(obj) { |
| assertIsWasmSharedMemory(obj.memory); |
| assertTrue(1 === obj.memory.grow(1)); |
| assertTrue(obj.memory.buffer.byteLength === obj.expected_size); |
| assertIsWasmSharedMemory(obj.memory); |
| postMessage("OK"); |
| }`, {type: 'string'}); |
| |
| let memory = new WebAssembly.Memory({initial: 1, maximum: 5, shared: true}); |
| let obj = {memory: memory, expected_size: 2 * kPageSize}; |
| assertEquals(obj.memory.buffer.byteLength, kPageSize); |
| worker.postMessage(obj); |
| assertEquals("OK", worker.getMessage()); |
| assertEquals(obj.memory.buffer.byteLength, 2 * kPageSize); |
| worker.terminate(); |
| })(); |
| |
| |
| // PostMessage from two different workers, and assert that the grow |
| // operations are performed on the same memory object. |
| (function TestWorkersWithGrowEarlyWorkerTerminate() { |
| print(arguments.callee.name); |
| let workerScript = workerHelpers + |
| `onmessage = function(obj) { |
| assertIsWasmSharedMemory(obj.memory); |
| obj.memory.grow(1); |
| assertIsWasmSharedMemory(obj.memory); |
| assertTrue(obj.memory.buffer.byteLength === obj.expected_size); |
| postMessage("OK"); |
| };`; |
| |
| let workers = [new Worker(workerScript, {type: 'string'}), |
| new Worker(workerScript, {type: 'string'})]; |
| let memory = new WebAssembly.Memory({initial: 1, maximum: 5, shared: true}); |
| let expected_pages = 1; |
| for (let worker of workers) { |
| assertEquals(memory.buffer.byteLength, expected_pages++ * kPageSize); |
| let obj = {memory: memory, expected_size: expected_pages * kPageSize}; |
| worker.postMessage(obj); |
| assertEquals("OK", worker.getMessage()); |
| assertEquals(memory.buffer.byteLength, expected_pages * kPageSize); |
| worker.terminate(); |
| } |
| assertEquals(memory.buffer.byteLength, expected_pages * kPageSize); |
| })(); |
| |
| // PostMessage of Multiple memories and grow |
| (function TestGrowSharedWithMultipleMemories() { |
| print(arguments.callee.name); |
| let workerScript = workerHelpers + |
| `onmessage = function(obj) { |
| let expected_size = 0; |
| let kPageSize = 0x10000; |
| for (let memory of obj.memories) { |
| assertIsWasmSharedMemory(memory); |
| assertTrue(expected_size === memory.grow(2)); |
| expected_size+=2; |
| assertIsWasmSharedMemory(memory); |
| assertTrue(memory.buffer.byteLength === expected_size * kPageSize); |
| } |
| postMessage("OK"); |
| };`; |
| |
| let worker = new Worker(workerScript, {type: 'string'}); |
| let memories = [new WebAssembly.Memory({initial: 0, maximum: 2, shared: true}), |
| new WebAssembly.Memory({initial: 2, maximum: 10, shared: true}), |
| new WebAssembly.Memory({initial: 4, maximum: 12, shared: true})]; |
| let obj = {memories: memories}; |
| worker.postMessage(obj); |
| assertEquals("OK", worker.getMessage()); |
| assertEquals(2 * kPageSize, memories[0].buffer.byteLength); |
| assertEquals(4 * kPageSize, memories[1].buffer.byteLength); |
| assertEquals(6 * kPageSize, memories[2].buffer.byteLength); |
| worker.terminate(); |
| })(); |
| |
| // SharedMemory Object shared between different instances |
| (function TestPostMessageJSAndWasmInterop() { |
| print(arguments.callee.name); |
| let worker = new Worker(workerHelpers + |
| `onmessage = function(obj) { |
| let kPageSize = 0x10000; |
| assertIsWasmSharedMemory(obj.memory); |
| let instance = new WebAssembly.Instance( |
| obj.module, {m: {memory: obj.memory}}); |
| assertTrue(5 === obj.memory.grow(10)); |
| assertIsWasmSharedMemory(obj.memory); |
| assertTrue(obj.memory.buffer.byteLength === 15 * kPageSize); |
| assertTrue(15 === instance.exports.grow(5)); |
| assertIsWasmSharedMemory(obj.memory); |
| assertTrue(obj.memory.buffer.byteLength === 20 * kPageSize); |
| postMessage("OK"); |
| }`, {type: 'string'}); |
| |
| let memory = new WebAssembly.Memory({initial: 5, maximum: 50, shared: true}); |
| var builder = new WasmModuleBuilder(); |
| builder.addImportedMemory("m", "memory", 5, 100, "shared"); |
| builder.addFunction("grow", kSig_i_i) |
| .addBody([kExprGetLocal, 0, kExprMemoryGrow, kMemoryZero]) |
| .exportFunc(); |
| var module = new WebAssembly.Module(builder.toBuffer()); |
| let obj = {memory: memory, module: module}; |
| assertEquals(obj.memory.buffer.byteLength, 5 * kPageSize); |
| worker.postMessage(obj); |
| assertEquals("OK", worker.getMessage()); |
| worker.terminate(); |
| assertEquals(obj.memory.buffer.byteLength, 20 * kPageSize); |
| })(); |
| |
| (function TestConsecutiveJSAndWasmSharedGrow() { |
| print(arguments.callee.name); |
| let worker = new Worker(workerHelpers + |
| `onmessage = function(obj) { |
| let kPageSize = 0x10000; |
| assertIsWasmSharedMemory(obj.memory); |
| let instance = new WebAssembly.Instance( |
| obj.module, {m: {memory: obj.memory}}); |
| assertTrue(5 === obj.memory.grow(10)); |
| assertIsWasmSharedMemory(obj.memory); |
| assertTrue(obj.memory.buffer.byteLength === 15 * kPageSize); |
| assertTrue(15 === instance.exports.grow(5)); |
| assertIsWasmSharedMemory(obj.memory); |
| assertTrue(obj.memory.buffer.byteLength === 20 * kPageSize); |
| postMessage("OK"); |
| }`, {type: 'string'}); |
| |
| let memory = new WebAssembly.Memory({initial: 5, maximum: 50, shared: true}); |
| var builder = new WasmModuleBuilder(); |
| builder.addImportedMemory("m", "memory", 5, 100, "shared"); |
| builder.addFunction("grow", kSig_i_i) |
| .addBody([kExprGetLocal, 0, kExprMemoryGrow, kMemoryZero]) |
| .exportFunc(); |
| var module = new WebAssembly.Module(builder.toBuffer()); |
| let obj = {memory: memory, module: module}; |
| assertEquals(obj.memory.buffer.byteLength, 5 * kPageSize); |
| worker.postMessage(obj); |
| assertEquals("OK", worker.getMessage()); |
| assertEquals(obj.memory.buffer.byteLength, 20 * kPageSize); |
| })(); |
| |
| (function TestConsecutiveWasmSharedGrow() { |
| print(arguments.callee.name); |
| let worker = new Worker(workerHelpers + |
| `onmessage = function(obj) { |
| let kPageSize = 0x10000; |
| assertIsWasmSharedMemory(obj.memory); |
| let instance = new WebAssembly.Instance( |
| obj.module, {m: {memory: obj.memory}}); |
| assertTrue(5 === obj.memory.grow(10)); |
| assertIsWasmSharedMemory(obj.memory); |
| assertTrue(obj.memory.buffer.byteLength === 15 * kPageSize); |
| assertTrue(17 === instance.exports.grow_twice(2)); |
| assertIsWasmSharedMemory(obj.memory); |
| assertTrue(obj.memory.buffer.byteLength === 19 * kPageSize); |
| postMessage("OK"); |
| }`, {type: 'string'}); |
| |
| let memory = new WebAssembly.Memory({initial: 5, maximum: 50, shared: true}); |
| var builder = new WasmModuleBuilder(); |
| builder.addImportedMemory("m", "memory", 5, 100, "shared"); |
| builder.addFunction("grow_twice", kSig_i_i) |
| .addBody([kExprGetLocal, 0, |
| kExprMemoryGrow, kMemoryZero, |
| kExprDrop, |
| kExprGetLocal, 0, |
| kExprMemoryGrow, kMemoryZero]) |
| .exportFunc(); |
| var module = new WebAssembly.Module(builder.toBuffer()); |
| let obj = {memory: memory, module: module}; |
| assertEquals(obj.memory.buffer.byteLength, 5 * kPageSize); |
| worker.postMessage(obj); |
| assertEquals("OK", worker.getMessage()); |
| assertEquals(obj.memory.buffer.byteLength, 19 * kPageSize); |
| let instance = new WebAssembly.Instance(module, {m: {memory: memory}}); |
| assertEquals(21, instance.exports.grow_twice(2)); |
| assertEquals(obj.memory.buffer.byteLength, 23 * kPageSize); |
| })(); |
| |
| (function TestConsecutiveSharedGrowAndMemorySize() { |
| print(arguments.callee.name); |
| let worker = new Worker(workerHelpers + |
| `onmessage = function(obj) { |
| let kPageSize = 0x10000; |
| assertIsWasmSharedMemory(obj.memory); |
| let instance = new WebAssembly.Instance( |
| obj.module, {m: {memory: obj.memory}}); |
| assertTrue(5 === obj.memory.grow(10)); |
| assertTrue(15 === instance.exports.memory_size()); |
| assertIsWasmSharedMemory(obj.memory); |
| assertTrue(obj.memory.buffer.byteLength === 15 * kPageSize); |
| assertTrue(19 === instance.exports.grow_and_size(2)); |
| assertIsWasmSharedMemory(obj.memory); |
| assertTrue(obj.memory.buffer.byteLength === 19 * kPageSize); |
| postMessage("OK"); |
| }`, {type: 'string'}); |
| |
| let memory = new WebAssembly.Memory({initial: 5, maximum: 50, shared: true}); |
| var builder = new WasmModuleBuilder(); |
| builder.addImportedMemory("m", "memory", 5, 100, "shared"); |
| builder.addFunction("grow_and_size", kSig_i_i) |
| .addBody([kExprGetLocal, 0, |
| kExprMemoryGrow, kMemoryZero, |
| kExprDrop, |
| kExprGetLocal, 0, |
| kExprMemoryGrow, kMemoryZero, |
| kExprDrop, |
| kExprMemorySize, kMemoryZero]) |
| .exportFunc(); |
| builder.addFunction("memory_size", kSig_i_v) |
| .addBody([kExprMemorySize, kMemoryZero]) |
| .exportFunc(); |
| var module = new WebAssembly.Module(builder.toBuffer()); |
| let obj = {memory: memory, module: module}; |
| assertEquals(obj.memory.buffer.byteLength, 5 * kPageSize); |
| worker.postMessage(obj); |
| assertEquals("OK", worker.getMessage()); |
| assertEquals(memory.buffer.byteLength, 19 * kPageSize); |
| let instance = new WebAssembly.Instance(module, {m: {memory: memory}}); |
| assertEquals(23, instance.exports.grow_and_size(2)); |
| assertEquals(obj.memory.buffer.byteLength, 23 * kPageSize); |
| assertEquals(23, memory.grow(2)); |
| assertEquals(25, instance.exports.memory_size()); |
| })(); |
| |
| // Only spot checking here because currently the underlying buffer doesn't move. |
| // In the case that the underlying buffer does move, more comprehensive memory |
| // integrity checking and bounds checks testing are needed. |
| (function TestSpotCheckMemoryWithSharedGrow() { |
| print(arguments.callee.name); |
| let worker = new Worker(workerHelpers + |
| `onmessage = function(obj) { |
| let kPageSize = 0x10000; |
| assertIsWasmSharedMemory(obj.memory); |
| let instance = new WebAssembly.Instance( |
| obj.module, {m: {memory: obj.memory}}); |
| assertTrue(5 === obj.memory.grow(10)); |
| assertIsWasmSharedMemory(obj.memory); |
| assertTrue(obj.memory.buffer.byteLength === 15 * kPageSize); |
| // Store again, and verify that the previous stores are still reflected. |
| instance.exports.atomic_store(15 * kPageSize - 4, 0xACED); |
| assertTrue(0xACED === instance.exports.atomic_load(0)); |
| assertTrue(0xACED === instance.exports.atomic_load(5 * kPageSize - 4)); |
| assertTrue(0xACED === instance.exports.atomic_load(15 * kPageSize - 4)); |
| assertTrue(15 === instance.exports.grow(2)); |
| assertIsWasmSharedMemory(obj.memory); |
| assertTrue(obj.memory.buffer.byteLength === 17 * kPageSize); |
| // Validate previous writes. |
| instance.exports.atomic_store(17 * kPageSize - 4, 0xACED); |
| assertTrue(0xACED === instance.exports.atomic_load(0)); |
| assertTrue(0xACED === instance.exports.atomic_load(5 * kPageSize - 4)); |
| assertTrue(0xACED === instance.exports.atomic_load(15 * kPageSize - 4)); |
| assertTrue(0xACED === instance.exports.atomic_load(17 * kPageSize - 4)); |
| postMessage("OK"); |
| }`, {type: 'string'}); |
| |
| let memory = new WebAssembly.Memory({initial: 5, maximum: 50, shared: true}); |
| var builder = new WasmModuleBuilder(); |
| builder.addImportedMemory("m", "memory", 5, 100, "shared"); |
| builder.addFunction("grow", kSig_i_i) |
| .addBody([kExprGetLocal, 0, kExprMemoryGrow, kMemoryZero]) |
| .exportFunc(); |
| builder.addFunction("atomic_load", kSig_i_i) |
| .addBody([kExprGetLocal, 0, kAtomicPrefix, kExprI32AtomicLoad, 2, 0]) |
| .exportFunc(); |
| builder.addFunction("atomic_store", kSig_v_ii) |
| .addBody([kExprGetLocal, 0, kExprGetLocal, 1, |
| kAtomicPrefix, kExprI32AtomicStore, 2, 0]) |
| .exportFunc(); |
| var module = new WebAssembly.Module(builder.toBuffer()); |
| let instance = new WebAssembly.Instance(module, {m: {memory: memory}}); |
| // Store at first and last accessible 32 bit offset. |
| instance.exports.atomic_store(0, 0xACED); |
| instance.exports.atomic_store(5 * kPageSize - 4, 0xACED); |
| // Verify that these were stored. |
| assertEquals(0xACED, instance.exports.atomic_load(0)); |
| assertEquals(0xACED, instance.exports.atomic_load(5 * kPageSize - 4)); |
| // Verify bounds. |
| assertTraps(kTrapMemOutOfBounds, |
| () => instance.exports.atomic_load(5 * kPageSize - 3)); |
| let obj = {memory: memory, module: module}; |
| assertEquals(obj.memory.buffer.byteLength, 5 * kPageSize); |
| // PostMessage |
| worker.postMessage(obj); |
| assertEquals("OK", worker.getMessage()); |
| assertEquals(memory.buffer.byteLength, 17 * kPageSize); |
| assertEquals(17, instance.exports.grow(2)); |
| assertEquals(obj.memory.buffer.byteLength, 19 * kPageSize); |
| // Validate previous writes, and check bounds. |
| assertTrue(0xACED === instance.exports.atomic_load(0)); |
| assertTrue(0xACED === instance.exports.atomic_load(5 * kPageSize - 4)); |
| assertTrue(0xACED === instance.exports.atomic_load(15 * kPageSize - 4)); |
| assertTrue(0xACED === instance.exports.atomic_load(17 * kPageSize - 4)); |
| assertTraps(kTrapMemOutOfBounds, |
| () => instance.exports.atomic_load(19 * kPageSize - 3)); |
| assertEquals(19, memory.grow(6)); |
| assertEquals(obj.memory.buffer.byteLength, 25 * kPageSize); |
| assertTraps(kTrapMemOutOfBounds, |
| () => instance.exports.atomic_load(25 * kPageSize - 3)); |
| })(); |
| |
| (function TestMemoryBufferTypeAfterGrow() { |
| const memory = new WebAssembly.Memory({ |
| "initial": 1, "maximum": 2, "shared": true }); |
| assertInstanceof(memory.buffer, SharedArrayBuffer); |
| assertEquals(memory.grow(1), 1); |
| assertInstanceof(memory.buffer, SharedArrayBuffer); |
| })(); |