diff options
Diffstat (limited to 'js/src/jit-test/tests/wasm/memory-sharing.js')
-rw-r--r-- | js/src/jit-test/tests/wasm/memory-sharing.js | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/js/src/jit-test/tests/wasm/memory-sharing.js b/js/src/jit-test/tests/wasm/memory-sharing.js new file mode 100644 index 0000000000..d67baad4fa --- /dev/null +++ b/js/src/jit-test/tests/wasm/memory-sharing.js @@ -0,0 +1,210 @@ +// |jit-test| skip-if: !wasmThreadsEnabled() + +const WASMPAGE = 65536; + +// A shared memory should yield a SharedArrayBuffer of appropriate length + +{ + let mem = new WebAssembly.Memory({initial: 2, maximum: 4, shared: true}); + assertEq(mem.buffer instanceof SharedArrayBuffer, true); + assertEq(mem.buffer.byteLength, WASMPAGE*2); +} + +// Ditto, when the memory was created by instantiation and exported + +{ + let text = `(module + (memory (export "memory") 1 2 shared) + (func (export "l0") (result i32) (i32.load (i32.const 0))))`; + let mod = new WebAssembly.Module(wasmTextToBinary(text)); + let ins = new WebAssembly.Instance(mod); + let mem = ins.exports.memory; + let buf = mem.buffer; + assertEq(buf instanceof SharedArrayBuffer, true); + assertEq(buf.byteLength, WASMPAGE); +} + +// Shared memory requires a maximum size + +{ + assertErrorMessage(() => new WebAssembly.Memory({initial: 2, shared: true}), + TypeError, + /'shared' is true but maximum is not specified/); +} + +// Ditto, syntactically + +{ + let text = `(module + (memory 1 shared) + (func (export "l0") (result i32) (i32.load (i32.const 0))))`; + assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(text)), + WebAssembly.CompileError, + /maximum length required for shared memory/); +} + +// Ditto, in the binary. The flags field can be 0 (unshared, min only), 1 +// (unshared, min and max), or 3 (shared, min and max), but not 2 (shared, min +// only). So construct a module that has that, and make sure it's rejected. + +{ + let bin = new Uint8Array([0x00, 0x61, 0x73, 0x6d, + 0x01, 0x00, 0x00, 0x00, + 0x05, // Memory + 0x03, // Section size + 0x01, // One memory + 0x02, // Shared, min only (illegal) + 0x01]); // Min + assertErrorMessage(() => new WebAssembly.Module(bin), + WebAssembly.CompileError, + /maximum length required for shared memory/); +} + +// Importing shared memory and being provided with shared should work + +{ + let text = `(module + (memory (import "" "memory") 1 1 shared) + (func (export "id") (param i32) (result i32) (local.get 0)))`; + let mod = new WebAssembly.Module(wasmTextToBinary(text)); + let mem = new WebAssembly.Memory({initial: 1, maximum: 1, shared: true}); + let ins = new WebAssembly.Instance(mod, {"": {memory: mem}}); + assertEq(ins.exports.id(0x12345678), 0x12345678); +} + +// Importing shared memory but being provided with unshared should fail + +{ + let text = `(module + (memory (import "" "memory") 1 1 shared) + (func (export "id") (param i32) (result i32) (local.get 0)))`; + let mod = new WebAssembly.Module(wasmTextToBinary(text)); + let mem = new WebAssembly.Memory({initial: 1, maximum: 1}); + assertErrorMessage(() => new WebAssembly.Instance(mod, {"": {memory: mem}}), + WebAssembly.LinkError, + /unshared memory but shared required/); +} + +// Importing unshared memory but being provided with shared should fail + +{ + let text = `(module + (memory (import "" "memory") 1 1) + (func (export "id") (param i32) (result i32) (local.get 0)))`; + let mod = new WebAssembly.Module(wasmTextToBinary(text)); + let mem = new WebAssembly.Memory({initial: 1, maximum: 1, shared: true}); + assertErrorMessage(() => new WebAssembly.Instance(mod, {"": {memory: mem}}), + WebAssembly.LinkError, + /shared memory but unshared required/); +} + +// Importing shared memory and being provided with shared memory with +// incompatible parameters should fail + +{ + let text = `(module + (memory (import "" "memory") 2 4 shared) + (func (export "id") (param i32) (result i32) (local.get 0)))`; + let mod = new WebAssembly.Module(wasmTextToBinary(text)); + + // some cases that are non-matching are allowed, eg, initial > declared min + + // initial < declared min + let mem3 = new WebAssembly.Memory({initial: 1, maximum: 4, shared: true}); + assertErrorMessage(() => new WebAssembly.Instance(mod, {"": {memory: mem3}}), + WebAssembly.LinkError, + /imported Memory with incompatible size/); + + // initial > declared max + let mem4 = new WebAssembly.Memory({initial: 5, maximum: 8, shared: true}); + assertErrorMessage(() => new WebAssembly.Instance(mod, {"": {memory: mem4}}), + WebAssembly.LinkError, + /imported Memory with incompatible size/); + + // max > declared max + let mem5 = new WebAssembly.Memory({initial: 2, maximum: 8, shared: true}); + assertErrorMessage(() => new WebAssembly.Instance(mod, {"": {memory: mem5}}), + WebAssembly.LinkError, + /imported Memory with incompatible maximum size/); +} + + +// basic memory.size and memory.grow operation, with bounds checking near the +// valid/invalid boundary + +{ + let text = `(module + (memory (export "memory") 2 4 shared) + (func (export "c") (result i32) memory.size) + (func (export "g") (result i32) (memory.grow (i32.const 1))) + (func (export "l") (param i32) (result i32) (i32.load (local.get 0))) + (func (export "s") (param i32) (param i32) (i32.store (local.get 0) (local.get 1))))`; + let mod = new WebAssembly.Module(wasmTextToBinary(text)); + let ins = new WebAssembly.Instance(mod); + let exp = ins.exports; + let mem = exp.memory; + + let b1 = mem.buffer; + assertEq(exp.c(), 2); + assertEq(b1.byteLength, WASMPAGE*2); + assertEq(mem.buffer === b1, true); // memory.size does not affect buffer + exp.s(WASMPAGE*2-4, 0x12345678) // access near end + assertEq(exp.l(WASMPAGE*2-4), 0x12345678); + assertErrorMessage(() => exp.l(WASMPAGE*2), // beyond current end (but below max) + WebAssembly.RuntimeError, + /index out of bounds/); + assertEq(exp.g(), 2); + assertEq(b1.byteLength, WASMPAGE*2); // growing does not affect existing buffer length + let b2 = mem.buffer; + assertEq(b1 !== b2, true); // growing produces a new buffer + assertEq(b2.byteLength, WASMPAGE*3); // new buffer has appropriate length + assertEq(exp.c(), 3); + exp.s(WASMPAGE*3-4, 0x12344321); // access near new end + assertEq(exp.l(WASMPAGE*3-4), 0x12344321); + assertErrorMessage(() => exp.l(WASMPAGE*3), // beyond current end (but below max) + WebAssembly.RuntimeError, + /index out of bounds/); + assertEq(exp.g(), 3); + assertEq(b2.byteLength, WASMPAGE*3); // growing does not affect existing buffer length + let b3 = mem.buffer; + assertEq(b2 !== b3, true); // growing produces a new buffer + assertEq(b3.byteLength, WASMPAGE*4); // new buffer has appropriate length + assertEq(exp.c(), 4); + exp.s(WASMPAGE*4-4, 0x12121212); // access near new end + assertEq(exp.l(WASMPAGE*4-4), 0x12121212); + assertErrorMessage(() => exp.l(WASMPAGE*4), // beyond current end (and beyond max) + WebAssembly.RuntimeError, + /index out of bounds/); + assertEq(exp.g(), -1); + assertEq(exp.c(), 4); // failure to grow -> no change + let b4 = mem.buffer; + assertEq(b3 === b4, true); // failure to grow -> same ol' buffer + assertEq(exp.g(), -1); // we can fail repeatedly +} + +// Test the grow() API with shared memory. In the implementation this API +// shares almost all code with the wasm instruction, so don't bother going deep. + +{ + let mem = new WebAssembly.Memory({initial: 2, maximum: 4, shared: true}); + let buf = mem.buffer; + assertEq(mem.grow(1), 2); + assertEq(buf.byteLength, WASMPAGE*2); + assertEq(mem.grow(1), 3); + assertErrorMessage(() => mem.grow(1), RangeError, /failed to grow memory/); +} + +// Initializing shared memory with data + +{ + let text = `(module + (memory (import "" "memory") 2 4 shared) + (data (i32.const 0) "abcdefghijklmnopqrstuvwxyz") + (func (export "l") (param i32) (result i32) (i32.load8_u (local.get 0))))`; + let mod = new WebAssembly.Module(wasmTextToBinary(text)); + let mem = new WebAssembly.Memory({initial: 2, maximum: 4, shared: true}); + let ins = new WebAssembly.Instance(mod, {"": {memory: mem}}); + let exp = ins.exports; + assertEq(exp.l(12), "a".charCodeAt(0) + 12); +} + |