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);