Source code
Revision control
Copy as Markdown
Other Tools
// |jit-test| skip-if: !wasmStackSwitchingEnabled()
// Test resume lifecycle: null continuations, double-resume, consumed continuations.
// Resume a null continuation traps.
{
let { run } = wasmEvalText(`(module
(type $ft (func))
(type $ct (cont $ft))
(func (export "run")
(ref.null $ct)
resume $ct
)
)`).exports;
assertErrorMessage(() => run(), WebAssembly.RuntimeError, /null/);
}
// Resume a completed continuation traps.
{
let { run } = wasmEvalText(`(module
(type $ft (func))
(type $ct (cont $ft))
(global $k (mut (ref null $ct)) (ref.null $ct))
(func $f (type $ft))
(elem declare func $f)
(func (export "run")
(global.set $k (cont.new $ct (ref.func $f)))
(global.get $k)
resume $ct
(global.get $k)
resume $ct
)
)`).exports;
assertErrorMessage(() => run(), WebAssembly.RuntimeError, /null/);
}
// Resume a continuation consumed by a prior resume traps.
{
let { run } = wasmEvalText(`(module
(type $ft (func))
(type $ct (cont $ft))
(tag $tag)
(global $k1 (mut (ref null $ct)) (ref.null $ct))
(global $k2 (mut (ref null $ct)) (ref.null $ct))
(func $f (type $ft)
suspend $tag
)
(elem declare func $f)
(func (export "run")
(local $cont (ref null $ct))
(local.set $cont (cont.new $ct (ref.func $f)))
(global.set $k1 (local.get $cont))
(global.set $k2 (local.get $cont))
(block (result (ref $ct))
(global.get $k1)
resume $ct (on $tag 0)
unreachable
)
(global.set $k1)
(global.get $k2)
resume $ct
)
)`).exports;
assertErrorMessage(() => run(), WebAssembly.RuntimeError, /null/);
}
// Funcref locals survive GC across suspension.
{
gczeal(14, 1);
let { run, getResult } = wasmEvalText(`(module
(type $ft (func))
(type $ct (cont $ft))
(type $adder (func (param i32 i32) (result i32)))
(tag $tag)
(global $k (mut (ref null $ct)) (ref.null $ct))
(global $r (mut i32) (i32.const 0))
(func $add (type $adder) (param i32 i32) (result i32)
(i32.add (local.get 0) (local.get 1))
)
(func $f (type $ft)
(local $fn (ref null $adder))
(local.set $fn (ref.func $add))
suspend $tag
(global.set $r
(call_ref $adder (i32.const 100) (i32.const 200) (local.get $fn)))
)
(elem declare func $f $add)
(func (export "run")
(global.set $k (cont.new $ct (ref.func $f)))
(block (result (ref $ct))
(global.get $k)
resume $ct (on $tag 0)
unreachable
)
(global.set $k)
(global.get $k)
resume $ct
)
(func (export "getResult") (result i32) global.get $r)
)`).exports;
run();
assertEq(getResult(), 300);
}