Tail Calls, Typed Function References and Stack Switching

25.1 Tail Calls (Wasm 3.0)

return_call, return_call_indirect, return_call_ref. Essential for functional languages (Scheme, Haskell, OCaml), interpreters, and continuation-passing style.

(func $loop_sum (param $n i64) (param $acc i64) (result i64)
  (if (result i64) (i64.eqz (local.get $n))
    (then (local.get $acc))
    (else (return_call $loop_sum                    ;; constant stack space
            (i64.sub (local.get $n) (i64.const 1))
            (i64.add (local.get $acc) (local.get $n))))))

25.2 Typed Function References

Typed (non-nullable) function references with call_ref, ref.as_non_null, br_on_null, and br_on_non_null. Faster than call_indirect (no table lookup or signature check), and the foundation for WasmGC.

(module
  (type $i2i (func (param i32) (result i32)))
  (func $inc (type $i2i) (i32.add (local.get 0) (i32.const 1)))
  (elem declare func $inc)
  (func (export "apply_twice") (param $x i32) (result i32)
    (local $f (ref $i2i))
    (local.set $f (ref.func $inc))
    (call_ref $i2i (call_ref $i2i (local.get $x) (local.get $f)) (local.get $f))))

25.3 Stack Switching (Proposal)

Lets Wasm suspend and resume computations (cont.new, resume, suspend). It enables coroutines, generators, async/await, green threads, and effect handlers without whole-program transforms like Asyncify. It's in active standardization (phase 3); JSPI (Module 28) covers the JS-promise use case already.