use crate::trampoline::StoreInstanceHandle;
use crate::{Engine, 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::{InstantiationError, 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],
host: Box<dyn Any>,
) -> Result<StoreInstanceHandle, Error> {
for import in imports {
if !import.comes_from_same_store(store) {
bail!("cross-`Store` instantiation is not currently supported");
}
}
if imports.len() != compiled_module.module().imports.len() {
bail!(
"wrong number of imports provided, {} != {}",
imports.len(),
compiled_module.module().imports.len()
);
}
let mut resolver = SimpleResolver { imports };
let config = store.engine().config();
let instance = unsafe {
let instance = compiled_module.instantiate(
&mut resolver,
&mut store.signatures_mut(),
config.memory_creator.as_ref().map(|a| a as _),
store.interrupts().clone(),
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::Trap(trap) => Trap::from_runtime(trap).into(),
other => other.into(),
}
})?;
instance
};
let start_func = instance.handle.module().start_func;
if let Some(start) = start_func {
let f = match instance
.handle
.lookup_by_declaration(&EntityIndex::Function(start))
{
wasmtime_runtime::Export::Function(f) => f,
_ => unreachable!(), };
let vmctx_ptr = instance.handle.vmctx_ptr();
unsafe {
super::func::catch_traps(vmctx_ptr, store, || {
mem::transmute::<
*const VMFunctionBody,
unsafe extern "C" fn(*mut VMContext, *mut VMContext),
>(f.address)(f.vmctx, vmctx_ptr)
})?;
}
}
Ok(instance)
}
#[derive(Clone)]
pub struct Instance {
pub(crate) handle: StoreInstanceHandle,
store: Store,
module: Module,
}
impl Instance {
pub fn new(store: &Store, module: &Module, imports: &[Extern]) -> Result<Instance, Error> {
if !Engine::same(store.engine(), module.engine()) {
bail!("cross-`Engine` instantiation is not currently supported");
}
let info = module.register_frame_info();
store.register_jit_code(module.compiled_module().jit_code_ranges());
let handle = instantiate(store, module.compiled_module(), imports, Box::new(info))?;
Ok(Instance {
handle,
store: store.clone(),
module: module.clone(),
})
}
pub fn store(&self) -> &Store {
&self.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()
}
}