mirror of
https://github.com/mii443/wasmer.git
synced 2025-12-16 17:18:57 +00:00
Use standard API for js and sys for Module. Added Engine in js
This commit is contained in:
47
lib/api/src/engine.rs
Normal file
47
lib/api/src/engine.rs
Normal file
@@ -0,0 +1,47 @@
|
||||
#[cfg(feature = "sys")]
|
||||
use crate::sys as engine_imp;
|
||||
|
||||
#[cfg(feature = "js")]
|
||||
use crate::js as engine_imp;
|
||||
|
||||
/// The engine type
|
||||
pub type Engine = engine_imp::Engine;
|
||||
|
||||
impl AsEngineRef for Engine {
|
||||
fn as_engine_ref(&self) -> EngineRef {
|
||||
EngineRef { inner: self }
|
||||
}
|
||||
}
|
||||
|
||||
/// A temporary handle to an [`Engine`]
|
||||
/// EngineRef can be used to build a [`Module`][wasmer::Module]
|
||||
/// It can be created directly with an [`Engine`]
|
||||
/// Or from anything implementing [`AsEngineRef`]
|
||||
/// like from [`Store`][wasmer::Store] typicaly.
|
||||
pub struct EngineRef<'a> {
|
||||
/// The inner engine
|
||||
pub(crate) inner: &'a Engine,
|
||||
}
|
||||
|
||||
impl<'a> EngineRef<'a> {
|
||||
/// Get inner [`Engine`]
|
||||
pub fn engine(&self) -> &Engine {
|
||||
self.inner
|
||||
}
|
||||
/// Create an EngineRef from an Engine
|
||||
pub fn new(engine: &'a Engine) -> Self {
|
||||
EngineRef { inner: engine }
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper trait for a value that is convertible to a [`EngineRef`].
|
||||
pub trait AsEngineRef {
|
||||
/// Returns a `EngineRef` pointing to the underlying context.
|
||||
fn as_engine_ref(&self) -> EngineRef<'_>;
|
||||
}
|
||||
|
||||
impl AsEngineRef for EngineRef<'_> {
|
||||
fn as_engine_ref(&self) -> EngineRef<'_> {
|
||||
EngineRef { inner: self.inner }
|
||||
}
|
||||
}
|
||||
9
lib/api/src/js/engine.rs
Normal file
9
lib/api/src/js/engine.rs
Normal file
@@ -0,0 +1,9 @@
|
||||
/// A WebAssembly `Universal` Engine.
|
||||
#[derive(Clone)]
|
||||
pub struct Engine;
|
||||
|
||||
impl Default for Engine {
|
||||
fn default() -> Self {
|
||||
Engine
|
||||
}
|
||||
}
|
||||
@@ -6,60 +6,7 @@ use crate::js::trap::RuntimeError;
|
||||
use std::borrow::Cow;
|
||||
#[cfg(feature = "std")]
|
||||
use thiserror::Error;
|
||||
use wasmer_types::ImportError;
|
||||
|
||||
// Compilation Errors
|
||||
//
|
||||
// If `std` feature is enable, we can't use `thiserror` until
|
||||
// https://github.com/dtolnay/thiserror/pull/64 is merged.
|
||||
|
||||
/// The WebAssembly.CompileError object indicates an error during
|
||||
/// WebAssembly decoding or validation.
|
||||
///
|
||||
/// This is based on the [Wasm Compile Error][compile-error] API.
|
||||
///
|
||||
/// [compiler-error]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/CompileError
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "std", derive(Error))]
|
||||
pub enum CompileError {
|
||||
/// A Wasm translation error occured.
|
||||
#[cfg_attr(feature = "std", error("WebAssembly translation error: {0}"))]
|
||||
Wasm(WasmError),
|
||||
|
||||
/// A compilation error occured.
|
||||
#[cfg_attr(feature = "std", error("Compilation error: {0}"))]
|
||||
Codegen(String),
|
||||
|
||||
/// The module did not pass validation.
|
||||
#[cfg_attr(feature = "std", error("Validation error: {0}"))]
|
||||
Validate(String),
|
||||
|
||||
/// The compiler doesn't support a Wasm feature
|
||||
#[cfg_attr(feature = "std", error("Feature {0} is not yet supported"))]
|
||||
UnsupportedFeature(String),
|
||||
|
||||
/// The compiler cannot compile for the given target.
|
||||
/// This can refer to the OS, the chipset or any other aspect of the target system.
|
||||
#[cfg_attr(feature = "std", error("The target {0} is not yet supported (see https://docs.wasmer.io/ecosystem/wasmer/wasmer-features)"))]
|
||||
UnsupportedTarget(String),
|
||||
|
||||
/// Insufficient resources available for execution.
|
||||
#[cfg_attr(feature = "std", error("Insufficient resources: {0}"))]
|
||||
Resource(String),
|
||||
}
|
||||
|
||||
#[cfg(feature = "core")]
|
||||
impl std::fmt::Display for CompileError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "CompileError")
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WasmError> for CompileError {
|
||||
fn from(original: WasmError) -> Self {
|
||||
Self::Wasm(original)
|
||||
}
|
||||
}
|
||||
use wasmer_types::{CompileError, ImportError};
|
||||
|
||||
/// A WebAssembly translation error.
|
||||
///
|
||||
|
||||
@@ -2,9 +2,9 @@ use crate::js::error::InstantiationError;
|
||||
use crate::js::exports::Exports;
|
||||
use crate::js::externals::Extern;
|
||||
use crate::js::imports::Imports;
|
||||
use crate::js::module::Module;
|
||||
use crate::js::store::{AsStoreMut, AsStoreRef};
|
||||
use crate::js::vm::{VMExtern, VMInstance};
|
||||
use crate::module::Module;
|
||||
use js_sys::WebAssembly;
|
||||
use std::fmt;
|
||||
|
||||
@@ -64,6 +64,7 @@ impl Instance {
|
||||
imports: &Imports,
|
||||
) -> Result<Self, InstantiationError> {
|
||||
let instance = module
|
||||
.0
|
||||
.instantiate(&mut store, imports)
|
||||
.map_err(|e| InstantiationError::Start(e))?;
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ mod lib {
|
||||
}
|
||||
}
|
||||
|
||||
mod engine;
|
||||
pub(crate) mod error;
|
||||
mod exports;
|
||||
mod externals;
|
||||
@@ -30,7 +31,7 @@ mod function_env;
|
||||
mod imports;
|
||||
mod instance;
|
||||
mod mem_access;
|
||||
mod module;
|
||||
pub(crate) mod module;
|
||||
#[cfg(feature = "wasm-types-polyfill")]
|
||||
mod module_info_polyfill;
|
||||
mod native;
|
||||
@@ -43,6 +44,7 @@ mod value;
|
||||
mod vm;
|
||||
mod wasm_bindgen_polyfill;
|
||||
|
||||
pub use crate::js::engine::Engine;
|
||||
pub use crate::js::error::{DeserializeError, InstantiationError, SerializeError};
|
||||
pub use crate::js::exports::{ExportError, Exportable, Exports, ExportsIterator};
|
||||
pub use crate::js::externals::{
|
||||
@@ -53,7 +55,7 @@ pub use crate::js::function_env::{FunctionEnv, FunctionEnvMut};
|
||||
pub use crate::js::imports::Imports;
|
||||
pub use crate::js::instance::Instance;
|
||||
pub use crate::js::mem_access::{MemoryAccessError, WasmRef, WasmSlice, WasmSliceIter};
|
||||
pub use crate::js::module::{IoCompileError, Module, ModuleTypeHints};
|
||||
pub use crate::js::module::{Module, ModuleTypeHints};
|
||||
pub use crate::js::native::TypedFunction;
|
||||
pub use crate::js::native_type::NativeWasmTypeInto;
|
||||
pub use crate::js::ptr::{Memory32, Memory64, MemorySize, WasmPtr, WasmPtr64};
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
use crate::js::error::InstantiationError;
|
||||
#[cfg(feature = "wat")]
|
||||
use crate::js::error::WasmError;
|
||||
use crate::js::error::{CompileError, InstantiationError};
|
||||
#[cfg(feature = "js-serializable-module")]
|
||||
use crate::js::error::{DeserializeError, SerializeError};
|
||||
use crate::js::externals::Extern;
|
||||
use crate::js::imports::Imports;
|
||||
use crate::js::store::AsStoreMut;
|
||||
use crate::js::types::{AsJs, ExportType, ImportType};
|
||||
use crate::js::vm::VMInstance;
|
||||
use crate::js::RuntimeError;
|
||||
use crate::AsStoreRef;
|
||||
use crate::module::IoCompileError;
|
||||
use crate::AsEngineRef;
|
||||
use crate::IntoBytes;
|
||||
#[cfg(feature = "js-serializable-module")]
|
||||
use bytes::Bytes;
|
||||
use js_sys::{Reflect, Uint8Array, WebAssembly};
|
||||
use std::fmt;
|
||||
@@ -23,22 +21,10 @@ use thiserror::Error;
|
||||
use tracing::{debug, warn};
|
||||
use wasm_bindgen::JsValue;
|
||||
use wasmer_types::{
|
||||
ExportsIterator, ExternType, FunctionType, GlobalType, ImportsIterator, MemoryType, Mutability,
|
||||
Pages, TableType, Type,
|
||||
CompileError, DeserializeError, ExportsIterator, ExternType, FunctionType, GlobalType,
|
||||
ImportsIterator, MemoryType, ModuleInfo, Mutability, Pages, SerializeError, TableType, Type,
|
||||
};
|
||||
|
||||
/// IO Error on a Module Compilation
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "std", derive(Error))]
|
||||
pub enum IoCompileError {
|
||||
/// An IO error
|
||||
#[cfg_attr(feature = "std", error(transparent))]
|
||||
Io(io::Error),
|
||||
/// A compilation error
|
||||
#[cfg_attr(feature = "std", error(transparent))]
|
||||
Compile(CompileError),
|
||||
}
|
||||
|
||||
/// WebAssembly in the browser doesn't yet output the descriptor/types
|
||||
/// corresponding to each extern (import and export).
|
||||
///
|
||||
@@ -75,119 +61,34 @@ pub struct 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(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[allow(unreachable_code)]
|
||||
pub fn new(_store: &impl AsStoreRef, bytes: impl AsRef<[u8]>) -> Result<Self, CompileError> {
|
||||
let bytes = bytes.as_ref();
|
||||
#[cfg(feature = "wat")]
|
||||
if bytes.starts_with(b"\0asm") == false {
|
||||
let parsed_bytes = wat::parse_bytes(bytes.as_ref()).map_err(|e| {
|
||||
CompileError::Wasm(WasmError::Generic(format!(
|
||||
"Error when converting wat: {}",
|
||||
e
|
||||
)))
|
||||
})?;
|
||||
return Self::from_binary(_store, parsed_bytes.as_ref());
|
||||
}
|
||||
Self::from_binary(_store, bytes)
|
||||
}
|
||||
|
||||
/// Creates a new WebAssembly module from a file path.
|
||||
pub fn from_file(
|
||||
_store: &impl AsStoreRef,
|
||||
_engine: &impl AsEngineRef,
|
||||
_file: impl AsRef<Path>,
|
||||
) -> Result<Self, IoCompileError> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
/// Creates a new WebAssembly module from a 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(_store: &impl AsStoreRef, binary: &[u8]) -> Result<Self, CompileError> {
|
||||
// Self::validate(store, binary)?;
|
||||
unsafe { Self::from_binary_unchecked(_store, binary) }
|
||||
pub(crate) fn from_binary(
|
||||
_engine: &impl AsEngineRef,
|
||||
binary: &[u8],
|
||||
) -> Result<Self, CompileError> {
|
||||
unsafe { Self::from_binary_unchecked(_engine, binary) }
|
||||
}
|
||||
|
||||
/// Creates a new WebAssembly module skipping any kind of validation.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This is safe since the JS vm should be safe already.
|
||||
/// We maintain the `unsafe` to preserve the same API as Wasmer
|
||||
pub unsafe fn from_binary_unchecked(
|
||||
store: &impl AsStoreRef,
|
||||
pub(crate) unsafe fn from_binary_unchecked(
|
||||
engine: &impl AsEngineRef,
|
||||
binary: &[u8],
|
||||
) -> Result<Self, CompileError> {
|
||||
let js_bytes = Uint8Array::view(binary);
|
||||
let module = WebAssembly::Module::new(&js_bytes.into()).unwrap();
|
||||
|
||||
Self::from_js_module(store, module, binary)
|
||||
Self::from_js_module(engine, module, binary)
|
||||
}
|
||||
|
||||
/// Creates a new WebAssembly module skipping any kind of validation from a javascript module
|
||||
///
|
||||
pub unsafe fn from_js_module(
|
||||
_store: &impl AsStoreRef,
|
||||
pub(crate) unsafe fn from_js_module(
|
||||
_engine: &impl AsEngineRef,
|
||||
module: WebAssembly::Module,
|
||||
binary: impl IntoBytes,
|
||||
) -> Result<Self, CompileError> {
|
||||
@@ -225,13 +126,7 @@ impl Module {
|
||||
})
|
||||
}
|
||||
|
||||
/// 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(_store: &impl AsStoreRef, binary: &[u8]) -> Result<(), CompileError> {
|
||||
pub fn validate(_engine: &impl AsEngineRef, binary: &[u8]) -> Result<(), CompileError> {
|
||||
let js_bytes = unsafe { Uint8Array::view(binary) };
|
||||
// Annotation is here to prevent spurious IDE warnings.
|
||||
#[allow(unused_unsafe)]
|
||||
@@ -328,98 +223,42 @@ impl Module {
|
||||
.map_err(|e: JsValue| -> RuntimeError { e.into() })?)
|
||||
}
|
||||
|
||||
/// 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.name.as_ref().map(|s| s.as_ref())
|
||||
// self.artifact.module_ref().name.as_deref()
|
||||
}
|
||||
|
||||
/// Serializes a module into a binary representation that the `Engine`
|
||||
/// can later process via [`Module::deserialize`].
|
||||
///
|
||||
#[cfg(feature = "js-serializable-module")]
|
||||
pub fn serialize(&self) -> Result<Bytes, SerializeError> {
|
||||
self.raw_bytes.clone().ok_or(SerializeError::Generic(
|
||||
#[cfg(feature = "js-serializable-module")]
|
||||
return self.raw_bytes.clone().ok_or(SerializeError::Generic(
|
||||
"Not able to serialize module".to_string(),
|
||||
))
|
||||
));
|
||||
|
||||
#[cfg(not(feature = "js-serializable-module"))]
|
||||
return Err(SerializeError::Generic(
|
||||
"You need to enable the `js-serializable-module` feature flag to serialize a `Module`"
|
||||
.to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
/// Deserializes a serialized Module binary into a `Module`.
|
||||
///
|
||||
/// This is safe since deserialization under `js` is essentially same as reconstructing `Module`.
|
||||
/// We maintain the `unsafe` to preserve the same API as Wasmer
|
||||
#[cfg(feature = "js-serializable-module")]
|
||||
pub unsafe fn deserialize(
|
||||
_store: &impl AsStoreRef,
|
||||
_engine: &impl AsEngineRef,
|
||||
bytes: impl IntoBytes,
|
||||
) -> Result<Self, DeserializeError> {
|
||||
let bytes = bytes.into_bytes();
|
||||
Self::new(_store, bytes).map_err(|e| DeserializeError::Compiler(e))
|
||||
#[cfg(feature = "js-serializable-module")]
|
||||
return Self::new(_engine, bytes.into_bytes()).map_err(|e| DeserializeError::Compiler(e));
|
||||
|
||||
#[cfg(not(feature = "js-serializable-module"))]
|
||||
return Err(DeserializeError::Generic("You need to enable the `js-serializable-module` feature flag to deserialize a `Module`".to_string()));
|
||||
}
|
||||
|
||||
#[cfg(feature = "compiler")]
|
||||
/// 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(
|
||||
store: &impl AsStoreRef,
|
||||
engine: &impl AsEngineRef,
|
||||
path: impl AsRef<Path>,
|
||||
) -> Result<Self, DeserializeError> {
|
||||
let artifact = std::fs::read(path.as_ref())?;
|
||||
Ok(Self::new(store, bytes).map_err(|e| DeserializeError::Compiler(e)))
|
||||
let bytes = std::fs::read(path.as_ref())?;
|
||||
Self::deserialize(engine, bytes)
|
||||
}
|
||||
|
||||
/// 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 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.name = Some(name.to_string());
|
||||
true
|
||||
@@ -436,30 +275,6 @@ impl Module {
|
||||
// .unwrap_or(false)
|
||||
}
|
||||
|
||||
/// 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<'a>(&'a self) -> ImportsIterator<impl Iterator<Item = ImportType> + 'a> {
|
||||
let imports = WebAssembly::Module::imports(&self.module);
|
||||
let iter = imports
|
||||
@@ -553,29 +368,6 @@ impl Module {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 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<'a>(&'a self) -> ExportsIterator<impl Iterator<Item = ExportType> + 'a> {
|
||||
let exports = WebAssembly::Module::exports(&self.module);
|
||||
let iter = exports
|
||||
@@ -633,13 +425,6 @@ impl Module {
|
||||
ExportsIterator::new(iter, exports.length() as usize)
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
WebAssembly::Module::custom_sections(&self.module, name)
|
||||
.iter()
|
||||
@@ -650,13 +435,9 @@ impl Module {
|
||||
.collect::<Vec<Box<[u8]>>>()
|
||||
.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Module {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("Module")
|
||||
.field("name", &self.name())
|
||||
.finish()
|
||||
pub(crate) fn info(&self) -> &ModuleInfo {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use crate::engine::{AsEngineRef, EngineRef};
|
||||
use crate::js::engine::Engine;
|
||||
use std::fmt;
|
||||
use wasmer_types::OnCalledAction;
|
||||
|
||||
@@ -14,6 +16,7 @@ pub type OnCalledHandler = Box<
|
||||
/// wrap the actual context in a box.
|
||||
pub(crate) struct StoreInner {
|
||||
pub(crate) objects: StoreObjects,
|
||||
pub(crate) engine: Engine,
|
||||
pub(crate) on_called: Option<OnCalledHandler>,
|
||||
}
|
||||
|
||||
@@ -37,6 +40,7 @@ impl Store {
|
||||
Self {
|
||||
inner: Box::new(StoreInner {
|
||||
objects: Default::default(),
|
||||
engine: Default::default(),
|
||||
on_called: None,
|
||||
}),
|
||||
}
|
||||
@@ -199,6 +203,30 @@ impl<T: AsStoreMut> AsStoreMut for &'_ mut T {
|
||||
}
|
||||
}
|
||||
|
||||
impl AsEngineRef for Store {
|
||||
fn as_engine_ref(&self) -> EngineRef<'_> {
|
||||
EngineRef::new(&self.inner.engine)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsEngineRef for &Store {
|
||||
fn as_engine_ref(&self) -> EngineRef<'_> {
|
||||
EngineRef::new(&self.inner.engine)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsEngineRef for StoreRef<'_> {
|
||||
fn as_engine_ref(&self) -> EngineRef<'_> {
|
||||
EngineRef::new(&self.inner.engine)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsEngineRef for StoreMut<'_> {
|
||||
fn as_engine_ref(&self) -> EngineRef<'_> {
|
||||
EngineRef::new(&self.inner.engine)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) use objects::{InternalStoreHandle, StoreObject};
|
||||
pub use objects::{StoreHandle, StoreId, StoreObjects};
|
||||
|
||||
|
||||
@@ -429,6 +429,9 @@ compile_error!(
|
||||
"The `js` feature must be enabled only for the `wasm32` target (either `wasm32-unknown-unknown` or `wasm32-wasi`)."
|
||||
);
|
||||
|
||||
mod engine;
|
||||
mod module;
|
||||
|
||||
#[cfg(feature = "sys")]
|
||||
mod sys;
|
||||
|
||||
@@ -441,5 +444,8 @@ mod js;
|
||||
#[cfg(feature = "js")]
|
||||
pub use js::*;
|
||||
|
||||
pub use engine::{AsEngineRef, Engine};
|
||||
pub use module::{IoCompileError, Module};
|
||||
|
||||
mod into_bytes;
|
||||
pub use into_bytes::IntoBytes;
|
||||
|
||||
400
lib/api/src/module.rs
Normal file
400
lib/api/src/module.rs
Normal file
@@ -0,0 +1,400 @@
|
||||
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(Module(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(Module(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(Module(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(Module(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 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()
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::module::Module;
|
||||
use crate::sys::exports::Exports;
|
||||
use crate::sys::module::Module;
|
||||
use crate::sys::{LinkError, RuntimeError};
|
||||
use std::fmt;
|
||||
use thiserror::Error;
|
||||
@@ -119,7 +119,7 @@ impl Instance {
|
||||
let externs = imports
|
||||
.imports_for_module(module)
|
||||
.map_err(InstantiationError::Link)?;
|
||||
let mut handle = module.instantiate(store, &externs)?;
|
||||
let mut handle = module.0.instantiate(store, &externs)?;
|
||||
let mut exports = module
|
||||
.exports()
|
||||
.map(|export| {
|
||||
@@ -164,7 +164,7 @@ impl Instance {
|
||||
externs: &[Extern],
|
||||
) -> Result<Self, InstantiationError> {
|
||||
let externs = externs.to_vec();
|
||||
let mut handle = module.instantiate(store, &externs)?;
|
||||
let mut handle = module.0.instantiate(store, &externs)?;
|
||||
let mut exports = module
|
||||
.exports()
|
||||
.map(|export| {
|
||||
|
||||
@@ -5,7 +5,7 @@ mod function_env;
|
||||
mod imports;
|
||||
mod instance;
|
||||
mod mem_access;
|
||||
mod module;
|
||||
pub(crate) mod module;
|
||||
mod native;
|
||||
mod native_type;
|
||||
mod ptr;
|
||||
@@ -23,7 +23,7 @@ pub use crate::sys::function_env::{FunctionEnv, FunctionEnvMut};
|
||||
pub use crate::sys::imports::Imports;
|
||||
pub use crate::sys::instance::{Instance, InstantiationError};
|
||||
pub use crate::sys::mem_access::{MemoryAccessError, WasmRef, WasmSlice, WasmSliceIter};
|
||||
pub use crate::sys::module::{IoCompileError, Module};
|
||||
pub use crate::sys::module::Module;
|
||||
pub use crate::sys::native::TypedFunction;
|
||||
pub use crate::sys::native_type::NativeWasmTypeInto;
|
||||
pub use crate::sys::store::{AsStoreMut, AsStoreRef, StoreMut, StoreRef};
|
||||
@@ -75,9 +75,9 @@ pub use wasmer_compiler_cranelift::{Cranelift, CraneliftOptLevel};
|
||||
#[cfg(feature = "llvm")]
|
||||
pub use wasmer_compiler_llvm::{LLVMOptLevel, LLVM};
|
||||
|
||||
pub use wasmer_compiler::Engine;
|
||||
#[cfg(feature = "compiler")]
|
||||
pub use wasmer_compiler::{Artifact, EngineBuilder};
|
||||
pub use wasmer_compiler::{AsEngineRef, Engine, EngineRef};
|
||||
|
||||
/// Version number of this crate.
|
||||
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
use crate::engine::AsEngineRef;
|
||||
use bytes::Bytes;
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use thiserror::Error;
|
||||
use wasmer_compiler::Artifact;
|
||||
use wasmer_compiler::ArtifactCreate;
|
||||
use wasmer_compiler::AsEngineRef;
|
||||
#[cfg(feature = "wat")]
|
||||
use wasmer_types::WasmError;
|
||||
use wasmer_types::{
|
||||
CompileError, DeserializeError, ExportsIterator, ImportsIterator, ModuleInfo, SerializeError,
|
||||
};
|
||||
@@ -19,17 +14,6 @@ use crate::{sys::InstantiationError, AsStoreMut, AsStoreRef, IntoBytes};
|
||||
#[cfg(feature = "compiler")]
|
||||
use wasmer_vm::VMInstance;
|
||||
|
||||
/// 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.
|
||||
@@ -59,125 +43,15 @@ pub struct Module {
|
||||
}
|
||||
|
||||
impl Module {
|
||||
#[cfg(feature = "compiler")]
|
||||
/// 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");
|
||||
/// ```
|
||||
#[allow(unreachable_code)]
|
||||
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())
|
||||
}
|
||||
|
||||
#[cfg(feature = "compiler")]
|
||||
/// Creates a new WebAssembly module from a file path.
|
||||
pub fn from_file(
|
||||
pub(crate) fn from_binary(
|
||||
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)
|
||||
}
|
||||
|
||||
#[cfg(feature = "compiler")]
|
||||
/// Creates a new WebAssembly module from a 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> {
|
||||
binary: &[u8],
|
||||
) -> Result<Self, CompileError> {
|
||||
Self::validate(engine, binary)?;
|
||||
unsafe { Self::from_binary_unchecked(engine, binary) }
|
||||
}
|
||||
|
||||
#[cfg(feature = "compiler")]
|
||||
/// 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(
|
||||
pub(crate) unsafe fn from_binary_unchecked(
|
||||
engine: &impl AsEngineRef,
|
||||
binary: &[u8],
|
||||
) -> Result<Self, CompileError> {
|
||||
@@ -185,14 +59,7 @@ impl Module {
|
||||
Ok(module)
|
||||
}
|
||||
|
||||
#[cfg(feature = "compiler")]
|
||||
/// 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> {
|
||||
pub(crate) fn validate(engine: &impl AsEngineRef, binary: &[u8]) -> Result<(), CompileError> {
|
||||
engine.as_engine_ref().engine().validate(binary)
|
||||
}
|
||||
|
||||
@@ -202,70 +69,17 @@ impl Module {
|
||||
Ok(Self::from_artifact(artifact))
|
||||
}
|
||||
|
||||
/// Serializes a module into a binary representation that the `Engine`
|
||||
/// can later process via
|
||||
#[cfg_attr(feature = "compiler", doc = "[`Module::deserialize`].")]
|
||||
#[cfg_attr(not(feature = "compiler"), doc = "`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> {
|
||||
#[cfg(not(feature = "compiler"))]
|
||||
fn compile(engine: &impl AsEngineRef, binary: &[u8]) -> Result<Self, CompileError> {
|
||||
Err(CompileError::UnsupportedTarget(
|
||||
"The compiler feature is not enabled, but is required to compile a Module",
|
||||
))
|
||||
}
|
||||
|
||||
pub(crate) fn serialize(&self) -> Result<Bytes, SerializeError> {
|
||||
self.artifact.serialize().map(|bytes| bytes.into())
|
||||
}
|
||||
|
||||
/// Serializes a module into a file that the `Engine`
|
||||
/// can later process via
|
||||
#[cfg_attr(feature = "compiler", doc = "[`Module::deserialize_from_file`].")]
|
||||
#[cfg_attr(not(feature = "compiler"), doc = "`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> {
|
||||
self.artifact.serialize_to_file(path.as_ref())
|
||||
}
|
||||
|
||||
#[cfg(feature = "compiler")]
|
||||
/// 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,
|
||||
@@ -275,24 +89,6 @@ impl Module {
|
||||
Ok(Self::from_artifact(artifact))
|
||||
}
|
||||
|
||||
#[cfg(feature = "compiler")]
|
||||
/// 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>,
|
||||
@@ -311,7 +107,6 @@ impl Module {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "compiler")]
|
||||
pub(crate) fn instantiate(
|
||||
&self,
|
||||
store: &mut impl AsStoreMut,
|
||||
@@ -349,136 +144,33 @@ impl Module {
|
||||
}
|
||||
}
|
||||
|
||||
/// 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> {
|
||||
pub(crate) fn name(&self) -> Option<&str> {
|
||||
self.module_info.name.as_deref()
|
||||
}
|
||||
|
||||
/// 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 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 {
|
||||
pub(crate) fn set_name(&mut self, name: &str) -> bool {
|
||||
Arc::get_mut(&mut self.module_info).map_or(false, |mut module_info| {
|
||||
module_info.name = Some(name.to_string());
|
||||
true
|
||||
})
|
||||
}
|
||||
|
||||
/// 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> + '_> {
|
||||
pub(crate) fn imports(&self) -> ImportsIterator<impl Iterator<Item = ImportType> + '_> {
|
||||
self.module_info.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> + '_> {
|
||||
pub(crate) fn exports(&self) -> ExportsIterator<impl Iterator<Item = ExportType> + '_> {
|
||||
self.module_info.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 {
|
||||
pub(crate) fn custom_sections<'a>(
|
||||
&'a self,
|
||||
name: &'a str,
|
||||
) -> impl Iterator<Item = Box<[u8]>> + 'a {
|
||||
self.module_info.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 {
|
||||
pub(crate) fn info(&self) -> &ModuleInfo {
|
||||
&self.module_info
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Module {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("Module")
|
||||
.field("name", &self.name())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
use crate::engine::{AsEngineRef, EngineRef};
|
||||
use crate::sys::tunables::BaseTunables;
|
||||
use derivative::Derivative;
|
||||
use std::fmt;
|
||||
#[cfg(feature = "compiler")]
|
||||
use wasmer_compiler::{AsEngineRef, Engine, EngineBuilder, EngineRef, Tunables};
|
||||
use wasmer_compiler::{Engine, EngineBuilder, Tunables};
|
||||
use wasmer_types::OnCalledAction;
|
||||
use wasmer_vm::{init_traps, StoreId, TrapHandler, TrapHandlerFn};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user