tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

memory-sharing.js (8168B)


      1 // |jit-test| skip-if: !wasmThreadsEnabled()
      2 
      3 const WASMPAGE = 65536;
      4 
      5 // A shared memory should yield a SharedArrayBuffer of appropriate length
      6 
      7 {
      8    let mem = new WebAssembly.Memory({initial: 2, maximum: 4, shared: true});
      9    assertEq(mem.buffer instanceof SharedArrayBuffer, true);
     10    assertEq(mem.buffer.byteLength, WASMPAGE*2);
     11 }
     12 
     13 // Ditto, when the memory was created by instantiation and exported
     14 
     15 {
     16    let text = `(module
     17 	 (memory (export "memory") 1 2 shared)
     18 	 (func (export "l0") (result i32) (i32.load (i32.const 0))))`;
     19    let mod = new WebAssembly.Module(wasmTextToBinary(text));
     20    let ins = new WebAssembly.Instance(mod);
     21    let mem = ins.exports.memory;
     22    let buf = mem.buffer;
     23    assertEq(buf instanceof SharedArrayBuffer, true);
     24    assertEq(buf.byteLength, WASMPAGE);
     25 }
     26 
     27 // Shared memory requires a maximum size
     28 
     29 {
     30    assertErrorMessage(() => new WebAssembly.Memory({initial: 2, shared: true}),
     31 	       TypeError,
     32 	       /'shared' is true but maximum is not specified/);
     33 }
     34 
     35 // Ditto, syntactically
     36 
     37 {
     38    let text = `(module
     39 	 (memory 1 shared)
     40 	 (func (export "l0") (result i32) (i32.load (i32.const 0))))`;
     41    assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(text)),
     42 	       WebAssembly.CompileError,
     43 	       /maximum length required for shared memory/);
     44 }
     45 
     46 // Ditto, in the binary.  The flags field can be 0 (unshared, min only), 1
     47 // (unshared, min and max), or 3 (shared, min and max), but not 2 (shared, min
     48 // only).  So construct a module that has that, and make sure it's rejected.
     49 
     50 {
     51    let bin = new Uint8Array([0x00, 0x61, 0x73, 0x6d,
     52 		      0x01, 0x00, 0x00, 0x00,
     53 		      0x05,                   // Memory
     54 		      0x03,                   // Section size
     55 		      0x01,                   // One memory
     56 		      0x02,		      // Shared, min only (illegal)
     57 		      0x01]);		      // Min
     58    assertErrorMessage(() => new WebAssembly.Module(bin),
     59 	       WebAssembly.CompileError,
     60 	       /maximum length required for shared memory/);
     61 }
     62 
     63 // Importing shared memory and being provided with shared should work
     64 
     65 {
     66    let text = `(module
     67 	 (memory (import "" "memory") 1 1 shared)
     68 	 (func (export "id") (param i32) (result i32) (local.get 0)))`;
     69    let mod = new WebAssembly.Module(wasmTextToBinary(text));
     70    let mem = new WebAssembly.Memory({initial: 1, maximum: 1, shared: true});
     71    let ins = new WebAssembly.Instance(mod, {"": {memory: mem}});
     72    assertEq(ins.exports.id(0x12345678), 0x12345678);
     73 }
     74 
     75 // Importing shared memory but being provided with unshared should fail
     76 
     77 {
     78    let text = `(module
     79 	 (memory (import "" "memory") 1 1 shared)
     80 	 (func (export "id") (param i32) (result i32) (local.get 0)))`;
     81    let mod = new WebAssembly.Module(wasmTextToBinary(text));
     82    let mem = new WebAssembly.Memory({initial: 1, maximum: 1});
     83    assertErrorMessage(() => new WebAssembly.Instance(mod, {"": {memory: mem}}),
     84 	       WebAssembly.LinkError,
     85 	       /unshared memory but shared required/);
     86 }
     87 
     88 // Importing unshared memory but being provided with shared should fail
     89 
     90 {
     91    let text = `(module
     92 	 (memory (import "" "memory") 1 1)
     93 	 (func (export "id") (param i32) (result i32) (local.get 0)))`;
     94    let mod = new WebAssembly.Module(wasmTextToBinary(text));
     95    let mem = new WebAssembly.Memory({initial: 1, maximum: 1, shared: true});
     96    assertErrorMessage(() => new WebAssembly.Instance(mod, {"": {memory: mem}}),
     97 	       WebAssembly.LinkError,
     98 	       /shared memory but unshared required/);
     99 }
    100 
    101 // Importing shared memory and being provided with shared memory with
    102 // incompatible parameters should fail
    103 
    104 {
    105    let text = `(module
    106 	 (memory (import "" "memory") 2 4 shared)
    107 	 (func (export "id") (param i32) (result i32) (local.get 0)))`;
    108    let mod = new WebAssembly.Module(wasmTextToBinary(text));
    109 
    110    // some cases that are non-matching are allowed, eg, initial > declared min
    111 
    112    // initial < declared min
    113    let mem3 = new WebAssembly.Memory({initial: 1, maximum: 4, shared: true});
    114    assertErrorMessage(() => new WebAssembly.Instance(mod, {"": {memory: mem3}}),
    115 	       WebAssembly.LinkError,
    116 	       /imported Memory with incompatible size/);
    117 
    118    // initial > declared max
    119    let mem4 = new WebAssembly.Memory({initial: 5, maximum: 8, shared: true});
    120    assertErrorMessage(() => new WebAssembly.Instance(mod, {"": {memory: mem4}}),
    121 	       WebAssembly.LinkError,
    122 	       /imported Memory with incompatible size/);
    123 
    124    // max > declared max
    125    let mem5 = new WebAssembly.Memory({initial: 2, maximum: 8, shared: true});
    126    assertErrorMessage(() => new WebAssembly.Instance(mod, {"": {memory: mem5}}),
    127 	       WebAssembly.LinkError,
    128 	       /imported Memory with incompatible maximum size/);
    129 }
    130 
    131 
    132 // basic memory.size and memory.grow operation, with bounds checking near the
    133 // valid/invalid boundary
    134 
    135 {
    136    let text = `(module
    137 	 (memory (export "memory") 2 4 shared)
    138 	 (func (export "c") (result i32) memory.size)
    139 	 (func (export "g") (result i32) (memory.grow (i32.const 1)))
    140 	 (func (export "l") (param i32) (result i32) (i32.load (local.get 0)))
    141 	 (func (export "s") (param i32) (param i32) (i32.store (local.get 0) (local.get 1))))`;
    142    let mod = new WebAssembly.Module(wasmTextToBinary(text));
    143    let ins = new WebAssembly.Instance(mod);
    144    let exp = ins.exports;
    145    let mem = exp.memory;
    146 
    147    let b1 = mem.buffer;
    148    assertEq(exp.c(), 2);
    149    assertEq(b1.byteLength, WASMPAGE*2);
    150    assertEq(mem.buffer === b1, true);   // memory.size does not affect buffer
    151    exp.s(WASMPAGE*2-4, 0x12345678)	 // access near end
    152    assertEq(exp.l(WASMPAGE*2-4), 0x12345678);
    153    assertErrorMessage(() => exp.l(WASMPAGE*2), // beyond current end (but below max)
    154 	       WebAssembly.RuntimeError,
    155 	       /index out of bounds/);
    156    assertEq(exp.g(), 2);
    157    assertEq(b1.byteLength, WASMPAGE*2); // growing does not affect existing buffer length
    158    let b2 = mem.buffer;
    159    assertEq(b1 !== b2, true);	         // growing produces a new buffer
    160    assertEq(b2.byteLength, WASMPAGE*3); // new buffer has appropriate length
    161    assertEq(exp.c(), 3);
    162    exp.s(WASMPAGE*3-4, 0x12344321);     // access near new end
    163    assertEq(exp.l(WASMPAGE*3-4), 0x12344321);
    164    assertErrorMessage(() => exp.l(WASMPAGE*3), // beyond current end (but below max)
    165 	       WebAssembly.RuntimeError,
    166 	       /index out of bounds/);
    167    assertEq(exp.g(), 3);
    168    assertEq(b2.byteLength, WASMPAGE*3); // growing does not affect existing buffer length
    169    let b3 = mem.buffer;
    170    assertEq(b2 !== b3, true);	         // growing produces a new buffer
    171    assertEq(b3.byteLength, WASMPAGE*4); // new buffer has appropriate length
    172    assertEq(exp.c(), 4);
    173    exp.s(WASMPAGE*4-4, 0x12121212);     // access near new end
    174    assertEq(exp.l(WASMPAGE*4-4), 0x12121212);
    175    assertErrorMessage(() => exp.l(WASMPAGE*4), // beyond current end (and beyond max)
    176 	       WebAssembly.RuntimeError,
    177 	       /index out of bounds/);
    178    assertEq(exp.g(), -1);
    179    assertEq(exp.c(), 4);                // failure to grow -> no change
    180    let b4 = mem.buffer;
    181    assertEq(b3 === b4, true);	         // failure to grow -> same ol' buffer
    182    assertEq(exp.g(), -1);               // we can fail repeatedly
    183 }
    184 
    185 // Test the grow() API with shared memory.  In the implementation this API
    186 // shares almost all code with the wasm instruction, so don't bother going deep.
    187 
    188 {
    189    let mem = new WebAssembly.Memory({initial: 2, maximum: 4, shared: true});
    190    let buf = mem.buffer;
    191    assertEq(mem.grow(1), 2);
    192    assertEq(buf.byteLength, WASMPAGE*2);
    193    assertEq(mem.grow(1), 3);
    194    assertErrorMessage(() => mem.grow(1), RangeError, /failed to grow memory/);
    195 }
    196 
    197 // Initializing shared memory with data
    198 
    199 {
    200    let text = `(module
    201 	 (memory (import "" "memory") 2 4 shared)
    202 	 (data (i32.const 0) "abcdefghijklmnopqrstuvwxyz")
    203 	 (func (export "l") (param i32) (result i32) (i32.load8_u (local.get 0))))`;
    204    let mod = new WebAssembly.Module(wasmTextToBinary(text));
    205    let mem = new WebAssembly.Memory({initial: 2, maximum: 4, shared: true});
    206    let ins = new WebAssembly.Instance(mod, {"": {memory: mem}});
    207    let exp = ins.exports;
    208    assertEq(exp.l(12), "a".charCodeAt(0) + 12);
    209 }