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