use crate::frame_info::GlobalFrameInfoRegistration;
use crate::runtime::Engine;
use crate::types::{EntityType, ExportType, ExternType, ImportType};
use anyhow::{Error, Result};
use std::path::Path;
use std::sync::{Arc, Mutex};
use wasmparser::validate;
use wasmtime_jit::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<()> {
let config = engine.config().validating_config.clone();
validate(binary, Some(config)).map_err(Error::new)
}
unsafe fn compile(engine: &Engine, binary: &[u8]) -> Result<Self> {
let compiled = CompiledModule::new(engine.compiler(), binary, &*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 _assert_send_sync() {
fn _assert<T: Send + Sync>() {}
_assert::<Module>();
}