use crate::{
resolve_imports, InstantiationError, Resolver, RuntimeError, SerializeError, Tunables,
};
use loupe::MemoryUsage;
use std::any::Any;
use std::fs;
use std::path::Path;
use std::sync::Arc;
use wasmer_compiler::Features;
use wasmer_types::entity::{BoxedSlice, PrimaryMap};
use wasmer_types::{
DataInitializer, FunctionIndex, LocalFunctionIndex, MemoryIndex, OwnedDataInitializer,
SignatureIndex, TableIndex,
};
use wasmer_vm::{
FuncDataRegistry, FunctionBodyPtr, InstanceAllocator, InstanceHandle, MemoryStyle, ModuleInfo,
TableStyle, TrapHandler, VMSharedSignatureIndex, VMTrampoline,
};
pub trait Artifact: Send + Sync + Upcastable + MemoryUsage {
fn module(&self) -> Arc<ModuleInfo>;
fn module_ref(&self) -> &ModuleInfo;
fn module_mut(&mut self) -> Option<&mut ModuleInfo>;
fn register_frame_info(&self);
fn features(&self) -> &Features;
fn memory_styles(&self) -> &PrimaryMap<MemoryIndex, MemoryStyle>;
fn table_styles(&self) -> &PrimaryMap<TableIndex, TableStyle>;
fn data_initializers(&self) -> &[OwnedDataInitializer];
fn finished_functions(&self) -> &BoxedSlice<LocalFunctionIndex, FunctionBodyPtr>;
fn finished_function_call_trampolines(&self) -> &BoxedSlice<SignatureIndex, VMTrampoline>;
fn finished_dynamic_function_trampolines(&self) -> &BoxedSlice<FunctionIndex, FunctionBodyPtr>;
fn signatures(&self) -> &BoxedSlice<SignatureIndex, VMSharedSignatureIndex>;
fn func_data_registry(&self) -> &FuncDataRegistry;
fn serialize(&self) -> Result<Vec<u8>, SerializeError>;
fn serialize_to_file(&self, path: &Path) -> Result<(), SerializeError> {
let serialized = self.serialize()?;
fs::write(&path, serialized)?;
Ok(())
}
fn preinstantiate(&self) -> Result<(), InstantiationError> {
Ok(())
}
unsafe fn instantiate(
&self,
tunables: &dyn Tunables,
resolver: &dyn Resolver,
host_state: Box<dyn Any>,
) -> Result<InstanceHandle, InstantiationError> {
self.preinstantiate()?;
let module = self.module();
let (imports, import_function_envs) = {
let mut imports = resolve_imports(
&module,
resolver,
&self.finished_dynamic_function_trampolines(),
self.memory_styles(),
self.table_styles(),
)
.map_err(InstantiationError::Link)?;
let import_function_envs = imports.get_imported_function_envs();
(imports, import_function_envs)
};
let (allocator, memory_definition_locations, table_definition_locations) =
InstanceAllocator::new(&*module);
let finished_memories = tunables
.create_memories(&module, self.memory_styles(), &memory_definition_locations)
.map_err(InstantiationError::Link)?
.into_boxed_slice();
let finished_tables = tunables
.create_tables(&module, self.table_styles(), &table_definition_locations)
.map_err(InstantiationError::Link)?
.into_boxed_slice();
let finished_globals = tunables
.create_globals(&module)
.map_err(InstantiationError::Link)?
.into_boxed_slice();
self.register_frame_info();
let handle = InstanceHandle::new(
allocator,
module,
self.finished_functions().clone(),
self.finished_function_call_trampolines().clone(),
finished_memories,
finished_tables,
finished_globals,
imports,
self.signatures().clone(),
self.func_data_registry(),
host_state,
import_function_envs,
)
.map_err(|trap| InstantiationError::Start(RuntimeError::from_trap(trap)))?;
Ok(handle)
}
unsafe fn finish_instantiation(
&self,
trap_handler: &dyn TrapHandler,
handle: &InstanceHandle,
) -> Result<(), InstantiationError> {
let data_initializers = self
.data_initializers()
.iter()
.map(|init| DataInitializer {
location: init.location.clone(),
data: &*init.data,
})
.collect::<Vec<_>>();
handle
.finish_instantiation(trap_handler, &data_initializers)
.map_err(|trap| InstantiationError::Start(RuntimeError::from_trap(trap)))
}
}
pub trait Upcastable {
fn upcast_any_ref(&'_ self) -> &'_ dyn Any;
fn upcast_any_mut(&'_ mut self) -> &'_ mut dyn Any;
fn upcast_any_box(self: Box<Self>) -> Box<dyn Any>;
}
impl<T: Any + Send + Sync + 'static> Upcastable for T {
#[inline]
fn upcast_any_ref(&'_ self) -> &'_ dyn Any {
self
}
#[inline]
fn upcast_any_mut(&'_ mut self) -> &'_ mut dyn Any {
self
}
#[inline]
fn upcast_any_box(self: Box<Self>) -> Box<dyn Any> {
self
}
}
impl dyn Artifact + 'static {
#[inline]
pub fn downcast_ref<T: 'static>(&'_ self) -> Option<&'_ T> {
self.upcast_any_ref().downcast_ref::<T>()
}
#[inline]
pub fn downcast_mut<T: 'static>(&'_ mut self) -> Option<&'_ mut T> {
self.upcast_any_mut().downcast_mut::<T>()
}
}