pub(crate) mod code;
pub(crate) mod compile;
pub(crate) mod const_expr;
pub(crate) mod debug;
pub(crate) mod handler;
pub(crate) mod inner;
pub(crate) mod op;
#[cfg(feature = "simd")]
pub(crate) mod op_simd;
mod op_types;
pub(crate) mod parse;
mod serialize;
mod typesec;
use std::path::Path;
use std::sync::Arc;
use wasmparser::{Validator, WasmFeatures};
use crate::engine::Engine;
use crate::module::inner::ModuleInner;
use crate::value::{ExportType, ExternType, ImportType};
use crate::{Error, Result};
pub(crate) fn enabled_features() -> WasmFeatures {
WasmFeatures::MUTABLE_GLOBAL
| WasmFeatures::SIGN_EXTENSION
| WasmFeatures::MULTI_VALUE
| WasmFeatures::BULK_MEMORY
| WasmFeatures::SATURATING_FLOAT_TO_INT
| WasmFeatures::FLOATS
| WasmFeatures::REFERENCE_TYPES
| WasmFeatures::GC_TYPES
| WasmFeatures::FUNCTION_REFERENCES
| WasmFeatures::TAIL_CALL
| WasmFeatures::GC
| WasmFeatures::EXCEPTIONS
| WasmFeatures::EXTENDED_CONST
| WasmFeatures::MULTI_MEMORY
| WasmFeatures::MEMORY64
| simd_features()
}
#[cfg(feature = "simd")]
fn simd_features() -> WasmFeatures {
WasmFeatures::SIMD | WasmFeatures::RELAXED_SIMD
}
#[cfg(not(feature = "simd"))]
fn simd_features() -> WasmFeatures {
WasmFeatures::empty()
}
pub(crate) const DEFAULT_MAX_MODULE_BYTES: usize = 256 << 20;
pub(crate) const DEFAULT_MAX_EXPANDED_LOCALS: usize = 1 << 23;
#[derive(Clone, Copy, Debug)]
pub struct ModuleLimits {
pub max_module_bytes: usize,
pub max_expanded_locals: usize,
}
impl Default for ModuleLimits {
fn default() -> Self {
ModuleLimits {
max_module_bytes: DEFAULT_MAX_MODULE_BYTES,
max_expanded_locals: DEFAULT_MAX_EXPANDED_LOCALS,
}
}
}
#[derive(Clone, Debug)]
pub struct Module(Arc<ModuleInner>);
impl Module {
pub fn new(engine: &Engine, bytes: impl AsRef<[u8]>) -> Result<Module> {
Module::from_binary(engine, bytes.as_ref())
}
pub fn from_binary(engine: &Engine, binary: &[u8]) -> Result<Module> {
let inner = parse::parse_module(engine, binary, &engine.module_limits())?;
Ok(Module(Arc::new(inner)))
}
pub fn new_with_limits(
engine: &Engine,
bytes: impl AsRef<[u8]>,
limits: &ModuleLimits,
) -> Result<Module> {
let inner = parse::parse_module(engine, bytes.as_ref(), limits)?;
Ok(Module(Arc::new(inner)))
}
pub fn from_file(engine: &Engine, file: impl AsRef<Path>) -> Result<Module> {
let bytes = std::fs::read(file).map_err(|e| Error::msg(e.to_string()))?;
Module::from_binary(engine, &bytes)
}
pub fn serialize(&self) -> Result<Vec<u8>> {
serialize::encode(&self.0)
}
#[allow(unsafe_code)] pub unsafe fn deserialize(engine: &Engine, bytes: impl AsRef<[u8]>) -> Result<Module> {
let mut inner = serialize::decode(bytes.as_ref())?;
inner.intern(engine);
Ok(Module(Arc::new(inner)))
}
#[allow(unsafe_code)] pub unsafe fn deserialize_file(engine: &Engine, path: impl AsRef<Path>) -> Result<Module> {
let bytes = std::fs::read(path).map_err(|e| Error::msg(e.to_string()))?;
let mut inner = serialize::decode(&bytes)?;
inner.intern(engine);
Ok(Module(Arc::new(inner)))
}
pub fn validate(engine: &Engine, binary: &[u8]) -> Result<()> {
let max_module_bytes = engine.module_limits().max_module_bytes;
if binary.len() > max_module_bytes {
return Err(Error::msg(format!(
"module size {} exceeds configured limit {max_module_bytes}",
binary.len(),
)));
}
Validator::new_with_features(enabled_features())
.validate_all(binary)
.map(|_| ())
.map_err(|e| Error::msg(e.to_string()))
}
pub fn imports(&self) -> impl ExactSizeIterator<Item = ImportType<'_>> + '_ {
self.0.imports.iter().map(|imp| {
ImportType::new(&imp.module, &imp.name, self.0.import_extern_type(&imp.kind))
})
}
pub fn exports(&self) -> impl ExactSizeIterator<Item = ExportType<'_>> + '_ {
self.0
.exports
.iter()
.map(|e| ExportType::new(&e.name, self.0.export_extern_type(e.kind)))
}
pub fn get_export(&self, name: &str) -> Option<ExternType> {
self.0
.exports
.iter()
.find(|e| e.name == name)
.map(|e| self.0.export_extern_type(e.kind))
}
pub fn name(&self) -> Option<&str> {
self.0.debug.module_name()
}
pub(crate) fn inner(&self) -> &ModuleInner {
&self.0
}
pub(crate) fn code(&self, module_func_idx: u32) -> code::Code {
code::Code {
module: self.0.clone(),
index: module_func_idx - self.0.num_imported_funcs,
}
}
}