From f9e8c8ee03a6ab8fa5ebbaa0a66c3d0b7a9e61d9 Mon Sep 17 00:00:00 2001 From: Pat Hickey <pat@moreproductive.org> Date: Fri, 28 May 2021 16:41:57 -0700 Subject: [PATCH] add hooks for entering and exiting native code to Store --- crates/wasmtime/src/func.rs | 15 ++++++++++--- crates/wasmtime/src/store.rs | 43 +++++++++++++++++++++++++++++++++++- 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/crates/wasmtime/src/func.rs b/crates/wasmtime/src/func.rs index 8e6cafac959b..aec521d7267e 100644 --- a/crates/wasmtime/src/func.rs +++ b/crates/wasmtime/src/func.rs @@ -843,6 +843,7 @@ impl Func { values_vec: *mut u128, func: &dyn Fn(Caller<'_, T>, &[Val], &mut [Val]) -> Result<(), Trap>, ) -> Result<(), Trap> { + caller.store.0.entering_native_hook()?; // We have a dynamic guarantee that `values_vec` has the right // number of arguments and the right types of arguments. As a result // we should be able to safely run through them all and read them. @@ -883,6 +884,7 @@ impl Func { } } + caller.store.0.exiting_native_hook()?; Ok(()) } @@ -1173,7 +1175,7 @@ pub unsafe trait WasmRet { // explicitly, used when wrapping async functions which always bottom-out // in a function that returns a trap because futures can be cancelled. #[doc(hidden)] - type Fallible: WasmRet; + type Fallible: WasmRet<Abi = Self::Abi, Retptr = Self::Retptr>; #[doc(hidden)] fn into_fallible(self) -> Self::Fallible; #[doc(hidden)] @@ -1689,12 +1691,19 @@ macro_rules! impl_into_func { let ret = { panic::catch_unwind(AssertUnwindSafe(|| { + if let Err(trap) = caller.store.0.entering_native_hook() { + return R::fallible_from_trap(trap); + } let mut _store = caller.sub_caller().store.opaque(); $(let $args = $args::from_abi($args, &mut _store);)* - func( + let r = func( caller.sub_caller(), $( $args, )* - ) + ); + if let Err(trap) = caller.store.0.exiting_native_hook() { + return R::fallible_from_trap(trap); + } + r.into_fallible() })) }; diff --git a/crates/wasmtime/src/store.rs b/crates/wasmtime/src/store.rs index 5520d463c713..367aba0d19e8 100644 --- a/crates/wasmtime/src/store.rs +++ b/crates/wasmtime/src/store.rs @@ -104,6 +104,8 @@ pub struct StoreInner<T> { _marker: marker::PhantomPinned, inner: StoreInnermost, limiter: Option<Box<dyn FnMut(&mut T) -> &mut (dyn crate::ResourceLimiter) + Send + Sync>>, + entering_native_hook: Option<Box<dyn FnMut(&mut T) -> Result<(), crate::Trap> + Send + Sync>>, + exiting_native_hook: Option<Box<dyn FnMut(&mut T) -> Result<(), crate::Trap> + Send + Sync>>, // for comments about `ManuallyDrop`, see `Store::into_data` data: ManuallyDrop<T>, } @@ -239,7 +241,8 @@ impl<T> Store<T> { default_callee, }, limiter: None, - default_callee, + entering_native_hook: None, + exiting_native_hook: None, data: ManuallyDrop::new(data), }); @@ -322,6 +325,28 @@ impl<T> Store<T> { inner.limiter = Some(Box::new(limiter)); } + /// Configure a function that runs each time WebAssembly code running on this [`Store`] calls + /// into native code. + /// + /// This function may return a [`Trap`], which terminates execution. + pub fn entering_native_code_hook( + &mut self, + hook: impl FnMut(&mut T) -> Result<(), Trap> + Send + Sync + 'static, + ) { + self.inner.entering_native_hook = Some(Box::new(hook)); + } + + /// Configure a function that runs before native code running on this [`Store`] returns to + /// WebAssembly code. + /// + /// This function may return a [`Trap`], which terminates execution. + pub fn exiting_native_code_hook( + &mut self, + hook: impl FnMut(&mut T) -> Result<(), Trap> + Send + Sync + 'static, + ) { + self.inner.exiting_native_hook = Some(Box::new(hook)); + } + /// Returns the [`Engine`] that this store is associated with. pub fn engine(&self) -> &Engine { self.inner.engine() @@ -621,6 +646,22 @@ impl<T> StoreInner<T> { let accessor = self.limiter.as_mut()?; Some(accessor(&mut self.data)) } + + pub fn entering_native_hook(&mut self) -> Result<(), Trap> { + if let Some(hook) = &mut self.entering_native_hook { + hook(&mut self.data) + } else { + Ok(()) + } + } + + pub fn exiting_native_hook(&mut self) -> Result<(), Trap> { + if let Some(hook) = &mut self.exiting_native_hook { + hook(&mut self.data) + } else { + Ok(()) + } + } } impl StoreInnermost {