use anyhow::Result;
use anyhow::bail;
use wasmtime::Config;
use wasmtime::Engine;
use wasmtime::Func;
use wasmtime::Memory;
use wasmtime::Module;
use super::PluginSchemaVersion;
use super::instance::Linker;
use super::instance::Store;
use super::instance::WasmHostState;
use super::instance::get_current_plugin_schema_version;
pub struct WasmInstance {
inner: wasmtime::Instance,
_engine: wasmtime::Engine,
version: PluginSchemaVersion,
}
impl WasmInstance {
pub fn version(&self) -> PluginSchemaVersion {
self.version
}
pub fn set_token(&self, store: &mut Store, token: std::sync::Arc<dyn dprint_core::plugins::CancellationToken>) {
store.data_mut().set_token(token);
}
pub fn get_memory(&self, store: &mut Store, name: &str) -> Option<Memory> {
self.inner.get_memory(store, name)
}
pub fn get_function(&self, store: &mut Store, name: &str) -> Option<Func> {
self.inner.get_func(store, name)
}
}
pub fn load_instance(store: &mut Store, module: &WasmModule, linker: &Linker) -> Result<WasmInstance> {
let instance = match linker.instantiate(&mut *store, &module.inner) {
Ok(instance) => instance,
Err(err) => bail!("Error instantiating module: {:#}", err),
};
if let Some(memory) = instance.get_memory(&mut *store, "memory") {
store.data_mut().set_memory(memory);
}
Ok(WasmInstance {
inner: instance,
_engine: module.engine.clone(),
version: module.version,
})
}
#[derive(Clone)]
pub struct WasmModule {
inner: wasmtime::Module,
engine: wasmtime::Engine,
version: PluginSchemaVersion,
}
impl WasmModule {
pub fn new(module: wasmtime::Module, engine: wasmtime::Engine) -> Result<Self> {
Ok(Self {
version: get_current_plugin_schema_version(&module)?,
inner: module,
engine,
})
}
pub fn version(&self) -> PluginSchemaVersion {
self.version
}
pub fn inner(&self) -> &wasmtime::Module {
&self.inner
}
pub fn engine(&self) -> &wasmtime::Engine {
&self.engine
}
pub fn new_store(&self, data: WasmHostState) -> Store {
Store::new(&self.engine, data)
}
}
pub struct WasmModuleCreator {
engine: wasmtime::Engine,
}
impl Default for WasmModuleCreator {
fn default() -> Self {
Self { engine: new_engine() }
}
}
impl WasmModuleCreator {
pub fn create_from_wasm_bytes(&self, wasm_bytes: &[u8]) -> Result<WasmModule> {
let module = Module::new(&self.engine, wasm_bytes)?;
WasmModule::new(module, self.engine.clone())
}
pub fn create_from_serialized(&self, compiled_module_bytes: &[u8]) -> Result<WasmModule> {
unsafe {
match Module::deserialize(&self.engine, compiled_module_bytes) {
Ok(module) => WasmModule::new(module, self.engine.clone()),
Err(err) => bail!("Error deserializing compiled wasm module: {:#}", err),
}
}
}
}
pub const MAX_WASM_STACK_SIZE: usize = 1024 * 1024;
pub const WASM_PLUGIN_THREAD_STACK_SIZE: usize = MAX_WASM_STACK_SIZE + 3 * 1024 * 1024;
fn new_engine() -> wasmtime::Engine {
let mut config = Config::new();
#[cfg(not(use_pulley))]
{
config.cranelift_opt_level(wasmtime::OptLevel::Speed);
}
#[cfg(use_pulley)]
{
let pulley_target = if cfg!(target_endian = "big") { "pulley64be" } else { "pulley64" };
config.target(pulley_target).expect("failed to set pulley target");
}
config.max_wasm_stack(MAX_WASM_STACK_SIZE);
Engine::new(&config).expect("failed to create wasmtime engine")
}