1;;! component_model_async = true
2;;! reference_types = true
3
4;; This test exercises corner cases where extremely large values are sent
5;; between guests and currently require copying out to the host in Wasmtime
6;; which should result in a trap of some form rather than the host spending all
7;; its time allocating and copying memory.
8
9(component definition $A
10  (type $t (list (list (list (list u8)))))
11  (type $s (stream $t))
12  (type $f (future $t))
13  (type $functy (func async (result $s)))
14
15  (component $A
16    (core module $libc (memory (export "memory") 1))
17    (core instance $libc (instantiate $libc))
18
19    (core module $m
20      (import "libc" "memory" (memory 1))
21      (import "" "stream.new" (func $stream.new (result i64)))
22      (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32)))
23      (import "" "future.new" (func $future.new (result i64)))
24      (import "" "future.write" (func $future.write (param i32 i32) (result i32)))
25      (import "" "task.return future" (func $task.return-future (param i32)))
26      (import "" "task.return stream" (func $task.return-stream (param i32)))
27
28      (func (export "big-stream") (result i32)
29        (local $w i32)
30        (local $r i32)
31        (local $s i64)
32        (local.set $s (call $stream.new))
33        (local.set $r (i32.wrap_i64 (local.get $s)))
34        (local.set $w (i32.wrap_i64 (i64.shr_u (local.get $s) (i64.const 32))))
35
36        (call $task.return-stream (local.get $r))
37
38        local.get $w
39        (call $prepare-list-to-write (i32.const 5) (i32.const 2))
40        call $stream.write
41        unreachable
42      )
43
44      (func (export "big-future") (result i32)
45        (local $w i32)
46        (local $r i32)
47        (local $s i64)
48        (local $base i32)
49        (local $len i32)
50        (local.set $s (call $future.new))
51        (local.set $r (i32.wrap_i64 (local.get $s)))
52        (local.set $w (i32.wrap_i64 (i64.shr_u (local.get $s) (i64.const 32))))
53
54        (call $task.return-future (local.get $r))
55
56        (call $prepare-list-to-write (i32.const 4) (i32.const 2))
57        local.set $len
58        local.set $base
59
60        (i32.store offset=0 (i32.const 100) (local.get $base))
61        (i32.store offset=4 (i32.const 100) (local.get $len))
62
63
64        local.get $w
65        i32.const 100
66        call $future.write
67        unreachable
68      )
69
70      ;; Prepare $depth+1 layers of lists where the leaves point to all of
71      ;; memory and each layer otherwise is a list of the previous layer.
72      ;;
73      ;; Each layer-of-lists is `$pages` large.
74      (func $prepare-list-to-write (param $depth i32) (param $pages i32) (result i32 i32)
75        (local $base i32)
76        (local $len i32)
77
78        (local $c_base i32)
79        (local $c_len i32)
80        (local $i i32)
81
82        local.get $depth
83        if
84          ;; Case of $depth>0 meaning that this is a list-of-lists layer.
85          ;; Allocate some memory to store this list itself then generate the
86          ;; layer down by recursing.
87          (local.set $base (call $grow (local.get $pages)))
88          (local.set $len
89            (i32.div_u
90              (i32.mul (local.get $pages) (i32.const 65536))
91              (i32.const 8)
92            )
93          )
94
95          (call $prepare-list-to-write
96            (i32.sub (local.get $depth) (i32.const 1))
97            (local.get $pages))
98          local.set $c_len
99          local.set $c_base
100
101          ;; Initialize this list-of-lists with all copies of the previous
102          ;; layer's list.
103          loop $l
104            (i32.store offset=0
105              (i32.add (local.get $base) (i32.mul (local.get $i) (i32.const 8)))
106              (local.get $c_base))
107            (i32.store offset=4
108              (i32.add (local.get $base) (i32.mul (local.get $i) (i32.const 8)))
109              (local.get $c_len))
110
111            (local.set $i (i32.add (local.get $i) (i32.const 1)))
112            (if (i32.lt_u (local.get $i) (local.get $len))
113              (then (br $l)))
114          end
115
116        else
117          ;; base case: the bottom list is just a byte list of all of memory.
118          (local.set $base (i32.const 0))
119          (local.set $len (i32.mul (memory.size) (i32.const 65536)))
120        end
121
122        local.get $base
123        local.get $len
124      )
125
126      (func $grow (param i32) (result i32)
127        (local $r i32)
128        (local.set $r (memory.grow (local.get 0)))
129        local.get $r
130        i32.const -1
131        i32.eq
132        if unreachable end
133        local.get $r
134        i32.const 65536
135        i32.mul
136      )
137
138      (func (export "cb") (param i32 i32 i32) (result i32) unreachable)
139    )
140    (core func $future.new (canon future.new $f))
141    (core func $future.write (canon future.write $f (memory $libc "memory")))
142    (core func $stream.new (canon stream.new $s))
143    (core func $stream.write (canon stream.write $s (memory $libc "memory")))
144    (core func $task.return-future (canon task.return (result $f)))
145    (core func $task.return-stream (canon task.return (result $s)))
146    (core instance $m (instantiate $m
147      (with "libc" (instance $libc))
148      (with "" (instance
149        (export "future.new" (func $future.new))
150        (export "future.write" (func $future.write))
151        (export "stream.new" (func $stream.new))
152        (export "stream.write" (func $stream.write))
153        (export "task.return future" (func $task.return-future))
154        (export "task.return stream" (func $task.return-stream))
155      ))
156    ))
157
158    (func (export "big-stream") (result $s)
159      (canon lift (core func $m "big-stream") async
160        (callback (func $m "cb"))))
161    (func (export "big-future") (result $f)
162      (canon lift (core func $m "big-future") async
163        (callback (func $m "cb"))))
164  )
165
166  (component $B
167    (import "a" (instance $a
168      (export "big-future" (func (result $f)))
169      (export "big-stream" (func (result $s)))
170    ))
171
172    (core module $libc
173      (memory (export "memory") 1)
174      (func (export "realloc") (param i32 i32 i32 i32) (result i32) unreachable)
175    )
176    (core instance $libc (instantiate $libc))
177
178    (core module $m
179      (import "libc" "memory" (memory 1))
180      (import "" "big-stream" (func $big-stream (result i32)))
181      (import "" "big-future" (func $big-future (result i32)))
182      (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32)))
183      (import "" "future.read" (func $future.read (param i32 i32) (result i32)))
184
185      (func (export "stream")
186        (call $stream.read
187          (call $big-stream)
188          i32.const 0
189          i32.const 100
190        )
191        unreachable
192      )
193      (func (export "future")
194        (call $future.read
195          (call $big-future)
196          i32.const 0
197        )
198        unreachable
199      )
200    )
201    (core func $big-stream (canon lower (func $a "big-stream")))
202    (core func $big-future (canon lower (func $a "big-future")))
203    (core func $stream.read
204      (canon stream.read $s
205        (memory $libc "memory")
206        (realloc (func $libc "realloc"))
207      )
208    )
209    (core func $future.read
210      (canon future.read $f
211        (memory $libc "memory")
212        (realloc (func $libc "realloc"))
213      )
214    )
215    (core instance $m (instantiate $m
216      (with "libc" (instance $libc))
217      (with "" (instance
218        (export "big-stream" (func $big-stream))
219        (export "big-future" (func $big-future))
220        (export "future.read" (func $future.read))
221        (export "stream.read" (func $stream.read))
222      ))
223    ))
224
225    (func (export "stream") async (canon lift (core func $m "stream")))
226    (func (export "future") async (canon lift (core func $m "future")))
227
228  )
229
230  (instance $a (instantiate $A))
231  (instance $b (instantiate $B (with "a" (instance $a))))
232  (export "stream" (func $b "stream"))
233  (export "future" (func $b "future"))
234)
235
236(component instance $A $A)
237(assert_trap (invoke "stream") "fuel allocated for hostcalls has been exhausted")
238(component instance $A $A)
239(assert_trap (invoke "future") "fuel allocated for hostcalls has been exhausted")
240