Path: blob/main/tests/misc_testsuite/component-model/async/trap-if-block-and-sync.wast
2450 views
;;! component_model_async = true
;;! component_model_threading = true
;;! reference_types = true
;;! gc_types = true
;;! multi_memory = true
;; TODO: remove this in favor of the upstream version once
;; https://github.com/WebAssembly/component-model/pull/578 has been merged.
;; The $Tester component has two nested components $C and $D, where $D imports
;; and calls $C. $C contains utilities used by $D to perform all the tests.
;; Most of the tests trap, $Tester exports 1 function per test and a fresh
;; $Tester is created to run each test.
(component definition $Tester
(component $C
(core module $Memory (memory (export "mem") 1))
(core instance $memory (instantiate $Memory))
(core module $CM
(import "" "mem" (memory 1))
(import "" "waitable.join" (func $waitable.join (param i32 i32)))
(import "" "waitable-set.new" (func $waitable-set.new (result i32)))
(import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32)))
(import "" "future.new" (func $future.new (result i64)))
(import "" "future.read" (func $future.read (param i32 i32) (result i32)))
(import "" "future.write" (func $future.write (param i32 i32) (result i32)))
;; $ws is waited on by 'blocker' and added to by 'unblocker'
(global $ws (mut i32) (i32.const 0))
(func $start (global.set $ws (call $waitable-set.new)))
(start $start)
(func (export "blocker") (result i32)
;; wait on $ws, which is initially empty, but will be populated with
;; a completed future when "unblocker" synchronously barges in.
(local $ret i32)
(local.set $ret (call $waitable-set.wait (global.get $ws) (i32.const 0)))
(if (i32.ne (i32.const 4 (; FUTURE_READ ;)) (local.get $ret))
(then unreachable))
(if (i32.ne (i32.const 0 (; COMPLETED ;)) (i32.load (i32.const 4)))
(then unreachable))
(i32.const 42)
)
(func (export "unblocker") (result i32)
(local $ret i32) (local $ret64 i64)
(local $futr i32) (local $futw i32)
;; create read/write futures that will be used to unblock 'blocker'
(local.set $ret64 (call $future.new))
(local.set $futr (i32.wrap_i64 (local.get $ret64)))
(local.set $futw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32))))
;; perform a future.read which will block, and add this future to the waitable-set
;; being waited on by 'blocker'
(local.set $ret (call $future.read (local.get $futr) (i32.const 0xdeadbeef)))
(if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret))
(then unreachable))
(call $waitable.join (local.get $futr) (global.get $ws))
;; perform a future.write which will rendezvous with the write and complete
(local.set $ret (call $future.write (local.get $futw) (i32.const 0xdeadbeef)))
(if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret))
(then unreachable))
(i32.const 43)
)
(func (export "sync-async-func")
unreachable
)
(func (export "async-async-func") (result i32)
unreachable
)
(func (export "async-async-func-cb") (param i32 i32 i32) (result i32)
unreachable
)
)
(type $FT (future))
(canon waitable.join (core func $waitable.join))
(canon waitable-set.new (core func $waitable-set.new))
(canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait))
(canon future.new $FT (core func $future.new))
(canon future.read $FT async (core func $future.read))
(canon future.write $FT async (core func $future.write))
(core instance $cm (instantiate $CM (with "" (instance
(export "mem" (memory $memory "mem"))
(export "waitable.join" (func $waitable.join))
(export "waitable-set.new" (func $waitable-set.new))
(export "waitable-set.wait" (func $waitable-set.wait))
(export "future.new" (func $future.new))
(export "future.read" (func $future.read))
(export "future.write" (func $future.write))
))))
(func (export "blocker") async (result u32) (canon lift (core func $cm "blocker")))
(func (export "unblocker") (result u32) (canon lift (core func $cm "unblocker")))
(func (export "sync-async-func") async (canon lift (core func $cm "sync-async-func")))
(func (export "async-async-func") async (canon lift (core func $cm "async-async-func") async (callback (func $cm "async-async-func-cb"))))
)
(component $D
(import "c" (instance $c
(export "blocker" (func async (result u32)))
(export "unblocker" (func (result u32)))
(export "sync-async-func" (func async))
(export "async-async-func" (func async))
))
(core module $Memory (memory (export "mem") 1))
(core instance $memory (instantiate $Memory))
(core module $Core
(import "" "mem" (memory 1))
(import "" "task.return" (func $task.return (param i32)))
(import "" "subtask.cancel" (func $subtask.cancel (param i32) (result i32)))
(import "" "thread.yield" (func $thread.yield (result i32)))
(import "" "thread.suspend" (func $thread.suspend (result i32)))
(import "" "waitable.join" (func $waitable.join (param i32 i32)))
(import "" "waitable-set.new" (func $waitable-set.new (result i32)))
(import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32)))
(import "" "waitable-set.poll" (func $waitable-set.poll (param i32 i32) (result i32)))
(import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32)))
(import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32)))
(import "" "future.read" (func $future.read (param i32 i32) (result i32)))
(import "" "future.write" (func $future.write (param i32 i32) (result i32)))
(import "" "stream.cancel-read" (func $stream.cancel-read (param i32) (result i32)))
(import "" "stream.cancel-write" (func $stream.cancel-write (param i32) (result i32)))
(import "" "future.cancel-read" (func $future.cancel-read (param i32) (result i32)))
(import "" "future.cancel-write" (func $future.cancel-write (param i32) (result i32)))
(import "" "blocker" (func $blocker (param i32) (result i32)))
(import "" "unblocker" (func $unblocker (result i32)))
(import "" "await-sync-async-func" (func $await-sync-async-func))
(import "" "await-async-async-func" (func $await-async-async-func))
(func (export "sync-barges-in") (result i32)
(local $ret i32) (local $retp1 i32) (local $retp2 i32)
(local $subtask i32) (local $ws i32) (local $event_code i32)
(local.set $retp1 (i32.const 8))
(local.set $retp2 (i32.const 12))
;; call $blocker which will block during a synchronous function.
(local.set $ret (call $blocker (local.get $retp1)))
(if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf)))
(then unreachable))
(local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4)))
;; normally calling another function would hit backpressure until
;; $blocker was done, but calling the sync-typed function $unblocker
;; barges in synchronously.
(local.set $ret (call $unblocker))
(if (i32.ne (local.get $ret) (i32.const 43))
(then unreachable))
;; now wait to confirm that $subtask was actually unblocked
(local.set $ws (call $waitable-set.new))
(call $waitable.join (local.get $subtask) (local.get $ws))
(local.set $event_code (call $waitable-set.wait (local.get $ws) (local.get $retp2)))
(if (i32.ne (i32.const 1 (; SUBTASK ;)) (local.get $event_code))
(then unreachable))
(if (i32.ne (local.get $subtask) (i32.load (local.get $retp2)))
(then unreachable))
(if (i32.ne (i32.const 2 (; RETURNED=2 ;)) (i32.load offset=4 (local.get $retp2)))
(then unreachable))
(if (i32.ne (i32.const 42) (i32.load (local.get $retp1)))
(then unreachable))
(i32.const 44)
)
(func (export "unreachable-cb") (param i32 i32 i32) (result i32)
unreachable
)
(func (export "return-42-cb") (param i32 i32 i32) (result i32)
(call $task.return (i32.const 42))
(i32.const 0 (; EXIT ;))
)
(func (export "trap-if-sync-call-async1")
(call $await-sync-async-func)
)
(func (export "trap-if-sync-call-async2")
(call $await-async-async-func)
)
(func (export "trap-if-suspend")
(call $thread.suspend)
unreachable
)
(func (export "trap-if-wait")
(call $waitable-set.wait (call $waitable-set.new) (i32.const 0xdeadbeef))
unreachable
)
(func (export "trap-if-wait-cb") (result i32)
(i32.or
(i32.const 2 (; WAIT ;))
(i32.shl (call $waitable-set.new) (i32.const 4)))
)
(func (export "trap-if-poll")
(call $waitable-set.poll (call $waitable-set.new) (i32.const 0xdeadbeef))
unreachable
)
(func (export "trap-if-poll-cb") (result i32)
(i32.or
(i32.const 3 (; POLL ;))
(i32.shl (call $waitable-set.new) (i32.const 4)))
)
(func (export "yield-is-fine") (result i32)
(drop (call $thread.yield))
(i32.const 42)
)
(func (export "yield-is-fine-cb") (result i32)
(i32.or
(i32.const 1 (; YIELD ;))
(i32.shl (i32.const 0xdead) (i32.const 4)))
)
(func (export "trap-if-sync-cancel")
(call $subtask.cancel (i32.const 0xdeadbeef))
unreachable
)
(func (export "trap-if-sync-stream-read")
(call $stream.read (i32.const 0xdead) (i32.const 0xbeef) (i32.const 0xdeadbeef))
unreachable
)
(func (export "trap-if-sync-stream-write")
(call $stream.write (i32.const 0xdead) (i32.const 0xbeef) (i32.const 0xdeadbeef))
unreachable
)
(func (export "trap-if-sync-future-read")
(call $future.read (i32.const 0xdead) (i32.const 0xdeadbeef))
unreachable
)
(func (export "trap-if-sync-future-write")
(call $future.write (i32.const 0xdead) (i32.const 0xdeadbeef))
unreachable
)
(func (export "trap-if-sync-stream-cancel-read")
(call $stream.cancel-read (i32.const 0xdead))
unreachable
)
(func (export "trap-if-sync-stream-cancel-write")
(call $stream.cancel-write (i32.const 0xdead))
unreachable
)
(func (export "trap-if-sync-future-cancel-read")
(call $future.cancel-read (i32.const 0xdead) (i32.const 0xdeadbeef))
unreachable
)
(func (export "trap-if-sync-future-cancel-write")
(call $future.cancel-write (i32.const 0xdead) (i32.const 0xdeadbeef))
unreachable
)
)
(type $FT (future u8))
(type $ST (stream u8))
(canon task.return (result u32) (core func $task.return))
(canon subtask.cancel (core func $subtask.cancel))
(canon thread.yield (core func $thread.yield))
(canon thread.suspend (core func $thread.suspend))
(canon waitable.join (core func $waitable.join))
(canon waitable-set.new (core func $waitable-set.new))
(canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait))
(canon waitable-set.poll (memory $memory "mem") (core func $waitable-set.poll))
(canon stream.read $ST (memory $memory "mem") (core func $stream.read))
(canon stream.write $ST (memory $memory "mem") (core func $stream.write))
(canon future.read $FT (memory $memory "mem") (core func $future.read))
(canon future.write $FT (memory $memory "mem") (core func $future.write))
(canon stream.cancel-read $ST (core func $stream.cancel-read))
(canon stream.cancel-write $ST (core func $stream.cancel-write))
(canon future.cancel-read $FT (core func $future.cancel-read))
(canon future.cancel-write $FT (core func $future.cancel-write))
(canon lower (func $c "blocker") (memory $memory "mem") async (core func $blocker'))
(canon lower (func $c "unblocker") (core func $unblocker'))
(canon lower (func $c "sync-async-func") (core func $await-sync-async-func'))
(canon lower (func $c "async-async-func") (core func $await-async-async-func'))
(core instance $core (instantiate $Core (with "" (instance
(export "mem" (memory $memory "mem"))
(export "task.return" (func $task.return))
(export "subtask.cancel" (func $subtask.cancel))
(export "thread.yield" (func $thread.yield))
(export "thread.suspend" (func $thread.suspend))
(export "waitable.join" (func $waitable.join))
(export "waitable-set.new" (func $waitable-set.new))
(export "waitable-set.wait" (func $waitable-set.wait))
(export "waitable-set.poll" (func $waitable-set.poll))
(export "stream.read" (func $stream.read))
(export "stream.write" (func $stream.write))
(export "future.read" (func $future.read))
(export "future.write" (func $future.write))
(export "stream.cancel-read" (func $stream.cancel-read))
(export "stream.cancel-write" (func $stream.cancel-write))
(export "future.cancel-read" (func $future.cancel-read))
(export "future.cancel-write" (func $future.cancel-write))
(export "blocker" (func $blocker'))
(export "unblocker" (func $unblocker'))
(export "await-sync-async-func" (func $await-sync-async-func'))
(export "await-async-async-func" (func $await-async-async-func'))
))))
(func (export "sync-barges-in") async (result u32) (canon lift (core func $core "sync-barges-in")))
(func (export "trap-if-suspend") (canon lift (core func $core "trap-if-suspend")))
(func (export "trap-if-wait") (canon lift (core func $core "trap-if-wait")))
(func (export "trap-if-wait-cb") (canon lift (core func $core "trap-if-wait-cb") async (callback (func $core "unreachable-cb"))))
(func (export "trap-if-poll") (canon lift (core func $core "trap-if-poll")))
(func (export "trap-if-poll-cb") (canon lift (core func $core "trap-if-poll-cb") async (callback (func $core "unreachable-cb"))))
(func (export "yield-is-fine") (result u32) (canon lift (core func $core "yield-is-fine")))
(func (export "yield-is-fine-cb") (result u32) (canon lift (core func $core "yield-is-fine-cb") async (callback (func $core "return-42-cb"))))
(func (export "trap-if-sync-call-async1") (canon lift (core func $core "trap-if-sync-call-async1")))
(func (export "trap-if-sync-call-async2") (canon lift (core func $core "trap-if-sync-call-async2")))
(func (export "trap-if-sync-cancel") (canon lift (core func $core "trap-if-sync-cancel")))
(func (export "trap-if-sync-stream-read") (canon lift (core func $core "trap-if-sync-stream-read")))
(func (export "trap-if-sync-stream-write") (canon lift (core func $core "trap-if-sync-stream-write")))
(func (export "trap-if-sync-future-read") (canon lift (core func $core "trap-if-sync-future-read")))
(func (export "trap-if-sync-future-write") (canon lift (core func $core "trap-if-sync-future-write")))
(func (export "trap-if-sync-stream-cancel-read") (canon lift (core func $core "trap-if-sync-stream-cancel-read")))
(func (export "trap-if-sync-stream-cancel-write") (canon lift (core func $core "trap-if-sync-stream-cancel-write")))
(func (export "trap-if-sync-future-cancel-read") (canon lift (core func $core "trap-if-sync-future-cancel-read")))
(func (export "trap-if-sync-future-cancel-write") (canon lift (core func $core "trap-if-sync-future-cancel-write")))
)
(instance $c (instantiate $C))
(instance $d (instantiate $D (with "c" (instance $c))))
(func (export "sync-barges-in") (alias export $d "sync-barges-in"))
(func (export "trap-if-sync-call-async1") (alias export $d "trap-if-sync-call-async1"))
(func (export "trap-if-sync-call-async2") (alias export $d "trap-if-sync-call-async2"))
(func (export "trap-if-suspend") (alias export $d "trap-if-suspend"))
(func (export "trap-if-wait") (alias export $d "trap-if-wait"))
(func (export "trap-if-wait-cb") (alias export $d "trap-if-wait-cb"))
(func (export "trap-if-poll") (alias export $d "trap-if-poll"))
(func (export "trap-if-poll-cb") (alias export $d "trap-if-poll-cb"))
(func (export "yield-is-fine") (alias export $d "yield-is-fine"))
(func (export "yield-is-fine-cb") (alias export $d "yield-is-fine-cb"))
(func (export "trap-if-sync-cancel") (alias export $d "trap-if-sync-cancel"))
(func (export "trap-if-sync-stream-read") (alias export $d "trap-if-sync-stream-read"))
(func (export "trap-if-sync-stream-write") (alias export $d "trap-if-sync-stream-write"))
(func (export "trap-if-sync-future-read") (alias export $d "trap-if-sync-future-read"))
(func (export "trap-if-sync-future-write") (alias export $d "trap-if-sync-future-write"))
(func (export "trap-if-sync-stream-cancel-read") (alias export $d "trap-if-sync-stream-cancel-read"))
(func (export "trap-if-sync-stream-cancel-write") (alias export $d "trap-if-sync-stream-cancel-write"))
(func (export "trap-if-sync-future-cancel-read") (alias export $d "trap-if-sync-future-cancel-read"))
(func (export "trap-if-sync-future-cancel-write") (alias export $d "trap-if-sync-future-cancel-write"))
)
(component instance $i $Tester)
(assert_return (invoke "sync-barges-in") (u32.const 44))
(component instance $i $Tester)
(assert_trap (invoke "trap-if-sync-call-async1") "cannot block a synchronous task before returning")
(component instance $i $Tester)
(assert_trap (invoke "trap-if-sync-call-async2") "cannot block a synchronous task before returning")
(component instance $i $Tester)
(assert_trap (invoke "trap-if-suspend") "cannot block a synchronous task before returning")
(component instance $i $Tester)
(assert_trap (invoke "trap-if-wait") "cannot block a synchronous task before returning")
(component instance $i $Tester)
(assert_trap (invoke "trap-if-wait-cb") "cannot block a synchronous task before returning")
(component instance $i $Tester)
(assert_trap (invoke "trap-if-poll") "cannot block a synchronous task before returning")
(component instance $i $Tester)
(assert_trap (invoke "trap-if-poll-cb") "cannot block a synchronous task before returning")
(component instance $i $Tester)
(assert_return (invoke "yield-is-fine") (u32.const 42))
(component instance $i $Tester)
(assert_return (invoke "yield-is-fine-cb") (u32.const 42))
(component instance $i $Tester)
(assert_trap (invoke "trap-if-sync-cancel") "cannot block a synchronous task before returning")
(component instance $i $Tester)
(assert_trap (invoke "trap-if-sync-stream-read") "cannot block a synchronous task before returning")
(component instance $i $Tester)
(assert_trap (invoke "trap-if-sync-stream-write") "cannot block a synchronous task before returning")
(component instance $i $Tester)
(assert_trap (invoke "trap-if-sync-future-read") "cannot block a synchronous task before returning")
(component instance $i $Tester)
(assert_trap (invoke "trap-if-sync-future-write") "cannot block a synchronous task before returning")
(component instance $i $Tester)
(assert_trap (invoke "trap-if-sync-stream-cancel-read") "cannot block a synchronous task before returning")
(component instance $i $Tester)
(assert_trap (invoke "trap-if-sync-stream-cancel-write") "cannot block a synchronous task before returning")
(component instance $i $Tester)
(assert_trap (invoke "trap-if-sync-future-cancel-read") "cannot block a synchronous task before returning")
(component instance $i $Tester)
(assert_trap (invoke "trap-if-sync-future-cancel-write") "cannot block a synchronous task before returning")