1;;! component_model_async = true
2
3;; bare bones "intrinsics work"
4(component
5  (type $r (resource (rep i32)))
6  (core func $rep (canon resource.rep $r))
7  (core func $new (canon resource.new $r))
8  (core func $drop (canon resource.drop $r))
9
10  (core module $m
11     (import "" "rep" (func $rep (param i32) (result i32)))
12     (import "" "new" (func $new (param i32) (result i32)))
13     (import "" "drop" (func $drop (param i32)))
14
15     (func $start
16       (local $r i32)
17       (local.set $r (call $new (i32.const 100)))
18
19       (if (i32.ne (local.get $r) (i32.const 1)) (then (unreachable)))
20       (if (i32.ne (call $rep (local.get $r)) (i32.const 100)) (then (unreachable)))
21
22       (call $drop (local.get $r))
23     )
24
25     (start $start)
26  )
27  (core instance (instantiate $m
28     (with "" (instance
29       (export "rep" (func $rep))
30       (export "new" (func $new))
31       (export "drop" (func $drop))
32     ))
33  ))
34)
35
36;; cannot call `resource.drop` on a nonexistent resource
37(component
38  (type $r (resource (rep i32)))
39  (core func $drop (canon resource.drop $r))
40
41  (core module $m
42     (import "" "drop" (func $drop (param i32)))
43
44     (func (export "r")
45       (call $drop (i32.const 0))
46     )
47  )
48  (core instance $i (instantiate $m
49     (with "" (instance
50       (export "drop" (func $drop))
51     ))
52  ))
53
54  (func (export "r") (canon lift (core func $i "r")))
55)
56(assert_trap (invoke "r") "unknown handle index 0")
57
58;; cannot call `resource.rep` on a nonexistent resource
59(component
60  (type $r (resource (rep i32)))
61  (core func $rep (canon resource.rep $r))
62
63  (core module $m
64     (import "" "rep" (func $rep (param i32) (result i32)))
65
66     (func (export "r")
67       (drop (call $rep (i32.const 0)))
68     )
69  )
70  (core instance $i (instantiate $m
71     (with "" (instance
72       (export "rep" (func $rep))
73     ))
74  ))
75
76  (func (export "r") (canon lift (core func $i "r")))
77)
78(assert_trap (invoke "r") "unknown handle index 0")
79
80;; index reuse behavior of handles
81(component
82  (type $r (resource (rep i32)))
83  (core func $rep (canon resource.rep $r))
84  (core func $new (canon resource.new $r))
85  (core func $drop (canon resource.drop $r))
86
87  (core module $m
88     (import "" "rep" (func $rep (param i32) (result i32)))
89     (import "" "new" (func $new (param i32) (result i32)))
90     (import "" "drop" (func $drop (param i32)))
91
92     (func $start
93       (local $r1 i32)
94       (local $r2 i32)
95       (local $r3 i32)
96       (local $r4 i32)
97
98       ;; resources assigned sequentially
99       (local.set $r1 (call $new (i32.const 100)))
100       (if (i32.ne (local.get $r1) (i32.const 1)) (then (unreachable)))
101
102       (local.set $r2 (call $new (i32.const 200)))
103       (if (i32.ne (local.get $r2) (i32.const 2)) (then (unreachable)))
104
105       (local.set $r3 (call $new (i32.const 300)))
106       (if (i32.ne (local.get $r3) (i32.const 3)) (then (unreachable)))
107
108       ;; representations all look good
109       (if (i32.ne (call $rep (local.get $r1)) (i32.const 100)) (then (unreachable)))
110       (if (i32.ne (call $rep (local.get $r2)) (i32.const 200)) (then (unreachable)))
111       (if (i32.ne (call $rep (local.get $r3)) (i32.const 300)) (then (unreachable)))
112
113       ;; reallocate r2
114       (call $drop (local.get $r2))
115       (local.set $r2 (call $new (i32.const 400)))
116
117       ;; should have reused index 3
118       (if (i32.ne (local.get $r2) (i32.const 2)) (then (unreachable)))
119
120       ;; representations all look good
121       (if (i32.ne (call $rep (local.get $r1)) (i32.const 100)) (then (unreachable)))
122       (if (i32.ne (call $rep (local.get $r2)) (i32.const 400)) (then (unreachable)))
123       (if (i32.ne (call $rep (local.get $r3)) (i32.const 300)) (then (unreachable)))
124
125       ;; deallocate, then reallocate
126       (call $drop (local.get $r1))
127       (call $drop (local.get $r2))
128       (call $drop (local.get $r3))
129
130       (local.set $r1 (call $new (i32.const 500)))
131       (local.set $r2 (call $new (i32.const 600)))
132       (local.set $r3 (call $new (i32.const 700)))
133
134       ;; representations all look good
135       (if (i32.ne (call $rep (local.get $r1)) (i32.const 500)) (then (unreachable)))
136       (if (i32.ne (call $rep (local.get $r2)) (i32.const 600)) (then (unreachable)))
137       (if (i32.ne (call $rep (local.get $r3)) (i32.const 700)) (then (unreachable)))
138
139       ;; indices should be lifo
140       (if (i32.ne (local.get $r1) (i32.const 3)) (then (unreachable)))
141       (if (i32.ne (local.get $r2) (i32.const 2)) (then (unreachable)))
142       (if (i32.ne (local.get $r3) (i32.const 1)) (then (unreachable)))
143
144       ;; bump one more time
145       (local.set $r4 (call $new (i32.const 800)))
146       (if (i32.ne (local.get $r4) (i32.const 4)) (then (unreachable)))
147
148       ;; deallocate everything
149       (call $drop (local.get $r1))
150       (call $drop (local.get $r2))
151       (call $drop (local.get $r3))
152       (call $drop (local.get $r4))
153     )
154
155     (start $start)
156  )
157  (core instance (instantiate $m
158     (with "" (instance
159       (export "rep" (func $rep))
160       (export "new" (func $new))
161       (export "drop" (func $drop))
162     ))
163  ))
164)
165
166(assert_unlinkable
167  (component
168    (import "host" (instance
169      (export "missing" (type (sub resource)))
170    ))
171  )
172  "was not found")
173(assert_unlinkable
174  (component
175    (import "host" (instance
176      (export "return-three" (type (sub resource)))
177    ))
178  )
179  "expected resource found func")
180
181;; all resources can be uniquely imported
182(component
183  (import "host" (instance
184    (export "resource1" (type (sub resource)))
185    (export "resource2" (type (sub resource)))
186    (export "resource1-again" (type (sub resource)))
187  ))
188)
189
190;; equality constraints also work
191(component
192  (import "host" (instance
193    (export "resource1" (type $r1 (sub resource)))
194    (export "resource2" (type (sub resource)))
195    (export "resource1-again" (type (eq $r1)))
196  ))
197)
198
199;; equality constraints are checked if resources are supplied
200(assert_unlinkable
201  (component
202    (import "host" (instance
203      (export "resource1" (type (sub resource)))
204      (export "resource2" (type $r1 (sub resource)))
205      (export "resource1-again" (type (eq $r1)))
206    ))
207  )
208  "mismatched resource types")
209
210;; equality constraints mean that types don't need to be supplied
211(component
212  (import "host" (instance
213    (export "resource1" (type $r1 (sub resource)))
214    (export "resource2" (type (sub resource)))
215    (export "this-name-is-not-provided-in-the-wast-harness" (type (eq $r1)))
216  ))
217)
218
219;; simple properties of handles
220(component
221  (import "host" (instance $host
222    (export "resource1" (type $r (sub resource)))
223    (export "[constructor]resource1" (func (param "r" u32) (result (own $r))))
224    (export "[static]resource1.assert" (func (param "r" (own $r)) (param "rep" u32)))
225  ))
226  (alias export $host "resource1" (type $r))
227  (alias export $host "[constructor]resource1" (func $ctor))
228  (alias export $host "[static]resource1.assert" (func $assert))
229
230  (core func $drop (canon resource.drop $r))
231  (core func $ctor (canon lower (func $ctor)))
232  (core func $assert (canon lower (func $assert)))
233
234  (core module $m
235     (import "" "drop" (func $drop (param i32)))
236     (import "" "ctor" (func $ctor (param i32) (result i32)))
237     (import "" "assert" (func $assert (param i32 i32)))
238
239     (func $start
240       (local $r1 i32)
241       (local $r2 i32)
242       (local.set $r1 (call $ctor (i32.const 100)))
243       (local.set $r2 (call $ctor (i32.const 200)))
244
245       ;; assert r1/r2 are sequential
246       (if (i32.ne (local.get $r1) (i32.const 1)) (then (unreachable)))
247       (if (i32.ne (local.get $r2) (i32.const 2)) (then (unreachable)))
248
249       ;; reallocate r1 and it should be reassigned the same index
250       (call $drop (local.get $r1))
251       (local.set $r1 (call $ctor (i32.const 300)))
252       (if (i32.ne (local.get $r1) (i32.const 1)) (then (unreachable)))
253
254       ;; internal values should match
255       (call $assert (local.get $r1) (i32.const 300))
256       (call $assert (local.get $r2) (i32.const 200))
257     )
258
259     (start $start)
260  )
261  (core instance (instantiate $m
262     (with "" (instance
263       (export "drop" (func $drop))
264       (export "ctor" (func $ctor))
265       (export "assert" (func $assert))
266     ))
267  ))
268)
269
270;; Using an index that has never been valid is a trap
271(component
272  (import "host" (instance $host
273    (export "resource1" (type $r (sub resource)))
274    (export "[static]resource1.assert" (func (param "r" (own $r)) (param "rep" u32)))
275  ))
276  (alias export $host "resource1" (type $r))
277  (alias export $host "[static]resource1.assert" (func $assert))
278  (core func $assert (canon lower (func $assert)))
279
280  (core module $m
281     (import "" "assert" (func $assert (param i32 i32)))
282
283     (func (export "f")
284       (call $assert (i32.const 0) (i32.const 0))
285     )
286  )
287  (core instance $i (instantiate $m
288     (with "" (instance
289       (export "assert" (func $assert))
290     ))
291  ))
292
293  (func (export "f") (canon lift (core func $i "f")))
294)
295
296(assert_trap (invoke "f") "unknown handle index")
297
298;; Using an index which was previously valid but no longer valid is also a trap.
299(component
300  (import "host" (instance $host
301    (export "resource1" (type $r (sub resource)))
302    (export "[constructor]resource1" (func (param "r" u32) (result (own $r))))
303    (export "[static]resource1.assert" (func (param "r" (own $r)) (param "rep" u32)))
304  ))
305  (alias export $host "[constructor]resource1" (func $ctor))
306  (alias export $host "[static]resource1.assert" (func $assert))
307
308  (core func $assert (canon lower (func $assert)))
309  (core func $ctor (canon lower (func $ctor)))
310
311  (core module $m
312     (import "" "assert" (func $assert (param i32 i32)))
313     (import "" "ctor" (func $ctor (param i32) (result i32)))
314
315     (global $handle (mut i32) i32.const 0)
316
317     (func (export "f")
318        (global.set $handle (call $ctor (i32.const 100)))
319        (call $assert (global.get $handle) (i32.const 100))
320     )
321
322     (func (export "f2")
323        (call $assert (global.get $handle) (i32.const 100))
324     )
325  )
326  (core instance $i (instantiate $m
327     (with "" (instance
328       (export "assert" (func $assert))
329       (export "ctor" (func $ctor))
330     ))
331  ))
332
333  (func (export "f") (canon lift (core func $i "f")))
334  (func (export "f2") (canon lift (core func $i "f2")))
335)
336
337(assert_return (invoke "f"))
338(assert_trap (invoke "f2") "unknown handle index")
339
340;; Also invalid to pass a previously valid handle to the drop intrinsic
341(component
342  (import "host" (instance $host
343    (export "resource1" (type $r (sub resource)))
344    (export "[constructor]resource1" (func (param "r" u32) (result (own $r))))
345  ))
346  (alias export $host "resource1" (type $r))
347  (alias export $host "[constructor]resource1" (func $ctor))
348
349  (core func $drop (canon resource.drop $r))
350  (core func $ctor (canon lower (func $ctor)))
351
352  (core module $m
353     (import "" "drop" (func $drop (param i32)))
354     (import "" "ctor" (func $ctor (param i32) (result i32)))
355
356     (global $handle (mut i32) i32.const 0)
357
358     (func (export "f")
359        (global.set $handle (call $ctor (i32.const 100)))
360        (call $drop (global.get $handle))
361     )
362
363     (func (export "f2")
364        (call $drop (global.get $handle))
365     )
366  )
367  (core instance $i (instantiate $m
368     (with "" (instance
369       (export "ctor" (func $ctor))
370       (export "drop" (func $drop))
371     ))
372  ))
373
374  (func (export "f") (canon lift (core func $i "f")))
375  (func (export "f2") (canon lift (core func $i "f2")))
376)
377
378(assert_return (invoke "f"))
379(assert_trap (invoke "f2") "unknown handle index")
380
381;; If an inner component instantiates a resource then an outer component
382;; should not implicitly have access to that resource.
383(component
384  (import "host" (instance $host
385    (export "resource1" (type $r (sub resource)))
386    (export "[constructor]resource1" (func (param "r" u32) (result (own $r))))
387  ))
388
389  ;; an inner component which upon instantiation will invoke the constructor,
390  ;; assert that it's zero, and then forget about it.
391  (component $inner
392    (import "host" (instance $host
393      (export "resource1" (type $r (sub resource)))
394      (export "[constructor]resource1" (func (param "r" u32) (result (own $r))))
395    ))
396    (alias export $host "[constructor]resource1" (func $ctor))
397
398    (core func $ctor (canon lower (func $ctor)))
399
400    (core module $m
401      (import "" "ctor" (func $ctor (param i32) (result i32)))
402
403      (func $start
404        (if (i32.ne (call $ctor (i32.const 100)) (i32.const 0)) (then (unreachable)))
405      )
406    )
407    (core instance $i (instantiate $m
408       (with "" (instance (export "ctor" (func $ctor))))
409    ))
410  )
411  (instance $i (instantiate $inner (with "host" (instance $host))))
412
413  ;; the rest of this component which is a single function that invokes `drop`
414  ;; for index 0. The index 0 should be valid within the above component, but
415  ;; it is not valid within this component
416  (alias export $host "resource1" (type $r))
417  (core func $drop (canon resource.drop $r))
418
419  (core module $m
420     (import "" "drop" (func $drop (param i32)))
421
422     (func (export "f")
423        (call $drop (i32.const 0))
424     )
425  )
426  (core instance $i (instantiate $m
427     (with "" (instance
428       (export "drop" (func $drop))
429     ))
430  ))
431
432  (func (export "f") (canon lift (core func $i "f")))
433)
434
435(assert_trap (invoke "f") "unknown handle index")
436
437;; Same as the above test, but for resources defined within a component
438(component
439  (component $inner
440    (type $r (resource (rep i32)))
441
442    (core func $ctor (canon resource.new $r))
443
444    (core module $m
445      (import "" "ctor" (func $ctor (param i32) (result i32)))
446
447      (func $start
448        (if (i32.ne (call $ctor (i32.const 100)) (i32.const 1)) (then (unreachable)))
449      )
450      (start $start)
451    )
452    (core instance $i (instantiate $m
453       (with "" (instance (export "ctor" (func $ctor))))
454    ))
455    (export "r" (type $r))
456  )
457  (instance $i (instantiate $inner))
458
459  ;; the rest of this component which is a single function that invokes `drop`
460  ;; for index 2. The index 2 should be valid within the above component, but
461  ;; it is not valid within this component
462  (alias export $i "r" (type $r))
463  (core func $drop (canon resource.drop $r))
464
465  (core module $m
466     (import "" "drop" (func $drop (param i32)))
467
468     (func (export "f")
469        (call $drop (i32.const 2))
470     )
471  )
472  (core instance $i (instantiate $m
473     (with "" (instance
474       (export "drop" (func $drop))
475     ))
476  ))
477
478  (func (export "f") (canon lift (core func $i "f")))
479)
480
481(assert_trap (invoke "f") "unknown handle index 2")
482
483;; Each instantiation of a component generates a unique resource type, so
484;; allocating in one component and deallocating in another should fail.
485(component
486  (component $inner
487    (type $r (resource (rep i32)))
488
489    (core func $ctor (canon resource.new $r))
490    (core func $drop (canon resource.drop $r))
491
492    (core module $m
493      (import "" "ctor" (func $ctor (param i32) (result i32)))
494      (import "" "drop" (func $drop (param i32)))
495
496      (func (export "alloc")
497        (if (i32.ne (call $ctor (i32.const 100)) (i32.const 1)) (then (unreachable)))
498      )
499      (func (export "dealloc")
500        (call $drop (i32.const 1))
501      )
502    )
503    (core instance $i (instantiate $m
504      (with "" (instance
505        (export "ctor" (func $ctor))
506        (export "drop" (func $drop))
507      ))
508    ))
509    (func (export "alloc") (canon lift (core func $i "alloc")))
510    (func (export "dealloc") (canon lift (core func $i "dealloc")))
511  )
512  (instance $i1 (instantiate $inner))
513  (instance $i2 (instantiate $inner))
514
515  (alias export $i1 "alloc" (func $alloc_in_1))
516  (alias export $i1 "dealloc" (func $dealloc_in_1))
517  (alias export $i2 "alloc" (func $alloc_in_2))
518  (alias export $i2 "dealloc" (func $dealloc_in_2))
519
520  (export "alloc-in1" (func $alloc_in_1))
521  (export "dealloc-in1" (func $dealloc_in_1))
522  (export "alloc-in2" (func $alloc_in_2))
523  (export "dealloc-in2" (func $dealloc_in_2))
524)
525
526(assert_return (invoke "alloc-in1"))
527(assert_return (invoke "dealloc-in1"))
528(assert_return (invoke "alloc-in1"))
529(assert_return (invoke "alloc-in2"))
530(assert_return (invoke "dealloc-in2"))
531(assert_trap (invoke "dealloc-in2") "unknown handle index")
532
533;; Same as above, but the same host resource type is imported into a
534;; component that is instantiated twice. Each component instance should
535;; receive different tables tracking resources so a resource allocated in one
536;; should not be visible in the other.
537(component
538  (import "host" (instance $host
539    (export "resource1" (type $r (sub resource)))
540    (export "[constructor]resource1" (func (param "r" u32) (result (own $r))))
541  ))
542  (alias export $host "resource1" (type $r))
543  (alias export $host "[constructor]resource1" (func $ctor))
544
545  (component $inner
546    (import "r" (type $r (sub resource)))
547    (import "[constructor]r" (func $ctor (param "r" u32) (result (own $r))))
548
549    (core func $ctor (canon lower (func $ctor)))
550    (core func $drop (canon resource.drop $r))
551
552    (core module $m
553      (import "" "ctor" (func $ctor (param i32) (result i32)))
554      (import "" "drop" (func $drop (param i32)))
555
556      (func (export "alloc")
557        (if (i32.ne (call $ctor (i32.const 100)) (i32.const 1)) (then (unreachable)))
558      )
559      (func (export "dealloc")
560        (call $drop (i32.const 1))
561      )
562    )
563    (core instance $i (instantiate $m
564      (with "" (instance
565        (export "ctor" (func $ctor))
566        (export "drop" (func $drop))
567      ))
568    ))
569    (func (export "alloc") (canon lift (core func $i "alloc")))
570    (func (export "dealloc") (canon lift (core func $i "dealloc")))
571  )
572  (instance $i1 (instantiate $inner
573    (with "r" (type $r))
574    (with "[constructor]r" (func $ctor))
575  ))
576  (instance $i2 (instantiate $inner
577    (with "r" (type $r))
578    (with "[constructor]r" (func $ctor))
579  ))
580
581  (alias export $i1 "alloc" (func $alloc_in_1))
582  (alias export $i1 "dealloc" (func $dealloc_in_1))
583  (alias export $i2 "alloc" (func $alloc_in_2))
584  (alias export $i2 "dealloc" (func $dealloc_in_2))
585
586  (export "alloc-in1" (func $alloc_in_1))
587  (export "dealloc-in1" (func $dealloc_in_1))
588  (export "alloc-in2" (func $alloc_in_2))
589  (export "dealloc-in2" (func $dealloc_in_2))
590)
591
592(assert_return (invoke "alloc-in1"))
593(assert_return (invoke "dealloc-in1"))
594(assert_return (invoke "alloc-in1"))
595(assert_return (invoke "alloc-in2"))
596(assert_return (invoke "dealloc-in2"))
597(assert_trap (invoke "dealloc-in2") "unknown handle index")
598
599;; Multiple copies of intrinsics all work
600(component
601  (type $r (resource (rep i32)))
602
603  (core func $new1 (canon resource.new $r))
604  (core func $new2 (canon resource.new $r))
605  (core func $drop1 (canon resource.drop $r))
606  (core func $drop2 (canon resource.drop $r))
607
608  (core module $m
609    (import "" "new1" (func $new1 (param i32) (result i32)))
610    (import "" "new2" (func $new2 (param i32) (result i32)))
611    (import "" "drop1" (func $drop1 (param i32)))
612    (import "" "drop2" (func $drop2 (param i32)))
613
614    (func $start
615      ;; 2x2 matrix of pairing new/drop
616      (call $drop1 (call $new1 (i32.const 101)))
617      (call $drop2 (call $new1 (i32.const 102)))
618      (call $drop1 (call $new2 (i32.const 103)))
619      (call $drop2 (call $new2 (i32.const 104)))
620
621      ;; should be referencing the same namespace
622      (if (i32.ne (call $new1 (i32.const 105)) (i32.const 1)) (then (unreachable)))
623      (if (i32.ne (call $new2 (i32.const 105)) (i32.const 2)) (then (unreachable)))
624
625      ;; use different drops out of order
626      (call $drop2 (i32.const 1))
627      (call $drop1 (i32.const 2))
628    )
629
630    (start $start)
631  )
632
633  (core instance (instantiate $m
634    (with "" (instance
635      (export "new1" (func $new1))
636      (export "new2" (func $new2))
637      (export "drop1" (func $drop1))
638      (export "drop2" (func $drop2))
639    ))
640  ))
641)
642
643;; u32::MAX isn't special in some weird way, it's just probably always invalid
644;; because that's a lot of handles.
645(component
646  (type $r (resource (rep i32)))
647
648  (core func $drop (canon resource.drop $r))
649
650  (core module $m
651    (import "" "drop" (func $drop (param i32)))
652
653    (func (export "f")
654      (call $drop (i32.const 0xffffffff))
655    )
656  )
657
658  (core instance $i (instantiate $m
659    (with "" (instance
660      (export "drop" (func $drop))
661    ))
662  ))
663  (func (export "f") (canon lift (core func $i "f")))
664)
665(assert_trap (invoke "f") "unknown handle index")
666
667;; Test behavior of running a destructor for local resources
668(component
669  (core module $m1
670    (global $drops (mut i32) i32.const 0)
671    (global $last_drop (mut i32) i32.const -1)
672
673    (func (export "dtor") (param i32)
674      (global.set $drops (i32.add (global.get $drops) (i32.const 1)))
675      (global.set $last_drop (local.get 0))
676    )
677    (func (export "drops") (result i32) global.get $drops)
678    (func (export "last-drop") (result i32) global.get $last_drop)
679  )
680  (core instance $i1 (instantiate $m1))
681
682  (type $r1 (resource (rep i32)))
683  (type $r2 (resource (rep i32) (dtor (func $i1 "dtor"))))
684
685  (core func $drop1 (canon resource.drop $r1))
686  (core func $drop2 (canon resource.drop $r2))
687  (core func $new1 (canon resource.new $r1))
688  (core func $new2 (canon resource.new $r2))
689
690  (core module $m2
691    (import "" "drop1" (func $drop1 (param i32)))
692    (import "" "drop2" (func $drop2 (param i32)))
693    (import "" "new1" (func $new1 (param i32) (result i32)))
694    (import "" "new2" (func $new2 (param i32) (result i32)))
695    (import "i1" "drops" (func $drops (result i32)))
696    (import "i1" "last-drop" (func $last-drop (result i32)))
697
698    (func $start
699      (local $r1 i32)
700      (local $r2 i32)
701
702      (local.set $r1 (call $new1 (i32.const 100)))
703      (local.set $r2 (call $new2 (i32.const 200)))
704
705      ;; indexes start at 1 and while they have distinct types they should be
706      ;; within the same table.
707      (if (i32.ne (local.get $r1) (i32.const 1)) (then (unreachable)))
708      (if (i32.ne (local.get $r2) (i32.const 2)) (then (unreachable)))
709
710      ;; nothing should be dropped yet
711      (if (i32.ne (call $drops) (i32.const 0)) (then (unreachable)))
712      (if (i32.ne (call $last-drop) (i32.const -1)) (then (unreachable)))
713
714      ;; dropping a resource without a destructor is ok, but shouldn't tamper
715      ;; with anything.
716      (call $drop1 (local.get $r1))
717      (if (i32.ne (call $drops) (i32.const 0)) (then (unreachable)))
718      (if (i32.ne (call $last-drop) (i32.const -1)) (then (unreachable)))
719
720      ;; drop r2 which should record a drop and additionally record the private
721      ;; representation value which was dropped
722      (call $drop2 (local.get $r2))
723      (if (i32.ne (call $drops) (i32.const 1)) (then (unreachable)))
724      (if (i32.ne (call $last-drop) (i32.const 200)) (then (unreachable)))
725
726      ;; do it all over again
727      (local.set $r2 (call $new2 (i32.const 300)))
728      (call $drop2 (local.get $r2))
729      (if (i32.ne (call $drops) (i32.const 2)) (then (unreachable)))
730      (if (i32.ne (call $last-drop) (i32.const 300)) (then (unreachable)))
731    )
732
733    (start $start)
734  )
735
736  (core instance $i2 (instantiate $m2
737    (with "" (instance
738      (export "drop1" (func $drop1))
739      (export "drop2" (func $drop2))
740      (export "new1" (func $new1))
741      (export "new2" (func $new2))
742    ))
743    (with "i1" (instance $i1))
744  ))
745)
746
747;; Test dropping a host resource
748(component
749  (import "host" (instance $host
750    (export "resource1" (type $r (sub resource)))
751    (export "[constructor]resource1" (func (param "r" u32) (result (own $r))))
752    (export "[static]resource1.last-drop" (func (result u32)))
753    (export "[static]resource1.drops" (func (result u32)))
754  ))
755
756  (alias export $host "resource1" (type $r))
757  (alias export $host "[constructor]resource1" (func $ctor))
758  (alias export $host "[static]resource1.last-drop" (func $last-drop))
759  (alias export $host "[static]resource1.drops" (func $drops))
760
761  (core func $drop (canon resource.drop $r))
762  (core func $ctor (canon lower (func $ctor)))
763  (core func $last-drop (canon lower (func $last-drop)))
764  (core func $drops (canon lower (func $drops)))
765
766  (core module $m
767    (import "" "drop" (func $drop (param i32)))
768    (import "" "ctor" (func $ctor (param i32) (result i32)))
769    (import "" "last-drop" (func $last-drop (result i32)))
770    (import "" "drops" (func $raw-drops (result i32)))
771
772    (global $init-drop-cnt (mut i32) i32.const 0)
773
774    (func $drops (result i32)
775      (i32.sub (call $raw-drops) (global.get $init-drop-cnt))
776    )
777
778    (func $start
779      (local $r1 i32)
780      (global.set $init-drop-cnt (call $raw-drops))
781
782      (local.set $r1 (call $ctor (i32.const 100)))
783
784      ;; should be no drops yet
785      (if (i32.ne (call $drops) (i32.const 0)) (then (unreachable)))
786
787      ;; should count a drop
788      (call $drop (local.get $r1))
789      (if (i32.ne (call $drops) (i32.const 1)) (then (unreachable)))
790      (if (i32.ne (call $last-drop) (i32.const 100)) (then (unreachable)))
791
792      ;; do it again to be sure
793      (local.set $r1 (call $ctor (i32.const 200)))
794      (call $drop (local.get $r1))
795      (if (i32.ne (call $drops) (i32.const 2)) (then (unreachable)))
796      (if (i32.ne (call $last-drop) (i32.const 200)) (then (unreachable)))
797    )
798
799    (start $start)
800  )
801  (core instance (instantiate $m
802    (with "" (instance
803      (export "drop" (func $drop))
804      (export "ctor" (func $ctor))
805      (export "last-drop" (func $last-drop))
806      (export "drops" (func $drops))
807    ))
808  ))
809)
810
811;; Test some bare-bones basics of borrowed resources
812(component
813  (import "host" (instance $host
814    (export "resource1" (type $r (sub resource)))
815    (export "[constructor]resource1" (func (param "r" u32) (result (own $r))))
816    (export "[method]resource1.simple" (func (param "self" (borrow $r)) (param "rep" u32)))
817    (export "[method]resource1.take-borrow" (func (param "self" (borrow $r)) (param "b" (borrow $r))))
818    (export "[method]resource1.take-own" (func (param "self" (borrow $r)) (param "b" (own $r))))
819  ))
820
821  (alias export $host "resource1" (type $r))
822  (alias export $host "[constructor]resource1" (func $ctor))
823  (alias export $host "[method]resource1.simple" (func $simple))
824  (alias export $host "[method]resource1.take-borrow" (func $take-borrow))
825  (alias export $host "[method]resource1.take-own" (func $take-own))
826
827  (core func $drop (canon resource.drop $r))
828  (core func $ctor (canon lower (func $ctor)))
829  (core func $simple (canon lower (func $simple)))
830  (core func $take-own (canon lower (func $take-own)))
831  (core func $take-borrow (canon lower (func $take-borrow)))
832
833  (core module $m
834    (import "" "drop" (func $drop (param i32)))
835    (import "" "ctor" (func $ctor (param i32) (result i32)))
836    (import "" "simple" (func $simple (param i32 i32)))
837    (import "" "take-own" (func $take-own (param i32 i32)))
838    (import "" "take-borrow" (func $take-borrow (param i32 i32)))
839
840
841    (func $start
842      (local $r1 i32)
843      (local $r2 i32)
844      (local.set $r1 (call $ctor (i32.const 100)))
845      (local.set $r2 (call $ctor (i32.const 200)))
846
847      (call $simple (local.get $r1) (i32.const 100))
848      (call $simple (local.get $r1) (i32.const 100))
849      (call $simple (local.get $r2) (i32.const 200))
850      (call $simple (local.get $r1) (i32.const 100))
851      (call $simple (local.get $r2) (i32.const 200))
852      (call $simple (local.get $r2) (i32.const 200))
853
854      (call $drop (local.get $r1))
855      (call $drop (local.get $r2))
856
857
858      (local.set $r1 (call $ctor (i32.const 200)))
859      (local.set $r2 (call $ctor (i32.const 300)))
860      (call $take-borrow (local.get $r1) (local.get $r2))
861      (call $take-borrow (local.get $r2) (local.get $r1))
862      (call $take-borrow (local.get $r1) (local.get $r1))
863      (call $take-borrow (local.get $r2) (local.get $r2))
864
865      (call $take-own (local.get $r1) (call $ctor (i32.const 400)))
866      (call $take-own (local.get $r2) (call $ctor (i32.const 500)))
867      (call $take-own (local.get $r2) (local.get $r1))
868      (call $drop (local.get $r2))
869
870      ;; table should be empty at this point, so a fresh allocation should get
871      ;; index 2
872      (if (i32.ne (call $ctor (i32.const 600)) (i32.const 1)) (then (unreachable)))
873    )
874
875    (start $start)
876  )
877  (core instance (instantiate $m
878    (with "" (instance
879      (export "drop" (func $drop))
880      (export "ctor" (func $ctor))
881      (export "simple" (func $simple))
882      (export "take-own" (func $take-own))
883      (export "take-borrow" (func $take-borrow))
884    ))
885  ))
886)
887
888;; Cannot pass out an owned resource when it's borrowed by the same call
889(component
890  (import "host" (instance $host
891    (export "resource1" (type $r (sub resource)))
892    (export "[constructor]resource1" (func (param "r" u32) (result (own $r))))
893    (export "[method]resource1.take-own" (func (param "self" (borrow $r)) (param "b" (own $r))))
894  ))
895
896  (alias export $host "resource1" (type $r))
897  (alias export $host "[constructor]resource1" (func $ctor))
898  (alias export $host "[method]resource1.take-own" (func $take-own))
899
900  (core func $drop (canon resource.drop $r))
901  (core func $ctor (canon lower (func $ctor)))
902  (core func $take-own (canon lower (func $take-own)))
903
904  (core module $m
905    (import "" "drop" (func $drop (param i32)))
906    (import "" "ctor" (func $ctor (param i32) (result i32)))
907    (import "" "take-own" (func $take-own (param i32 i32)))
908
909
910    (func (export "f")
911      (local $r i32)
912      (local.set $r (call $ctor (i32.const 100)))
913      (call $take-own (local.get $r) (local.get $r))
914    )
915  )
916  (core instance $i (instantiate $m
917    (with "" (instance
918      (export "drop" (func $drop))
919      (export "ctor" (func $ctor))
920      (export "take-own" (func $take-own))
921    ))
922  ))
923
924  (func (export "f") (canon lift (core func $i "f")))
925)
926
927(assert_trap (invoke "f") "cannot remove owned resource while borrowed")
928
929;; Borrows must actually exist
930(component
931  (import "host" (instance $host
932    (export "resource1" (type $r (sub resource)))
933    (export "[method]resource1.simple" (func (param "self" (borrow $r)) (param "b" u32)))
934  ))
935
936  (alias export $host "resource1" (type $r))
937  (alias export $host "[method]resource1.simple" (func $simple))
938
939  (core func $drop (canon resource.drop $r))
940  (core func $simple (canon lower (func $simple)))
941
942  (core module $m
943    (import "" "drop" (func $drop (param i32)))
944    (import "" "simple" (func $simple (param i32 i32)))
945
946
947    (func (export "f")
948      (call $simple (i32.const 0) (i32.const 0))
949    )
950  )
951  (core instance $i (instantiate $m
952    (with "" (instance
953      (export "drop" (func $drop))
954      (export "simple" (func $simple))
955    ))
956  ))
957
958  (func (export "f") (canon lift (core func $i "f")))
959)
960
961(assert_trap (invoke "f") "unknown handle index 0")
962
963(component
964  (component $A
965    (type $t' (resource (rep i32)))
966    (export $t "t" (type $t'))
967
968    (core func $ctor (canon resource.new $t))
969    (core func $dtor (canon resource.drop $t))
970    (core func $rep (canon resource.rep $t))
971
972    (core module $m
973      (import "" "dtor" (func $dtor (param i32)))
974      (import "" "rep" (func $rep (param i32) (result i32)))
975
976      (func (export "[method]t.assert") (param i32 i32)
977        (if (i32.ne (local.get 0) (local.get 1)) (then (unreachable)))
978      )
979      (func (export "[static]t.assert-own") (param i32 i32)
980        (if (i32.ne (call $rep (local.get 0)) (local.get 1)) (then (unreachable)))
981        (call $dtor (local.get 0))
982      )
983    )
984    (core instance $i (instantiate $m
985      (with "" (instance
986        (export "dtor" (func $dtor))
987        (export "rep" (func $rep))
988      ))
989    ))
990    (func (export "[constructor]t") (param "x" u32) (result (own $t))
991      (canon lift (core func $ctor)))
992    (func (export "[method]t.assert") (param "self" (borrow $t)) (param "x" u32)
993      (canon lift (core func $i "[method]t.assert")))
994    (func (export "[static]t.assert-own") (param "self" (own $t)) (param "x" u32)
995      (canon lift (core func $i "[static]t.assert-own")))
996  )
997  (instance $a (instantiate $A))
998
999  (component $B
1000    (import "a" (instance $i
1001      (export "t" (type $t (sub resource)))
1002      (export "[constructor]t" (func (param "x" u32) (result (own $t))))
1003      (export "[method]t.assert" (func (param "self" (borrow $t)) (param "x" u32)))
1004      (export "[static]t.assert-own" (func (param "self" (own $t)) (param "x" u32)))
1005    ))
1006
1007    (alias export $i "t" (type $t))
1008    (alias export $i "[constructor]t" (func $ctor))
1009    (alias export $i "[method]t.assert" (func $assert-borrow))
1010    (alias export $i "[static]t.assert-own" (func $assert-own))
1011
1012    (core func $ctor (canon lower (func $ctor)))
1013    (core func $dtor (canon resource.drop $t))
1014    (core func $assert-own (canon lower (func $assert-own)))
1015    (core func $assert-borrow (canon lower (func $assert-borrow)))
1016
1017    (core module $m
1018      (import "" "ctor" (func $ctor (param i32) (result i32)))
1019      (import "" "dtor" (func $dtor (param i32)))
1020      (import "" "assert-own" (func $assert-own (param i32 i32)))
1021      (import "" "assert-borrow" (func $assert-borrow (param i32 i32)))
1022
1023      (func (export "f")
1024        (local $r1 i32)
1025        (local $r2 i32)
1026
1027        (local.set $r1 (call $ctor (i32.const 100)))
1028        (local.set $r2 (call $ctor (i32.const 200)))
1029
1030        (if (i32.ne (local.get $r1) (i32.const 1)) (then (unreachable)))
1031        (if (i32.ne (local.get $r2) (i32.const 2)) (then (unreachable)))
1032
1033        (call $assert-borrow (local.get $r2) (i32.const 200))
1034        (call $assert-borrow (local.get $r1) (i32.const 100))
1035
1036        (call $assert-own (local.get $r2) (i32.const 200))
1037        (call $dtor (local.get $r1))
1038      )
1039    )
1040    (core instance $i (instantiate $m
1041      (with "" (instance
1042        (export "ctor" (func $ctor))
1043        (export "dtor" (func $dtor))
1044        (export "assert-own" (func $assert-own))
1045        (export "assert-borrow" (func $assert-borrow))
1046      ))
1047    ))
1048    (func (export "f") (canon lift (core func $i "f")))
1049  )
1050  (instance $b (instantiate $B (with "a" (instance $a))))
1051  (export "f" (func $b "f"))
1052)
1053
1054(assert_return (invoke "f"))
1055
1056;; Test destructor behavior when using the wrong resource type
1057(component definition $C
1058  (type $r1 (resource (rep i32)))
1059  (type $r2 (resource (rep i32)))
1060
1061  (core func $drop1 (canon resource.drop $r1))
1062  (core func $drop2 (canon resource.drop $r2))
1063  (core func $new1 (canon resource.new $r1))
1064  (core func $new2 (canon resource.new $r2))
1065
1066  (core module $m2
1067    (import "" "drop1" (func $drop1 (param i32)))
1068    (import "" "drop2" (func $drop2 (param i32)))
1069    (import "" "new1" (func $new1 (param i32) (result i32)))
1070    (import "" "new2" (func $new2 (param i32) (result i32)))
1071
1072    (func (export "drop-r1-as-r2") (call $drop2 (call $new1 (i32.const 100))))
1073    (func (export "return-r1-as-r2") (result i32) (call $new1 (i32.const 100)))
1074  )
1075
1076  (core instance $i2 (instantiate $m2
1077    (with "" (instance
1078      (export "drop1" (func $drop1))
1079      (export "drop2" (func $drop2))
1080      (export "new1" (func $new1))
1081      (export "new2" (func $new2))
1082    ))
1083  ))
1084
1085  (export $r2' "r2" (type $r2))
1086  (func (export "drop-r1-as-r2") (canon lift (core func $i2 "drop-r1-as-r2")))
1087  (func (export "return-r1-as-r2") (result (own $r2')) (canon lift (core func $i2 "return-r1-as-r2")))
1088)
1089
1090(component instance $C1 $C)
1091(assert_trap (invoke "drop-r1-as-r2") "handle index 1 used with the wrong type, expected guest-defined resource but found a different guest-defined resource")
1092(component instance $C1 $C)
1093(assert_trap (invoke "return-r1-as-r2") "handle index 1 used with the wrong type, expected guest-defined resource but found a different guest-defined resource")
1094
1095;; Test that `resource.rep` is exempt from may-leave checks
1096(component
1097  (type $r (resource (rep i32)))
1098  (core func $resource.new (canon resource.new $r))
1099  (core func $resource.rep (canon resource.rep $r))
1100
1101  (core module $DM
1102    (import "" "resource.new" (func $resource.new (param i32) (result i32)))
1103    (import "" "resource.rep" (func $resource.rep (param i32) (result i32)))
1104
1105    (global $g (mut i32) (i32.const 0))
1106
1107    (func (export "run")
1108      (global.set $g (call $resource.new (i32.const 42)))
1109    )
1110    (func (export "post-return")
1111      (i32.eq
1112        (call $resource.rep (global.get $g))
1113        (i32.const 42))
1114      if return end
1115      unreachable
1116    )
1117  )
1118  (core instance $dm (instantiate $DM (with "" (instance
1119    (export "resource.new" (func $resource.new))
1120    (export "resource.rep" (func $resource.rep))
1121  ))))
1122  (func (export "run")
1123    (canon lift (core func $dm "run") (post-return (func $dm "post-return"))))
1124)
1125
1126(assert_return (invoke "run"))
1127