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        (local.set $ret (call $stream.read (local.get $rx) (local.get $bufp) (i32.const 4)))
67        (if (i32.ne (i32.const 0x41 (; COMPLETED=0 | (4<<4) ;)) (local.get $ret))
68          (then unreachable))
69        (if (i32.ne (i32.const 0x89abcdef) (i32.load (local.get $bufp)))
70          (then unreachable))
71
72        (call $stream.drop-readable (local.get $rx))
73        (return (i32.const 0 (; EXIT ;)))
74      )
75      (func (export "set_cb") (param i32 i32 i32) (result i32)
76        unreachable
77      )
78    )
79    (type $ST (stream u8))
80    (canon task.return (memory $memory "mem") (core func $task.return0))
81    (canon task.return (result $ST) (memory $memory "mem") (core func $task.return1))
82    (canon stream.new $ST (core func $stream.new))
83    (canon stream.read $ST (memory $memory "mem") (core func $stream.read))
84    (canon stream.write $ST (memory $memory "mem") (core func $stream.write))
85    (canon stream.drop-readable $ST (core func $stream.drop-readable))
86    (canon stream.drop-writable $ST (core func $stream.drop-writable))
87    (core instance $cm (instantiate $CM (with "" (instance
88      (export "mem" (memory $memory "mem"))
89      (export "task.return0" (func $task.return0))
90      (export "task.return1" (func $task.return1))
91      (export "stream.new" (func $stream.new))
92      (export "stream.read" (func $stream.read))
93      (export "stream.write" (func $stream.write))
94      (export "stream.drop-readable" (func $stream.drop-readable))
95      (export "stream.drop-writable" (func $stream.drop-writable))
96    ))))
97    (func (export "get") (result (stream u8)) (canon lift
98      (core func $cm "get")
99      async (memory $memory "mem") (callback (func $cm "get_cb"))
100    ))
101    (func (export "set") (param "in" (stream u8)) (canon lift
102      (core func $cm "set")
103      async (memory $memory "mem") (callback (func $cm "set_cb"))
104    ))
105  )
106  (component $D
107    (import "get" (func $get (result (stream u8))))
108    (import "set" (func $set (param "in" (stream u8))))
109
110    (core module $Memory (memory (export "mem") 1))
111    (core instance $memory (instantiate $Memory))
112    (core module $DM
113      (import "" "mem" (memory 1))
114      (import "" "stream.new" (func $stream.new (result i64)))
115      (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32)))
116      (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32)))
117      (import "" "stream.drop-readable" (func $stream.drop-readable (param i32)))
118      (import "" "stream.drop-writable" (func $stream.drop-writable (param i32)))
119      (import "" "get" (func $get (result i32)))
120      (import "" "set" (func $set (param i32)))
121
122      (func (export "run") (result i32)
123        (local $ret i32) (local $ret64 i64)
124        (local $rx i32) (local $tx i32)
125        (local $bufp i32)
126
127        ;; $rx = $C.get()
128        (local.set $rx (call $get))
129
130        ;; (stream.read $tx $bufp 4) will succeed without blocking
131        (local.set $bufp (i32.const 20))
132        (local.set $ret (call $stream.read (local.get $rx) (local.get $bufp) (i32.const 4)))
133        (if (i32.ne (i32.const 0x40 (; COMPLETED=0 | (4<<4) ;)) (local.get $ret))
134          (then unreachable))
135        (if (i32.ne (i32.const 0x01234567) (i32.load (local.get $bufp)))
136          (then unreachable))
137
138        (call $stream.drop-readable (local.get $rx))
139
140        ;; ($rx, $tx) = stream.new
141        ;; $C.set($rx)
142        (local.set $ret64 (call $stream.new))
143        (local.set $rx (i32.wrap_i64 (local.get $ret64)))
144        (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32))))
145        (call $set (local.get $rx))
146
147        ;; (stream.write $tx $bufp 4) will succeed without blocking
148        (local.set $bufp (i32.const 16))
149        (local.set $ret (call $stream.write (local.get $tx) (local.get $bufp) (i32.const 4)))
150        (if (i32.ne (i32.const 0x40 (; COMPLETED=0 | (4<<4) ;)) (local.get $ret))
151          (then unreachable))
152
153        (call $stream.drop-writable (local.get $tx))
154        (i32.const 42)
155      )
156    )
157    (type $ST (stream u8))
158    (canon stream.new $ST (core func $stream.new))
159    (canon stream.read $ST async (memory $memory "mem") (core func $stream.read))
160    (canon stream.write $ST async (memory $memory "mem") (core func $stream.write))
161    (canon stream.drop-readable $ST (core func $stream.drop-readable))
162    (canon stream.drop-writable $ST (core func $stream.drop-writable))
163    (canon lower (func $get) (core func $get'))
164    (canon lower (func $set) (core func $set'))
165    (core instance $dm (instantiate $DM (with "" (instance
166      (export "mem" (memory $memory "mem"))
167      (export "stream.new" (func $stream.new))
168      (export "stream.read" (func $stream.read))
169      (export "stream.write" (func $stream.write))
170      (export "stream.drop-readable" (func $stream.drop-readable))
171      (export "stream.drop-writable" (func $stream.drop-writable))
172      (export "get" (func $get'))
173      (export "set" (func $set'))
174    ))))
175    (func (export "run") (result u32) (canon lift (core func $dm "run")))
176  )
177
178  (instance $c (instantiate $C))
179  (instance $d (instantiate $D
180    (with "get" (func $c "get"))
181    (with "set" (func $c "set"))
182  ))
183  (func (export "run") (alias export $d "run"))
184)
185(assert_return (invoke "run") (u32.const 42))
186