litmus10.js (2606B)
1 // Tail-call litmus test with multiple results 2 // 3 // Mutually recursive functions implement a multi-entry loop using indirect 4 // cross-module tail calls. The functions do not have the same signatures, so 5 // if all arguments are stack arguments then these use different amounts of 6 // stack space. 7 // 8 // Cross-module mutual recursion must be set up by JS, which is a bit of hair. 9 // But this should not destroy the ability to tail-call. 10 // 11 // The mutable globals accessed after the call are there to attempt to ensure 12 // that the correct instance is restored after the chain of tail calls. 13 14 var table = new WebAssembly.Table({initial:2, maximum:2, element:"funcref"}) 15 16 var odd_cookie = 24680246; 17 var oddins = wasmEvalText(` 18 (module 19 (table (import "" "table") 2 2 funcref) 20 (type $even_t (func (param i32) (result i32 i32 i32))) 21 (global $glob (export "g") (mut i32) (i32.const ${odd_cookie})) 22 23 (func $odd_entry (export "odd_entry") (param $n i32) (result i32 i32 i32 i32) 24 (call $odd (local.get $n) (i32.const 86)) 25 (global.get $glob)) 26 27 (func $odd (export "odd") (param $n i32) (param $dummy i32) (result i32 i32 i32) 28 (if (result i32 i32 i32) (i32.eqz (local.get $n)) 29 (then (return (i32.const 0) (i32.const 32769) (i32.const -37))) 30 (else (return_call_indirect (type $even_t) (i32.sub (local.get $n) (i32.const 1)) (i32.const 0))))))`, 31 {"":{table}}); 32 33 var even_cookie = 12345678; 34 var evenins = wasmEvalText(` 35 (module 36 (table (import "" "table") 2 2 funcref) 37 (type $odd_t (func (param i32 i32) (result i32 i32 i32))) 38 (global $glob (export "g") (mut i32) (i32.const ${even_cookie})) 39 40 (func $even_entry (export "even_entry") (param $n i32) (result i32 i32 i32 i32) 41 (call $even (local.get $n)) 42 (global.get $glob)) 43 44 (func $even (export "even") (param $n i32) (result i32 i32 i32) 45 (if (result i32 i32 i32) (i32.eqz (local.get $n)) 46 (then (return (i32.const 1) (i32.const -17) (i32.const 44021))) 47 (else (return_call_indirect (type $odd_t) (i32.sub (local.get $n) (i32.const 1)) (i32.const 33) (i32.const 1))))))`, 48 {"":{table}}); 49 50 51 table.set(0, evenins.exports.even); 52 table.set(1, oddins.exports.odd); 53 54 assertSame(evenins.exports.even_entry(TailCallIterations), [1, -17, 44021, even_cookie]); 55 assertSame(oddins.exports.odd_entry(TailCallIterations+1, 33), [1, -17, 44021, odd_cookie]); 56 assertSame(evenins.exports.even_entry(TailCallIterations+1), [0, 32769, -37, even_cookie]); 57 assertSame(oddins.exports.odd_entry(TailCallIterations, 33), [0, 32769, -37, odd_cookie]);