use crate::frame_info::GlobalFrameInfoRegistration;
use crate::runtime::{Config, Engine};
use crate::types::{EntityType, ExportType, ExternType, ImportType};
use anyhow::{bail, Context, Result};
use std::path::Path;
use std::sync::{Arc, Mutex};
#[cfg(feature = "cache")]
use wasmtime_cache::ModuleCacheEntry;
use wasmtime_jit::{CompilationArtifacts, CompiledModule};
#[derive(Clone)]
pub struct Module {
engine: Engine,
compiled: Arc<CompiledModule>,
frame_info_registration: Arc<Mutex<Option<Option<Arc<GlobalFrameInfoRegistration>>>>>,
}
impl Module {
pub fn new(engine: &Engine, bytes: impl AsRef<[u8]>) -> Result<Module> {
#[cfg(feature = "wat")]
let bytes = wat::parse_bytes(bytes.as_ref())?;
Module::from_binary(engine, bytes.as_ref())
}
pub fn new_with_name(engine: &Engine, bytes: impl AsRef<[u8]>, name: &str) -> Result<Module> {
let mut module = Module::new(engine, bytes.as_ref())?;
Arc::get_mut(&mut module.compiled)
.unwrap()
.module_mut()
.expect("mutable module")
.name = Some(name.to_string());
Ok(module)
}
pub fn from_file(engine: &Engine, file: impl AsRef<Path>) -> Result<Module> {
#[cfg(feature = "wat")]
let wasm = wat::parse_file(file)?;
#[cfg(not(feature = "wat"))]
let wasm = std::fs::read(file)?;
Module::new(engine, &wasm)
}
pub fn from_binary(engine: &Engine, binary: &[u8]) -> Result<Module> {
Module::validate(engine, binary)?;
unsafe { Module::from_binary_unchecked(engine, binary) }
}
pub unsafe fn from_binary_unchecked(engine: &Engine, binary: &[u8]) -> Result<Module> {
Module::compile(engine, binary)
}
pub fn validate(engine: &Engine, binary: &[u8]) -> Result<()> {
engine.config().validator().validate_all(binary)?;
Ok(())
}
unsafe fn compile(engine: &Engine, binary: &[u8]) -> Result<Self> {
#[cfg(feature = "cache")]
let artifacts = ModuleCacheEntry::new("wasmtime", engine.cache_config())
.get_data((engine.compiler(), binary), |(compiler, binary)| {
CompilationArtifacts::build(compiler, binary)
})?;
#[cfg(not(feature = "cache"))]
let artifacts = CompilationArtifacts::build(engine.compiler(), binary)?;
let compiled = CompiledModule::from_artifacts(
artifacts,
engine.compiler().isa(),
&*engine.config().profiler,
)?;
Ok(Module {
engine: engine.clone(),
compiled: Arc::new(compiled),
frame_info_registration: Arc::new(Mutex::new(None)),
})
}
pub fn serialize(&self) -> Result<Vec<u8>> {
let artifacts = (
compiler_fingerprint(self.engine.config()),
self.compiled.to_compilation_artifacts(),
);
let mut buffer = Vec::new();
bincode::serialize_into(&mut buffer, &artifacts)?;
Ok(buffer)
}
pub fn deserialize(engine: &Engine, serialized: &[u8]) -> Result<Module> {
let expected_fingerprint = compiler_fingerprint(engine.config());
let (fingerprint, artifacts) =
bincode::deserialize_from::<_, (u64, CompilationArtifacts)>(serialized)
.context("Deserialize compilation artifacts")?;
if fingerprint != expected_fingerprint {
bail!("Incompatible compilation artifact");
}
let compiled = CompiledModule::from_artifacts(
artifacts,
engine.compiler().isa(),
&*engine.config().profiler,
)?;
Ok(Module {
engine: engine.clone(),
compiled: Arc::new(compiled),
frame_info_registration: Arc::new(Mutex::new(None)),
})
}
pub(crate) fn compiled_module(&self) -> &CompiledModule {
&self.compiled
}
pub fn name(&self) -> Option<&str> {
self.compiled.module().name.as_deref()
}
pub fn imports<'module>(
&'module self,
) -> impl ExactSizeIterator<Item = ImportType<'module>> + 'module {
let module = self.compiled.module();
module
.imports
.iter()
.map(move |(module_name, name, entity_index)| {
let r#type = EntityType::new(entity_index, module);
ImportType::new(module_name, name, r#type)
})
}
pub fn exports<'module>(
&'module self,
) -> impl ExactSizeIterator<Item = ExportType<'module>> + 'module {
let module = self.compiled.module();
module.exports.iter().map(move |(name, entity_index)| {
let r#type = EntityType::new(entity_index, module);
ExportType::new(name, r#type)
})
}
pub fn get_export<'module>(&'module self, name: &'module str) -> Option<ExternType> {
let module = self.compiled.module();
let entity_index = module.exports.get(name)?;
Some(EntityType::new(entity_index, module).extern_type())
}
pub fn engine(&self) -> &Engine {
&self.engine
}
pub(crate) fn register_frame_info(&self) -> Option<Arc<GlobalFrameInfoRegistration>> {
let mut info = self.frame_info_registration.lock().unwrap();
if let Some(info) = &*info {
return info.clone();
}
let ret = super::frame_info::register(&self.compiled).map(Arc::new);
*info = Some(ret.clone());
return ret;
}
}
fn compiler_fingerprint(config: &Config) -> u64 {
use std::hash::Hasher;
let mut hasher = std::collections::hash_map::DefaultHasher::new();
config.compiler_fingerprint(&mut hasher);
hasher.finish()
}
fn _assert_send_sync() {
fn _assert<T: Send + Sync>() {}
_assert::<Module>();
}