use crate::frame_info::GlobalFrameInfoRegistration;
use crate::runtime::Store;
use crate::types::{EntityType, ExportType, 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 {
inner: Arc<ModuleInner>,
}
struct ModuleInner {
store: Store,
compiled: CompiledModule,
frame_info_registration: Mutex<Option<Option<Arc<GlobalFrameInfoRegistration>>>>,
}
impl Module {
pub fn new(store: &Store, bytes: impl AsRef<[u8]>) -> Result<Module> {
#[cfg(feature = "wat")]
let bytes = wat::parse_bytes(bytes.as_ref())?;
Module::from_binary(store, bytes.as_ref())
}
pub fn new_with_name(store: &Store, bytes: impl AsRef<[u8]>, name: &str) -> Result<Module> {
let mut module = Module::new(store, bytes.as_ref())?;
let inner = Arc::get_mut(&mut module.inner).unwrap();
Arc::get_mut(inner.compiled.module_mut()).unwrap().name = Some(name.to_string());
Ok(module)
}
pub fn from_file(store: &Store, 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(store, &wasm)
}
pub fn from_binary(store: &Store, binary: &[u8]) -> Result<Module> {
Module::validate(store, binary)?;
unsafe { Module::from_binary_unchecked(store, binary) }
}
pub unsafe fn from_binary_unchecked(store: &Store, binary: &[u8]) -> Result<Module> {
Module::compile(store, binary)
}
pub fn validate(store: &Store, binary: &[u8]) -> Result<()> {
let config = store.engine().config().validating_config.clone();
validate(binary, Some(config)).map_err(Error::new)
}
unsafe fn compile(store: &Store, binary: &[u8]) -> Result<Self> {
let compiled =
CompiledModule::new(store.compiler(), binary, &*store.engine().config().profiler)?;
Ok(Module {
inner: Arc::new(ModuleInner {
store: store.clone(),
compiled,
frame_info_registration: Mutex::new(None),
}),
})
}
pub(crate) fn compiled_module(&self) -> &CompiledModule {
&self.inner.compiled
}
pub fn name(&self) -> Option<&str> {
self.inner.compiled.module().name.as_deref()
}
pub fn imports<'module>(
&'module self,
) -> impl ExactSizeIterator<Item = ImportType<'module>> + 'module {
let module = self.inner.compiled.module_ref();
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.inner.compiled.module_ref();
module.exports.iter().map(move |(name, entity_index)| {
let r#type = EntityType::new(entity_index, module);
ExportType::new(name, r#type)
})
}
pub fn store(&self) -> &Store {
&self.inner.store
}
pub(crate) fn register_frame_info(&self) -> Option<Arc<GlobalFrameInfoRegistration>> {
let mut info = self.inner.frame_info_registration.lock().unwrap();
if let Some(info) = &*info {
return info.clone();
}
let ret = super::frame_info::register(&self.inner.compiled).map(Arc::new);
*info = Some(ret.clone());
return ret;
}
}