diff --git a/benches/call.rs b/benches/call.rs index aef4421b0789..a25cbb8fec8c 100644 --- a/benches/call.rs +++ b/benches/call.rs @@ -367,20 +367,24 @@ fn wasm_to_host(c: &mut Criterion) { let mut typed = Linker::new(&engine); typed - .func_wrap0_async("", "nop", |caller| { + .func_wrap_async("", "nop", |caller, _: ()| { Box::new(async { drop(caller); }) }) .unwrap(); typed - .func_wrap2_async("", "nop-params-and-results", |_caller, x: i32, y: i64| { - Box::new(async move { - assert_eq!(x, 0); - assert_eq!(y, 0); - 0.0f32 - }) - }) + .func_wrap_async( + "", + "nop-params-and-results", + |_caller, (x, y): (i32, i64)| { + Box::new(async move { + assert_eq!(x, 0); + assert_eq!(y, 0); + 0.0f32 + }) + }, + ) .unwrap(); let instance = run_await(typed.instantiate_async(&mut *store, &module)).unwrap(); bench_instance(group, store, &instance, "async-typed", is_async); diff --git a/crates/wasmtime/src/runtime/component/linker.rs b/crates/wasmtime/src/runtime/component/linker.rs index 6abe76045346..b36785f353d9 100644 --- a/crates/wasmtime/src/runtime/component/linker.rs +++ b/crates/wasmtime/src/runtime/component/linker.rs @@ -649,9 +649,9 @@ impl LinkerInstance<'_, T> { ty: ResourceType, dtor: impl Fn(StoreContextMut<'_, T>, u32) -> Result<()> + Send + Sync + 'static, ) -> Result<()> { - let dtor = Arc::new(crate::func::HostFunc::wrap( + let dtor = Arc::new(crate::func::HostFunc::wrap_inner( &self.engine, - move |mut cx: crate::Caller<'_, T>, param: u32| dtor(cx.as_context_mut(), param), + move |mut cx: crate::Caller<'_, T>, (param,): (u32,)| dtor(cx.as_context_mut(), param), )); self.insert(name, Definition::Resource(ty, dtor))?; Ok(()) diff --git a/crates/wasmtime/src/runtime/func.rs b/crates/wasmtime/src/runtime/func.rs index 19e0b90b15b2..54a8975e86e2 100644 --- a/crates/wasmtime/src/runtime/func.rs +++ b/crates/wasmtime/src/runtime/func.rs @@ -361,38 +361,6 @@ macro_rules! for_each_function_signature { mod typed; pub use typed::*; -macro_rules! generate_wrap_async_func { - ($num:tt $($args:ident)*) => (paste::paste!{ - /// Same as [`Func::wrap`], except the closure asynchronously produces - /// its result. For more information see the [`Func`] documentation. - /// - /// # Panics - /// - /// This function will panic if called with a non-asynchronous store. - #[allow(non_snake_case)] - #[cfg(feature = "async")] - pub fn []( - store: impl AsContextMut, - func: impl for<'a> Fn(Caller<'a, T>, $($args),*) -> Box + Send + 'a> + Send + Sync + 'static, - ) -> Func - where - $($args: WasmTy,)* - R: WasmRet, - { - assert!(store.as_context().async_support(), concat!("cannot use `wrap", $num, "_async` without enabling async support on the config")); - Func::wrap(store, move |mut caller: Caller<'_, T>, $($args: $args),*| { - let async_cx = caller.store.as_context_mut().0.async_cx().expect("Attempt to start async function on dying fiber"); - let mut future = Pin::from(func(caller, $($args),*)); - - match unsafe { async_cx.block_on(future.as_mut()) } { - Ok(ret) => ret.into_fallible(), - Err(e) => R::fallible_from_error(e), - } - }) - } - }) -} - impl Func { /// Creates a new `Func` with the given arguments, typically to create a /// host-defined function to pass as an import to a module. @@ -860,7 +828,57 @@ impl Func { } } - for_each_function_signature!(generate_wrap_async_func); + fn wrap_inner(mut store: impl AsContextMut, func: F) -> Func + where + F: Fn(Caller<'_, T>, Params) -> Results + Send + Sync + 'static, + Params: WasmTyList, + Results: WasmRet, + { + let store = store.as_context_mut().0; + // part of this unsafety is about matching the `T` to a `Store`, + // which is done through the `AsContextMut` bound above. + unsafe { + let host = HostFunc::wrap_inner(store.engine(), func); + host.into_func(store) + } + } + + /// Same as [`Func::wrap`], except the closure asynchronously produces the + /// result and the arguments are passed within a tuple. For more information + /// see the [`Func`] documentation. + /// + /// # Panics + /// + /// This function will panic if called with a non-asynchronous store. + #[cfg(feature = "async")] + pub fn wrap_async(store: impl AsContextMut, func: F) -> Func + where + F: for<'a> Fn(Caller<'a, T>, P) -> Box + Send + 'a> + + Send + + Sync + + 'static, + P: WasmTyList, + R: WasmRet, + { + assert!( + store.as_context().async_support(), + concat!("cannot use `wrap_async` without enabling async support on the config") + ); + Func::wrap_inner(store, move |mut caller: Caller<'_, T>, args| { + let async_cx = caller + .store + .as_context_mut() + .0 + .async_cx() + .expect("Attempt to start async function on dying fiber"); + let mut future = Pin::from(func(caller, args)); + + match unsafe { async_cx.block_on(future.as_mut()) } { + Ok(ret) => ret.into_fallible(), + Err(e) => R::fallible_from_error(e), + } + }) + } /// Returns the underlying wasm type that this `Func` has. /// @@ -1832,6 +1850,122 @@ pub trait IntoFunc: Send + Sync + 'static { fn into_func(self, engine: &Engine) -> HostContext; } +macro_rules! impl_into_func { + ($num:tt $arg:ident) => { + // Implement for functions without a leading `&Caller` parameter, + // delegating to the implementation below which does have the leading + // `Caller` parameter. + #[allow(non_snake_case)] + impl IntoFunc for F + where + F: Fn($arg) -> R + Send + Sync + 'static, + $arg: WasmTy, + R: WasmRet, + { + fn into_func(self, engine: &Engine) -> HostContext { + let f = move |_: Caller<'_, T>, $arg: $arg| { + self($arg) + }; + + f.into_func(engine) + } + } + + #[allow(non_snake_case)] + impl IntoFunc, $arg), R> for F + where + F: Fn(Caller<'_, T>, $arg) -> R + Send + Sync + 'static, + $arg: WasmTy, + R: WasmRet, + { + fn into_func(self, engine: &Engine) -> HostContext { + HostContext::from_closure(engine, move |caller: Caller<'_, T>, ($arg,)| { + self(caller, $arg) + }) + } + } + }; + ($num:tt $($args:ident)*) => { + // Implement for functions without a leading `&Caller` parameter, + // delegating to the implementation below which does have the leading + // `Caller` parameter. + #[allow(non_snake_case)] + impl IntoFunc for F + where + F: Fn($($args),*) -> R + Send + Sync + 'static, + $($args: WasmTy,)* + R: WasmRet, + { + fn into_func(self, engine: &Engine) -> HostContext { + let f = move |_: Caller<'_, T>, $($args:$args),*| { + self($($args),*) + }; + + f.into_func(engine) + } + } + + #[allow(non_snake_case)] + impl IntoFunc, $($args,)*), R> for F + where + F: Fn(Caller<'_, T>, $($args),*) -> R + Send + Sync + 'static, + $($args: WasmTy,)* + R: WasmRet, + { + fn into_func(self, engine: &Engine) -> HostContext { + HostContext::from_closure(engine, move |caller: Caller<'_, T>, ( $( $args ),* )| { + self(caller, $( $args ),* ) + }) + } + } + } +} + +for_each_function_signature!(impl_into_func); + +/// Trait implemented for various tuples made up of types which implement +/// [`WasmTy`] that can be passed to [`Func::wrap_inner`] and +/// [`HostContext::from_closure`]. +pub unsafe trait WasmTyList { + /// Get the value type that each Type in the list represents. + fn valtypes() -> impl Iterator; + + // Load a version of `Self` from the `values` provided. + // + // # Safety + // + // This function is unsafe as it's up to the caller to ensure that `values` are + // valid for this given type. + #[doc(hidden)] + unsafe fn load(store: &mut AutoAssertNoGc<'_>, values: &mut [MaybeUninit]) -> Self; +} + +macro_rules! impl_wasm_ty_list { + ($num:tt $($args:ident)*) => (paste::paste!{ + #[allow(non_snake_case)] + unsafe impl<$($args),*> WasmTyList for ($($args,)*) + where + $($args: WasmTy,)* + { + fn valtypes() -> impl Iterator { + IntoIterator::into_iter([$($args::valtype(),)*]) + } + + unsafe fn load(_store: &mut AutoAssertNoGc<'_>, _values: &mut [MaybeUninit]) -> Self { + let mut _cur = 0; + ($({ + debug_assert!(_cur < _values.len()); + let ptr = _values.get_unchecked(_cur).assume_init_ref(); + _cur += 1; + $args::load(_store, ptr) + },)*) + } + } + }); +} + +for_each_function_signature!(impl_wasm_ty_list); + /// A structure representing the caller's context when creating a function /// via [`Func::wrap`]. /// @@ -2012,155 +2146,6 @@ struct HostFuncState { ty: RegisteredType, } -macro_rules! impl_into_func { - ($num:tt $($args:ident)*) => { - // Implement for functions without a leading `&Caller` parameter, - // delegating to the implementation below which does have the leading - // `Caller` parameter. - #[allow(non_snake_case)] - impl IntoFunc for F - where - F: Fn($($args),*) -> R + Send + Sync + 'static, - $($args: WasmTy,)* - R: WasmRet, - { - fn into_func(self, engine: &Engine) -> HostContext { - let f = move |_: Caller<'_, T>, $($args:$args),*| { - self($($args),*) - }; - - f.into_func(engine) - } - } - - #[allow(non_snake_case)] - impl IntoFunc, $($args,)*), R> for F - where - F: Fn(Caller<'_, T>, $($args),*) -> R + Send + Sync + 'static, - $($args: WasmTy,)* - R: WasmRet, - { - fn into_func(self, engine: &Engine) -> HostContext { - /// This shim is a regular, non-closure function we can stuff - /// inside `VMFuncRef::array_call`. - /// - /// It reads the actual callee closure out of - /// `VMArrayCallHostFuncContext::host_state`, forwards - /// arguments to that function, and finally forwards the - /// results back out to the caller. It also handles traps and - /// panics along the way. - unsafe extern "C" fn array_call_trampoline( - callee_vmctx: *mut VMOpaqueContext, - caller_vmctx: *mut VMOpaqueContext, - args: *mut ValRaw, - args_len: usize - ) - where - F: Fn(Caller<'_, T>, $( $args ),*) -> R + 'static, - $($args: WasmTy,)* - R: WasmRet, - { - // Note that this function is intentionally scoped into a - // separate closure. Handling traps and panics will involve - // longjmp-ing from this function which means we won't run - // destructors. As a result anything requiring a destructor - // should be part of this closure, and the long-jmp-ing - // happens after the closure in handling the result. - let run = move |mut caller: Caller<'_, T>| { - let args = core::slice::from_raw_parts_mut( - args.cast::>(), - args_len, - ); - let vmctx = VMArrayCallHostFuncContext::from_opaque(callee_vmctx); - let state = (*vmctx).host_state(); - - // Double-check ourselves in debug mode, but we control - // the `Any` here so an unsafe downcast should also - // work. - debug_assert!(state.is::>()); - let state = &*(state as *const _ as *const HostFuncState); - let func = &state.func; - - let ret = 'ret: { - if let Err(trap) = caller.store.0.call_hook(CallHook::CallingHost) { - break 'ret R::fallible_from_error(trap); - } - - let mut store = AutoAssertNoGc::new(caller.store.0); - let mut _cur = 0; - $(let $args = { - debug_assert!(_cur < args.len()); - let ptr = args.get_unchecked(_cur).assume_init_ref(); - _cur += 1; - $args::load(&mut store, ptr) - };)* - let _ = &mut store; - drop(store); - - let r = func( - caller.sub_caller(), - $( $args, )* - ); - if let Err(trap) = caller.store.0.call_hook(CallHook::ReturningFromHost) { - break 'ret R::fallible_from_error(trap); - } - r.into_fallible() - }; - - if !ret.compatible_with_store(caller.store.0) { - bail!("host function attempted to return cross-`Store` value to Wasm") - } else { - let mut store = AutoAssertNoGc::new(&mut **caller.store.0); - let ret = ret.store(&mut store, args)?; - Ok(ret) - } - }; - - // With nothing else on the stack move `run` into this - // closure and then run it as part of `Caller::with`. - let result = crate::runtime::vm::catch_unwind_and_longjmp(move || { - let caller_vmctx = VMContext::from_opaque(caller_vmctx); - Caller::with(caller_vmctx, run) - }); - - match result { - Ok(val) => val, - Err(err) => crate::trap::raise(err), - } - } - - let ty = R::func_type( - engine, - None::.into_iter() - $(.chain(Some($args::valtype())))* - ); - let type_index = ty.type_index(); - - let array_call = array_call_trampoline::; - - let ctx = unsafe { - VMArrayCallHostFuncContext::new( - VMFuncRef { - array_call, - wasm_call: None, - type_index, - vmctx: ptr::null_mut(), - }, - Box::new(HostFuncState { - func: self, - ty: ty.into_registered_type(), - }), - ) - }; - - ctx.into() - } - } - } -} - -for_each_function_signature!(impl_into_func); - #[doc(hidden)] pub enum HostContext { Array(StoreBox), @@ -2172,6 +2157,105 @@ impl From> for HostContext { } } +impl HostContext { + fn from_closure(engine: &Engine, func: F) -> Self + where + F: Fn(Caller<'_, T>, P) -> R + Send + Sync + 'static, + P: WasmTyList, + R: WasmRet, + { + let ty = R::func_type(engine, None::.into_iter().chain(P::valtypes())); + let type_index = ty.type_index(); + + let array_call = Self::array_call_trampoline::; + + let ctx = unsafe { + VMArrayCallHostFuncContext::new( + VMFuncRef { + array_call, + wasm_call: None, + type_index, + vmctx: ptr::null_mut(), + }, + Box::new(HostFuncState { + func, + ty: ty.into_registered_type(), + }), + ) + }; + + ctx.into() + } + + unsafe extern "C" fn array_call_trampoline( + callee_vmctx: *mut VMOpaqueContext, + caller_vmctx: *mut VMOpaqueContext, + args: *mut ValRaw, + args_len: usize, + ) where + F: Fn(Caller<'_, T>, P) -> R + 'static, + P: WasmTyList, + R: WasmRet, + { + // Note that this function is intentionally scoped into a + // separate closure. Handling traps and panics will involve + // longjmp-ing from this function which means we won't run + // destructors. As a result anything requiring a destructor + // should be part of this closure, and the long-jmp-ing + // happens after the closure in handling the result. + let run = move |mut caller: Caller<'_, T>| { + let args = + core::slice::from_raw_parts_mut(args.cast::>(), args_len); + let vmctx = VMArrayCallHostFuncContext::from_opaque(callee_vmctx); + let state = (*vmctx).host_state(); + + // Double-check ourselves in debug mode, but we control + // the `Any` here so an unsafe downcast should also + // work. + debug_assert!(state.is::>()); + let state = &*(state as *const _ as *const HostFuncState); + let func = &state.func; + + let ret = 'ret: { + if let Err(trap) = caller.store.0.call_hook(CallHook::CallingHost) { + break 'ret R::fallible_from_error(trap); + } + + let mut store = AutoAssertNoGc::new(caller.store.0); + let params = P::load(&mut store, args); + let _ = &mut store; + drop(store); + + let r = func(caller.sub_caller(), params); + if let Err(trap) = caller.store.0.call_hook(CallHook::ReturningFromHost) { + break 'ret R::fallible_from_error(trap); + } + r.into_fallible() + }; + + if !ret.compatible_with_store(caller.store.0) { + bail!("host function attempted to return cross-`Store` value to Wasm") + } else { + let mut store = AutoAssertNoGc::new(&mut **caller.store.0); + let ret = ret.store(&mut store, args)?; + Ok(ret) + } + }; + + // With nothing else on the stack move `run` into this + // closure and then run it as part of `Caller::with`. + let result = crate::runtime::vm::catch_unwind_and_longjmp(move || { + let caller_vmctx = VMContext::from_opaque(caller_vmctx); + Caller::with(caller_vmctx, run) + }); + + match result { + Ok(val) => val, + Err(err) => crate::trap::raise(err), + } + } +} + /// Representation of a host-defined function. /// /// This is used for `Func::new` but also for `Linker`-defined functions. For @@ -2236,6 +2320,17 @@ impl HostFunc { HostFunc::_new(engine, ctx.into()) } + /// Analog of [`Func::wrap_inner`] + pub fn wrap_inner(engine: &Engine, func: F) -> Self + where + F: Fn(Caller<'_, T>, Params) -> Results + Send + Sync + 'static, + Params: WasmTyList, + Results: WasmRet, + { + let ctx = HostContext::from_closure(engine, func); + HostFunc::_new(engine, ctx) + } + /// Analog of [`Func::wrap`] pub fn wrap( engine: &Engine, diff --git a/crates/wasmtime/src/runtime/linker.rs b/crates/wasmtime/src/runtime/linker.rs index f02c969b8bb1..ed9001d12cef 100644 --- a/crates/wasmtime/src/runtime/linker.rs +++ b/crates/wasmtime/src/runtime/linker.rs @@ -1,10 +1,10 @@ use crate::func::HostFunc; use crate::instance::InstancePre; -use crate::prelude::*; use crate::store::StoreOpaque; +use crate::{prelude::*, IntoFunc}; use crate::{ AsContext, AsContextMut, Caller, Engine, Extern, ExternType, Func, FuncType, ImportType, - Instance, IntoFunc, Module, StoreContextMut, Val, ValRaw, ValType, + Instance, Module, StoreContextMut, Val, ValRaw, ValType, WasmTyList, }; use alloc::sync::Arc; use anyhow::{bail, Context, Result}; @@ -134,44 +134,6 @@ pub(crate) enum DefinitionType { Memory(wasmtime_environ::Memory, u64), } -macro_rules! generate_wrap_async_func { - ($num:tt $($args:ident)*) => (paste::paste!{ - /// Asynchronous analog of [`Linker::func_wrap`]. - /// - /// For more information also see - /// [`Func::wrapN_async`](crate::Func::wrap1_async). - #[allow(non_snake_case)] - #[cfg(feature = "async")] - pub fn []<$($args,)* R>( - &mut self, - module: &str, - name: &str, - func: impl for<'a> Fn(Caller<'a, T>, $($args),*) -> Box + Send + 'a> + Send + Sync + 'static, - ) -> Result<&mut Self> - where - $($args: crate::WasmTy,)* - R: crate::WasmRet, - { - assert!( - self.engine.config().async_support, - concat!( - "cannot use `func_wrap", - $num, - "_async` without enabling async support on the config", - ), - ); - self.func_wrap(module, name, move |mut caller: Caller<'_, T>, $($args: $args),*| { - let async_cx = caller.store.as_context_mut().0.async_cx().expect("Attempt to start async function on dying fiber"); - let mut future = Pin::from(func(caller, $($args),*)); - match unsafe { async_cx.block_on(future.as_mut()) } { - Ok(ret) => ret.into_fallible(), - Err(e) => R::fallible_from_error(e), - } - }) - } - }) -} - impl Linker { /// Creates a new [`Linker`]. /// @@ -580,7 +542,44 @@ impl Linker { Ok(self) } - for_each_function_signature!(generate_wrap_async_func); + /// Asynchronous analog of [`Linker::func_wrap`]. + #[cfg(feature = "async")] + pub fn func_wrap_async( + &mut self, + module: &str, + name: &str, + func: F, + ) -> Result<&mut Self> + where + F: for<'a> Fn(Caller<'a, T>, Params) -> Box + Send + 'a> + + Send + + Sync + + 'static, + { + assert!( + self.engine.config().async_support, + "cannot use `func_wrap_async` without enabling async support on the config", + ); + let func = HostFunc::wrap_inner( + &self.engine, + move |mut caller: Caller<'_, T>, args: Params| { + let async_cx = caller + .store + .as_context_mut() + .0 + .async_cx() + .expect("Attempt to start async function on dying fiber"); + let mut future = Pin::from(func(caller, args)); + match unsafe { async_cx.block_on(future.as_mut()) } { + Ok(ret) => ret.into_fallible(), + Err(e) => Args::fallible_from_error(e), + } + }, + ); + let key = self.import_key(module, Some(name)); + self.insert(key, Definition::HostFunc(Arc::new(func)))?; + Ok(self) + } /// Convenience wrapper to define an entire [`Instance`] in this linker. /// diff --git a/crates/wiggle/generate/src/wasmtime.rs b/crates/wiggle/generate/src/wasmtime.rs index 46158a224647..e3a8ca7294f0 100644 --- a/crates/wiggle/generate/src/wasmtime.rs +++ b/crates/wiggle/generate/src/wasmtime.rs @@ -83,13 +83,15 @@ fn generate_func( let arg_names = (0..params.len()) .map(|i| Ident::new(&format!("arg{}", i), Span::call_site())) .collect::>(); - let arg_decls = params + let arg_tys = params .iter() - .enumerate() - .map(|(i, ty)| { - let name = &arg_names[i]; - let wasm = names::wasm_type(*ty); - quote! { #name: #wasm } + .map(|ty| names::wasm_type(*ty)) + .collect::>(); + let arg_decls = arg_names + .iter() + .zip(arg_tys.iter()) + .map(|(name, ty)| { + quote! { #name: #ty } }) .collect::>(); @@ -130,12 +132,12 @@ fn generate_func( match asyncness { Asyncness::Async => { - let wrapper = format_ident!("func_wrap{}_async", params.len()); + let arg_decls = quote! { ( #(#arg_names,)* ) : ( #(#arg_tys,)* ) }; quote! { - linker.#wrapper( + linker.func_wrap_async( #module_str, #field_str, - move |mut caller: wiggle::wasmtime_crate::Caller<'_, T> #(, #arg_decls)*| { + move |mut caller: wiggle::wasmtime_crate::Caller<'_, T>, #arg_decls| { Box::new(async move { #body }) }, )?; diff --git a/tests/all/async_functions.rs b/tests/all/async_functions.rs index 7579085ea002..c94dc4e3b650 100644 --- a/tests/all/async_functions.rs +++ b/tests/all/async_functions.rs @@ -32,7 +32,7 @@ async fn smoke() { run_smoke_test(&mut store, func).await; run_smoke_typed_test(&mut store, func).await; - let func = Func::wrap0_async(&mut store, move |_caller| Box::new(async { Ok(()) })); + let func = Func::wrap_async(&mut store, move |_caller, _: ()| Box::new(async { Ok(()) })); run_smoke_test(&mut store, func).await; run_smoke_typed_test(&mut store, func).await; } @@ -49,7 +49,9 @@ async fn smoke_host_func() -> Result<()> { move |_caller, _params, _results| Box::new(async { Ok(()) }), )?; - linker.func_wrap0_async("", "second", move |_caller| Box::new(async { Ok(()) }))?; + linker.func_wrap_async("", "second", move |_caller, _: ()| { + Box::new(async { Ok(()) }) + })?; let func = linker .get(&mut store, "", "first") @@ -83,7 +85,7 @@ async fn smoke_with_suspension() { run_smoke_test(&mut store, func).await; run_smoke_typed_test(&mut store, func).await; - let func = Func::wrap0_async(&mut store, move |_caller| { + let func = Func::wrap_async(&mut store, move |_caller, _: ()| { Box::new(async { tokio::task::yield_now().await; Ok(()) @@ -110,7 +112,7 @@ async fn smoke_host_func_with_suspension() -> Result<()> { }, )?; - linker.func_wrap0_async("", "second", move |_caller| { + linker.func_wrap_async("", "second", move |_caller, _: ()| { Box::new(async { tokio::task::yield_now().await; Ok(()) @@ -509,7 +511,7 @@ async fn resume_separate_thread() { ", ) .unwrap(); - let func = Func::wrap0_async(&mut store, |_| { + let func = Func::wrap_async(&mut store, |_, _: ()| { Box::new(async { tokio::task::yield_now().await; Err::<(), _>(anyhow!("test")) @@ -541,7 +543,7 @@ async fn resume_separate_thread2() { ", ) .unwrap(); - let func = Func::wrap0_async(&mut store, |_| { + let func = Func::wrap_async(&mut store, |_, _: ()| { Box::new(async { tokio::task::yield_now().await; }) @@ -582,7 +584,7 @@ async fn resume_separate_thread3() { ", ) .unwrap(); - let func = Func::wrap0_async(&mut store, |_| { + let func = Func::wrap_async(&mut store, |_, _: ()| { Box::new(async { tokio::task::yield_now().await; }) @@ -627,7 +629,7 @@ async fn recursive_async() -> Result<()> { let i = Instance::new_async(&mut store, &m, &[]).await?; let overflow = i.get_typed_func::<(), ()>(&mut store, "overflow")?; let normal = i.get_typed_func::<(), ()>(&mut store, "normal")?; - let f2 = Func::wrap0_async(&mut store, move |mut caller| { + let f2 = Func::wrap_async(&mut store, move |mut caller, _: ()| { let normal = normal.clone(); let overflow = overflow.clone(); Box::new(async move { @@ -831,17 +833,17 @@ async fn non_stacky_async_activations() -> Result<()> { stacks.push(wasmtime::WasmBacktrace::force_capture(store)); } - linker1.func_wrap0_async("", "host_capture_stack", { + linker1.func_wrap_async("", "host_capture_stack", { let stacks = stacks.clone(); - move |caller| { + move |caller, _: ()| { capture_stack(&stacks, &caller); Box::new(async { Ok(()) }) } })?; - linker1.func_wrap0_async("", "start_async_instance", { + linker1.func_wrap_async("", "start_async_instance", { let stacks = stacks.clone(); - move |mut caller| { + move |mut caller, _: ()| { let stacks = stacks.clone(); capture_stack(&stacks, &caller); @@ -849,9 +851,9 @@ async fn non_stacky_async_activations() -> Result<()> { let mut store2 = Store::new(caller.engine(), ()); let mut linker2 = Linker::new(caller.engine()); linker2 - .func_wrap0_async("", "yield", { + .func_wrap_async("", "yield", { let stacks = stacks.clone(); - move |caller| { + move |caller, _: ()| { let stacks = stacks.clone(); Box::new(async move { capture_stack(&stacks, &caller); @@ -972,13 +974,17 @@ async fn gc_preserves_externref_on_historical_async_stacks() -> Result<()> { Ok(()) }, )?; - linker.func_wrap1_async("", "recurse", |mut cx: Caller<'_, Option>, val: i32| { - let func = cx.data().clone().unwrap(); - Box::new(async move { - let r = Some(ExternRef::new(&mut cx, val)?); - Ok(func.call_async(&mut cx, (val, r)).await) - }) - })?; + linker.func_wrap_async( + "", + "recurse", + |mut cx: Caller<'_, Option>, (val,): (i32,)| { + let func = cx.data().clone().unwrap(); + Box::new(async move { + let r = Some(ExternRef::new(&mut cx, val)?); + Ok(func.call_async(&mut cx, (val, r)).await) + }) + }, + )?; let instance = linker.instantiate_async(&mut store, &module).await?; let func: F = instance.get_typed_func(&mut store, "run")?; *store.data_mut() = Some(func.clone()); diff --git a/tests/all/call_hook.rs b/tests/all/call_hook.rs index fad0bfb8d0c0..5b7bc60da709 100644 --- a/tests/all/call_hook.rs +++ b/tests/all/call_hook.rs @@ -121,9 +121,9 @@ async fn call_wrapped_async_func() -> Result<(), Error> { let engine = Engine::new(&config)?; let mut store = Store::new(&engine, State::default()); store.call_hook(State::call_hook); - let f = Func::wrap4_async( + let f = Func::wrap_async( &mut store, - |caller: Caller, a: i32, b: i64, c: f32, d: f64| { + |caller: Caller, (a, b, c, d): (i32, i64, f32, f64)| { Box::new(async move { // Calling this func will switch context into wasm, then back to host: assert_eq!(caller.data().context, vec![Context::Wasm, Context::Host]); @@ -245,9 +245,9 @@ async fn call_linked_func_async() -> Result<(), Error> { let mut store = Store::new(&engine, State::default()); store.call_hook(State::call_hook); - let f = Func::wrap4_async( + let f = Func::wrap_async( &mut store, - |caller: Caller, a: i32, b: i64, c: f32, d: f64| { + |caller: Caller, (a, b, c, d): (i32, i64, f32, f64)| { Box::new(async move { // Calling this func will switch context into wasm, then back to host: assert_eq!(caller.data().context, vec![Context::Wasm, Context::Host]); @@ -728,7 +728,7 @@ async fn drop_suspended_async_hook() -> Result<(), Error> { let mut linker = Linker::new(&engine); // Simulate a host function that has lots of yields with an infinite loop. - linker.func_wrap0_async("host", "f", |mut cx| { + linker.func_wrap_async("host", "f", |mut cx, _: ()| { Box::new(async move { let state = cx.data_mut(); assert_eq!(*state, 0); diff --git a/tests/all/component_model/async.rs b/tests/all/component_model/async.rs index cbb398fdd3f8..6b995657c1f3 100644 --- a/tests/all/component_model/async.rs +++ b/tests/all/component_model/async.rs @@ -219,7 +219,7 @@ async fn poll_through_wasm_activation() -> Result<()> { execute_across_threads(async move { let mut store = Store::new(&engine, Some(Box::pin(invoke_component))); - let poll_once = wasmtime::Func::wrap0_async(&mut store, |mut cx| { + let poll_once = wasmtime::Func::wrap_async(&mut store, |mut cx, _: ()| { let invoke_component = cx.data_mut().take().unwrap(); Box::new(async move { match PollOnce::new(invoke_component).await { diff --git a/tests/host_segfault.rs b/tests/host_segfault.rs index 77e4eb08e87a..955c90cf3105 100644 --- a/tests/host_segfault.rs +++ b/tests/host_segfault.rs @@ -138,7 +138,7 @@ fn main() { config.async_support(true); let engine = Engine::new(&config).unwrap(); let mut store = Store::new(&engine, ()); - let f = Func::wrap0_async(&mut store, |_| { + let f = Func::wrap_async(&mut store, |_, _: ()| { Box::new(async { overrun_the_stack(); }) @@ -170,7 +170,7 @@ fn main() { config.allocation_strategy(InstanceAllocationStrategy::pooling()); let engine = Engine::new(&config).unwrap(); let mut store = Store::new(&engine, ()); - let f = Func::wrap0_async(&mut store, |_| { + let f = Func::wrap_async(&mut store, |_, _: ()| { Box::new(async { overrun_the_stack(); })