litmus3.js (1355B)
1 // Mutually recursive functions implement a multi-entry loop using tail calls, 2 // with exception handling. 3 // 4 // The functions do not have the same signatures, so if all arguments are stack 5 // arguments then these use different amounts of stack space. 6 // 7 // The "even" function will throw when the input is zero, so when an exception 8 // bubbles out of return_call it must not be caught by the exception handler in 9 // "odd", but must instead be delegated to the caller, which is JS code. 10 11 var ins = wasmEvalText(` 12 (module 13 (tag $t) 14 (func $odd (export "odd") (param $n i32) (param $dummy i32) (result i32) 15 try (result i32) 16 (if (result i32) (i32.eqz (local.get $n)) 17 (then (return (i32.const 0))) 18 (else (return_call $even (i32.sub (local.get $n) (i32.const 1))))) 19 catch_all 20 unreachable 21 end) 22 23 (func $even (export "even") (param $n i32) (result i32) 24 (if (result i32) (i32.eqz (local.get $n)) 25 (then (throw $t)) 26 (else (return_call $odd (i32.sub (local.get $n) (i32.const 1)) (i32.const 33))))) 27 ) 28 `); 29 30 assertErrorMessage(() => ins.exports.even(TailCallIterations), WebAssembly.Exception, /.*/); 31 assertEq(ins.exports.odd(TailCallIterations, 33), 0); 32 33 assertEq(ins.exports.even(TailCallIterations+1), 0); 34 assertErrorMessage(() => ins.exports.odd(TailCallIterations+1, 33), WebAssembly.Exception, /.*/);