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