diff options
Diffstat (limited to 'js/src/jit-test/tests/wasm/control-flow.js')
-rw-r--r-- | js/src/jit-test/tests/wasm/control-flow.js | 736 |
1 files changed, 736 insertions, 0 deletions
diff --git a/js/src/jit-test/tests/wasm/control-flow.js b/js/src/jit-test/tests/wasm/control-flow.js new file mode 100644 index 000000000..fd4f8e4be --- /dev/null +++ b/js/src/jit-test/tests/wasm/control-flow.js @@ -0,0 +1,736 @@ +load(libdir + "wasm.js"); + +const RuntimeError = WebAssembly.RuntimeError; + +// ---------------------------------------------------------------------------- +// if + +// Condition is an int32 +wasmFailValidateText('(module (func (local f32) (if (get_local 0) (i32.const 1))))', mismatchError("f32", "i32")); +wasmFailValidateText('(module (func (local f32) (if (get_local 0) (i32.const 1) (i32.const 0))))', mismatchError("f32", "i32")); +wasmFailValidateText('(module (func (local f64) (if (get_local 0) (i32.const 1) (i32.const 0))))', mismatchError("f64", "i32")); +wasmEvalText('(module (func (local i32) (if (get_local 0) (nop))) (export "" 0))'); +wasmEvalText('(module (func (local i32) (if (get_local 0) (nop) (nop))) (export "" 0))'); + +// Expression values types are consistent +wasmFailValidateText('(module (func (result i32) (local f32) (if f32 (i32.const 42) (get_local 0) (i32.const 0))))', mismatchError("i32", "f32")); +wasmFailValidateText('(module (func (result i32) (local f64) (if i32 (i32.const 42) (i32.const 0) (get_local 0))))', mismatchError("f64", "i32")); +assertEq(wasmEvalText('(module (func (result i32) (if i32 (i32.const 42) (i32.const 1) (i32.const 2))) (export "" 0))').exports[""](), 1); +assertEq(wasmEvalText('(module (func (result i32) (if i32 (i32.const 0) (i32.const 1) (i32.const 2))) (export "" 0))').exports[""](), 2); + +// Even if we don't yield, sub expressions types still have to match. +wasmFailValidateText('(module (func (param f32) (if i32 (i32.const 42) (i32.const 1) (get_local 0))) (export "" 0))', mismatchError('f32', 'i32')); +wasmFailValidateText('(module (func (if i32 (i32.const 42) (i32.const 1) (i32.const 0))) (export "" 0))', /unused values not explicitly dropped by end of block/); +wasmFullPass('(module (func (drop (if i32 (i32.const 42) (i32.const 1) (i32.const 0)))) (export "run" 0))', undefined); +wasmFullPass('(module (func (param f32) (if (i32.const 42) (drop (i32.const 1)) (drop (get_local 0)))) (export "run" 0))', undefined, {}, 13.37); + +// Sub-expression values are returned +wasmFullPass(`(module + (func + (result i32) + (if i32 + (i32.const 42) + (block i32 + ( + if i32 + (block i32 + (drop (i32.const 3)) + (drop (i32.const 5)) + (i32.const 0) + ) + (i32.const 1) + (i32.const 2) + ) + ) + (i32.const 0) + ) + ) + (export "run" 0) +)`, 2); + +// The if (resp. else) branch is taken iff the condition is true (resp. false) +counter = 0; +var imports = { "":{inc() { counter++ }} }; +wasmFullPass(`(module + (import "" "inc" (result i32)) + (func + (result i32) + (if i32 + (i32.const 42) + (i32.const 1) + (call 0) + ) + ) + (export "run" 1) +)`, 1, imports); +assertEq(counter, 0); + +wasmFullPass(`(module + (import "" "inc" (result i32)) + (func + (result i32) + (if i32 + (i32.const 0) + (call 0) + (i32.const 1) + ) + ) + (export "run" 1) +)`, 1, imports); +assertEq(counter, 0); + +wasmFullPass(`(module + (import "" "inc" (result i32)) + (func + (if + (i32.const 0) + (drop (call 0)) + ) + ) + (export "run" 1) +)`, undefined, imports); +assertEq(counter, 0); + +assertEq(wasmEvalText(`(module + (import "" "inc" (result i32)) + (func + (if + (i32.const 1) + (drop (call 0)) + ) + ) + (export "" 1) +)`, imports).exports[""](), undefined); +assertEq(counter, 1); + +wasmFullPass(`(module + (func + (result i32) + (if i32 + (i32.const 0) + (br 0 (i32.const 0)) + (br 0 (i32.const 1)) + ) + ) + (export "run" 0) +)`, 1); +assertEq(counter, 1); + +wasmFullPass(`(module + (func + (if + (i32.const 1) + (br 0) + ) + ) + (export "run" 0) +)`, undefined); +assertEq(counter, 1); + +// One can chain if with if/if +counter = 0; +wasmFullPass(`(module + (import "" "inc" (result i32)) + (func + (result i32) + (if i32 + (i32.const 1) + (if i32 + (i32.const 2) + (if i32 + (i32.const 3) + (if i32 + (i32.const 0) + (call 0) + (i32.const 42) + ) + (call 0) + ) + (call 0) + ) + (call 0) + ) + ) + (export "run" 1) +)`, 42, imports); +assertEq(counter, 0); + +// "if" doesn't return an expression value +wasmFailValidateText('(module (func (result i32) (if i32 (i32.const 42) (i32.const 0))))', /if without else with a result value/); +wasmFailValidateText('(module (func (result i32) (if i32 (i32.const 42) (drop (i32.const 0)))))', mismatchError("void", "i32")); +wasmFailValidateText('(module (func (result i32) (if i32 (i32.const 1) (i32.const 0) (if i32 (i32.const 1) (i32.const 1)))))', /if without else with a result value/); +wasmFailValidateText('(module (func (result i32) (if i32 (i32.const 1) (drop (i32.const 0)) (if (i32.const 1) (drop (i32.const 1))))))', mismatchError("void", "i32")); +wasmFailValidateText('(module (func (if i32 (i32.const 1) (i32.const 0) (if i32 (i32.const 1) (i32.const 1)))))', /if without else with a result value/); +wasmFailValidateText('(module (func (if i32 (i32.const 1) (i32.const 0) (if (i32.const 1) (drop (i32.const 1))))))', mismatchError("void", "i32")); +wasmFailValidateText('(module (func (if (i32.const 1) (drop (i32.const 0)) (if i32 (i32.const 1) (i32.const 1)))))', /if without else with a result value/); +wasmEvalText('(module (func (if (i32.const 1) (drop (i32.const 0)) (if (i32.const 1) (drop (i32.const 1))))))'); + +// ---------------------------------------------------------------------------- +// return + +wasmFullPass('(module (func (return)) (export "run" 0))', undefined); +wasmFullPass('(module (func (result i32) (return (i32.const 1))) (export "run" 0))', 1); +wasmFullPass('(module (func (if (return) (i32.const 0))) (export "run" 0))', undefined); +wasmFailValidateText('(module (func (result i32) (return)) (export "" 0))', /popping value from empty stack/); +wasmFullPass('(module (func (return (i32.const 1))) (export "run" 0))', undefined); +wasmFailValidateText('(module (func (result f32) (return (i32.const 1))) (export "" 0))', mismatchError("i32", "f32")); +wasmFailValidateText('(module (func (result i32) (return)) (export "" 0))', /popping value from empty stack/); + +// ---------------------------------------------------------------------------- +// br / br_if + +wasmFailValidateText('(module (func (result i32) (block (br 0))) (export "" 0))', mismatchError("void", "i32")); +wasmFailValidateText('(module (func (result i32) (br 0)) (export "" 0))', /popping value from empty stack/); +wasmFailValidateText('(module (func (result i32) (block (br_if 0 (i32.const 0)))) (export "" 0))', mismatchError("void", "i32")); + +const DEPTH_OUT_OF_BOUNDS = /branch depth exceeds current nesting level/; + +wasmFailValidateText('(module (func (br 1)))', DEPTH_OUT_OF_BOUNDS); +wasmFailValidateText('(module (func (block (br 2))))', DEPTH_OUT_OF_BOUNDS); +wasmFailValidateText('(module (func (loop (br 2))))', DEPTH_OUT_OF_BOUNDS); +wasmFailValidateText('(module (func (if (i32.const 0) (br 2))))', DEPTH_OUT_OF_BOUNDS); +wasmFailValidateText('(module (func (if (i32.const 0) (br 1) (br 2))))', DEPTH_OUT_OF_BOUNDS); +wasmFailValidateText('(module (func (if (i32.const 0) (br 2) (br 1))))', DEPTH_OUT_OF_BOUNDS); + +wasmFailValidateText('(module (func (br_if 1 (i32.const 0))))', DEPTH_OUT_OF_BOUNDS); +wasmFailValidateText('(module (func (block (br_if 2 (i32.const 0)))))', DEPTH_OUT_OF_BOUNDS); +wasmFailValidateText('(module (func (loop (br_if 2 (i32.const 0)))))', DEPTH_OUT_OF_BOUNDS); + +wasmFailValidateText(`(module (func (result i32) + (block + (if + (br 0) + (i32.const 0) + (i32.const 2) + ) + ) +) (export "" 0))`, mismatchError("void", "i32")); + +wasmFullPass(`(module (func (block $out (br_if $out (br 0)))) (export "run" 0))`, undefined); + +wasmFullPass('(module (func (br 0)) (export "run" 0))', undefined); +wasmFullPass('(module (func (block (br 0))) (export "run" 0))', undefined); +wasmFullPass('(module (func (block $l (br $l))) (export "run" 0))', undefined); + +wasmFullPass('(module (func (block (block (br 1)))) (export "run" 0))', undefined); +wasmFullPass('(module (func (block $l (block (br $l)))) (export "run" 0))', undefined); + +wasmFullPass('(module (func (block $l (block $m (br $l)))) (export "run" 0))', undefined); +wasmFullPass('(module (func (block $l (block $m (br $m)))) (export "run" 0))', undefined); + +wasmFullPass(`(module (func (result i32) + (block + (br 0) + (return (i32.const 0)) + ) + (return (i32.const 1)) +) (export "run" 0))`, 1); + +wasmFullPass(`(module (func (result i32) + (block + (block + (br 0) + (return (i32.const 0)) + ) + (return (i32.const 1)) + ) + (return (i32.const 2)) +) (export "run" 0))`, 1); + +wasmFullPass(`(module (func (result i32) + (block $outer + (block $inner + (br $inner) + (return (i32.const 0)) + ) + (return (i32.const 1)) + ) + (return (i32.const 2)) +) (export "run" 0))`, 1); + +var notcalled = false; +var called = false; +var imports = {"": { + notcalled() {notcalled = true}, + called() {called = true} +}}; +wasmFullPass(`(module +(import "" "notcalled") +(import "" "called") +(func + (block + (return (br 0)) + (call 0) + ) + (call 1) +) (export "run" 2))`, undefined, imports); +assertEq(notcalled, false); +assertEq(called, true); + +wasmFullPass(`(module (func + (block + (i32.add + (i32.const 0) + (return (br 0)) + ) + ) + (return) +) (export "run" 0))`, undefined); + +wasmFullPass(`(module (func (result i32) + (block + (if + (i32.const 1) + (br 0) + (return (i32.const 0)) + ) + ) + (return (i32.const 1)) +) (export "run" 0))`, 1); + +wasmFullPass('(module (func (br_if 0 (i32.const 1))) (export "run" 0))', undefined); +wasmFullPass('(module (func (br_if 0 (i32.const 0))) (export "run" 0))', undefined); +wasmFullPass('(module (func (block (br_if 0 (i32.const 1)))) (export "run" 0))', undefined); +wasmFullPass('(module (func (block (br_if 0 (i32.const 0)))) (export "run" 0))', undefined); +wasmFullPass('(module (func (block $l (br_if $l (i32.const 1)))) (export "run" 0))', undefined); + +var isNonZero = wasmEvalText(`(module (func (result i32) (param i32) + (block + (br_if 0 (get_local 0)) + (return (i32.const 0)) + ) + (return (i32.const 1)) +) (export "" 0))`).exports[""]; + +assertEq(isNonZero(0), 0); +assertEq(isNonZero(1), 1); +assertEq(isNonZero(-1), 1); + +// branches with values +// br/br_if and block +wasmFailValidateText('(module (func (result i32) (br 0)))', /popping value from empty stack/); +wasmFailValidateText('(module (func (result i32) (br 0 (f32.const 42))))', mismatchError("f32", "i32")); +wasmFailValidateText('(module (func (result i32) (block (br 0))))', mismatchError("void", "i32")); +wasmFailValidateText('(module (func (result i32) (block f32 (br 0 (f32.const 42)))))', mismatchError("f32", "i32")); + +wasmFailValidateText(`(module (func (result i32) (param i32) (block (if i32 (get_local 0) (br 0 (i32.const 42))))) (export "" 0))`, /if without else with a result value/); +wasmFailValidateText(`(module (func (result i32) (param i32) (block i32 (if (get_local 0) (drop (i32.const 42))) (br 0 (f32.const 42)))) (export "" 0))`, mismatchError("f32", "i32")); + +wasmFullPass('(module (func (result i32) (br 0 (i32.const 42)) (i32.const 13)) (export "run" 0))', 42); +wasmFullPass('(module (func (result i32) (block i32 (br 0 (i32.const 42)) (i32.const 13))) (export "run" 0))', 42); + +wasmFailValidateText('(module (func) (func (block i32 (br 0 (call 0)) (i32.const 13))) (export "" 0))', /popping value from empty stack/); +wasmFailValidateText('(module (func) (func (block i32 (br_if 0 (call 0) (i32.const 1)) (i32.const 13))) (export "" 0))', /popping value from empty stack/); + +var f = wasmEvalText(`(module (func (result i32) (param i32) (block i32 (if (get_local 0) (drop (i32.const 42))) (i32.const 43))) (export "" 0))`).exports[""]; +assertEq(f(0), 43); +assertEq(f(1), 43); + +wasmFailValidateText(`(module (func (result i32) (param i32) (block i32 (if i32 (get_local 0) (br 0 (i32.const 42))) (i32.const 43))) (export "" 0))`, /if without else with a result value/); + +var f = wasmEvalText(`(module (func (result i32) (param i32) (block i32 (if (get_local 0) (br 1 (i32.const 42))) (i32.const 43))) (export "" 0))`).exports[""]; +assertEq(f(0), 43); +assertEq(f(1), 42); + +wasmFailValidateText(`(module (func (result i32) (param i32) (block (br_if 0 (i32.const 42) (get_local 0)) (i32.const 43))) (export "" 0))`, /unused values not explicitly dropped by end of block/); + +var f = wasmEvalText(`(module (func (result i32) (param i32) (block i32 (drop (br_if 0 (i32.const 42) (get_local 0))) (i32.const 43))) (export "" 0))`).exports[""]; +assertEq(f(0), 43); +assertEq(f(1), 42); + +var f = wasmEvalText(`(module (func (result i32) (param i32) (block i32 (if (get_local 0) (drop (i32.const 42))) (br 0 (i32.const 43)))) (export "" 0))`).exports[""]; +assertEq(f(0), 43); +assertEq(f(1), 43); + +wasmFailValidateText(`(module (func (result i32) (param i32) (block i32 (if i32 (get_local 0) (br 0 (i32.const 42))) (br 0 (i32.const 43)))) (export "" 0))`, /if without else with a result value/); + +var f = wasmEvalText(`(module (func (result i32) (param i32) (if (get_local 0) (br 1 (i32.const 42))) (br 0 (i32.const 43))) (export "" 0))`).exports[""]; +assertEq(f(0), 43); +assertEq(f(1), 42); + +var f = wasmEvalText(`(module (func (result i32) (param i32) (block i32 (if (get_local 0) (br 1 (i32.const 42))) (br 0 (i32.const 43)))) (export "" 0))`).exports[""]; +assertEq(f(0), 43); +assertEq(f(1), 42); + +var f = wasmEvalText(`(module (func (result i32) (param i32) (br_if 0 (i32.const 42) (get_local 0)) (br 0 (i32.const 43))) (export "" 0))`).exports[""]; +assertEq(f(0), 43); +assertEq(f(1), 42); + +var f = wasmEvalText(`(module (func (result i32) (param i32) (block i32 (br_if 0 (i32.const 42) (get_local 0)) (br 0 (i32.const 43)))) (export "" 0))`).exports[""]; +assertEq(f(0), 43); +assertEq(f(1), 42); + +var f = wasmEvalText(`(module (func (param i32) (result i32) (i32.add (i32.const 1) (block i32 (if (get_local 0) (drop (i32.const 99))) (i32.const -1)))) (export "" 0))`).exports[""]; +assertEq(f(0), 0); +assertEq(f(1), 0); + +wasmFailValidateText(`(module (func (param i32) (result i32) (i32.add (i32.const 1) (block i32 (if i32 (get_local 0) (br 0 (i32.const 99))) (i32.const -1)))) (export "" 0))`, /if without else with a result value/); + +var f = wasmEvalText(`(module (func (param i32) (result i32) (i32.add (i32.const 1) (block i32 (if (get_local 0) (br 1 (i32.const 99))) (i32.const -1)))) (export "" 0))`).exports[""]; +assertEq(f(0), 0); +assertEq(f(1), 100); + +wasmFailValidateText(`(module (func (param i32) (result i32) (i32.add (i32.const 1) (block (br_if 0 (i32.const 99) (get_local 0)) (i32.const -1)))) (export "" 0))`, /unused values not explicitly dropped by end of block/); + +var f = wasmEvalText(`(module (func (param i32) (result i32) (i32.add (i32.const 1) (block i32 (drop (br_if 0 (i32.const 99) (get_local 0))) (i32.const -1)))) (export "" 0))`).exports[""]; +assertEq(f(0), 0); +assertEq(f(1), 100); + +wasmFullPass(`(module (func (result i32) (block i32 (br 0 (return (i32.const 42))) (i32.const 0))) (export "run" 0))`, 42); +wasmFullPass(`(module (func (result i32) (block i32 (return (br 0 (i32.const 42))))) (export "run" 0))`, 42); +wasmFullPass(`(module (func (result i32) (block i32 (return (br 0 (i32.const 42))) (i32.const 0))) (export "run" 0))`, 42); + +wasmFullPass(`(module (func (result f32) (drop (block i32 (br 0 (i32.const 0)))) (block f32 (br 0 (f32.const 42)))) (export "run" 0))`, 42); + +var called = 0; +var imports = { + sideEffects: { + ifTrue(x) {assertEq(x, 13); called++;}, + ifFalse(x) {assertEq(x, 37); called--;} + } +} +var f = wasmEvalText(`(module + (import "sideEffects" "ifTrue" (param i32)) + (import "sideEffects" "ifFalse" (param i32)) + (func + (param i32) (result i32) + (block $outer + (if + (get_local 0) + (block (call 0 (i32.const 13)) (br $outer)) + ) + (if + (i32.eqz (get_local 0)) + (block (call 1 (i32.const 37)) (br $outer)) + ) + ) + (i32.const 42) + ) +(export "" 2))`, imports).exports[""]; +assertEq(f(0), 42); +assertEq(called, -1); +assertEq(f(1), 42); +assertEq(called, 0); + +// br/br_if and loop +wasmFullPass(`(module (func (param i32) (result i32) (loop $out $in i32 (br $out (get_local 0)))) (export "run" 0))`, 1, {}, 1); +wasmFullPass(`(module (func (param i32) (result i32) (loop $in (br 1 (get_local 0)))) (export "run" 0))`, 1, {}, 1); +wasmFullPass(`(module (func (param i32) (result i32) (block $out i32 (loop $in i32 (br $out (get_local 0))))) (export "run" 0))`, 1, {}, 1); + +wasmFailValidateText(`(module (func (param i32) (result i32) + (loop $out $in + (if (get_local 0) (br $in (i32.const 1))) + (if (get_local 0) (br $in (f32.const 2))) + (if (get_local 0) (br $in (f64.const 3))) + (if (get_local 0) (br $in)) + (i32.const 7) + ) +) (export "" 0))`, /unused values not explicitly dropped by end of block/); + +wasmFullPass(`(module + (func + (result i32) + (local i32) + (block $out i32 + (loop $in + (set_local 0 (i32.add (get_local 0) (i32.const 1))) + (if (i32.ge_s (get_local 0) (i32.const 7)) (br $out (get_local 0))) + (br $in) + ) + ) + ) +(export "run" 0))`, 7); + +wasmFullPass(`(module + (func + (result i32) + (local i32) + (block $out i32 + (loop $in + (set_local 0 (i32.add (get_local 0) (i32.const 1))) + (br_if $out (get_local 0) (i32.ge_s (get_local 0) (i32.const 7))) + (br $in) + ) + ) + ) +(export "run" 0))`, 7); + +// ---------------------------------------------------------------------------- +// loop + +wasmFailValidateText('(module (func (loop (br 2))))', DEPTH_OUT_OF_BOUNDS); + +wasmFailValidateText('(module (func (result i32) (drop (loop (i32.const 2))) (i32.const 1)) (export "" 0))', /unused values not explicitly dropped by end of block/); +wasmFullPass('(module (func (loop)) (export "run" 0))', undefined); +wasmFullPass('(module (func (result i32) (loop (drop (i32.const 2))) (i32.const 1)) (export "run" 0))', 1); + +wasmFullPass('(module (func (loop (br 1))) (export "run" 0))', undefined); +wasmFullPass('(module (func (loop $a (br 1))) (export "run" 0))', undefined); +wasmFullPass('(module (func (loop $a (br_if $a (i32.const 0)))) (export "run" 0))', undefined); +wasmFullPass('(module (func (loop $a $b (br $a))) (export "run" 0))', undefined); +wasmFullPass('(module (func (block $a (loop $b (br $a)))) (export "run" 0))', undefined); +wasmFullPass('(module (func (result i32) (loop i32 (i32.const 1))) (export "run" 0))', 1); + +wasmFullPass(`(module (func (result i32) (local i32) + (loop + $break $continue + (if + (i32.gt_u (get_local 0) (i32.const 5)) + (br $break) + ) + (set_local 0 (i32.add (get_local 0) (i32.const 1))) + (br $continue) + ) + (return (get_local 0)) +) (export "run" 0))`, 6); + +wasmFullPass(`(module (func (result i32) (local i32) + (block + $break + (loop + $continue + (if + (i32.gt_u (get_local 0) (i32.const 5)) + (br $break) + ) + (set_local 0 (i32.add (get_local 0) (i32.const 1))) + (br $continue) + ) + ) + (return (get_local 0)) +) (export "run" 0))`, 6); + +wasmFullPass(`(module (func (result i32) (local i32) + (loop + $break $continue + (br_if + $break + (i32.gt_u (get_local 0) (i32.const 5)) + ) + (set_local 0 (i32.add (get_local 0) (i32.const 1))) + (br $continue) + ) + (return (get_local 0)) +) (export "run" 0))`, 6); + +wasmFullPass(`(module (func (result i32) (local i32) + (block + $break + (loop + $continue + (br_if + $break + (i32.gt_u (get_local 0) (i32.const 5)) + ) + (set_local 0 (i32.add (get_local 0) (i32.const 1))) + (br $continue) + ) + ) + (return (get_local 0)) +) (export "run" 0))`, 6); + +wasmFullPass(`(module (func (result i32) (local i32) + (loop + $break $continue + (set_local 0 (i32.add (get_local 0) (i32.const 1))) + (br_if + $continue + (i32.le_u (get_local 0) (i32.const 5)) + ) + ) + (return (get_local 0)) +) (export "run" 0))`, 6); + +wasmFullPass(`(module (func (result i32) (local i32) + (block + $break + (loop + $continue + (set_local 0 (i32.add (get_local 0) (i32.const 1))) + (br_if + $continue + (i32.le_u (get_local 0) (i32.const 5)) + ) + ) + ) + (return (get_local 0)) +) (export "run" 0))`, 6); + +wasmFullPass(`(module (func (result i32) (local i32) + (loop + $break $continue + (br_if + $break + (i32.gt_u (get_local 0) (i32.const 5)) + ) + (set_local 0 (i32.add (get_local 0) (i32.const 1))) + (loop + (br $continue) + ) + (return (i32.const 42)) + ) + (return (get_local 0)) +) (export "run" 0))`, 6); + +wasmFullPass(`(module (func (result i32) (local i32) + (block + $break + (loop + $continue + (br_if + $break + (i32.gt_u (get_local 0) (i32.const 5)) + ) + (set_local 0 (i32.add (get_local 0) (i32.const 1))) + (loop + (br $continue) + ) + (return (i32.const 42)) + ) + ) + (return (get_local 0)) +) (export "run" 0))`, 6); + +wasmFullPass(`(module (func (result i32) (local i32) + (loop + $break $continue + (set_local 0 (i32.add (get_local 0) (i32.const 1))) + (loop + (br_if + $continue + (i32.le_u (get_local 0) (i32.const 5)) + ) + ) + (br $break) + ) + (return (get_local 0)) +) (export "run" 0))`, 6); + +wasmFullPass(`(module (func (result i32) (local i32) + (block + $break + (loop + $continue + (set_local 0 (i32.add (get_local 0) (i32.const 1))) + (loop + (br_if + $continue + (i32.le_u (get_local 0) (i32.const 5)) + ) + ) + (br $break) + ) + ) + (return (get_local 0)) +) (export "run" 0))`, 6); + +// ---------------------------------------------------------------------------- +// br_table + +wasmFailValidateText('(module (func (br_table 1 (i32.const 0))))', DEPTH_OUT_OF_BOUNDS); +wasmFailValidateText('(module (func (br_table 1 0 (i32.const 0))))', DEPTH_OUT_OF_BOUNDS); +wasmFailValidateText('(module (func (br_table 0 1 (i32.const 0))))', DEPTH_OUT_OF_BOUNDS); +wasmFailValidateText('(module (func (block (br_table 2 0 (i32.const 0)))))', DEPTH_OUT_OF_BOUNDS); +wasmFailValidateText('(module (func (block (br_table 0 2 (i32.const 0)))))', DEPTH_OUT_OF_BOUNDS); +wasmFailValidateText('(module (func (block (br_table 0 (f32.const 0)))))', mismatchError("f32", "i32")); +wasmFailValidateText('(module (func (loop (br_table 2 0 (i32.const 0)))))', DEPTH_OUT_OF_BOUNDS); +wasmFailValidateText('(module (func (loop (br_table 0 2 (i32.const 0)))))', DEPTH_OUT_OF_BOUNDS); +wasmFailValidateText('(module (func (loop (br_table 0 (f32.const 0)))))', mismatchError("f32", "i32")); + +wasmFullPass(`(module (func (result i32) (param i32) + (block $default + (br_table $default (get_local 0)) + (return (i32.const 0)) + ) + (return (i32.const 1)) +) (export "run" 0))`, 1); + +wasmFullPass(`(module (func (result i32) (param i32) + (block $default + (br_table $default (return (i32.const 1))) + (return (i32.const 0)) + ) + (return (i32.const 2)) +) (export "run" 0))`, 1); + +wasmFullPass(`(module (func (result i32) (param i32) + (block $outer + (block $inner + (br_table $inner (get_local 0)) + (return (i32.const 0)) + ) + (return (i32.const 1)) + ) + (return (i32.const 2)) +) (export "run" 0))`, 1); + +var f = wasmEvalText(`(module (func (result i32) (param i32) + (block $0 + (block $1 + (block $2 + (block $default + (br_table $0 $1 $2 $default (get_local 0)) + ) + (return (i32.const -1)) + ) + (return (i32.const 2)) + ) + ) + (return (i32.const 0)) +) (export "" 0))`).exports[""]; + +assertEq(f(-2), -1); +assertEq(f(-1), -1); +assertEq(f(0), 0); +assertEq(f(1), 0); +assertEq(f(2), 2); +assertEq(f(3), -1); + +// br_table with values +wasmFailValidateText('(module (func (result i32) (block (br_table 0 (i32.const 0)))))', mismatchError("void", "i32")); +wasmFailValidateText('(module (func (result i32) (block i32 (br_table 0 (f32.const 0) (i32.const 0)))))', mismatchError("f32", "i32")); + +wasmFailValidateText(`(module + (func + (result i32) + (block $outer f32 + (block $inner f32 + (br_table $outer $inner (f32.const 13.37) (i32.const 1)) + ) + (br $outer (i32.const 42)) + ) + ) +(export "" 0))`, mismatchError("i32", "f32")); + +wasmFullPass(`(module (func (result i32) (block $default i32 (br_table $default (i32.const 42) (i32.const 1)))) (export "run" 0))`, 42); + +var f = wasmEvalText(`(module (func (param i32) (result i32) + (i32.add + (block $1 i32 + (drop (block $0 i32 + (drop (block $default i32 + (br_table $0 $1 $default (get_local 0) (get_local 0)) + )) + (tee_local 0 (i32.mul (i32.const 2) (get_local 0))) + )) + (tee_local 0 (i32.add (i32.const 4) (get_local 0))) + ) + (i32.const 1) + ) + ) (export "" 0))`).exports[""]; + +assertEq(f(0), 5); +assertEq(f(1), 2); +assertEq(f(2), 9); +assertEq(f(3), 11); +assertEq(f(4), 13); + +// ---------------------------------------------------------------------------- +// unreachable + +const UNREACHABLE = /unreachable/; +assertErrorMessage(wasmEvalText(`(module (func (unreachable)) (export "" 0))`).exports[""], RuntimeError, UNREACHABLE); +assertErrorMessage(wasmEvalText(`(module (func (if (unreachable) (i32.const 0))) (export "" 0))`).exports[""], RuntimeError, UNREACHABLE); +assertErrorMessage(wasmEvalText(`(module (func (block (br_if 0 (unreachable)))) (export "" 0))`).exports[""], RuntimeError, UNREACHABLE); +assertErrorMessage(wasmEvalText(`(module (func (block (br_table 0 (unreachable)))) (export "" 0))`).exports[""], RuntimeError, UNREACHABLE); +assertErrorMessage(wasmEvalText(`(module (func (result i32) (i32.add (i32.const 0) (unreachable))) (export "" 0))`).exports[""], RuntimeError, UNREACHABLE); |