use std::mem::transmute;
use crate::errors::SerializationError;
use anyhow::anyhow;
pub use wasmtime::Caller;
pub(crate) use wasmtime::{
AsContext, AsContextMut, Config, Engine, Extern, FuncType, Global,
GlobalType, Instance, Memory, MemoryType, Mutability, OptLevel, Store,
TypedFunc, Val, ValRaw, ValType,
};
#[derive(Clone)]
pub(crate) struct Module(wasmtime::Module);
impl Module {
pub fn from_binary(
engine: &Engine,
binary: &[u8],
) -> wasmtime::Result<Self> {
if cfg!(target_env = "musl") {
std::thread::scope(|s| {
std::thread::Builder::new()
.name("yara-x-wasm-compiler".to_string())
.stack_size(8 * 1024 * 1024) .spawn_scoped(s, || {
wasmtime::Module::from_binary(engine, binary)
.map(Module)
})
.unwrap()
.join()
.unwrap()
})
} else {
wasmtime::Module::from_binary(engine, binary).map(Module)
}
}
pub fn deserialize(
engine: &Engine,
bytes: impl AsRef<[u8]>,
) -> wasmtime::Result<Self> {
unsafe { wasmtime::Module::deserialize(engine, bytes).map(Module) }
}
#[allow(dead_code)]
pub fn serialize(&self) -> wasmtime::Result<Vec<u8>> {
self.0.serialize()
}
}
pub(crate) struct Linker<T>(wasmtime::Linker<T>);
pub(crate) type Trampoline<T> = Box<
dyn Fn(Caller<'_, T>, &mut [ValRaw]) -> TrampolineResult
+ Send
+ Sync
+ 'static,
>;
pub(crate) type TrampolineResult = wasmtime::Result<()>;
impl<T: 'static> Linker<T> {
pub fn new(engine: &wasmtime::Engine) -> Self {
Self(wasmtime::Linker::new(engine))
}
pub unsafe fn func_new_unchecked(
&mut self,
module: &str,
name: &str,
ty: FuncType,
sync_flags: u32,
trampoline: Trampoline<T>,
) -> TrampolineResult {
let _ = sync_flags;
unsafe {
self.0
.func_new_unchecked(module, name, ty, move |caller, args| {
trampoline(
caller,
transmute::<
&mut [std::mem::MaybeUninit<ValRaw>],
&mut [ValRaw],
>(args),
)
})
.map(|_| ())
}
}
pub fn define(
&mut self,
store: impl AsContext<Data = T>,
module: &str,
name: &str,
item: impl Into<Extern>,
) -> wasmtime::Result<&mut Self> {
self.0.define(store, module, name, item)?;
Ok(self)
}
pub fn instantiate(
&self,
store: impl AsContextMut<Data = T>,
module: &Module,
) -> Result<Instance, SerializationError> {
self.0
.instantiate(store, &module.0)
.map_err(|e| SerializationError::InvalidWASM(anyhow!(e)))
}
}