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