diff options
Diffstat (limited to 'js/src/jit-test/tests/wasm/basic.js')
-rw-r--r-- | js/src/jit-test/tests/wasm/basic.js | 627 |
1 files changed, 627 insertions, 0 deletions
diff --git a/js/src/jit-test/tests/wasm/basic.js b/js/src/jit-test/tests/wasm/basic.js new file mode 100644 index 000000000..500ff8d20 --- /dev/null +++ b/js/src/jit-test/tests/wasm/basic.js @@ -0,0 +1,627 @@ +load(libdir + "wasm.js"); + +// ---------------------------------------------------------------------------- +// exports + +var o = wasmEvalText('(module)').exports; +assertEq(Object.getOwnPropertyNames(o).length, 0); + +var o = wasmEvalText('(module (func))').exports; +assertEq(Object.getOwnPropertyNames(o).length, 0); + +var o = wasmEvalText('(module (func) (export "a" 0))').exports; +var names = Object.getOwnPropertyNames(o); +assertEq(names.length, 1); +assertEq(names[0], 'a'); +var desc = Object.getOwnPropertyDescriptor(o, 'a'); +assertEq(typeof desc.value, "function"); +assertEq(desc.value.name, "0"); +assertEq(desc.value.length, 0); +assertEq(desc.value(), undefined); +assertEq(desc.writable, false); +assertEq(desc.enumerable, true); +assertEq(desc.configurable, false); +assertEq(desc.value(), undefined); + +wasmValidateText('(module (func) (func) (export "a" 0))'); +wasmValidateText('(module (func) (func) (export "a" 1))'); +wasmValidateText('(module (func $a) (func $b) (export "a" $a) (export "b" $b))'); +wasmValidateText('(module (func $a) (func $b) (export "a" $a) (export "b" $b))'); + +wasmFailValidateText('(module (func) (export "a" 1))', /exported function index out of bounds/); +wasmFailValidateText('(module (func) (func) (export "a" 2))', /exported function index out of bounds/); + +var o = wasmEvalText('(module (func) (export "a" 0) (export "b" 0))').exports; +assertEq(Object.getOwnPropertyNames(o).sort().toString(), "a,b"); +assertEq(o.a.name, "0"); +assertEq(o.b.name, "0"); +assertEq(o.a === o.b, true); + +var o = wasmEvalText('(module (func) (func) (export "a" 0) (export "b" 1))').exports; +assertEq(Object.getOwnPropertyNames(o).sort().toString(), "a,b"); +assertEq(o.a.name, "0"); +assertEq(o.b.name, "1"); +assertEq(o.a === o.b, false); + +var o = wasmEvalText('(module (func (result i32) (i32.const 1)) (func (result i32) (i32.const 2)) (export "a" 0) (export "b" 1))').exports; +assertEq(o.a(), 1); +assertEq(o.b(), 2); +var o = wasmEvalText('(module (func (result i32) (i32.const 1)) (func (result i32) (i32.const 2)) (export "a" 1) (export "b" 0))').exports; +assertEq(o.a(), 2); +assertEq(o.b(), 1); + +wasmFailValidateText('(module (func) (export "a" 0) (export "a" 0))', /duplicate export/); +wasmFailValidateText('(module (func) (func) (export "a" 0) (export "a" 1))', /duplicate export/); + +// ---------------------------------------------------------------------------- +// signatures + +wasmFailValidateText('(module (func (result i32)))', mismatchError("void", "i32")); +wasmFailValidateText('(module (func (result i32) (nop)))', mismatchError("void", "i32")); + +wasmValidateText('(module (func (nop)))'); +wasmValidateText('(module (func (result i32) (i32.const 42)))'); +wasmValidateText('(module (func (param i32)))'); +wasmValidateText('(module (func (param i32) (result i32) (i32.const 42)))'); +wasmValidateText('(module (func (result i32) (param i32) (i32.const 42)))'); +wasmValidateText('(module (func (param f32)))'); +wasmValidateText('(module (func (param f64)))'); + +var f = wasmEvalText('(module (func (param i64) (result i32) (i32.const 123)) (export "" 0))').exports[""]; +assertErrorMessage(f, TypeError, /i64/); +var f = wasmEvalText('(module (func (param i32) (result i64) (i64.const 123)) (export "" 0))').exports[""]; +assertErrorMessage(f, TypeError, /i64/); + +var f = wasmEvalText('(module (import $imp "a" "b" (param i64) (result i32)) (func $f (result i32) (call $imp (i64.const 0))) (export "" $f))', {a:{b:()=>{}}}).exports[""]; +assertErrorMessage(f, TypeError, /i64/); +var f = wasmEvalText('(module (import $imp "a" "b" (result i64)) (func $f (result i64) (call $imp)) (export "" $f))', {a:{b:()=>{}}}).exports[""]; +assertErrorMessage(f, TypeError, /i64/); + +setJitCompilerOption('wasm.test-mode', 1); +wasmFullPassI64('(module (func (result i64) (i64.const 123)) (export "run" 0))', {low: 123, high: 0}); +wasmFullPassI64('(module (func (param i64) (result i64) (get_local 0)) (export "run" 0))', + { low: 0x7fffffff, high: 0x12340000}, + {}, + {low: 0x7fffffff, high: 0x12340000}); +wasmFullPassI64('(module (func (param i64) (result i64) (i64.add (get_local 0) (i64.const 1))) (export "run" 0))', + {low: 0x0, high: 0x12340001}, + {}, + { low: 0xffffffff, high: 0x12340000}); +setJitCompilerOption('wasm.test-mode', 0); + +// ---------------------------------------------------------------------------- +// imports + +const noImportObj = "second argument must be an object"; + +assertErrorMessage(() => wasmEvalText('(module (import "a" "b"))', 1), TypeError, noImportObj); +assertErrorMessage(() => wasmEvalText('(module (import "a" "b"))', null), TypeError, noImportObj); + +const notObject = /import object field '\w*' is not an Object/; +const notFunction = /import object field '\w*' is not a Function/; + +var code = '(module (import "a" "b"))'; +assertErrorMessage(() => wasmEvalText(code), TypeError, noImportObj); +assertErrorMessage(() => wasmEvalText(code, {}), TypeError, notObject); +assertErrorMessage(() => wasmEvalText(code, {a:1}), TypeError, notObject); +assertErrorMessage(() => wasmEvalText(code, {a:{}}), TypeError, notFunction); +assertErrorMessage(() => wasmEvalText(code, {a:{b:1}}), TypeError, notFunction); +wasmEvalText(code, {a:{b:()=>{}}}); + +var code = '(module (import "" "b"))'; +wasmEvalText(code, {"":{b:()=>{}}}); + +var code = '(module (import "a" ""))'; +assertErrorMessage(() => wasmEvalText(code), TypeError, noImportObj); +assertErrorMessage(() => wasmEvalText(code, {}), TypeError, notObject); +assertErrorMessage(() => wasmEvalText(code, {a:1}), TypeError, notObject); +wasmEvalText(code, {a:{"":()=>{}}}); + +var code = '(module (import "a" "") (import "b" "c") (import "c" ""))'; +assertErrorMessage(() => wasmEvalText(code, {a:()=>{}, b:{c:()=>{}}, c:{}}), TypeError, notFunction); +wasmEvalText(code, {a:{"":()=>{}}, b:{c:()=>{}}, c:{"":()=>{}}}); + +wasmEvalText('(module (import "a" "" (result i32)))', {a:{"":()=>{}}}); +wasmEvalText('(module (import "a" "" (result f32)))', {a:{"":()=>{}}}); +wasmEvalText('(module (import "a" "" (result f64)))', {a:{"":()=>{}}}); +wasmEvalText('(module (import $foo "a" "" (result f64)))', {a:{"":()=>{}}}); + +// ---------------------------------------------------------------------------- +// memory + +wasmValidateText('(module (memory 0))'); +wasmValidateText('(module (memory 1))'); +wasmFailValidateText('(module (memory 65536))', /initial memory size too big/); + +// May OOM, but must not crash: +try { + wasmEvalText('(module (memory 65535))'); +} catch (e) { + assertEq(String(e).indexOf("out of memory") != -1 || + String(e).indexOf("memory size too big") != -1, true); +} + +var buf = wasmEvalText('(module (memory 1) (export "memory" memory))').exports.memory.buffer; +assertEq(buf instanceof ArrayBuffer, true); +assertEq(buf.byteLength, 65536); + +var obj = wasmEvalText('(module (memory 1) (func (result i32) (i32.const 42)) (func (nop)) (export "memory" memory) (export "b" 0) (export "c" 1))').exports; +assertEq(obj.memory.buffer instanceof ArrayBuffer, true); +assertEq(obj.b instanceof Function, true); +assertEq(obj.c instanceof Function, true); +assertEq(obj.memory.buffer.byteLength, 65536); +assertEq(obj.b(), 42); +assertEq(obj.c(), undefined); + +var buf = wasmEvalText('(module (memory 1) (data (i32.const 0) "") (export "memory" memory))').exports.memory.buffer; +assertEq(new Uint8Array(buf)[0], 0); + +var buf = wasmEvalText('(module (memory 1) (data (i32.const 65536) "") (export "memory" memory))').exports.memory.buffer; +assertEq(new Uint8Array(buf)[0], 0); + +var buf = wasmEvalText('(module (memory 1) (data (i32.const 0) "a") (export "memory" memory))').exports.memory.buffer; +assertEq(new Uint8Array(buf)[0], 'a'.charCodeAt(0)); + +var buf = wasmEvalText('(module (memory 1) (data (i32.const 0) "a") (data (i32.const 2) "b") (export "memory" memory))').exports.memory.buffer; +assertEq(new Uint8Array(buf)[0], 'a'.charCodeAt(0)); +assertEq(new Uint8Array(buf)[1], 0); +assertEq(new Uint8Array(buf)[2], 'b'.charCodeAt(0)); + +var buf = wasmEvalText('(module (memory 1) (data (i32.const 65535) "c") (export "memory" memory))').exports.memory.buffer; +assertEq(new Uint8Array(buf)[0], 0); +assertEq(new Uint8Array(buf)[65535], 'c'.charCodeAt(0)); + +// ---------------------------------------------------------------------------- +// locals + +assertEq(wasmEvalText('(module (func (param i32) (result i32) (get_local 0)) (export "" 0))').exports[""](), 0); +assertEq(wasmEvalText('(module (func (param i32) (result i32) (get_local 0)) (export "" 0))').exports[""](42), 42); +assertEq(wasmEvalText('(module (func (param i32) (param i32) (result i32) (get_local 0)) (export "" 0))').exports[""](42, 43), 42); +assertEq(wasmEvalText('(module (func (param i32) (param i32) (result i32) (get_local 1)) (export "" 0))').exports[""](42, 43), 43); + +wasmFailValidateText('(module (func (get_local 0)))', /get_local index out of range/); +wasmFailValidateText('(module (func (result f32) (local i32) (get_local 0)))', mismatchError("i32", "f32")); +wasmFailValidateText('(module (func (result i32) (local f32) (get_local 0)))', mismatchError("f32", "i32")); +wasmFailValidateText('(module (func (result f32) (param i32) (local f32) (get_local 0)))', mismatchError("i32", "f32")); +wasmFailValidateText('(module (func (result i32) (param i32) (local f32) (get_local 1)))', mismatchError("f32", "i32")); + +wasmValidateText('(module (func (local i32)))'); +wasmValidateText('(module (func (local i32) (local f32)))'); + +wasmFullPass('(module (func (result i32) (local i32) (get_local 0)) (export "run" 0))', 0); +wasmFullPass('(module (func (result i32) (param i32) (local f32) (get_local 0)) (export "run" 0))', 0); +wasmFullPass('(module (func (result f32) (param i32) (local f32) (get_local 1)) (export "run" 0))', 0); + +wasmFailValidateText('(module (func (set_local 0 (i32.const 0))))', /set_local index out of range/); +wasmFailValidateText('(module (func (local f32) (set_local 0 (i32.const 0))))', mismatchError("i32", "f32")); +wasmFailValidateText('(module (func (local f32) (set_local 0 (nop))))', /popping value from empty stack/); +wasmFailValidateText('(module (func (local i32) (local f32) (set_local 0 (get_local 1))))', mismatchError("f32", "i32")); +wasmFailValidateText('(module (func (local i32) (local f32) (set_local 1 (get_local 0))))', mismatchError("i32", "f32")); + +wasmValidateText('(module (func (local i32) (set_local 0 (i32.const 0))))'); +wasmValidateText('(module (func (local i32) (local f32) (set_local 0 (get_local 0))))'); +wasmValidateText('(module (func (local i32) (local f32) (set_local 1 (get_local 1))))'); + +wasmFullPass('(module (func (result i32) (local i32) (tee_local 0 (i32.const 42))) (export "run" 0))', 42); +wasmFullPass('(module (func (result i32) (local i32) (tee_local 0 (get_local 0))) (export "run" 0))', 0); + +wasmFullPass('(module (func (param $a i32) (result i32) (get_local $a)) (export "run" 0))', 0); +wasmFullPass('(module (func (param $a i32) (local $b i32) (result i32) (block i32 (set_local $b (get_local $a)) (get_local $b))) (export "run" 0))', 42, {}, 42); + +wasmValidateText('(module (func (local i32) (local $a f32) (set_local 0 (i32.const 1)) (set_local $a (f32.const nan))))'); + +// ---------------------------------------------------------------------------- +// blocks + +wasmFullPass('(module (func (block )) (export "run" 0))', undefined); + +wasmFailValidateText('(module (func (result i32) (block )))', mismatchError("void", "i32")); +wasmFailValidateText('(module (func (result i32) (block (block ))))', mismatchError("void", "i32")); +wasmFailValidateText('(module (func (local i32) (set_local 0 (block ))))', /popping value from empty stack/); + +wasmFullPass('(module (func (block (block ))) (export "run" 0))', undefined); +wasmFullPass('(module (func (result i32) (block i32 (i32.const 42))) (export "run" 0))', 42); +wasmFullPass('(module (func (result i32) (block i32 (block i32 (i32.const 42)))) (export "run" 0))', 42); +wasmFailValidateText('(module (func (result f32) (block i32 (i32.const 0))))', mismatchError("i32", "f32")); + +wasmFullPass('(module (func (result i32) (block i32 (drop (i32.const 13)) (block i32 (i32.const 42)))) (export "run" 0))', 42); +wasmFailValidateText('(module (func (result f32) (param f32) (block i32 (drop (get_local 0)) (i32.const 0))))', mismatchError("i32", "f32")); + +wasmFullPass('(module (func (result i32) (local i32) (set_local 0 (i32.const 42)) (get_local 0)) (export "run" 0))', 42); + +// ---------------------------------------------------------------------------- +// calls + +wasmFailValidateText('(module (func (nop)) (func (call 0 (i32.const 0))))', /unused values not explicitly dropped by end of block/); + +wasmFailValidateText('(module (func (param i32) (nop)) (func (call 0)))', /peeking at value from outside block/); +wasmFailValidateText('(module (func (param f32) (nop)) (func (call 0 (i32.const 0))))', mismatchError("i32", "f32")); +wasmFailValidateText('(module (func (nop)) (func (call 3)))', /callee index out of range/); + +wasmValidateText('(module (func (nop)) (func (call 0)))'); +wasmValidateText('(module (func (param i32) (nop)) (func (call 0 (i32.const 0))))'); + +wasmFullPass('(module (func (result i32) (i32.const 42)) (func (result i32) (call 0)) (export "run" 1))', 42); +assertThrowsInstanceOf(() => wasmEvalText('(module (func (call 0)) (export "" 0))').exports[""](), InternalError); +assertThrowsInstanceOf(() => wasmEvalText('(module (func (call 1)) (func (call 0)) (export "" 0))').exports[""](), InternalError); + +wasmValidateText('(module (func (param i32 f32)) (func (call 0 (i32.const 0) (f32.const nan))))'); +wasmFailValidateText('(module (func (param i32 f32)) (func (call 0 (i32.const 0) (i32.const 0))))', mismatchError("i32", "f32")); + +wasmFailValidateText('(module (import "a" "") (func (call 0 (i32.const 0))))', /unused values not explicitly dropped by end of block/); +wasmFailValidateText('(module (import "a" "" (param i32)) (func (call 0)))', /peeking at value from outside block/); +wasmFailValidateText('(module (import "a" "" (param f32)) (func (call 0 (i32.const 0))))', mismatchError("i32", "f32")); + +assertErrorMessage(() => wasmEvalText('(module (import "a" "") (func (call 1)))'), TypeError, noImportObj); +wasmEvalText('(module (import "" "a") (func (call 0)))', {"":{a:()=>{}}}); +wasmEvalText('(module (import "" "a" (param i32)) (func (call 0 (i32.const 0))))', {"":{a:()=>{}}}); + +function checkF32CallImport(v) { + wasmFullPass('(module (import "" "a" (result f32)) (func (result f32) (call 0)) (export "run" 1))', + Math.fround(v), + {"":{a:()=>{ return v; }}}); + wasmFullPass('(module (import "" "a" (param f32)) (func (param f32) (call 0 (get_local 0))) (export "run" 1))', + undefined, + {"":{a:x=>{ assertEq(Math.fround(v), x); }}}, + v); +} +checkF32CallImport(13.37); +checkF32CallImport(NaN); +checkF32CallImport(-Infinity); +checkF32CallImport(-0); +checkF32CallImport(Math.pow(2, 32) - 1); + +var counter = 0; +var f = wasmEvalText('(module (import "" "inc") (func (call 0)) (export "" 1))', {"":{inc:()=>counter++}}).exports[""]; +var g = wasmEvalText('(module (import "" "f") (func (block (call 0) (call 0))) (export "" 1))', {"":{f}}).exports[""]; +f(); +assertEq(counter, 1); +g(); +assertEq(counter, 3); + +var f = wasmEvalText('(module (import "" "callf") (func (call 0)) (export "" 1))', {"":{callf:()=>f()}}).exports[""]; +assertThrowsInstanceOf(() => f(), InternalError); + +var f = wasmEvalText('(module (import "" "callg") (func (call 0)) (export "" 1))', {"":{callg:()=>g()}}).exports[""]; +var g = wasmEvalText('(module (import "" "callf") (func (call 0)) (export "" 1))', {"":{callf:()=>f()}}).exports[""]; +assertThrowsInstanceOf(() => f(), InternalError); + +var code = '(module (import "" "one" (result i32)) (import "" "two" (result i32)) (func (result i32) (i32.const 3)) (func (result i32) (i32.const 4)) (func (result i32) BODY) (export "run" 4))'; +var imports = {"":{one:()=>1, two:()=>2}}; +wasmFullPass(code.replace('BODY', '(call 0)'), 1, imports); +wasmFullPass(code.replace('BODY', '(call 1)'), 2, imports); +wasmFullPass(code.replace('BODY', '(call 2)'), 3, imports); +wasmFullPass(code.replace('BODY', '(call 3)'), 4, imports); + +wasmFullPass(`(module (import "" "evalcx" (param i32) (result i32)) (func (result i32) (call 0 (i32.const 0))) (export "run" 1))`, 0, {"":{evalcx}}); + +if (typeof evaluate === 'function') + evaluate(`new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary('(module)'))) `, { fileName: null }); + +{ + setJitCompilerOption('wasm.test-mode', 1); + + let imp = {"":{ + param(i64) { + assertEqI64(i64, { + low: 0x9abcdef0, + high: 0x12345678 + }); + return 42; + }, + result(i32) { + return { + low: 0xabcdef01, + high: 0x12345678 + i32 + } + }, + paramAndResult(i64) { + assertEqI64(i64, { + low: 0x9abcdef0, + high: 0x12345678 + }); + i64.low = 1337; + return i64; + } + }} + + wasmFullPass(`(module + (import "" "param" (param i64) (result i32)) + (func (result i32) (call 0 (i64.const 0x123456789abcdef0))) + (export "run" 1))`, 42, imp); + + wasmFullPass(`(module + (import "" "param" (param i64)(param i64)(param i64)(param i64)(param i64)(param i64)(param i64) (param i64) (result i32)) + (func (result i32) (call 0 (i64.const 0x123456789abcdef0)(i64.const 0x123456789abcdef0)(i64.const 0x123456789abcdef0)(i64.const 0x123456789abcdef0)(i64.const 0x123456789abcdef0)(i64.const 0x123456789abcdef0)(i64.const 0x123456789abcdef0)(i64.const 0x123456789abcdef0))) + (export "run" 1))`, 42, imp); + + wasmFullPassI64(`(module + (import "" "result" (param i32) (result i64)) + (func (result i64) (call 0 (i32.const 3))) + (export "run" 1))`, { low: 0xabcdef01, high: 0x1234567b }, imp); + + // Ensure the ion exit is never taken. + let ionThreshold = 2 * getJitCompilerOptions()['ion.warmup.trigger']; + wasmFullPassI64(`(module + (import "" "paramAndResult" (param i64) (result i64)) + (func (result i64) (local i32) (local i64) + (set_local 0 (i32.const 0)) + (loop $out $in + (set_local 1 (call 0 (i64.const 0x123456789abcdef0))) + (set_local 0 (i32.add (get_local 0) (i32.const 1))) + (if (i32.le_s (get_local 0) (i32.const ${ionThreshold})) (br $in)) + ) + (get_local 1) + ) + (export "run" 1))`, { low: 1337, high: 0x12345678 }, imp); + + wasmFullPassI64(`(module + (import "" "paramAndResult" (param i64) (result i64)) + (func (result i64) (local i32) (local i64) + (set_local 0 (i32.const 0)) + (block $out + (loop $in + (set_local 1 (call 0 (i64.const 0x123456789abcdef0))) + (set_local 0 (i32.add (get_local 0) (i32.const 1))) + (if (i32.le_s (get_local 0) (i32.const ${ionThreshold})) (br $in)) + ) + ) + (get_local 1) + ) + (export "run" 1))`, { low: 1337, high: 0x12345678 }, imp); + + setJitCompilerOption('wasm.test-mode', 0); +} + +wasmFailValidateText(`(module (type $t (func)) (func (call_indirect $t (i32.const 0))))`, /can't call_indirect without a table/); + +var {v2i, i2i, i2v} = wasmEvalText(`(module + (type (func (result i32))) + (type (func (param i32) (result i32))) + (type (func (param i32))) + (func (type 0) (i32.const 13)) + (func (type 0) (i32.const 42)) + (func (type 1) (i32.add (get_local 0) (i32.const 1))) + (func (type 1) (i32.add (get_local 0) (i32.const 2))) + (func (type 1) (i32.add (get_local 0) (i32.const 3))) + (func (type 1) (i32.add (get_local 0) (i32.const 4))) + (table anyfunc (elem 0 1 2 3 4 5)) + (func (param i32) (result i32) (call_indirect 0 (get_local 0))) + (func (param i32) (param i32) (result i32) (call_indirect 1 (get_local 1) (get_local 0))) + (func (param i32) (call_indirect 2 (i32.const 0) (get_local 0))) + (export "v2i" 6) + (export "i2i" 7) + (export "i2v" 8) +)`).exports; + +const signatureMismatch = /indirect call signature mismatch/; + +assertEq(v2i(0), 13); +assertEq(v2i(1), 42); +assertErrorMessage(() => v2i(2), Error, signatureMismatch); +assertErrorMessage(() => v2i(3), Error, signatureMismatch); +assertErrorMessage(() => v2i(4), Error, signatureMismatch); +assertErrorMessage(() => v2i(5), Error, signatureMismatch); + +assertErrorMessage(() => i2i(0), Error, signatureMismatch); +assertErrorMessage(() => i2i(1), Error, signatureMismatch); +assertEq(i2i(2, 100), 101); +assertEq(i2i(3, 100), 102); +assertEq(i2i(4, 100), 103); +assertEq(i2i(5, 100), 104); + +assertErrorMessage(() => i2v(0), Error, signatureMismatch); +assertErrorMessage(() => i2v(1), Error, signatureMismatch); +assertErrorMessage(() => i2v(2), Error, signatureMismatch); +assertErrorMessage(() => i2v(3), Error, signatureMismatch); +assertErrorMessage(() => i2v(4), Error, signatureMismatch); +assertErrorMessage(() => i2v(5), Error, signatureMismatch); + +{ + enableSPSProfiling(); + + var stack; + wasmFullPass( + `(module + (type $v2v (func)) + (import $foo "" "f") + (func $a (call $foo)) + (func $b (result i32) (i32.const 0)) + (table anyfunc (elem $a $b)) + (func $bar (call_indirect $v2v (i32.const 0))) + (export "run" $bar) + )`, + undefined, + {"":{f:() => { stack = new Error().stack }}} + ); + + disableSPSProfiling(); + + var inner = stack.indexOf("wasm-function[1]"); + var outer = stack.indexOf("wasm-function[3]"); + assertEq(inner === -1, false); + assertEq(outer === -1, false); + assertEq(inner < outer, true); +} + +for (bad of [6, 7, 100, Math.pow(2,31)-1, Math.pow(2,31), Math.pow(2,31)+1, Math.pow(2,32)-2, Math.pow(2,32)-1]) { + assertThrowsInstanceOf(() => v2i(bad), WebAssembly.RuntimeError); + assertThrowsInstanceOf(() => i2i(bad, 0), WebAssembly.RuntimeError); + assertThrowsInstanceOf(() => i2v(bad, 0), WebAssembly.RuntimeError); +} + +wasmValidateText('(module (func $foo (nop)) (func (call $foo)))'); +wasmValidateText('(module (func (call $foo)) (func $foo (nop)))'); +wasmValidateText('(module (import $bar "" "a") (func (call $bar)) (func $foo (nop)))'); + +// ---------------------------------------------------------------------------- +// select + +wasmFailValidateText('(module (func (select (i32.const 0) (i32.const 0) (f32.const 0))))', mismatchError("f32", "i32")); + +wasmFailValidateText('(module (func (select (i32.const 0) (f32.const 0) (i32.const 0))) (export "" 0))', /select operand types must match/); +wasmFailValidateText('(module (func (select (block ) (i32.const 0) (i32.const 0))) (export "" 0))', /popping value from empty stack/); +assertEq(wasmEvalText('(module (func (select (return) (i32.const 0) (i32.const 0))) (export "" 0))').exports[""](), undefined); +assertEq(wasmEvalText('(module (func (i32.add (i32.const 0) (select (return) (i32.const 0) (i32.const 0)))) (export "" 0))').exports[""](), undefined); +wasmFailValidateText('(module (func (select (if i32 (i32.const 1) (i32.const 0) (f32.const 0)) (i32.const 0) (i32.const 0))) (export "" 0))', mismatchError("f32", "i32")); +wasmFailValidateText('(module (func) (func (select (call 0) (call 0) (i32.const 0))) (export "" 0))', /popping value from empty stack/); + +(function testSideEffects() { + +var numT = 0; +var numF = 0; + +var imports = {"": { + ifTrue: () => 1 + numT++, + ifFalse: () => -1 + numF++, +}} + +// Test that side-effects are applied on both branches. +var f = wasmEvalText(` +(module + (import "" "ifTrue" (result i32)) + (import "" "ifFalse" (result i32)) + (func (result i32) (param i32) + (select + (call 0) + (call 1) + (get_local 0) + ) + ) + (export "" 2) +) +`, imports).exports[""]; + +assertEq(f(-1), numT); +assertEq(numT, 1); +assertEq(numF, 1); + +assertEq(f(0), numF - 2); +assertEq(numT, 2); +assertEq(numF, 2); + +assertEq(f(1), numT); +assertEq(numT, 3); +assertEq(numF, 3); + +assertEq(f(0), numF - 2); +assertEq(numT, 4); +assertEq(numF, 4); + +assertEq(f(0), numF - 2); +assertEq(numT, 5); +assertEq(numF, 5); + +assertEq(f(1), numT); +assertEq(numT, 6); +assertEq(numF, 6); + +})(); + +function testSelect(type, trueVal, falseVal) { + + var trueJS = jsify(trueVal); + var falseJS = jsify(falseVal); + + // Always true condition + var alwaysTrue = wasmEvalText(` + (module + (func (result ${type}) (param i32) + (select + (${type}.const ${trueVal}) + (${type}.const ${falseVal}) + (i32.const 1) + ) + ) + (export "" 0) + ) + `, imports).exports[""]; + + assertEq(alwaysTrue(0), trueJS); + assertEq(alwaysTrue(1), trueJS); + assertEq(alwaysTrue(-1), trueJS); + + // Always false condition + var alwaysFalse = wasmEvalText(` + (module + (func (result ${type}) (param i32) + (select + (${type}.const ${trueVal}) + (${type}.const ${falseVal}) + (i32.const 0) + ) + ) + (export "" 0) + ) + `, imports).exports[""]; + + assertEq(alwaysFalse(0), falseJS); + assertEq(alwaysFalse(1), falseJS); + assertEq(alwaysFalse(-1), falseJS); + + // Variable condition + var f = wasmEvalText(` + (module + (func (result ${type}) (param i32) + (select + (${type}.const ${trueVal}) + (${type}.const ${falseVal}) + (get_local 0) + ) + ) + (export "" 0) + ) + `, imports).exports[""]; + + assertEq(f(0), falseJS); + assertEq(f(1), trueJS); + assertEq(f(-1), trueJS); + + wasmFullPass(` + (module + (func (result ${type}) (param i32) + (select + (${type}.const ${trueVal}) + (${type}.const ${falseVal}) + (get_local 0) + ) + ) + (export "run" 0) + )`, + trueJS, + imports, + 1); +} + +testSelect('i32', 13, 37); +testSelect('i32', Math.pow(2, 31) - 1, -Math.pow(2, 31)); + +testSelect('f32', Math.fround(13.37), Math.fround(19.89)); +testSelect('f32', 'infinity', '-0'); +testSelect('f32', 'nan', Math.pow(2, -31)); + +testSelect('f64', 13.37, 19.89); +testSelect('f64', 'infinity', '-0'); +testSelect('f64', 'nan', Math.pow(2, -31)); + +{ + setJitCompilerOption('wasm.test-mode', 1); + + var f = wasmEvalText(` + (module + (func (result i64) (param i32) + (select + (i64.const 0xc0010ff08badf00d) + (i64.const 0x12345678deadc0de) + (get_local 0) + ) + ) + (export "" 0) + )`, imports).exports[""]; + + assertEqI64(f(0), { low: 0xdeadc0de, high: 0x12345678}); + assertEqI64(f(1), { low: 0x8badf00d, high: 0xc0010ff0}); + assertEqI64(f(-1), { low: 0x8badf00d, high: 0xc0010ff0}); + + setJitCompilerOption('wasm.test-mode', 0); +} |