diff options
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.js | 432 |
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); +} |