Files
wasmer/lib/api/src/module.rs
2023-02-16 20:44:49 -08:00

401 lines
13 KiB
Rust

use bytes::Bytes;
use std::fmt;
use std::fs;
use std::io;
use std::path::Path;
use crate::engine::AsEngineRef;
use thiserror::Error;
#[cfg(feature = "wat")]
use wasmer_types::WasmError;
use wasmer_types::{
CompileError, DeserializeError, ExportsIterator, ImportsIterator, ModuleInfo, SerializeError,
};
use wasmer_types::{ExportType, ImportType};
use crate::into_bytes::IntoBytes;
#[cfg(feature = "js")]
use crate::js::module as module_imp;
#[cfg(feature = "sys")]
use crate::sys::module as module_imp;
/// IO Error on a Module Compilation
#[derive(Error, Debug)]
pub enum IoCompileError {
/// An IO error
#[error(transparent)]
Io(#[from] io::Error),
/// A compilation error
#[error(transparent)]
Compile(#[from] CompileError),
}
/// A WebAssembly Module contains stateless WebAssembly
/// code that has already been compiled and can be instantiated
/// multiple times.
///
/// ## Cloning a module
///
/// Cloning a module is cheap: it does a shallow copy of the compiled
/// contents rather than a deep copy.
#[derive(Clone)]
pub struct Module(pub(crate) module_imp::Module);
impl Module {
/// Creates a new WebAssembly Module given the configuration
/// in the store.
///
/// If the provided bytes are not WebAssembly-like (start with `b"\0asm"`),
/// and the "wat" feature is enabled for this crate, this function will try to
/// to convert the bytes assuming they correspond to the WebAssembly text
/// format.
///
/// ## Security
///
/// Before the code is compiled, it will be validated using the store
/// features.
///
/// ## Errors
///
/// Creating a WebAssembly module from bytecode can result in a
/// [`CompileError`] since this operation requires to transorm the Wasm
/// bytecode into code the machine can easily execute.
///
/// ## Example
///
/// Reading from a WAT file.
///
/// ```
/// use wasmer::*;
/// # fn main() -> anyhow::Result<()> {
/// # let mut store = Store::default();
/// let wat = "(module)";
/// let module = Module::new(&store, wat)?;
/// # Ok(())
/// # }
/// ```
///
/// Reading from bytes:
///
/// ```
/// use wasmer::*;
/// # fn main() -> anyhow::Result<()> {
/// # let mut store = Store::default();
/// // The following is the same as:
/// // (module
/// // (type $t0 (func (param i32) (result i32)))
/// // (func $add_one (export "add_one") (type $t0) (param $p0 i32) (result i32)
/// // get_local $p0
/// // i32.const 1
/// // i32.add)
/// // )
/// let bytes: Vec<u8> = vec![
/// 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x01, 0x60,
/// 0x01, 0x7f, 0x01, 0x7f, 0x03, 0x02, 0x01, 0x00, 0x07, 0x0b, 0x01, 0x07,
/// 0x61, 0x64, 0x64, 0x5f, 0x6f, 0x6e, 0x65, 0x00, 0x00, 0x0a, 0x09, 0x01,
/// 0x07, 0x00, 0x20, 0x00, 0x41, 0x01, 0x6a, 0x0b, 0x00, 0x1a, 0x04, 0x6e,
/// 0x61, 0x6d, 0x65, 0x01, 0x0a, 0x01, 0x00, 0x07, 0x61, 0x64, 0x64, 0x5f,
/// 0x6f, 0x6e, 0x65, 0x02, 0x07, 0x01, 0x00, 0x01, 0x00, 0x02, 0x70, 0x30,
/// ];
/// let module = Module::new(&store, bytes)?;
/// # Ok(())
/// # }
/// ```
/// # Example of loading a module using just an `Engine` and no `Store`
///
/// ```
/// # use wasmer::*;
/// #
/// # let compiler = Cranelift::default();
/// # let engine = EngineBuilder::new(compiler).engine();
///
/// let module = Module::from_file(&engine, "path/to/foo.wasm");
/// ```
pub fn new(engine: &impl AsEngineRef, bytes: impl AsRef<[u8]>) -> Result<Self, CompileError> {
#[cfg(feature = "wat")]
let bytes = wat::parse_bytes(bytes.as_ref()).map_err(|e| {
CompileError::Wasm(WasmError::Generic(format!(
"Error when converting wat: {}",
e
)))
})?;
Self::from_binary(engine, bytes.as_ref())
}
/// Creates a new WebAssembly module from a file path.
pub fn from_file(
engine: &impl AsEngineRef,
file: impl AsRef<Path>,
) -> Result<Self, IoCompileError> {
let file_ref = file.as_ref();
let canonical = file_ref.canonicalize()?;
let wasm_bytes = std::fs::read(file_ref)?;
let mut module = Self::new(engine, &wasm_bytes)?;
// Set the module name to the absolute path of the filename.
// This is useful for debugging the stack traces.
let filename = canonical.as_path().to_str().unwrap();
module.set_name(filename);
Ok(module)
}
/// Creates a new WebAssembly module from a serialized binary.
///
/// Opposed to [`Module::new`], this function is not compatible with
/// the WebAssembly text format (if the "wat" feature is enabled for
/// this crate).
pub fn from_binary(engine: &impl AsEngineRef, binary: &[u8]) -> Result<Self, CompileError> {
Ok(Self(module_imp::Module::from_binary(engine, binary)?))
}
/// Creates a new WebAssembly module skipping any kind of validation.
///
/// # Safety
///
/// This can speed up compilation time a bit, but it should be only used
/// in environments where the WebAssembly modules are trusted and validated
/// beforehand.
pub unsafe fn from_binary_unchecked(
engine: &impl AsEngineRef,
binary: &[u8],
) -> Result<Self, CompileError> {
Ok(Self(module_imp::Module::from_binary_unchecked(
engine, binary,
)?))
}
/// Validates a new WebAssembly Module given the configuration
/// in the Store.
///
/// This validation is normally pretty fast and checks the enabled
/// WebAssembly features in the Store Engine to assure deterministic
/// validation of the Module.
pub fn validate(engine: &impl AsEngineRef, binary: &[u8]) -> Result<(), CompileError> {
module_imp::Module::validate(engine, binary)
}
/// Serializes a module into a binary representation that the `Engine`
/// can later process via [`Module::deserialize`].
///
/// # Usage
///
/// ```ignore
/// # use wasmer::*;
/// # fn main() -> anyhow::Result<()> {
/// # let mut store = Store::default();
/// # let module = Module::from_file(&store, "path/to/foo.wasm")?;
/// let serialized = module.serialize()?;
/// # Ok(())
/// # }
/// ```
pub fn serialize(&self) -> Result<Bytes, SerializeError> {
self.0.serialize()
}
/// Serializes a module into a file that the `Engine`
/// can later process via [`Module::deserialize_from_file`].
///
/// # Usage
///
/// ```ignore
/// # use wasmer::*;
/// # fn main() -> anyhow::Result<()> {
/// # let mut store = Store::default();
/// # let module = Module::from_file(&store, "path/to/foo.wasm")?;
/// module.serialize_to_file("path/to/foo.so")?;
/// # Ok(())
/// # }
/// ```
pub fn serialize_to_file(&self, path: impl AsRef<Path>) -> Result<(), SerializeError> {
let serialized = self.0.serialize()?;
fs::write(path, serialized)?;
Ok(())
}
/// Deserializes a serialized Module binary into a `Module`.
/// > Note: the module has to be serialized before with the `serialize` method.
///
/// # Safety
///
/// This function is inherently **unsafe** as the provided bytes:
/// 1. Are going to be deserialized directly into Rust objects.
/// 2. Contains the function assembly bodies and, if intercepted,
/// a malicious actor could inject code into executable
/// memory.
///
/// And as such, the `deserialize` method is unsafe.
///
/// # Usage
///
/// ```ignore
/// # use wasmer::*;
/// # fn main() -> anyhow::Result<()> {
/// # let mut store = Store::default();
/// let module = Module::deserialize(&store, serialized_data)?;
/// # Ok(())
/// # }
/// ```
pub unsafe fn deserialize(
engine: &impl AsEngineRef,
bytes: impl IntoBytes,
) -> Result<Self, DeserializeError> {
Ok(Self(module_imp::Module::deserialize(engine, bytes)?))
}
/// Deserializes a a serialized Module located in a `Path` into a `Module`.
/// > Note: the module has to be serialized before with the `serialize` method.
///
/// # Safety
///
/// Please check [`Module::deserialize`].
///
/// # Usage
///
/// ```ignore
/// # use wasmer::*;
/// # let mut store = Store::default();
/// # fn main() -> anyhow::Result<()> {
/// let module = Module::deserialize_from_file(&store, path)?;
/// # Ok(())
/// # }
/// ```
pub unsafe fn deserialize_from_file(
engine: &impl AsEngineRef,
path: impl AsRef<Path>,
) -> Result<Self, DeserializeError> {
Ok(Self(module_imp::Module::deserialize_from_file(
engine, path,
)?))
}
/// Returns the name of the current module.
///
/// This name is normally set in the WebAssembly bytecode by some
/// compilers, but can be also overwritten using the [`Module::set_name`] method.
///
/// # Example
///
/// ```
/// # use wasmer::*;
/// # fn main() -> anyhow::Result<()> {
/// # let mut store = Store::default();
/// let wat = "(module $moduleName)";
/// let module = Module::new(&store, wat)?;
/// assert_eq!(module.name(), Some("moduleName"));
/// # Ok(())
/// # }
/// ```
pub fn name(&self) -> Option<&str> {
self.0.name()
}
/// Sets the name of the current module.
/// This is normally useful for stacktraces and debugging.
///
/// It will return `true` if the module name was changed successfully,
/// and return `false` otherwise (in case the module is cloned or
/// already instantiated).
///
/// # Example
///
/// ```
/// # use wasmer::*;
/// # fn main() -> anyhow::Result<()> {
/// # let mut store = Store::default();
/// let wat = "(module)";
/// let mut module = Module::new(&store, wat)?;
/// assert_eq!(module.name(), None);
/// module.set_name("foo");
/// assert_eq!(module.name(), Some("foo"));
/// # Ok(())
/// # }
/// ```
pub fn set_name(&mut self, name: &str) -> bool {
self.0.set_name(name)
}
/// Returns an iterator over the imported types in the Module.
///
/// The order of the imports is guaranteed to be the same as in the
/// WebAssembly bytecode.
///
/// # Example
///
/// ```
/// # use wasmer::*;
/// # fn main() -> anyhow::Result<()> {
/// # let mut store = Store::default();
/// let wat = r#"(module
/// (import "host" "func1" (func))
/// (import "host" "func2" (func))
/// )"#;
/// let module = Module::new(&store, wat)?;
/// for import in module.imports() {
/// assert_eq!(import.module(), "host");
/// assert!(import.name().contains("func"));
/// import.ty();
/// }
/// # Ok(())
/// # }
/// ```
pub fn imports(&self) -> ImportsIterator<impl Iterator<Item = ImportType> + '_> {
self.0.imports()
}
/// Returns an iterator over the exported types in the Module.
///
/// The order of the exports is guaranteed to be the same as in the
/// WebAssembly bytecode.
///
/// # Example
///
/// ```
/// # use wasmer::*;
/// # fn main() -> anyhow::Result<()> {
/// # let mut store = Store::default();
/// let wat = r#"(module
/// (func (export "namedfunc"))
/// (memory (export "namedmemory") 1)
/// )"#;
/// let module = Module::new(&store, wat)?;
/// for export_ in module.exports() {
/// assert!(export_.name().contains("named"));
/// export_.ty();
/// }
/// # Ok(())
/// # }
/// ```
pub fn exports(&self) -> ExportsIterator<impl Iterator<Item = ExportType> + '_> {
self.0.exports()
}
/// Get the custom sections of the module given a `name`.
///
/// # Important
///
/// Following the WebAssembly spec, one name can have multiple
/// custom sections. That's why an iterator (rather than one element)
/// is returned.
pub fn custom_sections<'a>(&'a self, name: &'a str) -> impl Iterator<Item = Box<[u8]>> + 'a {
self.0.custom_sections(name)
}
/// The ABI of the [`ModuleInfo`] is very unstable, we refactor it very often.
/// This function is public because in some cases it can be useful to get some
/// extra information from the module.
///
/// However, the usage is highly discouraged.
#[doc(hidden)]
pub fn info(&self) -> &ModuleInfo {
self.0.info()
}
}
impl fmt::Debug for Module {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Module")
.field("name", &self.name())
.finish()
}
}