1 #![cfg(not(miri))]
2 
3 use wasmtime::Result;
4 use wasmtime::component::*;
5 use wasmtime::{Config, Engine, Store, Trap};
6 
7 #[test]
host_resource_types() -> Result<()>8 fn host_resource_types() -> Result<()> {
9     let engine = super::engine();
10     let c = Component::new(
11         &engine,
12         r#"
13             (component
14                 (import "t" (type $t (sub resource)))
15                 (import "u" (type $u (sub resource)))
16 
17                 (export "t1" (type $t))
18                 (export "t2" (type $t))
19                 (export "u1" (type $u))
20                 (export "u2" (type $u))
21 
22                 (component $c
23                     (import "r" (type $r (sub resource)))
24                     (export "r1" (type $r))
25                 )
26                 (instance $i1 (instantiate $c (with "r" (type $t))))
27                 (instance $i2 (instantiate $c (with "r" (type $t))))
28                 (export "t3" (type $i1 "r1"))
29                 (export "t4" (type $i2 "r1"))
30             )
31         "#,
32     )?;
33 
34     struct T;
35     struct U;
36     assert!(ResourceType::host::<T>() != ResourceType::host::<U>());
37 
38     let mut store = Store::new(&engine, ());
39     let mut linker = Linker::new(&engine);
40     linker
41         .root()
42         .resource("t", ResourceType::host::<T>(), |_, _| Ok(()))?;
43     linker
44         .root()
45         .resource("u", ResourceType::host::<U>(), |_, _| Ok(()))?;
46     let i = linker.instantiate(&mut store, &c)?;
47     let t1 = i.get_resource(&mut store, "t1").unwrap();
48     let t2 = i.get_resource(&mut store, "t2").unwrap();
49     let t3 = i.get_resource(&mut store, "t3").unwrap();
50     let t4 = i.get_resource(&mut store, "t4").unwrap();
51     let u1 = i.get_resource(&mut store, "u1").unwrap();
52     let u2 = i.get_resource(&mut store, "u2").unwrap();
53 
54     assert_eq!(t1, ResourceType::host::<T>());
55     assert_eq!(t2, ResourceType::host::<T>());
56     assert_eq!(t3, ResourceType::host::<T>());
57     assert_eq!(t4, ResourceType::host::<T>());
58     assert_eq!(u1, ResourceType::host::<U>());
59     assert_eq!(u2, ResourceType::host::<U>());
60     Ok(())
61 }
62 
63 #[test]
guest_resource_types() -> Result<()>64 fn guest_resource_types() -> Result<()> {
65     let engine = super::engine();
66     let c = Component::new(
67         &engine,
68         r#"
69             (component
70                 (type $t (resource (rep i32)))
71                 (type $u (resource (rep i32)))
72 
73                 (export "t1" (type $t))
74                 (export "t2" (type $t))
75                 (export "u1" (type $u))
76                 (export "u2" (type $u))
77 
78                 (component $c
79                     (import "r" (type $r (sub resource)))
80                     (export "r1" (type $r))
81                 )
82                 (instance $i1 (instantiate $c (with "r" (type $t))))
83                 (instance $i2 (instantiate $c (with "r" (type $t))))
84                 (export "t3" (type $i1 "r1"))
85                 (export "t4" (type $i2 "r1"))
86             )
87         "#,
88     )?;
89 
90     let mut store = Store::new(&engine, ());
91     let linker = Linker::new(&engine);
92     let i = linker.instantiate(&mut store, &c)?;
93     let t1 = i.get_resource(&mut store, "t1").unwrap();
94     let t2 = i.get_resource(&mut store, "t2").unwrap();
95     let t3 = i.get_resource(&mut store, "t3").unwrap();
96     let t4 = i.get_resource(&mut store, "t4").unwrap();
97     let u1 = i.get_resource(&mut store, "u1").unwrap();
98     let u2 = i.get_resource(&mut store, "u2").unwrap();
99 
100     assert_ne!(t1, u1);
101     assert_eq!(t1, t2);
102     assert_eq!(t1, t3);
103     assert_eq!(t1, t4);
104     assert_eq!(u1, u2);
105     Ok(())
106 }
107 
108 #[test]
resource_any() -> Result<()>109 fn resource_any() -> Result<()> {
110     let engine = super::engine();
111     let c = Component::new(
112         &engine,
113         r#"
114             (component
115                 (type $t' (resource (rep i32)))
116                 (type $u' (resource (rep i32)))
117 
118                 (export $t "t" (type $t'))
119                 (export $u "u" (type $u'))
120 
121                 (core func $t_ctor (canon resource.new $t))
122                 (core func $u_ctor (canon resource.new $u))
123 
124                 (func (export "[constructor]t") (param "x" u32) (result (own $t))
125                     (canon lift (core func $t_ctor)))
126                 (func (export "[constructor]u") (param "x" u32) (result (own $u))
127                     (canon lift (core func $u_ctor)))
128 
129                 (core func $t_drop (canon resource.drop $t))
130                 (core func $u_drop (canon resource.drop $u))
131 
132                 (func (export "drop-t") (param "x" (own $t))
133                     (canon lift (core func $t_drop)))
134                 (func (export "drop-u") (param "x" (own $u))
135                     (canon lift (core func $u_drop)))
136             )
137         "#,
138     )?;
139 
140     let linker = Linker::new(&engine);
141     {
142         let mut store = Store::new(&engine, ());
143         let i = linker.instantiate(&mut store, &c)?;
144         let t = i.get_resource(&mut store, "t").unwrap();
145         let u = i.get_resource(&mut store, "u").unwrap();
146 
147         assert_ne!(t, u);
148 
149         let t_ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "[constructor]t")?;
150         let u_ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "[constructor]u")?;
151         let t_dtor = i.get_typed_func::<(ResourceAny,), ()>(&mut store, "drop-t")?;
152         let u_dtor = i.get_typed_func::<(ResourceAny,), ()>(&mut store, "drop-u")?;
153 
154         let (t1,) = t_ctor.call(&mut store, (100,))?;
155         let (t2,) = t_ctor.call(&mut store, (200,))?;
156         let (u1,) = u_ctor.call(&mut store, (300,))?;
157         let (u2,) = u_ctor.call(&mut store, (400,))?;
158 
159         assert_eq!(t1.ty(), t);
160         assert_eq!(t2.ty(), t);
161         assert_eq!(u1.ty(), u);
162         assert_eq!(u2.ty(), u);
163 
164         u_dtor.call(&mut store, (u2,))?;
165 
166         u_dtor.call(&mut store, (u1,))?;
167 
168         t_dtor.call(&mut store, (t1,))?;
169 
170         t_dtor.call(&mut store, (t2,))?;
171     }
172 
173     {
174         let mut store = Store::new(&engine, ());
175         let i = linker.instantiate(&mut store, &c)?;
176         let t_ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "[constructor]t")?;
177         let u_ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "[constructor]u")?;
178         let t_dtor = i.get_typed_func::<(ResourceAny,), ()>(&mut store, "drop-t")?;
179 
180         // `t` is placed at host index 0
181         let (t,) = t_ctor.call(&mut store, (100,))?;
182         t_dtor.call(&mut store, (t,))?;
183 
184         // `u` is also placed at host index 0 since `t` was deallocated
185         let (_u,) = u_ctor.call(&mut store, (100,))?;
186 
187         // reuse of `t` should fail, despite it pointing to a valid resource
188         assert_eq!(
189             t_dtor.call(&mut store, (t,)).unwrap_err().to_string(),
190             "host-owned resource was already de-allocated"
191         );
192     }
193 
194     {
195         let mut store = Store::new(&engine, ());
196         let i = linker.instantiate(&mut store, &c)?;
197         let t_ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "[constructor]t")?;
198         let t_dtor = i.get_typed_func::<(ResourceAny,), ()>(&mut store, "drop-t")?;
199 
200         // `t0` is placed at host index 0
201         let (t0,) = t_ctor.call(&mut store, (100,))?;
202         t_dtor.call(&mut store, (t0,))?;
203 
204         // `t1` is also placed at host index 0 since `t0` was deallocated
205         let (_t1,) = t_ctor.call(&mut store, (100,))?;
206 
207         // reuse of `t0` should fail, despite it pointing to a valid resource
208         assert_eq!(
209             t_dtor.call(&mut store, (t0,)).unwrap_err().to_string(),
210             "host-owned resource was already de-allocated"
211         );
212     }
213 
214     Ok(())
215 }
216 
217 #[test]
mismatch_intrinsics() -> Result<()>218 fn mismatch_intrinsics() -> Result<()> {
219     let engine = super::engine();
220     let c = Component::new(
221         &engine,
222         r#"
223             (component
224                 (type $t' (resource (rep i32)))
225                 (type $u' (resource (rep i32)))
226 
227                 (export $t "t" (type $t'))
228                 (export $u "u" (type $u'))
229 
230                 ;; note the mismatch where this is an intrinsic for `u` but
231                 ;; we're typing it as `t`
232                 (core func $t_ctor (canon resource.new $u))
233 
234                 (func (export "ctor") (param "x" u32) (result (own $t))
235                     (canon lift (core func $t_ctor)))
236             )
237         "#,
238     )?;
239 
240     let mut store = Store::new(&engine, ());
241     let i = Linker::new(&engine).instantiate(&mut store, &c)?;
242     let ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "ctor")?;
243     assert_eq!(
244         ctor.call(&mut store, (100,)).unwrap_err().to_string(),
245         "handle index 1 used with the wrong type, expected guest-defined \
246          resource but found a different guest-defined resource",
247     );
248 
249     Ok(())
250 }
251 
252 #[test]
mismatch_resource_types() -> Result<()>253 fn mismatch_resource_types() -> Result<()> {
254     let engine = super::engine();
255     let c = Component::new(
256         &engine,
257         r#"
258             (component
259                 (type $t' (resource (rep i32)))
260                 (type $u' (resource (rep i32)))
261 
262                 (export $t "t" (type $t'))
263                 (export $u "u" (type $u'))
264 
265                 (core func $t_ctor (canon resource.new $t))
266                 (func (export "ctor") (param "x" u32) (result (own $t))
267                     (canon lift (core func $t_ctor)))
268 
269                 (core func $u_dtor (canon resource.drop $u))
270                 (func (export "dtor") (param "x" (own $u))
271                     (canon lift (core func $u_dtor)))
272             )
273         "#,
274     )?;
275 
276     let mut store = Store::new(&engine, ());
277     let i = Linker::new(&engine).instantiate(&mut store, &c)?;
278     let ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "ctor")?;
279     let dtor = i.get_typed_func::<(ResourceAny,), ()>(&mut store, "dtor")?;
280 
281     let (t,) = ctor.call(&mut store, (100,))?;
282     assert_eq!(
283         dtor.call(&mut store, (t,)).unwrap_err().to_string(),
284         "mismatched resource types"
285     );
286 
287     Ok(())
288 }
289 
290 #[test]
drop_in_different_places() -> Result<()>291 fn drop_in_different_places() -> Result<()> {
292     let engine = super::engine();
293     let c = Component::new(
294         &engine,
295         r#"
296             (component
297                 (type $t' (resource (rep i32)))
298 
299                 (export $t "t" (type $t'))
300 
301                 (core func $ctor (canon resource.new $t))
302                 (func (export "ctor") (param "x" u32) (result (own $t))
303                     (canon lift (core func $ctor)))
304 
305                 (core func $dtor (canon resource.drop $t))
306                 (func (export "dtor1") (param "x" (own $t))
307                     (canon lift (core func $dtor)))
308 
309                 (component $c
310                     (import "t" (type $t (sub resource)))
311                     (core func $dtor (canon resource.drop $t))
312                     (func (export "dtor") (param "x" (own $t))
313                         (canon lift (core func $dtor)))
314                 )
315                 (instance $i1 (instantiate $c (with "t" (type $t))))
316                 (instance $i2 (instantiate $c (with "t" (type $t))))
317 
318                 (export "dtor2" (func $i1 "dtor"))
319                 (export "dtor3" (func $i2 "dtor"))
320             )
321         "#,
322     )?;
323 
324     let mut store = Store::new(&engine, ());
325     let i = Linker::new(&engine).instantiate(&mut store, &c)?;
326     let ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "ctor")?;
327     let dtor1 = i.get_typed_func::<(ResourceAny,), ()>(&mut store, "dtor1")?;
328     let dtor2 = i.get_typed_func::<(ResourceAny,), ()>(&mut store, "dtor2")?;
329     let dtor3 = i.get_typed_func::<(ResourceAny,), ()>(&mut store, "dtor3")?;
330 
331     let (t,) = ctor.call(&mut store, (100,))?;
332     dtor1.call(&mut store, (t,))?;
333 
334     let (t,) = ctor.call(&mut store, (200,))?;
335     dtor2.call(&mut store, (t,))?;
336 
337     let (t,) = ctor.call(&mut store, (300,))?;
338     dtor3.call(&mut store, (t,))?;
339 
340     Ok(())
341 }
342 
343 #[test]
drop_guest_twice() -> Result<()>344 fn drop_guest_twice() -> Result<()> {
345     let engine = super::engine();
346     let c = Component::new(
347         &engine,
348         r#"
349             (component
350                 (type $t' (resource (rep i32)))
351 
352                 (export $t "t" (type $t'))
353 
354                 (core func $ctor (canon resource.new $t))
355                 (func (export "ctor") (param "x" u32) (result (own $t))
356                     (canon lift (core func $ctor)))
357 
358                 (core func $dtor (canon resource.drop $t))
359                 (func (export "dtor") (param "x" (own $t))
360                     (canon lift (core func $dtor)))
361             )
362         "#,
363     )?;
364 
365     let mut store = Store::new(&engine, ());
366     let i = Linker::new(&engine).instantiate(&mut store, &c)?;
367     let ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "ctor")?;
368     let dtor = i.get_typed_func::<(&ResourceAny,), ()>(&mut store, "dtor")?;
369 
370     let (t,) = ctor.call(&mut store, (100,))?;
371     dtor.call(&mut store, (&t,))?;
372 
373     assert_eq!(
374         dtor.call(&mut store, (&t,)).unwrap_err().to_string(),
375         "unknown handle index 1"
376     );
377 
378     Ok(())
379 }
380 
381 #[test]
drop_host_twice() -> Result<()>382 fn drop_host_twice() -> Result<()> {
383     let engine = super::engine();
384     let c = Component::new(
385         &engine,
386         r#"
387             (component
388                 (import "t" (type $t (sub resource)))
389 
390                 (core func $dtor (canon resource.drop $t))
391                 (func (export "dtor") (param "x" (own $t))
392                     (canon lift (core func $dtor)))
393             )
394         "#,
395     )?;
396 
397     struct MyType;
398 
399     let mut store = Store::new(&engine, ());
400     let mut linker = Linker::new(&engine);
401     linker
402         .root()
403         .resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;
404     let i = linker.instantiate(&mut store, &c)?;
405     let dtor = i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "dtor")?;
406 
407     let t = Resource::new_own(100);
408     dtor.call(&mut store, (&t,))?;
409 
410     assert_eq!(
411         dtor.call(&mut store, (&t,)).unwrap_err().to_string(),
412         "host resource already consumed"
413     );
414 
415     Ok(())
416 }
417 
418 #[test]
manually_destroy() -> Result<()>419 fn manually_destroy() -> Result<()> {
420     let engine = super::engine();
421     let c = Component::new(
422         &engine,
423         r#"
424             (component
425                 (import "t1" (type $t1 (sub resource)))
426 
427                 (core module $m
428                   (global $drops (mut i32) i32.const 0)
429                   (global $last-drop (mut i32) i32.const 0)
430 
431                   (func (export "dtor") (param i32)
432                     (global.set $drops (i32.add (global.get $drops) (i32.const 1)))
433                     (global.set $last-drop (local.get 0))
434                   )
435                   (func (export "drops") (result i32) global.get $drops)
436                   (func (export "last-drop") (result i32) global.get $last-drop)
437                   (func (export "pass") (param i32) (result i32) local.get 0)
438                 )
439                 (core instance $i (instantiate $m))
440                 (type $t2' (resource (rep i32) (dtor (func $i "dtor"))))
441                 (export $t2 "t2" (type $t2'))
442                 (core func $ctor (canon resource.new $t2))
443                 (func (export "[constructor]t2") (param "rep" u32) (result (own $t2))
444                   (canon lift (core func $ctor)))
445                 (func (export "[static]t2.drops") (result u32)
446                   (canon lift (core func $i "drops")))
447                 (func (export "[static]t2.last-drop") (result u32)
448                   (canon lift (core func $i "last-drop")))
449 
450                 (func (export "t1-pass") (param "t" (own $t1)) (result (own $t1))
451                   (canon lift (core func $i "pass")))
452             )
453         "#,
454     )?;
455 
456     struct MyType;
457 
458     #[derive(Default)]
459     struct Data {
460         drops: u32,
461         last_drop: Option<u32>,
462     }
463 
464     let mut store = Store::new(&engine, Data::default());
465     let mut linker = Linker::new(&engine);
466     linker
467         .root()
468         .resource("t1", ResourceType::host::<MyType>(), |mut cx, rep| {
469             let data: &mut Data = cx.data_mut();
470             data.drops += 1;
471             data.last_drop = Some(rep);
472             Ok(())
473         })?;
474     let i = linker.instantiate(&mut store, &c)?;
475     let t2_ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "[constructor]t2")?;
476     let t2_drops = i.get_typed_func::<(), (u32,)>(&mut store, "[static]t2.drops")?;
477     let t2_last_drop = i.get_typed_func::<(), (u32,)>(&mut store, "[static]t2.last-drop")?;
478     let t1_pass = i.get_typed_func::<(Resource<MyType>,), (ResourceAny,)>(&mut store, "t1-pass")?;
479 
480     // Host resources can be destroyed through `resource_drop`
481     let t1 = Resource::new_own(100);
482     let (t1,) = t1_pass.call(&mut store, (t1,))?;
483     assert_eq!(store.data().drops, 0);
484     assert_eq!(store.data().last_drop, None);
485     t1.resource_drop(&mut store)?;
486     assert_eq!(store.data().drops, 1);
487     assert_eq!(store.data().last_drop, Some(100));
488 
489     // Guest resources can be destroyed through `resource_drop`
490     let (t2,) = t2_ctor.call(&mut store, (200,))?;
491     assert_eq!(t2_drops.call(&mut store, ())?, (0,));
492     assert_eq!(t2_last_drop.call(&mut store, ())?, (0,));
493     t2.resource_drop(&mut store)?;
494     assert_eq!(t2_drops.call(&mut store, ())?, (1,));
495     assert_eq!(t2_last_drop.call(&mut store, ())?, (200,));
496 
497     // Wires weren't crossed to drop more resources
498     assert_eq!(store.data().drops, 1);
499     assert_eq!(store.data().last_drop, Some(100));
500 
501     Ok(())
502 }
503 
504 #[test]
dynamic_type() -> Result<()>505 fn dynamic_type() -> Result<()> {
506     let engine = super::engine();
507     let c = Component::new(
508         &engine,
509         r#"
510             (component
511                 (import "t1" (type $t1 (sub resource)))
512                 (type $t2' (resource (rep i32)))
513                 (export $t2 "t2" (type $t2'))
514                 (core func $f (canon resource.drop $t2))
515 
516                 (func (export "a") (param "x" (own $t1))
517                     (canon lift (core func $f)))
518                 (func (export "b") (param "x" (tuple (own $t2)))
519                     (canon lift (core func $f)))
520             )
521         "#,
522     )?;
523 
524     struct MyType;
525 
526     let mut store = Store::new(&engine, ());
527     let mut linker = Linker::new(&engine);
528     linker
529         .root()
530         .resource("t1", ResourceType::host::<MyType>(), |_, _| Ok(()))?;
531     let i = linker.instantiate(&mut store, &c)?;
532 
533     let a = i.get_func(&mut store, "a").unwrap();
534     let b = i.get_func(&mut store, "b").unwrap();
535     let t2 = i.get_resource(&mut store, "t2").unwrap();
536 
537     let aty = a.ty(&store);
538     assert_eq!(
539         aty.params().next().unwrap(),
540         ("x", Type::Own(ResourceType::host::<MyType>()))
541     );
542     let bty = b.ty(&store);
543     match bty.params().next().unwrap() {
544         (name, Type::Tuple(t)) => {
545             assert_eq!(name, "x");
546             assert_eq!(t.types().len(), 1);
547             let t0 = t.types().next().unwrap();
548             assert_eq!(t0, Type::Own(t2));
549         }
550         _ => unreachable!(),
551     }
552 
553     Ok(())
554 }
555 
556 #[test]
dynamic_val() -> Result<()>557 fn dynamic_val() -> Result<()> {
558     let engine = super::engine();
559     let c = Component::new(
560         &engine,
561         r#"
562             (component
563                 (import "t1" (type $t1 (sub resource)))
564                 (type $t2' (resource (rep i32)))
565                 (export $t2 "t2" (type $t2'))
566                 (core func $f (canon resource.new $t2))
567 
568                 (core module $m
569                     (func (export "pass") (param i32) (result i32)
570                         (local.get 0)))
571                 (core instance $i (instantiate $m))
572 
573                 (func (export "a") (param "x" (own $t1)) (result (own $t1))
574                     (canon lift (core func $i "pass")))
575                 (func (export "b") (param "x" u32) (result (own $t2))
576                     (canon lift (core func $f)))
577             )
578         "#,
579     )?;
580 
581     struct MyType;
582 
583     let mut store = Store::new(&engine, ());
584     let mut linker = Linker::new(&engine);
585     linker
586         .root()
587         .resource("t1", ResourceType::host::<MyType>(), |_, _| Ok(()))?;
588     let i_pre = linker.instantiate_pre(&c)?;
589     let i = i_pre.instantiate(&mut store)?;
590 
591     let a = i.get_func(&mut store, "a").unwrap();
592     let a_typed = i.get_typed_func::<(Resource<MyType>,), (ResourceAny,)>(&mut store, "a")?;
593     let a_typed_result =
594         i.get_typed_func::<(Resource<MyType>,), (Resource<MyType>,)>(&mut store, "a")?;
595     let b = i.get_func(&mut store, "b").unwrap();
596     let t2 = i.get_resource(&mut store, "t2").unwrap();
597 
598     let t1 = Resource::new_own(100);
599     let (t1,) = a_typed.call(&mut store, (t1,))?;
600     assert_eq!(t1.ty(), ResourceType::host::<MyType>());
601 
602     let mut results = [Val::Bool(false)];
603     a.call(&mut store, &[Val::Resource(t1)], &mut results)?;
604     match &results[0] {
605         Val::Resource(resource) => {
606             assert_eq!(resource.ty(), ResourceType::host::<MyType>());
607             assert!(resource.owned());
608 
609             let resource = resource.try_into_resource::<MyType>(&mut store)?;
610             assert_eq!(resource.rep(), 100);
611             assert!(resource.owned());
612 
613             let resource = resource.try_into_resource_any(&mut store)?;
614             assert_eq!(resource.ty(), ResourceType::host::<MyType>());
615             assert!(resource.owned());
616         }
617         _ => unreachable!(),
618     }
619 
620     let t1_any = Resource::<MyType>::new_own(100).try_into_resource_any(&mut store)?;
621     let mut results = [Val::Bool(false)];
622     a.call(&mut store, &[Val::Resource(t1_any)], &mut results)?;
623     match &results[0] {
624         Val::Resource(resource) => {
625             assert_eq!(resource.ty(), ResourceType::host::<MyType>());
626             assert!(resource.owned());
627 
628             let resource = resource.try_into_resource::<MyType>(&mut store)?;
629             assert_eq!(resource.rep(), 100);
630             assert!(resource.owned());
631 
632             let resource = resource.try_into_resource_any(&mut store)?;
633             assert_eq!(resource.ty(), ResourceType::host::<MyType>());
634             assert!(resource.owned());
635         }
636         _ => unreachable!(),
637     }
638 
639     let t1 = Resource::<MyType>::new_own(100)
640         .try_into_resource_any(&mut store)?
641         .try_into_resource(&mut store)?;
642     let (t1,) = a_typed_result.call(&mut store, (t1,))?;
643     assert_eq!(t1.rep(), 100);
644     assert!(t1.owned());
645 
646     let t1_any = t1
647         .try_into_resource_any(&mut store)?
648         .try_into_resource::<MyType>(&mut store)?
649         .try_into_resource_any(&mut store)?;
650     let mut results = [Val::Bool(false)];
651     a.call(&mut store, &[Val::Resource(t1_any)], &mut results)?;
652     match &results[0] {
653         Val::Resource(resource) => {
654             assert_eq!(resource.ty(), ResourceType::host::<MyType>());
655             assert!(resource.owned());
656 
657             let resource = resource.try_into_resource::<MyType>(&mut store)?;
658             assert_eq!(resource.rep(), 100);
659             assert!(resource.owned());
660 
661             let resource = resource.try_into_resource_any(&mut store)?;
662             assert_eq!(resource.ty(), ResourceType::host::<MyType>());
663             assert!(resource.owned());
664         }
665         _ => unreachable!(),
666     }
667 
668     b.call(&mut store, &[Val::U32(200)], &mut results)?;
669     match &results[0] {
670         Val::Resource(resource) => {
671             assert_eq!(resource.ty(), t2);
672         }
673         _ => unreachable!(),
674     }
675 
676     Ok(())
677 }
678 
679 #[test]
cannot_reenter_during_import() -> Result<()>680 fn cannot_reenter_during_import() -> Result<()> {
681     let engine = super::engine();
682     let c = Component::new(
683         &engine,
684         r#"
685             (component
686                 (import "f" (func $f))
687 
688                 (core func $f (canon lower (func $f)))
689 
690                 (core module $m
691                     (import "" "f" (func $f))
692                     (func (export "call") call $f)
693                     (func (export "dtor") (param i32) unreachable)
694                 )
695 
696                 (core instance $i (instantiate $m
697                     (with "" (instance
698                         (export "f" (func $f))
699                     ))
700                 ))
701 
702                 (type $t2' (resource (rep i32) (dtor (func $i "dtor"))))
703                 (export $t2 "t" (type $t2'))
704                 (core func $ctor (canon resource.new $t2))
705                 (func (export "ctor") (param "x" u32) (result (own $t2))
706                     (canon lift (core func $ctor)))
707 
708                 (func (export "call") (canon lift (core func $i "call")))
709             )
710         "#,
711     )?;
712 
713     let mut store = Store::new(&engine, None);
714     let mut linker = Linker::new(&engine);
715     linker.root().func_wrap("f", |mut cx, ()| {
716         let data: &mut Option<ResourceAny> = cx.data_mut();
717         let err = data.take().unwrap().resource_drop(cx).unwrap_err();
718         assert_eq!(
719             err.downcast_ref(),
720             Some(&Trap::CannotEnterComponent),
721             "bad error: {err:?}"
722         );
723         Ok(())
724     })?;
725     let i = linker.instantiate(&mut store, &c)?;
726 
727     let ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "ctor")?;
728     let call = i.get_typed_func::<(), ()>(&mut store, "call")?;
729 
730     let (resource,) = ctor.call(&mut store, (100,))?;
731     *store.data_mut() = Some(resource);
732     call.call(&mut store, ())?;
733 
734     Ok(())
735 }
736 
737 #[test]
active_borrows_at_end_of_call() -> Result<()>738 fn active_borrows_at_end_of_call() -> Result<()> {
739     let engine = super::engine();
740     let c = Component::new(
741         &engine,
742         r#"
743             (component
744                 (import "t" (type $t (sub resource)))
745 
746                 (core module $m
747                     (func (export "f") (param i32))
748                 )
749                 (core instance $i (instantiate $m))
750 
751                 (func (export "f") (param "x" (borrow $t))
752                     (canon lift (core func $i "f")))
753             )
754         "#,
755     )?;
756 
757     struct MyType;
758 
759     let mut store = Store::new(&engine, ());
760     let mut linker = Linker::new(&engine);
761     linker
762         .root()
763         .resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;
764     let i = linker.instantiate(&mut store, &c)?;
765 
766     let f = i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "f")?;
767 
768     let resource = Resource::new_own(1);
769     let err = f.call(&mut store, (&resource,)).unwrap_err();
770     assert_eq!(
771         err.to_string(),
772         "borrow handles still remain at the end of the call",
773     );
774 
775     Ok(())
776 }
777 
778 #[test]
thread_through_borrow() -> Result<()>779 fn thread_through_borrow() -> Result<()> {
780     let engine = super::engine();
781     let c = Component::new(
782         &engine,
783         r#"
784             (component
785                 (import "t" (type $t (sub resource)))
786                 (import "f" (func $f (param "x" (borrow $t))))
787 
788                 (core func $f (canon lower (func $f)))
789                 (core func $drop (canon resource.drop $t))
790 
791                 (core module $m
792                     (import "" "f" (func $f (param i32)))
793                     (import "" "drop" (func $drop (param i32)))
794                     (func (export "f2") (param i32)
795                         (call $f (local.get 0))
796                         (call $f (local.get 0))
797                         (call $drop (local.get 0))
798                     )
799                 )
800                 (core instance $i (instantiate $m
801                     (with "" (instance
802                         (export "f" (func $f))
803                         (export "drop" (func $drop))
804                     ))
805                 ))
806 
807                 (func (export "f2") (param "x" (borrow $t))
808                     (canon lift (core func $i "f2")))
809             )
810         "#,
811     )?;
812 
813     struct MyType;
814 
815     let mut store = Store::new(&engine, ());
816     let mut linker = Linker::new(&engine);
817     linker
818         .root()
819         .resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;
820     linker
821         .root()
822         .func_wrap("f", |_cx, (r,): (Resource<MyType>,)| {
823             assert!(!r.owned());
824             assert_eq!(r.rep(), 100);
825             Ok(())
826         })?;
827     let i = linker.instantiate(&mut store, &c)?;
828 
829     let f = i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "f2")?;
830 
831     let resource = Resource::new_own(100);
832     f.call(&mut store, (&resource,))?;
833     Ok(())
834 }
835 
836 #[test]
borrows_must_be_dropped_before_lifting() -> Result<()>837 fn borrows_must_be_dropped_before_lifting() -> Result<()> {
838     let engine = super::engine();
839     let c = Component::new(
840         &engine,
841         r#"
842             (component
843                 (import "t" (type $t (sub resource)))
844 
845                 (core module $m
846                     (func (export "f") (param i32) (result i32)
847                         ;; this is a `borrow $t`, and we're returning it as an
848                         ;; `own $t`. This should have an error about remaining
849                         ;; borrows rather than a mismatch of own/borrow.
850                         local.get 0
851                     )
852                 )
853                 (core instance $i (instantiate $m))
854 
855                 (func (export "f") (param "x" (borrow $t)) (result (own $t))
856                     (canon lift (core func $i "f")))
857             )
858         "#,
859     )?;
860 
861     struct MyType;
862 
863     let mut store = Store::new(&engine, ());
864     let mut linker = Linker::new(&engine);
865     linker
866         .root()
867         .resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;
868     let i = linker.instantiate(&mut store, &c)?;
869 
870     let f = i.get_typed_func::<(&Resource<MyType>,), (Resource<MyType>,)>(&mut store, "f")?;
871 
872     let resource = Resource::new_own(100);
873     let err = f.call(&mut store, (&resource,)).unwrap_err();
874     assert_eq!(
875         err.to_string(),
876         "borrow handles still remain at the end of the call"
877     );
878     Ok(())
879 }
880 
881 #[test]
cannot_use_borrow_for_own() -> Result<()>882 fn cannot_use_borrow_for_own() -> Result<()> {
883     let engine = super::engine();
884     let c = Component::new(
885         &engine,
886         r#"
887             (component
888                 (import "t" (type $t (sub resource)))
889                 (import "f" (func $f (param "x" (own $t))))
890 
891                 (core module $m
892                     (import "" "f" (func $f (param i32)))
893                     (func (export "f") (param i32)
894                         local.get 0
895                         call $f
896                     )
897                 )
898                 (core func $f (canon lower (func $f)))
899                 (core instance $i (instantiate $m
900                     (with "" (instance
901                         (export "f" (func $f))
902                     ))
903                 ))
904 
905                 (func (export "f") (param "x" (borrow $t))
906                     (canon lift (core func $i "f")))
907             )
908         "#,
909     )?;
910 
911     struct MyType;
912 
913     let mut store = Store::new(&engine, ());
914     let mut linker = Linker::new(&engine);
915     linker
916         .root()
917         .resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;
918     linker
919         .root()
920         .func_wrap("f", |_, _: (Resource<MyType>,)| Ok(()))?;
921     let i = linker.instantiate(&mut store, &c)?;
922 
923     let f = i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "f")?;
924 
925     let resource = Resource::new_own(100);
926     let err = f.call(&mut store, (&resource,)).unwrap_err();
927     assert!(
928         format!("{err:?}").contains("cannot lift own resource from a borrow"),
929         "bad error: {err:?}",
930     );
931     Ok(())
932 }
933 
934 #[test]
can_use_own_for_borrow() -> Result<()>935 fn can_use_own_for_borrow() -> Result<()> {
936     let engine = super::engine();
937     let c = Component::new(
938         &engine,
939         r#"
940             (component
941                 (import "t" (type $t (sub resource)))
942 
943                 (core func $drop (canon resource.drop $t))
944 
945                 (core module $m
946                     (import "" "drop" (func $drop (param i32)))
947                     (func (export "f") (param i32)
948                         (call $drop (local.get 0))
949                     )
950                 )
951                 (core instance $i (instantiate $m
952                     (with "" (instance
953                         (export "drop" (func $drop))
954                     ))
955                 ))
956 
957                 (func (export "f") (param "x" (borrow $t))
958                     (canon lift (core func $i "f")))
959             )
960         "#,
961     )?;
962 
963     struct MyType;
964 
965     let mut store = Store::new(&engine, ());
966     let mut linker = Linker::new(&engine);
967     linker
968         .root()
969         .resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;
970     let i_pre = linker.instantiate_pre(&c)?;
971     let i = i_pre.instantiate(&mut store)?;
972 
973     let f = i.get_func(&mut store, "f").unwrap();
974     let f_typed = i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "f")?;
975 
976     let resource = Resource::new_own(100);
977     f_typed.call(&mut store, (&resource,))?;
978 
979     let resource = Resource::new_borrow(200);
980     f_typed.call(&mut store, (&resource,))?;
981 
982     let resource = Resource::<MyType>::new_own(300).try_into_resource_any(&mut store)?;
983     f.call(&mut store, &[Val::Resource(resource)], &mut [])?;
984     resource.resource_drop(&mut store)?;
985 
986     // TODO: Enable once https://github.com/bytecodealliance/wasmtime/issues/7793 is fixed
987     //let resource =
988     //    Resource::<MyType>::new_borrow(400).try_into_resource_any(&mut store, &i_pre, ty_idx)?;
989     //f.call(&mut store, &[Val::Resource(resource)], &mut [])?;
990     //resource.resource_drop(&mut store)?;
991 
992     Ok(())
993 }
994 
995 #[test]
passthrough_wrong_type() -> Result<()>996 fn passthrough_wrong_type() -> Result<()> {
997     let engine = super::engine();
998     let c = Component::new(
999         &engine,
1000         r#"
1001             (component
1002                 (import "t" (type $t (sub resource)))
1003                 (import "f" (func $f (param "a" (borrow $t)) (result (own $t))))
1004 
1005                 (core func $f (canon lower (func $f)))
1006 
1007                 (core module $m
1008                     (import "" "f" (func $f (param i32) (result i32)))
1009                     (func (export "f2") (param i32)
1010                         (drop (call $f (local.get 0)))
1011                     )
1012                 )
1013                 (core instance $i (instantiate $m
1014                     (with "" (instance
1015                         (export "f" (func $f))
1016                     ))
1017                 ))
1018 
1019                 (func (export "f2") (param "x" (borrow $t))
1020                     (canon lift (core func $i "f2")))
1021             )
1022         "#,
1023     )?;
1024 
1025     struct MyType;
1026 
1027     let mut store = Store::new(&engine, ());
1028     let mut linker = Linker::new(&engine);
1029     linker
1030         .root()
1031         .resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;
1032     linker
1033         .root()
1034         .func_wrap("f", |_cx, (r,): (Resource<MyType>,)| Ok((r,)))?;
1035     let i = linker.instantiate(&mut store, &c)?;
1036 
1037     let f = i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "f2")?;
1038 
1039     let resource = Resource::new_own(100);
1040     let err = f.call(&mut store, (&resource,)).unwrap_err();
1041     assert!(
1042         format!("{err:?}").contains("cannot lower a `borrow` resource into an `own`"),
1043         "bad error: {err:?}"
1044     );
1045     Ok(())
1046 }
1047 
1048 #[test]
pass_moved_resource() -> Result<()>1049 fn pass_moved_resource() -> Result<()> {
1050     let engine = super::engine();
1051     let c = Component::new(
1052         &engine,
1053         r#"
1054             (component
1055                 (import "t" (type $t (sub resource)))
1056                 (core module $m
1057                     (func (export "f") (param i32 i32))
1058                 )
1059                 (core instance $i (instantiate $m))
1060 
1061                 (func (export "f") (param "x" (own $t)) (param "y" (borrow $t))
1062                     (canon lift (core func $i "f")))
1063             )
1064         "#,
1065     )?;
1066 
1067     struct MyType;
1068 
1069     let mut store = Store::new(&engine, ());
1070     let mut linker = Linker::new(&engine);
1071     linker
1072         .root()
1073         .resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;
1074     let i = linker.instantiate(&mut store, &c)?;
1075 
1076     let f = i.get_typed_func::<(&Resource<MyType>, &Resource<MyType>), ()>(&mut store, "f")?;
1077 
1078     let resource = Resource::new_own(100);
1079     let err = f.call(&mut store, (&resource, &resource)).unwrap_err();
1080     assert!(
1081         format!("{err:?}").contains("host resource already consumed"),
1082         "bad error: {err:?}"
1083     );
1084     Ok(())
1085 }
1086 
1087 #[test]
type_mismatch() -> Result<()>1088 fn type_mismatch() -> Result<()> {
1089     let engine = super::engine();
1090     let c = Component::new(
1091         &engine,
1092         r#"
1093             (component
1094                 (type $t' (resource (rep i32)))
1095                 (export $t "t" (type $t'))
1096 
1097                 (core func $drop (canon resource.drop $t))
1098 
1099                 (func (export "f1") (param "x" (own $t))
1100                     (canon lift (core func $drop)))
1101                 (func (export "f2") (param "x" (borrow $t))
1102                     (canon lift (core func $drop)))
1103                 (func (export "f3") (param "x" u32)
1104                     (canon lift (core func $drop)))
1105             )
1106         "#,
1107     )?;
1108 
1109     struct MyType;
1110 
1111     let mut store = Store::new(&engine, ());
1112     let i = Linker::new(&engine).instantiate(&mut store, &c)?;
1113 
1114     assert!(
1115         i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "f1")
1116             .is_err()
1117     );
1118     assert!(
1119         i.get_typed_func::<(&ResourceAny,), ()>(&mut store, "f1")
1120             .is_ok()
1121     );
1122 
1123     assert!(
1124         i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "f2")
1125             .is_err()
1126     );
1127     assert!(
1128         i.get_typed_func::<(&ResourceAny,), ()>(&mut store, "f2")
1129             .is_ok()
1130     );
1131 
1132     assert!(
1133         i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "f3")
1134             .is_err()
1135     );
1136     assert!(
1137         i.get_typed_func::<(&ResourceAny,), ()>(&mut store, "f3")
1138             .is_err()
1139     );
1140     assert!(i.get_typed_func::<(u32,), ()>(&mut store, "f3").is_ok());
1141 
1142     Ok(())
1143 }
1144 
1145 #[test]
drop_no_dtor() -> Result<()>1146 fn drop_no_dtor() -> Result<()> {
1147     let engine = super::engine();
1148     let c = Component::new(
1149         &engine,
1150         r#"
1151             (component
1152                 (type $t' (resource (rep i32)))
1153                 (export $t "t" (type $t'))
1154 
1155                 (core func $ctor (canon resource.new $t))
1156 
1157                 (func (export "ctor") (param "x" u32) (result (own $t))
1158                     (canon lift (core func $ctor)))
1159             )
1160         "#,
1161     )?;
1162 
1163     let mut store = Store::new(&engine, ());
1164     let i = Linker::new(&engine).instantiate(&mut store, &c)?;
1165     let ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "ctor")?;
1166     let (resource,) = ctor.call(&mut store, (100,))?;
1167     resource.resource_drop(&mut store)?;
1168 
1169     Ok(())
1170 }
1171 
1172 #[test]
host_borrow_as_resource_any() -> Result<()>1173 fn host_borrow_as_resource_any() -> Result<()> {
1174     let engine = super::engine();
1175     let c = Component::new(
1176         &engine,
1177         r#"
1178             (component
1179                 (import "t" (type $t (sub resource)))
1180                 (import "f" (func $f (param "f" (borrow $t))))
1181 
1182                 (core func $f (canon lower (func $f)))
1183                 (core func $drop (canon resource.drop $t))
1184 
1185                 (core module $m
1186                     (import "" "f" (func $f (param i32)))
1187                     (import "" "drop" (func $drop (param i32)))
1188                     (func (export "f2") (param i32)
1189                         (call $f (local.get 0))
1190                         (call $drop (local.get 0))
1191                     )
1192                 )
1193                 (core instance $i (instantiate $m
1194                     (with "" (instance
1195                         (export "f" (func $f))
1196                         (export "drop" (func $drop))
1197                     ))
1198                 ))
1199 
1200                 (func (export "f2") (param "x" (borrow $t))
1201                     (canon lift (core func $i "f2")))
1202             )
1203         "#,
1204     )?;
1205 
1206     struct MyType;
1207 
1208     let mut store = Store::new(&engine, ());
1209 
1210     // First test the above component where the host properly drops the argument
1211     {
1212         let mut linker = Linker::new(&engine);
1213         linker
1214             .root()
1215             .resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;
1216         linker
1217             .root()
1218             .func_wrap("f", |mut cx, (r,): (ResourceAny,)| {
1219                 r.resource_drop(&mut cx)?;
1220                 Ok(())
1221             })?;
1222         let i = linker.instantiate(&mut store, &c)?;
1223 
1224         let f = i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "f2")?;
1225 
1226         let resource = Resource::new_own(100);
1227         f.call(&mut store, (&resource,))?;
1228     }
1229 
1230     // Then also test the case where the host forgets a drop
1231     {
1232         let mut linker = Linker::new(&engine);
1233         linker
1234             .root()
1235             .resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;
1236         linker.root().func_wrap("f", |_cx, (_r,): (ResourceAny,)| {
1237             // ... no drop here
1238             Ok(())
1239         })?;
1240         let i = linker.instantiate(&mut store, &c)?;
1241 
1242         let f = i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "f2")?;
1243 
1244         let resource = Resource::new_own(100);
1245         let err = f.call(&mut store, (&resource,)).unwrap_err();
1246         assert!(
1247             format!("{err:?}").contains("borrow handles still remain at the end of the call"),
1248             "bad error: {err:?}"
1249         );
1250     }
1251     Ok(())
1252 }
1253 
1254 #[test]
pass_guest_back_as_borrow() -> Result<()>1255 fn pass_guest_back_as_borrow() -> Result<()> {
1256     let engine = super::engine();
1257     let c = Component::new(
1258         &engine,
1259         r#"
1260             (component
1261                 (type $t' (resource (rep i32)))
1262 
1263                 (export $t "t" (type $t'))
1264 
1265                 (core func $new (canon resource.new $t))
1266 
1267                 (core module $m
1268                     (import "" "new" (func $new (param i32) (result i32)))
1269 
1270                     (func (export "mk") (result i32)
1271                         (call $new (i32.const 100))
1272                     )
1273 
1274                     (func (export "take") (param i32)
1275                         (if (i32.ne (local.get 0) (i32.const 100)) (then (unreachable)))
1276                     )
1277                 )
1278                 (core instance $i (instantiate $m
1279                     (with "" (instance
1280                         (export "new" (func $new))
1281                     ))
1282                 ))
1283 
1284                 (func (export "mk") (result (own $t))
1285                     (canon lift (core func $i "mk")))
1286                 (func (export "take") (param "x" (borrow $t))
1287                     (canon lift (core func $i "take")))
1288             )
1289         "#,
1290     )?;
1291 
1292     let mut store = Store::new(&engine, ());
1293     let i = Linker::new(&engine).instantiate(&mut store, &c)?;
1294     let mk = i.get_typed_func::<(), (ResourceAny,)>(&mut store, "mk")?;
1295     let take = i.get_typed_func::<(&ResourceAny,), ()>(&mut store, "take")?;
1296 
1297     let (resource,) = mk.call(&mut store, ())?;
1298     take.call(&mut store, (&resource,))?;
1299 
1300     resource.resource_drop(&mut store)?;
1301 
1302     // Should not be valid to use `resource` again
1303     let err = take.call(&mut store, (&resource,)).unwrap_err();
1304     assert_eq!(err.to_string(), "unknown handle index 1");
1305 
1306     Ok(())
1307 }
1308 
1309 #[test]
pass_host_borrow_to_guest() -> Result<()>1310 fn pass_host_borrow_to_guest() -> Result<()> {
1311     let engine = super::engine();
1312     let c = Component::new(
1313         &engine,
1314         r#"
1315             (component
1316                 (import "t" (type $t (sub resource)))
1317 
1318                 (core func $drop (canon resource.drop $t))
1319 
1320                 (core module $m
1321                     (import "" "drop" (func $drop (param i32)))
1322                     (func (export "take") (param i32)
1323                       (call $drop (local.get 0))
1324                     )
1325                 )
1326                 (core instance $i (instantiate $m
1327                     (with "" (instance
1328                         (export "drop" (func $drop))
1329                     ))
1330                 ))
1331 
1332                 (func (export "take") (param "x" (borrow $t))
1333                     (canon lift (core func $i "take")))
1334             )
1335         "#,
1336     )?;
1337 
1338     struct MyType;
1339 
1340     let mut store = Store::new(&engine, ());
1341     let mut linker = Linker::new(&engine);
1342     linker
1343         .root()
1344         .resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;
1345     let i = linker.instantiate(&mut store, &c)?;
1346     let take = i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "take")?;
1347 
1348     let resource = Resource::new_borrow(100);
1349     take.call(&mut store, (&resource,))?;
1350 
1351     Ok(())
1352 }
1353 
1354 #[tokio::test]
drop_on_owned_resource() -> Result<()>1355 async fn drop_on_owned_resource() -> Result<()> {
1356     let mut config = wasmtime::Config::new();
1357     config.wasm_component_model_async(true);
1358     let engine = &wasmtime::Engine::new(&config)?;
1359     let c = Component::new(
1360         &engine,
1361         r#"
1362             (component
1363                 (import "t" (type $t (sub resource)))
1364                 (import "[constructor]t" (func $ctor (result (own $t))))
1365                 (import "[method]t.foo" (func $foo async (param "self" (borrow $t))))
1366 
1367                 (core func $ctor (canon lower (func $ctor)))
1368                 (core func $drop (canon resource.drop $t))
1369                 (core func $foo (canon lower (func $foo) async))
1370 
1371                 (core module $m
1372                     (import "" "ctor" (func $ctor (result i32)))
1373                     (import "" "foo" (func $foo (param i32) (result i32)))
1374                     (import "" "drop" (func $drop (param i32)))
1375 
1376                     (func (export "f")
1377                         (local $r i32)
1378                         (local $status i32)
1379                         (local.set $r (call $ctor))
1380                         (local.set $status (call $foo (local.get $r)))
1381                         (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $status) (i32.const 0xf)))
1382                            (then unreachable))
1383                         (call $drop (local.get $r))
1384                         (unreachable)
1385                     )
1386                 )
1387                 (core instance $i (instantiate $m
1388                     (with "" (instance
1389                         (export "ctor" (func $ctor))
1390                         (export "foo" (func $foo))
1391                         (export "drop" (func $drop))
1392                     ))
1393                 ))
1394                 (func (export "f") async (canon lift (core func $i "f")))
1395             )
1396         "#,
1397     )?;
1398 
1399     struct MyType;
1400 
1401     let mut store = Store::new(&engine, ());
1402     let mut linker = Linker::new(&engine);
1403     linker
1404         .root()
1405         .resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;
1406     linker.root().func_wrap("[constructor]t", |_, ()| {
1407         Ok((Resource::<MyType>::new_own(300),))
1408     })?;
1409     linker
1410         .root()
1411         .func_wrap_concurrent("[method]t.foo", |_cx, (r,): (Resource<MyType>,)| {
1412             assert!(!r.owned());
1413             Box::pin(core::future::pending::<Result<()>>())
1414         })?;
1415     let i = linker.instantiate_async(&mut store, &c).await?;
1416     let f = i.get_typed_func::<(), ()>(&mut store, "f")?;
1417 
1418     let err = f.call_async(&mut store, ()).await.unwrap_err();
1419     assert!(
1420         format!("{err:?}").contains("cannot remove owned resource while borrowed"),
1421         "bad error: {err:?}"
1422     );
1423 
1424     Ok(())
1425 }
1426 
1427 #[test]
guest_different_host_same() -> Result<()>1428 fn guest_different_host_same() -> Result<()> {
1429     let engine = super::engine();
1430     let c = Component::new(
1431         &engine,
1432         r#"
1433             (component
1434                 (import "t1" (type $t1 (sub resource)))
1435                 (import "t2" (type $t2 (sub resource)))
1436 
1437                 (import "f" (func $f (param "a" (borrow $t1)) (param "b" (borrow $t2))))
1438 
1439                 (export $g1 "g1" (type $t1))
1440                 (export $g2 "g2" (type $t2))
1441 
1442                 (core func $f (canon lower (func $f)))
1443                 (core func $drop1 (canon resource.drop $t1))
1444                 (core func $drop2 (canon resource.drop $t2))
1445 
1446                 (core module $m
1447                     (import "" "f" (func $f (param i32 i32)))
1448                     (import "" "drop1" (func $drop1 (param i32)))
1449                     (import "" "drop2" (func $drop2 (param i32)))
1450 
1451                     (func (export "f") (param i32 i32)
1452                         ;; different types, but everything goes into the same
1453                         ;; handle index namespace
1454                         (if (i32.ne (local.get 0) (i32.const 1)) (then (unreachable)))
1455                         (if (i32.ne (local.get 1) (i32.const 2)) (then (unreachable)))
1456 
1457                         ;; host should end up getting the same resource
1458                         (call $f (local.get 0) (local.get 1))
1459 
1460                         ;; drop our borrows
1461                         (call $drop1 (local.get 0))
1462                         (call $drop2 (local.get 1))
1463                     )
1464                 )
1465                 (core instance $i (instantiate $m
1466                     (with "" (instance
1467                         (export "f" (func $f))
1468                         (export "drop1" (func $drop1))
1469                         (export "drop2" (func $drop2))
1470                     ))
1471                 ))
1472 
1473                 (func (export "f2") (param "a" (borrow $g1)) (param "b" (borrow $g2))
1474                     (canon lift (core func $i "f")))
1475             )
1476         "#,
1477     )?;
1478 
1479     struct MyType;
1480 
1481     let mut store = Store::new(&engine, ());
1482     let mut linker = Linker::new(&engine);
1483     linker
1484         .root()
1485         .resource("t1", ResourceType::host::<MyType>(), |_, _| Ok(()))?;
1486     linker
1487         .root()
1488         .resource("t2", ResourceType::host::<MyType>(), |_, _| Ok(()))?;
1489     linker.root().func_wrap(
1490         "f",
1491         |_cx, (r1, r2): (Resource<MyType>, Resource<MyType>)| {
1492             assert!(!r1.owned());
1493             assert!(!r2.owned());
1494             assert_eq!(r1.rep(), 100);
1495             assert_eq!(r2.rep(), 100);
1496             Ok(())
1497         },
1498     )?;
1499     let i = linker.instantiate(&mut store, &c)?;
1500     let f = i.get_typed_func::<(&Resource<MyType>, &Resource<MyType>), ()>(&mut store, "f2")?;
1501 
1502     let t1 = i.get_resource(&mut store, "g1").unwrap();
1503     let t2 = i.get_resource(&mut store, "g2").unwrap();
1504     assert_eq!(t1, t2);
1505     assert_eq!(t1, ResourceType::host::<MyType>());
1506 
1507     let resource = Resource::new_own(100);
1508     f.call(&mut store, (&resource, &resource))?;
1509 
1510     Ok(())
1511 }
1512 
1513 #[test]
resource_any_to_typed_handles_borrow() -> Result<()>1514 fn resource_any_to_typed_handles_borrow() -> Result<()> {
1515     let engine = super::engine();
1516     let c = Component::new(
1517         &engine,
1518         r#"
1519             (component
1520                 (import "t" (type $t (sub resource)))
1521 
1522                 (import "f" (func $f (param "a" (borrow $t))))
1523 
1524                 (core func $f (canon lower (func $f)))
1525 
1526                 (core module $m
1527                     (import "" "f" (func $f (param i32)))
1528 
1529                     (func (export "f") (param i32)
1530                         (call $f (local.get 0))
1531                     )
1532                 )
1533                 (core instance $i (instantiate $m
1534                     (with "" (instance
1535                         (export "f" (func $f))
1536                     ))
1537                 ))
1538 
1539                 (func (export "f") (param "a" (own $t))
1540                     (canon lift (core func $i "f")))
1541             )
1542         "#,
1543     )?;
1544 
1545     struct MyType;
1546 
1547     let mut store = Store::new(&engine, ());
1548     let mut linker = Linker::new(&engine);
1549     linker
1550         .root()
1551         .resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;
1552     linker
1553         .root()
1554         .func_wrap("f", |mut cx, (r,): (ResourceAny,)| {
1555             let r = r.try_into_resource::<MyType>(&mut cx).unwrap();
1556             assert_eq!(r.rep(), 100);
1557             assert!(!r.owned());
1558             Ok(())
1559         })?;
1560     let i = linker.instantiate(&mut store, &c)?;
1561     let f = i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "f")?;
1562 
1563     let resource = Resource::new_own(100);
1564     f.call(&mut store, (&resource,))?;
1565 
1566     Ok(())
1567 }
1568 
1569 #[test]
resource_dynamic() -> Result<()>1570 fn resource_dynamic() -> Result<()> {
1571     let r = ResourceDynamic::new_own(1, 2);
1572     assert_eq!(r.rep(), 1);
1573     assert!(r.owned());
1574     assert_eq!(r.ty(), 2);
1575 
1576     let engine = super::engine();
1577     let mut store = Store::new(&engine, ());
1578 
1579     let r2 = r.try_into_resource_any(&mut store)?;
1580     assert_eq!(r2.ty(), ResourceType::host_dynamic(2));
1581     assert!(r2.owned());
1582 
1583     let r3 = r2.try_into_resource_dynamic(&mut store)?;
1584     assert_eq!(r3.rep(), 1);
1585     assert_eq!(r3.ty(), 2);
1586 
1587     let c = Component::new(
1588         &engine,
1589         r#"
1590             (component
1591                 (import "t" (type $t (sub resource)))
1592                 (import "u" (type $u (sub resource)))
1593 
1594                 (core func $t_drop (canon resource.drop $t))
1595                 (core func $u_drop (canon resource.drop $u))
1596 
1597                 (func (export "drop-t") (param "x" (own $t))
1598                     (canon lift (core func $t_drop)))
1599                 (func (export "drop-u") (param "x" (own $u))
1600                     (canon lift (core func $u_drop)))
1601             )
1602         "#,
1603     )?;
1604     let mut linker = Linker::new(&engine);
1605     linker
1606         .root()
1607         .resource("t", ResourceType::host_dynamic(2), |_, _| Ok(()))?;
1608     linker
1609         .root()
1610         .resource("u", ResourceType::host_dynamic(3), |_, _| Ok(()))?;
1611     let instance = linker.instantiate(&mut store, &c)?;
1612 
1613     let drop_t = instance.get_typed_func::<(ResourceDynamic,), ()>(&mut store, "drop-t")?;
1614     let drop_u = instance.get_typed_func::<(ResourceDynamic,), ()>(&mut store, "drop-u")?;
1615 
1616     drop_t.call(&mut store, (ResourceDynamic::new_own(1, 2),))?;
1617 
1618     drop_u.call(&mut store, (ResourceDynamic::new_own(2, 3),))?;
1619 
1620     assert!(
1621         drop_t
1622             .call(&mut store, (ResourceDynamic::new_own(1, 1),))
1623             .is_err()
1624     );
1625 
1626     Ok(())
1627 }
1628 
1629 #[test]
resource_dynamic_not_static() -> Result<()>1630 fn resource_dynamic_not_static() -> Result<()> {
1631     let engine = super::engine();
1632     let mut store = Store::new(&engine, ());
1633     let c = Component::new(
1634         &engine,
1635         r#"
1636             (component
1637                 (import "t" (type $t (sub resource)))
1638                 (core func $t_drop (canon resource.drop $t))
1639                 (func (export "drop-t") (param "x" (own $t))
1640                     (canon lift (core func $t_drop)))
1641             )
1642         "#,
1643     )?;
1644 
1645     struct T;
1646 
1647     {
1648         let mut linker = Linker::new(&engine);
1649         linker
1650             .root()
1651             .resource("t", ResourceType::host_dynamic(2), |_, _| Ok(()))?;
1652         let instance = linker.instantiate(&mut store, &c)?;
1653         instance.get_typed_func::<(ResourceDynamic,), ()>(&mut store, "drop-t")?;
1654         assert!(
1655             instance
1656                 .get_typed_func::<(Resource<T>,), ()>(&mut store, "drop-t")
1657                 .is_err()
1658         );
1659     }
1660 
1661     {
1662         let mut linker = Linker::new(&engine);
1663         linker
1664             .root()
1665             .resource("t", ResourceType::host::<T>(), |_, _| Ok(()))?;
1666         let instance = linker.instantiate(&mut store, &c)?;
1667         assert!(
1668             instance
1669                 .get_typed_func::<(ResourceDynamic,), ()>(&mut store, "drop-t")
1670                 .is_err()
1671         );
1672         instance.get_typed_func::<(Resource<T>,), ()>(&mut store, "drop-t")?;
1673     }
1674 
1675     Ok(())
1676 }
1677 
1678 #[test]
intrinsic_trampolines() -> Result<()>1679 fn intrinsic_trampolines() -> Result<()> {
1680     let engine = super::engine();
1681     let mut store = Store::new(&engine, ());
1682     let linker = Linker::new(&engine);
1683     let c = Component::new(
1684         &engine,
1685         r#"
1686 (component
1687   (type $r' (resource (rep i32)))
1688   (export $r "r" (type $r'))
1689 
1690   (core func $new (canon resource.new $r))
1691   (core func $rep (canon resource.rep $r))
1692 
1693   (func (export "new") (param "x" u32) (result (own $r))
1694     (canon lift (core func $new)))
1695   (func (export "rep") (param "x" (borrow $r)) (result u32)
1696     (canon lift (core func $rep)))
1697 )
1698 "#,
1699     )?;
1700     let i = linker.instantiate(&mut store, &c)?;
1701     let new = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "new")?;
1702     let rep = i.get_typed_func::<(ResourceAny,), (u32,)>(&mut store, "rep")?;
1703 
1704     let r = new.call(&mut store, (42,))?.0;
1705     assert!(rep.call(&mut store, (r,)).is_err());
1706     Ok(())
1707 }
1708 
1709 #[tokio::test]
drop_after_sync_lowered_async_host_function() -> Result<()>1710 async fn drop_after_sync_lowered_async_host_function() -> Result<()> {
1711     let mut config = Config::new();
1712     config.wasm_component_model_async(true);
1713     let engine = Engine::new(&config)?;
1714     let mut store = Store::new(&engine, ());
1715     let mut linker = Linker::new(&engine);
1716     let c = Component::new(
1717         &engine,
1718         r#"
1719 (component
1720   (import "r" (type $r (sub resource)))
1721   ;;(import "f" (func $f async (param "x" (borrow $r)) (param "y" (borrow $r))))
1722   ;;(import "n" (func $n (result (own $r))))
1723   (import "f" (func $f async))
1724 
1725 
1726   (component $A
1727     (import "f" (func $f async))
1728     (core module $m
1729       (import "" "f" (func $f))
1730       (func (export "call") (result i32) call $f i32.const 0)
1731       (func (export "cb") (param i32 i32 i32) (result i32) unreachable)
1732     )
1733     (core func $f (canon lower (func $f)))
1734     (core instance $i (instantiate $m
1735         (with "" (instance (export "f" (func $f))))
1736     ))
1737     (func (export "call") async
1738       (canon lift (core func $i "call")
1739         async
1740         (callback (func $i "cb"))))
1741   )
1742 
1743   (component $B
1744     (import "r" (type $r (sub resource)))
1745     (import "f" (func $f async))
1746     (core module $m
1747       (import "" "f" (func $f (result i32)))
1748       (import "" "r" (func $r))
1749       (import "" "drop" (func $drop (param i32)))
1750       (func (export "call") (param i32) (result i32)
1751         ;; Call into component `$A` which is an async-lifted function. This
1752         ;; function will call a sync-lowered async function from the host. In
1753         ;; effect this means that the task started here by calling `$f` is
1754         ;; blocked.
1755         call $f
1756         drop ;; ignore the `SUBTASK_STARTED` status code
1757 
1758         ;; Now drop our borrow that this function was provided. This is
1759         ;; entirely disconnected from `$A` and it should be using the borrow
1760         ;; tracking of this task, no other task.
1761         (call $drop (local.get 0))
1762 
1763         ;; Now finish up this task without actually waiting on `$A`.
1764         call $r
1765         i32.const 0
1766       )
1767       (func (export "cb") (param i32 i32 i32) (result i32) unreachable)
1768     )
1769     (core func $f (canon lower (func $f) async))
1770     (core func $r (canon task.return))
1771     (core func $drop (canon resource.drop $r))
1772     (core instance $i (instantiate $m
1773       (with "" (instance
1774         (export "f" (func $f))
1775         (export "r" (func $r))
1776         (export "drop" (func $drop))
1777       ))
1778     ))
1779     (func (export "call") async (param "x" (borrow $r))
1780         (canon lift (core func $i "call")
1781             async
1782             (callback (func $i "cb"))))
1783   )
1784   (instance $a (instantiate $A (with "f" (func $f))))
1785   (instance $b (instantiate $B
1786     (with "f" (func $a "call"))
1787     (with "r" (type $r))
1788 ))
1789   (export "call" (func $b "call"))
1790 )
1791 "#,
1792     )?;
1793 
1794     let mut root = linker.root();
1795     root.resource("r", ResourceType::host::<u32>(), |_, _| Ok(()))?;
1796     root.func_wrap_concurrent("f", |_accessor, ()| {
1797         Box::pin(async move { std::future::pending::<Result<()>>().await })
1798     })?;
1799 
1800     let i = linker.instantiate_async(&mut store, &c).await?;
1801     let call = i.get_typed_func::<(Resource<u32>,), ()>(&mut store, "call")?;
1802     let r = Resource::new_borrow(3);
1803     call.call_async(&mut store, (r,)).await?;
1804     Ok(())
1805 }
1806