use crate::{
resolve_imports, DeserializeError, InstantiationError, Resolver, RuntimeError, SerializeError,
Tunables,
};
use enumset::EnumSet;
use loupe::MemoryUsage;
use std::any::Any;
use std::convert::TryInto;
use std::path::Path;
use std::sync::Arc;
use std::{fs, mem};
use wasmer_compiler::{CpuFeature, Features};
use wasmer_types::entity::{BoxedSlice, PrimaryMap};
use wasmer_types::{
DataInitializer, FunctionIndex, LocalFunctionIndex, MemoryIndex, ModuleInfo,
OwnedDataInitializer, SignatureIndex, TableIndex,
};
use wasmer_vm::{
FuncDataRegistry, FunctionBodyPtr, InstanceAllocator, InstanceHandle, MemoryStyle, 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 cpu_features(&self) -> EnumSet<CpuFeature>;
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> {
let host_cpu_features = CpuFeature::for_host();
if !host_cpu_features.is_superset(self.cpu_features()) {
Err(InstantiationError::CpuFeature(format!(
"{:?}",
self.cpu_features().difference(host_cpu_features)
)))?;
}
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(),
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>()
}
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct MetadataHeader {
magic: [u8; 8],
version: u32,
len: u32,
}
impl MetadataHeader {
const CURRENT_VERSION: u32 = 1;
const MAGIC: [u8; 8] = *b"WASMER\0\0";
pub const LEN: usize = 16;
pub const ALIGN: usize = 16;
pub fn new(len: usize) -> [u8; 16] {
let header = MetadataHeader {
magic: Self::MAGIC,
version: Self::CURRENT_VERSION,
len: len.try_into().expect("metadata exceeds maximum length"),
};
unsafe { mem::transmute(header) }
}
pub fn parse(bytes: &[u8]) -> Result<usize, DeserializeError> {
if bytes.as_ptr() as usize % 16 != 0 {
return Err(DeserializeError::CorruptedBinary(
"misaligned metadata".to_string(),
));
}
let bytes: [u8; 16] = bytes
.get(..16)
.ok_or_else(|| {
DeserializeError::CorruptedBinary("invalid metadata header".to_string())
})?
.try_into()
.unwrap();
let header: MetadataHeader = unsafe { mem::transmute(bytes) };
if header.magic != Self::MAGIC {
return Err(DeserializeError::Incompatible(
"The provided bytes were not serialized by Wasmer".to_string(),
));
}
if header.version != Self::CURRENT_VERSION {
return Err(DeserializeError::Incompatible(
"The provided bytes were serialized by an incompatible version of Wasmer"
.to_string(),
));
}
Ok(header.len as usize)
}
}