use crate::{Engine, FuncType, ValRaw};
use anyhow::Result;
use std::panic::{self, AssertUnwindSafe};
use std::ptr::NonNull;
use wasmtime_jit::CodeMemory;
use wasmtime_runtime::{
StoreBox, VMArrayCallHostFuncContext, VMContext, VMFuncRef, VMOpaqueContext,
};
struct TrampolineState<F> {
func: F,
#[allow(dead_code)]
code_memory: CodeMemory,
}
unsafe extern "C" fn array_call_shim<F>(
vmctx: *mut VMOpaqueContext,
caller_vmctx: *mut VMOpaqueContext,
values_vec: *mut ValRaw,
values_vec_len: usize,
) where
F: Fn(*mut VMContext, &mut [ValRaw]) -> Result<()> + 'static,
{
let result = panic::catch_unwind(AssertUnwindSafe(|| {
let vmctx = VMArrayCallHostFuncContext::from_opaque(vmctx);
let state = (*vmctx).host_state();
debug_assert!(state.is::<TrampolineState<F>>());
let state = &*(state as *const _ as *const TrampolineState<F>);
let values_vec = std::slice::from_raw_parts_mut(values_vec, values_vec_len);
(state.func)(VMContext::from_opaque(caller_vmctx), values_vec)
}));
match result {
Ok(Ok(())) => {}
Ok(Err(trap)) => crate::trap::raise(trap.into()),
Err(panic) => wasmtime_runtime::resume_panic(panic),
}
}
#[cfg(any(feature = "cranelift", feature = "winch"))]
pub fn create_array_call_function<F>(
ft: &FuncType,
func: F,
engine: &Engine,
) -> Result<StoreBox<VMArrayCallHostFuncContext>>
where
F: Fn(*mut VMContext, &mut [ValRaw]) -> Result<()> + Send + Sync + 'static,
{
use std::ptr;
let mut obj = engine
.compiler()
.object(wasmtime_environ::ObjectKind::Module)?;
let (wasm_call_range, native_call_range) = engine
.compiler()
.emit_trampolines_for_array_call_host_func(
ft.as_wasm_func_type(),
array_call_shim::<F> as usize,
&mut obj,
)?;
engine.append_bti(&mut obj);
let obj = wasmtime_jit::ObjectBuilder::new(obj, &engine.config().tunables).finish()?;
let mut code_memory = CodeMemory::new(obj)?;
code_memory.publish()?;
engine.profiler().register_module(&code_memory, &|_| None);
let text = code_memory.text();
let array_call = array_call_shim::<F>;
let wasm_call = text[wasm_call_range.start as usize..].as_ptr() as *mut _;
let wasm_call = Some(NonNull::new(wasm_call).unwrap());
let native_call = text[native_call_range.start as usize..].as_ptr() as *mut _;
let native_call = NonNull::new(native_call).unwrap();
let sig = engine.signatures().register(ft.as_wasm_func_type());
unsafe {
Ok(VMArrayCallHostFuncContext::new(
VMFuncRef {
array_call,
wasm_call,
native_call,
type_index: sig,
vmctx: ptr::null_mut(),
},
Box::new(TrampolineState { func, code_memory }),
))
}
}