litmus4.js (1646B)
1 // Mutually recursive functions implement a multi-entry loop using indirect tail 2 // calls, 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 (table 2 2 funcref) 14 (elem (i32.const 0) $even $odd) 15 (type $even_t (func (param i32) (result i32))) 16 (type $odd_t (func (param i32 i32) (result i32))) 17 (tag $t) 18 19 (func $odd (export "odd") (param $n i32) (param $dummy i32) (result i32) 20 try (result i32) 21 (if (result i32) (i32.eqz (local.get $n)) 22 (then (return (i32.const 0))) 23 (else (return_call_indirect (type $even_t) (i32.sub (local.get $n) (i32.const 1)) 24 (i32.const 0)))) 25 catch_all 26 unreachable 27 end) 28 29 (func $even (export "even") (param $n i32) (result i32) 30 (if (result i32) (i32.eqz (local.get $n)) 31 (then (throw $t)) 32 (else (return_call_indirect (type $odd_t) (i32.sub (local.get $n) (i32.const 1)) (i32.const 33) 33 (i32.const 1))))) 34 ) 35 `); 36 37 assertErrorMessage(() => ins.exports.even(TailCallIterations), WebAssembly.Exception, /.*/); 38 assertEq(ins.exports.odd(TailCallIterations, 33), 0); 39 40 assertEq(ins.exports.even(TailCallIterations+1), 0); 41 assertErrorMessage(() => ins.exports.odd(TailCallIterations+1, 33), WebAssembly.Exception, /.*/);