summaryrefslogtreecommitdiffstats
path: root/js/src/jit-test/tests/wasm/resizing.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jit-test/tests/wasm/resizing.js')
-rw-r--r--js/src/jit-test/tests/wasm/resizing.js233
1 files changed, 233 insertions, 0 deletions
diff --git a/js/src/jit-test/tests/wasm/resizing.js b/js/src/jit-test/tests/wasm/resizing.js
new file mode 100644
index 000000000..230416ca9
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/resizing.js
@@ -0,0 +1,233 @@
+load(libdir + "wasm.js");
+
+const Module = WebAssembly.Module;
+const Instance = WebAssembly.Instance;
+const Table = WebAssembly.Table;
+const Memory = WebAssembly.Memory;
+const RuntimeError = WebAssembly.RuntimeError;
+
+// ======
+// MEMORY
+// ======
+
+// Test for stale heap pointers after resize
+
+// Grow directly from builtin call:
+wasmFullPass(`(module
+ (memory 1)
+ (func $test (result i32)
+ (i32.store (i32.const 0) (i32.const 1))
+ (i32.store (i32.const 65532) (i32.const 10))
+ (drop (grow_memory (i32.const 99)))
+ (i32.store (i32.const 6553596) (i32.const 100))
+ (i32.add
+ (i32.load (i32.const 0))
+ (i32.add
+ (i32.load (i32.const 65532))
+ (i32.load (i32.const 6553596)))))
+ (export "run" $test)
+)`, 111);
+
+// Grow during import call:
+var exports = wasmEvalText(`(module
+ (import $imp "" "imp")
+ (memory 1)
+ (func $grow (drop (grow_memory (i32.const 99))))
+ (export "grow" $grow)
+ (func $test (result i32)
+ (i32.store (i32.const 0) (i32.const 1))
+ (i32.store (i32.const 65532) (i32.const 10))
+ (call $imp)
+ (i32.store (i32.const 6553596) (i32.const 100))
+ (i32.add
+ (i32.load (i32.const 0))
+ (i32.add
+ (i32.load (i32.const 65532))
+ (i32.load (i32.const 6553596)))))
+ (export "test" $test)
+)`, {"":{imp() { exports.grow() }}}).exports;
+
+setJitCompilerOption("baseline.warmup.trigger", 2);
+setJitCompilerOption("ion.warmup.trigger", 4);
+for (var i = 0; i < 10; i++)
+ assertEq(exports.test(), 111);
+
+// Grow during call_indirect:
+var mem = new Memory({initial:1});
+var tbl = new Table({initial:1, element:"anyfunc"});
+var exports1 = wasmEvalText(`(module
+ (import "" "mem" (memory 1))
+ (func $grow
+ (i32.store (i32.const 65532) (i32.const 10))
+ (drop (grow_memory (i32.const 99)))
+ (i32.store (i32.const 6553596) (i32.const 100)))
+ (export "grow" $grow)
+)`, {"":{mem}}).exports;
+var exports2 = wasmEvalText(`(module
+ (import "" "tbl" (table 1 anyfunc))
+ (import "" "mem" (memory 1))
+ (type $v2v (func))
+ (func $test (result i32)
+ (i32.store (i32.const 0) (i32.const 1))
+ (call_indirect $v2v (i32.const 0))
+ (i32.add
+ (i32.load (i32.const 0))
+ (i32.add
+ (i32.load (i32.const 65532))
+ (i32.load (i32.const 6553596)))))
+ (export "test" $test)
+)`, {"":{tbl, mem}}).exports;
+tbl.set(0, exports1.grow);
+assertEq(exports2.test(), 111);
+
+// Test for coherent length/contents
+
+var mem = new Memory({initial:1});
+new Int32Array(mem.buffer)[0] = 42;
+var mod = new Module(wasmTextToBinary(`(module
+ (import "" "mem" (memory 1))
+ (func $gm (param i32) (result i32) (grow_memory (get_local 0)))
+ (export "grow_memory" $gm)
+ (func $cm (result i32) (current_memory))
+ (export "current_memory" $cm)
+ (func $ld (param i32) (result i32) (i32.load (get_local 0)))
+ (export "load" $ld)
+ (func $st (param i32) (param i32) (i32.store (get_local 0) (get_local 1)))
+ (export "store" $st)
+)`));
+var exp1 = new Instance(mod, {"":{mem}}).exports;
+var exp2 = new Instance(mod, {"":{mem}}).exports;
+assertEq(exp1.current_memory(), 1);
+assertEq(exp1.load(0), 42);
+assertEq(exp2.current_memory(), 1);
+assertEq(exp2.load(0), 42);
+mem.grow(1);
+assertEq(mem.buffer.byteLength, 2*64*1024);
+new Int32Array(mem.buffer)[64*1024/4] = 13;
+assertEq(exp1.current_memory(), 2);
+assertEq(exp1.load(0), 42);
+assertEq(exp1.load(64*1024), 13);
+assertEq(exp2.current_memory(), 2);
+assertEq(exp2.load(0), 42);
+assertEq(exp2.load(64*1024), 13);
+exp1.grow_memory(2);
+assertEq(exp1.current_memory(), 4);
+exp1.store(3*64*1024, 99);
+assertEq(exp2.current_memory(), 4);
+assertEq(exp2.load(3*64*1024), 99);
+assertEq(mem.buffer.byteLength, 4*64*1024);
+assertEq(new Int32Array(mem.buffer)[3*64*1024/4], 99);
+
+// Fail at maximum
+
+var mem = new Memory({initial:1, maximum:2});
+assertEq(mem.buffer.byteLength, 1 * 64*1024);
+assertEq(mem.grow(1), 1);
+assertEq(mem.buffer.byteLength, 2 * 64*1024);
+assertErrorMessage(() => mem.grow(1), RangeError, /failed to grow memory/);
+assertEq(mem.buffer.byteLength, 2 * 64*1024);
+
+// ======
+// TABLE
+// ======
+
+// Test for stale table base pointers after resize
+
+// Grow during import call:
+var exports = wasmEvalText(`(module
+ (type $v2i (func (result i32)))
+ (import $grow "" "grow")
+ (table (export "tbl") 1 anyfunc)
+ (func $test (result i32)
+ (i32.add
+ (call_indirect $v2i (i32.const 0))
+ (block i32
+ (call $grow)
+ (call_indirect $v2i (i32.const 1)))))
+ (func $one (result i32) (i32.const 1))
+ (elem (i32.const 0) $one)
+ (func $two (result i32) (i32.const 2))
+ (export "test" $test)
+ (export "two" $two)
+)`, {"":{grow() { exports.tbl.grow(1); exports.tbl.set(1, exports.two) }}}).exports;
+
+setJitCompilerOption("baseline.warmup.trigger", 2);
+setJitCompilerOption("ion.warmup.trigger", 4);
+for (var i = 0; i < 10; i++)
+ assertEq(exports.test(), 3);
+assertEq(exports.tbl.length, 11);
+
+// Grow during call_indirect:
+var exports1 = wasmEvalText(`(module
+ (import $grow "" "grow")
+ (func $exp (call $grow))
+ (export "exp" $exp)
+)`, {"":{grow() { exports2.tbl.grow(1); exports2.tbl.set(2, exports2.eleven) }}}).exports;
+var exports2 = wasmEvalText(`(module
+ (type $v2v (func))
+ (type $v2i (func (result i32)))
+ (import $imp "" "imp")
+ (elem (i32.const 0) $imp)
+ (table 2 anyfunc)
+ (func $test (result i32)
+ (i32.add
+ (call_indirect $v2i (i32.const 1))
+ (block i32
+ (call_indirect $v2v (i32.const 0))
+ (call_indirect $v2i (i32.const 2)))))
+ (func $ten (result i32) (i32.const 10))
+ (elem (i32.const 1) $ten)
+ (func $eleven (result i32) (i32.const 11))
+ (export "tbl" table)
+ (export "test" $test)
+ (export "eleven" $eleven)
+)`, {"":{imp:exports1.exp}}).exports;
+assertEq(exports2.test(), 21);
+
+// Test for coherent length/contents
+
+var src = wasmEvalText(`(module
+ (func $one (result i32) (i32.const 1))
+ (export "one" $one)
+ (func $two (result i32) (i32.const 2))
+ (export "two" $two)
+ (func $three (result i32) (i32.const 3))
+ (export "three" $three)
+)`).exports;
+var tbl = new Table({element:"anyfunc", initial:1});
+tbl.set(0, src.one);
+
+var mod = new Module(wasmTextToBinary(`(module
+ (type $v2i (func (result i32)))
+ (table (import "" "tbl") 1 anyfunc)
+ (func $ci (param i32) (result i32) (call_indirect $v2i (get_local 0)))
+ (export "call_indirect" $ci)
+)`));
+var exp1 = new Instance(mod, {"":{tbl}}).exports;
+var exp2 = new Instance(mod, {"":{tbl}}).exports;
+assertEq(exp1.call_indirect(0), 1);
+assertErrorMessage(() => exp1.call_indirect(1), RuntimeError, /index out of bounds/);
+assertEq(exp2.call_indirect(0), 1);
+assertErrorMessage(() => exp2.call_indirect(1), RuntimeError, /index out of bounds/);
+assertEq(tbl.grow(1), 1);
+assertEq(tbl.length, 2);
+assertEq(exp1.call_indirect(0), 1);
+assertErrorMessage(() => exp1.call_indirect(1), Error, /indirect call to null/);
+tbl.set(1, src.two);
+assertEq(exp1.call_indirect(1), 2);
+assertErrorMessage(() => exp1.call_indirect(2), RuntimeError, /index out of bounds/);
+assertEq(tbl.grow(2), 2);
+assertEq(tbl.length, 4);
+assertEq(exp2.call_indirect(0), 1);
+assertEq(exp2.call_indirect(1), 2);
+assertErrorMessage(() => exp2.call_indirect(2), Error, /indirect call to null/);
+assertErrorMessage(() => exp2.call_indirect(3), Error, /indirect call to null/);
+
+// Fail at maximum
+
+var tbl = new Table({initial:1, maximum:2, element:"anyfunc"});
+assertEq(tbl.length, 1);
+assertEq(tbl.grow(1), 1);
+assertEq(tbl.length, 2);
+assertErrorMessage(() => tbl.grow(1), RangeError, /failed to grow table/);
+assertEq(tbl.length, 2);