summaryrefslogtreecommitdiffstats
path: root/js/src/jit-test/tests/wasm/ref-types/tables-generalized.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jit-test/tests/wasm/ref-types/tables-generalized.js')
-rw-r--r--js/src/jit-test/tests/wasm/ref-types/tables-generalized.js432
1 files changed, 432 insertions, 0 deletions
diff --git a/js/src/jit-test/tests/wasm/ref-types/tables-generalized.js b/js/src/jit-test/tests/wasm/ref-types/tables-generalized.js
new file mode 100644
index 0000000000..19e530baae
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/ref-types/tables-generalized.js
@@ -0,0 +1,432 @@
+///////////////////////////////////////////////////////////////////////////
+//
+// General table management in wasm
+
+// Wasm: Create table-of-externref
+
+new WebAssembly.Module(wasmTextToBinary(
+ `(module
+ (table 10 externref))`));
+
+// Wasm: Import table-of-externref
+// JS: create table-of-externref
+
+new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(
+ `(module
+ (table (import "m" "t") 10 externref))`)),
+ {m:{t: new WebAssembly.Table({element:"externref", initial:10})}});
+
+new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(
+ `(module
+ (import "m" "t" (table 10 externref)))`)),
+ {m:{t: new WebAssembly.Table({element:"externref", initial:10})}});
+
+// Wasm: Export table-of-externref, initial values shall be null
+
+{
+ let ins = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(
+ `(module
+ (table (export "t") 10 externref))`)));
+ let t = ins.exports.t;
+ assertEq(t.length, 10);
+ for (let i=0; i < t.length; i++)
+ assertEq(t.get(0), null);
+}
+
+// JS: Exported table can be grown, and values are preserved
+
+{
+ let ins = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(
+ `(module
+ (table (export "t") 10 externref))`)));
+ let t = ins.exports.t;
+ let objs = [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}];
+ for (let i in objs)
+ t.set(i, objs[i]);
+ ins.exports.t.grow(10);
+ assertEq(ins.exports.t.length, 20);
+ for (let i in objs)
+ assertEq(t.get(i), objs[i]);
+}
+
+// Wasm: table.copy between tables of externref (currently source and destination
+// are both table zero)
+
+{
+ let ins = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(
+ `(module
+ (table (export "t") 10 externref)
+ (func (export "f")
+ (table.copy (i32.const 5) (i32.const 0) (i32.const 3))))`)));
+ let t = ins.exports.t;
+ let objs = [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}];
+ for (let i in objs)
+ t.set(i, objs[i]);
+ ins.exports.f();
+ assertEq(t.get(0), objs[0]);
+ assertEq(t.get(1), objs[1]);
+ assertEq(t.get(2), objs[2]);
+ assertEq(t.get(3), objs[3]);
+ assertEq(t.get(4), objs[4]);
+ assertEq(t.get(5), objs[0]);
+ assertEq(t.get(6), objs[1]);
+ assertEq(t.get(7), objs[2]);
+ assertEq(t.get(8), objs[8]);
+ assertEq(t.get(9), objs[9]);
+}
+
+// Wasm: table.copy from table(funcref) to table(externref) should not work
+
+assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(
+ `(module
+ (table (export "t") 10 externref)
+ (func $f1)
+ (func $f2)
+ (func $f3)
+ (func $f4)
+ (func $f5)
+ (table 5 funcref)
+ (elem (table 1) (i32.const 0) func $f1 $f2 $f3 $f4 $f5)
+ (func (export "f")
+ (table.copy 0 1 (i32.const 5) (i32.const 0) (i32.const 5))))`)),
+ WebAssembly.CompileError,
+ /(expression has type funcref but expected externref)|(type mismatch)/);
+
+// Wasm: table.copy from table(externref) to table(funcref) should not work
+
+assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(
+ `(module
+ (table 10 funcref)
+ (table 10 externref)
+ (func (export "f")
+ (table.copy 0 1 (i32.const 0) (i32.const 0) (i32.const 5))))`)),
+ WebAssembly.CompileError,
+ /(expression has type externref but expected funcref)|(type mismatch)/);
+
+// Wasm: Element segments of funcref can't target tables of externref
+
+assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(
+ `(module
+ (func $f1 (result i32) (i32.const 0))
+ (table (export "t") 10 externref)
+ (elem 0 (i32.const 0) funcref (ref.func $f1)))`)),
+ WebAssembly.CompileError,
+ /type mismatch/);
+
+
+// Wasm: Element segments of externref can't target tables of funcref
+
+assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(
+ `(module
+ (table (export "t") 10 funcref)
+ (elem 0 (i32.const 0) externref (ref.null extern)))`)),
+ WebAssembly.CompileError,
+ /type mismatch/);
+
+// Wasm: table.init on table-of-externref is not allowed when the segment has
+// funcref.
+
+assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(
+ `(module
+ (func $f1 (result i32) (i32.const 0))
+ (table 10 externref)
+ (elem funcref (ref.func $f1))
+ (func
+ (table.init 0 (i32.const 0) (i32.const 0) (i32.const 0))))`)),
+ WebAssembly.CompileError,
+ /(expression has type funcref but expected externref)|(type mismatch)/);
+
+
+// Wasm: table.init on table-of-funcref is not allowed when the segment has
+// externref.
+
+assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(
+ `(module
+ (table 10 funcref)
+ (elem externref (ref.null extern))
+ (func
+ (table.init 0 (i32.const 0) (i32.const 0) (i32.const 0))))`)),
+ WebAssembly.CompileError,
+ /(expression has type externref but expected funcref)|(type mismatch)/);
+
+// Wasm: table types must match at link time
+
+assertErrorMessage(
+ () => new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(
+ `(module
+ (import "m" "t" (table 10 externref)))`)),
+ {m:{t: new WebAssembly.Table({element:"anyfunc", initial:10})}}),
+ WebAssembly.LinkError,
+ /imported table type mismatch/);
+
+// call_indirect cannot reference table-of-externref
+
+assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(
+ `(module
+ (table 10 externref)
+ (type $t (func (param i32) (result i32)))
+ (func (result i32)
+ (call_indirect (type $t) (i32.const 37))))`)),
+ WebAssembly.CompileError,
+ /(indirect calls must go through a table of 'funcref')|(indirect calls must go through a table of funcref)/);
+
+///////////////////////////////////////////////////////////////////////////
+//
+// additional js api tests
+
+{
+ let tbl = new WebAssembly.Table({element:"externref", initial:10});
+
+ // Initial value is undefined. This is different from when tables are
+ // created inside wasm.
+ assertEq(tbl.get(0), undefined);
+
+ // Identity preserving.
+ let x = {hi: 48};
+ tbl.set(0, x);
+ assertEq(tbl.get(0), x);
+ tbl.set(2, dummy);
+ assertEq(tbl.get(2), dummy);
+ tbl.set(2, null);
+ assertEq(tbl.get(2), null);
+
+ // Temporary semantics is to convert to object and leave as object; once we
+ // have a better wrapped externref this will change, we won't be able to
+ // observe the boxing.
+ tbl.set(1, 42);
+ let y = tbl.get(1);
+ assertEq(typeof y, "number");
+ assertEq(y, 42);
+}
+
+function dummy() { return 37 }
+
+///////////////////////////////////////////////////////////////////////////
+//
+// table.get and table.set
+
+const wasmFun = wasmEvalText(`(module (func (export "x")))`).exports.x;
+
+// table.get in bounds - returns right value type & value
+// table.get out of bounds - fails
+
+function testTableGet(type, x) {
+ let ins = wasmEvalText(
+ `(module
+ (table (export "t") 10 ${type})
+ (func (export "f") (param i32) (result ${type})
+ (table.get (local.get 0))))`);
+ ins.exports.t.set(0, x);
+ assertEq(ins.exports.f(0), x);
+ assertEq(ins.exports.f(1), null);
+ assertErrorMessage(() => ins.exports.f(10), WebAssembly.RuntimeError, /index out of bounds/);
+ assertErrorMessage(() => ins.exports.f(-5), WebAssembly.RuntimeError, /index out of bounds/);
+}
+testTableGet('externref', {});
+testTableGet('funcref', wasmFun);
+
+// table.get with non-i32 index - fails validation
+
+assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(
+ `(module
+ (table 10 externref)
+ (func (export "f") (param f64) (result externref)
+ (table.get (local.get 0))))`)),
+ WebAssembly.CompileError,
+ /type mismatch/);
+
+// table.get when there are no tables - fails validation
+
+assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(
+ `(module
+ (func (export "f") (param i32)
+ (drop (table.get (local.get 0)))))`)),
+ WebAssembly.CompileError,
+ /(table index out of range for table.get)|(table index out of bounds)/);
+
+// table.set in bounds with i32 x externref - works, no value generated
+// table.set with null - works
+// table.set out of bounds - fails
+
+function testTableSet(lhs_type, rhs_type, rhs_reftype, x) {
+ let ins = wasmEvalText(
+ `(module
+ (table (export "t") 10 ${lhs_type})
+ (func (export "set_ref") (param i32) (param ${rhs_type})
+ (table.set (local.get 0) (local.get 1)))
+ (func (export "set_null") (param i32)
+ (table.set (local.get 0) (ref.null ${rhs_reftype}))))`);
+ ins.exports.set_ref(3, x);
+ assertEq(ins.exports.t.get(3), x);
+ ins.exports.set_null(3);
+ assertEq(ins.exports.t.get(3), null);
+
+ assertErrorMessage(() => ins.exports.set_ref(10, x), WebAssembly.RuntimeError, /index out of bounds/);
+ assertErrorMessage(() => ins.exports.set_ref(-1, x), WebAssembly.RuntimeError, /index out of bounds/);
+}
+testTableSet('externref', 'externref', 'extern', {});
+testTableSet('funcref', 'funcref', 'func', wasmFun);
+
+// Wasm: table.set on table(funcref) with externref value should fail
+
+assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(
+ `(module
+ (table (export "t") 10 funcref)
+ (func (export "set_ref") (param i32) (param externref)
+ (table.set (local.get 0) (local.get 1))))`)),
+ WebAssembly.CompileError,
+ /(type mismatch: expression has type externref but expected funcref)|(type mismatch: expected funcref, found externref)/);
+
+// table.set with non-i32 index - fails validation
+
+assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(
+ `(module
+ (table 10 externref)
+ (func (export "f") (param f64)
+ (table.set (local.get 0) (ref.null extern))))`)),
+ WebAssembly.CompileError,
+ /type mismatch/);
+
+// table.set with non-ref value - fails validation
+
+assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(
+ `(module
+ (table 10 externref)
+ (func (export "f") (param f64)
+ (table.set (i32.const 0) (local.get 0))))`)),
+ WebAssembly.CompileError,
+ /type mismatch/);
+assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(
+ `(module
+ (table 10 funcref)
+ (func (export "f") (param f64)
+ (table.set (i32.const 0) (local.get 0))))`)),
+ WebAssembly.CompileError,
+ /type mismatch/);
+
+// table.set when there are no tables - fails validation
+
+assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(
+ `(module
+ (func (export "f") (param externref)
+ (table.set (i32.const 0) (local.get 0))))`)),
+ WebAssembly.CompileError,
+ /(table index out of range for table.set)|(table index out of bounds)/);
+
+function testTableGrow(lhs_type, lhs_reftype, rhs_type, x) {
+ let ins = wasmEvalText(
+ `(module
+ (table (export "t") 10 20 ${lhs_type})
+ (func (export "grow") (param i32) (result i32)
+ (table.grow (ref.null ${lhs_reftype}) (local.get 0)))
+ (func (export "grow2") (param i32) (param ${rhs_type}) (result i32)
+ (table.grow (local.get 1) (local.get 0))))`);
+
+ // we can grow table of references
+ // table.grow with zero delta - always works even at maximum
+ // table.grow with delta - works and returns correct old value
+ // table.grow with delta at upper limit - fails
+ // table.grow with negative delta - fails
+ assertEq(ins.exports.grow(0), 10);
+ assertEq(ins.exports.t.length, 10);
+ assertEq(ins.exports.grow(1), 10);
+ assertEq(ins.exports.t.length, 11);
+ assertEq(ins.exports.t.get(10), null);
+ assertEq(ins.exports.grow2(9, x), 11);
+ assertEq(ins.exports.t.length, 20);
+ for (var i = 11; i < 20; i++)
+ assertEq(ins.exports.t.get(i), x);
+ assertEq(ins.exports.grow(0), 20);
+
+ // The JS API throws if it can't grow
+ assertErrorMessage(() => ins.exports.t.grow(1), RangeError, /failed to grow table/);
+ assertErrorMessage(() => ins.exports.t.grow(-1), TypeError, /bad [Tt]able grow delta/);
+
+ // The wasm API does not throw if it can't grow, but returns -1
+ assertEq(ins.exports.grow(1), -1);
+ assertEq(ins.exports.t.length, 20);
+ assertEq(ins.exports.grow(-1), -1);
+ assertEq(ins.exports.t.length, 20)
+}
+testTableGrow('externref', 'extern', 'externref', 42);
+testTableGrow('funcref', 'func', 'funcref', wasmFun);
+
+// Wasm: table.grow on table(funcref) with externref initializer should fail
+
+assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(
+ `(module
+ (table (export "t") 10 20 funcref)
+ (func (export "grow2") (param i32) (param externref) (result i32)
+ (table.grow (local.get 1) (local.get 0))))`)),
+ WebAssembly.CompileError,
+ /(type mismatch: expression has type externref but expected funcref)|(type mismatch: expected funcref, found externref)/);
+
+// Special case for private tables without a maximum
+
+{
+ let ins = wasmEvalText(
+ `(module
+ (table 10 externref)
+ (func (export "grow") (param i32) (result i32)
+ (table.grow (ref.null extern) (local.get 0))))`);
+ assertEq(ins.exports.grow(0), 10);
+ assertEq(ins.exports.grow(1), 10);
+ assertEq(ins.exports.grow(9), 11);
+ assertEq(ins.exports.grow(0), 20);
+}
+
+// table.grow with non-i32 argument - fails validation
+
+assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(
+ `(module
+ (table 10 externref)
+ (func (export "f") (param f64)
+ (table.grow (ref.null extern) (local.get 0))))`)),
+ WebAssembly.CompileError,
+ /type mismatch/);
+
+// table.grow when there are no tables - fails validation
+
+assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(
+ `(module
+ (func (export "f") (param i32)
+ (table.grow (ref.null extern) (local.get 0))))`)),
+ WebAssembly.CompileError,
+ /(table index out of range for table.grow)|(table index out of bounds)/);
+
+// table.size on table of externref
+
+for (let visibility of ['', '(export "t")', '(import "m" "t")']) {
+ let exp = {m:{t: new WebAssembly.Table({element:"externref",
+ initial: 10,
+ maximum: 20})}};
+ let ins = wasmEvalText(
+ `(module
+ (table ${visibility} 10 20 externref)
+ (func (export "grow") (param i32) (result i32)
+ (table.grow (ref.null extern) (local.get 0)))
+ (func (export "size") (result i32)
+ (table.size)))`,
+ exp);
+ assertEq(ins.exports.grow(0), 10);
+ assertEq(ins.exports.size(), 10);
+ assertEq(ins.exports.grow(1), 10);
+ assertEq(ins.exports.size(), 11);
+ assertEq(ins.exports.grow(9), 11);
+ assertEq(ins.exports.size(), 20);
+ assertEq(ins.exports.grow(0), 20);
+ assertEq(ins.exports.size(), 20);
+}
+
+// table.size on table of funcref
+
+{
+ let ins = wasmEvalText(
+ `(module
+ (table (export "t") 2 funcref)
+ (func (export "f") (result i32)
+ (table.size)))`);
+ assertEq(ins.exports.f(), 2);
+ ins.exports.t.grow(1);
+ assertEq(ins.exports.f(), 3);
+}