use crate::sys::exports::Exports;
use crate::sys::externals::Extern;
use crate::sys::module::Module;
use crate::sys::store::Store;
use crate::sys::{HostEnvInitError, LinkError, RuntimeError};
use loupe::MemoryUsage;
use std::fmt;
use std::sync::{Arc, Mutex};
use thiserror::Error;
use wasmer_engine::Resolver;
use wasmer_vm::{InstanceHandle, VMContext};
#[derive(Clone, MemoryUsage)]
pub struct Instance {
handle: Arc<Mutex<InstanceHandle>>,
module: Module,
pub exports: Exports,
}
#[cfg(test)]
mod send_test {
use super::*;
fn is_send<T: Send>() -> bool {
true
}
#[test]
fn instance_is_send() {
assert!(is_send::<Instance>());
}
}
#[derive(Error, Debug)]
pub enum InstantiationError {
#[error(transparent)]
Link(LinkError),
#[error(transparent)]
Start(RuntimeError),
#[error("missing requires CPU features: {0:?}")]
CpuFeature(String),
#[error(transparent)]
HostEnvInitialization(HostEnvInitError),
}
impl From<wasmer_engine::InstantiationError> for InstantiationError {
fn from(other: wasmer_engine::InstantiationError) -> Self {
match other {
wasmer_engine::InstantiationError::Link(e) => Self::Link(e),
wasmer_engine::InstantiationError::Start(e) => Self::Start(e),
wasmer_engine::InstantiationError::CpuFeature(e) => Self::CpuFeature(e),
}
}
}
impl From<HostEnvInitError> for InstantiationError {
fn from(other: HostEnvInitError) -> Self {
Self::HostEnvInitialization(other)
}
}
impl Instance {
pub fn new(
module: &Module,
resolver: &(dyn Resolver + Send + Sync),
) -> Result<Self, InstantiationError> {
let store = module.store();
let handle = module.instantiate(resolver)?;
let exports = module
.exports()
.map(|export| {
let name = export.name().to_string();
let export = handle.lookup(&name).expect("export");
let extern_ = Extern::from_vm_export(store, export.into());
(name, extern_)
})
.collect::<Exports>();
let instance = Self {
handle: Arc::new(Mutex::new(handle)),
module: module.clone(),
exports,
};
unsafe {
instance
.handle
.lock()
.unwrap()
.initialize_host_envs::<HostEnvInitError>(&instance as *const _ as *const _)?;
}
Ok(instance)
}
pub fn module(&self) -> &Module {
&self.module
}
pub fn store(&self) -> &Store {
self.module.store()
}
#[doc(hidden)]
pub fn vmctx_ptr(&self) -> *mut VMContext {
self.handle.lock().unwrap().vmctx_ptr()
}
}
impl fmt::Debug for Instance {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Instance")
.field("exports", &self.exports)
.finish()
}
}