use crate::sys::tunables::BaseTunables;
use loupe::MemoryUsage;
use std::any::Any;
use std::fmt;
use std::sync::{Arc, RwLock};
#[cfg(all(feature = "compiler", feature = "engine"))]
use wasmer_compiler::CompilerConfig;
use wasmer_engine::{is_wasm_pc, Engine, Tunables};
use wasmer_vm::{init_traps, TrapHandler, TrapHandlerFn};
#[derive(Clone, MemoryUsage)]
pub struct Store {
engine: Arc<dyn Engine + Send + Sync>,
tunables: Arc<dyn Tunables + Send + Sync>,
#[loupe(skip)]
trap_handler: Arc<RwLock<Option<Box<TrapHandlerFn>>>>,
}
impl Store {
pub fn new<E>(engine: &E) -> Self
where
E: Engine + ?Sized,
{
Self::new_with_tunables(engine, BaseTunables::for_target(engine.target()))
}
pub fn set_trap_handler(&self, handler: Option<Box<TrapHandlerFn>>) {
let mut m = self.trap_handler.write().unwrap();
*m = handler;
}
pub fn new_with_tunables<E>(engine: &E, tunables: impl Tunables + Send + Sync + 'static) -> Self
where
E: Engine + ?Sized,
{
init_traps(is_wasm_pc);
Self {
engine: engine.cloned(),
tunables: Arc::new(tunables),
trap_handler: Arc::new(RwLock::new(None)),
}
}
pub fn tunables(&self) -> &dyn Tunables {
self.tunables.as_ref()
}
pub fn engine(&self) -> &Arc<dyn Engine + Send + Sync> {
&self.engine
}
pub fn same(a: &Self, b: &Self) -> bool {
a.engine.id() == b.engine.id()
}
}
impl PartialEq for Store {
fn eq(&self, other: &Self) -> bool {
Self::same(self, other)
}
}
unsafe impl TrapHandler for Store {
#[inline]
fn as_any(&self) -> &dyn Any {
self
}
fn custom_trap_handler(&self, call: &dyn Fn(&TrapHandlerFn) -> bool) -> bool {
if let Some(handler) = *&self.trap_handler.read().unwrap().as_ref() {
call(handler)
} else {
false
}
}
}
unsafe impl Send for Store {}
unsafe impl Sync for Store {}
#[cfg(all(feature = "default-compiler", feature = "default-engine"))]
impl Default for Store {
fn default() -> Self {
#[allow(unreachable_code)]
fn get_config() -> impl CompilerConfig + 'static {
cfg_if::cfg_if! {
if #[cfg(feature = "default-cranelift")] {
wasmer_compiler_cranelift::Cranelift::default()
} else if #[cfg(feature = "default-llvm")] {
wasmer_compiler_llvm::LLVM::default()
} else if #[cfg(feature = "default-singlepass")] {
wasmer_compiler_singlepass::Singlepass::default()
} else {
compile_error!("No default compiler chosen")
}
}
}
#[allow(unreachable_code, unused_mut)]
fn get_engine(mut config: impl CompilerConfig + 'static) -> impl Engine + Send + Sync {
cfg_if::cfg_if! {
if #[cfg(feature = "default-universal")] {
wasmer_engine_universal::Universal::new(config)
.engine()
} else if #[cfg(feature = "default-dylib")] {
wasmer_engine_dylib::Dylib::new(config)
.engine()
} else {
compile_error!("No default engine chosen")
}
}
}
let config = get_config();
let engine = get_engine(config);
let tunables = BaseTunables::for_target(engine.target());
Self::new_with_tunables(&engine, tunables)
}
}
impl fmt::Debug for Store {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Store").finish()
}
}
pub trait StoreObject {
fn comes_from_same_store(&self, store: &Store) -> bool;
}