use crate::trampoline::StoreInstanceHandle;
use crate::{Export, Extern, Func, Global, Memory, Module, Store, Table, Trap};
use anyhow::{bail, Error, Result};
use std::any::Any;
use std::mem;
use wasmtime_environ::EntityIndex;
use wasmtime_jit::{CompiledModule, Resolver};
use wasmtime_runtime::{
InstanceHandle, InstantiationError, SignatureRegistry, VMContext, VMFunctionBody,
};
struct SimpleResolver<'a> {
imports: &'a [Extern],
}
impl Resolver for SimpleResolver<'_> {
fn resolve(&mut self, idx: u32, _name: &str, _field: &str) -> Option<wasmtime_runtime::Export> {
self.imports
.get(idx as usize)
.map(|i| i.get_wasmtime_export())
}
}
fn instantiate(
store: &Store,
compiled_module: &CompiledModule,
imports: &[Extern],
sig_registry: &SignatureRegistry,
host: Box<dyn Any>,
) -> Result<StoreInstanceHandle, Error> {
let mut resolver = SimpleResolver { imports };
unsafe {
let config = store.engine().config();
let instance = compiled_module.instantiate(
&mut resolver,
sig_registry,
config.memory_creator.as_ref().map(|a| a as _),
host,
)?;
let instance = store.add_instance(instance);
instance
.initialize(
config.validating_config.operator_config.enable_bulk_memory,
&compiled_module.data_initializers(),
)
.map_err(|e| -> Error {
match e {
InstantiationError::StartTrap(trap) | InstantiationError::Trap(trap) => {
Trap::from_jit(trap).into()
}
other => other.into(),
}
})?;
if let Some(start) = instance.module().start_func {
let f = match instance.lookup_by_declaration(&EntityIndex::Function(start)) {
wasmtime_runtime::Export::Function(f) => f,
_ => unreachable!(), };
super::func::catch_traps(instance.vmctx_ptr(), store, || {
mem::transmute::<
*const VMFunctionBody,
unsafe extern "C" fn(*mut VMContext, *mut VMContext),
>(f.address)(f.vmctx, instance.vmctx_ptr())
})?;
}
Ok(instance)
}
}
#[derive(Clone)]
pub struct Instance {
pub(crate) handle: StoreInstanceHandle,
module: Module,
}
impl Instance {
pub fn new(module: &Module, imports: &[Extern]) -> Result<Instance, Error> {
let store = module.store();
for import in imports {
if !import.comes_from_same_store(store) {
bail!("cross-`Store` instantiation is not currently supported");
}
}
if imports.len() != module.imports().len() {
bail!(
"wrong number of imports provided, {} != {}",
imports.len(),
module.imports().len()
);
}
let info = module.register_frame_info();
let handle = instantiate(
store,
module.compiled_module(),
imports,
store.compiler().signatures(),
Box::new(info),
)?;
Ok(Instance {
handle,
module: module.clone(),
})
}
pub fn store(&self) -> &Store {
self.module.store()
}
pub fn exports<'instance>(
&'instance self,
) -> impl ExactSizeIterator<Item = Export<'instance>> + 'instance {
self.handle.exports().map(move |(name, entity_index)| {
let export = self.handle.lookup_by_declaration(entity_index);
let extern_ = Extern::from_wasmtime_export(export, self.handle.clone());
Export::new(name, extern_)
})
}
pub fn get_export(&self, name: &str) -> Option<Extern> {
let export = self.handle.lookup(&name)?;
Some(Extern::from_wasmtime_export(export, self.handle.clone()))
}
pub fn get_func(&self, name: &str) -> Option<Func> {
self.get_export(name)?.into_func()
}
pub fn get_table(&self, name: &str) -> Option<Table> {
self.get_export(name)?.into_table()
}
pub fn get_memory(&self, name: &str) -> Option<Memory> {
self.get_export(name)?.into_memory()
}
pub fn get_global(&self, name: &str) -> Option<Global> {
self.get_export(name)?.into_global()
}
pub fn handle(&self) -> &InstanceHandle {
&self.handle.handle
}
}