Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions crates/wasmtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ default = [
'component-model',
'threads',
'std',
'call-hook',
]

# An on-by-default feature enabling runtime compilation of WebAssembly modules
Expand Down Expand Up @@ -261,3 +262,9 @@ std = [
'object/std',
'once_cell/std',
]

# Enables support for the `Store::call_hook` API which enables injecting custom
# logic around all entries/exits from WebAssembly. This has a slight performance
# cost for all host functions so is provided as a compile-time feature if
# embedders would like to disable it.
call-hook = []
5 changes: 5 additions & 0 deletions crates/wasmtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,11 @@
//! * `threads` - Enabled by default, this enables compile-time support for the
//! WebAssembly `threads` proposal, notably shared memories.
//!
//! * `call-hook` - Enabled by default, this enables support for the
//! [`Store::call_hook`] API. This incurs a small overhead on all
//! entries/exits from WebAssembly and may want to be disabled by some
//! embedders.
//!
//! More crate features can be found in the [manifest] of Wasmtime itself for
//! seeing what can be enabled and disabled.
//!
Expand Down
2 changes: 1 addition & 1 deletion crates/wasmtime/src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ pub use linker::*;
pub use memory::*;
pub use module::{Module, ModuleExport};
pub use resources::*;
#[cfg(feature = "async")]
#[cfg(all(feature = "async", feature = "call-hook"))]
pub use store::CallHookHandler;
pub use store::{
AsContext, AsContextMut, CallHook, Store, StoreContext, StoreContextMut, UpdateDeadline,
Expand Down
23 changes: 18 additions & 5 deletions crates/wasmtime/src/runtime/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ use crate::runtime::vm::{
use crate::trampoline::VMHostGlobalContext;
use crate::RootSet;
use crate::{module::ModuleRegistry, Engine, Module, Trap, Val, ValRaw};
use crate::{Global, Instance, Memory, RootScope, Table};
use crate::{Global, Instance, Memory, RootScope, Table, Uninhabited};
use alloc::sync::Arc;
use anyhow::{anyhow, bail, Result};
use core::cell::UnsafeCell;
Expand Down Expand Up @@ -234,7 +234,7 @@ enum ResourceLimiterInner<T> {
}

/// An object that can take callbacks when the runtime enters or exits hostcalls.
#[cfg(feature = "async")]
#[cfg(all(feature = "async", feature = "call-hook"))]
#[async_trait::async_trait]
pub trait CallHookHandler<T>: Send {
/// A callback to run when wasmtime is about to enter a host call, or when about to
Expand All @@ -243,9 +243,15 @@ pub trait CallHookHandler<T>: Send {
}

enum CallHookInner<T> {
#[cfg(feature = "call-hook")]
Sync(Box<dyn FnMut(StoreContextMut<'_, T>, CallHook) -> Result<()> + Send + Sync>),
#[cfg(feature = "async")]
#[cfg(all(feature = "async", feature = "call-hook"))]
Async(Box<dyn CallHookHandler<T> + Send + Sync>),
#[allow(dead_code)]
ForceTypeParameterToBeUsed {
uninhabited: Uninhabited,
_marker: marker::PhantomData<T>,
},
}

/// What to do after returning from a callback when the engine epoch reaches
Expand Down Expand Up @@ -751,7 +757,7 @@ impl<T> Store<T> {
///
/// After this function returns a trap, it may be called for subsequent
/// returns to host or wasm code as the trap propagates to the root call.
#[cfg(feature = "async")]
#[cfg(all(feature = "async", feature = "call-hook"))]
pub fn call_hook_async(&mut self, hook: impl CallHookHandler<T> + Send + Sync + 'static) {
self.inner.call_hook = Some(CallHookInner::Async(Box::new(hook)));
}
Expand All @@ -770,6 +776,7 @@ impl<T> Store<T> {
///
/// After this function returns a trap, it may be called for subsequent returns
/// to host or wasm code as the trap propagates to the root call.
#[cfg(feature = "call-hook")]
pub fn call_hook(
&mut self,
hook: impl FnMut(StoreContextMut<'_, T>, CallHook) -> Result<()> + Send + Sync + 'static,
Expand Down Expand Up @@ -1156,9 +1163,10 @@ impl<T> StoreInner<T> {

fn invoke_call_hook(&mut self, call_hook: &mut CallHookInner<T>, s: CallHook) -> Result<()> {
match call_hook {
#[cfg(feature = "call-hook")]
CallHookInner::Sync(hook) => hook((&mut *self).as_context_mut(), s),

#[cfg(feature = "async")]
#[cfg(all(feature = "async", feature = "call-hook"))]
CallHookInner::Async(handler) => unsafe {
self.inner
.async_cx()
Expand All @@ -1169,6 +1177,11 @@ impl<T> StoreInner<T> {
.as_mut(),
)?
},

CallHookInner::ForceTypeParameterToBeUsed { uninhabited, .. } => {
let _ = s;
match *uninhabited {}
}
}
}
}
Expand Down