Repository: bytecodealliance/wasmtime
Pull request #7788 (2024-01-18 00:44:00)

mpk: add `--memory-protection-keys` to the CLI options
This only adds MPK configuration to the new Wasmtime flags.


Patch:
diff --git a/Cargo.toml b/Cargo.toml
index b7c83c71a..c66ed0db4 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -179,7 +179,7 @@ component-fuzz-util = { path = "crates/misc/component-fuzz-util" }
 wiggle = { path = "crates/wiggle", version = "=18.0.0", default-features = false }
 wiggle-macro = { path = "crates/wiggle/macro", version = "=18.0.0" }
 wiggle-generate = { path = "crates/wiggle/generate", version = "=18.0.0" }
-wasi-common = { path = "crates/wasi-common", version = "=18.0.0" }
+wasi-common = { path = "crates/wasi-common", version = "=18.0.0", default-features = false }
 wasi-tokio = { path = "crates/wasi-common/tokio", version = "=18.0.0" }
 wasi-cap-std-sync = { path = "crates/wasi-common/cap-std-sync", version = "=18.0.0" }
 wasmtime-fuzzing = { path = "crates/fuzzing" }
diff --git a/benches/call.rs b/benches/call.rs
index 90f9beca6..fbfe96d84 100644
--- a/benches/call.rs
+++ b/benches/call.rs
@@ -23,6 +23,7 @@ enum IsAsync {
     Yes,
     YesPooling,
     No,
+    NoPooling,
 }
 
 impl IsAsync {
@@ -31,12 +32,13 @@ impl IsAsync {
             IsAsync::Yes => "async",
             IsAsync::YesPooling => "async-pool",
             IsAsync::No => "sync",
+            IsAsync::NoPooling => "sync-pool",
         }
     }
     fn use_async(&self) -> bool {
         match self {
             IsAsync::Yes | IsAsync::YesPooling => true,
-            IsAsync::No => false,
+            IsAsync::No | IsAsync::NoPooling => false,
         }
     }
 }
@@ -47,14 +49,29 @@ fn engines() -> Vec<(Engine, IsAsync)> {
     #[cfg(feature = "component-model")]
     config.wasm_component_model(true);
 
+    let mut pool = PoolingAllocationConfig::default();
+    if std::env::var("WASMTIME_TEST_FORCE_MPK").is_ok() {
+        pool.memory_protection_keys(MpkEnabled::Enable);
+    }
+
     vec![
         (Engine::new(&config).unwrap(), IsAsync::No),
+        (
+            Engine::new(
+                config
+                    .clone()
+                    .allocation_strategy(InstanceAllocationStrategy::Pooling(pool.clone())),
+            )
+            .unwrap(),
+            IsAsync::NoPooling,
+        ),
         (
             Engine::new(config.async_support(true)).unwrap(),
             IsAsync::Yes,
         ),
         (
-            Engine::new(config.allocation_strategy(InstanceAllocationStrategy::pooling())).unwrap(),
+            Engine::new(config.allocation_strategy(InstanceAllocationStrategy::Pooling(pool)))
+                .unwrap(),
             IsAsync::YesPooling,
         ),
     ]
diff --git a/crates/cli-flags/src/lib.rs b/crates/cli-flags/src/lib.rs
index 1192017dc..199a4f082 100644
--- a/crates/cli-flags/src/lib.rs
+++ b/crates/cli-flags/src/lib.rs
@@ -70,6 +70,10 @@ wasmtime_option_group! {
         /// pooling allocator in tables.
         pub pooling_table_keep_resident: Option<usize>,
 
+        /// Enable memory protection keys for the pooling allocator; this can
+        /// optimize the size of memory slots.
+        pub memory_protection_keys: Option<bool>,
+
         /// Configure attempting to initialize linear memory via a
         /// copy-on-write mapping (default: yes)
         pub memory_init_cow: Option<bool>,
@@ -517,12 +521,23 @@ impl CommonOptions {
                     if let Some(size) = self.opts.pooling_table_keep_resident {
                         cfg.table_keep_resident(size);
                     }
+                    if let Some(enable) = self.opts.memory_protection_keys {
+                        if enable {
+                            cfg.memory_protection_keys(wasmtime::MpkEnabled::Enable);
+                        }
+                    }
                     config.allocation_strategy(wasmtime::InstanceAllocationStrategy::Pooling(cfg));
                 }
             },
             true => err,
         }
 
+        if self.opts.memory_protection_keys.unwrap_or(false)
+            && !self.opts.pooling_allocator.unwrap_or(false)
+        {
+            anyhow::bail!("memory protection keys require the pooling allocator");
+        }
+
         if let Some(max) = self.wasm.max_wasm_stack {
             config.max_wasm_stack(max);
         }
diff --git a/crates/component-macro/build.rs b/crates/component-macro/build.rs
new file mode 100644
index 000000000..be0ad5bc9
--- /dev/null
+++ b/crates/component-macro/build.rs
@@ -0,0 +1,5 @@
+fn main() {
+    println!("cargo:rerun-if-changed=build.rs");
+    let out_dir = std::env::var("OUT_DIR").unwrap();
+    println!("cargo:rustc-env=DEBUG_OUTPUT_DIR={out_dir}");
+}
diff --git a/crates/component-macro/src/bindgen.rs b/crates/component-macro/src/bindgen.rs
index 096126be2..361354108 100644
--- a/crates/component-macro/src/bindgen.rs
+++ b/crates/component-macro/src/bindgen.rs
@@ -3,6 +3,7 @@ use quote::ToTokens;
 use std::collections::HashMap;
 use std::collections::HashSet;
 use std::path::{Path, PathBuf};
+use std::sync::atomic::{AtomicUsize, Ordering::Relaxed};
 use syn::parse::{Error, Parse, ParseStream, Result};
 use syn::punctuated::Punctuated;
 use syn::{braced, token, Token};
@@ -24,7 +25,31 @@ pub fn expand(input: &Config) -> Result<TokenStream> {
         ));
     }
 
-    let src = input.opts.generate(&input.resolve, input.world);
+    let mut src = input.opts.generate(&input.resolve, input.world);
+
+    // If a magical `WASMTIME_DEBUG_BINDGEN` environment variable is set then
+    // place a formatted version of the expanded code into a file. This file
+    // will then show up in rustc error messages for any codegen issues and can
+    // be inspected manually.
+    if std::env::var("WASMTIME_DEBUG_BINDGEN").is_ok() {
+        static INVOCATION: AtomicUsize = AtomicUsize::new(0);
+        let root = Path::new(env!("DEBUG_OUTPUT_DIR"));
+        let world_name = &input.resolve.worlds[input.world].name;
+        let n = INVOCATION.fetch_add(1, Relaxed);
+        let path = root.join(format!("{world_name}{n}.rs"));
+
+        std::fs::write(&path, &src).unwrap();
+
+        // optimistically format the code but don't require success
+        drop(
+            std::process::Command::new("rustfmt")
+                .arg(&path)
+                .arg("--edition=2021")
+                .output(),
+        );
+
+        src = format!("include!({path:?});");
+    }
     let mut contents = src.parse::<TokenStream>().unwrap();
 
     // Include a dummy `include_str!` for any files we read so rustc knows that
diff --git a/crates/runtime/src/mpk/enabled.rs b/crates/runtime/src/mpk/enabled.rs
index 2ce2de8ea..19827532c 100644
--- a/crates/runtime/src/mpk/enabled.rs
+++ b/crates/runtime/src/mpk/enabled.rs
@@ -50,7 +50,11 @@ static KEYS: OnceLock<Vec<ProtectionKey>> = OnceLock::new();
 /// Any accesses to pages marked by another key will result in a `SIGSEGV`
 /// fault.
 pub fn allow(mask: ProtectionMask) {
-    let previous = pkru::read();
+    let previous = if log::log_enabled!(log::Level::Trace) {
+        pkru::read()
+    } else {
+        0
+    };
     pkru::write(mask.0);
     log::trace!("PKRU change: {:#034b} => {:#034b}", previous, pkru::read());
 }
diff --git a/crates/runtime/src/mpk/pkru.rs b/crates/runtime/src/mpk/pkru.rs
index af6e54946..0bb7f6321 100644
--- a/crates/runtime/src/mpk/pkru.rs
+++ b/crates/runtime/src/mpk/pkru.rs
@@ -30,6 +30,7 @@ pub const ALLOW_ACCESS: u32 = 0;
 pub const DISABLE_ACCESS: u32 = 0b11111111_11111111_11111111_11111111;
 
 /// Read the value of the `PKRU` register.
+#[inline]
 pub fn read() -> u32 {
     // ECX must be 0 to prevent a general protection exception (#GP).
     let ecx: u32 = 0;
@@ -42,6 +43,7 @@ pub fn read() -> u32 {
 }
 
 /// Write a value to the `PKRU` register.
+#[inline]
 pub fn write(pkru: u32) {
     // Both ECX and EDX must be 0 to prevent a general protection exception
     // (#GP).
diff --git a/crates/wasi-common/Cargo.toml b/crates/wasi-common/Cargo.toml
index 8437fbc50..c0479b9be 100644
--- a/crates/wasi-common/Cargo.toml
+++ b/crates/wasi-common/Cargo.toml
@@ -24,7 +24,7 @@ workspace = true
 anyhow = { workspace = true }
 thiserror = { workspace = true }
 wiggle = { workspace = true }
-wasmtime = { workspace = true }
+wasmtime = { workspace = true, optional = true }
 tracing = { workspace = true }
 cap-std = { workspace = true }
 cap-rand = { workspace = true }
@@ -54,7 +54,7 @@ test-programs-artifacts = { workspace = true }
 tokio = { workspace = true, features = ['macros', 'rt-multi-thread'] }
 
 [features]
-default = ["trace_log"]
+default = ["trace_log", "wasmtime"]
 # This feature enables the `tracing` logs in the calls to target the `log`
 # ecosystem of backends (e.g. `env_logger`. Disable this if you want to use
 # `tracing-subscriber`.
@@ -62,3 +62,5 @@ trace_log = [ "wiggle/tracing_log", "tracing/log" ]
 # Need to make the wiggle_metadata feature available to consumers of this
 # crate if they want the snapshots to have metadata available.
 wiggle_metadata = ["wiggle/wiggle_metadata"]
+# This feature enables integration with wasmtime.
+wasmtime = ["dep:wasmtime", "wiggle/wasmtime"]
\ No newline at end of file
diff --git a/crates/wasi/Cargo.toml b/crates/wasi/Cargo.toml
index f75bc8532..33fc29cc0 100644
--- a/crates/wasi/Cargo.toml
+++ b/crates/wasi/Cargo.toml
@@ -20,7 +20,7 @@ anyhow = { workspace = true }
 wasi-common = { workspace = true }
 wasi-cap-std-sync = { workspace = true, optional = true }
 wasi-tokio = { workspace = true, optional = true }
-wiggle = { workspace = true, optional = true }
+wiggle = { workspace = true, optional = true, features = ["wasmtime"] }
 libc = { workspace = true }
 once_cell = { workspace = true }
 log = { workspace = true }
diff --git a/crates/wasmtime/src/component/func.rs b/crates/wasmtime/src/component/func.rs
index 0b69aff34..cf4f710f1 100644
--- a/crates/wasmtime/src/component/func.rs
+++ b/crates/wasmtime/src/component/func.rs
@@ -362,7 +362,8 @@ impl Func {
         }
 
         for (param, ty) in params.iter().zip(param_tys.iter()) {
-            ty.check(param).context("type mismatch with parameters")?;
+            ty.is_supertype_of(param)
+                .context("type mismatch with parameters")?;
         }
 
         self.call_raw(
diff --git a/crates/wasmtime/src/component/func/host.rs b/crates/wasmtime/src/component/func/host.rs
index a048275b9..c00f38c83 100644
--- a/crates/wasmtime/src/component/func/host.rs
+++ b/crates/wasmtime/src/component/func/host.rs
@@ -385,7 +385,7 @@ where
     let mut cx = LowerContext::new(store, &options, types, instance);
     let instance = cx.instance_type();
     for (val, ty) in result_vals.iter().zip(result_tys.types.iter()) {
-        Type::from(ty, &instance).check(val)?;
+        Type::from(ty, &instance).is_supertype_of(val)?;
     }
     if let Some(cnt) = result_tys.abi.flat_count(MAX_FLAT_RESULTS) {
         let mut dst = storage[..cnt].iter_mut();
diff --git a/crates/wasmtime/src/component/types.rs b/crates/wasmtime/src/component/types.rs
index f751079fa..401ba15ec 100644
--- a/crates/wasmtime/src/component/types.rs
+++ b/crates/wasmtime/src/component/types.rs
@@ -675,9 +675,16 @@ impl Type {
         }
     }
 
-    pub(crate) fn check(&self, value: &Val) -> Result<()> {
+    /// Checks whether type of `value` is a subtype of `self`.
+    ///
+    /// # Errors
+    ///
+    /// Returns an error in case of a type mismatch
+    pub(crate) fn is_supertype_of(&self, value: &Val) -> Result<()> {
         let other = &value.ty();
-        if self == other {
+        if self == other
+            || matches!((self, other), (Self::Borrow(s), Self::Own(other)) if s == other)
+        {
             Ok(())
         } else if mem::discriminant(self) != mem::discriminant(other) {
             Err(anyhow!(
diff --git a/crates/wasmtime/src/component/values.rs b/crates/wasmtime/src/component/values.rs
index 332a0659a..0775dcf7b 100644
--- a/crates/wasmtime/src/component/values.rs
+++ b/crates/wasmtime/src/component/values.rs
@@ -26,7 +26,7 @@ impl List {
         let element_type = ty.ty();
         for (index, value) in values.iter().enumerate() {
             element_type
-                .check(value)
+                .is_supertype_of(value)
                 .with_context(|| format!("type mismatch for element {index} of list"))?;
         }
 
@@ -83,7 +83,7 @@ impl Record {
                     if name == field.name {
                         field
                             .ty
-                            .check(&value)
+                            .is_supertype_of(&value)
                             .with_context(|| format!("type mismatch for field {name} of record"))?;
 
                         values.push(value);
@@ -150,7 +150,7 @@ impl Tuple {
         }
 
         for (index, (value, ty)) in values.iter().zip(ty.types()).enumerate() {
-            ty.check(value)
+            ty.is_supertype_of(value)
                 .with_context(|| format!("type mismatch for field {index} of tuple"))?;
         }
 
@@ -256,7 +256,7 @@ impl Variant {
 fn typecheck_payload(name: &str, case_type: Option<&Type>, value: Option<&Val>) -> Result<()> {
     match (case_type, value) {
         (Some(expected), Some(actual)) => expected
-            .check(&actual)
+            .is_supertype_of(&actual)
             .with_context(|| format!("type mismatch for case {name} of variant")),
         (None, None) => Ok(()),
         (Some(_), None) => bail!("expected a payload for case `{name}`"),
@@ -341,7 +341,9 @@ impl OptionVal {
     pub fn new(ty: &types::OptionType, value: Option<Val>) -> Result<Self> {
         let value = value
             .map(|value| {
-                ty.ty().check(&value).context("type mismatch for option")?;
+                ty.ty()
+                    .is_supertype_of(&value)
+                    .context("type mismatch for option")?;
 
                 Ok::<_, Error>(value)
             })
diff --git a/crates/wiggle/Cargo.toml b/crates/wiggle/Cargo.toml
index b1d65de00..7dfa3a9a2 100644
--- a/crates/wiggle/Cargo.toml
+++ b/crates/wiggle/Cargo.toml
@@ -20,13 +20,14 @@ wiggle-macro = { workspace = true }
 tracing = { workspace = true }
 bitflags = { workspace = true }
 async-trait = { workspace = true }
-wasmtime = { workspace = true }
+wasmtime = { workspace = true, optional = true }
 anyhow = { workspace = true }
 
 [dev-dependencies]
 wiggle-test = { path = "test-helpers" }
 proptest = "1.0.0"
 tokio = { version = "1", features = ["rt-multi-thread","time", "macros"] }
+wasmtime = { workspace = true }
 
 [[test]]
 name = "atoms_async"
@@ -62,7 +63,10 @@ wiggle_metadata = ['witx', "wiggle-macro/wiggle_metadata"]
 # the logs out of wiggle-generated libraries.
 tracing_log = [ "tracing/log" ]
 
+# This feature enables integration with wasmtime.
+wasmtime = ["dep:wasmtime"]
+
 # Support for async in the wasmtime crates.
 wasmtime_async = [ "wasmtime/async" ]
 
-default = ["wiggle_metadata", "wasmtime_async" ]
+default = ["wiggle_metadata", "wasmtime", "wasmtime_async" ]
diff --git a/crates/wiggle/src/lib.rs b/crates/wiggle/src/lib.rs
index 5fe7eb124..14141c36d 100644
--- a/crates/wiggle/src/lib.rs
+++ b/crates/wiggle/src/lib.rs
@@ -32,6 +32,7 @@ pub mod async_trait_crate {
 }
 
 pub mod wasmtime;
+#[cfg(feature = "wasmtime")]
 pub mod wasmtime_crate {
     pub use wasmtime::*;
 }
diff --git a/crates/wit-bindgen/src/lib.rs b/crates/wit-bindgen/src/lib.rs
index a73f6bcca..c9dd0455a 100644
--- a/crates/wit-bindgen/src/lib.rs
+++ b/crates/wit-bindgen/src/lib.rs
@@ -362,13 +362,13 @@ impl Wasmtime {
                 gen.gen.name_interface(resolve, *id, name, true);
                 gen.current_interface = Some((*id, name, true));
                 gen.types(*id);
+                let struct_name = "Guest";
                 let iface = &resolve.interfaces[*id];
                 let iface_name = match name {
                     WorldKey::Name(name) => name,
                     WorldKey::Interface(_) => iface.name.as_ref().unwrap(),
                 };
-                let camel = to_rust_upper_camel_case(iface_name);
-                uwriteln!(gen.src, "pub struct {camel} {{");
+                uwriteln!(gen.src, "pub struct {struct_name} {{");
                 for (_, func) in iface.functions.iter() {
                     uwriteln!(
                         gen.src,
@@ -378,13 +378,13 @@ impl Wasmtime {
                 }
                 uwriteln!(gen.src, "}}");
 
-                uwriteln!(gen.src, "impl {camel} {{");
+                uwriteln!(gen.src, "impl {struct_name} {{");
                 uwrite!(
                     gen.src,
                     "
                         pub fn new(
                             __exports: &mut wasmtime::component::ExportInstance<'_, '_>,
-                        ) -> wasmtime::Result<{camel}> {{
+                        ) -> wasmtime::Result<{struct_name}> {{
                     "
                 );
                 let mut fields = Vec::new();
@@ -393,7 +393,7 @@ impl Wasmtime {
                     uwriteln!(gen.src, "let {name} = {getter};");
                     fields.push(name);
                 }
-                uwriteln!(gen.src, "Ok({camel} {{");
+                uwriteln!(gen.src, "Ok({struct_name} {{");
                 for name in fields {
                     uwriteln!(gen.src, "{name},");
                 }
@@ -467,7 +467,7 @@ impl Wasmtime {
                 let (path, method_name) = match pkgname {
                     Some(pkgname) => (
                         format!(
-                            "exports::{}::{}::{snake}::{camel}",
+                            "exports::{}::{}::{snake}::{struct_name}",
                             pkgname.namespace.to_snake_case(),
                             self.name_package_module(resolve, iface.package.unwrap()),
                         ),
@@ -477,7 +477,7 @@ impl Wasmtime {
                             self.name_package_module(resolve, iface.package.unwrap())
                         ),
                     ),
-                    None => (format!("exports::{snake}::{camel}"), snake.clone()),
+                    None => (format!("exports::{snake}::{struct_name}"), snake.clone()),
                 };
                 let getter = format!(
                     "\
@@ -519,7 +519,13 @@ impl Wasmtime {
         self.toplevel_import_trait(resolve, world);
 
         uwriteln!(self.src, "const _: () = {{");
-        uwriteln!(self.src, "use wasmtime::component::__internal::anyhow;");
+        uwriteln!(
+            self.src,
+            "
+                #[allow(unused_imports)]
+                use wasmtime::component::__internal::anyhow;
+            "
+        );
 
         uwriteln!(self.src, "impl {camel} {{");
         self.toplevel_add_to_linker(resolve, world);
@@ -1011,14 +1017,6 @@ impl<'a> InterfaceGenerator<'a> {
 
             uwriteln!(self.src, "}}");
         } else {
-            let iface_name = match self.current_interface.unwrap().1 {
-                WorldKey::Name(name) => name.to_upper_camel_case(),
-                WorldKey::Interface(i) => self.resolve.interfaces[*i]
-                    .name
-                    .as_ref()
-                    .unwrap()
-                    .to_upper_camel_case(),
-            };
             self.rustdoc(docs);
             uwriteln!(
                 self.src,
@@ -1026,7 +1024,7 @@ impl<'a> InterfaceGenerator<'a> {
                     pub type {camel} = wasmtime::component::ResourceAny;
 
                     pub struct Guest{camel}<'a> {{
-                        funcs: &'a {iface_name},
+                        funcs: &'a Guest,
                     }}
                 "
             );


Test patch:
diff --git a/crates/component-macro/tests/codegen/wat.wit b/crates/component-macro/tests/codegen/wat.wit
new file mode 100644
index 000000000..cba93e0d4
--- /dev/null
+++ b/crates/component-macro/tests/codegen/wat.wit
@@ -0,0 +1,10 @@
+package same:name;
+
+interface this-name-is-duplicated {
+  resource this-name-is-duplicated {
+  }
+}
+
+world example {
+  export this-name-is-duplicated;
+}
diff --git a/tests/all/cli_tests.rs b/tests/all/cli_tests.rs
index 8a7d08027..478c25830 100644
--- a/tests/all/cli_tests.rs
+++ b/tests/all/cli_tests.rs
@@ -1208,6 +1208,24 @@ fn float_args() -> Result<()> {
     Ok(())
 }
 
+#[test]
+fn mpk_without_pooling() -> Result<()> {
+    let output = get_wasmtime_command()?
+        .args(&[
+            "run",
+            "-O",
+            "memory-protection-keys=y",
+            "--invoke",
+            "echo_f32",
+            "tests/all/cli_tests/simple.wat",
+            "1.0",
+        ])
+        .env("WASMTIME_NEW_CLI", "1")
+        .output()?;
+    assert!(!output.status.success());
+    Ok(())
+}
+
 mod test_programs {
     use super::{get_wasmtime_command, run_wasmtime};
     use anyhow::Result;
diff --git a/tests/all/component_model/resources.rs b/tests/all/component_model/resources.rs
index 448eceecf..bb5938944 100644
--- a/tests/all/component_model/resources.rs
+++ b/tests/all/component_model/resources.rs
@@ -856,6 +856,72 @@ fn cannot_use_borrow_for_own() -> Result<()> {
     Ok(())
 }
 
+#[test]
+fn can_use_own_for_borrow() -> Result<()> {
+    let engine = super::engine();
+    let c = Component::new(
+        &engine,
+        r#"
+            (component
+                (import "t" (type $t (sub resource)))
+
+                (core func $drop (canon resource.drop $t))
+
+                (core module $m
+                    (import "" "drop" (func $drop (param i32)))
+                    (func (export "f") (param i32)
+                        (call $drop (local.get 0))
+                    )
+                )
+                (core instance $i (instantiate $m
+                    (with "" (instance
+                        (export "drop" (func $drop))
+                    ))
+                ))
+
+                (func (export "f") (param "x" (borrow $t))
+                    (canon lift (core func $i "f")))
+            )
+        "#,
+    )?;
+
+    struct MyType;
+
+    let mut store = Store::new(&engine, ());
+    let mut linker = Linker::new(&engine);
+    let ty_idx = linker
+        .root()
+        .resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;
+    let i_pre = linker.instantiate_pre(&c)?;
+    let i = i_pre.instantiate(&mut store)?;
+
+    let f = i.get_func(&mut store, "f").unwrap();
+    let f_typed = i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "f")?;
+
+    let resource = Resource::new_own(100);
+    f_typed.call(&mut store, (&resource,))?;
+    f_typed.post_return(&mut store)?;
+
+    let resource = Resource::new_borrow(200);
+    f_typed.call(&mut store, (&resource,))?;
+    f_typed.post_return(&mut store)?;
+
+    let resource =
+        Resource::<MyType>::new_own(300).try_into_resource_any(&mut store, &i_pre, ty_idx)?;
+    f.call(&mut store, &[Val::Resource(resource)], &mut [])?;
+    f.post_return(&mut store)?;
+    resource.resource_drop(&mut store)?;
+
+    // TODO: Enable once https://github.com/bytecodealliance/wasmtime/issues/7793 is fixed
+    //let resource =
+    //    Resource::<MyType>::new_borrow(400).try_into_resource_any(&mut store, &i_pre, ty_idx)?;
+    //f.call(&mut store, &[Val::Resource(resource)], &mut [])?;
+    //f.post_return(&mut store)?;
+    //resource.resource_drop(&mut store)?;
+
+    Ok(())
+}
+
 #[test]
 fn passthrough_wrong_type() -> Result<()> {
     let engine = super::engine();