1;;! component_model_async = true 2;;! reference_types = true 3;;! multi_memory = true 4;;! gc_types = true 5 6;; This test has two components $C and $D, where $D imports and calls $C.transform 7;; $C.transform takes and returns a stream<u8> 8;; Before $C.transform blocks the first time, it supplies a 12-byte read buffer 9;; When $D.run regains control after $C.transform blocks, it can perform multiple 10;; successful writes until it fully uses up the 12-byte buffer. 11;; ... and that's where I am so far ... 12;; 13;; (Copied from 14;; https://github.com/WebAssembly/component-model/blob/add-tests/test/concurrency/partial-stream-copies.wast) 15(component 16 (component $C 17 (core module $Memory (memory (export "mem") 1)) 18 (core instance $memory (instantiate $Memory)) 19 (core module $CM 20 (import "" "mem" (memory 1)) 21 (import "" "task.return" (func $task.return (param i32))) 22 (import "" "waitable.join" (func $waitable.join (param i32 i32))) 23 (import "" "waitable-set.new" (func $waitable-set.new (result i32))) 24 (import "" "stream.new" (func $stream.new (result i64))) 25 (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) 26 (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) 27 (import "" "stream.drop-readable" (func $stream.drop-readable (param i32))) 28 (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) 29 30 ;; $ws is waited on by 'transform' 31 (global $ws (mut i32) (i32.const 0)) 32 (func $start (global.set $ws (call $waitable-set.new))) 33 (start $start) 34 35 ;; $insr/$outsw are read/written by 'transform' 36 (global $insr (mut i32) (i32.const 0)) 37 (global $inbufp (mut i32) (i32.const 0x10)) 38 (global $outsw (mut i32) (i32.const 0)) 39 (global $outbufp (mut i32) (i32.const 0x20)) 40 41 (func $transform (export "transform") (param i32) (result i32) 42 (local $ret i32) (local $ret64 i64) (local $outsr i32) 43 44 ;; check the incoming readable stream end 45 (global.set $insr (local.get 0)) 46 (if (i32.ne (i32.const 2) (global.get $insr)) 47 (then unreachable)) 48 49 ;; create a new stream r/w pair $outsr/$outsw 50 (local.set $ret64 (call $stream.new)) 51 (local.set $outsr (i32.wrap_i64 (local.get $ret64))) 52 (if (i32.ne (i32.const 3) (local.get $outsr)) 53 (then unreachable)) 54 (global.set $outsw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) 55 (if (i32.ne (i32.const 4) (global.get $outsw)) 56 (then unreachable)) 57 58 ;; start async read on $insr which will block 59 (local.set $ret (call $stream.read (global.get $insr) (global.get $inbufp) (i32.const 12))) 60 (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) 61 (then unreachable)) 62 63 ;; return the readable end of the outgoing stream to the caller 64 (call $task.return (local.get $outsr)) 65 66 ;; wait for the stream.read/write to complete 67 (call $waitable.join (global.get $insr) (global.get $ws)) 68 (call $waitable.join (global.get $outsw) (global.get $ws)) 69 (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4))) 70 ) 71 (func $transform_cb (export "transform_cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32) 72 (local $ret i32) (local $ret64 i64) 73 74 ;; confirm the read succeeded fully 75 (if (i32.ne (local.get $event_code) (i32.const 2 (; STREAM_READ ;))) 76 (then unreachable)) 77 (if (i32.ne (local.get $index) (global.get $insr)) 78 (then unreachable)) 79 (if (i32.ne (local.get $payload) (i32.const 0xc0 (; COMPLETED=0 | (12 << 4) ;))) 80 (then unreachable)) 81 (if (i32.ne (i32.const 0x89abcdef) (i32.load offset=0 (global.get $inbufp))) 82 (then unreachable)) 83 (if (i32.ne (i32.const 0x01234567) (i32.load offset=4 (global.get $inbufp))) 84 (then unreachable)) 85 (if (i32.ne (i32.const 0x89abcdef) (i32.load offset=8 (global.get $inbufp))) 86 (then unreachable)) 87 88 ;; multiple read calls succeed until 12-byte buffer is consumed 89 (local.set $ret (call $stream.read (global.get $insr) (global.get $inbufp) (i32.const 4))) 90 (if (i32.ne (i32.const 0x40) (local.get $ret)) 91 (then unreachable)) 92 (if (i32.ne (i32.const 0x76543210) (i32.load (global.get $inbufp))) 93 (then unreachable)) 94 (local.set $ret (call $stream.read (global.get $insr) (global.get $inbufp) (i32.const 2))) 95 (if (i32.ne (i32.const 0x20) (local.get $ret)) 96 (then unreachable)) 97 (if (i32.ne (i32.const 0xba98) (i32.load16_u (global.get $inbufp))) 98 (then unreachable)) 99 (local.set $ret (call $stream.read (global.get $insr) (global.get $inbufp) (i32.const 8))) 100 (if (i32.ne (i32.const 0x60) (local.get $ret)) 101 (then unreachable)) 102 (if (i32.ne (i32.const 0x3210fedc) (i32.load (global.get $inbufp))) 103 (then unreachable)) 104 (if (i32.ne (i32.const 0x7654) (i32.load16_u offset=4 (global.get $inbufp))) 105 (then unreachable)) 106 107 (call $stream.drop-readable (global.get $insr)) 108 (call $stream.drop-writable (global.get $outsw)) 109 (return (i32.const 0 (; EXIT ;))) 110 ) 111 ) 112 (type $ST (stream u8)) 113 (canon task.return (result $ST) (memory $memory "mem") (core func $task.return)) 114 (canon waitable.join (core func $waitable.join)) 115 (canon waitable-set.new (core func $waitable-set.new)) 116 (canon stream.new $ST (core func $stream.new)) 117 (canon stream.read $ST async (memory $memory "mem") (core func $stream.read)) 118 (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) 119 (canon stream.drop-readable $ST (core func $stream.drop-readable)) 120 (canon stream.drop-writable $ST (core func $stream.drop-writable)) 121 (core instance $cm (instantiate $CM (with "" (instance 122 (export "mem" (memory $memory "mem")) 123 (export "task.return" (func $task.return)) 124 (export "waitable.join" (func $waitable.join)) 125 (export "waitable-set.new" (func $waitable-set.new)) 126 (export "stream.new" (func $stream.new)) 127 (export "stream.read" (func $stream.read)) 128 (export "stream.write" (func $stream.write)) 129 (export "stream.drop-readable" (func $stream.drop-readable)) 130 (export "stream.drop-writable" (func $stream.drop-writable)) 131 )))) 132 (func (export "transform") (param "in" (stream u8)) (result (stream u8)) (canon lift 133 (core func $cm "transform") 134 async (memory $memory "mem") (callback (func $cm "transform_cb")) 135 )) 136 ) 137 138 (component $D 139 (import "transform" (func $transform (param "in" (stream u8)) (result (stream u8)))) 140 141 (core module $Memory (memory (export "mem") 1)) 142 (core instance $memory (instantiate $Memory)) 143 (core module $DM 144 (import "" "mem" (memory 1)) 145 (import "" "waitable.join" (func $waitable.join (param i32 i32))) 146 (import "" "waitable-set.new" (func $waitable-set.new (result i32))) 147 (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) 148 (import "" "stream.new" (func $stream.new (result i64))) 149 (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) 150 (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) 151 (import "" "stream.drop-readable" (func $stream.drop-readable (param i32))) 152 (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) 153 (import "" "transform" (func $transform (param i32 i32) (result i32))) 154 155 (func $run (export "run") (result i32) 156 (local $ret i32) (local $ret64 i64) (local $retp i32) 157 (local $insr i32) (local $insw i32) (local $outsr i32) 158 (local $subtask i32) 159 (local $ws i32) 160 161 ;; create a new stream r/w pair $insr/$insw 162 (local.set $ret64 (call $stream.new)) 163 (local.set $insr (i32.wrap_i64 (local.get $ret64))) 164 (if (i32.ne (i32.const 1) (local.get $insr)) 165 (then unreachable)) 166 (local.set $insw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) 167 (if (i32.ne (i32.const 2) (local.get $insw)) 168 (then unreachable)) 169 170 ;; call 'transform' which will return a readable stream $outsr eagerly 171 (local.set $retp (i32.const 8)) 172 (local.set $ret (call $transform (local.get $insr) (local.get $retp))) 173 (if (i32.ne (i32.const 2 (; RETURNED=2 | (0<<4) ;)) (local.get $ret)) 174 (then unreachable)) 175 (local.set $outsr (i32.load (local.get $retp))) 176 (if (i32.ne (i32.const 1) (local.get $outsr)) 177 (then unreachable)) 178 179 ;; multiple write calls succeed until 12-byte buffer is filled 180 (i64.store (i32.const 16) (i64.const 0x0123456789abcdef)) 181 (local.set $ret (call $stream.write (local.get $insw) (i32.const 16) (i32.const 8))) 182 (if (i32.ne (i32.const 0x80) (local.get $ret)) 183 (then unreachable)) 184 (local.set $ret (call $stream.write (local.get $insw) (i32.const 16) (i32.const 8))) 185 (if (i32.ne (i32.const 0x40) (local.get $ret)) 186 (then unreachable)) 187 188 ;; start a blocking write with a 12-byte buffer 189 (i64.store (i32.const 16) (i64.const 0xfedcba9876543210)) 190 (i32.store (i32.const 24) (i32.const 0x76543210)) 191 (local.set $ret (call $stream.write (local.get $insw) (i32.const 16) (i32.const 12))) 192 (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) 193 (then unreachable)) 194 195 ;; wait for transform to read our write and drop all the streams 196 (local.set $ws (call $waitable-set.new)) 197 (call $waitable.join (local.get $insw) (local.get $ws)) 198 (local.set $ret (call $waitable-set.wait (local.get $ws) (i32.const 0))) 199 200 ;; confirm the write and the dropped stream 201 (if (i32.ne (i32.const 3 (; STREAM_WRITE ;)) (local.get $ret)) 202 (then unreachable)) 203 (if (i32.ne (local.get $insw) (i32.load (i32.const 0))) 204 (then unreachable)) 205 (if (i32.ne (i32.const 0xc1 (; DROPPED=1 | (12 << 4) ;) (; TODO: currently returns 0xc0 ;)) (i32.load (i32.const 4))) 206 (then unreachable)) 207 208 (call $stream.drop-writable (local.get $insw)) 209 (call $stream.drop-readable (local.get $outsr)) 210 211 ;; return 42 to the top-level test harness 212 (i32.const 42) 213 ) 214 ) 215 (type $ST (stream u8)) 216 (canon waitable.join (core func $waitable.join)) 217 (canon waitable-set.new (core func $waitable-set.new)) 218 (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) 219 (canon stream.new $ST (core func $stream.new)) 220 (canon stream.read $ST async (memory $memory "mem") (core func $stream.read)) 221 (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) 222 (canon stream.drop-readable $ST (core func $stream.drop-readable)) 223 (canon stream.drop-writable $ST (core func $stream.drop-writable)) 224 (canon lower (func $transform) async (memory $memory "mem") (core func $transform')) 225 (core instance $dm (instantiate $DM (with "" (instance 226 (export "mem" (memory $memory "mem")) 227 (export "waitable.join" (func $waitable.join)) 228 (export "waitable-set.new" (func $waitable-set.new)) 229 (export "waitable-set.wait" (func $waitable-set.wait)) 230 (export "stream.new" (func $stream.new)) 231 (export "stream.read" (func $stream.read)) 232 (export "stream.write" (func $stream.write)) 233 (export "stream.drop-readable" (func $stream.drop-readable)) 234 (export "stream.drop-writable" (func $stream.drop-writable)) 235 (export "transform" (func $transform')) 236 )))) 237 (func (export "run") async (result u32) (canon lift (core func $dm "run"))) 238 ) 239 240 (instance $c (instantiate $C)) 241 (instance $d (instantiate $D (with "transform" (func $c "transform")))) 242 (func (export "run") (alias export $d "run")) 243) 244(assert_return (invoke "run") (u32.const 42)) 245