1;;! component_model_async = true 2 3;; This test contains two components $C and $D that test that a trap occurs 4;; when closing the writable end of a future (in $C) before having written 5;; a value while closing the readable end of a future (in $D) before reading 6;; a value is fine. 7;; 8;; (Copied from 9;; https://github.com/WebAssembly/component-model/blob/future-trap/test/async/futures-must-write.wast) 10(component 11 (component $C 12 (core module $Memory (memory (export "mem") 1)) 13 (core instance $memory (instantiate $Memory)) 14 (core module $CM 15 (import "" "mem" (memory 1)) 16 (import "" "future.new" (func $future.new (result i64))) 17 (import "" "future.write" (func $future.write (param i32 i32) (result i32))) 18 (import "" "future.drop-writable" (func $future.drop-writable (param i32))) 19 20 (global $fw (mut i32) (i32.const 0)) 21 22 (func $start-future (export "start-future") (result i32) 23 ;; create a new future, return the readable end to the caller 24 (local $ret64 i64) 25 (local.set $ret64 (call $future.new)) 26 (global.set $fw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) 27 (i32.wrap_i64 (local.get $ret64)) 28 ) 29 (func $attempt-write (export "attempt-write") (result i32) 30 ;; because the caller already dropped the readable end, this write will eagerly 31 ;; return DROPPED having written no values. 32 (local $ret i32) 33 (local.set $ret (call $future.write (global.get $fw) (i32.const 42))) 34 (if (i32.ne (i32.const 0x01 (; DROPPED=1 | (0<<4) ;)) (local.get $ret)) 35 (then 36 (i32.load (i32.add (local.get $ret) (i32.const 0x8000_0000))) 37 unreachable)) 38 39 ;; return without trapping 40 (i32.const 42) 41 ) 42 (func $drop-writable (export "drop-writable") 43 ;; maybe boom 44 (call $future.drop-writable (global.get $fw)) 45 ) 46 ) 47 (type $FT (future u8)) 48 (canon future.new $FT (core func $future.new)) 49 (canon future.write $FT async (memory $memory "mem") (core func $future.write)) 50 (canon future.drop-writable $FT (core func $future.drop-writable)) 51 (core instance $cm (instantiate $CM (with "" (instance 52 (export "mem" (memory $memory "mem")) 53 (export "future.new" (func $future.new)) 54 (export "future.write" (func $future.write)) 55 (export "future.drop-writable" (func $future.drop-writable)) 56 )))) 57 (func (export "start-future") (result (future u8)) (canon lift (core func $cm "start-future"))) 58 (func (export "attempt-write") (result u32) (canon lift (core func $cm "attempt-write"))) 59 (func (export "drop-writable") (canon lift (core func $cm "drop-writable"))) 60 ) 61 (component $D 62 (import "c" (instance $c 63 (export "start-future" (func (result (future u8)))) 64 (export "attempt-write" (func (result u32))) 65 (export "drop-writable" (func)) 66 )) 67 68 (core module $Memory (memory (export "mem") 1)) 69 (core instance $memory (instantiate $Memory)) 70 (core module $Core 71 (import "" "mem" (memory 1)) 72 (import "" "future.read" (func $future.read (param i32 i32) (result i32))) 73 (import "" "future.drop-readable" (func $future.drop-readable (param i32))) 74 (import "" "start-future" (func $start-future (result i32))) 75 (import "" "attempt-write" (func $attempt-write (result i32))) 76 (import "" "drop-writable" (func $drop-writable)) 77 78 (func $drop-readable-future-before-read (export "drop-readable-future-before-read") (result i32) 79 ;; call 'start-future' to get the future we'll be working with 80 (local $fr i32) 81 (local.set $fr (call $start-future)) 82 (if (i32.ne (i32.const 1) (local.get $fr)) 83 (then unreachable)) 84 85 ;; ok to immediately drop the readable end 86 (call $future.drop-readable (local.get $fr)) 87 88 ;; the callee will see that we dropped the readable end when it tries to write 89 (call $attempt-write) 90 ) 91 (func $drop-writable-future-before-write (export "drop-writable-future-before-write") 92 ;; call 'start-future' to get the future we'll be working with 93 (local $fr i32) 94 (local.set $fr (call $start-future)) 95 (if (i32.ne (i32.const 1) (local.get $fr)) 96 (then unreachable)) 97 98 ;; boom 99 (call $drop-writable) 100 ) 101 ) 102 (type $FT (future u8)) 103 (canon future.new $FT (core func $future.new)) 104 (canon future.read $FT async (memory $memory "mem") (core func $future.read)) 105 (canon future.drop-readable $FT (core func $future.drop-readable)) 106 (canon lower (func $c "start-future") (core func $start-future')) 107 (canon lower (func $c "attempt-write") (core func $attempt-write')) 108 (canon lower (func $c "drop-writable") (core func $drop-writable')) 109 (core instance $core (instantiate $Core (with "" (instance 110 (export "mem" (memory $memory "mem")) 111 (export "future.new" (func $future.new)) 112 (export "future.read" (func $future.read)) 113 (export "future.drop-readable" (func $future.drop-readable)) 114 (export "start-future" (func $start-future')) 115 (export "attempt-write" (func $attempt-write')) 116 (export "drop-writable" (func $drop-writable')) 117 )))) 118 (func (export "drop-readable-future-before-read") (result u32) (canon lift (core func $core "drop-readable-future-before-read"))) 119 (func (export "drop-writable-future-before-write") (canon lift (core func $core "drop-writable-future-before-write"))) 120 ) 121 (instance $c (instantiate $C)) 122 (instance $d (instantiate $D (with "c" (instance $c)))) 123 (func (export "drop-writable-future-before-write") (alias export $d "drop-writable-future-before-write")) 124 (func (export "drop-readable-future-before-read") (alias export $d "drop-readable-future-before-read")) 125) 126 127(assert_return (invoke "drop-readable-future-before-read") (u32.const 42)) 128(assert_trap (invoke "drop-writable-future-before-write") "cannot drop future write end without first writing a value") 129