1;;! component_model_async = true
2;;! reference_types = true
3;;! gc_types = true
4
5;; This test calls sync stream.write in $C.get and sync stream.read in $C.set.
6;; Both of these calls block because $C is first to the rendezvous. But since
7;; they are synchronous, control flow switches to $D.run which will do
8;; a complementary read/write that rendezvous, and then control flow will
9;; switch back to $C.get/set where the synchronous read/write will return
10;; without blocking.
11;;
12;; (Copied from
13;; https://github.com/WebAssembly/component-model/blob/main/test/async/sync-streams.wast)
14(component
15  (component $C
16    (core module $Memory (memory (export "mem") 1))
17    (core instance $memory (instantiate $Memory))
18    (core module $CM
19      (import "" "mem" (memory 1))
20      (import "" "task.return0" (func $task.return0))
21      (import "" "task.return1" (func $task.return1 (param i32)))
22      (import "" "stream.new" (func $stream.new (result i64)))
23      (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32)))
24      (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32)))
25      (import "" "stream.drop-readable" (func $stream.drop-readable (param i32)))
26      (import "" "stream.drop-writable" (func $stream.drop-writable (param i32)))
27
28      (func (export "get") (result i32)
29        (local $ret i32) (local $ret64 i64)
30        (local $tx i32) (local $rx i32)
31        (local $bufp i32)
32
33        ;; ($rx, $tx) = stream.new
34        (local.set $ret64 (call $stream.new))
35        (local.set $rx (i32.wrap_i64 (local.get $ret64)))
36        (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32))))
37
38        ;; return $rx
39        (call $task.return1 (local.get $rx))
40
41        ;; (stream.write $tx $bufp 4) will block and, because called
42        ;; synchronously, switch to the caller who will read and rendezvous
43        (local.set $bufp (i32.const 16))
44        (i32.store (local.get $bufp) (i32.const 0x01234567))
45        (local.set $ret (call $stream.write (local.get $tx) (local.get $bufp) (i32.const 4)))
46        (if (i32.ne (i32.const 0x41 (; DROPPED=1 | (4<<4) ;)) (local.get $ret))
47          (then unreachable))
48
49        (call $stream.drop-writable (local.get $tx))
50        (return (i32.const 0 (; EXIT ;)))
51      )
52      (func (export "get_cb") (param i32 i32 i32) (result i32)
53        unreachable
54      )
55
56      (func (export "set") (param $rx i32) (result i32)
57        (local $ret i32) (local $ret64 i64)
58        (local $bufp i32)
59
60        ;; return immediately so that the caller can just call synchronously
61        (call $task.return0)
62
63        ;; (stream.read $tx $bufp 4) will block and, because called
64        ;; synchronously, switch to the caller who will write and rendezvous
65        (local.set $bufp (i32.const 16))
66
67        (local.set $ret (call $stream.read (local.get $rx) (local.get $bufp) (i32.const 4)))
68        (if (i32.ne (i32.const 0x41 (; COMPLETED=0 | (4<<4) ;)) (local.get $ret))
69          (then unreachable))
70        (if (i32.ne (i32.const 0x89abcdef) (i32.load (local.get $bufp)))
71          (then unreachable))
72
73        (call $stream.drop-readable (local.get $rx))
74        (return (i32.const 0 (; EXIT ;)))
75      )
76      (func (export "set_cb") (param i32 i32 i32) (result i32)
77        unreachable
78      )
79    )
80    (type $ST (stream u8))
81    (canon task.return (memory $memory "mem") (core func $task.return0))
82    (canon task.return (result $ST) (memory $memory "mem") (core func $task.return1))
83    (canon stream.new $ST (core func $stream.new))
84    (canon stream.read $ST (memory $memory "mem") (core func $stream.read))
85    (canon stream.write $ST (memory $memory "mem") (core func $stream.write))
86    (canon stream.drop-readable $ST (core func $stream.drop-readable))
87    (canon stream.drop-writable $ST (core func $stream.drop-writable))
88    (core instance $cm (instantiate $CM (with "" (instance
89      (export "mem" (memory $memory "mem"))
90      (export "task.return0" (func $task.return0))
91      (export "task.return1" (func $task.return1))
92      (export "stream.new" (func $stream.new))
93      (export "stream.read" (func $stream.read))
94      (export "stream.write" (func $stream.write))
95      (export "stream.drop-readable" (func $stream.drop-readable))
96      (export "stream.drop-writable" (func $stream.drop-writable))
97    ))))
98    (func (export "get") async (result (stream u8)) (canon lift
99      (core func $cm "get")
100      async (memory $memory "mem") (callback (func $cm "get_cb"))
101    ))
102    (func (export "set") async (param "in" (stream u8)) (canon lift
103      (core func $cm "set")
104      async (memory $memory "mem") (callback (func $cm "set_cb"))
105    ))
106  )
107  (component $D
108    (import "get" (func $get async (result (stream u8))))
109    (import "set" (func $set async (param "in" (stream u8))))
110
111    (core module $Memory (memory (export "mem") 1))
112    (core instance $memory (instantiate $Memory))
113    (core module $DM
114      (import "" "mem" (memory 1))
115      (import "" "stream.new" (func $stream.new (result i64)))
116      (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32)))
117      (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32)))
118      (import "" "stream.drop-readable" (func $stream.drop-readable (param i32)))
119      (import "" "stream.drop-writable" (func $stream.drop-writable (param i32)))
120      (import "" "get" (func $get (result i32)))
121      (import "" "set" (func $set (param i32)))
122
123      (func (export "run") (result i32)
124        (local $ret i32) (local $ret64 i64)
125        (local $rx i32) (local $tx i32)
126        (local $bufp i32)
127
128        ;; $rx = $C.get()
129        (local.set $rx (call $get))
130
131        ;; (stream.read $tx $bufp 4) will succeed without blocking
132        (local.set $bufp (i32.const 20))
133        (local.set $ret (call $stream.read (local.get $rx) (local.get $bufp) (i32.const 4)))
134        (if (i32.ne (i32.const 0x40 (; COMPLETED=0 | (4<<4) ;)) (local.get $ret))
135          (then unreachable))
136        (if (i32.ne (i32.const 0x01234567) (i32.load (local.get $bufp)))
137          (then unreachable))
138
139        (call $stream.drop-readable (local.get $rx))
140
141        ;; ($rx, $tx) = stream.new
142        ;; $C.set($rx)
143        (local.set $ret64 (call $stream.new))
144        (local.set $rx (i32.wrap_i64 (local.get $ret64)))
145        (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32))))
146        (call $set (local.get $rx))
147
148        ;; (stream.write $tx $bufp 4) will succeed without blocking
149        (local.set $bufp (i32.const 16))
150        (local.set $ret (call $stream.write (local.get $tx) (local.get $bufp) (i32.const 4)))
151        (if (i32.ne (i32.const 0x40 (; COMPLETED=0 | (4<<4) ;)) (local.get $ret))
152          (then unreachable))
153
154        (call $stream.drop-writable (local.get $tx))
155        (i32.const 42)
156      )
157    )
158    (type $ST (stream u8))
159    (canon stream.new $ST (core func $stream.new))
160    (canon stream.read $ST async (memory $memory "mem") (core func $stream.read))
161    (canon stream.write $ST async (memory $memory "mem") (core func $stream.write))
162    (canon stream.drop-readable $ST (core func $stream.drop-readable))
163    (canon stream.drop-writable $ST (core func $stream.drop-writable))
164    (canon lower (func $get) (core func $get'))
165    (canon lower (func $set) (core func $set'))
166    (core instance $dm (instantiate $DM (with "" (instance
167      (export "mem" (memory $memory "mem"))
168      (export "stream.new" (func $stream.new))
169      (export "stream.read" (func $stream.read))
170      (export "stream.write" (func $stream.write))
171      (export "stream.drop-readable" (func $stream.drop-readable))
172      (export "stream.drop-writable" (func $stream.drop-writable))
173      (export "get" (func $get'))
174      (export "set" (func $set'))
175    ))))
176    (func (export "run") async (result u32) (canon lift (core func $dm "run")))
177  )
178
179  (instance $c (instantiate $C))
180  (instance $d (instantiate $D
181    (with "get" (func $c "get"))
182    (with "set" (func $c "set"))
183  ))
184  (func (export "run") (alias export $d "run"))
185)
186(assert_return (invoke "run") (u32.const 42))
187