wasmtime/runtime/trampoline/
func.rs

1//! Support for a calling of an imported function.
2
3use crate::prelude::*;
4use crate::runtime::vm::{StoreBox, VMArrayCallHostFuncContext, VMContext, VMOpaqueContext};
5use crate::type_registry::RegisteredType;
6use crate::{FuncType, ValRaw};
7use core::ptr::NonNull;
8
9struct TrampolineState<F> {
10    func: F,
11
12    // Need to keep our `VMSharedTypeIndex` registered in the engine.
13    #[allow(dead_code)]
14    sig: RegisteredType,
15}
16
17/// Shim to call a host-defined function that uses the array calling convention.
18///
19/// Together with `VMArrayCallHostFuncContext`, this implements the transition
20/// from a raw, non-closure function pointer to a Rust closure that associates
21/// data and function together.
22///
23/// Also shepherds panics and traps across Wasm.
24unsafe extern "C" fn array_call_shim<F>(
25    vmctx: NonNull<VMOpaqueContext>,
26    caller_vmctx: NonNull<VMOpaqueContext>,
27    values_vec: NonNull<ValRaw>,
28    values_vec_len: usize,
29) -> bool
30where
31    F: Fn(NonNull<VMContext>, &mut [ValRaw]) -> Result<()> + 'static,
32{
33    // Be sure to catch Rust panics to manually shepherd them across the wasm
34    // boundary, and then otherwise delegate as normal.
35    crate::runtime::vm::catch_unwind_and_record_trap(|| {
36        let vmctx = VMArrayCallHostFuncContext::from_opaque(vmctx);
37        // Double-check ourselves in debug mode, but we control
38        // the `Any` here so an unsafe downcast should also
39        // work.
40        let state = vmctx.as_ref().host_state();
41        debug_assert!(state.is::<TrampolineState<F>>());
42        let state = &*(state as *const _ as *const TrampolineState<F>);
43        let mut values_vec = NonNull::slice_from_raw_parts(values_vec, values_vec_len);
44        (state.func)(VMContext::from_opaque(caller_vmctx), values_vec.as_mut())
45    })
46}
47
48pub fn create_array_call_function<F>(
49    ft: &FuncType,
50    func: F,
51) -> Result<StoreBox<VMArrayCallHostFuncContext>>
52where
53    F: Fn(NonNull<VMContext>, &mut [ValRaw]) -> Result<()> + Send + Sync + 'static,
54{
55    let array_call = array_call_shim::<F>;
56
57    let sig = ft.clone().into_registered_type();
58
59    unsafe {
60        Ok(VMArrayCallHostFuncContext::new(
61            array_call,
62            sig.index(),
63            Box::new(TrampolineState { func, sig }),
64        ))
65    }
66}