Path: blob/main/tests/all/component_model/resources.rs
1692 views
#![cfg(not(miri))]12use anyhow::Result;3use wasmtime::component::*;4use wasmtime::{Store, Trap};56#[test]7fn host_resource_types() -> Result<()> {8let engine = super::engine();9let c = Component::new(10&engine,11r#"12(component13(import "t" (type $t (sub resource)))14(import "u" (type $u (sub resource)))1516(export "t1" (type $t))17(export "t2" (type $t))18(export "u1" (type $u))19(export "u2" (type $u))2021(component $c22(import "r" (type $r (sub resource)))23(export "r1" (type $r))24)25(instance $i1 (instantiate $c (with "r" (type $t))))26(instance $i2 (instantiate $c (with "r" (type $t))))27(export "t3" (type $i1 "r1"))28(export "t4" (type $i2 "r1"))29)30"#,31)?;3233struct T;34struct U;35assert!(ResourceType::host::<T>() != ResourceType::host::<U>());3637let mut store = Store::new(&engine, ());38let mut linker = Linker::new(&engine);39linker40.root()41.resource("t", ResourceType::host::<T>(), |_, _| Ok(()))?;42linker43.root()44.resource("u", ResourceType::host::<U>(), |_, _| Ok(()))?;45let i = linker.instantiate(&mut store, &c)?;46let t1 = i.get_resource(&mut store, "t1").unwrap();47let t2 = i.get_resource(&mut store, "t2").unwrap();48let t3 = i.get_resource(&mut store, "t3").unwrap();49let t4 = i.get_resource(&mut store, "t4").unwrap();50let u1 = i.get_resource(&mut store, "u1").unwrap();51let u2 = i.get_resource(&mut store, "u2").unwrap();5253assert_eq!(t1, ResourceType::host::<T>());54assert_eq!(t2, ResourceType::host::<T>());55assert_eq!(t3, ResourceType::host::<T>());56assert_eq!(t4, ResourceType::host::<T>());57assert_eq!(u1, ResourceType::host::<U>());58assert_eq!(u2, ResourceType::host::<U>());59Ok(())60}6162#[test]63fn guest_resource_types() -> Result<()> {64let engine = super::engine();65let c = Component::new(66&engine,67r#"68(component69(type $t (resource (rep i32)))70(type $u (resource (rep i32)))7172(export "t1" (type $t))73(export "t2" (type $t))74(export "u1" (type $u))75(export "u2" (type $u))7677(component $c78(import "r" (type $r (sub resource)))79(export "r1" (type $r))80)81(instance $i1 (instantiate $c (with "r" (type $t))))82(instance $i2 (instantiate $c (with "r" (type $t))))83(export "t3" (type $i1 "r1"))84(export "t4" (type $i2 "r1"))85)86"#,87)?;8889let mut store = Store::new(&engine, ());90let linker = Linker::new(&engine);91let i = linker.instantiate(&mut store, &c)?;92let t1 = i.get_resource(&mut store, "t1").unwrap();93let t2 = i.get_resource(&mut store, "t2").unwrap();94let t3 = i.get_resource(&mut store, "t3").unwrap();95let t4 = i.get_resource(&mut store, "t4").unwrap();96let u1 = i.get_resource(&mut store, "u1").unwrap();97let u2 = i.get_resource(&mut store, "u2").unwrap();9899assert_ne!(t1, u1);100assert_eq!(t1, t2);101assert_eq!(t1, t3);102assert_eq!(t1, t4);103assert_eq!(u1, u2);104Ok(())105}106107#[test]108fn resource_any() -> Result<()> {109let engine = super::engine();110let c = Component::new(111&engine,112r#"113(component114(type $t' (resource (rep i32)))115(type $u' (resource (rep i32)))116117(export $t "t" (type $t'))118(export $u "u" (type $u'))119120(core func $t_ctor (canon resource.new $t))121(core func $u_ctor (canon resource.new $u))122123(func (export "[constructor]t") (param "x" u32) (result (own $t))124(canon lift (core func $t_ctor)))125(func (export "[constructor]u") (param "x" u32) (result (own $u))126(canon lift (core func $u_ctor)))127128(core func $t_drop (canon resource.drop $t))129(core func $u_drop (canon resource.drop $u))130131(func (export "drop-t") (param "x" (own $t))132(canon lift (core func $t_drop)))133(func (export "drop-u") (param "x" (own $u))134(canon lift (core func $u_drop)))135)136"#,137)?;138139let linker = Linker::new(&engine);140{141let mut store = Store::new(&engine, ());142let i = linker.instantiate(&mut store, &c)?;143let t = i.get_resource(&mut store, "t").unwrap();144let u = i.get_resource(&mut store, "u").unwrap();145146assert_ne!(t, u);147148let t_ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "[constructor]t")?;149let u_ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "[constructor]u")?;150let t_dtor = i.get_typed_func::<(ResourceAny,), ()>(&mut store, "drop-t")?;151let u_dtor = i.get_typed_func::<(ResourceAny,), ()>(&mut store, "drop-u")?;152153let (t1,) = t_ctor.call(&mut store, (100,))?;154t_ctor.post_return(&mut store)?;155let (t2,) = t_ctor.call(&mut store, (200,))?;156t_ctor.post_return(&mut store)?;157let (u1,) = u_ctor.call(&mut store, (300,))?;158u_ctor.post_return(&mut store)?;159let (u2,) = u_ctor.call(&mut store, (400,))?;160u_ctor.post_return(&mut store)?;161162assert_eq!(t1.ty(), t);163assert_eq!(t2.ty(), t);164assert_eq!(u1.ty(), u);165assert_eq!(u2.ty(), u);166167u_dtor.call(&mut store, (u2,))?;168u_dtor.post_return(&mut store)?;169170u_dtor.call(&mut store, (u1,))?;171u_dtor.post_return(&mut store)?;172173t_dtor.call(&mut store, (t1,))?;174t_dtor.post_return(&mut store)?;175176t_dtor.call(&mut store, (t2,))?;177t_dtor.post_return(&mut store)?;178}179180{181let mut store = Store::new(&engine, ());182let i = linker.instantiate(&mut store, &c)?;183let t_ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "[constructor]t")?;184let u_ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "[constructor]u")?;185let t_dtor = i.get_typed_func::<(ResourceAny,), ()>(&mut store, "drop-t")?;186187// `t` is placed at host index 0188let (t,) = t_ctor.call(&mut store, (100,))?;189t_ctor.post_return(&mut store)?;190t_dtor.call(&mut store, (t,))?;191t_dtor.post_return(&mut store)?;192193// `u` is also placed at host index 0 since `t` was deallocated194let (_u,) = u_ctor.call(&mut store, (100,))?;195u_ctor.post_return(&mut store)?;196197// reuse of `t` should fail, despite it pointing to a valid resource198assert_eq!(199t_dtor.call(&mut store, (t,)).unwrap_err().to_string(),200"host-owned resource is being used with the wrong type"201);202}203204Ok(())205}206207#[test]208fn mismatch_intrinsics() -> Result<()> {209let engine = super::engine();210let c = Component::new(211&engine,212r#"213(component214(type $t' (resource (rep i32)))215(type $u' (resource (rep i32)))216217(export $t "t" (type $t'))218(export $u "u" (type $u'))219220;; note the mismatch where this is an intrinsic for `u` but221;; we're typing it as `t`222(core func $t_ctor (canon resource.new $u))223224(func (export "ctor") (param "x" u32) (result (own $t))225(canon lift (core func $t_ctor)))226)227"#,228)?;229230let mut store = Store::new(&engine, ());231let i = Linker::new(&engine).instantiate(&mut store, &c)?;232let ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "ctor")?;233assert_eq!(234ctor.call(&mut store, (100,)).unwrap_err().to_string(),235"handle index 1 used with the wrong type, expected guest-defined \236resource but found a different guest-defined resource",237);238239Ok(())240}241242#[test]243fn mismatch_resource_types() -> Result<()> {244let engine = super::engine();245let c = Component::new(246&engine,247r#"248(component249(type $t' (resource (rep i32)))250(type $u' (resource (rep i32)))251252(export $t "t" (type $t'))253(export $u "u" (type $u'))254255(core func $t_ctor (canon resource.new $t))256(func (export "ctor") (param "x" u32) (result (own $t))257(canon lift (core func $t_ctor)))258259(core func $u_dtor (canon resource.drop $u))260(func (export "dtor") (param "x" (own $u))261(canon lift (core func $u_dtor)))262)263"#,264)?;265266let mut store = Store::new(&engine, ());267let i = Linker::new(&engine).instantiate(&mut store, &c)?;268let ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "ctor")?;269let dtor = i.get_typed_func::<(ResourceAny,), ()>(&mut store, "dtor")?;270271let (t,) = ctor.call(&mut store, (100,))?;272ctor.post_return(&mut store)?;273assert_eq!(274dtor.call(&mut store, (t,)).unwrap_err().to_string(),275"mismatched resource types"276);277278Ok(())279}280281#[test]282fn drop_in_different_places() -> Result<()> {283let engine = super::engine();284let c = Component::new(285&engine,286r#"287(component288(type $t' (resource (rep i32)))289290(export $t "t" (type $t'))291292(core func $ctor (canon resource.new $t))293(func (export "ctor") (param "x" u32) (result (own $t))294(canon lift (core func $ctor)))295296(core func $dtor (canon resource.drop $t))297(func (export "dtor1") (param "x" (own $t))298(canon lift (core func $dtor)))299300(component $c301(import "t" (type $t (sub resource)))302(core func $dtor (canon resource.drop $t))303(func (export "dtor") (param "x" (own $t))304(canon lift (core func $dtor)))305)306(instance $i1 (instantiate $c (with "t" (type $t))))307(instance $i2 (instantiate $c (with "t" (type $t))))308309(export "dtor2" (func $i1 "dtor"))310(export "dtor3" (func $i2 "dtor"))311)312"#,313)?;314315let mut store = Store::new(&engine, ());316let i = Linker::new(&engine).instantiate(&mut store, &c)?;317let ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "ctor")?;318let dtor1 = i.get_typed_func::<(ResourceAny,), ()>(&mut store, "dtor1")?;319let dtor2 = i.get_typed_func::<(ResourceAny,), ()>(&mut store, "dtor2")?;320let dtor3 = i.get_typed_func::<(ResourceAny,), ()>(&mut store, "dtor3")?;321322let (t,) = ctor.call(&mut store, (100,))?;323ctor.post_return(&mut store)?;324dtor1.call(&mut store, (t,))?;325dtor1.post_return(&mut store)?;326327let (t,) = ctor.call(&mut store, (200,))?;328ctor.post_return(&mut store)?;329dtor2.call(&mut store, (t,))?;330dtor2.post_return(&mut store)?;331332let (t,) = ctor.call(&mut store, (300,))?;333ctor.post_return(&mut store)?;334dtor3.call(&mut store, (t,))?;335dtor3.post_return(&mut store)?;336337Ok(())338}339340#[test]341fn drop_guest_twice() -> Result<()> {342let engine = super::engine();343let c = Component::new(344&engine,345r#"346(component347(type $t' (resource (rep i32)))348349(export $t "t" (type $t'))350351(core func $ctor (canon resource.new $t))352(func (export "ctor") (param "x" u32) (result (own $t))353(canon lift (core func $ctor)))354355(core func $dtor (canon resource.drop $t))356(func (export "dtor") (param "x" (own $t))357(canon lift (core func $dtor)))358)359"#,360)?;361362let mut store = Store::new(&engine, ());363let i = Linker::new(&engine).instantiate(&mut store, &c)?;364let ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "ctor")?;365let dtor = i.get_typed_func::<(&ResourceAny,), ()>(&mut store, "dtor")?;366367let (t,) = ctor.call(&mut store, (100,))?;368ctor.post_return(&mut store)?;369dtor.call(&mut store, (&t,))?;370dtor.post_return(&mut store)?;371372assert_eq!(373dtor.call(&mut store, (&t,)).unwrap_err().to_string(),374"unknown handle index 1"375);376377Ok(())378}379380#[test]381fn drop_host_twice() -> Result<()> {382let engine = super::engine();383let c = Component::new(384&engine,385r#"386(component387(import "t" (type $t (sub resource)))388389(core func $dtor (canon resource.drop $t))390(func (export "dtor") (param "x" (own $t))391(canon lift (core func $dtor)))392)393"#,394)?;395396struct MyType;397398let mut store = Store::new(&engine, ());399let mut linker = Linker::new(&engine);400linker401.root()402.resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;403let i = linker.instantiate(&mut store, &c)?;404let dtor = i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "dtor")?;405406let t = Resource::new_own(100);407dtor.call(&mut store, (&t,))?;408dtor.post_return(&mut store)?;409410assert_eq!(411dtor.call(&mut store, (&t,)).unwrap_err().to_string(),412"host resource already consumed"413);414415Ok(())416}417418#[test]419fn manually_destroy() -> Result<()> {420let engine = super::engine();421let c = Component::new(422&engine,423r#"424(component425(import "t1" (type $t1 (sub resource)))426427(core module $m428(global $drops (mut i32) i32.const 0)429(global $last-drop (mut i32) i32.const 0)430431(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")))449450(func (export "t1-pass") (param "t" (own $t1)) (result (own $t1))451(canon lift (core func $i "pass")))452)453"#,454)?;455456struct MyType;457458#[derive(Default)]459struct Data {460drops: u32,461last_drop: Option<u32>,462}463464let mut store = Store::new(&engine, Data::default());465let mut linker = Linker::new(&engine);466linker467.root()468.resource("t1", ResourceType::host::<MyType>(), |mut cx, rep| {469let data: &mut Data = cx.data_mut();470data.drops += 1;471data.last_drop = Some(rep);472Ok(())473})?;474let i = linker.instantiate(&mut store, &c)?;475let t2_ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "[constructor]t2")?;476let t2_drops = i.get_typed_func::<(), (u32,)>(&mut store, "[static]t2.drops")?;477let t2_last_drop = i.get_typed_func::<(), (u32,)>(&mut store, "[static]t2.last-drop")?;478let t1_pass = i.get_typed_func::<(Resource<MyType>,), (ResourceAny,)>(&mut store, "t1-pass")?;479480// Host resources can be destroyed through `resource_drop`481let t1 = Resource::new_own(100);482let (t1,) = t1_pass.call(&mut store, (t1,))?;483t1_pass.post_return(&mut store)?;484assert_eq!(store.data().drops, 0);485assert_eq!(store.data().last_drop, None);486t1.resource_drop(&mut store)?;487assert_eq!(store.data().drops, 1);488assert_eq!(store.data().last_drop, Some(100));489490// Guest resources can be destroyed through `resource_drop`491let (t2,) = t2_ctor.call(&mut store, (200,))?;492t2_ctor.post_return(&mut store)?;493assert_eq!(t2_drops.call(&mut store, ())?, (0,));494t2_drops.post_return(&mut store)?;495assert_eq!(t2_last_drop.call(&mut store, ())?, (0,));496t2_last_drop.post_return(&mut store)?;497t2.resource_drop(&mut store)?;498assert_eq!(t2_drops.call(&mut store, ())?, (1,));499t2_drops.post_return(&mut store)?;500assert_eq!(t2_last_drop.call(&mut store, ())?, (200,));501t2_last_drop.post_return(&mut store)?;502503// Wires weren't crossed to drop more resources504assert_eq!(store.data().drops, 1);505assert_eq!(store.data().last_drop, Some(100));506507Ok(())508}509510#[test]511fn dynamic_type() -> Result<()> {512let engine = super::engine();513let c = Component::new(514&engine,515r#"516(component517(import "t1" (type $t1 (sub resource)))518(type $t2' (resource (rep i32)))519(export $t2 "t2" (type $t2'))520(core func $f (canon resource.drop $t2))521522(func (export "a") (param "x" (own $t1))523(canon lift (core func $f)))524(func (export "b") (param "x" (tuple (own $t2)))525(canon lift (core func $f)))526)527"#,528)?;529530struct MyType;531532let mut store = Store::new(&engine, ());533let mut linker = Linker::new(&engine);534linker535.root()536.resource("t1", ResourceType::host::<MyType>(), |_, _| Ok(()))?;537let i = linker.instantiate(&mut store, &c)?;538539let a = i.get_func(&mut store, "a").unwrap();540let b = i.get_func(&mut store, "b").unwrap();541let t2 = i.get_resource(&mut store, "t2").unwrap();542543let a_params = a.params(&store);544assert_eq!(545a_params[0],546("x".to_string(), Type::Own(ResourceType::host::<MyType>()))547);548let b_params = b.params(&store);549match &b_params[0] {550(name, Type::Tuple(t)) => {551assert_eq!(name, "x");552assert_eq!(t.types().len(), 1);553let t0 = t.types().next().unwrap();554assert_eq!(t0, Type::Own(t2));555}556_ => unreachable!(),557}558559Ok(())560}561562#[test]563fn dynamic_val() -> Result<()> {564let engine = super::engine();565let c = Component::new(566&engine,567r#"568(component569(import "t1" (type $t1 (sub resource)))570(type $t2' (resource (rep i32)))571(export $t2 "t2" (type $t2'))572(core func $f (canon resource.new $t2))573574(core module $m575(func (export "pass") (param i32) (result i32)576(local.get 0)))577(core instance $i (instantiate $m))578579(func (export "a") (param "x" (own $t1)) (result (own $t1))580(canon lift (core func $i "pass")))581(func (export "b") (param "x" u32) (result (own $t2))582(canon lift (core func $f)))583)584"#,585)?;586587struct MyType;588589let mut store = Store::new(&engine, ());590let mut linker = Linker::new(&engine);591linker592.root()593.resource("t1", ResourceType::host::<MyType>(), |_, _| Ok(()))?;594let i_pre = linker.instantiate_pre(&c)?;595let i = i_pre.instantiate(&mut store)?;596597let a = i.get_func(&mut store, "a").unwrap();598let a_typed = i.get_typed_func::<(Resource<MyType>,), (ResourceAny,)>(&mut store, "a")?;599let a_typed_result =600i.get_typed_func::<(Resource<MyType>,), (Resource<MyType>,)>(&mut store, "a")?;601let b = i.get_func(&mut store, "b").unwrap();602let t2 = i.get_resource(&mut store, "t2").unwrap();603604let t1 = Resource::new_own(100);605let (t1,) = a_typed.call(&mut store, (t1,))?;606a_typed.post_return(&mut store)?;607assert_eq!(t1.ty(), ResourceType::host::<MyType>());608609let mut results = [Val::Bool(false)];610a.call(&mut store, &[Val::Resource(t1)], &mut results)?;611a.post_return(&mut store)?;612match &results[0] {613Val::Resource(resource) => {614assert_eq!(resource.ty(), ResourceType::host::<MyType>());615assert!(resource.owned());616617let resource = resource.try_into_resource::<MyType>(&mut store)?;618assert_eq!(resource.rep(), 100);619assert!(resource.owned());620621let resource = resource.try_into_resource_any(&mut store)?;622assert_eq!(resource.ty(), ResourceType::host::<MyType>());623assert!(resource.owned());624}625_ => unreachable!(),626}627628let t1_any = Resource::<MyType>::new_own(100).try_into_resource_any(&mut store)?;629let mut results = [Val::Bool(false)];630a.call(&mut store, &[Val::Resource(t1_any)], &mut results)?;631a.post_return(&mut store)?;632match &results[0] {633Val::Resource(resource) => {634assert_eq!(resource.ty(), ResourceType::host::<MyType>());635assert!(resource.owned());636637let resource = resource.try_into_resource::<MyType>(&mut store)?;638assert_eq!(resource.rep(), 100);639assert!(resource.owned());640641let resource = resource.try_into_resource_any(&mut store)?;642assert_eq!(resource.ty(), ResourceType::host::<MyType>());643assert!(resource.owned());644}645_ => unreachable!(),646}647648let t1 = Resource::<MyType>::new_own(100)649.try_into_resource_any(&mut store)?650.try_into_resource(&mut store)?;651let (t1,) = a_typed_result.call(&mut store, (t1,))?;652a_typed_result.post_return(&mut store)?;653assert_eq!(t1.rep(), 100);654assert!(t1.owned());655656let t1_any = t1657.try_into_resource_any(&mut store)?658.try_into_resource::<MyType>(&mut store)?659.try_into_resource_any(&mut store)?;660let mut results = [Val::Bool(false)];661a.call(&mut store, &[Val::Resource(t1_any)], &mut results)?;662a.post_return(&mut store)?;663match &results[0] {664Val::Resource(resource) => {665assert_eq!(resource.ty(), ResourceType::host::<MyType>());666assert!(resource.owned());667668let resource = resource.try_into_resource::<MyType>(&mut store)?;669assert_eq!(resource.rep(), 100);670assert!(resource.owned());671672let resource = resource.try_into_resource_any(&mut store)?;673assert_eq!(resource.ty(), ResourceType::host::<MyType>());674assert!(resource.owned());675}676_ => unreachable!(),677}678679b.call(&mut store, &[Val::U32(200)], &mut results)?;680match &results[0] {681Val::Resource(resource) => {682assert_eq!(resource.ty(), t2);683}684_ => unreachable!(),685}686687Ok(())688}689690#[test]691fn cannot_reenter_during_import() -> Result<()> {692let engine = super::engine();693let c = Component::new(694&engine,695r#"696(component697(import "f" (func $f))698699(core func $f (canon lower (func $f)))700701(core module $m702(import "" "f" (func $f))703(func (export "call") call $f)704(func (export "dtor") (param i32) unreachable)705)706707(core instance $i (instantiate $m708(with "" (instance709(export "f" (func $f))710))711))712713(type $t2' (resource (rep i32) (dtor (func $i "dtor"))))714(export $t2 "t" (type $t2'))715(core func $ctor (canon resource.new $t2))716(func (export "ctor") (param "x" u32) (result (own $t2))717(canon lift (core func $ctor)))718719(func (export "call") (canon lift (core func $i "call")))720)721"#,722)?;723724let mut store = Store::new(&engine, None);725let mut linker = Linker::new(&engine);726linker.root().func_wrap("f", |mut cx, ()| {727let data: &mut Option<ResourceAny> = cx.data_mut();728let err = data.take().unwrap().resource_drop(cx).unwrap_err();729assert_eq!(730err.downcast_ref(),731Some(&Trap::CannotEnterComponent),732"bad error: {err:?}"733);734Ok(())735})?;736let i = linker.instantiate(&mut store, &c)?;737738let ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "ctor")?;739let call = i.get_typed_func::<(), ()>(&mut store, "call")?;740741let (resource,) = ctor.call(&mut store, (100,))?;742ctor.post_return(&mut store)?;743*store.data_mut() = Some(resource);744call.call(&mut store, ())?;745746Ok(())747}748749#[test]750fn active_borrows_at_end_of_call() -> Result<()> {751let engine = super::engine();752let c = Component::new(753&engine,754r#"755(component756(import "t" (type $t (sub resource)))757758(core module $m759(func (export "f") (param i32))760)761(core instance $i (instantiate $m))762763(func (export "f") (param "x" (borrow $t))764(canon lift (core func $i "f")))765)766"#,767)?;768769struct MyType;770771let mut store = Store::new(&engine, ());772let mut linker = Linker::new(&engine);773linker774.root()775.resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;776let i = linker.instantiate(&mut store, &c)?;777778let f = i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "f")?;779780let resource = Resource::new_own(1);781f.call(&mut store, (&resource,))?;782let err = f.post_return(&mut store).unwrap_err();783assert_eq!(784err.to_string(),785"borrow handles still remain at the end of the call",786);787788Ok(())789}790791#[test]792fn thread_through_borrow() -> Result<()> {793let engine = super::engine();794let c = Component::new(795&engine,796r#"797(component798(import "t" (type $t (sub resource)))799(import "f" (func $f (param "x" (borrow $t))))800801(core func $f (canon lower (func $f)))802(core func $drop (canon resource.drop $t))803804(core module $m805(import "" "f" (func $f (param i32)))806(import "" "drop" (func $drop (param i32)))807(func (export "f2") (param i32)808(call $f (local.get 0))809(call $f (local.get 0))810(call $drop (local.get 0))811)812)813(core instance $i (instantiate $m814(with "" (instance815(export "f" (func $f))816(export "drop" (func $drop))817))818))819820(func (export "f2") (param "x" (borrow $t))821(canon lift (core func $i "f2")))822)823"#,824)?;825826struct MyType;827828let mut store = Store::new(&engine, ());829let mut linker = Linker::new(&engine);830linker831.root()832.resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;833linker834.root()835.func_wrap("f", |_cx, (r,): (Resource<MyType>,)| {836assert!(!r.owned());837assert_eq!(r.rep(), 100);838Ok(())839})?;840let i = linker.instantiate(&mut store, &c)?;841842let f = i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "f2")?;843844let resource = Resource::new_own(100);845f.call(&mut store, (&resource,))?;846f.post_return(&mut store)?;847Ok(())848}849850#[test]851fn cannot_use_borrow_for_own() -> Result<()> {852let engine = super::engine();853let c = Component::new(854&engine,855r#"856(component857(import "t" (type $t (sub resource)))858859(core module $m860(func (export "f") (param i32) (result i32)861local.get 0862)863)864(core instance $i (instantiate $m))865866(func (export "f") (param "x" (borrow $t)) (result (own $t))867(canon lift (core func $i "f")))868)869"#,870)?;871872struct MyType;873874let mut store = Store::new(&engine, ());875let mut linker = Linker::new(&engine);876linker877.root()878.resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;879let i = linker.instantiate(&mut store, &c)?;880881let f = i.get_typed_func::<(&Resource<MyType>,), (Resource<MyType>,)>(&mut store, "f")?;882883let resource = Resource::new_own(100);884let err = f.call(&mut store, (&resource,)).unwrap_err();885assert_eq!(err.to_string(), "cannot lift own resource from a borrow");886Ok(())887}888889#[test]890fn can_use_own_for_borrow() -> Result<()> {891let engine = super::engine();892let c = Component::new(893&engine,894r#"895(component896(import "t" (type $t (sub resource)))897898(core func $drop (canon resource.drop $t))899900(core module $m901(import "" "drop" (func $drop (param i32)))902(func (export "f") (param i32)903(call $drop (local.get 0))904)905)906(core instance $i (instantiate $m907(with "" (instance908(export "drop" (func $drop))909))910))911912(func (export "f") (param "x" (borrow $t))913(canon lift (core func $i "f")))914)915"#,916)?;917918struct MyType;919920let mut store = Store::new(&engine, ());921let mut linker = Linker::new(&engine);922linker923.root()924.resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;925let i_pre = linker.instantiate_pre(&c)?;926let i = i_pre.instantiate(&mut store)?;927928let f = i.get_func(&mut store, "f").unwrap();929let f_typed = i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "f")?;930931let resource = Resource::new_own(100);932f_typed.call(&mut store, (&resource,))?;933f_typed.post_return(&mut store)?;934935let resource = Resource::new_borrow(200);936f_typed.call(&mut store, (&resource,))?;937f_typed.post_return(&mut store)?;938939let resource = Resource::<MyType>::new_own(300).try_into_resource_any(&mut store)?;940f.call(&mut store, &[Val::Resource(resource)], &mut [])?;941f.post_return(&mut store)?;942resource.resource_drop(&mut store)?;943944// TODO: Enable once https://github.com/bytecodealliance/wasmtime/issues/7793 is fixed945//let resource =946// Resource::<MyType>::new_borrow(400).try_into_resource_any(&mut store, &i_pre, ty_idx)?;947//f.call(&mut store, &[Val::Resource(resource)], &mut [])?;948//f.post_return(&mut store)?;949//resource.resource_drop(&mut store)?;950951Ok(())952}953954#[test]955fn passthrough_wrong_type() -> Result<()> {956let engine = super::engine();957let c = Component::new(958&engine,959r#"960(component961(import "t" (type $t (sub resource)))962(import "f" (func $f (param "a" (borrow $t)) (result (own $t))))963964(core func $f (canon lower (func $f)))965966(core module $m967(import "" "f" (func $f (param i32) (result i32)))968(func (export "f2") (param i32)969(drop (call $f (local.get 0)))970)971)972(core instance $i (instantiate $m973(with "" (instance974(export "f" (func $f))975))976))977978(func (export "f2") (param "x" (borrow $t))979(canon lift (core func $i "f2")))980)981"#,982)?;983984struct MyType;985986let mut store = Store::new(&engine, ());987let mut linker = Linker::new(&engine);988linker989.root()990.resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;991linker992.root()993.func_wrap("f", |_cx, (r,): (Resource<MyType>,)| Ok((r,)))?;994let i = linker.instantiate(&mut store, &c)?;995996let f = i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "f2")?;997998let resource = Resource::new_own(100);999let err = f.call(&mut store, (&resource,)).unwrap_err();1000assert!(1001format!("{err:?}").contains("cannot lower a `borrow` resource into an `own`"),1002"bad error: {err:?}"1003);1004Ok(())1005}10061007#[test]1008fn pass_moved_resource() -> Result<()> {1009let engine = super::engine();1010let c = Component::new(1011&engine,1012r#"1013(component1014(import "t" (type $t (sub resource)))1015(core module $m1016(func (export "f") (param i32 i32))1017)1018(core instance $i (instantiate $m))10191020(func (export "f") (param "x" (own $t)) (param "y" (borrow $t))1021(canon lift (core func $i "f")))1022)1023"#,1024)?;10251026struct MyType;10271028let mut store = Store::new(&engine, ());1029let mut linker = Linker::new(&engine);1030linker1031.root()1032.resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;1033let i = linker.instantiate(&mut store, &c)?;10341035let f = i.get_typed_func::<(&Resource<MyType>, &Resource<MyType>), ()>(&mut store, "f")?;10361037let resource = Resource::new_own(100);1038let err = f.call(&mut store, (&resource, &resource)).unwrap_err();1039assert!(1040format!("{err:?}").contains("host resource already consumed"),1041"bad error: {err:?}"1042);1043Ok(())1044}10451046#[test]1047fn type_mismatch() -> Result<()> {1048let engine = super::engine();1049let c = Component::new(1050&engine,1051r#"1052(component1053(type $t' (resource (rep i32)))1054(export $t "t" (type $t'))10551056(core func $drop (canon resource.drop $t))10571058(func (export "f1") (param "x" (own $t))1059(canon lift (core func $drop)))1060(func (export "f2") (param "x" (borrow $t))1061(canon lift (core func $drop)))1062(func (export "f3") (param "x" u32)1063(canon lift (core func $drop)))1064)1065"#,1066)?;10671068struct MyType;10691070let mut store = Store::new(&engine, ());1071let i = Linker::new(&engine).instantiate(&mut store, &c)?;10721073assert!(1074i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "f1")1075.is_err()1076);1077assert!(1078i.get_typed_func::<(&ResourceAny,), ()>(&mut store, "f1")1079.is_ok()1080);10811082assert!(1083i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "f2")1084.is_err()1085);1086assert!(1087i.get_typed_func::<(&ResourceAny,), ()>(&mut store, "f2")1088.is_ok()1089);10901091assert!(1092i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "f3")1093.is_err()1094);1095assert!(1096i.get_typed_func::<(&ResourceAny,), ()>(&mut store, "f3")1097.is_err()1098);1099assert!(i.get_typed_func::<(u32,), ()>(&mut store, "f3").is_ok());11001101Ok(())1102}11031104#[test]1105fn drop_no_dtor() -> Result<()> {1106let engine = super::engine();1107let c = Component::new(1108&engine,1109r#"1110(component1111(type $t' (resource (rep i32)))1112(export $t "t" (type $t'))11131114(core func $ctor (canon resource.new $t))11151116(func (export "ctor") (param "x" u32) (result (own $t))1117(canon lift (core func $ctor)))1118)1119"#,1120)?;11211122let mut store = Store::new(&engine, ());1123let i = Linker::new(&engine).instantiate(&mut store, &c)?;1124let ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "ctor")?;1125let (resource,) = ctor.call(&mut store, (100,))?;1126ctor.post_return(&mut store)?;1127resource.resource_drop(&mut store)?;11281129Ok(())1130}11311132#[test]1133fn host_borrow_as_resource_any() -> Result<()> {1134let engine = super::engine();1135let c = Component::new(1136&engine,1137r#"1138(component1139(import "t" (type $t (sub resource)))1140(import "f" (func $f (param "f" (borrow $t))))11411142(core func $f (canon lower (func $f)))11431144(core module $m1145(import "" "f" (func $f (param i32)))1146(func (export "f2") (param i32)1147(call $f (local.get 0))1148)1149)1150(core instance $i (instantiate $m1151(with "" (instance1152(export "f" (func $f))1153))1154))11551156(func (export "f2") (param "x" (borrow $t))1157(canon lift (core func $i "f2")))1158)1159"#,1160)?;11611162struct MyType;11631164let mut store = Store::new(&engine, ());11651166// First test the above component where the host properly drops the argument1167{1168let mut linker = Linker::new(&engine);1169linker1170.root()1171.resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;1172linker1173.root()1174.func_wrap("f", |mut cx, (r,): (ResourceAny,)| {1175r.resource_drop(&mut cx)?;1176Ok(())1177})?;1178let i = linker.instantiate(&mut store, &c)?;11791180let f = i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "f2")?;11811182let resource = Resource::new_own(100);1183f.call(&mut store, (&resource,))?;1184}11851186// Then also test the case where the host forgets a drop1187{1188let mut linker = Linker::new(&engine);1189linker1190.root()1191.resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;1192linker.root().func_wrap("f", |_cx, (_r,): (ResourceAny,)| {1193// ... no drop here1194Ok(())1195})?;1196let i = linker.instantiate(&mut store, &c)?;11971198let f = i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "f2")?;11991200let resource = Resource::new_own(100);1201let err = f.call(&mut store, (&resource,)).unwrap_err();1202assert!(1203format!("{err:?}").contains("borrow handles still remain at the end of the call"),1204"bad error: {err:?}"1205);1206}1207Ok(())1208}12091210#[test]1211fn pass_guest_back_as_borrow() -> Result<()> {1212let engine = super::engine();1213let c = Component::new(1214&engine,1215r#"1216(component1217(type $t' (resource (rep i32)))12181219(export $t "t" (type $t'))12201221(core func $new (canon resource.new $t))12221223(core module $m1224(import "" "new" (func $new (param i32) (result i32)))12251226(func (export "mk") (result i32)1227(call $new (i32.const 100))1228)12291230(func (export "take") (param i32)1231(if (i32.ne (local.get 0) (i32.const 100)) (then (unreachable)))1232)1233)1234(core instance $i (instantiate $m1235(with "" (instance1236(export "new" (func $new))1237))1238))12391240(func (export "mk") (result (own $t))1241(canon lift (core func $i "mk")))1242(func (export "take") (param "x" (borrow $t))1243(canon lift (core func $i "take")))1244)1245"#,1246)?;12471248let mut store = Store::new(&engine, ());1249let i = Linker::new(&engine).instantiate(&mut store, &c)?;1250let mk = i.get_typed_func::<(), (ResourceAny,)>(&mut store, "mk")?;1251let take = i.get_typed_func::<(&ResourceAny,), ()>(&mut store, "take")?;12521253let (resource,) = mk.call(&mut store, ())?;1254mk.post_return(&mut store)?;1255take.call(&mut store, (&resource,))?;1256take.post_return(&mut store)?;12571258resource.resource_drop(&mut store)?;12591260// Should not be valid to use `resource` again1261let err = take.call(&mut store, (&resource,)).unwrap_err();1262assert_eq!(err.to_string(), "unknown handle index 1");12631264Ok(())1265}12661267#[test]1268fn pass_host_borrow_to_guest() -> Result<()> {1269let engine = super::engine();1270let c = Component::new(1271&engine,1272r#"1273(component1274(import "t" (type $t (sub resource)))12751276(core func $drop (canon resource.drop $t))12771278(core module $m1279(import "" "drop" (func $drop (param i32)))1280(func (export "take") (param i32)1281(call $drop (local.get 0))1282)1283)1284(core instance $i (instantiate $m1285(with "" (instance1286(export "drop" (func $drop))1287))1288))12891290(func (export "take") (param "x" (borrow $t))1291(canon lift (core func $i "take")))1292)1293"#,1294)?;12951296struct MyType;12971298let mut store = Store::new(&engine, ());1299let mut linker = Linker::new(&engine);1300linker1301.root()1302.resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;1303let i = linker.instantiate(&mut store, &c)?;1304let take = i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "take")?;13051306let resource = Resource::new_borrow(100);1307take.call(&mut store, (&resource,))?;1308take.post_return(&mut store)?;13091310Ok(())1311}13121313#[test]1314fn drop_on_owned_resource() -> Result<()> {1315let engine = super::engine();1316let c = Component::new(1317&engine,1318r#"1319(component1320(import "t" (type $t (sub resource)))1321(import "[constructor]t" (func $ctor (result (own $t))))1322(import "[method]t.foo" (func $foo (param "self" (borrow $t)) (result (list u8))))13231324(core func $ctor (canon lower (func $ctor)))1325(core func $drop (canon resource.drop $t))13261327(core module $m11328(import "" "drop" (func $drop (param i32)))1329(memory (export "memory") 1)1330(global $to-drop (export "to-drop") (mut i32) (i32.const 0))1331(func (export "realloc") (param i32 i32 i32 i32) (result i32)1332(call $drop (global.get $to-drop))1333unreachable)1334)1335(core instance $i1 (instantiate $m11336(with "" (instance1337(export "drop" (func $drop))1338))1339))13401341(core func $foo (canon lower (func $foo)1342(memory $i1 "memory")1343(realloc (func $i1 "realloc"))))13441345(core module $m21346(import "" "ctor" (func $ctor (result i32)))1347(import "" "foo" (func $foo (param i32 i32)))1348(import "i1" "to-drop" (global $to-drop (mut i32)))13491350(func (export "f")1351(local $r i32)1352(local.set $r (call $ctor))1353(global.set $to-drop (local.get $r))1354(call $foo1355(local.get $r)1356(i32.const 200))1357)1358)1359(core instance $i2 (instantiate $m21360(with "" (instance1361(export "ctor" (func $ctor))1362(export "foo" (func $foo))1363))1364(with "i1" (instance $i1))1365))1366(func (export "f") (canon lift (core func $i2 "f")))1367)1368"#,1369)?;13701371struct MyType;13721373let mut store = Store::new(&engine, ());1374let mut linker = Linker::new(&engine);1375linker1376.root()1377.resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;1378linker.root().func_wrap("[constructor]t", |_cx, ()| {1379Ok((Resource::<MyType>::new_own(300),))1380})?;1381linker1382.root()1383.func_wrap("[method]t.foo", |_cx, (r,): (Resource<MyType>,)| {1384assert!(!r.owned());1385Ok((vec![2u8],))1386})?;1387let i = linker.instantiate(&mut store, &c)?;1388let f = i.get_typed_func::<(), ()>(&mut store, "f")?;13891390let err = f.call(&mut store, ()).unwrap_err();1391assert!(1392format!("{err:?}").contains("cannot remove owned resource while borrowed"),1393"bad error: {err:?}"1394);13951396Ok(())1397}13981399#[test]1400fn guest_different_host_same() -> Result<()> {1401let engine = super::engine();1402let c = Component::new(1403&engine,1404r#"1405(component1406(import "t1" (type $t1 (sub resource)))1407(import "t2" (type $t2 (sub resource)))14081409(import "f" (func $f (param "a" (borrow $t1)) (param "b" (borrow $t2))))14101411(export $g1 "g1" (type $t1))1412(export $g2 "g2" (type $t2))14131414(core func $f (canon lower (func $f)))1415(core func $drop1 (canon resource.drop $t1))1416(core func $drop2 (canon resource.drop $t2))14171418(core module $m1419(import "" "f" (func $f (param i32 i32)))1420(import "" "drop1" (func $drop1 (param i32)))1421(import "" "drop2" (func $drop2 (param i32)))14221423(func (export "f") (param i32 i32)1424;; different types, but everything goes into the same1425;; handle index namespace1426(if (i32.ne (local.get 0) (i32.const 1)) (then (unreachable)))1427(if (i32.ne (local.get 1) (i32.const 2)) (then (unreachable)))14281429;; host should end up getting the same resource1430(call $f (local.get 0) (local.get 1))14311432;; drop our borrows1433(call $drop1 (local.get 0))1434(call $drop2 (local.get 1))1435)1436)1437(core instance $i (instantiate $m1438(with "" (instance1439(export "f" (func $f))1440(export "drop1" (func $drop1))1441(export "drop2" (func $drop2))1442))1443))14441445(func (export "f2") (param "a" (borrow $g1)) (param "b" (borrow $g2))1446(canon lift (core func $i "f")))1447)1448"#,1449)?;14501451struct MyType;14521453let mut store = Store::new(&engine, ());1454let mut linker = Linker::new(&engine);1455linker1456.root()1457.resource("t1", ResourceType::host::<MyType>(), |_, _| Ok(()))?;1458linker1459.root()1460.resource("t2", ResourceType::host::<MyType>(), |_, _| Ok(()))?;1461linker.root().func_wrap(1462"f",1463|_cx, (r1, r2): (Resource<MyType>, Resource<MyType>)| {1464assert!(!r1.owned());1465assert!(!r2.owned());1466assert_eq!(r1.rep(), 100);1467assert_eq!(r2.rep(), 100);1468Ok(())1469},1470)?;1471let i = linker.instantiate(&mut store, &c)?;1472let f = i.get_typed_func::<(&Resource<MyType>, &Resource<MyType>), ()>(&mut store, "f2")?;14731474let t1 = i.get_resource(&mut store, "g1").unwrap();1475let t2 = i.get_resource(&mut store, "g2").unwrap();1476assert_eq!(t1, t2);1477assert_eq!(t1, ResourceType::host::<MyType>());14781479let resource = Resource::new_own(100);1480f.call(&mut store, (&resource, &resource))?;1481f.post_return(&mut store)?;14821483Ok(())1484}14851486#[test]1487fn resource_any_to_typed_handles_borrow() -> Result<()> {1488let engine = super::engine();1489let c = Component::new(1490&engine,1491r#"1492(component1493(import "t" (type $t (sub resource)))14941495(import "f" (func $f (param "a" (borrow $t))))14961497(core func $f (canon lower (func $f)))14981499(core module $m1500(import "" "f" (func $f (param i32)))15011502(func (export "f") (param i32)1503(call $f (local.get 0))1504)1505)1506(core instance $i (instantiate $m1507(with "" (instance1508(export "f" (func $f))1509))1510))15111512(func (export "f") (param "a" (own $t))1513(canon lift (core func $i "f")))1514)1515"#,1516)?;15171518struct MyType;15191520let mut store = Store::new(&engine, ());1521let mut linker = Linker::new(&engine);1522linker1523.root()1524.resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;1525linker1526.root()1527.func_wrap("f", |mut cx, (r,): (ResourceAny,)| {1528let r = r.try_into_resource::<MyType>(&mut cx).unwrap();1529assert_eq!(r.rep(), 100);1530assert!(!r.owned());1531Ok(())1532})?;1533let i = linker.instantiate(&mut store, &c)?;1534let f = i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "f")?;15351536let resource = Resource::new_own(100);1537f.call(&mut store, (&resource,))?;1538f.post_return(&mut store)?;15391540Ok(())1541}154215431544