From d09a76ec5f00f6036310bab73a4c72973ddb9759 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Fri, 27 Jan 2023 17:10:54 +0100 Subject: [PATCH 01/81] Use standard API for js and sys for Module. Added Engine in js --- .../engine/engineref.rs => api/src/engine.rs} | 24 +- lib/api/src/js/engine.rs | 9 + lib/api/src/js/error.rs | 55 +-- lib/api/src/js/instance.rs | 3 +- lib/api/src/js/mod.rs | 6 +- lib/api/src/js/module.rs | 293 ++----------- lib/api/src/js/store.rs | 28 ++ lib/api/src/lib.rs | 6 + lib/api/src/module.rs | 400 ++++++++++++++++++ lib/api/src/sys/instance.rs | 6 +- lib/api/src/sys/mod.rs | 6 +- lib/api/src/sys/module.rs | 352 +-------------- lib/api/src/sys/store.rs | 3 +- lib/compiler/src/engine/inner.rs | 9 - lib/compiler/src/engine/mod.rs | 6 - lib/compiler/src/traits.rs | 9 - lib/types/src/serialize.rs | 10 +- 17 files changed, 534 insertions(+), 691 deletions(-) rename lib/{compiler/src/engine/engineref.rs => api/src/engine.rs} (69%) create mode 100644 lib/api/src/js/engine.rs create mode 100644 lib/api/src/module.rs diff --git a/lib/compiler/src/engine/engineref.rs b/lib/api/src/engine.rs similarity index 69% rename from lib/compiler/src/engine/engineref.rs rename to lib/api/src/engine.rs index 107cd9b1153..ec3e394a3b0 100644 --- a/lib/compiler/src/engine/engineref.rs +++ b/lib/api/src/engine.rs @@ -1,11 +1,23 @@ -use super::Engine; -use crate::Tunables; +#[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 +/// like from [`Store`][wasmer::Store] typicaly. pub struct EngineRef<'a> { /// The inner engine pub(crate) inner: &'a Engine, @@ -16,11 +28,7 @@ impl<'a> EngineRef<'a> { pub fn engine(&self) -> &Engine { self.inner } - /// Get the [`Tunables`] - pub fn tunables(&self) -> &dyn Tunables { - self.inner.tunables() - } - /// Create an EngineRef from an Engine and Tunables + /// Create an EngineRef from an Engine pub fn new(engine: &'a Engine) -> Self { EngineRef { inner: engine } } diff --git a/lib/api/src/js/engine.rs b/lib/api/src/js/engine.rs new file mode 100644 index 00000000000..4237a6fc33b --- /dev/null +++ b/lib/api/src/js/engine.rs @@ -0,0 +1,9 @@ +/// A WebAssembly `Universal` Engine. +#[derive(Clone)] +pub struct Engine; + +impl Default for Engine { + fn default() -> Self { + Engine + } +} diff --git a/lib/api/src/js/error.rs b/lib/api/src/js/error.rs index ffc9eeff8b3..74d62bd64db 100644 --- a/lib/api/src/js/error.rs +++ b/lib/api/src/js/error.rs @@ -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 for CompileError { - fn from(original: WasmError) -> Self { - Self::Wasm(original) - } -} +use wasmer_types::{CompileError, ImportError}; /// A WebAssembly translation error. /// diff --git a/lib/api/src/js/instance.rs b/lib/api/src/js/instance.rs index 04bcf49091c..393b12023f6 100644 --- a/lib/api/src/js/instance.rs +++ b/lib/api/src/js/instance.rs @@ -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 { let instance = module + .0 .instantiate(&mut store, imports) .map_err(|e| InstantiationError::Start(e))?; diff --git a/lib/api/src/js/mod.rs b/lib/api/src/js/mod.rs index 9d62313be65..e66af0acdfd 100644 --- a/lib/api/src/js/mod.rs +++ b/lib/api/src/js/mod.rs @@ -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}; diff --git a/lib/api/src/js/module.rs b/lib/api/src/js/module.rs index 4c75811fe66..f3498fa82ad 100644 --- a/lib/api/src/js/module.rs +++ b/lib/api/src/js/module.rs @@ -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 = 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 { - 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, ) -> Result { 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::validate(store, binary)?; - unsafe { Self::from_binary_unchecked(_store, binary) } + pub(crate) fn from_binary( + _engine: &impl AsEngineRef, + binary: &[u8], + ) -> Result { + 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 { 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 { @@ -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 { - 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 { - 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, ) -> Result { - 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 + '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 + '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> + 'a { WebAssembly::Module::custom_sections(&self.module, name) .iter() @@ -650,13 +435,9 @@ impl Module { .collect::>>() .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!() } } diff --git a/lib/api/src/js/store.rs b/lib/api/src/js/store.rs index 7fa22cfa855..7bc7e503459 100644 --- a/lib/api/src/js/store.rs +++ b/lib/api/src/js/store.rs @@ -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, } @@ -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 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}; diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index a7d5c730567..3684b0c9376 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -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; diff --git a/lib/api/src/module.rs b/lib/api/src/module.rs new file mode 100644 index 00000000000..66c9cf22a5a --- /dev/null +++ b/lib/api/src/module.rs @@ -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 = 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 { + #[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, + ) -> Result { + 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 { + 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 { + 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 { + 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) -> 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 { + 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, + ) -> Result { + 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 + '_> { + 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 + '_> { + 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> + '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() + } +} diff --git a/lib/api/src/sys/instance.rs b/lib/api/src/sys/instance.rs index a1572c681af..2f7da0adc8e 100644 --- a/lib/api/src/sys/instance.rs +++ b/lib/api/src/sys/instance.rs @@ -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 { 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| { diff --git a/lib/api/src/sys/mod.rs b/lib/api/src/sys/mod.rs index 3989ec10f36..9c3defa2201 100644 --- a/lib/api/src/sys/mod.rs +++ b/lib/api/src/sys/mod.rs @@ -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"); diff --git a/lib/api/src/sys/module.rs b/lib/api/src/sys/module.rs index e6405272dbe..16fa7ee23a0 100644 --- a/lib/api/src/sys/module.rs +++ b/lib/api/src/sys/module.rs @@ -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 = 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 { - #[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, - ) -> Result { - 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 { + binary: &[u8], + ) -> Result { 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 { @@ -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 { - self.artifact.serialize().map(|bytes| bytes.into()) + #[cfg(not(feature = "compiler"))] + fn compile(engine: &impl AsEngineRef, binary: &[u8]) -> Result { + Err(CompileError::UnsupportedTarget( + "The compiler feature is not enabled, but is required to compile a Module", + )) } - /// 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) -> Result<(), SerializeError> { - self.artifact.serialize_to_file(path.as_ref()) + pub(crate) fn serialize(&self) -> Result { + self.artifact.serialize().map(|bytes| bytes.into()) } - #[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, @@ -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 + '_> { + pub(crate) fn imports(&self) -> ImportsIterator + '_> { 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 + '_> { + pub(crate) fn exports(&self) -> ExportsIterator + '_> { 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> + 'a { + pub(crate) fn custom_sections<'a>( + &'a self, + name: &'a str, + ) -> impl Iterator> + '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() - } -} diff --git a/lib/api/src/sys/store.rs b/lib/api/src/sys/store.rs index 6f7cf6ac9fd..fc095652df1 100644 --- a/lib/api/src/sys/store.rs +++ b/lib/api/src/sys/store.rs @@ -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}; diff --git a/lib/compiler/src/engine/inner.rs b/lib/compiler/src/engine/inner.rs index 240ef19c87d..8b7e71d4fe9 100644 --- a/lib/compiler/src/engine/inner.rs +++ b/lib/compiler/src/engine/inner.rs @@ -7,8 +7,6 @@ use crate::Artifact; use crate::BaseTunables; #[cfg(not(target_arch = "wasm32"))] use crate::CodeMemory; -#[cfg(not(target_arch = "wasm32"))] -use crate::{AsEngineRef, EngineRef}; #[cfg(feature = "compiler")] use crate::{Compiler, CompilerConfig}; #[cfg(not(target_arch = "wasm32"))] @@ -235,13 +233,6 @@ impl Engine { } } -#[cfg(not(target_arch = "wasm32"))] -impl AsEngineRef for Engine { - fn as_engine_ref(&self) -> EngineRef { - EngineRef { inner: self } - } -} - impl std::fmt::Debug for Engine { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("Engine") diff --git a/lib/compiler/src/engine/mod.rs b/lib/compiler/src/engine/mod.rs index bf54a791311..75b4db3b2f9 100644 --- a/lib/compiler/src/engine/mod.rs +++ b/lib/compiler/src/engine/mod.rs @@ -1,8 +1,5 @@ //! The Wasmer Engine. -#[cfg(feature = "translator")] -#[cfg(not(target_arch = "wasm32"))] -mod engineref; mod error; #[cfg(not(target_arch = "wasm32"))] mod resolver; @@ -28,9 +25,6 @@ mod link; #[cfg(not(target_arch = "wasm32"))] mod unwind; -#[cfg(feature = "translator")] -#[cfg(not(target_arch = "wasm32"))] -pub use self::engineref::{AsEngineRef, EngineRef}; pub use self::error::{InstantiationError, LinkError}; #[cfg(not(target_arch = "wasm32"))] pub use self::resolver::resolve_imports; diff --git a/lib/compiler/src/traits.rs b/lib/compiler/src/traits.rs index d6ce67eda09..99b3c43e44a 100644 --- a/lib/compiler/src/traits.rs +++ b/lib/compiler/src/traits.rs @@ -3,8 +3,6 @@ use crate::Features; use enumset::EnumSet; use std::any::Any; -use std::fs; -use std::path::Path; use wasmer_types::entity::PrimaryMap; use wasmer_types::SerializeError; use wasmer_types::{ @@ -38,13 +36,6 @@ pub trait ArtifactCreate: Send + Sync + Upcastable { /// Serializes an artifact into bytes fn serialize(&self) -> Result, SerializeError>; - - /// Serializes an artifact into a file path - fn serialize_to_file(&self, path: &Path) -> Result<(), SerializeError> { - let serialized = self.serialize()?; - fs::write(path, serialized)?; - Ok(()) - } } // Implementation of `Upcastable` taken from https://users.rust-lang.org/t/why-does-downcasting-not-work-for-subtraits/33286/7 . diff --git a/lib/types/src/serialize.rs b/lib/types/src/serialize.rs index 4d1fe7f229a..4f04056134d 100644 --- a/lib/types/src/serialize.rs +++ b/lib/types/src/serialize.rs @@ -12,8 +12,7 @@ use rkyv::{ Serialize as RkyvSerialize, }; use std::convert::TryInto; -use std::path::Path; -use std::{fs, mem}; +use std::mem; /// The compilation related data for a serialized modules #[derive(Archive, Default, RkyvDeserialize, RkyvSerialize)] @@ -156,13 +155,6 @@ impl SerializableModule { pub fn table_styles(&self) -> &PrimaryMap { &self.compile_info.table_styles } - - /// Serializes an artifact into a file path - pub fn serialize_to_file(&self, path: &Path) -> Result<(), SerializeError> { - let serialized = self.serialize()?; - fs::write(path, serialized)?; - Ok(()) - } } /// Metadata header which holds an ABI version and the length of the remaining From 5a030f5f3104e6b6bc4a86878fe17b1a0c2a6096 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Sat, 28 Jan 2023 22:45:33 +0100 Subject: [PATCH 02/81] Fix compile --- lib/cli-compiler/src/commands/compile.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/cli-compiler/src/commands/compile.rs b/lib/cli-compiler/src/commands/compile.rs index bcffabff54f..5052a4bf810 100644 --- a/lib/cli-compiler/src/commands/compile.rs +++ b/lib/cli-compiler/src/commands/compile.rs @@ -2,6 +2,7 @@ use crate::store::StoreOptions; use crate::warning; use anyhow::{Context, Result}; use clap::Parser; +use std::fs; use std::path::{Path, PathBuf}; use wasmer_compiler::{ArtifactBuild, ArtifactCreate, ModuleEnvironment}; use wasmer_types::entity::PrimaryMap; @@ -105,7 +106,8 @@ impl Compile { memory_styles, table_styles, )?; - artifact.serialize_to_file(self.output.as_ref())?; + let serialized = artifact.serialize(self.output.as_ref())?; + fs::write(output_filename, serialized)?; eprintln!( "✔ File compiled successfully to `{}`.", self.output.display(), From 42fd09bcfbc70fe072a231ab1e1d53dccb80cde4 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Mon, 30 Jan 2023 20:18:22 +0100 Subject: [PATCH 03/81] Move tunables into engine --- lib/api/src/sys/externals/memory.rs | 2 +- lib/api/src/sys/externals/table.rs | 2 +- lib/api/src/sys/imports.rs | 2 +- lib/api/src/sys/module.rs | 4 ++-- lib/api/src/sys/store.rs | 16 ++++++++++++++-- lib/cli/src/commands/create_exe.rs | 2 +- lib/wasi/src/utils.rs | 2 +- 7 files changed, 21 insertions(+), 9 deletions(-) diff --git a/lib/api/src/sys/externals/memory.rs b/lib/api/src/sys/externals/memory.rs index fddcb2995ab..a82a031bfa6 100644 --- a/lib/api/src/sys/externals/memory.rs +++ b/lib/api/src/sys/externals/memory.rs @@ -51,7 +51,7 @@ impl Memory { /// ``` pub fn new(store: &mut impl AsStoreMut, ty: MemoryType) -> Result { let mut store = store.as_store_mut(); - let tunables = store.tunables(); + let tunables = store.engine().tunables(); let style = tunables.memory_style(&ty); let memory = tunables.create_host_memory(&ty, &style)?; diff --git a/lib/api/src/sys/externals/table.rs b/lib/api/src/sys/externals/table.rs index 52137330846..754d925b2ba 100644 --- a/lib/api/src/sys/externals/table.rs +++ b/lib/api/src/sys/externals/table.rs @@ -73,7 +73,7 @@ impl Table { ) -> Result { let item = value_to_table_element(&mut store, init)?; let mut store = store.as_store_mut(); - let tunables = store.tunables(); + let tunables = store.engine().tunables(); let style = tunables.table_style(&ty); let mut table = tunables .create_host_table(&ty, &style) diff --git a/lib/api/src/sys/imports.rs b/lib/api/src/sys/imports.rs index a08d1b6adad..6c0f0b3d6dd 100644 --- a/lib/api/src/sys/imports.rs +++ b/lib/api/src/sys/imports.rs @@ -138,7 +138,7 @@ impl Imports { .next() .map(|a| *a.ty()) .map(|ty| { - let style = store.as_store_ref().tunables().memory_style(&ty); + let style = store.as_store_ref().engine().tunables().memory_style(&ty); VMSharedMemory::new(&ty, &style).unwrap() }); diff --git a/lib/api/src/sys/module.rs b/lib/api/src/sys/module.rs index 16fa7ee23a0..ea4d5539908 100644 --- a/lib/api/src/sys/module.rs +++ b/lib/api/src/sys/module.rs @@ -119,10 +119,10 @@ impl Module { } } let mut store_mut = store.as_store_mut(); - let (tunables, objects) = store_mut.tunables_and_objects_mut(); + let (engine, objects) = store_mut.engine_and_objects_mut(); unsafe { let mut instance_handle = self.artifact.instantiate( - tunables, + engine.tunables(), &imports .iter() .map(crate::Extern::to_vm_extern) diff --git a/lib/api/src/sys/store.rs b/lib/api/src/sys/store.rs index fc095652df1..1f3a999dbbb 100644 --- a/lib/api/src/sys/store.rs +++ b/lib/api/src/sys/store.rs @@ -95,6 +95,10 @@ impl Store { } #[cfg(feature = "compiler")] + #[deprecated( + since = "3.2.0", + note = "store.tunables() has been deprecated in favor of store.engine().tunables()" + )] /// Returns the [`Tunables`]. pub fn tunables(&self) -> &dyn Tunables { self.engine.tunables() @@ -259,6 +263,10 @@ impl<'a> StoreRef<'a> { } #[cfg(feature = "compiler")] + #[deprecated( + since = "3.2.0", + note = "store.tunables() has been deprecated in favor of store.engine().tunables()" + )] /// Returns the [`Tunables`]. pub fn tunables(&self) -> &dyn Tunables { self.inner.engine.tunables() @@ -296,6 +304,10 @@ pub struct StoreMut<'a> { impl<'a> StoreMut<'a> { /// Returns the [`Tunables`]. #[cfg(feature = "compiler")] + #[deprecated( + since = "3.2.0", + note = "store.tunables() has been deprecated in favor of store.engine().tunables()" + )] pub fn tunables(&self) -> &dyn Tunables { self.inner.engine.tunables() } @@ -315,8 +327,8 @@ impl<'a> StoreMut<'a> { } #[cfg(feature = "compiler")] - pub(crate) fn tunables_and_objects_mut(&mut self) -> (&dyn Tunables, &mut StoreObjects) { - (self.inner.engine.tunables(), &mut self.inner.objects) + pub(crate) fn engine_and_objects_mut(&mut self) -> (&Engine, &mut StoreObjects) { + (&self.inner.engine, &mut self.inner.objects) } pub(crate) fn as_raw(&self) -> *mut StoreInner { diff --git a/lib/cli/src/commands/create_exe.rs b/lib/cli/src/commands/create_exe.rs index 29613cd4bcb..675e26b9391 100644 --- a/lib/cli/src/commands/create_exe.rs +++ b/lib/cli/src/commands/create_exe.rs @@ -754,7 +754,7 @@ fn compile_atoms( let engine_inner = engine.inner(); let compiler = engine_inner.compiler()?; let features = engine_inner.features(); - let tunables = store.tunables(); + let tunables = store.engine().tunables(); let (module_info, obj, _, _) = Artifact::generate_object( compiler, data, diff --git a/lib/wasi/src/utils.rs b/lib/wasi/src/utils.rs index ba0df86f276..c380b0ef4ed 100644 --- a/lib/wasi/src/utils.rs +++ b/lib/wasi/src/utils.rs @@ -65,7 +65,7 @@ pub fn wasi_import_shared_memory( .next() .map(|a| *a.ty()) .map(|ty| { - let style = store.as_store_ref().tunables().memory_style(&ty); + let style = store.as_store_ref().engine().tunables().memory_style(&ty); VMSharedMemory::new(&ty, &style).unwrap() }); From cd730e09c6ea855f8e76137d41f2e2cdcf2cdfe0 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Thu, 9 Feb 2023 18:19:58 +0100 Subject: [PATCH 04/81] Moved the gross of default store to default_engine --- examples/tunables_limit_memory.rs | 8 +++-- lib/api/src/js/engine.rs | 5 +++ lib/api/src/sys/engine.rs | 50 ++++++++++++++++++++++++++++ lib/api/src/sys/mod.rs | 3 +- lib/api/src/sys/store.rs | 54 ++++--------------------------- 5 files changed, 69 insertions(+), 51 deletions(-) create mode 100644 lib/api/src/sys/engine.rs diff --git a/examples/tunables_limit_memory.rs b/examples/tunables_limit_memory.rs index 104f1acc681..8099aa4b19d 100644 --- a/examples/tunables_limit_memory.rs +++ b/examples/tunables_limit_memory.rs @@ -3,8 +3,8 @@ use std::ptr::NonNull; use wasmer::{ imports, vm::{self, MemoryError, MemoryStyle, TableStyle, VMMemoryDefinition, VMTableDefinition}, - wat2wasm, BaseTunables, Instance, Memory, MemoryType, Module, Pages, Store, TableType, Target, - Tunables, + wat2wasm, BaseTunables, Engine, Instance, Memory, MemoryType, Module, Pages, Store, TableType, + Target, Tunables, }; use wasmer_compiler_cranelift::Cranelift; @@ -140,9 +140,11 @@ fn main() -> Result<(), Box> { // Here is where the fun begins let base = BaseTunables::for_target(&Target::default()); let tunables = LimitingTunables::new(base, Pages(24)); + let mut engine: Engine = compiler.into(); + engine.set_tunables(tunables); // Create a store, that holds the engine and our custom tunables - let mut store = Store::new_with_tunables(compiler, tunables); + let mut store = Store::new(engine); println!("Compiling module..."); let module = Module::new(&store, wasm_bytes)?; diff --git a/lib/api/src/js/engine.rs b/lib/api/src/js/engine.rs index 4237a6fc33b..327d183bc65 100644 --- a/lib/api/src/js/engine.rs +++ b/lib/api/src/js/engine.rs @@ -7,3 +7,8 @@ impl Default for Engine { Engine } } + +/// Returns the default engine for the JS engine +pub(crate) fn default_engine() -> Engine { + Engine::default() +} diff --git a/lib/api/src/sys/engine.rs b/lib/api/src/sys/engine.rs new file mode 100644 index 00000000000..97e58841463 --- /dev/null +++ b/lib/api/src/sys/engine.rs @@ -0,0 +1,50 @@ +pub use wasmer_compiler::BaseTunables; +pub use wasmer_compiler::{Artifact, Engine, EngineBuilder}; + +/// Returns the default engine for the Sys engine +pub(crate) fn default_engine() -> Engine { + // We store them on a function that returns to make + // sure this function doesn't emit a compile error even if + // more than one compiler is enabled. + #[allow(unreachable_code)] + #[cfg(any(feature = "cranelift", feature = "llvm", feature = "singlepass"))] + fn get_config() -> impl wasmer_compiler::CompilerConfig + 'static { + cfg_if::cfg_if! { + if #[cfg(feature = "cranelift")] { + wasmer_compiler_cranelift::Cranelift::default() + } else if #[cfg(feature = "llvm")] { + wasmer_compiler_llvm::LLVM::default() + } else if #[cfg(feature = "singlepass")] { + wasmer_compiler_singlepass::Singlepass::default() + } else { + compile_error!("No default compiler chosen") + } + } + } + + #[allow(unreachable_code, unused_mut)] + fn get_engine() -> Engine { + cfg_if::cfg_if! { + if #[cfg(feature = "compiler")] { + cfg_if::cfg_if! { + if #[cfg(any(feature = "cranelift", feature = "llvm", feature = "singlepass"))] + { + let config = get_config(); + EngineBuilder::new(Box::new(config) as Box) + .engine() + } else { + EngineBuilder::headless() + .engine() + } + } + } else { + compile_error!("No default engine chosen") + } + } + } + + let mut engine = get_engine(); + let tunables = BaseTunables::for_target(engine.target()); + engine.set_tunables(tunables); + engine +} diff --git a/lib/api/src/sys/mod.rs b/lib/api/src/sys/mod.rs index 9c3defa2201..b3b3cdcbea1 100644 --- a/lib/api/src/sys/mod.rs +++ b/lib/api/src/sys/mod.rs @@ -1,3 +1,4 @@ +mod engine; mod exports; mod extern_ref; mod externals; @@ -13,6 +14,7 @@ mod store; mod tunables; mod value; +pub use crate::sys::engine::Engine; pub use crate::sys::exports::{ExportError, Exportable, Exports, ExportsIterator}; pub use crate::sys::extern_ref::ExternRef; pub use crate::sys::externals::{ @@ -75,7 +77,6 @@ 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}; diff --git a/lib/api/src/sys/store.rs b/lib/api/src/sys/store.rs index 1f3a999dbbb..978fbd5cd82 100644 --- a/lib/api/src/sys/store.rs +++ b/lib/api/src/sys/store.rs @@ -1,9 +1,9 @@ use crate::engine::{AsEngineRef, EngineRef}; -use crate::sys::tunables::BaseTunables; +use crate::sys::engine::{default_engine, Engine}; use derivative::Derivative; use std::fmt; +use wasmer_compiler::Tunables; #[cfg(feature = "compiler")] -use wasmer_compiler::{Engine, EngineBuilder, Tunables}; use wasmer_types::OnCalledAction; use wasmer_vm::{init_traps, StoreId, TrapHandler, TrapHandlerFn}; @@ -83,6 +83,10 @@ impl Store { } #[cfg(feature = "compiler")] + #[deprecated( + since = "3.2.0", + note = "store.new_with_tunables() has been deprecated in favor of engine.set_tunables()" + )] /// Creates a new `Store` with a specific [`Engine`] and [`Tunables`]. pub fn new_with_tunables( engine: impl Into, @@ -152,53 +156,9 @@ unsafe impl TrapHandler for Store { unsafe impl Send for Store {} unsafe impl Sync for Store {} -// We only implement default if we have assigned a default compiler and engine -#[cfg(feature = "compiler")] impl Default for Store { fn default() -> Self { - // We store them on a function that returns to make - // sure this function doesn't emit a compile error even if - // more than one compiler is enabled. - #[allow(unreachable_code)] - #[cfg(any(feature = "cranelift", feature = "llvm", feature = "singlepass"))] - fn get_config() -> impl wasmer_compiler::CompilerConfig + 'static { - cfg_if::cfg_if! { - if #[cfg(feature = "cranelift")] { - wasmer_compiler_cranelift::Cranelift::default() - } else if #[cfg(feature = "llvm")] { - wasmer_compiler_llvm::LLVM::default() - } else if #[cfg(feature = "singlepass")] { - wasmer_compiler_singlepass::Singlepass::default() - } else { - compile_error!("No default compiler chosen") - } - } - } - - #[allow(unreachable_code, unused_mut)] - fn get_engine() -> Engine { - cfg_if::cfg_if! { - if #[cfg(feature = "compiler")] { - cfg_if::cfg_if! { - if #[cfg(any(feature = "cranelift", feature = "llvm", feature = "singlepass"))] - { - let config = get_config(); - EngineBuilder::new(Box::new(config) as Box) - .engine() - } else { - EngineBuilder::headless() - .engine() - } - } - } else { - compile_error!("No default engine chosen") - } - } - } - - let engine = get_engine(); - let tunables = BaseTunables::for_target(engine.target()); - Self::new_with_tunables(&engine, tunables) + Self::new(default_engine()) } } From 8c456334cbe70d942442c3055313c13e55b06c85 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Thu, 9 Feb 2023 18:58:43 +0100 Subject: [PATCH 05/81] Remove deprecated/unused TrapHandler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Note: wasmer_vm::TrapHandler was never exposed via the `wasmer` crate, so it’s safe to remove --- lib/api/src/sys/store.rs | 12 +----------- lib/vm/src/trap/mod.rs | 2 +- lib/vm/src/trap/traphandlers.rs | 15 --------------- 3 files changed, 2 insertions(+), 27 deletions(-) diff --git a/lib/api/src/sys/store.rs b/lib/api/src/sys/store.rs index 978fbd5cd82..6b2da8eb2e6 100644 --- a/lib/api/src/sys/store.rs +++ b/lib/api/src/sys/store.rs @@ -5,7 +5,7 @@ use std::fmt; use wasmer_compiler::Tunables; #[cfg(feature = "compiler")] use wasmer_types::OnCalledAction; -use wasmer_vm::{init_traps, StoreId, TrapHandler, TrapHandlerFn}; +use wasmer_vm::{init_traps, StoreId, TrapHandlerFn}; use wasmer_vm::StoreObjects; @@ -135,16 +135,6 @@ impl PartialEq for Store { } } -unsafe impl TrapHandler for Store { - fn custom_trap_handler(&self, call: &dyn Fn(&TrapHandlerFn) -> bool) -> bool { - if let Some(handler) = self.inner.trap_handler.as_ref() { - call(handler.as_ref()) - } else { - false - } - } -} - // impl PartialEq for Store { // fn eq(&self, other: &Self) -> bool { // Self::same(self, other) diff --git a/lib/vm/src/trap/mod.rs b/lib/vm/src/trap/mod.rs index afa81642a45..6a467c2d438 100644 --- a/lib/vm/src/trap/mod.rs +++ b/lib/vm/src/trap/mod.rs @@ -11,7 +11,7 @@ mod traphandlers; pub use trap::Trap; pub use traphandlers::{ catch_traps, on_host_stack, raise_lib_trap, raise_user_trap, wasmer_call_trampoline, - TrapHandler, TrapHandlerFn, + TrapHandlerFn, }; pub use traphandlers::{init_traps, resume_panic}; pub use wasmer_types::TrapCode; diff --git a/lib/vm/src/trap/traphandlers.rs b/lib/vm/src/trap/traphandlers.rs index 117833bd859..89b9a141da5 100644 --- a/lib/vm/src/trap/traphandlers.rs +++ b/lib/vm/src/trap/traphandlers.rs @@ -86,21 +86,6 @@ unsafe fn process_illegal_op(addr: usize) -> Option { } } -/// A package of functionality needed by `catch_traps` to figure out what to do -/// when handling a trap. -/// -/// # Safety -/// -/// Note that this is an `unsafe` trait at least because it's being run in the -/// context of a synchronous signal handler, so it needs to be careful to not -/// access too much state in answering these queries. -pub unsafe trait TrapHandler { - /// Uses `call` to call a custom signal handler, if one is specified. - /// - /// Returns `true` if `call` returns true, otherwise returns `false`. - fn custom_trap_handler(&self, call: &dyn Fn(&TrapHandlerFn) -> bool) -> bool; -} - cfg_if::cfg_if! { if #[cfg(unix)] { static mut PREV_SIGSEGV: MaybeUninit = MaybeUninit::uninit(); From 83313eb098bb16c16c59be60f75c5dfe5c0ef0c6 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Thu, 9 Feb 2023 19:08:38 +0100 Subject: [PATCH 06/81] Improved sys store --- lib/api/src/sys/store.rs | 52 ++++++++++------------------------------ 1 file changed, 12 insertions(+), 40 deletions(-) diff --git a/lib/api/src/sys/store.rs b/lib/api/src/sys/store.rs index 6b2da8eb2e6..4b55e6f60eb 100644 --- a/lib/api/src/sys/store.rs +++ b/lib/api/src/sys/store.rs @@ -3,7 +3,6 @@ use crate::sys::engine::{default_engine, Engine}; use derivative::Derivative; use std::fmt; use wasmer_compiler::Tunables; -#[cfg(feature = "compiler")] use wasmer_types::OnCalledAction; use wasmer_vm::{init_traps, StoreId, TrapHandlerFn}; @@ -23,8 +22,8 @@ pub type OnCalledHandler = Box< pub(crate) struct StoreInner { pub(crate) objects: StoreObjects, #[derivative(Debug = "ignore")] - #[cfg(feature = "compiler")] pub(crate) engine: Engine, + #[cfg(feature = "sys")] #[derivative(Debug = "ignore")] pub(crate) trap_handler: Option>>, #[derivative(Debug = "ignore")] @@ -42,12 +41,9 @@ pub(crate) struct StoreInner { /// Spec: pub struct Store { pub(crate) inner: Box, - #[cfg(feature = "compiler")] - engine: Engine, } impl Store { - #[cfg(feature = "compiler")] /// Creates a new `Store` with a specific [`Engine`]. pub fn new(engine: impl Into) -> Self { let engine = engine.into(); @@ -63,11 +59,9 @@ impl Store { trap_handler: None, on_called: None, }), - engine: engine.cloned(), } } - #[cfg(feature = "compiler")] #[deprecated( since = "3.0.0", note = "Store::new_with_engine has been deprecated in favor of Store::new" @@ -77,12 +71,12 @@ impl Store { Self::new(engine) } + #[cfg(feature = "sys")] /// Set the trap handler in this store. pub fn set_trap_handler(&mut self, handler: Option>>) { self.inner.trap_handler = handler; } - #[cfg(feature = "compiler")] #[deprecated( since = "3.2.0", note = "store.new_with_tunables() has been deprecated in favor of engine.set_tunables()" @@ -98,28 +92,24 @@ impl Store { Self::new(engine) } - #[cfg(feature = "compiler")] #[deprecated( since = "3.2.0", note = "store.tunables() has been deprecated in favor of store.engine().tunables()" )] /// Returns the [`Tunables`]. pub fn tunables(&self) -> &dyn Tunables { - self.engine.tunables() + self.inner.engine.tunables() } - #[cfg(feature = "compiler")] /// Returns the [`Engine`]. pub fn engine(&self) -> &Engine { - &self.engine + &self.inner.engine } - #[cfg(feature = "compiler")] /// Checks whether two stores are identical. A store is considered - /// equal to another store if both have the same engine. The - /// tunables are excluded from the logic. + /// equal to another store if both have the same engine. pub fn same(a: &Self, b: &Self) -> bool { - a.engine.id() == b.engine.id() + a.id() == b.id() } /// Returns the ID of this store @@ -128,19 +118,12 @@ impl Store { } } -#[cfg(feature = "compiler")] impl PartialEq for Store { fn eq(&self, other: &Self) -> bool { Self::same(self, other) } } -// impl PartialEq for Store { -// fn eq(&self, other: &Self) -> bool { -// Self::same(self, other) -// } -// } - // This is required to be able to set the trap_handler in the // Store. unsafe impl Send for Store {} @@ -168,28 +151,24 @@ impl AsStoreMut for Store { } } -#[cfg(feature = "compiler")] impl AsEngineRef for Store { fn as_engine_ref(&self) -> EngineRef<'_> { - EngineRef::new(&self.engine) + EngineRef::new(&self.inner.engine) } } -#[cfg(feature = "compiler")] impl AsEngineRef for &Store { fn as_engine_ref(&self) -> EngineRef<'_> { - EngineRef::new(&self.engine) + EngineRef::new(&self.inner.engine) } } -#[cfg(feature = "compiler")] impl AsEngineRef for StoreRef<'_> { fn as_engine_ref(&self) -> EngineRef<'_> { EngineRef::new(&self.inner.engine) } } -#[cfg(feature = "compiler")] impl AsEngineRef for StoreMut<'_> { fn as_engine_ref(&self) -> EngineRef<'_> { EngineRef::new(&self.inner.engine) @@ -212,7 +191,6 @@ impl<'a> StoreRef<'a> { &self.inner.objects } - #[cfg(feature = "compiler")] #[deprecated( since = "3.2.0", note = "store.tunables() has been deprecated in favor of store.engine().tunables()" @@ -222,21 +200,20 @@ impl<'a> StoreRef<'a> { self.inner.engine.tunables() } - #[cfg(feature = "compiler")] /// Returns the [`Engine`]. pub fn engine(&self) -> &Engine { &self.inner.engine } - #[cfg(feature = "compiler")] /// Checks whether two stores are identical. A store is considered /// equal to another store if both have the same engine. The /// tunables are excluded from the logic. pub fn same(a: &Self, b: &Self) -> bool { - a.inner.engine.id() == b.inner.engine.id() + a.inner.objects.id() == b.inner.objects.id() } /// The signal handler + #[cfg(feature = "sys")] #[inline] pub fn signal_handler(&self) -> Option<*const TrapHandlerFn<'static>> { self.inner @@ -253,7 +230,6 @@ pub struct StoreMut<'a> { impl<'a> StoreMut<'a> { /// Returns the [`Tunables`]. - #[cfg(feature = "compiler")] #[deprecated( since = "3.2.0", note = "store.tunables() has been deprecated in favor of store.engine().tunables()" @@ -263,20 +239,16 @@ impl<'a> StoreMut<'a> { } /// Returns the [`Engine`]. - #[cfg(feature = "compiler")] pub fn engine(&self) -> &Engine { &self.inner.engine } - #[cfg(feature = "compiler")] /// Checks whether two stores are identical. A store is considered - /// equal to another store if both have the same engine. The - /// tunables are excluded from the logic. + /// equal to another store if both have the same engine. pub fn same(a: &Self, b: &Self) -> bool { - a.inner.engine.id() == b.inner.engine.id() + a.inner.objects.id() == b.inner.objects.id() } - #[cfg(feature = "compiler")] pub(crate) fn engine_and_objects_mut(&mut self) -> (&Engine, &mut StoreObjects) { (&self.inner.engine, &mut self.inner.objects) } From 30f4589f234b43e8f7e60bc178f5058afd77f683 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Thu, 9 Feb 2023 19:22:33 +0100 Subject: [PATCH 07/81] Move StoreId to common wasmer_types --- lib/api/src/js/store.rs | 26 ++------------------------ lib/api/src/sys/store.rs | 5 +++-- lib/types/src/lib.rs | 3 +++ lib/types/src/store_id.rs | 22 ++++++++++++++++++++++ lib/vm/src/lib.rs | 6 ++---- lib/vm/src/store.rs | 31 +++---------------------------- 6 files changed, 35 insertions(+), 58 deletions(-) create mode 100644 lib/types/src/store_id.rs diff --git a/lib/api/src/js/store.rs b/lib/api/src/js/store.rs index 7bc7e503459..b751f394a84 100644 --- a/lib/api/src/js/store.rs +++ b/lib/api/src/js/store.rs @@ -234,30 +234,8 @@ mod objects { use wasm_bindgen::JsValue; use crate::js::{function_env::VMFunctionEnvironment, vm::VMGlobal}; - use std::{ - fmt, - marker::PhantomData, - num::{NonZeroU64, NonZeroUsize}, - sync::atomic::{AtomicU64, Ordering}, - }; - - /// Unique ID to identify a context. - /// - /// Every handle to an object managed by a context also contains the ID of the - /// context. This is used to check that a handle is always used with the - /// correct context. - #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] - pub struct StoreId(NonZeroU64); - - impl Default for StoreId { - // Allocates a unique ID for a new context. - fn default() -> Self { - // No overflow checking is needed here: overflowing this would take - // thousands of years. - static NEXT_ID: AtomicU64 = AtomicU64::new(1); - Self(NonZeroU64::new(NEXT_ID.fetch_add(1, Ordering::Relaxed)).unwrap()) - } - } + use std::{fmt, marker::PhantomData, num::NonZeroUsize}; + pub use wasmer_types::StoreId; /// Trait to represent an object managed by a context. This is implemented on /// the VM types managed by the context. diff --git a/lib/api/src/sys/store.rs b/lib/api/src/sys/store.rs index 4b55e6f60eb..6b2ac16d6b4 100644 --- a/lib/api/src/sys/store.rs +++ b/lib/api/src/sys/store.rs @@ -3,9 +3,10 @@ use crate::sys::engine::{default_engine, Engine}; use derivative::Derivative; use std::fmt; use wasmer_compiler::Tunables; -use wasmer_types::OnCalledAction; -use wasmer_vm::{init_traps, StoreId, TrapHandlerFn}; +use wasmer_types::{OnCalledAction, StoreId}; +use wasmer_vm::{init_traps, TrapHandlerFn}; +#[cfg(feature = "sys")] use wasmer_vm::StoreObjects; /// Call handler for a store. diff --git a/lib/types/src/lib.rs b/lib/types/src/lib.rs index 1c84890dcc1..268c59b5ce4 100644 --- a/lib/types/src/lib.rs +++ b/lib/types/src/lib.rs @@ -62,6 +62,7 @@ mod libcalls; mod memory; mod module; mod serialize; +mod store_id; mod table; mod trapcode; mod types; @@ -129,6 +130,8 @@ pub use crate::compilation::symbols::{Symbol, SymbolRegistry}; pub use crate::compilation::trap::TrapInformation; pub use crate::compilation::unwind::CompiledFunctionUnwindInfo; +pub use crate::store_id::StoreId; + /// Offset in bytes from the beginning of the function. pub type CodeOffset = u32; diff --git a/lib/types/src/store_id.rs b/lib/types/src/store_id.rs new file mode 100644 index 00000000000..4c183f9d1c2 --- /dev/null +++ b/lib/types/src/store_id.rs @@ -0,0 +1,22 @@ +use std::{ + num::NonZeroU64, + sync::atomic::{AtomicU64, Ordering}, +}; + +/// Unique ID to identify a context. +/// +/// Every handle to an object managed by a context also contains the ID of the +/// context. This is used to check that a handle is always used with the +/// correct context. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub struct StoreId(NonZeroU64); + +impl Default for StoreId { + // Allocates a unique ID for a new context. + fn default() -> Self { + // No overflow checking is needed here: overflowing this would take + // thousands of years. + static NEXT_ID: AtomicU64 = AtomicU64::new(1); + Self(NonZeroU64::new(NEXT_ID.fetch_add(1, Ordering::Relaxed)).unwrap()) + } +} diff --git a/lib/vm/src/lib.rs b/lib/vm/src/lib.rs index f4fe1a18ea2..b2d69b8616d 100644 --- a/lib/vm/src/lib.rs +++ b/lib/vm/src/lib.rs @@ -52,9 +52,7 @@ pub use crate::memory::{ pub use crate::mmap::Mmap; pub use crate::probestack::PROBESTACK; pub use crate::sig_registry::SignatureRegistry; -pub use crate::store::{ - InternalStoreHandle, MaybeInstanceOwned, StoreHandle, StoreId, StoreObjects, -}; +pub use crate::store::{InternalStoreHandle, MaybeInstanceOwned, StoreHandle, StoreObjects}; pub use crate::table::{TableElement, VMTable}; pub use crate::trap::*; pub use crate::vmcontext::{ @@ -67,7 +65,7 @@ pub use wasmer_types::MemoryError; pub use wasmer_types::MemoryStyle; use wasmer_types::RawValue; pub use wasmer_types::TableStyle; -pub use wasmer_types::{TargetSharedSignatureIndex, VMBuiltinFunctionIndex, VMOffsets}; +pub use wasmer_types::{StoreId, TargetSharedSignatureIndex, VMBuiltinFunctionIndex, VMOffsets}; #[deprecated( since = "2.1.0", diff --git a/lib/vm/src/store.rs b/lib/vm/src/store.rs index c28421474d8..2b1f0e74da3 100644 --- a/lib/vm/src/store.rs +++ b/lib/vm/src/store.rs @@ -1,34 +1,9 @@ -use core::slice::Iter; -use std::{ - cell::UnsafeCell, - fmt, - marker::PhantomData, - num::{NonZeroU64, NonZeroUsize}, - ptr::NonNull, - sync::atomic::{AtomicU64, Ordering}, -}; - use crate::{ VMExternObj, VMFunction, VMFunctionEnvironment, VMGlobal, VMInstance, VMMemory, VMTable, }; - -/// Unique ID to identify a context. -/// -/// Every handle to an object managed by a context also contains the ID of the -/// context. This is used to check that a handle is always used with the -/// correct context. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub struct StoreId(NonZeroU64); - -impl Default for StoreId { - // Allocates a unique ID for a new context. - fn default() -> Self { - // No overflow checking is needed here: overflowing this would take - // thousands of years. - static NEXT_ID: AtomicU64 = AtomicU64::new(1); - Self(NonZeroU64::new(NEXT_ID.fetch_add(1, Ordering::Relaxed)).unwrap()) - } -} +use core::slice::Iter; +use std::{cell::UnsafeCell, fmt, marker::PhantomData, num::NonZeroUsize, ptr::NonNull}; +use wasmer_types::StoreId; /// Trait to represent an object managed by a context. This is implemented on /// the VM types managed by the context. From 2a067fdb8c6779e5d2ed0a34d3773958b370c92b Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Thu, 9 Feb 2023 19:29:57 +0100 Subject: [PATCH 08/81] Made store compiler flags clearer --- lib/api/src/sys/store.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/api/src/sys/store.rs b/lib/api/src/sys/store.rs index 6b2ac16d6b4..09ddc91dd49 100644 --- a/lib/api/src/sys/store.rs +++ b/lib/api/src/sys/store.rs @@ -2,9 +2,11 @@ use crate::engine::{AsEngineRef, EngineRef}; use crate::sys::engine::{default_engine, Engine}; use derivative::Derivative; use std::fmt; -use wasmer_compiler::Tunables; use wasmer_types::{OnCalledAction, StoreId}; +#[cfg(feature = "sys")] use wasmer_vm::{init_traps, TrapHandlerFn}; +#[cfg(feature = "sys")] +use wasmer_compiler::Tunables; #[cfg(feature = "sys")] use wasmer_vm::StoreObjects; @@ -47,8 +49,6 @@ pub struct Store { impl Store { /// Creates a new `Store` with a specific [`Engine`]. pub fn new(engine: impl Into) -> Self { - let engine = engine.into(); - // Make sure the signal handlers are installed. // This is required for handling traps. init_traps(); @@ -56,7 +56,8 @@ impl Store { Self { inner: Box::new(StoreInner { objects: Default::default(), - engine: engine.cloned(), + engine: engine.into(), + #[cfg(feature = "sys")] trap_handler: None, on_called: None, }), @@ -78,6 +79,7 @@ impl Store { self.inner.trap_handler = handler; } + #[cfg(feature = "sys")] #[deprecated( since = "3.2.0", note = "store.new_with_tunables() has been deprecated in favor of engine.set_tunables()" @@ -93,6 +95,7 @@ impl Store { Self::new(engine) } + #[cfg(feature = "sys")] #[deprecated( since = "3.2.0", note = "store.tunables() has been deprecated in favor of store.engine().tunables()" @@ -192,6 +195,7 @@ impl<'a> StoreRef<'a> { &self.inner.objects } + #[cfg(feature = "sys")] #[deprecated( since = "3.2.0", note = "store.tunables() has been deprecated in favor of store.engine().tunables()" @@ -207,8 +211,7 @@ impl<'a> StoreRef<'a> { } /// Checks whether two stores are identical. A store is considered - /// equal to another store if both have the same engine. The - /// tunables are excluded from the logic. + /// equal to another store if both have the same engine. pub fn same(a: &Self, b: &Self) -> bool { a.inner.objects.id() == b.inner.objects.id() } @@ -231,6 +234,7 @@ pub struct StoreMut<'a> { impl<'a> StoreMut<'a> { /// Returns the [`Tunables`]. + #[cfg(feature = "sys")] #[deprecated( since = "3.2.0", note = "store.tunables() has been deprecated in favor of store.engine().tunables()" From 4c9a154e7726119814754e2104b43f7786cf112a Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Thu, 9 Feb 2023 20:29:24 +0100 Subject: [PATCH 09/81] Use general store --- lib/api/src/engine.rs | 8 +- lib/api/src/js/exports.rs | 2 +- lib/api/src/js/externals/function.rs | 5 +- lib/api/src/js/externals/global.rs | 2 +- lib/api/src/js/externals/memory.rs | 2 +- lib/api/src/js/externals/memory_view.rs | 2 +- lib/api/src/js/externals/mod.rs | 2 +- lib/api/src/js/externals/table.rs | 2 +- lib/api/src/js/function_env.rs | 5 +- lib/api/src/js/imports.rs | 5 +- lib/api/src/js/instance.rs | 2 +- lib/api/src/js/mod.rs | 9 +- lib/api/src/js/module.rs | 2 +- lib/api/src/js/native.rs | 2 +- lib/api/src/js/native_type.rs | 2 +- lib/api/src/js/ptr.rs | 3 +- lib/api/src/js/store.rs | 233 +---------------------- lib/api/src/js/types.rs | 4 +- lib/api/src/js/value.rs | 2 +- lib/api/src/js/vm.rs | 2 +- lib/api/src/lib.rs | 4 + lib/api/src/{sys => }/store.rs | 17 +- lib/api/src/sys/exports.rs | 2 +- lib/api/src/sys/extern_ref.rs | 2 +- lib/api/src/sys/externals/function.rs | 4 +- lib/api/src/sys/externals/global.rs | 2 +- lib/api/src/sys/externals/memory.rs | 2 +- lib/api/src/sys/externals/memory_view.rs | 2 +- lib/api/src/sys/externals/mod.rs | 2 +- lib/api/src/sys/externals/table.rs | 2 +- lib/api/src/sys/instance.rs | 2 +- lib/api/src/sys/mod.rs | 6 +- lib/api/src/sys/native.rs | 2 +- lib/api/src/sys/native_type.rs | 2 +- lib/api/src/sys/value.rs | 2 +- 35 files changed, 66 insertions(+), 283 deletions(-) rename lib/api/src/{sys => }/store.rs (96%) diff --git a/lib/api/src/engine.rs b/lib/api/src/engine.rs index ec3e394a3b0..4eb05d458a9 100644 --- a/lib/api/src/engine.rs +++ b/lib/api/src/engine.rs @@ -1,8 +1,12 @@ #[cfg(feature = "sys")] -use crate::sys as engine_imp; +use crate::sys::engine as engine_imp; +#[cfg(feature = "sys")] +pub(crate) use crate::sys::engine::default_engine; #[cfg(feature = "js")] -use crate::js as engine_imp; +use crate::js::engine as engine_imp; +#[cfg(feature = "js")] +pub(crate) use crate::js::engine::default_engine; /// The engine type pub type Engine = engine_imp::Engine; diff --git a/lib/api/src/js/exports.rs b/lib/api/src/js/exports.rs index 024ab8b9696..1797284945f 100644 --- a/lib/api/src/js/exports.rs +++ b/lib/api/src/js/exports.rs @@ -1,7 +1,7 @@ use crate::js::externals::{Extern, Function, Global, Memory, Table}; use crate::js::native::TypedFunction; -use crate::js::store::AsStoreRef; use crate::js::WasmTypeList; +use crate::store::AsStoreRef; use indexmap::IndexMap; use std::fmt; use std::iter::{ExactSizeIterator, FromIterator}; diff --git a/lib/api/src/js/externals/function.rs b/lib/api/src/js/externals/function.rs index 7b7115f473b..24236ec0277 100644 --- a/lib/api/src/js/externals/function.rs +++ b/lib/api/src/js/externals/function.rs @@ -2,13 +2,13 @@ pub use self::inner::{FromToNativeWasmType, HostFunction, WasmTypeList, WithEnv, use crate::js::exports::{ExportError, Exportable}; use crate::js::externals::Extern; use crate::js::function_env::FunctionEnvMut; -use crate::js::store::{AsStoreMut, AsStoreRef, StoreMut}; use crate::js::types::{param_from_js, AsJs}; /* ValFuncRef */ use crate::js::vm::VMExtern; use crate::js::RuntimeError; use crate::js::TypedFunction; use crate::js::Value; use crate::js::{FunctionEnv, FunctionType}; +use crate::store::{AsStoreMut, AsStoreRef, StoreMut}; use js_sys::{Array, Function as JSFunction}; use std::iter::FromIterator; use wasm_bindgen::prelude::*; @@ -630,9 +630,10 @@ mod inner { use super::RuntimeError; use super::VMFunctionBody; use crate::js::function_env::{FunctionEnvMut, VMFunctionEnvironment}; - use crate::js::store::{AsStoreMut, AsStoreRef, InternalStoreHandle, StoreHandle, StoreMut}; + use crate::js::store::{InternalStoreHandle, StoreHandle}; use crate::js::FunctionEnv; use crate::js::NativeWasmTypeInto; + use crate::store::{AsStoreMut, AsStoreRef, StoreMut}; use std::array::TryFromSliceError; use std::convert::{Infallible, TryInto}; use std::error::Error; diff --git a/lib/api/src/js/externals/global.rs b/lib/api/src/js/externals/global.rs index 2572cbb1fbe..cdc61360279 100644 --- a/lib/api/src/js/externals/global.rs +++ b/lib/api/src/js/externals/global.rs @@ -1,12 +1,12 @@ use crate::js::exports::{ExportError, Exportable}; use crate::js::externals::Extern; -use crate::js::store::{AsStoreMut, AsStoreRef}; use crate::js::value::Value; use crate::js::vm::{VMExtern, VMGlobal}; use crate::js::wasm_bindgen_polyfill::Global as JSGlobal; use crate::js::GlobalType; use crate::js::Mutability; use crate::js::RuntimeError; +use crate::store::{AsStoreMut, AsStoreRef}; use wasm_bindgen::JsValue; /// A WebAssembly `global` instance. diff --git a/lib/api/src/js/externals/memory.rs b/lib/api/src/js/externals/memory.rs index 39d5b4732d1..e90bd8278e5 100644 --- a/lib/api/src/js/externals/memory.rs +++ b/lib/api/src/js/externals/memory.rs @@ -1,8 +1,8 @@ use crate::js::exports::{ExportError, Exportable}; use crate::js::externals::Extern; -use crate::js::store::{AsStoreMut, AsStoreRef, StoreObjects}; use crate::js::vm::{VMExtern, VMMemory}; use crate::js::{MemoryAccessError, MemoryType}; +use crate::store::{AsStoreMut, AsStoreRef, StoreObjects}; use std::marker::PhantomData; use std::mem::MaybeUninit; use std::slice; diff --git a/lib/api/src/js/externals/memory_view.rs b/lib/api/src/js/externals/memory_view.rs index 347547e8664..65b5865fb54 100644 --- a/lib/api/src/js/externals/memory_view.rs +++ b/lib/api/src/js/externals/memory_view.rs @@ -1,5 +1,5 @@ -use crate::js::store::AsStoreRef; use crate::js::MemoryAccessError; +use crate::store::AsStoreRef; use std::convert::TryInto; use std::marker::PhantomData; use std::mem::MaybeUninit; diff --git a/lib/api/src/js/externals/mod.rs b/lib/api/src/js/externals/mod.rs index 6dd72eb6ff7..d01480f1597 100644 --- a/lib/api/src/js/externals/mod.rs +++ b/lib/api/src/js/externals/mod.rs @@ -11,9 +11,9 @@ pub use self::memory_view::MemoryView; pub use self::table::Table; use crate::js::exports::{ExportError, Exportable}; -use crate::js::store::{AsStoreMut, AsStoreRef}; use crate::js::types::AsJs; use crate::js::vm::VMExtern; +use crate::store::{AsStoreMut, AsStoreRef}; use std::fmt; use wasmer_types::ExternType; diff --git a/lib/api/src/js/externals/table.rs b/lib/api/src/js/externals/table.rs index 6e9860042f4..d1415e5f684 100644 --- a/lib/api/src/js/externals/table.rs +++ b/lib/api/src/js/externals/table.rs @@ -1,10 +1,10 @@ use crate::js::exports::{ExportError, Exportable}; use crate::js::externals::Extern; -use crate::js::store::{AsStoreMut, AsStoreRef}; use crate::js::value::Value; use crate::js::vm::{VMExtern, VMFunction, VMTable}; use crate::js::RuntimeError; use crate::js::{FunctionType, TableType}; +use crate::store::{AsStoreMut, AsStoreRef}; use js_sys::Function; /// A WebAssembly `table` instance. diff --git a/lib/api/src/js/function_env.rs b/lib/api/src/js/function_env.rs index 524fc7a2dbe..6eca9771ad9 100644 --- a/lib/api/src/js/function_env.rs +++ b/lib/api/src/js/function_env.rs @@ -1,8 +1,8 @@ use std::{any::Any, marker::PhantomData}; -use crate::js::{StoreHandle, StoreObjects}; +use crate::js::store::{StoreHandle, StoreObjects}; -use crate::js::{AsStoreMut, AsStoreRef, StoreMut, StoreRef}; +use crate::store::{AsStoreMut, AsStoreRef, StoreMut, StoreRef}; #[derive(Debug)] #[repr(transparent)] @@ -147,6 +147,7 @@ impl AsStoreMut for FunctionEnvMut<'_, T> { } /// Underlying FunctionEnvironment used by a `VMFunction`. +#[derive(Debug)] pub struct VMFunctionEnvironment { contents: Box, } diff --git a/lib/api/src/js/imports.rs b/lib/api/src/js/imports.rs index ae76b7e0ace..90bf46eaa5d 100644 --- a/lib/api/src/js/imports.rs +++ b/lib/api/src/js/imports.rs @@ -4,10 +4,10 @@ use crate::js::error::{LinkError, WasmError}; use crate::js::exports::Exports; use crate::js::module::Module; -use crate::js::store::{AsStoreMut, AsStoreRef}; use crate::js::types::AsJs; use crate::js::vm::VMExtern; use crate::js::ExternType; +use crate::store::{AsStoreMut, AsStoreRef}; use crate::Extern; use std::collections::HashMap; use std::fmt; @@ -421,7 +421,8 @@ macro_rules! import_namespace { #[cfg(test)] mod test { - use crate::js::{Global, Store, Value}; + use crate::js::{Global, Value}; + use crate::store::Store; // use wasm_bindgen::*; use wasm_bindgen_test::*; diff --git a/lib/api/src/js/instance.rs b/lib/api/src/js/instance.rs index 393b12023f6..a5326ea083d 100644 --- a/lib/api/src/js/instance.rs +++ b/lib/api/src/js/instance.rs @@ -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::store::{AsStoreMut, AsStoreRef}; use crate::js::vm::{VMExtern, VMInstance}; use crate::module::Module; +use crate::store::{AsStoreMut, AsStoreRef}; use js_sys::WebAssembly; use std::fmt; diff --git a/lib/api/src/js/mod.rs b/lib/api/src/js/mod.rs index e66af0acdfd..6f2584f989b 100644 --- a/lib/api/src/js/mod.rs +++ b/lib/api/src/js/mod.rs @@ -23,7 +23,7 @@ mod lib { } } -mod engine; +pub(crate) mod engine; pub(crate) mod error; mod exports; mod externals; @@ -37,7 +37,7 @@ mod module_info_polyfill; mod native; mod native_type; mod ptr; -mod store; +pub(crate) mod store; mod trap; mod types; mod value; @@ -59,11 +59,8 @@ 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}; +pub use crate::js::store::StoreObjects; pub use crate::js::trap::RuntimeError; - -pub use crate::js::store::{ - AsStoreMut, AsStoreRef, Store, StoreHandle, StoreMut, StoreObjects, StoreRef, -}; pub use crate::js::types::ValType as Type; pub use crate::js::types::{ ExportType, ExternType, FunctionType, GlobalType, ImportType, MemoryType, Mutability, diff --git a/lib/api/src/js/module.rs b/lib/api/src/js/module.rs index f3498fa82ad..ee884ed176a 100644 --- a/lib/api/src/js/module.rs +++ b/lib/api/src/js/module.rs @@ -3,11 +3,11 @@ use crate::js::error::InstantiationError; use crate::js::error::WasmError; 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::module::IoCompileError; +use crate::store::AsStoreMut; use crate::AsEngineRef; use crate::IntoBytes; use bytes::Bytes; diff --git a/lib/api/src/js/native.rs b/lib/api/src/js/native.rs index 436eff84d2e..db718de1d0d 100644 --- a/lib/api/src/js/native.rs +++ b/lib/api/src/js/native.rs @@ -10,8 +10,8 @@ use std::marker::PhantomData; use crate::js::externals::Function; -use crate::js::store::{AsStoreMut, AsStoreRef}; use crate::js::{FromToNativeWasmType, RuntimeError, WasmTypeList}; +use crate::store::{AsStoreMut, AsStoreRef}; // use std::panic::{catch_unwind, AssertUnwindSafe}; use crate::js::types::param_from_js; use crate::js::types::AsJs; diff --git a/lib/api/src/js/native_type.rs b/lib/api/src/js/native_type.rs index a12a186ce48..ec7e92c786e 100644 --- a/lib/api/src/js/native_type.rs +++ b/lib/api/src/js/native_type.rs @@ -5,7 +5,7 @@ use wasmer_types::{NativeWasmType, Type}; use crate::js::Function; -use super::store::AsStoreMut; +use crate::store::AsStoreMut; /// `NativeWasmTypeInto` performs conversions from and into `NativeWasmType` /// types with a context. diff --git a/lib/api/src/js/ptr.rs b/lib/api/src/js/ptr.rs index 7d78109790b..ae41e470211 100644 --- a/lib/api/src/js/ptr.rs +++ b/lib/api/src/js/ptr.rs @@ -1,6 +1,7 @@ +use crate::js::NativeWasmTypeInto; use crate::js::{externals::MemoryView, FromToNativeWasmType}; use crate::js::{MemoryAccessError, WasmRef, WasmSlice}; -use crate::{js::NativeWasmTypeInto, AsStoreRef}; +use crate::store::AsStoreRef; use std::convert::TryFrom; use std::{fmt, marker::PhantomData, mem}; pub use wasmer_types::Memory32; diff --git a/lib/api/src/js/store.rs b/lib/api/src/js/store.rs index b751f394a84..d4cd48e0693 100644 --- a/lib/api/src/js/store.rs +++ b/lib/api/src/js/store.rs @@ -1,234 +1,5 @@ -use crate::engine::{AsEngineRef, EngineRef}; -use crate::js::engine::Engine; -use std::fmt; -use wasmer_types::OnCalledAction; - -/// Call handler for a store. -// TODO: better documentation! -// TODO: this type is duplicated in sys/store.rs. -// Maybe want to move it to wasmer_types... -pub type OnCalledHandler = Box< - dyn FnOnce(StoreMut<'_>) -> Result>, ->; - -/// We require the context to have a fixed memory address for its lifetime since -/// various bits of the VM have raw pointers that point back to it. Hence we -/// wrap the actual context in a box. -pub(crate) struct StoreInner { - pub(crate) objects: StoreObjects, - pub(crate) engine: Engine, - pub(crate) on_called: Option, -} - -/// The store represents all global state that can be manipulated by -/// WebAssembly programs. It consists of the runtime representation -/// of all instances of functions, tables, memories, and globals that -/// have been allocated during the lifetime of the abstract machine. -/// -/// The `Store` holds the engine (that is —amongst many things— used to compile -/// the Wasm bytes into a valid module artifact), in addition to the -/// [`Tunables`] (that are used to create the memories, tables and globals). -/// -/// Spec: -pub struct Store { - pub(crate) inner: Box, -} - -impl Store { - /// Creates a new `Store`. - pub fn new() -> Self { - Self { - inner: Box::new(StoreInner { - objects: Default::default(), - engine: Default::default(), - on_called: None, - }), - } - } - - /// Checks whether two stores are identical. A store is considered - /// equal to another store if both have the same engine. The - /// tunables are excluded from the logic. - pub fn same(_a: &Self, _b: &Self) -> bool { - true - } - - /// Returns the ID of this store - pub fn id(&self) -> StoreId { - self.inner.objects.id() - } -} - -impl PartialEq for Store { - fn eq(&self, other: &Self) -> bool { - Self::same(self, other) - } -} - -// This is required to be able to set the trap_handler in the -// Store. -unsafe impl Send for Store {} -unsafe impl Sync for Store {} - -impl Default for Store { - fn default() -> Self { - Self::new() - } -} - -impl fmt::Debug for Store { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("Store").finish() - } -} - -impl AsStoreRef for Store { - fn as_store_ref(&self) -> StoreRef<'_> { - StoreRef { inner: &self.inner } - } -} -impl AsStoreMut for Store { - fn as_store_mut(&mut self) -> StoreMut<'_> { - StoreMut { - inner: &mut self.inner, - } - } - fn objects_mut(&mut self) -> &mut StoreObjects { - &mut self.inner.objects - } -} - -/// A temporary handle to a [`Context`]. -pub struct StoreRef<'a> { - pub(crate) inner: &'a StoreInner, -} - -impl<'a> StoreRef<'a> { - pub(crate) fn objects(&self) -> &'a StoreObjects { - &self.inner.objects - } - - /// Checks whether two stores are identical. A store is considered - /// equal to another store if both have the same engine. The - /// tunables are excluded from the logic. - pub fn same(a: &Self, b: &Self) -> bool { - a.inner.objects.id() == b.inner.objects.id() - } -} - -/// A temporary handle to a [`Context`]. -pub struct StoreMut<'a> { - pub(crate) inner: &'a mut StoreInner, -} - -impl<'a> StoreMut<'a> { - /// Checks whether two stores are identical. A store is considered - /// equal to another store if both have the same engine. The - /// tunables are excluded from the logic. - pub fn same(a: &Self, b: &Self) -> bool { - a.inner.objects.id() == b.inner.objects.id() - } - - pub(crate) fn as_raw(&self) -> *mut StoreInner { - self.inner as *const StoreInner as *mut StoreInner - } - - pub(crate) unsafe fn from_raw(raw: *mut StoreInner) -> Self { - Self { inner: &mut *raw } - } - - /// Sets the unwind callback which will be invoked when the call finishes - pub fn on_called(&mut self, callback: F) - where - F: FnOnce(StoreMut<'_>) -> Result> - + Send - + Sync - + 'static, - { - self.inner.on_called.replace(Box::new(callback)); - } -} - -/// Helper trait for a value that is convertible to a [`StoreRef`]. -pub trait AsStoreRef { - /// Returns a `StoreRef` pointing to the underlying context. - fn as_store_ref(&self) -> StoreRef<'_>; -} - -/// Helper trait for a value that is convertible to a [`StoreMut`]. -pub trait AsStoreMut: AsStoreRef { - /// Returns a `StoreMut` pointing to the underlying context. - fn as_store_mut(&mut self) -> StoreMut<'_>; - - /// Returns the ObjectMutable - fn objects_mut(&mut self) -> &mut StoreObjects; -} - -impl AsStoreRef for StoreRef<'_> { - fn as_store_ref(&self) -> StoreRef<'_> { - StoreRef { inner: self.inner } - } -} - -impl AsStoreRef for StoreMut<'_> { - fn as_store_ref(&self) -> StoreRef<'_> { - StoreRef { inner: self.inner } - } -} -impl AsStoreMut for StoreMut<'_> { - fn as_store_mut(&mut self) -> StoreMut<'_> { - StoreMut { inner: self.inner } - } - fn objects_mut(&mut self) -> &mut StoreObjects { - &mut self.inner.objects - } -} - -impl AsStoreRef for &'_ T { - fn as_store_ref(&self) -> StoreRef<'_> { - T::as_store_ref(*self) - } -} -impl AsStoreRef for &'_ mut T { - fn as_store_ref(&self) -> StoreRef<'_> { - T::as_store_ref(*self) - } -} -impl AsStoreMut for &'_ mut T { - fn as_store_mut(&mut self) -> StoreMut<'_> { - T::as_store_mut(*self) - } - fn objects_mut(&mut self) -> &mut StoreObjects { - T::objects_mut(*self) - } -} - -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}; +pub use objects::{StoreHandle, StoreObjects}; mod objects { use wasm_bindgen::JsValue; @@ -273,7 +44,7 @@ mod objects { } /// Set of objects managed by a context. - #[derive(Default)] + #[derive(Default, Debug)] pub struct StoreObjects { id: StoreId, globals: Vec, diff --git a/lib/api/src/js/types.rs b/lib/api/src/js/types.rs index 4dd2133f523..a1ec6df0fb9 100644 --- a/lib/api/src/js/types.rs +++ b/lib/api/src/js/types.rs @@ -1,8 +1,8 @@ //use crate::js::externals::Function; -// use crate::js::store::{Store, StoreObject}; +// use crate::store::{Store, StoreObject}; // use crate::js::RuntimeError; -use crate::js::store::AsStoreRef; use crate::js::value::Value; +use crate::store::AsStoreRef; use wasm_bindgen::JsValue; pub use wasmer_types::{ ExportType, ExternType, FunctionType, GlobalType, ImportType, MemoryType, Mutability, diff --git a/lib/api/src/js/value.rs b/lib/api/src/js/value.rs index 4a432c9ce2e..3124f7702f8 100644 --- a/lib/api/src/js/value.rs +++ b/lib/api/src/js/value.rs @@ -8,7 +8,7 @@ use wasmer_types::Type; //use crate::ExternRef; use crate::js::externals::function::Function; -use super::store::AsStoreRef; +use crate::store::AsStoreRef; /// WebAssembly computations manipulate values of basic value types: /// * Integers (32 or 64 bit width) diff --git a/lib/api/src/js/vm.rs b/lib/api/src/js/vm.rs index 08e43ffc233..5804a5471b2 100644 --- a/lib/api/src/js/vm.rs +++ b/lib/api/src/js/vm.rs @@ -5,9 +5,9 @@ /// once the type reflection is added to the WebAssembly JS API. /// https://github.com/WebAssembly/js-types/ use crate::js::error::WasmError; -use crate::js::store::{AsStoreMut, AsStoreRef}; use crate::js::wasm_bindgen_polyfill::Global; use crate::js::wasm_bindgen_polyfill::Global as JsGlobal; +use crate::store::{AsStoreMut, AsStoreRef}; use crate::MemoryView; use js_sys::Function; use js_sys::Function as JsFunction; diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index 3684b0c9376..3c5efb8895c 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -431,6 +431,7 @@ compile_error!( mod engine; mod module; +mod store; #[cfg(feature = "sys")] mod sys; @@ -446,6 +447,9 @@ pub use js::*; pub use engine::{AsEngineRef, Engine}; pub use module::{IoCompileError, Module}; +pub use store::{OnCalledHandler, Store, StoreId}; +#[cfg(feature = "sys")] +pub use store::{TrapHandlerFn, Tunables}; mod into_bytes; pub use into_bytes::IntoBytes; diff --git a/lib/api/src/sys/store.rs b/lib/api/src/store.rs similarity index 96% rename from lib/api/src/sys/store.rs rename to lib/api/src/store.rs index 09ddc91dd49..c8c34a35a09 100644 --- a/lib/api/src/sys/store.rs +++ b/lib/api/src/store.rs @@ -1,15 +1,19 @@ -use crate::engine::{AsEngineRef, EngineRef}; -use crate::sys::engine::{default_engine, Engine}; +use crate::engine::{default_engine, AsEngineRef, Engine, EngineRef}; use derivative::Derivative; use std::fmt; -use wasmer_types::{OnCalledAction, StoreId}; #[cfg(feature = "sys")] -use wasmer_vm::{init_traps, TrapHandlerFn}; +pub use wasmer_compiler::Tunables; +pub use wasmer_types::{OnCalledAction, StoreId}; #[cfg(feature = "sys")] -use wasmer_compiler::Tunables; +use wasmer_vm::init_traps; +#[cfg(feature = "sys")] +pub use wasmer_vm::TrapHandlerFn; #[cfg(feature = "sys")] -use wasmer_vm::StoreObjects; +pub use wasmer_vm::StoreObjects; + +#[cfg(feature = "js")] +pub use crate::js::store::StoreObjects; /// Call handler for a store. // TODO: better documentation! @@ -51,6 +55,7 @@ impl Store { pub fn new(engine: impl Into) -> Self { // Make sure the signal handlers are installed. // This is required for handling traps. + #[cfg(feature = "sys")] init_traps(); Self { diff --git a/lib/api/src/sys/exports.rs b/lib/api/src/sys/exports.rs index 571419deefb..2e887494e18 100644 --- a/lib/api/src/sys/exports.rs +++ b/lib/api/src/sys/exports.rs @@ -1,4 +1,4 @@ -use super::store::AsStoreRef; +use crate::store::AsStoreRef; use crate::sys::externals::{Extern, Function, Global, Memory, Table}; use crate::sys::native::TypedFunction; use crate::sys::WasmTypeList; diff --git a/lib/api/src/sys/extern_ref.rs b/lib/api/src/sys/extern_ref.rs index 4f0fcd9fa83..b8fb7cfb52d 100644 --- a/lib/api/src/sys/extern_ref.rs +++ b/lib/api/src/sys/extern_ref.rs @@ -2,7 +2,7 @@ use std::any::Any; use wasmer_vm::{StoreHandle, VMExternObj, VMExternRef}; -use super::store::{AsStoreMut, AsStoreRef}; +use crate::store::{AsStoreMut, AsStoreRef}; #[derive(Debug, Clone)] #[repr(transparent)] diff --git a/lib/api/src/sys/externals/function.rs b/lib/api/src/sys/externals/function.rs index 3c3d383113a..e9a93a877db 100644 --- a/lib/api/src/sys/externals/function.rs +++ b/lib/api/src/sys/externals/function.rs @@ -5,9 +5,9 @@ use wasmer_vm::{ VMTrampoline, }; +use crate::store::{AsStoreMut, AsStoreRef}; use crate::sys::exports::{ExportError, Exportable}; use crate::sys::externals::Extern; -use crate::sys::store::{AsStoreMut, AsStoreRef}; use crate::sys::{FunctionType, RuntimeError, TypedFunction}; use crate::FunctionEnv; @@ -16,7 +16,7 @@ pub use inner::{FromToNativeWasmType, HostFunction, WasmTypeList, WithEnv, Witho #[cfg(feature = "compiler")] use { crate::{ - sys::store::{StoreInner, StoreMut}, + store::{StoreInner, StoreMut}, FunctionEnvMut, Value, }, inner::StaticFunction, diff --git a/lib/api/src/sys/externals/global.rs b/lib/api/src/sys/externals/global.rs index 2dfc77ff06d..27e3d3e3dad 100644 --- a/lib/api/src/sys/externals/global.rs +++ b/lib/api/src/sys/externals/global.rs @@ -1,6 +1,6 @@ +use crate::store::{AsStoreMut, AsStoreRef}; use crate::sys::exports::{ExportError, Exportable}; use crate::sys::externals::Extern; -use crate::sys::store::{AsStoreMut, AsStoreRef}; use crate::sys::value::Value; use crate::sys::GlobalType; use crate::sys::Mutability; diff --git a/lib/api/src/sys/externals/memory.rs b/lib/api/src/sys/externals/memory.rs index a82a031bfa6..a54c1c63daa 100644 --- a/lib/api/src/sys/externals/memory.rs +++ b/lib/api/src/sys/externals/memory.rs @@ -1,6 +1,6 @@ +use crate::store::{AsStoreMut, AsStoreRef}; use crate::sys::exports::{ExportError, Exportable}; use crate::sys::externals::Extern; -use crate::sys::store::{AsStoreMut, AsStoreRef}; use crate::sys::MemoryType; use crate::MemoryAccessError; use std::convert::TryInto; diff --git a/lib/api/src/sys/externals/memory_view.rs b/lib/api/src/sys/externals/memory_view.rs index ee1cbaea17c..0412a4f8a21 100644 --- a/lib/api/src/sys/externals/memory_view.rs +++ b/lib/api/src/sys/externals/memory_view.rs @@ -1,4 +1,4 @@ -use crate::sys::store::AsStoreRef; +use crate::store::AsStoreRef; use crate::MemoryAccessError; use std::convert::TryInto; use std::marker::PhantomData; diff --git a/lib/api/src/sys/externals/mod.rs b/lib/api/src/sys/externals/mod.rs index e33518c8ccd..b54d94b901b 100644 --- a/lib/api/src/sys/externals/mod.rs +++ b/lib/api/src/sys/externals/mod.rs @@ -16,7 +16,7 @@ use crate::sys::ExternType; use std::fmt; use wasmer_vm::VMExtern; -use super::store::{AsStoreMut, AsStoreRef}; +use super::{AsStoreMut, AsStoreRef}; /// An `Extern` is the runtime representation of an entity that /// can be imported or exported. diff --git a/lib/api/src/sys/externals/table.rs b/lib/api/src/sys/externals/table.rs index 754d925b2ba..ee10af08f3e 100644 --- a/lib/api/src/sys/externals/table.rs +++ b/lib/api/src/sys/externals/table.rs @@ -1,6 +1,6 @@ +use crate::store::{AsStoreMut, AsStoreRef}; use crate::sys::exports::{ExportError, Exportable}; use crate::sys::externals::Extern; -use crate::sys::store::{AsStoreMut, AsStoreRef}; use crate::sys::TableType; use crate::Value; use crate::{sys::RuntimeError, ExternRef, Function}; diff --git a/lib/api/src/sys/instance.rs b/lib/api/src/sys/instance.rs index 2f7da0adc8e..3672ac99ae1 100644 --- a/lib/api/src/sys/instance.rs +++ b/lib/api/src/sys/instance.rs @@ -6,7 +6,7 @@ use thiserror::Error; use wasmer_vm::{StoreHandle, VMInstance}; #[cfg(feature = "compiler")] -use super::store::AsStoreMut; +use crate::store::AsStoreMut; #[cfg(feature = "compiler")] use crate::sys::{externals::Extern, imports::Imports}; diff --git a/lib/api/src/sys/mod.rs b/lib/api/src/sys/mod.rs index b3b3cdcbea1..77ddacecf90 100644 --- a/lib/api/src/sys/mod.rs +++ b/lib/api/src/sys/mod.rs @@ -1,4 +1,4 @@ -mod engine; +pub(crate) mod engine; mod exports; mod extern_ref; mod externals; @@ -10,10 +10,10 @@ pub(crate) mod module; mod native; mod native_type; mod ptr; -mod store; mod tunables; mod value; +pub use crate::store::{AsStoreMut, AsStoreRef, Store, StoreMut, StoreRef}; pub use crate::sys::engine::Engine; pub use crate::sys::exports::{ExportError, Exportable, Exports, ExportsIterator}; pub use crate::sys::extern_ref::ExternRef; @@ -28,10 +28,8 @@ pub use crate::sys::mem_access::{MemoryAccessError, WasmRef, WasmSlice, WasmSlic 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}; pub use crate::sys::ptr::{Memory32, Memory64, MemorySize, WasmPtr, WasmPtr64}; -pub use crate::sys::store::Store; pub use crate::sys::tunables::BaseTunables; pub use crate::sys::value::Value; pub use target_lexicon::{Architecture, CallingConvention, OperatingSystem, Triple, HOST}; diff --git a/lib/api/src/sys/native.rs b/lib/api/src/sys/native.rs index 90fd7c14b36..654c1e13e81 100644 --- a/lib/api/src/sys/native.rs +++ b/lib/api/src/sys/native.rs @@ -15,7 +15,7 @@ use crate::sys::{ }; use wasmer_types::RawValue; -use super::store::OnCalledHandler; +use crate::store::OnCalledHandler; /// A WebAssembly function that can be called natively /// (using the Native ABI). diff --git a/lib/api/src/sys/native_type.rs b/lib/api/src/sys/native_type.rs index 765b5f6b2c1..afbe52dcfbe 100644 --- a/lib/api/src/sys/native_type.rs +++ b/lib/api/src/sys/native_type.rs @@ -8,7 +8,7 @@ use wasmer_vm::VMFuncRef; use crate::{ExternRef, Function, TypedFunction, WasmTypeList}; -use super::store::AsStoreMut; +use crate::store::AsStoreMut; /// `NativeWasmTypeInto` performs conversions from and into `NativeWasmType` /// types with a context. diff --git a/lib/api/src/sys/value.rs b/lib/api/src/sys/value.rs index fe4fb5c4b5f..89eb8b5276d 100644 --- a/lib/api/src/sys/value.rs +++ b/lib/api/src/sys/value.rs @@ -9,7 +9,7 @@ use wasmer_vm::{VMExternRef, VMFuncRef}; use crate::ExternRef; use crate::Function; -use super::store::AsStoreRef; +use crate::store::AsStoreRef; pub use wasmer_types::RawValue; From 24253b86a71c472d588251496824415c6bb75e8e Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Thu, 9 Feb 2023 21:12:03 +0100 Subject: [PATCH 10/81] Remove import_shared_memory --- lib/api/src/sys/imports.rs | 33 --------------------------------- lib/wasi/src/utils.rs | 31 ------------------------------- 2 files changed, 64 deletions(-) diff --git a/lib/api/src/sys/imports.rs b/lib/api/src/sys/imports.rs index 6c0f0b3d6dd..95bc58328b5 100644 --- a/lib/api/src/sys/imports.rs +++ b/lib/api/src/sys/imports.rs @@ -6,8 +6,6 @@ use std::collections::HashMap; use std::fmt; use wasmer_compiler::LinkError; use wasmer_types::ImportError; -#[cfg(feature = "compiler")] -use wasmer_vm::VMSharedMemory; /// All of the import data used when instantiating. /// @@ -123,37 +121,6 @@ impl Imports { .insert((ns.to_string(), name.to_string()), val.into()); } - /// Imports (any) shared memory into the imports. - /// (if the module does not import memory then this function is ignored) - #[cfg(feature = "compiler")] - pub fn import_shared_memory( - &mut self, - module: &Module, - store: &mut impl crate::AsStoreMut, - ) -> Option { - // Determine if shared memory needs to be created and imported - let shared_memory = module - .imports() - .memories() - .next() - .map(|a| *a.ty()) - .map(|ty| { - let style = store.as_store_ref().engine().tunables().memory_style(&ty); - VMSharedMemory::new(&ty, &style).unwrap() - }); - - if let Some(memory) = shared_memory { - self.define( - "env", - "memory", - crate::Memory::new_from_existing(store, memory.clone().into()), - ); - Some(memory) - } else { - None - } - } - /// Returns the contents of a namespace as an `Exports`. /// /// Returns `None` if the namespace doesn't exist. diff --git a/lib/wasi/src/utils.rs b/lib/wasi/src/utils.rs index c380b0ef4ed..9bf703f1cdc 100644 --- a/lib/wasi/src/utils.rs +++ b/lib/wasi/src/utils.rs @@ -50,37 +50,6 @@ pub fn map_io_err(err: std::io::Error) -> Errno { } } -/// Imports (any) shared memory into the imports. -/// (if the module does not import memory then this function is ignored) -#[cfg(not(feature = "js"))] -pub fn wasi_import_shared_memory( - imports: &mut Imports, - module: &Module, - store: &mut impl AsStoreMut, -) { - // Determine if shared memory needs to be created and imported - let shared_memory = module - .imports() - .memories() - .next() - .map(|a| *a.ty()) - .map(|ty| { - let style = store.as_store_ref().engine().tunables().memory_style(&ty); - VMSharedMemory::new(&ty, &style).unwrap() - }); - - if let Some(memory) = shared_memory { - // if the memory has already be defined, don't redefine it! - if !imports.exists("env", "memory") { - imports.define( - "env", - "memory", - wasmer::Memory::new_from_existing(store, memory.into()), - ); - } - }; -} -#[cfg(feature = "js")] pub fn wasi_import_shared_memory( _imports: &mut Imports, _module: &Module, From bb3492900e2d1d2031fb6524dbd2f77003a9f603 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Thu, 9 Feb 2023 16:46:01 -0800 Subject: [PATCH 11/81] Make function_env common for js/sys --- lib/api/src/{sys => }/function_env.rs | 15 ++- lib/api/src/js/externals/function.rs | 8 +- lib/api/src/js/function_env.rs | 174 -------------------------- lib/api/src/js/mod.rs | 4 +- lib/api/src/js/store.rs | 2 +- lib/api/src/js/vm.rs | 28 +++++ lib/api/src/lib.rs | 2 + lib/api/src/store.rs | 4 +- lib/api/src/sys/externals/function.rs | 2 +- lib/api/src/sys/mod.rs | 2 - 10 files changed, 52 insertions(+), 189 deletions(-) rename lib/api/src/{sys => }/function_env.rs (88%) delete mode 100644 lib/api/src/js/function_env.rs diff --git a/lib/api/src/sys/function_env.rs b/lib/api/src/function_env.rs similarity index 88% rename from lib/api/src/sys/function_env.rs rename to lib/api/src/function_env.rs index 6ef7b48a3c9..c5f65a64068 100644 --- a/lib/api/src/sys/function_env.rs +++ b/lib/api/src/function_env.rs @@ -1,8 +1,11 @@ use std::{any::Any, marker::PhantomData}; -use wasmer_vm::{StoreHandle, StoreObjects, VMFunctionEnvironment}; +#[cfg(feature = "js")] +use crate::js::vm::VMFunctionEnvironment; +#[cfg(feature = "sys")] +use wasmer_vm::VMFunctionEnvironment; -use crate::{AsStoreMut, AsStoreRef, StoreMut, StoreRef}; +use crate::store::{AsStoreMut, AsStoreRef, StoreHandle, StoreMut, StoreObjects, StoreRef}; #[derive(Debug)] #[repr(transparent)] @@ -40,6 +43,14 @@ impl FunctionEnv { .unwrap() } + #[allow(dead_code)] // This function is only used in js + pub(crate) fn from_handle(handle: StoreHandle) -> Self { + Self { + handle, + marker: PhantomData, + } + } + /// Get the data as mutable pub fn as_mut<'a>(&self, store: &'a mut impl AsStoreMut) -> &'a mut T where diff --git a/lib/api/src/js/externals/function.rs b/lib/api/src/js/externals/function.rs index 24236ec0277..0bba3cbb1e7 100644 --- a/lib/api/src/js/externals/function.rs +++ b/lib/api/src/js/externals/function.rs @@ -1,13 +1,13 @@ pub use self::inner::{FromToNativeWasmType, HostFunction, WasmTypeList, WithEnv, WithoutEnv}; +use crate::function_env::{FunctionEnv, FunctionEnvMut}; use crate::js::exports::{ExportError, Exportable}; use crate::js::externals::Extern; -use crate::js::function_env::FunctionEnvMut; use crate::js::types::{param_from_js, AsJs}; /* ValFuncRef */ use crate::js::vm::VMExtern; +use crate::js::FunctionType; use crate::js::RuntimeError; use crate::js::TypedFunction; use crate::js::Value; -use crate::js::{FunctionEnv, FunctionType}; use crate::store::{AsStoreMut, AsStoreRef, StoreMut}; use js_sys::{Array, Function as JSFunction}; use std::iter::FromIterator; @@ -629,9 +629,9 @@ impl fmt::Debug for Function { mod inner { use super::RuntimeError; use super::VMFunctionBody; - use crate::js::function_env::{FunctionEnvMut, VMFunctionEnvironment}; + use crate::function_env::{FunctionEnv, FunctionEnvMut}; use crate::js::store::{InternalStoreHandle, StoreHandle}; - use crate::js::FunctionEnv; + use crate::js::vm::VMFunctionEnvironment; use crate::js::NativeWasmTypeInto; use crate::store::{AsStoreMut, AsStoreRef, StoreMut}; use std::array::TryFromSliceError; diff --git a/lib/api/src/js/function_env.rs b/lib/api/src/js/function_env.rs deleted file mode 100644 index 6eca9771ad9..00000000000 --- a/lib/api/src/js/function_env.rs +++ /dev/null @@ -1,174 +0,0 @@ -use std::{any::Any, marker::PhantomData}; - -use crate::js::store::{StoreHandle, StoreObjects}; - -use crate::store::{AsStoreMut, AsStoreRef, StoreMut, StoreRef}; - -#[derive(Debug)] -#[repr(transparent)] -/// An opaque reference to a function environment. -/// The function environment data is owned by the `Store`. -pub struct FunctionEnv { - pub(crate) handle: StoreHandle, - marker: PhantomData, -} - -impl FunctionEnv { - /// Make a new extern reference - pub fn new(store: &mut impl AsStoreMut, value: T) -> Self - where - T: Any + Send + 'static + Sized, - { - Self { - handle: StoreHandle::new( - store.as_store_mut().objects_mut(), - VMFunctionEnvironment::new(value), - ), - marker: PhantomData, - } - } - - pub(crate) fn from_handle(handle: StoreHandle) -> Self { - Self { - handle, - marker: PhantomData, - } - } - - /// Get the data as reference - pub fn as_ref<'a>(&self, store: &'a impl AsStoreRef) -> &'a T - where - T: Any + Send + 'static + Sized, - { - self.handle - .get(store.as_store_ref().objects()) - .as_ref() - .downcast_ref::() - .unwrap() - } - - /// Get the data as mutable - pub fn as_mut<'a>(&self, store: &'a mut impl AsStoreMut) -> &'a mut T - where - T: Any + Send + 'static + Sized, - { - self.handle - .get_mut(store.objects_mut()) - .as_mut() - .downcast_mut::() - .unwrap() - } - - /// Convert it into a `FunctionEnvMut` - pub fn into_mut(self, store: &mut impl AsStoreMut) -> FunctionEnvMut - where - T: Any + Send + 'static + Sized, - { - FunctionEnvMut { - store_mut: store.as_store_mut(), - func_env: self, - } - } -} - -impl PartialEq for FunctionEnv { - fn eq(&self, other: &Self) -> bool { - self.handle == other.handle - } -} - -impl Eq for FunctionEnv {} - -impl std::hash::Hash for FunctionEnv { - fn hash(&self, state: &mut H) { - self.handle.hash(state); - self.marker.hash(state); - } -} - -impl Clone for FunctionEnv { - fn clone(&self) -> Self { - Self { - handle: self.handle.clone(), - marker: self.marker, - } - } -} - -/// A temporary handle to a [`Context`]. -pub struct FunctionEnvMut<'a, T: 'a> { - pub(crate) store_mut: StoreMut<'a>, - pub(crate) func_env: FunctionEnv, -} - -impl FunctionEnvMut<'_, T> { - /// Returns a reference to the host state in this context. - pub fn data(&self) -> &T { - self.func_env.as_ref(&self.store_mut) - } - - /// Returns a mutable- reference to the host state in this context. - pub fn data_mut<'a>(&'a mut self) -> &'a mut T { - self.func_env.as_mut(&mut self.store_mut) - } - - /// Borrows a new immmutable reference - pub fn as_ref(&self) -> FunctionEnv { - self.func_env.clone() - } - - /// Borrows a new mutable reference - pub fn as_mut<'a>(&'a mut self) -> FunctionEnvMut<'a, T> { - FunctionEnvMut { - store_mut: self.store_mut.as_store_mut(), - func_env: self.func_env.clone(), - } - } -} - -impl AsStoreRef for FunctionEnvMut<'_, T> { - fn as_store_ref(&self) -> StoreRef<'_> { - StoreRef { - inner: self.store_mut.inner, - } - } -} - -impl AsStoreMut for FunctionEnvMut<'_, T> { - fn as_store_mut(&mut self) -> StoreMut<'_> { - StoreMut { - inner: self.store_mut.inner, - } - } - #[inline] - fn objects_mut(&mut self) -> &mut StoreObjects { - &mut self.store_mut.inner.objects - } -} - -/// Underlying FunctionEnvironment used by a `VMFunction`. -#[derive(Debug)] -pub struct VMFunctionEnvironment { - contents: Box, -} - -impl VMFunctionEnvironment { - /// Wraps the given value to expose it to Wasm code as a function context. - pub fn new(val: impl Any + Send + 'static) -> Self { - Self { - contents: Box::new(val), - } - } - - #[allow(clippy::should_implement_trait)] - /// Returns a reference to the underlying value. - pub fn as_ref(&self) -> &(dyn Any + Send + 'static) { - &*self.contents - } - - #[allow(clippy::should_implement_trait)] - /// Returns a mutable reference to the underlying value. - pub fn as_mut(&mut self) -> &mut (dyn Any + Send + 'static) { - &mut *self.contents - } -} diff --git a/lib/api/src/js/mod.rs b/lib/api/src/js/mod.rs index 6f2584f989b..424fae92d02 100644 --- a/lib/api/src/js/mod.rs +++ b/lib/api/src/js/mod.rs @@ -27,7 +27,6 @@ pub(crate) mod engine; pub(crate) mod error; mod exports; mod externals; -mod function_env; mod imports; mod instance; mod mem_access; @@ -41,7 +40,7 @@ pub(crate) mod store; mod trap; mod types; mod value; -mod vm; +pub(crate) mod vm; mod wasm_bindgen_polyfill; pub use crate::js::engine::Engine; @@ -51,7 +50,6 @@ pub use crate::js::externals::{ Extern, FromToNativeWasmType, Function, Global, HostFunction, Memory, MemoryError, MemoryView, Table, WasmTypeList, }; -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}; diff --git a/lib/api/src/js/store.rs b/lib/api/src/js/store.rs index d4cd48e0693..eb20de275b8 100644 --- a/lib/api/src/js/store.rs +++ b/lib/api/src/js/store.rs @@ -4,7 +4,7 @@ pub use objects::{StoreHandle, StoreObjects}; mod objects { use wasm_bindgen::JsValue; - use crate::js::{function_env::VMFunctionEnvironment, vm::VMGlobal}; + use crate::js::vm::{VMFunctionEnvironment, VMGlobal}; use std::{fmt, marker::PhantomData, num::NonZeroUsize}; pub use wasmer_types::StoreId; diff --git a/lib/api/src/js/vm.rs b/lib/api/src/js/vm.rs index 5804a5471b2..26705ee38e2 100644 --- a/lib/api/src/js/vm.rs +++ b/lib/api/src/js/vm.rs @@ -15,6 +15,7 @@ use js_sys::WebAssembly; use js_sys::WebAssembly::{Memory, Table}; use js_sys::WebAssembly::{Memory as JsMemory, Table as JsTable}; use serde::{Deserialize, Serialize}; +use std::any::Any; use std::fmt; #[cfg(feature = "tracing")] use tracing::trace; @@ -255,3 +256,30 @@ impl VMExtern { } pub type VMInstance = WebAssembly::Instance; + +/// Underlying FunctionEnvironment used by a `VMFunction`. +#[derive(Debug)] +pub struct VMFunctionEnvironment { + contents: Box, +} + +impl VMFunctionEnvironment { + /// Wraps the given value to expose it to Wasm code as a function context. + pub fn new(val: impl Any + Send + 'static) -> Self { + Self { + contents: Box::new(val), + } + } + + #[allow(clippy::should_implement_trait)] + /// Returns a reference to the underlying value. + pub fn as_ref(&self) -> &(dyn Any + Send + 'static) { + &*self.contents + } + + #[allow(clippy::should_implement_trait)] + /// Returns a mutable reference to the underlying value. + pub fn as_mut(&mut self) -> &mut (dyn Any + Send + 'static) { + &mut *self.contents + } +} diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index 3c5efb8895c..f1a11d23a70 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -430,6 +430,7 @@ compile_error!( ); mod engine; +mod function_env; mod module; mod store; @@ -446,6 +447,7 @@ mod js; pub use js::*; pub use engine::{AsEngineRef, Engine}; +pub use function_env::{FunctionEnv, FunctionEnvMut}; pub use module::{IoCompileError, Module}; pub use store::{OnCalledHandler, Store, StoreId}; #[cfg(feature = "sys")] diff --git a/lib/api/src/store.rs b/lib/api/src/store.rs index c8c34a35a09..f32dd85a5db 100644 --- a/lib/api/src/store.rs +++ b/lib/api/src/store.rs @@ -10,10 +10,10 @@ use wasmer_vm::init_traps; pub use wasmer_vm::TrapHandlerFn; #[cfg(feature = "sys")] -pub use wasmer_vm::StoreObjects; +pub use wasmer_vm::{StoreHandle, StoreObjects}; #[cfg(feature = "js")] -pub use crate::js::store::StoreObjects; +pub use crate::js::store::{StoreHandle, StoreObjects}; /// Call handler for a store. // TODO: better documentation! diff --git a/lib/api/src/sys/externals/function.rs b/lib/api/src/sys/externals/function.rs index e9a93a877db..431dc8760fa 100644 --- a/lib/api/src/sys/externals/function.rs +++ b/lib/api/src/sys/externals/function.rs @@ -856,7 +856,7 @@ mod inner { use std::panic::{self, AssertUnwindSafe}; use wasmer_vm::{on_host_stack, VMContext, VMTrampoline}; - use crate::sys::function_env::FunctionEnvMut; + use crate::function_env::FunctionEnvMut; use wasmer_types::{NativeWasmType, RawValue, Type}; use wasmer_vm::{raise_user_trap, resume_panic, VMFunctionBody}; diff --git a/lib/api/src/sys/mod.rs b/lib/api/src/sys/mod.rs index 77ddacecf90..037e30c65c9 100644 --- a/lib/api/src/sys/mod.rs +++ b/lib/api/src/sys/mod.rs @@ -2,7 +2,6 @@ pub(crate) mod engine; mod exports; mod extern_ref; mod externals; -mod function_env; mod imports; mod instance; mod mem_access; @@ -21,7 +20,6 @@ pub use crate::sys::externals::{ Extern, FromToNativeWasmType, Function, Global, HostFunction, Memory, MemoryView, Table, WasmTypeList, }; -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}; From bd55e7b2a05e3361fd3cc76859c3e57bbd9d8b94 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Thu, 9 Feb 2023 16:46:08 -0800 Subject: [PATCH 12/81] Remove unused import in wasi --- lib/wasi/src/utils.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/wasi/src/utils.rs b/lib/wasi/src/utils.rs index 9bf703f1cdc..46f6cfafa02 100644 --- a/lib/wasi/src/utils.rs +++ b/lib/wasi/src/utils.rs @@ -1,6 +1,4 @@ use std::collections::BTreeSet; -#[cfg(not(feature = "js"))] -use wasmer::vm::VMSharedMemory; use wasmer::{AsStoreMut, Imports, Module}; use wasmer_wasi_types::wasi::Errno; From 039098ce2c67831f86a57b299b33c2ac147ac7dd Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Thu, 9 Feb 2023 16:52:48 -0800 Subject: [PATCH 13/81] Prepare mem_access commons --- lib/api/src/js/externals/memory_view.rs | 1 + lib/api/src/js/mem_access.rs | 14 +++++++------- lib/api/src/sys/externals/memory_view.rs | 1 + lib/api/src/sys/mem_access.rs | 4 ++-- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/lib/api/src/js/externals/memory_view.rs b/lib/api/src/js/externals/memory_view.rs index 65b5865fb54..e2622bb7a3d 100644 --- a/lib/api/src/js/externals/memory_view.rs +++ b/lib/api/src/js/externals/memory_view.rs @@ -103,6 +103,7 @@ impl<'a> MemoryView<'a> { Bytes(self.size as usize).try_into().unwrap() } + #[inline] pub(crate) fn buffer(&self) -> MemoryBuffer<'a> { MemoryBuffer { base: &self.view as *const _ as *mut _, diff --git a/lib/api/src/js/mem_access.rs b/lib/api/src/js/mem_access.rs index 5a9142e48e4..99084254dfc 100644 --- a/lib/api/src/js/mem_access.rs +++ b/lib/api/src/js/mem_access.rs @@ -30,12 +30,12 @@ pub enum MemoryAccessError { impl From for RuntimeError { fn from(err: MemoryAccessError) -> Self { - RuntimeError::new(err.to_string()) + Self::new(err.to_string()) } } impl From for MemoryAccessError { fn from(_err: FromUtf8Error) -> Self { - MemoryAccessError::NonUtf8String + Self::NonUtf8String } } @@ -158,7 +158,7 @@ impl<'a, T: ValueType> WasmSlice<'a, T> { /// /// Returns a `MemoryAccessError` if the slice length overflows. #[inline] - pub fn new(memory: &'a MemoryView, offset: u64, len: u64) -> Result { + pub fn new(view: &'a MemoryView, offset: u64, len: u64) -> Result { let total_len = len .checked_mul(mem::size_of::() as u64) .ok_or(MemoryAccessError::Overflow)?; @@ -166,7 +166,7 @@ impl<'a, T: ValueType> WasmSlice<'a, T> { .checked_add(total_len) .ok_or(MemoryAccessError::Overflow)?; Ok(Self { - buffer: memory.buffer(), + buffer: view.buffer(), offset, len, marker: PhantomData, @@ -197,7 +197,7 @@ impl<'a, T: ValueType> WasmSlice<'a, T> { self.len } - /// Return if the slice is empty. + /// Returns `true` if the number of elements is 0. #[inline] pub fn is_empty(&self) -> bool { self.len == 0 @@ -367,7 +367,7 @@ impl<'a, T: ValueType> Iterator for WasmSliceIter<'a, T> { type Item = WasmRef<'a, T>; fn next(&mut self) -> Option { - if self.slice.len() != 0 { + if !self.slice.is_empty() { let elem = self.slice.index(0); self.slice = self.slice.subslice(1..self.slice.len()); Some(elem) @@ -383,7 +383,7 @@ impl<'a, T: ValueType> Iterator for WasmSliceIter<'a, T> { impl<'a, T: ValueType> DoubleEndedIterator for WasmSliceIter<'a, T> { fn next_back(&mut self) -> Option { - if self.slice.len() != 0 { + if !self.slice.is_empty() { let elem = self.slice.index(self.slice.len() - 1); self.slice = self.slice.subslice(0..self.slice.len() - 1); Some(elem) diff --git a/lib/api/src/sys/externals/memory_view.rs b/lib/api/src/sys/externals/memory_view.rs index 0412a4f8a21..94044f8770e 100644 --- a/lib/api/src/sys/externals/memory_view.rs +++ b/lib/api/src/sys/externals/memory_view.rs @@ -96,6 +96,7 @@ impl<'a> MemoryView<'a> { self.size } + #[inline] pub(crate) fn buffer(&'a self) -> MemoryBuffer<'a> { self.buffer } diff --git a/lib/api/src/sys/mem_access.rs b/lib/api/src/sys/mem_access.rs index 8bceda732e9..9fd0793792e 100644 --- a/lib/api/src/sys/mem_access.rs +++ b/lib/api/src/sys/mem_access.rs @@ -64,7 +64,7 @@ impl<'a, T: ValueType> WasmRef<'a, T> { #[inline] pub fn new(view: &'a MemoryView, offset: u64) -> Self { Self { - buffer: view.buffer, + buffer: view.buffer(), offset, marker: PhantomData, } @@ -201,7 +201,7 @@ impl<'a, T: ValueType> WasmSlice<'a, T> { /// Returns `true` if the number of elements is 0. #[inline] - pub fn is_empty(self) -> bool { + pub fn is_empty(&self) -> bool { self.len == 0 } From 5a829bc363a6f7a46c7836f1cd39460f25e908e8 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Thu, 9 Feb 2023 17:59:30 -0800 Subject: [PATCH 14/81] Unify mem_access api for js/sys --- lib/api/src/js/externals/memory.rs | 3 +- lib/api/src/js/externals/memory_view.rs | 2 +- lib/api/src/js/mem_access.rs | 396 ------------------------ lib/api/src/js/mod.rs | 4 +- lib/api/src/js/ptr.rs | 2 +- lib/api/src/lib.rs | 2 + lib/api/src/{sys => }/mem_access.rs | 5 +- lib/api/src/sys/mod.rs | 4 +- lib/api/src/sys/ptr.rs | 2 +- 9 files changed, 13 insertions(+), 407 deletions(-) delete mode 100644 lib/api/src/js/mem_access.rs rename lib/api/src/{sys => }/mem_access.rs (98%) diff --git a/lib/api/src/js/externals/memory.rs b/lib/api/src/js/externals/memory.rs index e90bd8278e5..4115b7e988c 100644 --- a/lib/api/src/js/externals/memory.rs +++ b/lib/api/src/js/externals/memory.rs @@ -1,7 +1,8 @@ use crate::js::exports::{ExportError, Exportable}; use crate::js::externals::Extern; use crate::js::vm::{VMExtern, VMMemory}; -use crate::js::{MemoryAccessError, MemoryType}; +use crate::js::MemoryType; +use crate::mem_access::MemoryAccessError; use crate::store::{AsStoreMut, AsStoreRef, StoreObjects}; use std::marker::PhantomData; use std::mem::MaybeUninit; diff --git a/lib/api/src/js/externals/memory_view.rs b/lib/api/src/js/externals/memory_view.rs index e2622bb7a3d..03619cda812 100644 --- a/lib/api/src/js/externals/memory_view.rs +++ b/lib/api/src/js/externals/memory_view.rs @@ -1,4 +1,4 @@ -use crate::js::MemoryAccessError; +use crate::mem_access::MemoryAccessError; use crate::store::AsStoreRef; use std::convert::TryInto; use std::marker::PhantomData; diff --git a/lib/api/src/js/mem_access.rs b/lib/api/src/js/mem_access.rs deleted file mode 100644 index 99084254dfc..00000000000 --- a/lib/api/src/js/mem_access.rs +++ /dev/null @@ -1,396 +0,0 @@ -use crate::js::externals::memory::MemoryBuffer; -use crate::js::RuntimeError; -use crate::js::{Memory32, Memory64, MemoryView, WasmPtr}; -use std::{ - convert::TryInto, - fmt, - marker::PhantomData, - mem::{self, MaybeUninit}, - ops::Range, - slice, - string::FromUtf8Error, -}; -use thiserror::Error; -use wasmer_types::{MemorySize, ValueType}; - -/// Error for invalid [`Memory`] access. -#[derive(Clone, Copy, Debug, Error)] -#[non_exhaustive] -pub enum MemoryAccessError { - /// Memory access is outside heap bounds. - #[error("memory access out of bounds")] - HeapOutOfBounds, - /// Address calculation overflow. - #[error("address calculation overflow")] - Overflow, - /// String is not valid UTF-8. - #[error("string is not valid utf-8")] - NonUtf8String, -} - -impl From for RuntimeError { - fn from(err: MemoryAccessError) -> Self { - Self::new(err.to_string()) - } -} -impl From for MemoryAccessError { - fn from(_err: FromUtf8Error) -> Self { - Self::NonUtf8String - } -} - -/// Reference to a value in Wasm memory. -/// -/// The type of the value must satisfy the requirements of the `ValueType` -/// trait which guarantees that reading and writing such a value to untrusted -/// memory is safe. -/// -/// The address is not required to be aligned: unaligned accesses are fully -/// supported. -/// -/// This wrapper safely handles concurrent modifications of the data by another -/// thread. -#[derive(Clone, Copy)] -pub struct WasmRef<'a, T: ValueType> { - buffer: MemoryBuffer<'a>, - offset: u64, - marker: PhantomData<*mut T>, -} - -impl<'a, T: ValueType> WasmRef<'a, T> { - /// Creates a new `WasmRef` at the given offset in a memory. - #[inline] - pub fn new(view: &'a MemoryView, offset: u64) -> Self { - Self { - buffer: view.buffer(), - offset, - marker: PhantomData, - } - } - - /// Get the offset into Wasm linear memory for this `WasmRef`. - #[inline] - pub fn offset(self) -> u64 { - self.offset - } - - /// Get a `WasmPtr` for this `WasmRef`. - #[inline] - pub fn as_ptr32(self) -> WasmPtr { - WasmPtr::new(self.offset as u32) - } - - /// Get a 64-bit `WasmPtr` for this `WasmRef`. - #[inline] - pub fn as_ptr64(self) -> WasmPtr { - WasmPtr::new(self.offset) - } - - /// Get a `WasmPtr` fror this `WasmRef`. - #[inline] - pub fn as_ptr(self) -> WasmPtr { - let offset: M::Offset = self - .offset - .try_into() - .map_err(|_| "invalid offset into memory") - .unwrap(); - WasmPtr::::new(offset) - } - - /// Reads the location pointed to by this `WasmRef`. - #[inline] - pub fn read(self) -> Result { - let mut out = MaybeUninit::uninit(); - let buf = - unsafe { slice::from_raw_parts_mut(out.as_mut_ptr() as *mut u8, mem::size_of::()) }; - self.buffer.read(self.offset, buf)?; - Ok(unsafe { out.assume_init() }) - } - - /// Writes to the location pointed to by this `WasmRef`. - #[inline] - pub fn write(self, val: T) -> Result<(), MemoryAccessError> { - let mut data = MaybeUninit::new(val); - let data = unsafe { - slice::from_raw_parts_mut( - data.as_mut_ptr() as *mut MaybeUninit, - mem::size_of::(), - ) - }; - val.zero_padding_bytes(data); - let data = unsafe { slice::from_raw_parts(data.as_ptr() as *const _, data.len()) }; - self.buffer.write(self.offset, data) - } -} - -impl<'a, T: ValueType> fmt::Debug for WasmRef<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "WasmRef(offset: {}, pointer: {:#x})", - self.offset, self.offset - ) - } -} - -/// Reference to an array of values in Wasm memory. -/// -/// The type of the value must satisfy the requirements of the `ValueType` -/// trait which guarantees that reading and writing such a value to untrusted -/// memory is safe. -/// -/// The address is not required to be aligned: unaligned accesses are fully -/// supported. -/// -/// This wrapper safely handles concurrent modifications of the data by another -/// thread. -#[derive(Clone, Copy)] -pub struct WasmSlice<'a, T: ValueType> { - buffer: MemoryBuffer<'a>, - offset: u64, - len: u64, - marker: PhantomData<*mut T>, -} - -impl<'a, T: ValueType> WasmSlice<'a, T> { - /// Creates a new `WasmSlice` starting at the given offset in memory and - /// with the given number of elements. - /// - /// Returns a `MemoryAccessError` if the slice length overflows. - #[inline] - pub fn new(view: &'a MemoryView, offset: u64, len: u64) -> Result { - let total_len = len - .checked_mul(mem::size_of::() as u64) - .ok_or(MemoryAccessError::Overflow)?; - offset - .checked_add(total_len) - .ok_or(MemoryAccessError::Overflow)?; - Ok(Self { - buffer: view.buffer(), - offset, - len, - marker: PhantomData, - }) - } - - /// Get the offset into Wasm linear memory for this `WasmSlice`. - #[inline] - pub fn offset(self) -> u64 { - self.offset - } - - /// Get a 32-bit `WasmPtr` for this `WasmRef`. - #[inline] - pub fn as_ptr32(self) -> WasmPtr { - WasmPtr::new(self.offset as u32) - } - - /// Get a 64-bit `WasmPtr` for this `WasmRef`. - #[inline] - pub fn as_ptr64(self) -> WasmPtr { - WasmPtr::new(self.offset) - } - - /// Get the number of elements in this slice. - #[inline] - pub fn len(self) -> u64 { - self.len - } - - /// Returns `true` if the number of elements is 0. - #[inline] - pub fn is_empty(&self) -> bool { - self.len == 0 - } - - /// Get a `WasmRef` to an element in the slice. - #[inline] - pub fn index(self, idx: u64) -> WasmRef<'a, T> { - if idx >= self.len { - panic!("WasmSlice out of bounds"); - } - let offset = self.offset + idx * mem::size_of::() as u64; - WasmRef { - buffer: self.buffer, - offset, - marker: PhantomData, - } - } - - /// Get a `WasmSlice` for a subslice of this slice. - #[inline] - pub fn subslice(self, range: Range) -> WasmSlice<'a, T> { - if range.start > range.end || range.end > self.len { - panic!("WasmSlice out of bounds"); - } - let offset = self.offset + range.start * mem::size_of::() as u64; - Self { - buffer: self.buffer, - offset, - len: range.end - range.start, - marker: PhantomData, - } - } - - /// Get an iterator over the elements in this slice. - #[inline] - pub fn iter(self) -> WasmSliceIter<'a, T> { - WasmSliceIter { slice: self } - } - - /// Reads an element of this slice. - #[inline] - pub fn read(self, idx: u64) -> Result { - self.index(idx).read() - } - - /// Writes to an element of this slice. - #[inline] - pub fn write(self, idx: u64, val: T) -> Result<(), MemoryAccessError> { - self.index(idx).write(val) - } - - /// Reads the entire slice into the given buffer. - /// - /// The length of the buffer must match the length of the slice. - #[inline] - pub fn read_slice(self, buf: &mut [T]) -> Result<(), MemoryAccessError> { - assert_eq!( - buf.len() as u64, - self.len, - "slice length doesn't match WasmSlice length" - ); - let bytes = unsafe { - slice::from_raw_parts_mut( - buf.as_mut_ptr() as *mut MaybeUninit, - buf.len() * mem::size_of::(), - ) - }; - self.buffer.read_uninit(self.offset, bytes)?; - Ok(()) - } - - /// Reads the entire slice into the given uninitialized buffer. - /// - /// The length of the buffer must match the length of the slice. - /// - /// This method returns an initialized view of the buffer. - #[inline] - pub fn read_slice_uninit( - self, - buf: &mut [MaybeUninit], - ) -> Result<&mut [T], MemoryAccessError> { - assert_eq!( - buf.len() as u64, - self.len, - "slice length doesn't match WasmSlice length" - ); - let bytes = unsafe { - slice::from_raw_parts_mut( - buf.as_mut_ptr() as *mut MaybeUninit, - buf.len() * mem::size_of::(), - ) - }; - self.buffer.read_uninit(self.offset, bytes)?; - Ok(unsafe { slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut T, buf.len()) }) - } - - /// Write the given slice into this `WasmSlice`. - /// - /// The length of the slice must match the length of the `WasmSlice`. - #[inline] - pub fn write_slice(self, data: &[T]) -> Result<(), MemoryAccessError> { - assert_eq!( - data.len() as u64, - self.len, - "slice length doesn't match WasmSlice length" - ); - let bytes = unsafe { - slice::from_raw_parts(data.as_ptr() as *const u8, data.len() * mem::size_of::()) - }; - self.buffer.write(self.offset, bytes) - } - - /// Reads this `WasmSlice` into a `Vec`. - #[inline] - pub fn read_to_vec(self) -> Result, MemoryAccessError> { - let len = self.len.try_into().expect("WasmSlice length overflow"); - let mut vec = Vec::with_capacity(len); - let bytes = unsafe { - slice::from_raw_parts_mut( - vec.as_mut_ptr() as *mut MaybeUninit, - len * mem::size_of::(), - ) - }; - self.buffer.read_uninit(self.offset, bytes)?; - unsafe { - vec.set_len(len); - } - Ok(vec) - } - - /// Reads this `WasmSlice` into a `BytesMut` - #[inline] - pub fn read_to_bytes(self) -> Result { - let len = self.len.try_into().expect("WasmSlice length overflow"); - let mut ret = bytes::BytesMut::with_capacity(len); - let bytes = unsafe { - slice::from_raw_parts_mut( - ret.as_mut_ptr() as *mut MaybeUninit, - len * mem::size_of::(), - ) - }; - self.buffer.read_uninit(self.offset, bytes)?; - unsafe { - ret.set_len(len); - } - Ok(ret) - } -} - -impl<'a, T: ValueType> fmt::Debug for WasmSlice<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "WasmSlice(offset: {}, len: {}, pointer: {:#x})", - self.offset, self.len, self.offset - ) - } -} - -/// Iterator over the elements of a `WasmSlice`. -pub struct WasmSliceIter<'a, T: ValueType> { - slice: WasmSlice<'a, T>, -} - -impl<'a, T: ValueType> Iterator for WasmSliceIter<'a, T> { - type Item = WasmRef<'a, T>; - - fn next(&mut self) -> Option { - if !self.slice.is_empty() { - let elem = self.slice.index(0); - self.slice = self.slice.subslice(1..self.slice.len()); - Some(elem) - } else { - None - } - } - - fn size_hint(&self) -> (usize, Option) { - (0..self.slice.len()).size_hint() - } -} - -impl<'a, T: ValueType> DoubleEndedIterator for WasmSliceIter<'a, T> { - fn next_back(&mut self) -> Option { - if !self.slice.is_empty() { - let elem = self.slice.index(self.slice.len() - 1); - self.slice = self.slice.subslice(0..self.slice.len() - 1); - Some(elem) - } else { - None - } - } -} - -impl<'a, T: ValueType> ExactSizeIterator for WasmSliceIter<'a, T> {} diff --git a/lib/api/src/js/mod.rs b/lib/api/src/js/mod.rs index 424fae92d02..1ce7da1c9ea 100644 --- a/lib/api/src/js/mod.rs +++ b/lib/api/src/js/mod.rs @@ -26,10 +26,9 @@ mod lib { pub(crate) mod engine; pub(crate) mod error; mod exports; -mod externals; +pub(crate) mod externals; mod imports; mod instance; -mod mem_access; pub(crate) mod module; #[cfg(feature = "wasm-types-polyfill")] mod module_info_polyfill; @@ -52,7 +51,6 @@ pub use crate::js::externals::{ }; 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::{Module, ModuleTypeHints}; pub use crate::js::native::TypedFunction; pub use crate::js::native_type::NativeWasmTypeInto; diff --git a/lib/api/src/js/ptr.rs b/lib/api/src/js/ptr.rs index ae41e470211..0f6f6e0f5b8 100644 --- a/lib/api/src/js/ptr.rs +++ b/lib/api/src/js/ptr.rs @@ -1,6 +1,6 @@ use crate::js::NativeWasmTypeInto; use crate::js::{externals::MemoryView, FromToNativeWasmType}; -use crate::js::{MemoryAccessError, WasmRef, WasmSlice}; +use crate::mem_access::{MemoryAccessError, WasmRef, WasmSlice}; use crate::store::AsStoreRef; use std::convert::TryFrom; use std::{fmt, marker::PhantomData, mem}; diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index f1a11d23a70..db54194c7d1 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -431,6 +431,7 @@ compile_error!( mod engine; mod function_env; +mod mem_access; mod module; mod store; @@ -448,6 +449,7 @@ pub use js::*; pub use engine::{AsEngineRef, Engine}; pub use function_env::{FunctionEnv, FunctionEnvMut}; +pub use mem_access::{MemoryAccessError, WasmRef, WasmSlice, WasmSliceIter}; pub use module::{IoCompileError, Module}; pub use store::{OnCalledHandler, Store, StoreId}; #[cfg(feature = "sys")] diff --git a/lib/api/src/sys/mem_access.rs b/lib/api/src/mem_access.rs similarity index 98% rename from lib/api/src/sys/mem_access.rs rename to lib/api/src/mem_access.rs index 9fd0793792e..7c55baaf1cd 100644 --- a/lib/api/src/sys/mem_access.rs +++ b/lib/api/src/mem_access.rs @@ -13,7 +13,10 @@ use std::{ use thiserror::Error; use wasmer_types::ValueType; -use super::externals::memory::MemoryBuffer; +#[cfg(feature = "js")] +use crate::js::externals::memory::MemoryBuffer; +#[cfg(feature = "sys")] +use crate::sys::externals::memory::MemoryBuffer; /// Error for invalid [`Memory`] access. #[derive(Clone, Copy, Debug, Error)] diff --git a/lib/api/src/sys/mod.rs b/lib/api/src/sys/mod.rs index 037e30c65c9..ef039ef8be7 100644 --- a/lib/api/src/sys/mod.rs +++ b/lib/api/src/sys/mod.rs @@ -1,10 +1,9 @@ pub(crate) mod engine; mod exports; mod extern_ref; -mod externals; +pub(crate) mod externals; mod imports; mod instance; -mod mem_access; pub(crate) mod module; mod native; mod native_type; @@ -22,7 +21,6 @@ pub use crate::sys::externals::{ }; 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::Module; pub use crate::sys::native::TypedFunction; pub use crate::sys::native_type::NativeWasmTypeInto; diff --git a/lib/api/src/sys/ptr.rs b/lib/api/src/sys/ptr.rs index 1f51c203094..586cf27971a 100644 --- a/lib/api/src/sys/ptr.rs +++ b/lib/api/src/sys/ptr.rs @@ -1,6 +1,6 @@ +use crate::mem_access::{MemoryAccessError, WasmRef, WasmSlice}; use crate::sys::{externals::MemoryView, FromToNativeWasmType}; use crate::NativeWasmTypeInto; -use crate::{MemoryAccessError, WasmRef, WasmSlice}; use std::convert::TryFrom; use std::{fmt, marker::PhantomData, mem}; use wasmer_types::ValueType; From 543e7cb945ae8add7969e0b41ae0c3250bac4c2e Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Fri, 10 Feb 2023 08:05:07 -0800 Subject: [PATCH 15/81] Make CI happy. Fix linting and imports --- Cargo.lock | 4 ++-- lib/api/src/lib.rs | 2 +- lib/api/src/mem_access.rs | 2 +- lib/api/src/module.rs | 8 ++++---- lib/api/src/sys/externals/function.rs | 3 ++- lib/api/src/sys/externals/mod.rs | 2 +- lib/api/src/sys/mod.rs | 3 --- lib/api/src/sys/native.rs | 6 ++---- lib/cli-compiler/src/commands/compile.rs | 2 +- lib/cli/src/commands/gen_c_header.rs | 2 +- lib/wasi/src/syscalls/wasix32.rs | 2 +- lib/wasi/src/syscalls/wasix64.rs | 2 +- 12 files changed, 17 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6ce7ebaecdd..53f7f77ab39 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1942,9 +1942,9 @@ dependencies = [ [[package]] name = "llvm-sys" -version = "120.2.5" +version = "120.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1c9655eec036faf512507746ce70765bda72ed98e52b4328f0d7b93e970c6d8" +checksum = "909fd0ded1d3becfa3d52581b33602d87160d63da6a3844a86a51b0c93e8460c" dependencies = [ "cc", "lazy_static", diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index db54194c7d1..891f55b0bd3 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -451,7 +451,7 @@ pub use engine::{AsEngineRef, Engine}; pub use function_env::{FunctionEnv, FunctionEnvMut}; pub use mem_access::{MemoryAccessError, WasmRef, WasmSlice, WasmSliceIter}; pub use module::{IoCompileError, Module}; -pub use store::{OnCalledHandler, Store, StoreId}; +pub use store::{AsStoreMut, AsStoreRef, OnCalledHandler, Store, StoreId, StoreMut, StoreRef}; #[cfg(feature = "sys")] pub use store::{TrapHandlerFn, Tunables}; diff --git a/lib/api/src/mem_access.rs b/lib/api/src/mem_access.rs index 7c55baaf1cd..9bffc7a2a04 100644 --- a/lib/api/src/mem_access.rs +++ b/lib/api/src/mem_access.rs @@ -204,7 +204,7 @@ impl<'a, T: ValueType> WasmSlice<'a, T> { /// Returns `true` if the number of elements is 0. #[inline] - pub fn is_empty(&self) -> bool { + pub fn is_empty(self) -> bool { self.len == 0 } diff --git a/lib/api/src/module.rs b/lib/api/src/module.rs index 66c9cf22a5a..0e53a9d8ef4 100644 --- a/lib/api/src/module.rs +++ b/lib/api/src/module.rs @@ -145,7 +145,7 @@ impl Module { /// the WebAssembly text format (if the "wat" feature is enabled for /// this crate). pub fn from_binary(engine: &impl AsEngineRef, binary: &[u8]) -> Result { - Ok(Module(module_imp::Module::from_binary(engine, binary)?)) + Ok(Self(module_imp::Module::from_binary(engine, binary)?)) } /// Creates a new WebAssembly module skipping any kind of validation. @@ -159,7 +159,7 @@ impl Module { engine: &impl AsEngineRef, binary: &[u8], ) -> Result { - Ok(Module(module_imp::Module::from_binary_unchecked( + Ok(Self(module_imp::Module::from_binary_unchecked( engine, binary, )?)) } @@ -239,7 +239,7 @@ impl Module { engine: &impl AsEngineRef, bytes: impl IntoBytes, ) -> Result { - Ok(Module(module_imp::Module::deserialize(engine, bytes)?)) + Ok(Self(module_imp::Module::deserialize(engine, bytes)?)) } /// Deserializes a a serialized Module located in a `Path` into a `Module`. @@ -263,7 +263,7 @@ impl Module { engine: &impl AsEngineRef, path: impl AsRef, ) -> Result { - Ok(Module(module_imp::Module::deserialize_from_file( + Ok(Self(module_imp::Module::deserialize_from_file( engine, path, )?)) } diff --git a/lib/api/src/sys/externals/function.rs b/lib/api/src/sys/externals/function.rs index 431dc8760fa..ba8252a8fed 100644 --- a/lib/api/src/sys/externals/function.rs +++ b/lib/api/src/sys/externals/function.rs @@ -860,8 +860,9 @@ mod inner { use wasmer_types::{NativeWasmType, RawValue, Type}; use wasmer_vm::{raise_user_trap, resume_panic, VMFunctionBody}; + use crate::store::{AsStoreMut, AsStoreRef, StoreMut}; use crate::sys::NativeWasmTypeInto; - use crate::{AsStoreMut, AsStoreRef, ExternRef, FunctionEnv, StoreMut}; + use crate::{ExternRef, FunctionEnv}; use crate::Function; diff --git a/lib/api/src/sys/externals/mod.rs b/lib/api/src/sys/externals/mod.rs index b54d94b901b..452d44cd825 100644 --- a/lib/api/src/sys/externals/mod.rs +++ b/lib/api/src/sys/externals/mod.rs @@ -16,7 +16,7 @@ use crate::sys::ExternType; use std::fmt; use wasmer_vm::VMExtern; -use super::{AsStoreMut, AsStoreRef}; +use crate::store::{AsStoreMut, AsStoreRef}; /// An `Extern` is the runtime representation of an entity that /// can be imported or exported. diff --git a/lib/api/src/sys/mod.rs b/lib/api/src/sys/mod.rs index ef039ef8be7..c94405cc247 100644 --- a/lib/api/src/sys/mod.rs +++ b/lib/api/src/sys/mod.rs @@ -11,8 +11,6 @@ mod ptr; mod tunables; mod value; -pub use crate::store::{AsStoreMut, AsStoreRef, Store, StoreMut, StoreRef}; -pub use crate::sys::engine::Engine; pub use crate::sys::exports::{ExportError, Exportable, Exports, ExportsIterator}; pub use crate::sys::extern_ref::ExternRef; pub use crate::sys::externals::{ @@ -21,7 +19,6 @@ pub use crate::sys::externals::{ }; pub use crate::sys::imports::Imports; pub use crate::sys::instance::{Instance, InstantiationError}; -pub use crate::sys::module::Module; pub use crate::sys::native::TypedFunction; pub use crate::sys::native_type::NativeWasmTypeInto; diff --git a/lib/api/src/sys/native.rs b/lib/api/src/sys/native.rs index 654c1e13e81..16c93d0cda2 100644 --- a/lib/api/src/sys/native.rs +++ b/lib/api/src/sys/native.rs @@ -10,12 +10,10 @@ use std::cell::Cell; use std::marker::PhantomData; -use crate::sys::{ - AsStoreMut, FromToNativeWasmType, Function, NativeWasmTypeInto, RuntimeError, WasmTypeList, -}; +use crate::sys::{FromToNativeWasmType, Function, NativeWasmTypeInto, RuntimeError, WasmTypeList}; use wasmer_types::RawValue; -use crate::store::OnCalledHandler; +use crate::store::{AsStoreMut, OnCalledHandler}; /// A WebAssembly function that can be called natively /// (using the Native ABI). diff --git a/lib/cli-compiler/src/commands/compile.rs b/lib/cli-compiler/src/commands/compile.rs index 5052a4bf810..6efc44c9a5e 100644 --- a/lib/cli-compiler/src/commands/compile.rs +++ b/lib/cli-compiler/src/commands/compile.rs @@ -106,7 +106,7 @@ impl Compile { memory_styles, table_styles, )?; - let serialized = artifact.serialize(self.output.as_ref())?; + let serialized = artifact.serialize()?; fs::write(output_filename, serialized)?; eprintln!( "✔ File compiled successfully to `{}`.", diff --git a/lib/cli/src/commands/gen_c_header.rs b/lib/cli/src/commands/gen_c_header.rs index 2a309af21a6..aa796408f58 100644 --- a/lib/cli/src/commands/gen_c_header.rs +++ b/lib/cli/src/commands/gen_c_header.rs @@ -96,7 +96,7 @@ impl GenCHeader { let engine_inner = engine.inner(); let compiler = engine_inner.compiler()?; let features = engine_inner.features(); - let tunables = store.tunables(); + let tunables = store.engine().tunables(); let (metadata, _, _) = Artifact::metadata( compiler, &file, diff --git a/lib/wasi/src/syscalls/wasix32.rs b/lib/wasi/src/syscalls/wasix32.rs index 0683cdfa1ca..5d53adabf52 100644 --- a/lib/wasi/src/syscalls/wasix32.rs +++ b/lib/wasi/src/syscalls/wasix32.rs @@ -1,6 +1,6 @@ #![deny(dead_code)] use crate::{WasiEnv, WasiError, WasiState, WasiThread}; -use wasmer::{FunctionEnvMut, Memory, Memory32, MemorySize, StoreMut, WasmPtr, WasmSlice}; +use wasmer::{FunctionEnvMut, Memory, Memory32, MemorySize, WasmPtr, WasmSlice}; use wasmer_wasi_types::types::*; use wasmer_wasi_types::wasi::{ Addressfamily, Advice, Bid, BusDataFormat, BusErrno, BusHandles, Cid, Clockid, Dircookie, diff --git a/lib/wasi/src/syscalls/wasix64.rs b/lib/wasi/src/syscalls/wasix64.rs index d5291ebeca2..7c2792d4d63 100644 --- a/lib/wasi/src/syscalls/wasix64.rs +++ b/lib/wasi/src/syscalls/wasix64.rs @@ -1,6 +1,6 @@ #![deny(dead_code)] use crate::{WasiEnv, WasiError, WasiState, WasiThread}; -use wasmer::{FunctionEnvMut, Memory, Memory64, MemorySize, StoreMut, WasmPtr, WasmSlice}; +use wasmer::{FunctionEnvMut, Memory, Memory64, MemorySize, WasmPtr, WasmSlice}; use wasmer_wasi_types::types::*; use wasmer_wasi_types::wasi::{ Addressfamily, Advice, Bid, BusDataFormat, BusErrno, BusHandles, Cid, Clockid, Dircookie, From 293834c793628d338ce46c4f2fc0ba43f38a09c0 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Fri, 10 Feb 2023 08:21:55 -0800 Subject: [PATCH 16/81] Fix pending test --- lib/api/src/sys/imports.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/api/src/sys/imports.rs b/lib/api/src/sys/imports.rs index 95bc58328b5..eff13e7d9d8 100644 --- a/lib/api/src/sys/imports.rs +++ b/lib/api/src/sys/imports.rs @@ -305,7 +305,8 @@ macro_rules! import_namespace { #[cfg(test)] mod test { - use crate::sys::{AsStoreMut, Global, Store, Value}; + use crate::store::{Store, AsStoreMut}; + use crate::sys::{Global, Value}; use wasmer_types::Type; use wasmer_vm::VMExtern; From 59a6b197fc410086ddbd1db2a6765252fdf73230 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Fri, 10 Feb 2023 08:26:14 -0800 Subject: [PATCH 17/81] Fix linting --- lib/api/src/sys/imports.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/api/src/sys/imports.rs b/lib/api/src/sys/imports.rs index eff13e7d9d8..6bdfa2ac77d 100644 --- a/lib/api/src/sys/imports.rs +++ b/lib/api/src/sys/imports.rs @@ -305,7 +305,7 @@ macro_rules! import_namespace { #[cfg(test)] mod test { - use crate::store::{Store, AsStoreMut}; + use crate::store::{AsStoreMut, Store}; use crate::sys::{Global, Value}; use wasmer_types::Type; use wasmer_vm::VMExtern; From 312aaf1e16e6ef78af828eb73be698048edbdf6d Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Fri, 10 Feb 2023 15:11:56 -0800 Subject: [PATCH 18/81] Use RawValue for wasmer js --- lib/api/src/js/externals/function.rs | 22 +++++------ lib/api/src/js/externals/global.rs | 30 +++++++++++++- lib/api/src/js/native.rs | 4 +- lib/api/src/js/native_type.rs | 48 +++++++++++------------ lib/api/src/js/types.rs | 2 +- lib/api/src/js/value.rs | 58 ++++++++++++++-------------- lib/types/src/value.rs | 56 +++++++++++++++++++++++++++ 7 files changed, 151 insertions(+), 69 deletions(-) diff --git a/lib/api/src/js/externals/function.rs b/lib/api/src/js/externals/function.rs index 0bba3cbb1e7..64f57bdc25a 100644 --- a/lib/api/src/js/externals/function.rs +++ b/lib/api/src/js/externals/function.rs @@ -405,7 +405,7 @@ impl Function { let params: Vec<_> = unsafe { params .iter() - .map(|a| a.as_raw_value(&store.as_store_ref())) + .map(|a| a.as_raw(&store.as_store_ref())) .collect() }; let arr = js_sys::Array::new_with_length(params.len() as u32); @@ -640,7 +640,7 @@ mod inner { use std::marker::PhantomData; use std::panic::{self, AssertUnwindSafe}; - use wasmer_types::{FunctionType, NativeWasmType, Type}; + use wasmer_types::{FunctionType, NativeWasmType, RawValue, Type}; // use wasmer::{raise_user_trap, resume_panic}; /// A trait to convert a Rust value to a `WasmNativeType` value, @@ -783,7 +783,7 @@ mod inner { /// The array type that can hold all the represented values. /// /// Note that all values are stored in their binary form. - type Array: AsMut<[f64]>; + type Array: AsMut<[RawValue]>; /// The size of the array fn size() -> u32; @@ -803,7 +803,7 @@ mod inner { /// # Safety unsafe fn from_slice( store: &mut impl AsStoreMut, - slice: &[f64], + slice: &[RawValue], ) -> Result; /// Builds and returns an array of type `Array` from a tuple @@ -1037,7 +1037,7 @@ mod inner { { type CStruct = $c_struct_name< $( $x ),* >; - type Array = [f64; count_idents!( $( $x ),* )]; + type Array = [RawValue; count_idents!( $( $x ),* )]; fn size() -> u32 { count_idents!( $( $x ),* ) as _ @@ -1054,13 +1054,13 @@ mod inner { // Build the tuple. ( $( - FromToNativeWasmType::from_native(NativeWasmTypeInto::from_raw(_store, $x)) + FromToNativeWasmType::from_native(NativeWasmTypeInto::from_raw(_store, $x.into())) ),* ) } #[allow(clippy::missing_safety_doc)] - unsafe fn from_slice(store: &mut impl AsStoreMut, slice: &[f64]) -> Result { + unsafe fn from_slice(store: &mut impl AsStoreMut, slice: &[RawValue]) -> Result { Ok(Self::from_array(store, slice.try_into()?)) } @@ -1081,7 +1081,7 @@ mod inner { fn empty_array() -> Self::Array { // Build an array initialized with `0`. - [0_f64; count_idents!( $( $x ),* )] + [RawValue { i32: 0 }; count_idents!( $( $x ),* )] } #[allow(unused_mut)] @@ -1094,7 +1094,7 @@ mod inner { ( $( - FromToNativeWasmType::from_native(NativeWasmTypeInto::from_abi(_store, $x)) + FromToNativeWasmType::from_native(NativeWasmTypeInto::from_abi(_store, $x.into())) ),* ) } @@ -1288,7 +1288,7 @@ mod inner { // fail (with `Result<_, Infallible>`). impl WasmTypeList for Infallible { type CStruct = Self; - type Array = [f64; 0]; + type Array = [RawValue; 0]; fn size() -> u32 { 0 @@ -1300,7 +1300,7 @@ mod inner { unsafe fn from_slice( _: &mut impl AsStoreMut, - _: &[f64], + _: &[RawValue], ) -> Result { unreachable!() } diff --git a/lib/api/src/js/externals/global.rs b/lib/api/src/js/externals/global.rs index cdc61360279..558a35a517d 100644 --- a/lib/api/src/js/externals/global.rs +++ b/lib/api/src/js/externals/global.rs @@ -8,6 +8,7 @@ use crate::js::Mutability; use crate::js::RuntimeError; use crate::store::{AsStoreMut, AsStoreRef}; use wasm_bindgen::JsValue; +use wasmer_types::{RawValue, Type}; /// A WebAssembly `global` instance. /// @@ -130,8 +131,35 @@ impl Global { /// ``` pub fn get(&self, store: &impl AsStoreRef) -> Value { unsafe { - let raw = self.handle.global.value().as_f64().unwrap(); + let value = self.handle.global.value(); let ty = self.handle.ty; + let raw = match ty.ty { + Type::I32 => RawValue { + i32: value.as_f64().unwrap() as _, + }, + Type::I64 => RawValue { + i64: value.as_f64().unwrap() as _, + }, + Type::F32 => RawValue { + f32: value.as_f64().unwrap() as _, + }, + Type::F64 => RawValue { + f64: value.as_f64().unwrap(), + }, + Type::V128 => RawValue { + u128: value.as_f64().unwrap() as _, + }, + Type::FuncRef => { + unimplemented!(); + // Self::FuncRef(VMFuncRef::from_raw(raw).map(|f| Function::from_vm_funcref(store, f))) + } + Type::ExternRef => { + unimplemented!(); + // Self::ExternRef( + // VMExternRef::from_raw(raw).map(|e| ExternRef::from_vm_externref(store, e)), + // ) + } + }; Value::from_raw(store, ty.ty, raw) } } diff --git a/lib/api/src/js/native.rs b/lib/api/src/js/native.rs index db718de1d0d..8ab3858ce77 100644 --- a/lib/api/src/js/native.rs +++ b/lib/api/src/js/native.rs @@ -68,7 +68,7 @@ macro_rules! impl_native_traits { { #[allow(unused_unsafe)] let params_list: Vec = unsafe { - vec![ $( RawValue { f64: $x.into_raw(store) } ),* ] + vec![ $( $x.into_raw(store) ),* ] }; let params_list: Vec = params_list .into_iter() @@ -96,7 +96,7 @@ macro_rules! impl_native_traits { r? }; let mut rets_list_array = Rets::empty_array(); - let mut_rets = rets_list_array.as_mut() as *mut [f64] as *mut f64; + let mut_rets = rets_list_array.as_mut() as *mut [RawValue] as *mut RawValue; match Rets::size() { 0 => {}, 1 => unsafe { diff --git a/lib/api/src/js/native_type.rs b/lib/api/src/js/native_type.rs index ec7e92c786e..597211fc304 100644 --- a/lib/api/src/js/native_type.rs +++ b/lib/api/src/js/native_type.rs @@ -1,7 +1,7 @@ //! This module permits to create native functions //! easily in Rust, thanks to its advanced typing system. -use wasmer_types::{NativeWasmType, Type}; +use wasmer_types::{NativeWasmType, RawValue, Type}; use crate::js::Function; @@ -17,13 +17,13 @@ pub trait NativeWasmTypeInto: NativeWasmType + Sized { unsafe fn from_abi(store: &mut impl AsStoreMut, abi: Self::Abi) -> Self; /// Convert self to raw value representation. - fn into_raw(self, store: &mut impl AsStoreMut) -> f64; + fn into_raw(self, store: &mut impl AsStoreMut) -> RawValue; /// Convert to self from raw value representation. /// /// # Safety /// - unsafe fn from_raw(store: &mut impl AsStoreMut, raw: f64) -> Self; + unsafe fn from_raw(store: &mut impl AsStoreMut, raw: RawValue) -> Self; } impl NativeWasmTypeInto for i32 { @@ -38,13 +38,13 @@ impl NativeWasmTypeInto for i32 { } #[inline] - fn into_raw(self, _store: &mut impl AsStoreMut) -> f64 { - self.into() + fn into_raw(self, _store: &mut impl AsStoreMut) -> RawValue { + RawValue { i32: self } } #[inline] - unsafe fn from_raw(_store: &mut impl AsStoreMut, raw: f64) -> Self { - raw as _ + unsafe fn from_raw(_store: &mut impl AsStoreMut, raw: RawValue) -> Self { + raw.i32 } } @@ -60,13 +60,13 @@ impl NativeWasmTypeInto for i64 { } #[inline] - fn into_raw(self, _store: &mut impl AsStoreMut) -> f64 { - self as _ + fn into_raw(self, _store: &mut impl AsStoreMut) -> RawValue { + RawValue { i64: self } } #[inline] - unsafe fn from_raw(_store: &mut impl AsStoreMut, raw: f64) -> Self { - raw as _ + unsafe fn from_raw(_store: &mut impl AsStoreMut, raw: RawValue) -> Self { + raw.i64 } } @@ -82,13 +82,13 @@ impl NativeWasmTypeInto for f32 { } #[inline] - fn into_raw(self, _store: &mut impl AsStoreMut) -> f64 { - self as _ + fn into_raw(self, _store: &mut impl AsStoreMut) -> RawValue { + RawValue { f32: self } } #[inline] - unsafe fn from_raw(_store: &mut impl AsStoreMut, raw: f64) -> Self { - raw as _ + unsafe fn from_raw(_store: &mut impl AsStoreMut, raw: RawValue) -> Self { + raw.f32 } } @@ -104,13 +104,13 @@ impl NativeWasmTypeInto for f64 { } #[inline] - fn into_raw(self, _store: &mut impl AsStoreMut) -> f64 { - self + fn into_raw(self, _store: &mut impl AsStoreMut) -> RawValue { + RawValue { f64: self } } #[inline] - unsafe fn from_raw(_store: &mut impl AsStoreMut, raw: f64) -> Self { - raw + unsafe fn from_raw(_store: &mut impl AsStoreMut, raw: RawValue) -> Self { + raw.f64 } } @@ -126,19 +126,19 @@ impl NativeWasmTypeInto for u128 { } #[inline] - fn into_raw(self, _store: &mut impl AsStoreMut) -> f64 { - self as _ + fn into_raw(self, _store: &mut impl AsStoreMut) -> RawValue { + RawValue { u128: self } } #[inline] - unsafe fn from_raw(_store: &mut impl AsStoreMut, raw: f64) -> Self { - raw as _ + unsafe fn from_raw(_store: &mut impl AsStoreMut, raw: RawValue) -> Self { + raw.u128 } } impl NativeWasmType for Function { const WASM_TYPE: Type = Type::FuncRef; - type Abi = f64; + type Abi = usize; } /* diff --git a/lib/api/src/js/types.rs b/lib/api/src/js/types.rs index a1ec6df0fb9..f14e1b8a77d 100644 --- a/lib/api/src/js/types.rs +++ b/lib/api/src/js/types.rs @@ -52,6 +52,6 @@ impl AsJs for Value { impl AsJs for wasmer_types::RawValue { fn as_jsvalue(&self, _store: &impl AsStoreRef) -> JsValue { - unsafe { JsValue::from_f64(self.f64) } + unsafe { JsValue::from_f64(self.into()) } } } diff --git a/lib/api/src/js/value.rs b/lib/api/src/js/value.rs index 3124f7702f8..89019167a8d 100644 --- a/lib/api/src/js/value.rs +++ b/lib/api/src/js/value.rs @@ -87,25 +87,19 @@ impl Value { } /// Converts the `Value` into a `f64`. - pub fn as_raw(&self, _store: &impl AsStoreRef) -> f64 { + pub fn as_raw(&self, _store: &impl AsStoreRef) -> RawValue { match *self { - Self::I32(v) => v as f64, - Self::I64(v) => v as f64, - Self::F32(v) => v as f64, - Self::F64(v) => v, - Self::V128(v) => v as f64, - Self::FuncRef(Some(ref f)) => f.handle.function.as_f64().unwrap_or(0_f64), //TODO is this correct? - - Self::FuncRef(None) => 0_f64, - //Self::ExternRef(Some(ref e)) => unsafe { *e.address().0 } as .into_raw(), - //Self::ExternRef(None) => externref: 0 }, - } - } - - /// Converts the `Value` into a `RawValue`. - pub unsafe fn as_raw_value(&self, store: &impl AsStoreRef) -> RawValue { - RawValue { - f64: self.as_raw(store), + Self::I32(i32) => RawValue { i32 }, + Self::I64(i64) => RawValue { i64 }, + Self::F32(f32) => RawValue { f32 }, + Self::F64(f64) => RawValue { f64 }, + Self::V128(u128) => RawValue { u128 }, + Self::FuncRef(None) => RawValue { funcref: 0 }, + Self::FuncRef(Some(ref f)) => RawValue { + funcref: f.handle.function.as_f64().unwrap_or(0_f64) as _, + }, + // Self::ExternRef(Some(ref e)) => e.vm_externref().into_raw(), + // Self::ExternRef(None) => RawValue { externref: 0 }, } } @@ -113,19 +107,23 @@ impl Value { /// /// # Safety /// - pub unsafe fn from_raw(_store: &impl AsStoreRef, ty: Type, raw: f64) -> Self { + pub unsafe fn from_raw(_store: &impl AsStoreRef, ty: Type, raw: RawValue) -> Self { match ty { - Type::I32 => Self::I32(raw as _), - Type::I64 => Self::I64(raw as _), - Type::F32 => Self::F32(raw as _), - Type::F64 => Self::F64(raw), - Type::V128 => Self::V128(raw as _), - Type::FuncRef => todo!(), - Type::ExternRef => todo!(), - //Self::ExternRef( - //{ - //VMExternRef::from_raw(raw).map(|e| ExternRef::from_vm_externref(store, e)), - //), + Type::I32 => Self::I32(raw.i32), + Type::I64 => Self::I64(raw.i64), + Type::F32 => Self::F32(raw.f32), + Type::F64 => Self::F64(raw.f64), + Type::V128 => Self::V128(raw.u128), + Type::FuncRef => { + unimplemented!(); + // Self::FuncRef(VMFuncRef::from_raw(raw).map(|f| Function::from_vm_funcref(store, f))) + } + Type::ExternRef => { + unimplemented!(); + // Self::ExternRef( + // VMExternRef::from_raw(raw).map(|e| ExternRef::from_vm_externref(store, e)), + // ) + } } } diff --git a/lib/types/src/value.rs b/lib/types/src/value.rs index e07d2d5231e..b4259e2f7bb 100644 --- a/lib/types/src/value.rs +++ b/lib/types/src/value.rs @@ -20,6 +20,30 @@ pub union RawValue { pub bytes: [u8; 16], } +impl From for RawValue { + fn from(value: i32) -> Self { + RawValue { i32: value } + } +} + +impl From for RawValue { + fn from(value: i64) -> Self { + RawValue { i64: value } + } +} + +impl From for RawValue { + fn from(value: f32) -> Self { + RawValue { f32: value } + } +} + +impl From for RawValue { + fn from(value: f64) -> Self { + RawValue { f64: value } + } +} + impl Default for RawValue { fn default() -> Self { Self { bytes: [0; 16] } @@ -43,6 +67,27 @@ macro_rules! partial_eq { } )*) } + +macro_rules! into { + ($($t:ty => $f:tt),*) => ($( + impl From<&RawValue> for $t { + fn from(from: &RawValue) -> $t { + unsafe { + match &from { + RawValue { i32: i32 } => *i32 as _, + // RawValue { f32: f32 } => *f32 as _, + // RawValue { u32: u32 } => *u32 as _, + // RawValue { i64: i64 } => *i64 as _, + // RawValue { f64: f64 } => *f64 as _, + // RawValue { u64: u64 } => *u64 as _, + // _ => unimplemented!() + } + } + } + } + )*) +} + partial_eq! { i32 => i32, u32 => u32, @@ -54,6 +99,17 @@ partial_eq! { u128 => u128 } +into! { + i32 => i32, + u32 => u32, + i64 => i64, + u64 => u64, + f32 => f32, + f64 => f64, + i128 => i128, + u128 => u128 +} + impl PartialEq for RawValue { fn eq(&self, o: &Self) -> bool { unsafe { self.u128 == o.u128 } From 0dda3c1e65eca0f45491c4bf411b63b8ede823e9 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Fri, 10 Feb 2023 15:26:57 -0800 Subject: [PATCH 19/81] Unified extern_ref in js/sys --- lib/api/src/extern_ref.rs | 56 +++++++++++++++++++++++++++++++++++ lib/api/src/js/extern_ref.rs | 40 +++++++++++++++++++++++++ lib/api/src/js/mod.rs | 1 + lib/api/src/lib.rs | 2 ++ lib/api/src/sys/extern_ref.rs | 13 ++------ lib/api/src/sys/mod.rs | 3 +- 6 files changed, 102 insertions(+), 13 deletions(-) create mode 100644 lib/api/src/extern_ref.rs create mode 100644 lib/api/src/js/extern_ref.rs diff --git a/lib/api/src/extern_ref.rs b/lib/api/src/extern_ref.rs new file mode 100644 index 00000000000..db251a578d1 --- /dev/null +++ b/lib/api/src/extern_ref.rs @@ -0,0 +1,56 @@ +use std::any::Any; + +use crate::store::{AsStoreMut, AsStoreRef}; + +#[cfg(feature = "js")] +use crate::js::extern_ref as extern_ref_imp; +#[cfg(feature = "sys")] +use crate::sys::extern_ref as extern_ref_imp; + +#[derive(Debug, Clone)] +#[repr(transparent)] +/// An opaque reference to some data. This reference can be passed through Wasm. +pub struct ExternRef(pub(crate) extern_ref_imp::ExternRef); + +impl ExternRef { + /// Make a new extern reference + pub fn new(store: &mut impl AsStoreMut, value: T) -> Self + where + T: Any + Send + Sync + 'static + Sized, + { + ExternRef(extern_ref_imp::ExternRef::new(store, value)) + } + + /// Try to downcast to the given value. + pub fn downcast<'a, T>(&self, store: &'a impl AsStoreRef) -> Option<&'a T> + where + T: Any + Send + Sync + 'static + Sized, + { + self.0.downcast(store) + } + + pub(crate) fn vm_externref(&self) -> extern_ref_imp::VMExternRef { + self.0.vm_externref() + } + + pub(crate) unsafe fn from_vm_externref( + store: &mut impl AsStoreMut, + vm_externref: extern_ref_imp::VMExternRef, + ) -> Self { + ExternRef(extern_ref_imp::ExternRef::from_vm_externref( + store, + vm_externref, + )) + } + + /// Checks whether this `ExternRef` can be used with the given context. + /// + /// Primitive (`i32`, `i64`, etc) and null funcref/externref values are not + /// tied to a context and can be freely shared between contexts. + /// + /// Externref and funcref values are tied to a context and can only be used + /// with that context. + pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool { + self.0.is_from_store(store) + } +} diff --git a/lib/api/src/js/extern_ref.rs b/lib/api/src/js/extern_ref.rs new file mode 100644 index 00000000000..7aad132ab08 --- /dev/null +++ b/lib/api/src/js/extern_ref.rs @@ -0,0 +1,40 @@ +use std::any::Any; + +use crate::store::{AsStoreMut, AsStoreRef}; + +#[derive(Debug, Clone)] +#[repr(transparent)] +pub struct ExternRef; + +pub struct VMExternRef; + +impl ExternRef { + pub fn new(store: &mut impl AsStoreMut, value: T) -> Self + where + T: Any + Send + Sync + 'static + Sized, + { + unimplemented!(); + } + + pub fn downcast<'a, T>(&self, store: &'a impl AsStoreRef) -> Option<&'a T> + where + T: Any + Send + Sync + 'static + Sized, + { + unimplemented!(); + } + + pub(crate) fn vm_externref(&self) -> VMExternRef { + unimplemented!(); + } + + pub(crate) unsafe fn from_vm_externref( + store: &mut impl AsStoreMut, + vm_externref: VMExternRef, + ) -> Self { + unimplemented!(); + } + + pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool { + true + } +} diff --git a/lib/api/src/js/mod.rs b/lib/api/src/js/mod.rs index 1ce7da1c9ea..c629ed93144 100644 --- a/lib/api/src/js/mod.rs +++ b/lib/api/src/js/mod.rs @@ -26,6 +26,7 @@ mod lib { pub(crate) mod engine; pub(crate) mod error; mod exports; +pub(crate) mod extern_ref; pub(crate) mod externals; mod imports; mod instance; diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index 891f55b0bd3..9b3cf82ae9f 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -430,6 +430,7 @@ compile_error!( ); mod engine; +mod extern_ref; mod function_env; mod mem_access; mod module; @@ -448,6 +449,7 @@ mod js; pub use js::*; pub use engine::{AsEngineRef, Engine}; +pub use extern_ref::ExternRef; pub use function_env::{FunctionEnv, FunctionEnvMut}; pub use mem_access::{MemoryAccessError, WasmRef, WasmSlice, WasmSliceIter}; pub use module::{IoCompileError, Module}; diff --git a/lib/api/src/sys/extern_ref.rs b/lib/api/src/sys/extern_ref.rs index b8fb7cfb52d..53b86d9b7c7 100644 --- a/lib/api/src/sys/extern_ref.rs +++ b/lib/api/src/sys/extern_ref.rs @@ -1,18 +1,17 @@ use std::any::Any; -use wasmer_vm::{StoreHandle, VMExternObj, VMExternRef}; +pub use wasmer_vm::VMExternRef; +use wasmer_vm::{StoreHandle, VMExternObj}; use crate::store::{AsStoreMut, AsStoreRef}; #[derive(Debug, Clone)] #[repr(transparent)] -/// An opaque reference to some data. This reference can be passed through Wasm. pub struct ExternRef { handle: StoreHandle, } impl ExternRef { - /// Make a new extern reference pub fn new(store: &mut impl AsStoreMut, value: T) -> Self where T: Any + Send + Sync + 'static + Sized, @@ -22,7 +21,6 @@ impl ExternRef { } } - /// Try to downcast to the given value. pub fn downcast<'a, T>(&self, store: &'a impl AsStoreRef) -> Option<&'a T> where T: Any + Send + Sync + 'static + Sized, @@ -46,13 +44,6 @@ impl ExternRef { } } - /// Checks whether this `ExternRef` can be used with the given context. - /// - /// Primitive (`i32`, `i64`, etc) and null funcref/externref values are not - /// tied to a context and can be freely shared between contexts. - /// - /// Externref and funcref values are tied to a context and can only be used - /// with that context. pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool { self.handle.store_id() == store.as_store_ref().objects().id() } diff --git a/lib/api/src/sys/mod.rs b/lib/api/src/sys/mod.rs index c94405cc247..b0377854dca 100644 --- a/lib/api/src/sys/mod.rs +++ b/lib/api/src/sys/mod.rs @@ -1,6 +1,6 @@ pub(crate) mod engine; mod exports; -mod extern_ref; +pub(crate) mod extern_ref; pub(crate) mod externals; mod imports; mod instance; @@ -12,7 +12,6 @@ mod tunables; mod value; pub use crate::sys::exports::{ExportError, Exportable, Exports, ExportsIterator}; -pub use crate::sys::extern_ref::ExternRef; pub use crate::sys::externals::{ Extern, FromToNativeWasmType, Function, Global, HostFunction, Memory, MemoryView, Table, WasmTypeList, From a1d3891c1f847058ce24fae30a5a5d7cace98198 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Fri, 10 Feb 2023 15:55:09 -0800 Subject: [PATCH 20/81] Unify native_type::NativeWasmTypeInto in js/sys --- lib/api/src/js/extern_ref.rs | 20 ++- lib/api/src/js/externals/function.rs | 22 +++- lib/api/src/js/externals/mod.rs | 4 +- lib/api/src/js/mod.rs | 2 - lib/api/src/js/native.rs | 9 +- lib/api/src/js/native_type.rs | 182 -------------------------- lib/api/src/js/ptr.rs | 2 +- lib/api/src/lib.rs | 3 + lib/api/src/{sys => }/native_type.rs | 12 +- lib/api/src/sys/externals/function.rs | 6 +- lib/api/src/sys/mod.rs | 2 - lib/api/src/sys/native.rs | 7 +- 12 files changed, 70 insertions(+), 201 deletions(-) delete mode 100644 lib/api/src/js/native_type.rs rename lib/api/src/{sys => }/native_type.rs (96%) diff --git a/lib/api/src/js/extern_ref.rs b/lib/api/src/js/extern_ref.rs index 7aad132ab08..fb8e1cb46db 100644 --- a/lib/api/src/js/extern_ref.rs +++ b/lib/api/src/js/extern_ref.rs @@ -1,13 +1,29 @@ use std::any::Any; use crate::store::{AsStoreMut, AsStoreRef}; +use wasmer_types::RawValue; + +pub(crate) struct VMExternRef; + +impl VMExternRef { + /// Converts the `VMExternRef` into a `RawValue`. + pub fn into_raw(self) -> RawValue { + unimplemented!(); + } + + /// Extracts a `VMExternRef` from a `RawValue`. + /// + /// # Safety + /// `raw` must be a valid `VMExternRef` instance. + pub unsafe fn from_raw(raw: RawValue) -> Option { + unimplemented!(); + } +} #[derive(Debug, Clone)] #[repr(transparent)] pub struct ExternRef; -pub struct VMExternRef; - impl ExternRef { pub fn new(store: &mut impl AsStoreMut, value: T) -> Self where diff --git a/lib/api/src/js/externals/function.rs b/lib/api/src/js/externals/function.rs index 64f57bdc25a..b68395d522a 100644 --- a/lib/api/src/js/externals/function.rs +++ b/lib/api/src/js/externals/function.rs @@ -13,6 +13,7 @@ use js_sys::{Array, Function as JSFunction}; use std::iter::FromIterator; use wasm_bindgen::prelude::*; use wasm_bindgen::JsCast; +use wasmer_types::RawValue; use crate::js::vm::VMFunction; use std::fmt; @@ -20,6 +21,25 @@ use std::fmt; #[repr(C)] pub struct VMFunctionBody(u8); +#[repr(transparent)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub(crate) struct VMFuncRef; + +impl VMFuncRef { + /// Converts the `VMFuncRef` into a `RawValue`. + pub fn into_raw(self) -> RawValue { + unimplemented!() + } + + /// Extracts a `VMFuncRef` from a `RawValue`. + /// + /// # Safety + /// `raw.funcref` must be a valid pointer. + pub unsafe fn from_raw(raw: RawValue) -> Option { + unimplemented!(); + } +} + #[inline] fn result_to_js(val: &Value) -> JsValue { match val { @@ -632,8 +652,8 @@ mod inner { use crate::function_env::{FunctionEnv, FunctionEnvMut}; use crate::js::store::{InternalStoreHandle, StoreHandle}; use crate::js::vm::VMFunctionEnvironment; - use crate::js::NativeWasmTypeInto; use crate::store::{AsStoreMut, AsStoreRef, StoreMut}; + use crate::NativeWasmTypeInto; use std::array::TryFromSliceError; use std::convert::{Infallible, TryInto}; use std::error::Error; diff --git a/lib/api/src/js/externals/mod.rs b/lib/api/src/js/externals/mod.rs index d01480f1597..8502ad82288 100644 --- a/lib/api/src/js/externals/mod.rs +++ b/lib/api/src/js/externals/mod.rs @@ -1,8 +1,8 @@ pub(crate) mod function; -mod global; +pub(crate) mod global; pub(crate) mod memory; pub(crate) mod memory_view; -mod table; +pub(crate) mod table; pub use self::function::{FromToNativeWasmType, Function, HostFunction, WasmTypeList}; pub use self::global::Global; diff --git a/lib/api/src/js/mod.rs b/lib/api/src/js/mod.rs index c629ed93144..9c42bfa0935 100644 --- a/lib/api/src/js/mod.rs +++ b/lib/api/src/js/mod.rs @@ -34,7 +34,6 @@ pub(crate) mod module; #[cfg(feature = "wasm-types-polyfill")] mod module_info_polyfill; mod native; -mod native_type; mod ptr; pub(crate) mod store; mod trap; @@ -54,7 +53,6 @@ pub use crate::js::imports::Imports; pub use crate::js::instance::Instance; 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}; pub use crate::js::store::StoreObjects; pub use crate::js::trap::RuntimeError; diff --git a/lib/api/src/js/native.rs b/lib/api/src/js/native.rs index 8ab3858ce77..95b48f35e42 100644 --- a/lib/api/src/js/native.rs +++ b/lib/api/src/js/native.rs @@ -11,6 +11,7 @@ use std::marker::PhantomData; use crate::js::externals::Function; use crate::js::{FromToNativeWasmType, RuntimeError, WasmTypeList}; +use crate::native_type::NativeWasmTypeInto; use crate::store::{AsStoreMut, AsStoreRef}; // use std::panic::{catch_unwind, AssertUnwindSafe}; use crate::js::types::param_from_js; @@ -45,6 +46,12 @@ where } } + pub(crate) fn into_function(self) -> Function { + Function { + handle: self.handle, + } + } + pub(crate) fn from_handle(f: Function) -> Self { Self { handle: f.handle, @@ -64,7 +71,7 @@ macro_rules! impl_native_traits { /// Call the typed func and return results. #[allow(clippy::too_many_arguments)] pub fn call(&self, mut store: &mut impl AsStoreMut, $( $x: $x, )* ) -> Result where - $( $x: FromToNativeWasmType + crate::js::NativeWasmTypeInto, )* + $( $x: FromToNativeWasmType + NativeWasmTypeInto, )* { #[allow(unused_unsafe)] let params_list: Vec = unsafe { diff --git a/lib/api/src/js/native_type.rs b/lib/api/src/js/native_type.rs deleted file mode 100644 index 597211fc304..00000000000 --- a/lib/api/src/js/native_type.rs +++ /dev/null @@ -1,182 +0,0 @@ -//! This module permits to create native functions -//! easily in Rust, thanks to its advanced typing system. - -use wasmer_types::{NativeWasmType, RawValue, Type}; - -use crate::js::Function; - -use crate::store::AsStoreMut; - -/// `NativeWasmTypeInto` performs conversions from and into `NativeWasmType` -/// types with a context. -pub trait NativeWasmTypeInto: NativeWasmType + Sized { - #[doc(hidden)] - fn into_abi(self, store: &mut impl AsStoreMut) -> Self::Abi; - - #[doc(hidden)] - unsafe fn from_abi(store: &mut impl AsStoreMut, abi: Self::Abi) -> Self; - - /// Convert self to raw value representation. - fn into_raw(self, store: &mut impl AsStoreMut) -> RawValue; - - /// Convert to self from raw value representation. - /// - /// # Safety - /// - unsafe fn from_raw(store: &mut impl AsStoreMut, raw: RawValue) -> Self; -} - -impl NativeWasmTypeInto for i32 { - #[inline] - unsafe fn from_abi(_store: &mut impl AsStoreMut, abi: Self::Abi) -> Self { - abi - } - - #[inline] - fn into_abi(self, _store: &mut impl AsStoreMut) -> Self::Abi { - self - } - - #[inline] - fn into_raw(self, _store: &mut impl AsStoreMut) -> RawValue { - RawValue { i32: self } - } - - #[inline] - unsafe fn from_raw(_store: &mut impl AsStoreMut, raw: RawValue) -> Self { - raw.i32 - } -} - -impl NativeWasmTypeInto for i64 { - #[inline] - unsafe fn from_abi(_store: &mut impl AsStoreMut, abi: Self::Abi) -> Self { - abi - } - - #[inline] - fn into_abi(self, _store: &mut impl AsStoreMut) -> Self::Abi { - self - } - - #[inline] - fn into_raw(self, _store: &mut impl AsStoreMut) -> RawValue { - RawValue { i64: self } - } - - #[inline] - unsafe fn from_raw(_store: &mut impl AsStoreMut, raw: RawValue) -> Self { - raw.i64 - } -} - -impl NativeWasmTypeInto for f32 { - #[inline] - unsafe fn from_abi(_store: &mut impl AsStoreMut, abi: Self::Abi) -> Self { - abi - } - - #[inline] - fn into_abi(self, _store: &mut impl AsStoreMut) -> Self::Abi { - self - } - - #[inline] - fn into_raw(self, _store: &mut impl AsStoreMut) -> RawValue { - RawValue { f32: self } - } - - #[inline] - unsafe fn from_raw(_store: &mut impl AsStoreMut, raw: RawValue) -> Self { - raw.f32 - } -} - -impl NativeWasmTypeInto for f64 { - #[inline] - unsafe fn from_abi(_store: &mut impl AsStoreMut, abi: Self::Abi) -> Self { - abi - } - - #[inline] - fn into_abi(self, _store: &mut impl AsStoreMut) -> Self::Abi { - self - } - - #[inline] - fn into_raw(self, _store: &mut impl AsStoreMut) -> RawValue { - RawValue { f64: self } - } - - #[inline] - unsafe fn from_raw(_store: &mut impl AsStoreMut, raw: RawValue) -> Self { - raw.f64 - } -} - -impl NativeWasmTypeInto for u128 { - #[inline] - unsafe fn from_abi(_store: &mut impl AsStoreMut, abi: Self::Abi) -> Self { - abi - } - - #[inline] - fn into_abi(self, _store: &mut impl AsStoreMut) -> Self::Abi { - self - } - - #[inline] - fn into_raw(self, _store: &mut impl AsStoreMut) -> RawValue { - RawValue { u128: self } - } - - #[inline] - unsafe fn from_raw(_store: &mut impl AsStoreMut, raw: RawValue) -> Self { - raw.u128 - } -} - -impl NativeWasmType for Function { - const WASM_TYPE: Type = Type::FuncRef; - type Abi = usize; -} - -/* -mod test_native_type { - use super::*; - use wasmer_types::Type; - - fn test_wasm_types() { - assert_eq!(i32::WASM_TYPE, Type::I32); - assert_eq!(i64::WASM_TYPE, Type::I64); - assert_eq!(f32::WASM_TYPE, Type::F32); - assert_eq!(f64::WASM_TYPE, Type::F64); - } - - fn test_roundtrip() { - unsafe { - assert_eq!(i32::from_raw(42i32.into_raw()), 42i32); - assert_eq!(i64::from_raw(42i64.into_raw()), 42i64); - assert_eq!(f32::from_raw(42f32.into_raw()), 42f32); - assert_eq!(f64::from_raw(42f64.into_raw()), 42f64); - } - } -} - */ - -// pub trait IntegerAtomic -// where -// Self: Sized -// { -// type Primitive; - -// fn add(&self, other: Self::Primitive) -> Self::Primitive; -// fn sub(&self, other: Self::Primitive) -> Self::Primitive; -// fn and(&self, other: Self::Primitive) -> Self::Primitive; -// fn or(&self, other: Self::Primitive) -> Self::Primitive; -// fn xor(&self, other: Self::Primitive) -> Self::Primitive; -// fn load(&self) -> Self::Primitive; -// fn store(&self, other: Self::Primitive) -> Self::Primitive; -// fn compare_exchange(&self, expected: Self::Primitive, new: Self::Primitive) -> Self::Primitive; -// fn swap(&self, other: Self::Primitive) -> Self::Primitive; -// } diff --git a/lib/api/src/js/ptr.rs b/lib/api/src/js/ptr.rs index 0f6f6e0f5b8..4a3688489a6 100644 --- a/lib/api/src/js/ptr.rs +++ b/lib/api/src/js/ptr.rs @@ -1,7 +1,7 @@ -use crate::js::NativeWasmTypeInto; use crate::js::{externals::MemoryView, FromToNativeWasmType}; use crate::mem_access::{MemoryAccessError, WasmRef, WasmSlice}; use crate::store::AsStoreRef; +use crate::NativeWasmTypeInto; use std::convert::TryFrom; use std::{fmt, marker::PhantomData, mem}; pub use wasmer_types::Memory32; diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index 9b3cf82ae9f..06625476eba 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -434,6 +434,7 @@ mod extern_ref; mod function_env; mod mem_access; mod module; +mod native_type; mod store; #[cfg(feature = "sys")] @@ -453,6 +454,8 @@ pub use extern_ref::ExternRef; pub use function_env::{FunctionEnv, FunctionEnvMut}; pub use mem_access::{MemoryAccessError, WasmRef, WasmSlice, WasmSliceIter}; pub use module::{IoCompileError, Module}; +pub use native_type::NativeWasmTypeInto; + pub use store::{AsStoreMut, AsStoreRef, OnCalledHandler, Store, StoreId, StoreMut, StoreRef}; #[cfg(feature = "sys")] pub use store::{TrapHandlerFn, Tunables}; diff --git a/lib/api/src/sys/native_type.rs b/lib/api/src/native_type.rs similarity index 96% rename from lib/api/src/sys/native_type.rs rename to lib/api/src/native_type.rs index afbe52dcfbe..2ca88e22765 100644 --- a/lib/api/src/sys/native_type.rs +++ b/lib/api/src/native_type.rs @@ -2,9 +2,13 @@ //! easily in Rust, thanks to its advanced typing system. use wasmer_types::{NativeWasmType, RawValue, Type}; -use wasmer_vm::VMExternRef; -#[cfg(feature = "compiler")] -use wasmer_vm::VMFuncRef; + +#[cfg(feature = "js")] +use crate::js::extern_ref::VMExternRef; +#[cfg(feature = "js")] +use crate::js::externals::function::VMFuncRef; +#[cfg(feature = "sys")] +use wasmer_vm::{VMExternRef, VMFuncRef}; use crate::{ExternRef, Function, TypedFunction, WasmTypeList}; @@ -173,7 +177,7 @@ where Rets: WasmTypeList, { fn from(other: TypedFunction) -> Self { - other.func + other.into_function() } } diff --git a/lib/api/src/sys/externals/function.rs b/lib/api/src/sys/externals/function.rs index ba8252a8fed..1bd5f4458d9 100644 --- a/lib/api/src/sys/externals/function.rs +++ b/lib/api/src/sys/externals/function.rs @@ -1,8 +1,8 @@ use wasmer_types::RawValue; +pub use wasmer_vm::VMFuncRef; use wasmer_vm::{ on_host_stack, raise_user_trap, resume_panic, InternalStoreHandle, StoreHandle, VMContext, - VMDynamicFunctionContext, VMExtern, VMFuncRef, VMFunction, VMFunctionBody, VMFunctionKind, - VMTrampoline, + VMDynamicFunctionContext, VMExtern, VMFunction, VMFunctionBody, VMFunctionKind, VMTrampoline, }; use crate::store::{AsStoreMut, AsStoreRef}; @@ -860,8 +860,8 @@ mod inner { use wasmer_types::{NativeWasmType, RawValue, Type}; use wasmer_vm::{raise_user_trap, resume_panic, VMFunctionBody}; + use crate::native_type::NativeWasmTypeInto; use crate::store::{AsStoreMut, AsStoreRef, StoreMut}; - use crate::sys::NativeWasmTypeInto; use crate::{ExternRef, FunctionEnv}; use crate::Function; diff --git a/lib/api/src/sys/mod.rs b/lib/api/src/sys/mod.rs index b0377854dca..47a3f331475 100644 --- a/lib/api/src/sys/mod.rs +++ b/lib/api/src/sys/mod.rs @@ -6,7 +6,6 @@ mod imports; mod instance; pub(crate) mod module; mod native; -mod native_type; mod ptr; mod tunables; mod value; @@ -19,7 +18,6 @@ pub use crate::sys::externals::{ pub use crate::sys::imports::Imports; pub use crate::sys::instance::{Instance, InstantiationError}; pub use crate::sys::native::TypedFunction; -pub use crate::sys::native_type::NativeWasmTypeInto; pub use crate::sys::ptr::{Memory32, Memory64, MemorySize, WasmPtr, WasmPtr64}; pub use crate::sys::tunables::BaseTunables; diff --git a/lib/api/src/sys/native.rs b/lib/api/src/sys/native.rs index 16c93d0cda2..9bd514f4cd5 100644 --- a/lib/api/src/sys/native.rs +++ b/lib/api/src/sys/native.rs @@ -10,9 +10,10 @@ use std::cell::Cell; use std::marker::PhantomData; -use crate::sys::{FromToNativeWasmType, Function, NativeWasmTypeInto, RuntimeError, WasmTypeList}; +use crate::sys::{FromToNativeWasmType, Function, RuntimeError, WasmTypeList}; use wasmer_types::RawValue; +use crate::native_type::NativeWasmTypeInto; use crate::store::{AsStoreMut, OnCalledHandler}; /// A WebAssembly function that can be called natively @@ -35,6 +36,10 @@ where _phantom: PhantomData, } } + + pub(crate) fn into_function(self) -> Function { + self.func + } } impl Clone for TypedFunction { From c3576e1b3f7de537c00d357d08fa6762e50f95b6 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Fri, 10 Feb 2023 16:03:43 -0800 Subject: [PATCH 21/81] Unified ptr::WasmPtr into js/sys --- lib/api/src/js/mod.rs | 2 - lib/api/src/js/ptr.rs | 276 ----------------------------------- lib/api/src/lib.rs | 3 +- lib/api/src/{sys => }/ptr.rs | 10 +- lib/api/src/sys/mod.rs | 2 - 5 files changed, 8 insertions(+), 285 deletions(-) delete mode 100644 lib/api/src/js/ptr.rs rename lib/api/src/{sys => }/ptr.rs (97%) diff --git a/lib/api/src/js/mod.rs b/lib/api/src/js/mod.rs index 9c42bfa0935..e7d7a426e21 100644 --- a/lib/api/src/js/mod.rs +++ b/lib/api/src/js/mod.rs @@ -34,7 +34,6 @@ pub(crate) mod module; #[cfg(feature = "wasm-types-polyfill")] mod module_info_polyfill; mod native; -mod ptr; pub(crate) mod store; mod trap; mod types; @@ -53,7 +52,6 @@ pub use crate::js::imports::Imports; pub use crate::js::instance::Instance; pub use crate::js::module::{Module, ModuleTypeHints}; pub use crate::js::native::TypedFunction; -pub use crate::js::ptr::{Memory32, Memory64, MemorySize, WasmPtr, WasmPtr64}; pub use crate::js::store::StoreObjects; pub use crate::js::trap::RuntimeError; pub use crate::js::types::ValType as Type; diff --git a/lib/api/src/js/ptr.rs b/lib/api/src/js/ptr.rs deleted file mode 100644 index 4a3688489a6..00000000000 --- a/lib/api/src/js/ptr.rs +++ /dev/null @@ -1,276 +0,0 @@ -use crate::js::{externals::MemoryView, FromToNativeWasmType}; -use crate::mem_access::{MemoryAccessError, WasmRef, WasmSlice}; -use crate::store::AsStoreRef; -use crate::NativeWasmTypeInto; -use std::convert::TryFrom; -use std::{fmt, marker::PhantomData, mem}; -pub use wasmer_types::Memory32; -pub use wasmer_types::Memory64; -pub use wasmer_types::MemorySize; -use wasmer_types::ValueType; - -/// Alias for `WasmPtr. -pub type WasmPtr64 = WasmPtr; - -/// A zero-cost type that represents a pointer to something in Wasm linear -/// memory. -/// -/// This type can be used directly in the host function arguments: -/// ``` -/// # use wasmer::Memory; -/// # use wasmer::WasmPtr; -/// pub fn host_import(memory: Memory, ptr: WasmPtr) { -/// let derefed_ptr = ptr.deref(&memory); -/// let inner_val: u32 = derefed_ptr.read().expect("pointer in bounds"); -/// println!("Got {} from Wasm memory address 0x{:X}", inner_val, ptr.offset()); -/// // update the value being pointed to -/// derefed_ptr.write(inner_val + 1).expect("pointer in bounds"); -/// } -/// ``` -/// -/// This type can also be used with primitive-filled structs, but be careful of -/// guarantees required by `ValueType`. -/// ``` -/// # use wasmer::Memory; -/// # use wasmer::WasmPtr; -/// # use wasmer::ValueType; -/// -/// // This is safe as the 12 bytes represented by this struct -/// // are valid for all bit combinations. -/// #[derive(Copy, Clone, Debug, ValueType)] -/// #[repr(C)] -/// struct V3 { -/// x: f32, -/// y: f32, -/// z: f32 -/// } -/// -/// fn update_vector_3(memory: Memory, ptr: WasmPtr) { -/// let derefed_ptr = ptr.deref(&memory); -/// let mut inner_val: V3 = derefed_ptr.read().expect("pointer in bounds"); -/// println!("Got {:?} from Wasm memory address 0x{:X}", inner_val, ptr.offset()); -/// // update the value being pointed to -/// inner_val.x = 10.4; -/// derefed_ptr.write(inner_val).expect("pointer in bounds"); -/// } -/// ``` -#[repr(transparent)] -pub struct WasmPtr { - offset: M::Offset, - _phantom: PhantomData<*mut T>, -} - -impl WasmPtr { - /// Create a new `WasmPtr` at the given offset. - #[inline] - pub fn new(offset: M::Offset) -> Self { - Self { - offset, - _phantom: PhantomData, - } - } - - /// Get the offset into Wasm linear memory for this `WasmPtr`. - #[inline] - pub fn offset(&self) -> M::Offset { - self.offset - } - - /// Casts this `WasmPtr` to a `WasmPtr` of a different type. - #[inline] - pub fn cast(self) -> WasmPtr { - WasmPtr { - offset: self.offset, - _phantom: PhantomData, - } - } - - /// Returns a null `UserPtr`. - #[inline] - pub fn null() -> Self { - WasmPtr::new(M::ZERO) - } - - /// Checks whether the `WasmPtr` is null. - #[inline] - pub fn is_null(self) -> bool { - self.offset.into() == 0 - } - - /// Calculates an offset from the current pointer address. The argument is - /// in units of `T`. - /// - /// This method returns an error if an address overflow occurs. - #[inline] - pub fn add_offset(self, offset: M::Offset) -> Result { - let base = self.offset.into(); - let index = offset.into(); - let offset = index - .checked_mul(mem::size_of::() as u64) - .ok_or(MemoryAccessError::Overflow)?; - let address = base - .checked_add(offset) - .ok_or(MemoryAccessError::Overflow)?; - let address = M::Offset::try_from(address).map_err(|_| MemoryAccessError::Overflow)?; - Ok(WasmPtr::new(address)) - } - - /// Calculates an offset from the current pointer address. The argument is - /// in units of `T`. - /// - /// This method returns an error if an address overflow occurs. - #[inline] - pub fn sub_offset(self, offset: M::Offset) -> Result { - let base = self.offset.into(); - let index = offset.into(); - let offset = index - .checked_mul(mem::size_of::() as u64) - .ok_or(MemoryAccessError::Overflow)?; - let address = base - .checked_sub(offset) - .ok_or(MemoryAccessError::Overflow)?; - let address = M::Offset::try_from(address).map_err(|_| MemoryAccessError::Overflow)?; - Ok(WasmPtr::new(address)) - } -} - -impl WasmPtr { - /// Creates a `WasmRef` from this `WasmPtr` which allows reading and - /// mutating of the value being pointed to. - #[inline] - pub fn deref<'a>(self, view: &'a MemoryView) -> WasmRef<'a, T> { - WasmRef::new(view, self.offset.into()) - } - - /// Reads the address pointed to by this `WasmPtr` in a memory. - #[inline] - pub fn read(self, view: &MemoryView) -> Result { - self.deref(view).read() - } - - /// Writes to the address pointed to by this `WasmPtr` in a memory. - #[inline] - pub fn write(self, view: &MemoryView, val: T) -> Result<(), MemoryAccessError> { - self.deref(view).write(val) - } - - /// Creates a `WasmSlice` starting at this `WasmPtr` which allows reading - /// and mutating of an array of value being pointed to. - /// - /// Returns a `MemoryAccessError` if the slice length overflows a 64-bit - /// address. - #[inline] - pub fn slice<'a>( - self, - view: &'a MemoryView, - len: M::Offset, - ) -> Result, MemoryAccessError> { - WasmSlice::new(view, self.offset.into(), len.into()) - } - - /// Reads a sequence of values from this `WasmPtr` until a value that - /// matches the given condition is found. - /// - /// This last value is not included in the returned vector. - #[inline] - pub fn read_until<'a>( - self, - view: &'a MemoryView, - mut end: impl FnMut(&T) -> bool, - ) -> Result, MemoryAccessError> { - let mut vec = Vec::new(); - for i in 0u64.. { - let i = M::Offset::try_from(i).map_err(|_| MemoryAccessError::Overflow)?; - let val = self.add_offset(i)?.deref(view).read()?; - if end(&val) { - break; - } - vec.push(val); - } - Ok(vec) - } -} - -impl WasmPtr { - /// Reads a UTF-8 string from the `WasmPtr` with the given length. - /// - /// This method is safe to call even if the memory is being concurrently - /// modified. - #[inline] - pub fn read_utf8_string<'a>( - self, - view: &'a MemoryView, - len: M::Offset, - ) -> Result { - let vec = self.slice(view, len)?.read_to_vec()?; - Ok(String::from_utf8(vec)?) - } - - /// Reads a null-terminated UTF-8 string from the `WasmPtr`. - /// - /// This method is safe to call even if the memory is being concurrently - /// modified. - #[inline] - pub fn read_utf8_string_with_nul<'a>( - self, - view: &'a MemoryView, - ) -> Result { - let vec = self.read_until(view, |&byte| byte == 0)?; - Ok(String::from_utf8(vec)?) - } -} - -unsafe impl FromToNativeWasmType for WasmPtr -where - ::Native: NativeWasmTypeInto, -{ - type Native = M::Native; - - fn to_native(self) -> Self::Native { - M::offset_to_native(self.offset) - } - fn from_native(n: Self::Native) -> Self { - Self { - offset: M::native_to_offset(n), - _phantom: PhantomData, - } - } - #[inline] - fn is_from_store(&self, _store: &impl AsStoreRef) -> bool { - true // in Javascript there are no different stores - } -} - -unsafe impl ValueType for WasmPtr { - fn zero_padding_bytes(&self, _bytes: &mut [mem::MaybeUninit]) {} -} - -impl Clone for WasmPtr { - fn clone(&self) -> Self { - Self { - offset: self.offset, - _phantom: PhantomData, - } - } -} - -impl Copy for WasmPtr {} - -impl PartialEq for WasmPtr { - fn eq(&self, other: &Self) -> bool { - self.offset.into() == other.offset.into() - } -} - -impl Eq for WasmPtr {} - -impl fmt::Debug for WasmPtr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "WasmPtr(offset: {}, pointer: {:#x})", - self.offset.into(), - self.offset.into() - ) - } -} diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index 06625476eba..2e0ac4b77c8 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -435,6 +435,7 @@ mod function_env; mod mem_access; mod module; mod native_type; +mod ptr; mod store; #[cfg(feature = "sys")] @@ -455,7 +456,7 @@ pub use function_env::{FunctionEnv, FunctionEnvMut}; pub use mem_access::{MemoryAccessError, WasmRef, WasmSlice, WasmSliceIter}; pub use module::{IoCompileError, Module}; pub use native_type::NativeWasmTypeInto; - +pub use ptr::{Memory32, Memory64, MemorySize, WasmPtr, WasmPtr64}; pub use store::{AsStoreMut, AsStoreRef, OnCalledHandler, Store, StoreId, StoreMut, StoreRef}; #[cfg(feature = "sys")] pub use store::{TrapHandlerFn, Tunables}; diff --git a/lib/api/src/sys/ptr.rs b/lib/api/src/ptr.rs similarity index 97% rename from lib/api/src/sys/ptr.rs rename to lib/api/src/ptr.rs index 586cf27971a..82609acdf99 100644 --- a/lib/api/src/sys/ptr.rs +++ b/lib/api/src/ptr.rs @@ -1,13 +1,11 @@ use crate::mem_access::{MemoryAccessError, WasmRef, WasmSlice}; -use crate::sys::{externals::MemoryView, FromToNativeWasmType}; -use crate::NativeWasmTypeInto; +use crate::{AsStoreRef, FromToNativeWasmType, MemoryView, NativeWasmTypeInto}; use std::convert::TryFrom; use std::{fmt, marker::PhantomData, mem}; -use wasmer_types::ValueType; - pub use wasmer_types::Memory32; pub use wasmer_types::Memory64; pub use wasmer_types::MemorySize; +use wasmer_types::ValueType; /// Alias for `WasmPtr. pub type WasmPtr64 = WasmPtr; @@ -236,6 +234,10 @@ where _phantom: PhantomData, } } + #[inline] + fn is_from_store(&self, _store: &impl AsStoreRef) -> bool { + true // in Javascript there are no different stores + } } unsafe impl ValueType for WasmPtr { diff --git a/lib/api/src/sys/mod.rs b/lib/api/src/sys/mod.rs index 47a3f331475..7a24f579110 100644 --- a/lib/api/src/sys/mod.rs +++ b/lib/api/src/sys/mod.rs @@ -6,7 +6,6 @@ mod imports; mod instance; pub(crate) mod module; mod native; -mod ptr; mod tunables; mod value; @@ -19,7 +18,6 @@ pub use crate::sys::imports::Imports; pub use crate::sys::instance::{Instance, InstantiationError}; pub use crate::sys::native::TypedFunction; -pub use crate::sys::ptr::{Memory32, Memory64, MemorySize, WasmPtr, WasmPtr64}; pub use crate::sys::tunables::BaseTunables; pub use crate::sys::value::Value; pub use target_lexicon::{Architecture, CallingConvention, OperatingSystem, Triple, HOST}; From c9e18e8d571de8b11db8dec17c34aa1006444393 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Fri, 10 Feb 2023 16:06:47 -0800 Subject: [PATCH 22/81] Fixed Context references --- lib/api/src/sys/externals/function.rs | 2 +- lib/api/src/sys/externals/global.rs | 4 ++-- lib/api/src/sys/externals/table.rs | 2 +- lib/api/src/sys/native.rs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/api/src/sys/externals/function.rs b/lib/api/src/sys/externals/function.rs index 1bd5f4458d9..51ba6c52ae7 100644 --- a/lib/api/src/sys/externals/function.rs +++ b/lib/api/src/sys/externals/function.rs @@ -424,7 +424,7 @@ impl Function { } if !arg.is_from_store(store) { return Err(RuntimeError::new( - "cross-`Context` values are not supported", + "cross-`Store` values are not supported", )); } *slot = arg.as_raw(store); diff --git a/lib/api/src/sys/externals/global.rs b/lib/api/src/sys/externals/global.rs index 27e3d3e3dad..511c0bb3f3f 100644 --- a/lib/api/src/sys/externals/global.rs +++ b/lib/api/src/sys/externals/global.rs @@ -61,7 +61,7 @@ impl Global { ) -> Result { if !val.is_from_store(store) { return Err(RuntimeError::new( - "cross-`Context` values are not supported", + "cross-`Store` values are not supported", )); } let global = VMGlobal::new(GlobalType { @@ -165,7 +165,7 @@ impl Global { pub fn set(&self, store: &mut impl AsStoreMut, val: Value) -> Result<(), RuntimeError> { if !val.is_from_store(store) { return Err(RuntimeError::new( - "cross-`Context` values are not supported", + "cross-`Store` values are not supported", )); } if self.ty(store).mutability != Mutability::Var { diff --git a/lib/api/src/sys/externals/table.rs b/lib/api/src/sys/externals/table.rs index ee10af08f3e..ada06289cc4 100644 --- a/lib/api/src/sys/externals/table.rs +++ b/lib/api/src/sys/externals/table.rs @@ -156,7 +156,7 @@ impl Table { ) -> Result<(), RuntimeError> { if dst_table.handle.store_id() != src_table.handle.store_id() { return Err(RuntimeError::new( - "cross-`Context` table copies are not supported", + "cross-`Store` table copies are not supported", )); } let store = store; diff --git a/lib/api/src/sys/native.rs b/lib/api/src/sys/native.rs index 9bd514f4cd5..30746d25004 100644 --- a/lib/api/src/sys/native.rs +++ b/lib/api/src/sys/native.rs @@ -78,7 +78,7 @@ macro_rules! impl_native_traits { // Ensure all parameters come from the same context. if $(!FromToNativeWasmType::is_from_store(&$x, store) ||)* false { return Err(RuntimeError::new( - "cross-`Context` values are not supported", + "cross-`Store` values are not supported", )); } // TODO: when `const fn` related features mature more, we can declare a single array From a5e631c1764593c5b221a1de514aa1fee20b200e Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Fri, 10 Feb 2023 16:20:47 -0800 Subject: [PATCH 23/81] Unified Value into js/sys --- lib/api/src/js/externals/function.rs | 10 +- lib/api/src/js/externals/global.rs | 4 +- lib/api/src/js/externals/table.rs | 2 +- lib/api/src/js/imports.rs | 3 +- lib/api/src/js/mod.rs | 3 - lib/api/src/js/types.rs | 3 +- lib/api/src/js/value.rs | 448 -------------------------- lib/api/src/lib.rs | 2 + lib/api/src/sys/externals/function.rs | 5 +- lib/api/src/sys/externals/global.rs | 10 +- lib/api/src/sys/imports.rs | 3 +- lib/api/src/sys/mod.rs | 2 - lib/api/src/{sys => }/value.rs | 8 +- 13 files changed, 29 insertions(+), 474 deletions(-) delete mode 100644 lib/api/src/js/value.rs rename lib/api/src/{sys => }/value.rs (98%) diff --git a/lib/api/src/js/externals/function.rs b/lib/api/src/js/externals/function.rs index b68395d522a..706d74ab0d4 100644 --- a/lib/api/src/js/externals/function.rs +++ b/lib/api/src/js/externals/function.rs @@ -7,8 +7,8 @@ use crate::js::vm::VMExtern; use crate::js::FunctionType; use crate::js::RuntimeError; use crate::js::TypedFunction; -use crate::js::Value; use crate::store::{AsStoreMut, AsStoreRef, StoreMut}; +use crate::value::Value; use js_sys::{Array, Function as JSFunction}; use std::iter::FromIterator; use wasm_bindgen::prelude::*; @@ -618,6 +618,14 @@ impl Function { Ok(TypedFunction::from_handle(self.clone())) } + pub(crate) fn vm_funcref(&self, store: &impl AsStoreRef) -> VMFuncRef { + unimplemented!(); + } + + pub(crate) unsafe fn from_vm_funcref(store: &mut impl AsStoreMut, funcref: VMFuncRef) -> Self { + unimplemented!(); + } + #[track_caller] fn closures_unsupported_panic() -> ! { unimplemented!("Closures (functions with captured environments) are currently unsupported with native functions. See: https://github.com/wasmerio/wasmer/issues/1840") diff --git a/lib/api/src/js/externals/global.rs b/lib/api/src/js/externals/global.rs index 558a35a517d..33f0ffbbbca 100644 --- a/lib/api/src/js/externals/global.rs +++ b/lib/api/src/js/externals/global.rs @@ -1,12 +1,12 @@ use crate::js::exports::{ExportError, Exportable}; use crate::js::externals::Extern; -use crate::js::value::Value; use crate::js::vm::{VMExtern, VMGlobal}; use crate::js::wasm_bindgen_polyfill::Global as JSGlobal; use crate::js::GlobalType; use crate::js::Mutability; use crate::js::RuntimeError; use crate::store::{AsStoreMut, AsStoreRef}; +use crate::value::Value; use wasm_bindgen::JsValue; use wasmer_types::{RawValue, Type}; @@ -129,7 +129,7 @@ impl Global { /// /// assert_eq!(g.get(), Value::I32(1)); /// ``` - pub fn get(&self, store: &impl AsStoreRef) -> Value { + pub fn get(&self, store: &mut impl AsStoreMut) -> Value { unsafe { let value = self.handle.global.value(); let ty = self.handle.ty; diff --git a/lib/api/src/js/externals/table.rs b/lib/api/src/js/externals/table.rs index d1415e5f684..123f96391ad 100644 --- a/lib/api/src/js/externals/table.rs +++ b/lib/api/src/js/externals/table.rs @@ -1,10 +1,10 @@ use crate::js::exports::{ExportError, Exportable}; use crate::js::externals::Extern; -use crate::js::value::Value; use crate::js::vm::{VMExtern, VMFunction, VMTable}; use crate::js::RuntimeError; use crate::js::{FunctionType, TableType}; use crate::store::{AsStoreMut, AsStoreRef}; +use crate::value::Value; use js_sys::Function; /// A WebAssembly `table` instance. diff --git a/lib/api/src/js/imports.rs b/lib/api/src/js/imports.rs index 90bf46eaa5d..af7b4ab6132 100644 --- a/lib/api/src/js/imports.rs +++ b/lib/api/src/js/imports.rs @@ -421,8 +421,7 @@ macro_rules! import_namespace { #[cfg(test)] mod test { - use crate::js::{Global, Value}; - use crate::store::Store; + use crate::{Global, Store, Value}; // use wasm_bindgen::*; use wasm_bindgen_test::*; diff --git a/lib/api/src/js/mod.rs b/lib/api/src/js/mod.rs index e7d7a426e21..e8c9c5e74ab 100644 --- a/lib/api/src/js/mod.rs +++ b/lib/api/src/js/mod.rs @@ -37,7 +37,6 @@ mod native; pub(crate) mod store; mod trap; mod types; -mod value; pub(crate) mod vm; mod wasm_bindgen_polyfill; @@ -59,8 +58,6 @@ pub use crate::js::types::{ ExportType, ExternType, FunctionType, GlobalType, ImportType, MemoryType, Mutability, TableType, ValType, }; -pub use crate::js::value::Value; -pub use crate::js::value::Value as Val; pub use wasmer_types::is_wasm; // TODO: OnCalledAction is needed for asyncify. It will be refactored with https://github.com/wasmerio/wasmer/issues/3451 diff --git a/lib/api/src/js/types.rs b/lib/api/src/js/types.rs index f14e1b8a77d..ecea9c64b7f 100644 --- a/lib/api/src/js/types.rs +++ b/lib/api/src/js/types.rs @@ -1,8 +1,8 @@ //use crate::js::externals::Function; // use crate::store::{Store, StoreObject}; // use crate::js::RuntimeError; -use crate::js::value::Value; use crate::store::AsStoreRef; +use crate::value::Value; use wasm_bindgen::JsValue; pub use wasmer_types::{ ExportType, ExternType, FunctionType, GlobalType, ImportType, MemoryType, Mutability, @@ -46,6 +46,7 @@ impl AsJs for Value { Self::V128(f) => JsValue::from_f64(*f as f64), Self::FuncRef(Some(func)) => func.handle.function.clone().into(), Self::FuncRef(None) => JsValue::null(), + Self::ExternRef(_) => unimplemented!(), } } } diff --git a/lib/api/src/js/value.rs b/lib/api/src/js/value.rs deleted file mode 100644 index 89019167a8d..00000000000 --- a/lib/api/src/js/value.rs +++ /dev/null @@ -1,448 +0,0 @@ -use std::convert::TryFrom; -use std::fmt; -use std::string::{String, ToString}; - -use wasmer_types::RawValue; -use wasmer_types::Type; - -//use crate::ExternRef; -use crate::js::externals::function::Function; - -use crate::store::AsStoreRef; - -/// WebAssembly computations manipulate values of basic value types: -/// * Integers (32 or 64 bit width) -/// * Floating-point (32 or 64 bit width) -/// -/// Spec: -#[derive(Clone, PartialEq)] -pub enum Value { - /// A 32-bit integer. - /// - /// In Wasm integers are sign-agnostic, i.e. this can either be signed or unsigned. - I32(i32), - - /// A 64-bit integer. - /// - /// In Wasm integers are sign-agnostic, i.e. this can either be signed or unsigned. - I64(i64), - - /// A 32-bit float. - F32(f32), - - /// A 64-bit float. - F64(f64), - - /// An `externref` value which can hold opaque data to the wasm instance itself. - //ExternRef(Option), - - /// A first-class reference to a WebAssembly function. - FuncRef(Option), - - /// A 128-bit number - V128(u128), -} - -macro_rules! accessors { - ($bind:ident $(($variant:ident($ty:ty) $get:ident $unwrap:ident $cvt:expr))*) => ($( - /// Attempt to access the underlying value of this `Value`, returning - /// `None` if it is not the correct type. - pub fn $get(&self) -> Option<$ty> { - if let Self::$variant($bind) = self { - Some($cvt) - } else { - None - } - } - - /// Returns the underlying value of this `Value`, panicking if it's the - /// wrong type. - /// - /// # Panics - /// - /// Panics if `self` is not of the right type. - pub fn $unwrap(&self) -> $ty { - self.$get().expect(concat!("expected ", stringify!($ty))) - } - )*) -} - -impl Value { - /// Returns a null `externref` value. - pub fn null() -> Self { - Self::FuncRef(None) - } - - /// Returns the corresponding [`Type`] for this `Value`. - pub fn ty(&self) -> Type { - match self { - Self::I32(_) => Type::I32, - Self::I64(_) => Type::I64, - Self::F32(_) => Type::F32, - Self::F64(_) => Type::F64, - Self::V128(_) => Type::V128, - //Self::ExternRef(_) => Type::ExternRef, - Self::FuncRef(_) => Type::FuncRef, - } - } - - /// Converts the `Value` into a `f64`. - pub fn as_raw(&self, _store: &impl AsStoreRef) -> RawValue { - match *self { - Self::I32(i32) => RawValue { i32 }, - Self::I64(i64) => RawValue { i64 }, - Self::F32(f32) => RawValue { f32 }, - Self::F64(f64) => RawValue { f64 }, - Self::V128(u128) => RawValue { u128 }, - Self::FuncRef(None) => RawValue { funcref: 0 }, - Self::FuncRef(Some(ref f)) => RawValue { - funcref: f.handle.function.as_f64().unwrap_or(0_f64) as _, - }, - // Self::ExternRef(Some(ref e)) => e.vm_externref().into_raw(), - // Self::ExternRef(None) => RawValue { externref: 0 }, - } - } - - /// Converts a `f64` to a `Value`. - /// - /// # Safety - /// - pub unsafe fn from_raw(_store: &impl AsStoreRef, ty: Type, raw: RawValue) -> Self { - match ty { - Type::I32 => Self::I32(raw.i32), - Type::I64 => Self::I64(raw.i64), - Type::F32 => Self::F32(raw.f32), - Type::F64 => Self::F64(raw.f64), - Type::V128 => Self::V128(raw.u128), - Type::FuncRef => { - unimplemented!(); - // Self::FuncRef(VMFuncRef::from_raw(raw).map(|f| Function::from_vm_funcref(store, f))) - } - Type::ExternRef => { - unimplemented!(); - // Self::ExternRef( - // VMExternRef::from_raw(raw).map(|e| ExternRef::from_vm_externref(store, e)), - // ) - } - } - } - - /// Checks whether a value can be used with the given context. - /// - /// Primitive (`i32`, `i64`, etc) and null funcref/externref values are not - /// tied to a context and can be freely shared between contexts. - /// - /// Externref and funcref values are tied to a context and can only be used - /// with that context. - pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool { - match self { - Self::I32(_) - | Self::I64(_) - | Self::F32(_) - | Self::F64(_) - | Self::V128(_) - //| Self::ExternRef(None) - | Self::FuncRef(None) => true, - //Self::ExternRef(Some(e)) => e.is_from_store(store), - Self::FuncRef(Some(f)) => f.is_from_store(store), - } - } - - accessors! { - e - (I32(i32) i32 unwrap_i32 *e) - (I64(i64) i64 unwrap_i64 *e) - (F32(f32) f32 unwrap_f32 *e) - (F64(f64) f64 unwrap_f64 *e) - (V128(u128) v128 unwrap_v128 *e) - //(ExternRef(&Option) externref unwrap_externref e) - (FuncRef(&Option) funcref unwrap_funcref e) - } -} - -impl fmt::Debug for Value { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::I32(v) => write!(f, "I32({:?})", v), - Self::I64(v) => write!(f, "I64({:?})", v), - Self::F32(v) => write!(f, "F32({:?})", v), - Self::F64(v) => write!(f, "F64({:?})", v), - Self::V128(v) => write!(f, "V128({:?})", v), - //Self::ExternRef(None) => write!(f, "Null ExternRef"), - //Self::ExternRef(Some(v)) => write!(f, "ExternRef({:?})", v), - Self::FuncRef(None) => write!(f, "Null FuncRef"), - Self::FuncRef(Some(v)) => write!(f, "FuncRef({:?})", v), - } - } -} - -impl ToString for Value { - fn to_string(&self) -> String { - match self { - Self::I32(v) => v.to_string(), - Self::I64(v) => v.to_string(), - Self::F32(v) => v.to_string(), - Self::F64(v) => v.to_string(), - Self::V128(v) => v.to_string(), - //Self::ExternRef(_) => "externref".to_string(), - Self::FuncRef(_) => "funcref".to_string(), - } - } -} - -impl From for Value { - fn from(val: u128) -> Self { - Self::V128(val) - } -} - -impl From for Value { - fn from(val: i32) -> Self { - Self::I32(val) - } -} - -impl From for Value { - fn from(val: u32) -> Self { - // In Wasm integers are sign-agnostic, so i32 is basically a 4 byte storage we can use for signed or unsigned 32-bit integers. - Self::I32(val as i32) - } -} - -impl From for Value { - fn from(val: i64) -> Self { - Self::I64(val) - } -} - -impl From for Value { - fn from(val: u64) -> Self { - // In Wasm integers are sign-agnostic, so i64 is basically an 8 byte storage we can use for signed or unsigned 64-bit integers. - Self::I64(val as i64) - } -} - -impl From for Value { - fn from(val: f32) -> Self { - Self::F32(val) - } -} - -impl From for Value { - fn from(val: f64) -> Self { - Self::F64(val) - } -} - -impl From for Value { - fn from(val: Function) -> Self { - Self::FuncRef(Some(val)) - } -} - -impl From> for Value { - fn from(val: Option) -> Self { - Self::FuncRef(val) - } -} - -//impl From for Value { -// fn from(val: ExternRef) -> Self { -// Self::ExternRef(Some(val)) -// } -//} -// -//impl From> for Value { -// fn from(val: Option) -> Self { -// Self::ExternRef(val) -// } -//} - -const NOT_I32: &str = "Value is not of Wasm type i32"; -const NOT_I64: &str = "Value is not of Wasm type i64"; -const NOT_F32: &str = "Value is not of Wasm type f32"; -const NOT_F64: &str = "Value is not of Wasm type f64"; -const NOT_V128: &str = "Value is not of Wasm type u128"; -const NOT_FUNCREF: &str = "Value is not of Wasm type funcref"; -//const NOT_EXTERNREF: &str = "Value is not of Wasm type externref"; - -impl TryFrom for u128 { - type Error = &'static str; - - fn try_from(value: Value) -> Result { - value.v128().ok_or(NOT_V128) - } -} - -impl TryFrom for i32 { - type Error = &'static str; - - fn try_from(value: Value) -> Result { - value.i32().ok_or(NOT_I32) - } -} - -impl TryFrom for u32 { - type Error = &'static str; - - fn try_from(value: Value) -> Result { - value.i32().ok_or(NOT_I32).map(|int| int as Self) - } -} - -impl TryFrom for i64 { - type Error = &'static str; - - fn try_from(value: Value) -> Result { - value.i64().ok_or(NOT_I64) - } -} - -impl TryFrom for u64 { - type Error = &'static str; - - fn try_from(value: Value) -> Result { - value.i64().ok_or(NOT_I64).map(|int| int as Self) - } -} - -impl TryFrom for f32 { - type Error = &'static str; - - fn try_from(value: Value) -> Result { - value.f32().ok_or(NOT_F32) - } -} - -impl TryFrom for f64 { - type Error = &'static str; - - fn try_from(value: Value) -> Result { - value.f64().ok_or(NOT_F64) - } -} - -impl TryFrom for Option { - type Error = &'static str; - - fn try_from(value: Value) -> Result { - match value { - Value::FuncRef(f) => Ok(f), - _ => Err(NOT_FUNCREF), - } - } -} - -//impl TryFrom for Option { -// type Error = &'static str; -// -// fn try_from(value: Value) -> Result { -// match value { -// Value::ExternRef(e) => Ok(e), -// _ => Err(NOT_EXTERNREF), -// } -// } -//} - -#[cfg(tests)] -mod tests { - use super::*; - /* - - fn test_value_i32_from_u32() { - let bytes = [0x00, 0x00, 0x00, 0x00]; - let v = Value::<()>::from(u32::from_be_bytes(bytes)); - assert_eq!(v, Value::I32(i32::from_be_bytes(bytes))); - - let bytes = [0x00, 0x00, 0x00, 0x01]; - let v = Value::<()>::from(u32::from_be_bytes(bytes)); - assert_eq!(v, Value::I32(i32::from_be_bytes(bytes))); - - let bytes = [0xAA, 0xBB, 0xCC, 0xDD]; - let v = Value::<()>::from(u32::from_be_bytes(bytes)); - assert_eq!(v, Value::I32(i32::from_be_bytes(bytes))); - - let bytes = [0xFF, 0xFF, 0xFF, 0xFF]; - let v = Value::<()>::from(u32::from_be_bytes(bytes)); - assert_eq!(v, Value::I32(i32::from_be_bytes(bytes))); - } - - fn test_value_i64_from_u64() { - let bytes = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; - let v = Value::<()>::from(u64::from_be_bytes(bytes)); - assert_eq!(v, Value::I64(i64::from_be_bytes(bytes))); - - let bytes = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01]; - let v = Value::<()>::from(u64::from_be_bytes(bytes)); - assert_eq!(v, Value::I64(i64::from_be_bytes(bytes))); - - let bytes = [0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00, 0x11]; - let v = Value::<()>::from(u64::from_be_bytes(bytes)); - assert_eq!(v, Value::I64(i64::from_be_bytes(bytes))); - - let bytes = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]; - let v = Value::<()>::from(u64::from_be_bytes(bytes)); - assert_eq!(v, Value::I64(i64::from_be_bytes(bytes))); - } - - fn convert_value_to_i32() { - let value = Value::<()>::I32(5678); - let result = i32::try_from(value); - assert_eq!(result.unwrap(), 5678); - - let value = Value::<()>::from(u32::MAX); - let result = i32::try_from(value); - assert_eq!(result.unwrap(), -1); - } - - fn convert_value_to_u32() { - let value = Value::<()>::from(u32::MAX); - let result = u32::try_from(value); - assert_eq!(result.unwrap(), u32::MAX); - - let value = Value::<()>::I32(-1); - let result = u32::try_from(value); - assert_eq!(result.unwrap(), u32::MAX); - } - - fn convert_value_to_i64() { - let value = Value::<()>::I64(5678); - let result = i64::try_from(value); - assert_eq!(result.unwrap(), 5678); - - let value = Value::<()>::from(u64::MAX); - let result = i64::try_from(value); - assert_eq!(result.unwrap(), -1); - } - - fn convert_value_to_u64() { - let value = Value::<()>::from(u64::MAX); - let result = u64::try_from(value); - assert_eq!(result.unwrap(), u64::MAX); - - let value = Value::<()>::I64(-1); - let result = u64::try_from(value); - assert_eq!(result.unwrap(), u64::MAX); - } - - fn convert_value_to_f32() { - let value = Value::<()>::F32(1.234); - let result = f32::try_from(value); - assert_eq!(result.unwrap(), 1.234); - - let value = Value::<()>::F64(1.234); - let result = f32::try_from(value); - assert_eq!(result.unwrap_err(), "Value is not of Wasm type f32"); - } - - fn convert_value_to_f64() { - let value = Value::<()>::F64(1.234); - let result = f64::try_from(value); - assert_eq!(result.unwrap(), 1.234); - - let value = Value::<()>::F32(1.234); - let result = f64::try_from(value); - assert_eq!(result.unwrap_err(), "Value is not of Wasm type f64"); - } - */ -} diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index 2e0ac4b77c8..49305cbfd6c 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -437,6 +437,7 @@ mod module; mod native_type; mod ptr; mod store; +mod value; #[cfg(feature = "sys")] mod sys; @@ -460,6 +461,7 @@ pub use ptr::{Memory32, Memory64, MemorySize, WasmPtr, WasmPtr64}; pub use store::{AsStoreMut, AsStoreRef, OnCalledHandler, Store, StoreId, StoreMut, StoreRef}; #[cfg(feature = "sys")] pub use store::{TrapHandlerFn, Tunables}; +pub use value::Value; mod into_bytes; pub use into_bytes::IntoBytes; diff --git a/lib/api/src/sys/externals/function.rs b/lib/api/src/sys/externals/function.rs index 51ba6c52ae7..8984b5fc968 100644 --- a/lib/api/src/sys/externals/function.rs +++ b/lib/api/src/sys/externals/function.rs @@ -423,9 +423,7 @@ impl Function { ))); } if !arg.is_from_store(store) { - return Err(RuntimeError::new( - "cross-`Store` values are not supported", - )); + return Err(RuntimeError::new("cross-`Store` values are not supported")); } *slot = arg.as_raw(store); } @@ -613,7 +611,6 @@ impl Function { VMFuncRef(vm_function.anyfunc.as_ptr()) } - #[cfg(feature = "compiler")] pub(crate) unsafe fn from_vm_funcref(store: &mut impl AsStoreMut, funcref: VMFuncRef) -> Self { let signature = store .as_store_ref() diff --git a/lib/api/src/sys/externals/global.rs b/lib/api/src/sys/externals/global.rs index 511c0bb3f3f..a8e059ea711 100644 --- a/lib/api/src/sys/externals/global.rs +++ b/lib/api/src/sys/externals/global.rs @@ -1,10 +1,10 @@ use crate::store::{AsStoreMut, AsStoreRef}; use crate::sys::exports::{ExportError, Exportable}; use crate::sys::externals::Extern; -use crate::sys::value::Value; use crate::sys::GlobalType; use crate::sys::Mutability; use crate::sys::RuntimeError; +use crate::value::Value; use wasmer_vm::{InternalStoreHandle, StoreHandle, VMExtern, VMGlobal}; /// A WebAssembly `global` instance. @@ -60,9 +60,7 @@ impl Global { mutability: Mutability, ) -> Result { if !val.is_from_store(store) { - return Err(RuntimeError::new( - "cross-`Store` values are not supported", - )); + return Err(RuntimeError::new("cross-`Store` values are not supported")); } let global = VMGlobal::new(GlobalType { mutability, @@ -164,9 +162,7 @@ impl Global { /// ``` pub fn set(&self, store: &mut impl AsStoreMut, val: Value) -> Result<(), RuntimeError> { if !val.is_from_store(store) { - return Err(RuntimeError::new( - "cross-`Store` values are not supported", - )); + return Err(RuntimeError::new("cross-`Store` values are not supported")); } if self.ty(store).mutability != Mutability::Var { return Err(RuntimeError::new("Attempted to set an immutable global")); diff --git a/lib/api/src/sys/imports.rs b/lib/api/src/sys/imports.rs index 6bdfa2ac77d..e3e47c07326 100644 --- a/lib/api/src/sys/imports.rs +++ b/lib/api/src/sys/imports.rs @@ -306,7 +306,8 @@ macro_rules! import_namespace { #[cfg(test)] mod test { use crate::store::{AsStoreMut, Store}; - use crate::sys::{Global, Value}; + use crate::sys::Global; + use crate::value::Value; use wasmer_types::Type; use wasmer_vm::VMExtern; diff --git a/lib/api/src/sys/mod.rs b/lib/api/src/sys/mod.rs index 7a24f579110..72d627290c0 100644 --- a/lib/api/src/sys/mod.rs +++ b/lib/api/src/sys/mod.rs @@ -7,7 +7,6 @@ mod instance; pub(crate) mod module; mod native; mod tunables; -mod value; pub use crate::sys::exports::{ExportError, Exportable, Exports, ExportsIterator}; pub use crate::sys::externals::{ @@ -19,7 +18,6 @@ pub use crate::sys::instance::{Instance, InstantiationError}; pub use crate::sys::native::TypedFunction; pub use crate::sys::tunables::BaseTunables; -pub use crate::sys::value::Value; pub use target_lexicon::{Architecture, CallingConvention, OperatingSystem, Triple, HOST}; #[cfg(feature = "compiler")] pub use wasmer_compiler::{ diff --git a/lib/api/src/sys/value.rs b/lib/api/src/value.rs similarity index 98% rename from lib/api/src/sys/value.rs rename to lib/api/src/value.rs index 89eb8b5276d..b06f01cc8a0 100644 --- a/lib/api/src/sys/value.rs +++ b/lib/api/src/value.rs @@ -3,7 +3,12 @@ use std::fmt; use std::string::{String, ToString}; use wasmer_types::Type; -#[cfg(feature = "compiler")] + +#[cfg(feature = "js")] +use crate::js::extern_ref::VMExternRef; +#[cfg(feature = "js")] +use crate::js::externals::function::VMFuncRef; +#[cfg(feature = "sys")] use wasmer_vm::{VMExternRef, VMFuncRef}; use crate::ExternRef; @@ -106,7 +111,6 @@ impl Value { } } - #[cfg(feature = "compiler")] /// Converts a `RawValue` to a `Value`. /// /// # Safety From 1e405d3e22573e88b0dcc6a441f5a3d43c139a9a Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Fri, 10 Feb 2023 16:29:28 -0800 Subject: [PATCH 24/81] Unified exports in js/sys --- lib/api/src/{sys => }/exports.rs | 8 +- lib/api/src/js/exports.rs | 351 -------------------------- lib/api/src/js/externals/function.rs | 2 +- lib/api/src/js/externals/global.rs | 2 +- lib/api/src/js/externals/memory.rs | 2 +- lib/api/src/js/externals/mod.rs | 2 +- lib/api/src/js/externals/table.rs | 2 +- lib/api/src/js/imports.rs | 2 +- lib/api/src/js/instance.rs | 2 +- lib/api/src/js/mod.rs | 2 - lib/api/src/js/native.rs | 12 - lib/api/src/lib.rs | 2 + lib/api/src/sys/externals/function.rs | 2 +- lib/api/src/sys/externals/global.rs | 2 +- lib/api/src/sys/externals/memory.rs | 2 +- lib/api/src/sys/externals/mod.rs | 2 +- lib/api/src/sys/externals/table.rs | 2 +- lib/api/src/sys/instance.rs | 2 +- lib/api/src/sys/mod.rs | 2 - 19 files changed, 16 insertions(+), 387 deletions(-) rename lib/api/src/{sys => }/exports.rs (97%) delete mode 100644 lib/api/src/js/exports.rs diff --git a/lib/api/src/sys/exports.rs b/lib/api/src/exports.rs similarity index 97% rename from lib/api/src/sys/exports.rs rename to lib/api/src/exports.rs index 2e887494e18..b263ee7fd29 100644 --- a/lib/api/src/sys/exports.rs +++ b/lib/api/src/exports.rs @@ -1,7 +1,5 @@ use crate::store::AsStoreRef; -use crate::sys::externals::{Extern, Function, Global, Memory, Table}; -use crate::sys::native::TypedFunction; -use crate::sys::WasmTypeList; +use crate::{Extern, Function, Global, Memory, Table, TypedFunction, WasmTypeList}; use indexmap::IndexMap; use std::fmt; use std::iter::{ExactSizeIterator, FromIterator}; @@ -18,9 +16,7 @@ use thiserror::Error; /// /// ```should_panic /// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value, ExportError}; -/// # use wasmer::FunctionEnv; /// # let mut store = Store::default(); -/// # let env = FunctionEnv::new(&mut store, ()); /// # let wasm_bytes = wat2wasm(r#" /// # (module /// # (global $one (export "glob") f32 (f32.const 1))) @@ -37,9 +33,7 @@ use thiserror::Error; /// /// ```should_panic /// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value, ExportError}; -/// # use wasmer::FunctionEnv; /// # let mut store = Store::default(); -/// # let env = FunctionEnv::new(&mut store, ()); /// # let wasm_bytes = wat2wasm("(module)".as_bytes()).unwrap(); /// # let module = Module::new(&store, wasm_bytes).unwrap(); /// # let import_object = imports! {}; diff --git a/lib/api/src/js/exports.rs b/lib/api/src/js/exports.rs deleted file mode 100644 index 1797284945f..00000000000 --- a/lib/api/src/js/exports.rs +++ /dev/null @@ -1,351 +0,0 @@ -use crate::js::externals::{Extern, Function, Global, Memory, Table}; -use crate::js::native::TypedFunction; -use crate::js::WasmTypeList; -use crate::store::AsStoreRef; -use indexmap::IndexMap; -use std::fmt; -use std::iter::{ExactSizeIterator, FromIterator}; -use thiserror::Error; - -/// The `ExportError` can happen when trying to get a specific -/// export [`Extern`] from the [`Instance`] exports. -/// -/// [`Instance`]: crate::js::Instance -/// -/// # Examples -/// -/// ## Incompatible export type -/// -/// ```should_panic -/// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value, ExportError}; -/// # let mut store = Store::default(); -/// # let wasm_bytes = wat2wasm(r#" -/// # (module -/// # (global $one (export "glob") f32 (f32.const 1))) -/// # "#.as_bytes()).unwrap(); -/// # let module = Module::new(&store, wasm_bytes).unwrap(); -/// # let import_object = imports! {}; -/// # let instance = Instance::new(&module, &import_object).unwrap(); -/// # -/// // This results with an error: `ExportError::IncompatibleType`. -/// let export = instance.exports.get_function("glob").unwrap(); -/// ``` -/// -/// ## Missing export -/// -/// ```should_panic -/// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value, ExportError}; -/// # let mut store = Store::default(); -/// # let wasm_bytes = wat2wasm("(module)".as_bytes()).unwrap(); -/// # let module = Module::new(&store, wasm_bytes).unwrap(); -/// # let import_object = imports! {}; -/// # let instance = Instance::new(&module, &import_object).unwrap(); -/// # -/// // This results with an error: `ExportError::Missing`. -/// let export = instance.exports.get_function("unknown").unwrap(); -/// ``` -#[derive(Error, Debug)] -pub enum ExportError { - /// An error than occurs when the exported type and the expected type - /// are incompatible. - #[error("Incompatible Export Type")] - IncompatibleType, - /// This error arises when an export is missing - #[error("Missing export {0}")] - Missing(String), -} - -/// Exports is a special kind of map that allows easily unwrapping -/// the types of instances. -/// -/// TODO: add examples of using exports -#[derive(Clone, Default)] -pub struct Exports { - map: IndexMap, -} - -impl Exports { - /// Creates a new `Exports`. - pub fn new() -> Self { - Default::default() - } - - /// Creates a new `Exports` with capacity `n`. - pub fn with_capacity(n: usize) -> Self { - Self { - map: IndexMap::with_capacity(n), - } - } - - /// Return the number of exports in the `Exports` map. - pub fn len(&self) -> usize { - self.map.len() - } - - /// Return whether or not there are no exports - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - - /// Insert a new export into this `Exports` map. - pub fn insert(&mut self, name: S, value: E) - where - S: Into, - E: Into, - { - self.map.insert(name.into(), value.into()); - } - - /// Get an export given a `name`. - /// - /// The `get` method is specifically made for usage inside of - /// Rust APIs, as we can detect what's the desired type easily. - /// - /// If you want to get an export dynamically with type checking - /// please use the following functions: `get_func`, `get_memory`, - /// `get_table` or `get_global` instead. - /// - /// If you want to get an export dynamically handling manually - /// type checking manually, please use `get_extern`. - pub fn get<'a, T: Exportable<'a>>(&'a self, name: &str) -> Result<&'a T, ExportError> { - match self.map.get(name) { - None => Err(ExportError::Missing(name.to_string())), - Some(extern_) => T::get_self_from_extern(extern_), - } - } - - /// Get an export as a `Global`. - pub fn get_global(&self, name: &str) -> Result<&Global, ExportError> { - self.get(name) - } - - /// Get an export as a `Memory`. - pub fn get_memory(&self, name: &str) -> Result<&Memory, ExportError> { - self.get(name) - } - - /// Get an export as a `Table`. - pub fn get_table(&self, name: &str) -> Result<&Table, ExportError> { - self.get(name) - } - - /// Get an export as a `Func`. - pub fn get_function(&self, name: &str) -> Result<&Function, ExportError> { - self.get(name) - } - - #[deprecated( - since = "3.0.0", - note = "get_native_function() has been renamed to get_typed_function(), just like NativeFunc has been renamed to TypedFunction." - )] - /// Get an export as a `TypedFunction`. - pub fn get_native_function( - &self, - store: &impl AsStoreRef, - name: &str, - ) -> Result, ExportError> - where - Args: WasmTypeList, - Rets: WasmTypeList, - { - self.get_typed_function(store, name) - } - - /// Get an export as a `TypedFunction`. - pub fn get_typed_function( - &self, - store: &impl AsStoreRef, - name: &str, - ) -> Result, ExportError> - where - Args: WasmTypeList, - Rets: WasmTypeList, - { - self.get_function(name)? - .typed(store) - .map_err(|_| ExportError::IncompatibleType) - } - - /// Hack to get this working with nativefunc too - pub fn get_with_generics<'a, T, Args, Rets>( - &'a self, - store: &impl AsStoreRef, - name: &str, - ) -> Result - where - Args: WasmTypeList, - Rets: WasmTypeList, - T: ExportableWithGenerics<'a, Args, Rets>, - { - match self.map.get(name) { - None => Err(ExportError::Missing(name.to_string())), - Some(extern_) => T::get_self_from_extern_with_generics(store, extern_), - } - } - - /// Like `get_with_generics` but with a WeakReference to the `InstanceRef` internally. - /// This is useful for passing data into Context data, for example. - pub fn get_with_generics_weak<'a, T, Args, Rets>( - &'a self, - store: &impl AsStoreRef, - name: &str, - ) -> Result - where - Args: WasmTypeList, - Rets: WasmTypeList, - T: ExportableWithGenerics<'a, Args, Rets>, - { - let out: T = self.get_with_generics(store, name)?; - Ok(out) - } - - /// Get an export as an `Extern`. - pub fn get_extern(&self, name: &str) -> Option<&Extern> { - self.map.get(name) - } - - /// Returns true if the `Exports` contains the given export name. - pub fn contains(&self, name: S) -> bool - where - S: Into, - { - self.map.contains_key(&name.into()) - } - - /// Get an iterator over the exports. - pub fn iter(&self) -> ExportsIterator> { - ExportsIterator { - iter: self.map.iter(), - } - } -} - -impl fmt::Debug for Exports { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_set().entries(self.iter()).finish() - } -} - -/// An iterator over exports. -pub struct ExportsIterator<'a, I> -where - I: Iterator + Sized, -{ - iter: I, -} - -impl<'a, I> Iterator for ExportsIterator<'a, I> -where - I: Iterator + Sized, -{ - type Item = (&'a String, &'a Extern); - - fn next(&mut self) -> Option { - self.iter.next() - } -} - -impl<'a, I> ExactSizeIterator for ExportsIterator<'a, I> -where - I: Iterator + ExactSizeIterator + Sized, -{ - fn len(&self) -> usize { - self.iter.len() - } -} - -impl<'a, I> ExportsIterator<'a, I> -where - I: Iterator + Sized, -{ - /// Get only the functions. - pub fn functions(self) -> impl Iterator + Sized { - self.iter.filter_map(|(name, export)| match export { - Extern::Function(function) => Some((name, function)), - _ => None, - }) - } - - /// Get only the memories. - pub fn memories(self) -> impl Iterator + Sized { - self.iter.filter_map(|(name, export)| match export { - Extern::Memory(memory) => Some((name, memory)), - _ => None, - }) - } - - /// Get only the globals. - pub fn globals(self) -> impl Iterator + Sized { - self.iter.filter_map(|(name, export)| match export { - Extern::Global(global) => Some((name, global)), - _ => None, - }) - } - - /// Get only the tables. - pub fn tables(self) -> impl Iterator + Sized { - self.iter.filter_map(|(name, export)| match export { - Extern::Table(table) => Some((name, table)), - _ => None, - }) - } -} - -impl FromIterator<(String, Extern)> for Exports { - fn from_iter>(iter: I) -> Self { - Self { - map: IndexMap::from_iter(iter), - } - } -} - -impl IntoIterator for Exports { - type IntoIter = indexmap::map::IntoIter; - type Item = (String, Extern); - - fn into_iter(self) -> Self::IntoIter { - self.map.clone().into_iter() - } -} - -impl<'a> IntoIterator for &'a Exports { - type IntoIter = indexmap::map::Iter<'a, String, Extern>; - type Item = (&'a String, &'a Extern); - - fn into_iter(self) -> Self::IntoIter { - self.map.iter() - } -} - -/// This trait is used to mark types as gettable from an [`Instance`]. -/// -/// [`Instance`]: crate::js::Instance -pub trait Exportable<'a>: Sized { - /// Implementation of how to get the export corresponding to the implementing type - /// from an [`Instance`] by name. - /// - /// [`Instance`]: crate::js::Instance - fn get_self_from_extern(_extern: &'a Extern) -> Result<&'a Self, ExportError>; -} - -/// A trait for accessing exports (like [`Exportable`]) but it takes generic -/// `Args` and `Rets` parameters so that `TypedFunction` can be accessed directly -/// as well. -pub trait ExportableWithGenerics<'a, Args: WasmTypeList, Rets: WasmTypeList>: Sized { - /// Get an export with the given generics. - fn get_self_from_extern_with_generics( - store: &impl AsStoreRef, - _extern: &'a Extern, - ) -> Result; -} - -/// We implement it for all concrete [`Exportable`] types (that are `Clone`) -/// with empty `Args` and `Rets`. -impl<'a, T: Exportable<'a> + Clone + 'static> ExportableWithGenerics<'a, (), ()> for T { - fn get_self_from_extern_with_generics( - _store: &impl AsStoreRef, - _extern: &'a Extern, - ) -> Result { - T::get_self_from_extern(_extern).map(|i| i.clone()) - } -} diff --git a/lib/api/src/js/externals/function.rs b/lib/api/src/js/externals/function.rs index 706d74ab0d4..b50691a1638 100644 --- a/lib/api/src/js/externals/function.rs +++ b/lib/api/src/js/externals/function.rs @@ -1,6 +1,6 @@ pub use self::inner::{FromToNativeWasmType, HostFunction, WasmTypeList, WithEnv, WithoutEnv}; +use crate::exports::{ExportError, Exportable}; use crate::function_env::{FunctionEnv, FunctionEnvMut}; -use crate::js::exports::{ExportError, Exportable}; use crate::js::externals::Extern; use crate::js::types::{param_from_js, AsJs}; /* ValFuncRef */ use crate::js::vm::VMExtern; diff --git a/lib/api/src/js/externals/global.rs b/lib/api/src/js/externals/global.rs index 33f0ffbbbca..e18b1c3f5dd 100644 --- a/lib/api/src/js/externals/global.rs +++ b/lib/api/src/js/externals/global.rs @@ -1,4 +1,4 @@ -use crate::js::exports::{ExportError, Exportable}; +use crate::exports::{ExportError, Exportable}; use crate::js::externals::Extern; use crate::js::vm::{VMExtern, VMGlobal}; use crate::js::wasm_bindgen_polyfill::Global as JSGlobal; diff --git a/lib/api/src/js/externals/memory.rs b/lib/api/src/js/externals/memory.rs index 4115b7e988c..98d52ccb43c 100644 --- a/lib/api/src/js/externals/memory.rs +++ b/lib/api/src/js/externals/memory.rs @@ -1,4 +1,4 @@ -use crate::js::exports::{ExportError, Exportable}; +use crate::exports::{ExportError, Exportable}; use crate::js::externals::Extern; use crate::js::vm::{VMExtern, VMMemory}; use crate::js::MemoryType; diff --git a/lib/api/src/js/externals/mod.rs b/lib/api/src/js/externals/mod.rs index 8502ad82288..bd49012d40d 100644 --- a/lib/api/src/js/externals/mod.rs +++ b/lib/api/src/js/externals/mod.rs @@ -10,7 +10,7 @@ pub use self::memory::{Memory, MemoryError}; pub use self::memory_view::MemoryView; pub use self::table::Table; -use crate::js::exports::{ExportError, Exportable}; +use crate::exports::{ExportError, Exportable}; use crate::js::types::AsJs; use crate::js::vm::VMExtern; use crate::store::{AsStoreMut, AsStoreRef}; diff --git a/lib/api/src/js/externals/table.rs b/lib/api/src/js/externals/table.rs index 123f96391ad..e616d5031d5 100644 --- a/lib/api/src/js/externals/table.rs +++ b/lib/api/src/js/externals/table.rs @@ -1,4 +1,4 @@ -use crate::js::exports::{ExportError, Exportable}; +use crate::exports::{ExportError, Exportable}; use crate::js::externals::Extern; use crate::js::vm::{VMExtern, VMFunction, VMTable}; use crate::js::RuntimeError; diff --git a/lib/api/src/js/imports.rs b/lib/api/src/js/imports.rs index af7b4ab6132..8e38c7c43ec 100644 --- a/lib/api/src/js/imports.rs +++ b/lib/api/src/js/imports.rs @@ -1,8 +1,8 @@ //! The import module contains the implementation data structures and helper functions used to //! manipulate and access a wasm module's imports including memories, tables, globals, and //! functions. +use crate::exports::Exports; use crate::js::error::{LinkError, WasmError}; -use crate::js::exports::Exports; use crate::js::module::Module; use crate::js::types::AsJs; use crate::js::vm::VMExtern; diff --git a/lib/api/src/js/instance.rs b/lib/api/src/js/instance.rs index a5326ea083d..988bc6a831b 100644 --- a/lib/api/src/js/instance.rs +++ b/lib/api/src/js/instance.rs @@ -1,5 +1,5 @@ +use crate::exports::Exports; use crate::js::error::InstantiationError; -use crate::js::exports::Exports; use crate::js::externals::Extern; use crate::js::imports::Imports; use crate::js::vm::{VMExtern, VMInstance}; diff --git a/lib/api/src/js/mod.rs b/lib/api/src/js/mod.rs index e8c9c5e74ab..f346836bafa 100644 --- a/lib/api/src/js/mod.rs +++ b/lib/api/src/js/mod.rs @@ -25,7 +25,6 @@ mod lib { pub(crate) mod engine; pub(crate) mod error; -mod exports; pub(crate) mod extern_ref; pub(crate) mod externals; mod imports; @@ -42,7 +41,6 @@ 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::{ Extern, FromToNativeWasmType, Function, Global, HostFunction, Memory, MemoryError, MemoryView, Table, WasmTypeList, diff --git a/lib/api/src/js/native.rs b/lib/api/src/js/native.rs index 95b48f35e42..a0245e1a56f 100644 --- a/lib/api/src/js/native.rs +++ b/lib/api/src/js/native.rs @@ -126,18 +126,6 @@ macro_rules! impl_native_traits { Ok(unsafe { Rets::from_array(store, rets_list_array) }) } } - - #[allow(unused_parens)] - impl<'a, $( $x, )* Rets> crate::js::exports::ExportableWithGenerics<'a, ($( $x ),*), Rets> for TypedFunction<( $( $x ),* ), Rets> - where - $( $x: FromToNativeWasmType, )* - Rets: WasmTypeList, - { - fn get_self_from_extern_with_generics(store: &impl AsStoreRef, _extern: &crate::js::externals::Extern) -> Result { - use crate::js::exports::Exportable; - crate::js::Function::get_self_from_extern(_extern)?.typed(store).map_err(|_| crate::js::exports::ExportError::IncompatibleType) - } - } }; } diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index 49305cbfd6c..af59b11db57 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -430,6 +430,7 @@ compile_error!( ); mod engine; +mod exports; mod extern_ref; mod function_env; mod mem_access; @@ -452,6 +453,7 @@ mod js; pub use js::*; pub use engine::{AsEngineRef, Engine}; +pub use exports::{ExportError, Exportable, Exports, ExportsIterator}; pub use extern_ref::ExternRef; pub use function_env::{FunctionEnv, FunctionEnvMut}; pub use mem_access::{MemoryAccessError, WasmRef, WasmSlice, WasmSliceIter}; diff --git a/lib/api/src/sys/externals/function.rs b/lib/api/src/sys/externals/function.rs index 8984b5fc968..3573d3ab851 100644 --- a/lib/api/src/sys/externals/function.rs +++ b/lib/api/src/sys/externals/function.rs @@ -5,8 +5,8 @@ use wasmer_vm::{ VMDynamicFunctionContext, VMExtern, VMFunction, VMFunctionBody, VMFunctionKind, VMTrampoline, }; +use crate::exports::{ExportError, Exportable}; use crate::store::{AsStoreMut, AsStoreRef}; -use crate::sys::exports::{ExportError, Exportable}; use crate::sys::externals::Extern; use crate::sys::{FunctionType, RuntimeError, TypedFunction}; use crate::FunctionEnv; diff --git a/lib/api/src/sys/externals/global.rs b/lib/api/src/sys/externals/global.rs index a8e059ea711..7d3acb855ea 100644 --- a/lib/api/src/sys/externals/global.rs +++ b/lib/api/src/sys/externals/global.rs @@ -1,5 +1,5 @@ +use crate::exports::{ExportError, Exportable}; use crate::store::{AsStoreMut, AsStoreRef}; -use crate::sys::exports::{ExportError, Exportable}; use crate::sys::externals::Extern; use crate::sys::GlobalType; use crate::sys::Mutability; diff --git a/lib/api/src/sys/externals/memory.rs b/lib/api/src/sys/externals/memory.rs index a54c1c63daa..a8d8b0ca7de 100644 --- a/lib/api/src/sys/externals/memory.rs +++ b/lib/api/src/sys/externals/memory.rs @@ -1,5 +1,5 @@ +use crate::exports::{ExportError, Exportable}; use crate::store::{AsStoreMut, AsStoreRef}; -use crate::sys::exports::{ExportError, Exportable}; use crate::sys::externals::Extern; use crate::sys::MemoryType; use crate::MemoryAccessError; diff --git a/lib/api/src/sys/externals/mod.rs b/lib/api/src/sys/externals/mod.rs index 452d44cd825..84999e61616 100644 --- a/lib/api/src/sys/externals/mod.rs +++ b/lib/api/src/sys/externals/mod.rs @@ -11,7 +11,7 @@ pub use self::memory::Memory; pub use self::memory_view::MemoryView; pub use self::table::Table; -use crate::sys::exports::{ExportError, Exportable}; +use crate::exports::{ExportError, Exportable}; use crate::sys::ExternType; use std::fmt; use wasmer_vm::VMExtern; diff --git a/lib/api/src/sys/externals/table.rs b/lib/api/src/sys/externals/table.rs index ada06289cc4..57c97d130b5 100644 --- a/lib/api/src/sys/externals/table.rs +++ b/lib/api/src/sys/externals/table.rs @@ -1,5 +1,5 @@ +use crate::exports::{ExportError, Exportable}; use crate::store::{AsStoreMut, AsStoreRef}; -use crate::sys::exports::{ExportError, Exportable}; use crate::sys::externals::Extern; use crate::sys::TableType; use crate::Value; diff --git a/lib/api/src/sys/instance.rs b/lib/api/src/sys/instance.rs index 3672ac99ae1..d582058db98 100644 --- a/lib/api/src/sys/instance.rs +++ b/lib/api/src/sys/instance.rs @@ -1,5 +1,5 @@ +use crate::exports::Exports; use crate::module::Module; -use crate::sys::exports::Exports; use crate::sys::{LinkError, RuntimeError}; use std::fmt; use thiserror::Error; diff --git a/lib/api/src/sys/mod.rs b/lib/api/src/sys/mod.rs index 72d627290c0..9bc25c97be4 100644 --- a/lib/api/src/sys/mod.rs +++ b/lib/api/src/sys/mod.rs @@ -1,5 +1,4 @@ pub(crate) mod engine; -mod exports; pub(crate) mod extern_ref; pub(crate) mod externals; mod imports; @@ -8,7 +7,6 @@ pub(crate) mod module; mod native; mod tunables; -pub use crate::sys::exports::{ExportError, Exportable, Exports, ExportsIterator}; pub use crate::sys::externals::{ Extern, FromToNativeWasmType, Function, Global, HostFunction, Memory, MemoryView, Table, WasmTypeList, From 6ede6a1999018bc42ea55e8c627873a8d25869b9 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Fri, 10 Feb 2023 16:50:09 -0800 Subject: [PATCH 25/81] Unified api for native in js/sys --- lib/api/src/js/externals/function.rs | 2 +- lib/api/src/js/native.rs | 20 +++++--------------- lib/api/src/sys/externals/function.rs | 2 +- lib/api/src/sys/native.rs | 20 ++++---------------- 4 files changed, 11 insertions(+), 33 deletions(-) diff --git a/lib/api/src/js/externals/function.rs b/lib/api/src/js/externals/function.rs index b50691a1638..fe3bc725b29 100644 --- a/lib/api/src/js/externals/function.rs +++ b/lib/api/src/js/externals/function.rs @@ -615,7 +615,7 @@ impl Function { } } - Ok(TypedFunction::from_handle(self.clone())) + Ok(TypedFunction::new(store, self.clone())) } pub(crate) fn vm_funcref(&self, store: &impl AsStoreRef) -> VMFuncRef { diff --git a/lib/api/src/js/native.rs b/lib/api/src/js/native.rs index a0245e1a56f..58a0b5b85e4 100644 --- a/lib/api/src/js/native.rs +++ b/lib/api/src/js/native.rs @@ -16,7 +16,6 @@ use crate::store::{AsStoreMut, AsStoreRef}; // use std::panic::{catch_unwind, AssertUnwindSafe}; use crate::js::types::param_from_js; use crate::js::types::AsJs; -use crate::js::vm::VMFunction; use js_sys::Array; use std::iter::FromIterator; use wasm_bindgen::JsValue; @@ -26,7 +25,7 @@ use wasmer_types::RawValue; /// (using the Native ABI). #[derive(Clone)] pub struct TypedFunction { - pub(crate) handle: VMFunction, + pub(crate) func: Function, _phantom: PhantomData<(Args, Rets)>, } @@ -39,24 +38,15 @@ where Rets: WasmTypeList, { #[allow(dead_code)] - pub(crate) fn new(_store: &mut impl AsStoreMut, vm_function: VMFunction) -> Self { + pub(crate) fn new(_store: &impl AsStoreRef, func: Function) -> Self { Self { - handle: vm_function, + func, _phantom: PhantomData, } } pub(crate) fn into_function(self) -> Function { - Function { - handle: self.handle, - } - } - - pub(crate) fn from_handle(f: Function) -> Self { - Self { - handle: f.handle, - _phantom: PhantomData, - } + self.func } } @@ -85,7 +75,7 @@ macro_rules! impl_native_traits { let mut r; // TODO: This loop is needed for asyncify. It will be refactored with https://github.com/wasmerio/wasmer/issues/3451 loop { - r = self.handle.function.apply( + r = self.func.handle.function.apply( &JsValue::UNDEFINED, &Array::from_iter(params_list.iter()) ); diff --git a/lib/api/src/sys/externals/function.rs b/lib/api/src/sys/externals/function.rs index 3573d3ab851..d07f91b75b6 100644 --- a/lib/api/src/sys/externals/function.rs +++ b/lib/api/src/sys/externals/function.rs @@ -764,7 +764,7 @@ impl Function { } } - Ok(TypedFunction::new(self.clone())) + Ok(TypedFunction::new(store, self.clone())) } pub(crate) fn from_vm_extern( diff --git a/lib/api/src/sys/native.rs b/lib/api/src/sys/native.rs index 30746d25004..4bdf191bd38 100644 --- a/lib/api/src/sys/native.rs +++ b/lib/api/src/sys/native.rs @@ -7,17 +7,17 @@ //! let add_one = instance.exports.get_function("function_name")?; //! let add_one_native: TypedFunction = add_one.native().unwrap(); //! ``` -use std::cell::Cell; use std::marker::PhantomData; use crate::sys::{FromToNativeWasmType, Function, RuntimeError, WasmTypeList}; use wasmer_types::RawValue; use crate::native_type::NativeWasmTypeInto; -use crate::store::{AsStoreMut, OnCalledHandler}; +use crate::store::{AsStoreMut, AsStoreRef}; /// A WebAssembly function that can be called natively /// (using the Native ABI). +#[derive(Clone)] pub struct TypedFunction { pub(crate) func: Function, _phantom: PhantomData Rets>, @@ -30,7 +30,8 @@ where Args: WasmTypeList, Rets: WasmTypeList, { - pub(crate) fn new(func: Function) -> Self { + #[allow(dead_code)] + pub(crate) fn new(_store: &impl AsStoreRef, func: Function) -> Self { Self { func, _phantom: PhantomData, @@ -42,19 +43,6 @@ where } } -impl Clone for TypedFunction { - fn clone(&self) -> Self { - Self { - func: self.func.clone(), - _phantom: PhantomData, - } - } -} - -thread_local! { - static ON_CALLED: Cell> = Cell::new(None); -} - macro_rules! impl_native_traits { ( $( $x:ident ),* ) => { #[allow(unused_parens, non_snake_case)] From 7d9ed6b67a672de3eaa082f3e190ba57c35f4921 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Fri, 10 Feb 2023 17:11:23 -0800 Subject: [PATCH 26/81] Unified typed_function in js/sys --- lib/api/src/js/externals/function.rs | 2 +- lib/api/src/js/mod.rs | 10 +---- .../src/js/{native.rs => typed_function.rs} | 31 +------------- lib/api/src/lib.rs | 12 +++++- lib/api/src/sys/externals/function.rs | 2 +- lib/api/src/sys/mod.rs | 10 +---- .../src/sys/{native.rs => typed_function.rs} | 41 +----------------- lib/api/src/typed_function.rs | 42 +++++++++++++++++++ 8 files changed, 58 insertions(+), 92 deletions(-) rename lib/api/src/js/{native.rs => typed_function.rs} (87%) rename lib/api/src/sys/{native.rs => typed_function.rs} (90%) create mode 100644 lib/api/src/typed_function.rs diff --git a/lib/api/src/js/externals/function.rs b/lib/api/src/js/externals/function.rs index fe3bc725b29..6866a78ef1d 100644 --- a/lib/api/src/js/externals/function.rs +++ b/lib/api/src/js/externals/function.rs @@ -6,9 +6,9 @@ use crate::js::types::{param_from_js, AsJs}; /* ValFuncRef */ use crate::js::vm::VMExtern; use crate::js::FunctionType; use crate::js::RuntimeError; -use crate::js::TypedFunction; use crate::store::{AsStoreMut, AsStoreRef, StoreMut}; use crate::value::Value; +use crate::TypedFunction; use js_sys::{Array, Function as JSFunction}; use std::iter::FromIterator; use wasm_bindgen::prelude::*; diff --git a/lib/api/src/js/mod.rs b/lib/api/src/js/mod.rs index f346836bafa..9d0f35f5f89 100644 --- a/lib/api/src/js/mod.rs +++ b/lib/api/src/js/mod.rs @@ -32,9 +32,9 @@ mod instance; pub(crate) mod module; #[cfg(feature = "wasm-types-polyfill")] mod module_info_polyfill; -mod native; pub(crate) mod store; mod trap; +pub(crate) mod typed_function; mod types; pub(crate) mod vm; mod wasm_bindgen_polyfill; @@ -48,7 +48,6 @@ pub use crate::js::externals::{ pub use crate::js::imports::Imports; pub use crate::js::instance::Instance; pub use crate::js::module::{Module, ModuleTypeHints}; -pub use crate::js::native::TypedFunction; pub use crate::js::store::StoreObjects; pub use crate::js::trap::RuntimeError; pub use crate::js::types::ValType as Type; @@ -72,10 +71,3 @@ pub use wasmparser; /// Version number of this crate. pub const VERSION: &str = env!("CARGO_PKG_VERSION"); - -/// This type is deprecated, it has been replaced by TypedFunction. -#[deprecated( - since = "3.0.0", - note = "NativeFunc has been replaced by TypedFunction" -)] -pub type NativeFunc = TypedFunction; diff --git a/lib/api/src/js/native.rs b/lib/api/src/js/typed_function.rs similarity index 87% rename from lib/api/src/js/native.rs rename to lib/api/src/js/typed_function.rs index 58a0b5b85e4..5c5fdb03c30 100644 --- a/lib/api/src/js/native.rs +++ b/lib/api/src/js/typed_function.rs @@ -12,7 +12,7 @@ use std::marker::PhantomData; use crate::js::externals::Function; use crate::js::{FromToNativeWasmType, RuntimeError, WasmTypeList}; use crate::native_type::NativeWasmTypeInto; -use crate::store::{AsStoreMut, AsStoreRef}; +use crate::{AsStoreMut, AsStoreRef, TypedFunction}; // use std::panic::{catch_unwind, AssertUnwindSafe}; use crate::js::types::param_from_js; use crate::js::types::AsJs; @@ -21,35 +21,6 @@ use std::iter::FromIterator; use wasm_bindgen::JsValue; use wasmer_types::RawValue; -/// A WebAssembly function that can be called natively -/// (using the Native ABI). -#[derive(Clone)] -pub struct TypedFunction { - pub(crate) func: Function, - _phantom: PhantomData<(Args, Rets)>, -} - -unsafe impl Send for TypedFunction {} -unsafe impl Sync for TypedFunction {} - -impl TypedFunction -where - Args: WasmTypeList, - Rets: WasmTypeList, -{ - #[allow(dead_code)] - pub(crate) fn new(_store: &impl AsStoreRef, func: Function) -> Self { - Self { - func, - _phantom: PhantomData, - } - } - - pub(crate) fn into_function(self) -> Function { - self.func - } -} - macro_rules! impl_native_traits { ( $( $x:ident ),* ) => { #[allow(unused_parens, non_snake_case)] diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index af59b11db57..c31370abbfa 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -433,11 +433,13 @@ mod engine; mod exports; mod extern_ref; mod function_env; +mod into_bytes; mod mem_access; mod module; mod native_type; mod ptr; mod store; +mod typed_function; mod value; #[cfg(feature = "sys")] @@ -456,6 +458,7 @@ pub use engine::{AsEngineRef, Engine}; pub use exports::{ExportError, Exportable, Exports, ExportsIterator}; pub use extern_ref::ExternRef; pub use function_env::{FunctionEnv, FunctionEnvMut}; +pub use into_bytes::IntoBytes; pub use mem_access::{MemoryAccessError, WasmRef, WasmSlice, WasmSliceIter}; pub use module::{IoCompileError, Module}; pub use native_type::NativeWasmTypeInto; @@ -463,7 +466,12 @@ pub use ptr::{Memory32, Memory64, MemorySize, WasmPtr, WasmPtr64}; pub use store::{AsStoreMut, AsStoreRef, OnCalledHandler, Store, StoreId, StoreMut, StoreRef}; #[cfg(feature = "sys")] pub use store::{TrapHandlerFn, Tunables}; +pub use typed_function::TypedFunction; pub use value::Value; -mod into_bytes; -pub use into_bytes::IntoBytes; +/// This type is deprecated, it has been replaced by TypedFunction. +#[deprecated( + since = "3.0.0", + note = "NativeFunc has been replaced by TypedFunction" +)] +pub type NativeFunc = TypedFunction; diff --git a/lib/api/src/sys/externals/function.rs b/lib/api/src/sys/externals/function.rs index d07f91b75b6..b7bdbe61b92 100644 --- a/lib/api/src/sys/externals/function.rs +++ b/lib/api/src/sys/externals/function.rs @@ -8,8 +8,8 @@ use wasmer_vm::{ use crate::exports::{ExportError, Exportable}; use crate::store::{AsStoreMut, AsStoreRef}; use crate::sys::externals::Extern; -use crate::sys::{FunctionType, RuntimeError, TypedFunction}; use crate::FunctionEnv; +use crate::{FunctionType, RuntimeError, TypedFunction}; pub use inner::{FromToNativeWasmType, HostFunction, WasmTypeList, WithEnv, WithoutEnv}; diff --git a/lib/api/src/sys/mod.rs b/lib/api/src/sys/mod.rs index 9bc25c97be4..2ee265b6576 100644 --- a/lib/api/src/sys/mod.rs +++ b/lib/api/src/sys/mod.rs @@ -4,8 +4,8 @@ pub(crate) mod externals; mod imports; mod instance; pub(crate) mod module; -mod native; mod tunables; +pub(crate) mod typed_function; pub use crate::sys::externals::{ Extern, FromToNativeWasmType, Function, Global, HostFunction, Memory, MemoryView, Table, @@ -13,7 +13,6 @@ pub use crate::sys::externals::{ }; pub use crate::sys::imports::Imports; pub use crate::sys::instance::{Instance, InstantiationError}; -pub use crate::sys::native::TypedFunction; pub use crate::sys::tunables::BaseTunables; pub use target_lexicon::{Architecture, CallingConvention, OperatingSystem, Triple, HOST}; @@ -64,10 +63,3 @@ pub use wasmer_compiler::{Artifact, EngineBuilder}; /// Version number of this crate. pub const VERSION: &str = env!("CARGO_PKG_VERSION"); - -/// This type is deprecated, it has been replaced by TypedFunction. -#[deprecated( - since = "3.0.0", - note = "NativeFunc has been replaced by TypedFunction" -)] -pub type NativeFunc = TypedFunction; diff --git a/lib/api/src/sys/native.rs b/lib/api/src/sys/typed_function.rs similarity index 90% rename from lib/api/src/sys/native.rs rename to lib/api/src/sys/typed_function.rs index 4bdf191bd38..15f29a57db0 100644 --- a/lib/api/src/sys/native.rs +++ b/lib/api/src/sys/typed_function.rs @@ -1,48 +1,9 @@ -//! Native Functions. -//! -//! This module creates the helper `TypedFunction` that let us call WebAssembly -//! functions with the native ABI, that is: -//! -//! ```ignore -//! let add_one = instance.exports.get_function("function_name")?; -//! let add_one_native: TypedFunction = add_one.native().unwrap(); -//! ``` -use std::marker::PhantomData; - -use crate::sys::{FromToNativeWasmType, Function, RuntimeError, WasmTypeList}; +use crate::{FromToNativeWasmType, RuntimeError, TypedFunction, WasmTypeList}; use wasmer_types::RawValue; use crate::native_type::NativeWasmTypeInto; use crate::store::{AsStoreMut, AsStoreRef}; -/// A WebAssembly function that can be called natively -/// (using the Native ABI). -#[derive(Clone)] -pub struct TypedFunction { - pub(crate) func: Function, - _phantom: PhantomData Rets>, -} - -unsafe impl Send for TypedFunction {} - -impl TypedFunction -where - Args: WasmTypeList, - Rets: WasmTypeList, -{ - #[allow(dead_code)] - pub(crate) fn new(_store: &impl AsStoreRef, func: Function) -> Self { - Self { - func, - _phantom: PhantomData, - } - } - - pub(crate) fn into_function(self) -> Function { - self.func - } -} - macro_rules! impl_native_traits { ( $( $x:ident ),* ) => { #[allow(unused_parens, non_snake_case)] diff --git a/lib/api/src/typed_function.rs b/lib/api/src/typed_function.rs new file mode 100644 index 00000000000..ccaadcfd4e5 --- /dev/null +++ b/lib/api/src/typed_function.rs @@ -0,0 +1,42 @@ +//! Native Functions. +//! +//! This module creates the helper `TypedFunction` that let us call WebAssembly +//! functions with the native ABI, that is: +//! +//! ```ignore +//! let add_one = instance.exports.get_function("function_name")?; +//! let add_one_native: TypedFunction = add_one.native().unwrap(); +//! ``` +use crate::{Function, WasmTypeList}; +use std::marker::PhantomData; + +use crate::store::AsStoreRef; + +/// A WebAssembly function that can be called natively +/// (using the Native ABI). +#[derive(Clone)] +pub struct TypedFunction { + pub(crate) func: Function, + _phantom: PhantomData Rets>, +} + +unsafe impl Send for TypedFunction {} +unsafe impl Sync for TypedFunction {} + +impl TypedFunction +where + Args: WasmTypeList, + Rets: WasmTypeList, +{ + #[allow(dead_code)] + pub(crate) fn new(_store: &impl AsStoreRef, func: Function) -> Self { + Self { + func, + _phantom: PhantomData, + } + } + + pub(crate) fn into_function(self) -> Function { + self.func + } +} From 6c6f070c8d1680922940d39a4165dbd0746ad747 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Fri, 10 Feb 2023 17:19:31 -0800 Subject: [PATCH 27/81] Remove unnecessary compiler flags in wasmer crate --- lib/api/src/native_type.rs | 1 - lib/api/src/sys/externals/function.rs | 29 --------------------------- lib/api/src/sys/externals/global.rs | 1 - lib/api/src/sys/externals/memory.rs | 2 -- lib/api/src/sys/externals/table.rs | 3 --- lib/api/src/sys/instance.rs | 4 ---- lib/api/src/sys/module.rs | 2 -- 7 files changed, 42 deletions(-) diff --git a/lib/api/src/native_type.rs b/lib/api/src/native_type.rs index 2ca88e22765..3b13084ff62 100644 --- a/lib/api/src/native_type.rs +++ b/lib/api/src/native_type.rs @@ -186,7 +186,6 @@ impl NativeWasmType for Function { type Abi = usize; } -#[cfg(feature = "compiler")] impl NativeWasmTypeInto for Option { #[inline] unsafe fn from_abi(store: &mut impl AsStoreMut, abi: Self::Abi) -> Self { diff --git a/lib/api/src/sys/externals/function.rs b/lib/api/src/sys/externals/function.rs index b7bdbe61b92..13144c39cd8 100644 --- a/lib/api/src/sys/externals/function.rs +++ b/lib/api/src/sys/externals/function.rs @@ -13,7 +13,6 @@ use crate::{FunctionType, RuntimeError, TypedFunction}; pub use inner::{FromToNativeWasmType, HostFunction, WasmTypeList, WithEnv, WithoutEnv}; -#[cfg(feature = "compiler")] use { crate::{ store::{StoreInner, StoreMut}, @@ -59,7 +58,6 @@ impl Function { /// /// If you know the signature of the host function at compile time, /// consider using [`Function::new_typed`] for less runtime overhead. - #[cfg(feature = "compiler")] pub fn new(store: &mut impl AsStoreMut, ty: FT, func: F) -> Self where FT: Into, @@ -72,7 +70,6 @@ impl Function { Self::new_with_env(store, &env, ty, wrapped_func) } - #[cfg(feature = "compiler")] /// Creates a new host `Function` (dynamic) with the provided signature. /// /// If you know the signature of the host function at compile time, @@ -193,7 +190,6 @@ impl Function { } } - #[cfg(feature = "compiler")] #[deprecated( since = "3.0.0", note = "new_native() has been renamed to new_typed()." @@ -208,7 +204,6 @@ impl Function { Self::new_typed(store, func) } - #[cfg(feature = "compiler")] /// Creates a new host `Function` from a native function. pub fn new_typed(store: &mut impl AsStoreMut, func: F) -> Self where @@ -252,7 +247,6 @@ impl Function { } } - #[cfg(feature = "compiler")] #[deprecated( since = "3.0.0", note = "new_native_with_env() has been renamed to new_typed_with_env()." @@ -271,7 +265,6 @@ impl Function { Self::new_typed_with_env(store, env, func) } - #[cfg(feature = "compiler")] /// Creates a new host `Function` with an environment from a typed function. /// /// The function signature is automatically retrieved using the @@ -337,22 +330,6 @@ impl Function { } } - #[allow(missing_docs)] - #[allow(unused_variables)] - #[cfg(not(feature = "compiler"))] - pub fn new_typed_with_env( - store: &mut impl AsStoreMut, - env: &FunctionEnv, - func: F, - ) -> Self - where - F: HostFunction + 'static + Send + Sync, - Args: WasmTypeList, - Rets: WasmTypeList, - { - unimplemented!("this platform does not support functions without the 'compiler' feature") - } - /// Returns the [`FunctionType`] of the `Function`. /// /// # Example @@ -378,7 +355,6 @@ impl Function { .clone() } - #[cfg(feature = "compiler")] fn call_wasm( &self, store: &mut impl AsStoreMut, @@ -433,7 +409,6 @@ impl Function { Ok(()) } - #[cfg(feature = "compiler")] fn call_wasm_raw( &self, store: &mut impl AsStoreMut, @@ -532,7 +507,6 @@ impl Function { self.ty(store).results().len() } - #[cfg(feature = "compiler")] /// Call the `Function` function. /// /// Depending on where the Function is defined, it will call it. @@ -584,7 +558,6 @@ impl Function { #[doc(hidden)] #[allow(missing_docs)] - #[cfg(feature = "compiler")] pub fn call_raw( &self, store: &mut impl AsStoreMut, @@ -632,7 +605,6 @@ impl Function { /// Transform this WebAssembly function into a native function. /// See [`TypedFunction`] to learn more. - #[cfg(feature = "compiler")] #[deprecated(since = "3.0.0", note = "native() has been renamed to typed().")] pub fn native( &self, @@ -978,7 +950,6 @@ mod inner { } } - #[cfg(feature = "compiler")] unsafe impl FromToNativeWasmType for Option { type Native = Self; diff --git a/lib/api/src/sys/externals/global.rs b/lib/api/src/sys/externals/global.rs index 7d3acb855ea..5c053cd47d8 100644 --- a/lib/api/src/sys/externals/global.rs +++ b/lib/api/src/sys/externals/global.rs @@ -93,7 +93,6 @@ impl Global { *self.handle.get(store.as_store_ref().objects()).ty() } - #[cfg(feature = "compiler")] /// Retrieves the current value [`Value`] that the Global has. /// /// # Example diff --git a/lib/api/src/sys/externals/memory.rs b/lib/api/src/sys/externals/memory.rs index a8d8b0ca7de..b81285583f9 100644 --- a/lib/api/src/sys/externals/memory.rs +++ b/lib/api/src/sys/externals/memory.rs @@ -35,7 +35,6 @@ pub struct Memory { } impl Memory { - #[cfg(feature = "compiler")] /// Creates a new host `Memory` from the provided [`MemoryType`]. /// /// This function will construct the `Memory` using the store @@ -133,7 +132,6 @@ impl Memory { } /// Copies the memory to a new store and returns a memory reference to it - #[cfg(feature = "compiler")] pub fn copy_to_store( &self, store: &impl AsStoreRef, diff --git a/lib/api/src/sys/externals/table.rs b/lib/api/src/sys/externals/table.rs index 57c97d130b5..d4d735da675 100644 --- a/lib/api/src/sys/externals/table.rs +++ b/lib/api/src/sys/externals/table.rs @@ -46,7 +46,6 @@ fn value_to_table_element( }) } -#[cfg(feature = "compiler")] fn value_from_table_element(store: &mut impl AsStoreMut, item: wasmer_vm::TableElement) -> Value { match item { wasmer_vm::TableElement::FuncRef(funcref) => { @@ -59,7 +58,6 @@ fn value_from_table_element(store: &mut impl AsStoreMut, item: wasmer_vm::TableE } impl Table { - #[cfg(feature = "compiler")] /// Creates a new `Table` with the provided [`TableType`] definition. /// /// All the elements in the table will be set to the `init` value. @@ -94,7 +92,6 @@ impl Table { *self.handle.get(store.as_store_ref().objects()).ty() } - #[cfg(feature = "compiler")] /// Retrieves an element of the table at the provided `index`. pub fn get(&self, store: &mut impl AsStoreMut, index: u32) -> Option { let item = self.handle.get(store.as_store_ref().objects()).get(index)?; diff --git a/lib/api/src/sys/instance.rs b/lib/api/src/sys/instance.rs index d582058db98..2327c64779d 100644 --- a/lib/api/src/sys/instance.rs +++ b/lib/api/src/sys/instance.rs @@ -5,9 +5,7 @@ use std::fmt; use thiserror::Error; use wasmer_vm::{StoreHandle, VMInstance}; -#[cfg(feature = "compiler")] use crate::store::AsStoreMut; -#[cfg(feature = "compiler")] use crate::sys::{externals::Extern, imports::Imports}; /// A WebAssembly Instance is a stateful, executable @@ -80,7 +78,6 @@ impl From for InstantiationError { } impl Instance { - #[cfg(feature = "compiler")] /// Creates a new `Instance` from a WebAssembly [`Module`] and a /// set of imports using [`Imports`] or the [`imports`] macro helper. /// @@ -147,7 +144,6 @@ impl Instance { Ok(instance) } - #[cfg(feature = "compiler")] /// Creates a new `Instance` from a WebAssembly [`Module`] and a /// vector of imports. /// diff --git a/lib/api/src/sys/module.rs b/lib/api/src/sys/module.rs index ea4d5539908..cd2230652a5 100644 --- a/lib/api/src/sys/module.rs +++ b/lib/api/src/sys/module.rs @@ -9,9 +9,7 @@ use wasmer_types::{ }; use wasmer_types::{ExportType, ImportType}; -#[cfg(feature = "compiler")] use crate::{sys::InstantiationError, AsStoreMut, AsStoreRef, IntoBytes}; -#[cfg(feature = "compiler")] use wasmer_vm::VMInstance; /// A WebAssembly Module contains stateless WebAssembly From 9f83b84e866c80a4961b15a32496ae8e2f699b82 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Fri, 10 Feb 2023 18:05:56 -0800 Subject: [PATCH 28/81] Moved js-specific functions to as_js module --- lib/api/src/js/as_js.rs | 223 +++++++++++++++++++++++++++ lib/api/src/js/externals/function.rs | 2 +- lib/api/src/js/externals/mod.rs | 15 +- lib/api/src/js/imports.rs | 112 +------------- lib/api/src/js/mod.rs | 12 +- lib/api/src/js/module.rs | 4 +- lib/api/src/js/typed_function.rs | 3 +- lib/api/src/js/types.rs | 58 ------- 8 files changed, 236 insertions(+), 193 deletions(-) create mode 100644 lib/api/src/js/as_js.rs delete mode 100644 lib/api/src/js/types.rs diff --git a/lib/api/src/js/as_js.rs b/lib/api/src/js/as_js.rs new file mode 100644 index 00000000000..d8352346951 --- /dev/null +++ b/lib/api/src/js/as_js.rs @@ -0,0 +1,223 @@ +//use crate::js::externals::Function; +// use crate::store::{Store, StoreObject}; +// use crate::js::RuntimeError; +use crate::js::externals::Extern; +use crate::js::imports::Imports; +use crate::js::vm::VMExtern; +use crate::store::{AsStoreMut, AsStoreRef}; +use crate::value::Value; +use crate::ValType; +use std::collections::HashMap; +use wasm_bindgen::JsValue; +use wasmer_types::ExternType; + +/// Convert the given type to a [`JsValue`]. +pub trait AsJs { + /// The inner definition type from this Javascript object + type DefinitionType; + /// Convert the given type to a [`JsValue`]. + fn as_jsvalue(&self, store: &impl AsStoreRef) -> JsValue; + /// Convert the given type to a [`JsValue`]. + fn from_jsvalue( + &self, + store: &mut impl AsStoreMut, + type_: &Self::DefinitionType, + value: &JsValue, + ) -> Self; +} + +#[inline] +pub fn param_from_js(ty: &ValType, js_val: &JsValue) -> Value { + match ty { + ValType::I32 => Value::I32(js_val.as_f64().unwrap() as _), + ValType::I64 => Value::I64(js_val.as_f64().unwrap() as _), + ValType::F32 => Value::F32(js_val.as_f64().unwrap() as _), + ValType::F64 => Value::F64(js_val.as_f64().unwrap()), + t => unimplemented!( + "The type `{:?}` is not yet supported in the JS Function API", + t + ), + } +} + +impl AsJs for Value { + type DefinitionType = ValType; + + fn as_jsvalue(&self, _store: &impl AsStoreRef) -> JsValue { + match self { + Self::I32(i) => JsValue::from_f64(*i as f64), + Self::I64(i) => JsValue::from_f64(*i as f64), + Self::F32(f) => JsValue::from_f64(*f as f64), + Self::F64(f) => JsValue::from_f64(*f), + Self::V128(f) => JsValue::from_f64(*f as f64), + Self::FuncRef(Some(func)) => func.handle.function.clone().into(), + Self::FuncRef(None) => JsValue::null(), + Self::ExternRef(_) => unimplemented!(), + } + } + + fn from_jsvalue( + &self, + _store: &mut impl AsStoreMut, + type_: &Self::DefinitionType, + value: &JsValue, + ) -> Self { + param_from_js(type_, value) + } +} + +impl AsJs for wasmer_types::RawValue { + type DefinitionType = ValType; + + fn as_jsvalue(&self, _store: &impl AsStoreRef) -> JsValue { + unsafe { JsValue::from_f64(self.into()) } + } + + fn from_jsvalue( + &self, + _store: &mut impl AsStoreMut, + type_: &Self::DefinitionType, + value: &JsValue, + ) -> Self { + unimplemented!(); + } +} + +impl AsJs for Imports { + type DefinitionType = crate::js::module::Module; + + // Annotation is here to prevent spurious IDE warnings. + #[allow(unused_unsafe)] + fn as_jsvalue(&self, store: &impl AsStoreRef) -> wasm_bindgen::JsValue { + // /// Returns the `Imports` as a Javascript `Object` + // pub fn as_jsobject(&self, store: &impl AsStoreRef) -> js_sys::Object { + // let imports = js_sys::Object::new(); + // let namespaces: HashMap<&str, Vec<(&str, &Extern)>> = + // self.map + // .iter() + // .fold(HashMap::default(), |mut acc, ((ns, name), ext)| { + // acc.entry(ns.as_str()) + // .or_default() + // .push((name.as_str(), ext)); + // acc + // }); + + // for (ns, exports) in namespaces.into_iter() { + // let import_namespace = js_sys::Object::new(); + // for (name, ext) in exports { + // // Annotation is here to prevent spurious IDE warnings. + // #[allow(unused_unsafe)] + // unsafe { + // js_sys::Reflect::set(&import_namespace, &name.into(), &ext.as_jsvalue(store)) + // .expect("Error while setting into the js namespace object"); + // } + // } + // // Annotation is here to prevent spurious IDE warnings. + // #[allow(unused_unsafe)] + // unsafe { + // js_sys::Reflect::set(&imports, &ns.into(), &import_namespace.into()) + // .expect("Error while setting into the js imports object"); + // } + // } + // imports + // } + + let imports_object = js_sys::Object::new(); + for (namespace, name, extern_) in self.iter() { + let val = unsafe { js_sys::Reflect::get(&imports_object, &namespace.into()).unwrap() }; + if !val.is_undefined() { + // If the namespace is already set + + // Annotation is here to prevent spurious IDE warnings. + #[allow(unused_unsafe)] + unsafe { + js_sys::Reflect::set( + &val, + &name.into(), + &extern_.as_jsvalue(&store.as_store_ref()), + ) + .unwrap(); + } + } else { + // If the namespace doesn't exist + let import_namespace = js_sys::Object::new(); + #[allow(unused_unsafe)] + unsafe { + js_sys::Reflect::set( + &import_namespace, + &name.into(), + &extern_.as_jsvalue(&store.as_store_ref()), + ) + .unwrap(); + js_sys::Reflect::set( + &imports_object, + &namespace.into(), + &import_namespace.into(), + ) + .unwrap(); + } + } + } + imports_object.into() + } + + fn from_jsvalue( + &self, + store: &mut impl AsStoreMut, + module: &Self::DefinitionType, + value: &JsValue, + ) -> Self { + let module_imports: HashMap<(String, String), ExternType> = module + .imports() + .map(|import| { + ( + (import.module().to_string(), import.name().to_string()), + import.ty().clone(), + ) + }) + .collect::>(); + + let mut map: HashMap<(String, String), Extern> = HashMap::new(); + let object: js_sys::Object = value.clone().into(); + for module_entry in js_sys::Object::entries(&object).iter() { + let module_entry: js_sys::Array = module_entry.into(); + let module_name = module_entry.get(0).as_string().unwrap().to_string(); + let module_import_object: js_sys::Object = module_entry.get(1).into(); + for import_entry in js_sys::Object::entries(&module_import_object).iter() { + let import_entry: js_sys::Array = import_entry.into(); + let import_name = import_entry.get(0).as_string().unwrap().to_string(); + let import_js: wasm_bindgen::JsValue = import_entry.get(1); + let key = (module_name.clone(), import_name); + let extern_type = module_imports.get(&key).unwrap(); + let export = + VMExtern::from_js_value(import_js, store, extern_type.clone()).unwrap(); + let extern_ = Extern::from_vm_extern(store, export); + map.insert(key, extern_); + } + } + + Self { map } + } +} + +impl AsJs for Extern { + type DefinitionType = ExternType; + + fn as_jsvalue(&self, store: &impl AsStoreRef) -> wasm_bindgen::JsValue { + match self { + Self::Function(_) => self.to_vm_extern().as_jsvalue(store), + Self::Global(_) => self.to_vm_extern().as_jsvalue(store), + Self::Table(_) => self.to_vm_extern().as_jsvalue(store), + Self::Memory(_) => self.to_vm_extern().as_jsvalue(store), + } + .clone() + } + fn from_jsvalue( + &self, + _store: &mut impl AsStoreMut, + type_: &Self::DefinitionType, + value: &JsValue, + ) -> Self { + unimplemented!(); + } +} diff --git a/lib/api/src/js/externals/function.rs b/lib/api/src/js/externals/function.rs index 6866a78ef1d..1ab9fac2356 100644 --- a/lib/api/src/js/externals/function.rs +++ b/lib/api/src/js/externals/function.rs @@ -1,8 +1,8 @@ pub use self::inner::{FromToNativeWasmType, HostFunction, WasmTypeList, WithEnv, WithoutEnv}; use crate::exports::{ExportError, Exportable}; use crate::function_env::{FunctionEnv, FunctionEnvMut}; +use crate::js::as_js::{param_from_js, AsJs}; /* ValFuncRef */ use crate::js::externals::Extern; -use crate::js::types::{param_from_js, AsJs}; /* ValFuncRef */ use crate::js::vm::VMExtern; use crate::js::FunctionType; use crate::js::RuntimeError; diff --git a/lib/api/src/js/externals/mod.rs b/lib/api/src/js/externals/mod.rs index bd49012d40d..b58e17ae15c 100644 --- a/lib/api/src/js/externals/mod.rs +++ b/lib/api/src/js/externals/mod.rs @@ -11,7 +11,6 @@ pub use self::memory_view::MemoryView; pub use self::table::Table; use crate::exports::{ExportError, Exportable}; -use crate::js::types::AsJs; use crate::js::vm::VMExtern; use crate::store::{AsStoreMut, AsStoreRef}; use std::fmt; @@ -37,7 +36,7 @@ impl Extern { /// Return the underlying type of the inner `Extern`. pub fn ty(&self, store: &impl AsStoreRef) -> ExternType { match self { - Self::Function(ft) => ExternType::Function(ft.ty(store).clone()), + Self::Function(ft) => ExternType::Function(ft.ty(store)), Self::Memory(ft) => ExternType::Memory(ft.ty(store)), Self::Table(tt) => ExternType::Table(tt.ty(store)), Self::Global(gt) => ExternType::Global(gt.ty(store)), @@ -75,18 +74,6 @@ impl Extern { } } -impl AsJs for Extern { - fn as_jsvalue(&self, store: &impl AsStoreRef) -> wasm_bindgen::JsValue { - match self { - Self::Function(_) => self.to_vm_extern().as_jsvalue(store), - Self::Global(_) => self.to_vm_extern().as_jsvalue(store), - Self::Table(_) => self.to_vm_extern().as_jsvalue(store), - Self::Memory(_) => self.to_vm_extern().as_jsvalue(store), - } - .clone() - } -} - impl<'a> Exportable<'a> for Extern { fn get_self_from_extern(_extern: &'a Self) -> Result<&'a Self, ExportError> { // Since this is already an extern, we can just return it. diff --git a/lib/api/src/js/imports.rs b/lib/api/src/js/imports.rs index 8e38c7c43ec..56edd3b8a3d 100644 --- a/lib/api/src/js/imports.rs +++ b/lib/api/src/js/imports.rs @@ -4,9 +4,6 @@ use crate::exports::Exports; use crate::js::error::{LinkError, WasmError}; use crate::js::module::Module; -use crate::js::types::AsJs; -use crate::js::vm::VMExtern; -use crate::js::ExternType; use crate::store::{AsStoreMut, AsStoreRef}; use crate::Extern; use std::collections::HashMap; @@ -42,7 +39,7 @@ use wasmer_types::ImportError; /// ``` #[derive(Clone, Default)] pub struct Imports { - map: HashMap<(String, String), Extern>, + pub(crate) map: HashMap<(String, String), Extern>, } impl Imports { @@ -156,39 +153,6 @@ impl Imports { Ok(ret) } - /// Returns the `Imports` as a Javascript `Object` - pub fn as_jsobject(&self, store: &impl AsStoreRef) -> js_sys::Object { - let imports = js_sys::Object::new(); - let namespaces: HashMap<&str, Vec<(&str, &Extern)>> = - self.map - .iter() - .fold(HashMap::default(), |mut acc, ((ns, name), ext)| { - acc.entry(ns.as_str()) - .or_default() - .push((name.as_str(), ext)); - acc - }); - - for (ns, exports) in namespaces.into_iter() { - let import_namespace = js_sys::Object::new(); - for (name, ext) in exports { - // Annotation is here to prevent spurious IDE warnings. - #[allow(unused_unsafe)] - unsafe { - js_sys::Reflect::set(&import_namespace, &name.into(), &ext.as_jsvalue(store)) - .expect("Error while setting into the js namespace object"); - } - } - // Annotation is here to prevent spurious IDE warnings. - #[allow(unused_unsafe)] - unsafe { - js_sys::Reflect::set(&imports, &ns.into(), &import_namespace.into()) - .expect("Error while setting into the js imports object"); - } - } - imports - } - /// Iterates through all the imports in this structure pub fn iter<'a>(&'a self) -> ImportsIterator<'a> { ImportsIterator::new(self) @@ -207,79 +171,7 @@ impl Imports { module: &Module, object: js_sys::Object, ) -> Result { - let module_imports: HashMap<(String, String), ExternType> = module - .imports() - .map(|import| { - ( - (import.module().to_string(), import.name().to_string()), - import.ty().clone(), - ) - }) - .collect::>(); - - let mut map: HashMap<(String, String), Extern> = HashMap::new(); - - for module_entry in js_sys::Object::entries(&object).iter() { - let module_entry: js_sys::Array = module_entry.into(); - let module_name = module_entry.get(0).as_string().unwrap().to_string(); - let module_import_object: js_sys::Object = module_entry.get(1).into(); - for import_entry in js_sys::Object::entries(&module_import_object).iter() { - let import_entry: js_sys::Array = import_entry.into(); - let import_name = import_entry.get(0).as_string().unwrap().to_string(); - let import_js: wasm_bindgen::JsValue = import_entry.get(1); - let key = (module_name.clone(), import_name); - let extern_type = module_imports.get(&key).unwrap(); - let export = VMExtern::from_js_value(import_js, store, extern_type.clone())?; - let extern_ = Extern::from_vm_extern(store, export); - map.insert(key, extern_); - } - } - - Ok(Self { map }) - } -} - -impl AsJs for Imports { - // Annotation is here to prevent spurious IDE warnings. - #[allow(unused_unsafe)] - fn as_jsvalue(&self, store: &impl AsStoreRef) -> wasm_bindgen::JsValue { - let imports_object = js_sys::Object::new(); - for (namespace, name, extern_) in self.iter() { - let val = unsafe { js_sys::Reflect::get(&imports_object, &namespace.into()).unwrap() }; - if !val.is_undefined() { - // If the namespace is already set - - // Annotation is here to prevent spurious IDE warnings. - #[allow(unused_unsafe)] - unsafe { - js_sys::Reflect::set( - &val, - &name.into(), - &extern_.as_jsvalue(&store.as_store_ref()), - ) - .unwrap(); - } - } else { - // If the namespace doesn't exist - let import_namespace = js_sys::Object::new(); - #[allow(unused_unsafe)] - unsafe { - js_sys::Reflect::set( - &import_namespace, - &name.into(), - &extern_.as_jsvalue(&store.as_store_ref()), - ) - .unwrap(); - js_sys::Reflect::set( - &imports_object, - &namespace.into(), - &import_namespace.into(), - ) - .unwrap(); - } - } - } - imports_object.into() + unimplemented!(); } } diff --git a/lib/api/src/js/mod.rs b/lib/api/src/js/mod.rs index 9d0f35f5f89..40e8355b487 100644 --- a/lib/api/src/js/mod.rs +++ b/lib/api/src/js/mod.rs @@ -23,6 +23,7 @@ mod lib { } } +mod as_js; pub(crate) mod engine; pub(crate) mod error; pub(crate) mod extern_ref; @@ -35,10 +36,10 @@ mod module_info_polyfill; pub(crate) mod store; mod trap; pub(crate) mod typed_function; -mod types; pub(crate) mod vm; mod wasm_bindgen_polyfill; +pub use crate::js::as_js::AsJs; pub use crate::js::engine::Engine; pub use crate::js::error::{DeserializeError, InstantiationError, SerializeError}; pub use crate::js::externals::{ @@ -50,11 +51,6 @@ pub use crate::js::instance::Instance; pub use crate::js::module::{Module, ModuleTypeHints}; pub use crate::js::store::StoreObjects; pub use crate::js::trap::RuntimeError; -pub use crate::js::types::ValType as Type; -pub use crate::js::types::{ - ExportType, ExternType, FunctionType, GlobalType, ImportType, MemoryType, Mutability, - TableType, ValType, -}; pub use wasmer_types::is_wasm; // TODO: OnCalledAction is needed for asyncify. It will be refactored with https://github.com/wasmerio/wasmer/issues/3451 @@ -62,6 +58,10 @@ pub use wasmer_types::{ Bytes, ExportIndex, GlobalInit, LocalFunctionIndex, OnCalledAction, Pages, ValueType, WASM_MAX_PAGES, WASM_MIN_PAGES, WASM_PAGE_SIZE, }; +pub use wasmer_types::{ + ExportType, ExternType, FunctionType, GlobalType, ImportType, MemoryType, Mutability, + TableType, Type as ValType, Type, +}; #[cfg(feature = "wat")] pub use wat::parse_bytes as wat2wasm; diff --git a/lib/api/src/js/module.rs b/lib/api/src/js/module.rs index ee884ed176a..60a111be1ca 100644 --- a/lib/api/src/js/module.rs +++ b/lib/api/src/js/module.rs @@ -3,13 +3,13 @@ use crate::js::error::InstantiationError; use crate::js::error::WasmError; use crate::js::externals::Extern; use crate::js::imports::Imports; -use crate::js::types::{AsJs, ExportType, ImportType}; use crate::js::vm::VMInstance; +use crate::js::AsJs; use crate::js::RuntimeError; use crate::module::IoCompileError; use crate::store::AsStoreMut; -use crate::AsEngineRef; use crate::IntoBytes; +use crate::{AsEngineRef, ExportType, ImportType}; use bytes::Bytes; use js_sys::{Reflect, Uint8Array, WebAssembly}; use std::fmt; diff --git a/lib/api/src/js/typed_function.rs b/lib/api/src/js/typed_function.rs index 5c5fdb03c30..075872f4684 100644 --- a/lib/api/src/js/typed_function.rs +++ b/lib/api/src/js/typed_function.rs @@ -14,8 +14,7 @@ use crate::js::{FromToNativeWasmType, RuntimeError, WasmTypeList}; use crate::native_type::NativeWasmTypeInto; use crate::{AsStoreMut, AsStoreRef, TypedFunction}; // use std::panic::{catch_unwind, AssertUnwindSafe}; -use crate::js::types::param_from_js; -use crate::js::types::AsJs; +use crate::js::as_js::{param_from_js, AsJs}; use js_sys::Array; use std::iter::FromIterator; use wasm_bindgen::JsValue; diff --git a/lib/api/src/js/types.rs b/lib/api/src/js/types.rs deleted file mode 100644 index ecea9c64b7f..00000000000 --- a/lib/api/src/js/types.rs +++ /dev/null @@ -1,58 +0,0 @@ -//use crate::js::externals::Function; -// use crate::store::{Store, StoreObject}; -// use crate::js::RuntimeError; -use crate::store::AsStoreRef; -use crate::value::Value; -use wasm_bindgen::JsValue; -pub use wasmer_types::{ - ExportType, ExternType, FunctionType, GlobalType, ImportType, MemoryType, Mutability, - TableType, Type as ValType, -}; - -/// WebAssembly computations manipulate values of basic value types: -/// * Integers (32 or 64 bit width) -/// * Floating-point (32 or 64 bit width) -/// * Vectors (128 bits, with 32 or 64 bit lanes) -/// -/// Spec: -// pub type Value = (); -//pub type Value = Value; - -pub trait AsJs { - fn as_jsvalue(&self, store: &impl AsStoreRef) -> JsValue; -} - -#[inline] -pub fn param_from_js(ty: &ValType, js_val: &JsValue) -> Value { - match ty { - ValType::I32 => Value::I32(js_val.as_f64().unwrap() as _), - ValType::I64 => Value::I64(js_val.as_f64().unwrap() as _), - ValType::F32 => Value::F32(js_val.as_f64().unwrap() as _), - ValType::F64 => Value::F64(js_val.as_f64().unwrap()), - t => unimplemented!( - "The type `{:?}` is not yet supported in the JS Function API", - t - ), - } -} - -impl AsJs for Value { - fn as_jsvalue(&self, _store: &impl AsStoreRef) -> JsValue { - match self { - Self::I32(i) => JsValue::from_f64(*i as f64), - Self::I64(i) => JsValue::from_f64(*i as f64), - Self::F32(f) => JsValue::from_f64(*f as f64), - Self::F64(f) => JsValue::from_f64(*f), - Self::V128(f) => JsValue::from_f64(*f as f64), - Self::FuncRef(Some(func)) => func.handle.function.clone().into(), - Self::FuncRef(None) => JsValue::null(), - Self::ExternRef(_) => unimplemented!(), - } - } -} - -impl AsJs for wasmer_types::RawValue { - fn as_jsvalue(&self, _store: &impl AsStoreRef) -> JsValue { - unsafe { JsValue::from_f64(self.into()) } - } -} From 4eaddb5ce4fa46895e802f13df0614f5bee24c88 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Fri, 10 Feb 2023 18:16:05 -0800 Subject: [PATCH 29/81] Unify Imports in wasmer js/sys --- lib/api/src/{sys => }/imports.rs | 23 +- lib/api/src/js/as_js.rs | 2 +- lib/api/src/js/imports.rs | 352 ------------------------------- lib/api/src/js/instance.rs | 2 +- lib/api/src/js/mod.rs | 4 +- lib/api/src/js/module.rs | 2 +- lib/api/src/lib.rs | 2 + lib/api/src/sys/instance.rs | 3 +- lib/api/src/sys/mod.rs | 2 - 9 files changed, 18 insertions(+), 374 deletions(-) rename lib/api/src/{sys => }/imports.rs (96%) delete mode 100644 lib/api/src/js/imports.rs diff --git a/lib/api/src/sys/imports.rs b/lib/api/src/imports.rs similarity index 96% rename from lib/api/src/sys/imports.rs rename to lib/api/src/imports.rs index e3e47c07326..f0b4f231c88 100644 --- a/lib/api/src/sys/imports.rs +++ b/lib/api/src/imports.rs @@ -1,10 +1,9 @@ //! The import module contains the implementation data structures and helper functions used to //! manipulate and access a wasm module's imports including memories, tables, globals, and //! functions. -use crate::{Exports, Extern, Module}; +use crate::{Exports, Extern, LinkError, Module}; use std::collections::HashMap; use std::fmt; -use wasmer_compiler::LinkError; use wasmer_types::ImportError; /// All of the import data used when instantiating. @@ -36,7 +35,7 @@ use wasmer_types::ImportError; /// ``` #[derive(Clone, Default)] pub struct Imports { - map: HashMap<(String, String), Extern>, + pub(crate) map: HashMap<(String, String), Extern>, } impl Imports { @@ -306,10 +305,10 @@ macro_rules! import_namespace { #[cfg(test)] mod test { use crate::store::{AsStoreMut, Store}; - use crate::sys::Global; use crate::value::Value; + use crate::Extern; + use crate::Global; use wasmer_types::Type; - use wasmer_vm::VMExtern; #[test] fn namespace() { @@ -324,18 +323,16 @@ mod test { let happy_dog_entry = imports1.get_export("dog", "happy").unwrap(); - assert!( - if let VMExtern::Global(happy_dog_global) = happy_dog_entry.to_vm_extern() { - (*happy_dog_global.get(store.objects_mut()).ty()).ty == Type::I32 - } else { - false - } - ); + assert!(if let Extern::Global(happy_dog_global) = happy_dog_entry { + happy_dog_global.get(&mut store).ty() == Type::I32 + } else { + false + }); } #[test] fn imports_macro_allows_trailing_comma_and_none() { - use crate::sys::Function; + use crate::Function; let mut store: Store = Default::default(); diff --git a/lib/api/src/js/as_js.rs b/lib/api/src/js/as_js.rs index d8352346951..485f67e4072 100644 --- a/lib/api/src/js/as_js.rs +++ b/lib/api/src/js/as_js.rs @@ -1,8 +1,8 @@ //use crate::js::externals::Function; // use crate::store::{Store, StoreObject}; // use crate::js::RuntimeError; +use crate::imports::Imports; use crate::js::externals::Extern; -use crate::js::imports::Imports; use crate::js::vm::VMExtern; use crate::store::{AsStoreMut, AsStoreRef}; use crate::value::Value; diff --git a/lib/api/src/js/imports.rs b/lib/api/src/js/imports.rs deleted file mode 100644 index 56edd3b8a3d..00000000000 --- a/lib/api/src/js/imports.rs +++ /dev/null @@ -1,352 +0,0 @@ -//! The import module contains the implementation data structures and helper functions used to -//! manipulate and access a wasm module's imports including memories, tables, globals, and -//! functions. -use crate::exports::Exports; -use crate::js::error::{LinkError, WasmError}; -use crate::js::module::Module; -use crate::store::{AsStoreMut, AsStoreRef}; -use crate::Extern; -use std::collections::HashMap; -use std::fmt; -use wasmer_types::ImportError; - -/// All of the import data used when instantiating. -/// -/// It's suggested that you use the [`imports!`] macro -/// instead of creating an `Imports` by hand. -/// -/// [`imports!`]: macro.imports.html -/// -/// # Usage: -/// ```no_run -/// use wasmer::{Exports, Module, Store, Instance, imports, Imports, Function}; -/// # fn foo_test(module: Module, store: Store) { -/// -/// let host_fn = Function::new_typed(foo); -/// let import_object: Imports = imports! { -/// "env" => { -/// "foo" => host_fn, -/// }, -/// }; -/// -/// let instance = Instance::new(&module, &import_object).expect("Could not instantiate module."); -/// -/// fn foo(n: i32) -> i32 { -/// n -/// } -/// -/// # } -/// ``` -#[derive(Clone, Default)] -pub struct Imports { - pub(crate) map: HashMap<(String, String), Extern>, -} - -impl Imports { - /// Create a new `Imports`. - pub fn new() -> Self { - Default::default() - } - - /// Gets an export given a ns and a name - /// - /// # Usage - /// ```no_run - /// # use wasmer::Imports; - /// let mut import_object = Imports::new(); - /// import_object.get_export("ns", "name"); - /// ``` - pub fn get_export(&self, ns: &str, name: &str) -> Option { - if self.map.contains_key(&(ns.to_string(), name.to_string())) { - let ext = &self.map[&(ns.to_string(), name.to_string())]; - return Some(ext.clone()); - } - None - } - - /// Returns true if the Imports contains namespace with the provided name. - pub fn contains_namespace(&self, name: &str) -> bool { - self.map.keys().any(|(k, _)| (k == name)) - } - - /// Register a list of externs into a namespace. - /// - /// # Usage: - /// ```no_run - /// # use wasmer::{Imports, Exports, Memory}; - /// # fn foo_test(memory: Memory) { - /// let mut exports = Exports::new() - /// exports.insert("memory", memory); - /// - /// let mut import_object = Imports::new(); - /// import_object.register_namespace("env", exports); - /// // ... - /// # } - /// ``` - pub fn register_namespace( - &mut self, - ns: &str, - contents: impl IntoIterator, - ) { - for (name, extern_) in contents.into_iter() { - self.map.insert((ns.to_string(), name.clone()), extern_); - } - } - - /// Add a single import with a namespace `ns` and name `name`. - /// - /// # Usage - /// ```no_run - /// # let mut store = Default::default(); - /// use wasmer::{Imports, Function}; - /// fn foo(n: i32) -> i32 { - /// n - /// } - /// let mut import_object = Imports::new(); - /// import_object.define("env", "foo", Function::new_typed(&store, foo)); - /// ``` - pub fn define(&mut self, ns: &str, name: &str, val: impl Into) { - self.map - .insert((ns.to_string(), name.to_string()), val.into()); - } - - /// Returns the contents of a namespace as an `Exports`. - /// - /// Returns `None` if the namespace doesn't exist. - pub fn get_namespace_exports(&self, name: &str) -> Option { - let ret: Exports = self - .map - .iter() - .filter(|((ns, _), _)| ns == name) - .map(|((_, name), e)| (name.clone(), e.clone())) - .collect(); - if ret.is_empty() { - None - } else { - Some(ret) - } - } - - /// Resolve and return a vector of imports in the order they are defined in the `module`'s source code. - /// - /// This means the returned `Vec` might be a subset of the imports contained in `self`. - pub fn imports_for_module( - &self, - module: &Module, - _store: &mut impl AsStoreMut, - ) -> Result, LinkError> { - let mut ret = vec![]; - for import in module.imports() { - if let Some(imp) = self - .map - .get(&(import.module().to_string(), import.name().to_string())) - { - ret.push(imp.clone()); - } else { - return Err(LinkError::Import( - import.module().to_string(), - import.name().to_string(), - ImportError::UnknownImport(import.ty().clone()), - )); - } - } - Ok(ret) - } - - /// Iterates through all the imports in this structure - pub fn iter<'a>(&'a self) -> ImportsIterator<'a> { - ImportsIterator::new(self) - } - - /// Create a new `Imports` from a JS Object, it receives a reference to a `Module` to - /// map and assign the types of each import and the JS Object - /// that contains the values of imports. - /// - /// # Usage - /// ```ignore - /// let import_object = Imports::new_from_js_object(&mut store, &module, js_object); - /// ``` - pub fn new_from_js_object( - store: &mut impl AsStoreMut, - module: &Module, - object: js_sys::Object, - ) -> Result { - unimplemented!(); - } -} - -pub struct ImportsIterator<'a> { - iter: std::collections::hash_map::Iter<'a, (String, String), Extern>, -} - -impl<'a> ImportsIterator<'a> { - fn new(imports: &'a Imports) -> Self { - let iter = imports.map.iter(); - Self { iter } - } -} - -impl<'a> Iterator for ImportsIterator<'a> { - type Item = (&'a str, &'a str, &'a Extern); - - fn next(&mut self) -> Option { - self.iter - .next() - .map(|(k, v)| (k.0.as_str(), k.1.as_str(), v)) - } -} - -impl IntoIterator for &Imports { - type IntoIter = std::collections::hash_map::IntoIter<(String, String), Extern>; - type Item = ((String, String), Extern); - - fn into_iter(self) -> Self::IntoIter { - self.map.clone().into_iter() - } -} - -impl Extend<((String, String), Extern)> for Imports { - fn extend>(&mut self, iter: T) { - for ((ns, name), ext) in iter.into_iter() { - self.define(&ns, &name, ext); - } - } -} - -impl fmt::Debug for Imports { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - enum SecretMap { - Empty, - Some(usize), - } - - impl SecretMap { - fn new(len: usize) -> Self { - if len == 0 { - Self::Empty - } else { - Self::Some(len) - } - } - } - - impl fmt::Debug for SecretMap { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Self::Empty => write!(f, "(empty)"), - Self::Some(len) => write!(f, "(... {} item(s) ...)", len), - } - } - } - - f.debug_struct("Imports") - .field("map", &SecretMap::new(self.map.len())) - .finish() - } -} - -// The import! macro for Imports - -/// Generate an [`Imports`] easily with the `imports!` macro. -/// -/// [`Imports`]: struct.Imports.html -/// -/// # Usage -/// -/// ``` -/// # use wasmer::{Function, Store}; -/// # let mut store = Store::default(); -/// use wasmer::imports; -/// -/// let import_object = imports! { -/// "env" => { -/// "foo" => Function::new_typed(&store, foo) -/// }, -/// }; -/// -/// fn foo(n: i32) -> i32 { -/// n -/// } -/// ``` -#[macro_export] -macro_rules! imports { - ( $( $ns_name:expr => $ns:tt ),* $(,)? ) => { - { - let mut import_object = $crate::Imports::new(); - - $({ - let namespace = $crate::import_namespace!($ns); - - import_object.register_namespace($ns_name, namespace); - })* - - import_object - } - }; -} - -#[macro_export] -#[doc(hidden)] -macro_rules! namespace { - ($( $import_name:expr => $import_item:expr ),* $(,)? ) => { - $crate::import_namespace!( { $( $import_name => $import_item, )* } ) - }; -} - -#[macro_export] -#[doc(hidden)] -macro_rules! import_namespace { - ( { $( $import_name:expr => $import_item:expr ),* $(,)? } ) => {{ - let mut namespace = $crate::Exports::new(); - - $( - namespace.insert($import_name, $import_item); - )* - - namespace - }}; - - ( $namespace:ident ) => { - $namespace - }; -} - -#[cfg(test)] -mod test { - use crate::{Global, Store, Value}; - - // use wasm_bindgen::*; - use wasm_bindgen_test::*; - - #[wasm_bindgen_test] - fn chaining_works() { - let mut store = Store::default(); - - let g = Global::new(&mut store, Value::I32(0)); - - let mut imports1 = imports! { - "dog" => { - "happy" => g.clone() - } - }; - - let imports2 = imports! { - "dog" => { - "small" => g.clone() - }, - "cat" => { - "small" => g - } - }; - - imports1.extend(&imports2); - - let small_cat_export = imports1.get_export("cat", "small"); - assert!(small_cat_export.is_some()); - - let happy = imports1.get_export("dog", "happy"); - let small = imports1.get_export("dog", "small"); - assert!(happy.is_some()); - assert!(small.is_some()); - } -} diff --git a/lib/api/src/js/instance.rs b/lib/api/src/js/instance.rs index 988bc6a831b..e358d2abd3f 100644 --- a/lib/api/src/js/instance.rs +++ b/lib/api/src/js/instance.rs @@ -1,7 +1,7 @@ use crate::exports::Exports; +use crate::imports::Imports; use crate::js::error::InstantiationError; use crate::js::externals::Extern; -use crate::js::imports::Imports; use crate::js::vm::{VMExtern, VMInstance}; use crate::module::Module; use crate::store::{AsStoreMut, AsStoreRef}; diff --git a/lib/api/src/js/mod.rs b/lib/api/src/js/mod.rs index 40e8355b487..28c0d8cdf0e 100644 --- a/lib/api/src/js/mod.rs +++ b/lib/api/src/js/mod.rs @@ -28,7 +28,6 @@ pub(crate) mod engine; pub(crate) mod error; pub(crate) mod extern_ref; pub(crate) mod externals; -mod imports; mod instance; pub(crate) mod module; #[cfg(feature = "wasm-types-polyfill")] @@ -41,12 +40,11 @@ mod wasm_bindgen_polyfill; pub use crate::js::as_js::AsJs; pub use crate::js::engine::Engine; -pub use crate::js::error::{DeserializeError, InstantiationError, SerializeError}; +pub use crate::js::error::{DeserializeError, InstantiationError, LinkError, SerializeError}; pub use crate::js::externals::{ Extern, FromToNativeWasmType, Function, Global, HostFunction, Memory, MemoryError, MemoryView, Table, WasmTypeList, }; -pub use crate::js::imports::Imports; pub use crate::js::instance::Instance; pub use crate::js::module::{Module, ModuleTypeHints}; pub use crate::js::store::StoreObjects; diff --git a/lib/api/src/js/module.rs b/lib/api/src/js/module.rs index 60a111be1ca..2358d48e619 100644 --- a/lib/api/src/js/module.rs +++ b/lib/api/src/js/module.rs @@ -1,8 +1,8 @@ +use crate::imports::Imports; use crate::js::error::InstantiationError; #[cfg(feature = "wat")] use crate::js::error::WasmError; use crate::js::externals::Extern; -use crate::js::imports::Imports; use crate::js::vm::VMInstance; use crate::js::AsJs; use crate::js::RuntimeError; diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index c31370abbfa..c4a963af255 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -433,6 +433,7 @@ mod engine; mod exports; mod extern_ref; mod function_env; +mod imports; mod into_bytes; mod mem_access; mod module; @@ -458,6 +459,7 @@ pub use engine::{AsEngineRef, Engine}; pub use exports::{ExportError, Exportable, Exports, ExportsIterator}; pub use extern_ref::ExternRef; pub use function_env::{FunctionEnv, FunctionEnvMut}; +pub use imports::Imports; pub use into_bytes::IntoBytes; pub use mem_access::{MemoryAccessError, WasmRef, WasmSlice, WasmSliceIter}; pub use module::{IoCompileError, Module}; diff --git a/lib/api/src/sys/instance.rs b/lib/api/src/sys/instance.rs index 2327c64779d..12a57606eb7 100644 --- a/lib/api/src/sys/instance.rs +++ b/lib/api/src/sys/instance.rs @@ -5,8 +5,9 @@ use std::fmt; use thiserror::Error; use wasmer_vm::{StoreHandle, VMInstance}; +use crate::imports::Imports; use crate::store::AsStoreMut; -use crate::sys::{externals::Extern, imports::Imports}; +use crate::sys::externals::Extern; /// A WebAssembly Instance is a stateful, executable /// instance of a WebAssembly [`Module`]. diff --git a/lib/api/src/sys/mod.rs b/lib/api/src/sys/mod.rs index 2ee265b6576..be96df66d97 100644 --- a/lib/api/src/sys/mod.rs +++ b/lib/api/src/sys/mod.rs @@ -1,7 +1,6 @@ pub(crate) mod engine; pub(crate) mod extern_ref; pub(crate) mod externals; -mod imports; mod instance; pub(crate) mod module; mod tunables; @@ -11,7 +10,6 @@ pub use crate::sys::externals::{ Extern, FromToNativeWasmType, Function, Global, HostFunction, Memory, MemoryView, Table, WasmTypeList, }; -pub use crate::sys::imports::Imports; pub use crate::sys::instance::{Instance, InstantiationError}; pub use crate::sys::tunables::BaseTunables; From b9d21187ed59c4d7bae5d5a6195e7d1fb65ef007 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Fri, 10 Feb 2023 18:53:18 -0800 Subject: [PATCH 30/81] Make instance more uniform --- lib/api/src/js/as_js.rs | 75 ++++++++++++++++++++++++++++++------- lib/api/src/js/error.rs | 15 -------- lib/api/src/js/instance.rs | 62 +++++------------------------- lib/api/src/sys/instance.rs | 8 ---- 4 files changed, 70 insertions(+), 90 deletions(-) diff --git a/lib/api/src/js/as_js.rs b/lib/api/src/js/as_js.rs index 485f67e4072..da8aba60324 100644 --- a/lib/api/src/js/as_js.rs +++ b/lib/api/src/js/as_js.rs @@ -4,26 +4,27 @@ use crate::imports::Imports; use crate::js::externals::Extern; use crate::js::vm::VMExtern; +use crate::js::Instance; use crate::store::{AsStoreMut, AsStoreRef}; use crate::value::Value; +use crate::Exports; use crate::ValType; use std::collections::HashMap; -use wasm_bindgen::JsValue; +use wasm_bindgen::{JsError, JsValue}; use wasmer_types::ExternType; /// Convert the given type to a [`JsValue`]. -pub trait AsJs { +pub trait AsJs: Sized { /// The inner definition type from this Javascript object type DefinitionType; /// Convert the given type to a [`JsValue`]. fn as_jsvalue(&self, store: &impl AsStoreRef) -> JsValue; /// Convert the given type to a [`JsValue`]. fn from_jsvalue( - &self, store: &mut impl AsStoreMut, type_: &Self::DefinitionType, value: &JsValue, - ) -> Self; + ) -> Result; } #[inline] @@ -57,12 +58,11 @@ impl AsJs for Value { } fn from_jsvalue( - &self, _store: &mut impl AsStoreMut, type_: &Self::DefinitionType, value: &JsValue, - ) -> Self { - param_from_js(type_, value) + ) -> Result { + Ok(param_from_js(type_, value)) } } @@ -74,11 +74,10 @@ impl AsJs for wasmer_types::RawValue { } fn from_jsvalue( - &self, _store: &mut impl AsStoreMut, type_: &Self::DefinitionType, value: &JsValue, - ) -> Self { + ) -> Result { unimplemented!(); } } @@ -162,11 +161,10 @@ impl AsJs for Imports { } fn from_jsvalue( - &self, store: &mut impl AsStoreMut, module: &Self::DefinitionType, value: &JsValue, - ) -> Self { + ) -> Result { let module_imports: HashMap<(String, String), ExternType> = module .imports() .map(|import| { @@ -196,7 +194,7 @@ impl AsJs for Imports { } } - Self { map } + Ok(Self { map }) } } @@ -213,11 +211,60 @@ impl AsJs for Extern { .clone() } fn from_jsvalue( - &self, _store: &mut impl AsStoreMut, type_: &Self::DefinitionType, value: &JsValue, - ) -> Self { + ) -> Result { unimplemented!(); } } + +impl AsJs for Instance { + type DefinitionType = crate::module::Module; + fn as_jsvalue(&self, store: &impl AsStoreRef) -> wasm_bindgen::JsValue { + self.handle.clone().into() + } + + fn from_jsvalue( + mut store: &mut impl AsStoreMut, + module: &Self::DefinitionType, + value: &JsValue, + ) -> Result { + let instance: js_sys::WebAssembly::Instance = value.clone().into(); + let instance_exports = instance.exports(); + + let exports = module + .exports() + .map(|export_type| { + let name = export_type.name(); + let extern_type = export_type.ty().clone(); + // Annotation is here to prevent spurious IDE warnings. + #[allow(unused_unsafe)] + let js_export = unsafe { + js_sys::Reflect::get(&instance_exports, &name.into()).map_err(|_e| { + JsError::new(&format!( + "Can't get {0} from the instance exports", + name.to_string() + )) + })? + }; + let export: VMExtern = VMExtern::from_js_value(js_export, &mut store, extern_type) + .map_err(|_e| { + JsError::new(&format!( + "Can't get {0} from the instance exports", + name.to_string() + )) + })? + .into(); + let extern_ = Extern::from_vm_extern(&mut store, export); + Ok((name.to_string(), extern_)) + }) + .collect::>()?; + + Ok(Self { + handle: instance, + module: module.clone(), + exports, + }) + } +} diff --git a/lib/api/src/js/error.rs b/lib/api/src/js/error.rs index 74d62bd64db..b39d1bde26d 100644 --- a/lib/api/src/js/error.rs +++ b/lib/api/src/js/error.rs @@ -109,7 +109,6 @@ pub enum LinkError { #[cfg_attr(feature = "std", error("Error while importing {0:?}.{1:?}: {2}"))] Import(String, String, ImportError), - #[cfg(not(target_arch = "wasm32"))] /// A trap ocurred during linking. #[cfg_attr(feature = "std", error("RuntimeError occurred during linking: {0}"))] Trap(#[source] RuntimeError), @@ -146,20 +145,6 @@ pub enum InstantiationError { /// This error occurs when an import from a different store is used. #[cfg_attr(feature = "std", error("cannot mix imports from different stores"))] DifferentStores, - - /// A generic error occured while invoking API functions - #[cfg_attr(feature = "std", error(transparent))] - Wasm(WasmError), - - /// Insufficient resources available for execution. - #[cfg_attr(feature = "std", error("Can't get {0} from the instance exports"))] - NotInExports(String), -} - -impl From for InstantiationError { - fn from(original: WasmError) -> Self { - Self::Wasm(original) - } } #[cfg(feature = "core")] diff --git a/lib/api/src/js/instance.rs b/lib/api/src/js/instance.rs index e358d2abd3f..3e59fa57393 100644 --- a/lib/api/src/js/instance.rs +++ b/lib/api/src/js/instance.rs @@ -1,10 +1,12 @@ use crate::exports::Exports; use crate::imports::Imports; +use crate::js::as_js::AsJs; use crate::js::error::InstantiationError; use crate::js::externals::Extern; use crate::js::vm::{VMExtern, VMInstance}; use crate::module::Module; use crate::store::{AsStoreMut, AsStoreRef}; +use crate::{LinkError, RuntimeError}; use js_sys::WebAssembly; use std::fmt; @@ -18,8 +20,8 @@ use std::fmt; /// Spec: #[derive(Clone)] pub struct Instance { - handle: VMInstance, - module: Module, + pub(crate) handle: VMInstance, + pub(crate) module: Module, /// The exports for an instance. pub exports: Exports, } @@ -68,7 +70,11 @@ impl Instance { .instantiate(&mut store, imports) .map_err(|e| InstantiationError::Start(e))?; - let self_instance = Self::from_module_and_instance(store, module, instance)?; + let self_instance = Self::from_jsvalue(store, &module, &instance).map_err(|e| { + let js_err: wasm_bindgen::JsValue = e.into(); + let err: RuntimeError = js_err.into(); + InstantiationError::Link(LinkError::Trap(err)) + })?; Ok(self_instance) } @@ -94,60 +100,10 @@ impl Instance { Self::new(store, module, &imports) } - /// Creates a Wasmer `Instance` from a Wasmer `Module` and a WebAssembly Instance - /// - /// # Important - /// - /// Is expected that the function [`Instance::init_envs`] is run manually - /// by the user in case the instance has any Wasmer imports, so the function - /// environments are properly initiated. - /// - /// *This method is only available when targeting JS environments* - pub fn from_module_and_instance( - mut store: &mut impl AsStoreMut, - module: &Module, - instance: WebAssembly::Instance, - ) -> Result { - let instance_exports = instance.exports(); - - let exports = module - .exports() - .map(|export_type| { - let name = export_type.name(); - let extern_type = export_type.ty().clone(); - // Annotation is here to prevent spurious IDE warnings. - #[allow(unused_unsafe)] - let js_export = unsafe { - js_sys::Reflect::get(&instance_exports, &name.into()) - .map_err(|_e| InstantiationError::NotInExports(name.to_string()))? - }; - let export: VMExtern = - VMExtern::from_js_value(js_export, &mut store, extern_type)?.into(); - let extern_ = Extern::from_vm_extern(&mut store, export); - Ok((name.to_string(), extern_)) - }) - .collect::>()?; - - Ok(Self { - handle: instance, - module: module.clone(), - exports, - }) - } - /// Gets the [`Module`] associated with this instance. pub fn module(&self) -> &Module { &self.module } - - /// Returns the inner WebAssembly Instance - #[doc(hidden)] - pub fn raw<'context>( - &'context self, - _store: &'context impl AsStoreRef, - ) -> &'context WebAssembly::Instance { - &self.handle - } } impl fmt::Debug for Instance { diff --git a/lib/api/src/sys/instance.rs b/lib/api/src/sys/instance.rs index 12a57606eb7..de05531a10f 100644 --- a/lib/api/src/sys/instance.rs +++ b/lib/api/src/sys/instance.rs @@ -172,14 +172,6 @@ impl Instance { }) .collect::(); - // If the memory is imported then also export it for backwards compatibility reasons - // (many will assume the memory is always exported) - later we can remove this - if exports.get_memory("memory").is_err() { - if let Some(memory) = externs.iter().find(|a| a.ty(store).memory().is_some()) { - exports.insert("memory", memory.clone()); - } - } - let instance = Self { _handle: StoreHandle::new(store.objects_mut(), handle), module: module.clone(), From f8176e3bb613c42cc9afd0a2de8d6ca1ee52cbaf Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Sat, 11 Feb 2023 17:25:50 -0800 Subject: [PATCH 31/81] Make js conversion uniform --- lib/api/src/js/as_js.rs | 133 ++++++++++++++++++++++-------------- lib/api/src/js/instance.rs | 31 +++++++++ lib/api/src/js/vm.rs | 87 +++-------------------- lib/api/src/sys/instance.rs | 8 --- 4 files changed, 122 insertions(+), 137 deletions(-) diff --git a/lib/api/src/js/as_js.rs b/lib/api/src/js/as_js.rs index da8aba60324..680fb9473a0 100644 --- a/lib/api/src/js/as_js.rs +++ b/lib/api/src/js/as_js.rs @@ -2,14 +2,18 @@ // use crate::store::{Store, StoreObject}; // use crate::js::RuntimeError; use crate::imports::Imports; -use crate::js::externals::Extern; -use crate::js::vm::VMExtern; +use crate::js::externals::{Extern, Function, Global, Memory, Table}; +use crate::js::vm::{VMExtern, VMFunction, VMGlobal, VMMemory, VMTable}; +use crate::js::wasm_bindgen_polyfill::Global as JsGlobal; use crate::js::Instance; use crate::store::{AsStoreMut, AsStoreRef}; use crate::value::Value; use crate::Exports; use crate::ValType; +use js_sys::Function as JsFunction; +use js_sys::WebAssembly::{Memory as JsMemory, Table as JsTable}; use std::collections::HashMap; +use wasm_bindgen::JsCast; use wasm_bindgen::{JsError, JsValue}; use wasmer_types::ExternType; @@ -187,9 +191,7 @@ impl AsJs for Imports { let import_js: wasm_bindgen::JsValue = import_entry.get(1); let key = (module_name.clone(), import_name); let extern_type = module_imports.get(&key).unwrap(); - let export = - VMExtern::from_js_value(import_js, store, extern_type.clone()).unwrap(); - let extern_ = Extern::from_vm_extern(store, export); + let extern_ = Extern::from_jsvalue(store, extern_type, &import_js)?; map.insert(key, extern_); } } @@ -201,21 +203,85 @@ impl AsJs for Imports { impl AsJs for Extern { type DefinitionType = ExternType; - fn as_jsvalue(&self, store: &impl AsStoreRef) -> wasm_bindgen::JsValue { + fn as_jsvalue(&self, _store: &impl AsStoreRef) -> wasm_bindgen::JsValue { match self { - Self::Function(_) => self.to_vm_extern().as_jsvalue(store), - Self::Global(_) => self.to_vm_extern().as_jsvalue(store), - Self::Table(_) => self.to_vm_extern().as_jsvalue(store), - Self::Memory(_) => self.to_vm_extern().as_jsvalue(store), + Self::Memory(memory) => memory.handle.memory.clone().into(), + Self::Function(function) => function.handle.function.clone().into(), + Self::Table(table) => table.handle.table.clone().into(), + Self::Global(global) => global.handle.global.clone().into(), } - .clone() } + fn from_jsvalue( - _store: &mut impl AsStoreMut, - type_: &Self::DefinitionType, - value: &JsValue, + store: &mut impl AsStoreMut, + extern_type: &Self::DefinitionType, + val: &JsValue, ) -> Result { - unimplemented!(); + // Note: this function do a soft check over the type + // We only check the "kind" of Extern, but nothing else + match extern_type { + ExternType::Memory(memory_type) => { + if val.is_instance_of::() { + Ok(Self::Memory(Memory::from_vm_extern( + store, + VMMemory::new( + val.clone().unchecked_into::(), + memory_type.clone(), + ), + ))) + } else { + Err(JsError::new(&format!( + "Extern expect to be of type Memory, but received {:?}", + val + ))) + } + } + ExternType::Global(global_type) => { + if val.is_instance_of::() { + Ok(Self::Global(Global::from_vm_extern( + store, + VMGlobal::new( + val.clone().unchecked_into::(), + global_type.clone(), + ), + ))) + } else { + Err(JsError::new(&format!( + "Extern expect to be of type Global, but received {:?}", + val + ))) + } + } + ExternType::Function(function_type) => { + if val.is_instance_of::() { + Ok(Self::Function(Function::from_vm_extern( + store, + VMFunction::new( + val.clone().unchecked_into::(), + function_type.clone(), + ), + ))) + } else { + Err(JsError::new(&format!( + "Extern expect to be of type Function, but received {:?}", + val + ))) + } + } + ExternType::Table(table_type) => { + if val.is_instance_of::() { + Ok(Self::Table(Table::from_vm_extern( + store, + VMTable::new(val.clone().unchecked_into::(), table_type.clone()), + ))) + } else { + Err(JsError::new(&format!( + "Extern expect to be of type Table, but received {:?}", + val + ))) + } + } + } } } @@ -231,40 +297,7 @@ impl AsJs for Instance { value: &JsValue, ) -> Result { let instance: js_sys::WebAssembly::Instance = value.clone().into(); - let instance_exports = instance.exports(); - - let exports = module - .exports() - .map(|export_type| { - let name = export_type.name(); - let extern_type = export_type.ty().clone(); - // Annotation is here to prevent spurious IDE warnings. - #[allow(unused_unsafe)] - let js_export = unsafe { - js_sys::Reflect::get(&instance_exports, &name.into()).map_err(|_e| { - JsError::new(&format!( - "Can't get {0} from the instance exports", - name.to_string() - )) - })? - }; - let export: VMExtern = VMExtern::from_js_value(js_export, &mut store, extern_type) - .map_err(|_e| { - JsError::new(&format!( - "Can't get {0} from the instance exports", - name.to_string() - )) - })? - .into(); - let extern_ = Extern::from_vm_extern(&mut store, export); - Ok((name.to_string(), extern_)) - }) - .collect::>()?; - - Ok(Self { - handle: instance, - module: module.clone(), - exports, - }) + Self::from_module_and_instance(store, module, instance) + .map_err(|e| JsError::new(&format!("Can't get the instance: {:?}", e))) } } diff --git a/lib/api/src/js/instance.rs b/lib/api/src/js/instance.rs index 3e59fa57393..c1715ed58a4 100644 --- a/lib/api/src/js/instance.rs +++ b/lib/api/src/js/instance.rs @@ -100,6 +100,37 @@ impl Instance { Self::new(store, module, &imports) } + /// Creates a Wasmer `Instance` from a Wasmer `Module` and a WebAssembly Instance + pub fn from_module_and_instance( + mut store: &mut impl AsStoreMut, + module: &Module, + instance: WebAssembly::Instance, + ) -> Result { + let instance_exports = instance.exports(); + + let exports = module + .exports() + .map(|export_type| { + let name = export_type.name(); + let extern_type = export_type.ty(); + // Annotation is here to prevent spurious IDE warnings. + #[allow(unused_unsafe)] + let js_export = + unsafe { js_sys::Reflect::get(&instance_exports, &name.into()).unwrap() }; + let extern_ = Extern::from_jsvalue(&mut store, extern_type, &js_export) + .map_err(|e| wasm_bindgen::JsValue::from(e)) + .unwrap(); + Ok((name.to_string(), extern_)) + }) + .collect::>()?; + + Ok(Self { + handle: instance, + module: module.clone(), + exports, + }) + } + /// Gets the [`Module`] associated with this instance. pub fn module(&self) -> &Module { &self.module diff --git a/lib/api/src/js/vm.rs b/lib/api/src/js/vm.rs index 26705ee38e2..84baabb35b3 100644 --- a/lib/api/src/js/vm.rs +++ b/lib/api/src/js/vm.rs @@ -5,14 +5,11 @@ /// once the type reflection is added to the WebAssembly JS API. /// https://github.com/WebAssembly/js-types/ use crate::js::error::WasmError; -use crate::js::wasm_bindgen_polyfill::Global; use crate::js::wasm_bindgen_polyfill::Global as JsGlobal; use crate::store::{AsStoreMut, AsStoreRef}; use crate::MemoryView; -use js_sys::Function; use js_sys::Function as JsFunction; use js_sys::WebAssembly; -use js_sys::WebAssembly::{Memory, Table}; use js_sys::WebAssembly::{Memory as JsMemory, Table as JsTable}; use serde::{Deserialize, Serialize}; use std::any::Any; @@ -27,7 +24,7 @@ use wasmer_types::{ /// Represents linear memory that is managed by the javascript runtime #[derive(Clone, Debug, PartialEq)] pub struct VMMemory { - pub(crate) memory: Memory, + pub(crate) memory: JsMemory, pub(crate) ty: MemoryType, } @@ -42,7 +39,7 @@ struct DummyBuffer { impl VMMemory { /// Creates a new memory directly from a WebAssembly javascript object - pub fn new(memory: Memory, ty: MemoryType) -> Self { + pub fn new(memory: JsMemory, ty: MemoryType) -> Self { Self { memory, ty } } @@ -112,12 +109,12 @@ impl VMMemory { #[derive(Clone, Debug, PartialEq)] pub struct VMGlobal { - pub(crate) global: Global, + pub(crate) global: JsGlobal, pub(crate) ty: GlobalType, } impl VMGlobal { - pub(crate) fn new(global: Global, ty: GlobalType) -> Self { + pub(crate) fn new(global: JsGlobal, ty: GlobalType) -> Self { Self { global, ty } } } @@ -127,7 +124,7 @@ unsafe impl Sync for VMGlobal {} #[derive(Clone, Debug, PartialEq)] pub struct VMTable { - pub(crate) table: Table, + pub(crate) table: JsTable, pub(crate) ty: TableType, } @@ -135,7 +132,7 @@ unsafe impl Send for VMTable {} unsafe impl Sync for VMTable {} impl VMTable { - pub(crate) fn new(table: Table, ty: TableType) -> Self { + pub(crate) fn new(table: JsTable, ty: TableType) -> Self { Self { table, ty } } pub fn get_runtime_size(&self) -> u32 { @@ -145,7 +142,7 @@ impl VMTable { #[derive(Clone)] pub struct VMFunction { - pub(crate) function: Function, + pub(crate) function: JsFunction, pub(crate) ty: FunctionType, } @@ -153,7 +150,7 @@ unsafe impl Send for VMFunction {} unsafe impl Sync for VMFunction {} impl VMFunction { - pub(crate) fn new(function: Function, ty: FunctionType) -> Self { + pub(crate) fn new(function: JsFunction, ty: FunctionType) -> Self { Self { function, ty } } } @@ -187,74 +184,6 @@ pub enum VMExtern { Global(VMGlobal), } -impl VMExtern { - /// Return the export as a `JSValue`. - pub fn as_jsvalue<'context>(&self, _store: &'context impl AsStoreRef) -> JsValue { - match self { - Self::Memory(js_wasm_memory) => js_wasm_memory.memory.clone().into(), - Self::Function(js_func) => js_func.function.clone().into(), - Self::Table(js_wasm_table) => js_wasm_table.table.clone().into(), - Self::Global(js_wasm_global) => js_wasm_global.global.clone().into(), - } - } - - /// Convert a `JsValue` into an `Export` within a given `Context`. - pub fn from_js_value( - val: JsValue, - _store: &mut impl AsStoreMut, - extern_type: ExternType, - ) -> Result { - match extern_type { - ExternType::Memory(memory_type) => { - if val.is_instance_of::() { - Ok(Self::Memory(VMMemory::new( - val.unchecked_into::(), - memory_type, - ))) - } else { - Err(WasmError::TypeMismatch( - val.js_typeof() - .as_string() - .map(Into::into) - .unwrap_or("unknown".into()), - "Memory".into(), - )) - } - } - ExternType::Global(global_type) => { - if val.is_instance_of::() { - Ok(Self::Global(VMGlobal::new( - val.unchecked_into::(), - global_type, - ))) - } else { - panic!("Extern type doesn't match js value type"); - } - } - ExternType::Function(function_type) => { - if val.is_instance_of::() { - Ok(Self::Function(VMFunction::new( - val.unchecked_into::(), - function_type, - ))) - } else { - panic!("Extern type doesn't match js value type"); - } - } - ExternType::Table(table_type) => { - if val.is_instance_of::() { - Ok(Self::Table(VMTable::new( - val.unchecked_into::(), - table_type, - ))) - } else { - panic!("Extern type doesn't match js value type"); - } - } - } - } -} - pub type VMInstance = WebAssembly::Instance; /// Underlying FunctionEnvironment used by a `VMFunction`. diff --git a/lib/api/src/sys/instance.rs b/lib/api/src/sys/instance.rs index de05531a10f..e5cbd8e5cb8 100644 --- a/lib/api/src/sys/instance.rs +++ b/lib/api/src/sys/instance.rs @@ -128,14 +128,6 @@ impl Instance { }) .collect::(); - // If the memory is imported then also export it for backwards compatibility reasons - // (many will assume the memory is always exported) - later we can remove this - if exports.get_memory("memory").is_err() { - if let Some(memory) = externs.iter().find(|a| a.ty(store).memory().is_some()) { - exports.insert("memory", memory.clone()); - } - } - let instance = Self { _handle: StoreHandle::new(store.objects_mut(), handle), module: module.clone(), From 58f27ae045137d7c50f291b7afb3c0ed9afd32cf Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Sat, 11 Feb 2023 17:41:53 -0800 Subject: [PATCH 32/81] Unify InstantiationError --- lib/api/src/errors.rs | 39 +++++++++++++++++++++ lib/api/src/js/error.rs | 37 -------------------- lib/api/src/js/instance.rs | 2 +- lib/api/src/js/mod.rs | 2 +- lib/api/src/js/module.rs | 2 +- lib/api/src/lib.rs | 2 ++ lib/api/src/sys/instance.rs | 69 ++++++++++--------------------------- lib/api/src/sys/mod.rs | 2 +- lib/api/src/sys/module.rs | 2 +- 9 files changed, 65 insertions(+), 92 deletions(-) create mode 100644 lib/api/src/errors.rs diff --git a/lib/api/src/errors.rs b/lib/api/src/errors.rs new file mode 100644 index 00000000000..a8222f9a444 --- /dev/null +++ b/lib/api/src/errors.rs @@ -0,0 +1,39 @@ +use crate::{LinkError, RuntimeError}; +use thiserror::Error; + +/// An error while instantiating a module. +/// +/// This is not a common WebAssembly error, however +/// we need to differentiate from a `LinkError` (an error +/// that happens while linking, on instantiation), a +/// Trap that occurs when calling the WebAssembly module +/// start function, and an error when initializing the user's +/// host environments. +#[derive(Debug)] +#[cfg_attr(feature = "std", derive(Error))] +pub enum InstantiationError { + /// A linking ocurred during instantiation. + #[cfg_attr(feature = "std", error(transparent))] + Link(LinkError), + + /// A runtime error occured while invoking the start function + #[cfg_attr(feature = "std", error(transparent))] + Start(RuntimeError), + + /// The module was compiled with a CPU feature that is not available on + /// the current host. + #[cfg_attr(feature = "std", error("missing required CPU features: {0:?}"))] + CpuFeature(String), + + /// Import from a different [`Store`]. + /// This error occurs when an import from a different store is used. + #[cfg_attr(feature = "std", error("cannot mix imports from different stores"))] + DifferentStores, +} + +#[cfg(feature = "core")] +impl std::fmt::Display for InstantiationError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "InstantiationError") + } +} diff --git a/lib/api/src/js/error.rs b/lib/api/src/js/error.rs index b39d1bde26d..d2d2a9070cf 100644 --- a/lib/api/src/js/error.rs +++ b/lib/api/src/js/error.rs @@ -116,40 +116,3 @@ pub enum LinkError { #[cfg_attr(feature = "std", error("Insufficient resources: {0}"))] Resource(String), } - -/// An error while instantiating a module. -/// -/// This is not a common WebAssembly error, however -/// we need to differentiate from a `LinkError` (an error -/// that happens while linking, on instantiation), a -/// Trap that occurs when calling the WebAssembly module -/// start function, and an error when initializing the user's -/// host environments. -#[derive(Debug)] -#[cfg_attr(feature = "std", derive(Error))] -pub enum InstantiationError { - /// A linking ocurred during instantiation. - #[cfg_attr(feature = "std", error(transparent))] - Link(LinkError), - - /// A runtime error occured while invoking the start function - #[cfg_attr(feature = "std", error(transparent))] - Start(RuntimeError), - - /// The module was compiled with a CPU feature that is not available on - /// the current host. - #[cfg_attr(feature = "std", error("missing required CPU features: {0:?}"))] - CpuFeature(String), - - /// Import from a different [`Store`]. - /// This error occurs when an import from a different store is used. - #[cfg_attr(feature = "std", error("cannot mix imports from different stores"))] - DifferentStores, -} - -#[cfg(feature = "core")] -impl std::fmt::Display for InstantiationError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "InstantiationError") - } -} diff --git a/lib/api/src/js/instance.rs b/lib/api/src/js/instance.rs index c1715ed58a4..44c915097a0 100644 --- a/lib/api/src/js/instance.rs +++ b/lib/api/src/js/instance.rs @@ -1,7 +1,7 @@ +use crate::errors::InstantiationError; use crate::exports::Exports; use crate::imports::Imports; use crate::js::as_js::AsJs; -use crate::js::error::InstantiationError; use crate::js::externals::Extern; use crate::js::vm::{VMExtern, VMInstance}; use crate::module::Module; diff --git a/lib/api/src/js/mod.rs b/lib/api/src/js/mod.rs index 28c0d8cdf0e..578ba4b1bd3 100644 --- a/lib/api/src/js/mod.rs +++ b/lib/api/src/js/mod.rs @@ -40,7 +40,7 @@ mod wasm_bindgen_polyfill; pub use crate::js::as_js::AsJs; pub use crate::js::engine::Engine; -pub use crate::js::error::{DeserializeError, InstantiationError, LinkError, SerializeError}; +pub use crate::js::error::{DeserializeError, LinkError, SerializeError}; pub use crate::js::externals::{ Extern, FromToNativeWasmType, Function, Global, HostFunction, Memory, MemoryError, MemoryView, Table, WasmTypeList, diff --git a/lib/api/src/js/module.rs b/lib/api/src/js/module.rs index 2358d48e619..a0af2775747 100644 --- a/lib/api/src/js/module.rs +++ b/lib/api/src/js/module.rs @@ -1,5 +1,5 @@ +use crate::errors::InstantiationError; use crate::imports::Imports; -use crate::js::error::InstantiationError; #[cfg(feature = "wat")] use crate::js::error::WasmError; use crate::js::externals::Extern; diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index c4a963af255..930816fb764 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -430,6 +430,7 @@ compile_error!( ); mod engine; +mod errors; mod exports; mod extern_ref; mod function_env; @@ -456,6 +457,7 @@ mod js; pub use js::*; pub use engine::{AsEngineRef, Engine}; +pub use errors::InstantiationError; pub use exports::{ExportError, Exportable, Exports, ExportsIterator}; pub use extern_ref::ExternRef; pub use function_env::{FunctionEnv, FunctionEnvMut}; diff --git a/lib/api/src/sys/instance.rs b/lib/api/src/sys/instance.rs index e5cbd8e5cb8..660ec375b7d 100644 --- a/lib/api/src/sys/instance.rs +++ b/lib/api/src/sys/instance.rs @@ -1,8 +1,7 @@ +use crate::errors::InstantiationError; use crate::exports::Exports; use crate::module::Module; -use crate::sys::{LinkError, RuntimeError}; use std::fmt; -use thiserror::Error; use wasmer_vm::{StoreHandle, VMInstance}; use crate::imports::Imports; @@ -39,35 +38,6 @@ mod send_test { } } -/// An error while instantiating a module. -/// -/// This is not a common WebAssembly error, however -/// we need to differentiate from a `LinkError` (an error -/// that happens while linking, on instantiation), a -/// Trap that occurs when calling the WebAssembly module -/// start function, and an error when initializing the user's -/// host environments. -#[derive(Error, Debug)] -pub enum InstantiationError { - /// A linking ocurred during instantiation. - #[error(transparent)] - Link(LinkError), - - /// A runtime error occured while invoking the start function - #[error(transparent)] - Start(RuntimeError), - - /// The module was compiled with a CPU feature that is not available on - /// the current host. - #[error("missing required CPU features: {0:?}")] - CpuFeature(String), - - /// Import from a different Store. - /// This error occurs when an import from a different store is used. - #[error("cannot mix imports from different stores")] - DifferentStores, -} - impl From for InstantiationError { fn from(other: wasmer_compiler::InstantiationError) -> Self { match other { @@ -118,15 +88,7 @@ impl Instance { .imports_for_module(module) .map_err(InstantiationError::Link)?; let mut handle = module.0.instantiate(store, &externs)?; - let mut exports = module - .exports() - .map(|export| { - let name = export.name().to_string(); - let export = handle.lookup(&name).expect("export"); - let extern_ = Extern::from_vm_extern(store, export); - (name, extern_) - }) - .collect::(); + let exports = Self::get_exports(store, module, &mut handle); let instance = Self { _handle: StoreHandle::new(store.objects_mut(), handle), @@ -154,16 +116,7 @@ impl Instance { ) -> Result { let externs = externs.to_vec(); let mut handle = module.0.instantiate(store, &externs)?; - let mut exports = module - .exports() - .map(|export| { - let name = export.name().to_string(); - let export = handle.lookup(&name).expect("export"); - let extern_ = Extern::from_vm_extern(store, export); - (name, extern_) - }) - .collect::(); - + let exports = Self::get_exports(store, module, &mut handle); let instance = Self { _handle: StoreHandle::new(store.objects_mut(), handle), module: module.clone(), @@ -173,6 +126,22 @@ impl Instance { Ok(instance) } + fn get_exports( + store: &mut impl AsStoreMut, + module: &Module, + handle: &mut VMInstance, + ) -> Exports { + module + .exports() + .map(|export| { + let name = export.name().to_string(); + let export = handle.lookup(&name).expect("export"); + let extern_ = Extern::from_vm_extern(store, export); + (name, extern_) + }) + .collect::() + } + /// Gets the [`Module`] associated with this instance. pub fn module(&self) -> &Module { &self.module diff --git a/lib/api/src/sys/mod.rs b/lib/api/src/sys/mod.rs index be96df66d97..325a74e477e 100644 --- a/lib/api/src/sys/mod.rs +++ b/lib/api/src/sys/mod.rs @@ -10,7 +10,7 @@ pub use crate::sys::externals::{ Extern, FromToNativeWasmType, Function, Global, HostFunction, Memory, MemoryView, Table, WasmTypeList, }; -pub use crate::sys::instance::{Instance, InstantiationError}; +pub use crate::sys::instance::Instance; pub use crate::sys::tunables::BaseTunables; pub use target_lexicon::{Architecture, CallingConvention, OperatingSystem, Triple, HOST}; diff --git a/lib/api/src/sys/module.rs b/lib/api/src/sys/module.rs index cd2230652a5..c42c55af740 100644 --- a/lib/api/src/sys/module.rs +++ b/lib/api/src/sys/module.rs @@ -9,7 +9,7 @@ use wasmer_types::{ }; use wasmer_types::{ExportType, ImportType}; -use crate::{sys::InstantiationError, AsStoreMut, AsStoreRef, IntoBytes}; +use crate::{AsStoreMut, AsStoreRef, InstantiationError, IntoBytes}; use wasmer_vm::VMInstance; /// A WebAssembly Module contains stateless WebAssembly From 3d56b6bdd6496520153354ff29259720d43119b5 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Sat, 11 Feb 2023 18:01:07 -0800 Subject: [PATCH 33/81] Unify Instance in js/sys --- lib/api/src/errors.rs | 57 +++++++++++++---- lib/api/src/instance.rs | 123 ++++++++++++++++++++++++++++++++++++ lib/api/src/js/as_js.rs | 9 +-- lib/api/src/js/error.rs | 59 ++++------------- lib/api/src/js/instance.rs | 97 ++++------------------------ lib/api/src/js/mod.rs | 2 +- lib/api/src/js/module.rs | 4 +- lib/api/src/js/vm.rs | 1 - lib/api/src/lib.rs | 2 + lib/api/src/sys/instance.rs | 87 ++----------------------- lib/api/src/sys/mod.rs | 2 +- 11 files changed, 205 insertions(+), 238 deletions(-) create mode 100644 lib/api/src/instance.rs diff --git a/lib/api/src/errors.rs b/lib/api/src/errors.rs index a8222f9a444..239e03b8339 100644 --- a/lib/api/src/errors.rs +++ b/lib/api/src/errors.rs @@ -1,6 +1,43 @@ use crate::{LinkError, RuntimeError}; use thiserror::Error; +// /// An error while instantiating a module. +// /// +// /// This is not a common WebAssembly error, however +// /// we need to differentiate from a `LinkError` (an error +// /// that happens while linking, on instantiation), a +// /// Trap that occurs when calling the WebAssembly module +// /// start function, and an error when initializing the user's +// /// host environments. +// #[derive(Debug)] +// #[cfg_attr(feature = "std", derive(Error))] +// pub enum InstantiationError { +// /// A linking ocurred during instantiation. +// #[cfg_attr(feature = "std", error(transparent))] +// Link(LinkError), + +// /// A runtime error occured while invoking the start function +// #[cfg_attr(feature = "std", error(transparent))] +// Start(RuntimeError), + +// /// The module was compiled with a CPU feature that is not available on +// /// the current host. +// #[cfg_attr(feature = "std", error("missing required CPU features: {0:?}"))] +// CpuFeature(String), + +// /// Import from a different [`Store`]. +// /// This error occurs when an import from a different store is used. +// #[cfg_attr(feature = "std", error("cannot mix imports from different stores"))] +// DifferentStores, +// } + +// #[cfg(feature = "core")] +// impl std::fmt::Display for InstantiationError { +// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +// write!(f, "InstantiationError") +// } +// } + /// An error while instantiating a module. /// /// This is not a common WebAssembly error, however @@ -9,31 +46,23 @@ use thiserror::Error; /// Trap that occurs when calling the WebAssembly module /// start function, and an error when initializing the user's /// host environments. -#[derive(Debug)] -#[cfg_attr(feature = "std", derive(Error))] +#[derive(Error, Debug)] pub enum InstantiationError { /// A linking ocurred during instantiation. - #[cfg_attr(feature = "std", error(transparent))] + #[error(transparent)] Link(LinkError), /// A runtime error occured while invoking the start function - #[cfg_attr(feature = "std", error(transparent))] + #[error(transparent)] Start(RuntimeError), /// The module was compiled with a CPU feature that is not available on /// the current host. - #[cfg_attr(feature = "std", error("missing required CPU features: {0:?}"))] + #[error("missing required CPU features: {0:?}")] CpuFeature(String), - /// Import from a different [`Store`]. + /// Import from a different Store. /// This error occurs when an import from a different store is used. - #[cfg_attr(feature = "std", error("cannot mix imports from different stores"))] + #[error("cannot mix imports from different stores")] DifferentStores, } - -#[cfg(feature = "core")] -impl std::fmt::Display for InstantiationError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "InstantiationError") - } -} diff --git a/lib/api/src/instance.rs b/lib/api/src/instance.rs new file mode 100644 index 00000000000..14a8b5fb4dc --- /dev/null +++ b/lib/api/src/instance.rs @@ -0,0 +1,123 @@ +use crate::exports::Exports; +use crate::module::Module; +use crate::{Extern, InstantiationError}; +use std::fmt; + +use crate::imports::Imports; +use crate::store::AsStoreMut; + +#[cfg(feature = "js")] +use crate::js::instance as instance_imp; +#[cfg(feature = "sys")] +use crate::sys::instance as instance_imp; + +/// A WebAssembly Instance is a stateful, executable +/// instance of a WebAssembly [`Module`]. +/// +/// Instance objects contain all the exported WebAssembly +/// functions, memories, tables and globals that allow +/// interacting with WebAssembly. +/// +/// Spec: +#[derive(Clone)] +pub struct Instance { + _inner: instance_imp::Instance, + module: Module, + /// The exports for an instance. + pub exports: Exports, +} + +#[cfg(test)] +mod send_test { + use super::*; + + fn is_send() -> bool { + true + } + + #[test] + fn instance_is_send() { + assert!(is_send::()); + } +} + +impl Instance { + /// Creates a new `Instance` from a WebAssembly [`Module`] and a + /// set of imports using [`Imports`] or the [`imports`] macro helper. + /// + /// [`imports`]: crate::imports + /// [`Imports`]: crate::Imports + /// + /// ``` + /// # use wasmer::{imports, Store, Module, Global, Value, Instance}; + /// # use wasmer::FunctionEnv; + /// # fn main() -> anyhow::Result<()> { + /// let mut store = Store::default(); + /// let env = FunctionEnv::new(&mut store, ()); + /// let module = Module::new(&store, "(module)")?; + /// let imports = imports!{ + /// "host" => { + /// "var" => Global::new(&mut store, Value::I32(2)) + /// } + /// }; + /// let instance = Instance::new(&mut store, &module, &imports)?; + /// # Ok(()) + /// # } + /// ``` + /// + /// ## Errors + /// + /// The function can return [`InstantiationError`]s. + /// + /// Those are, as defined by the spec: + /// * Link errors that happen when plugging the imports into the instance + /// * Runtime errors that happen when running the module `start` function. + pub fn new( + store: &mut impl AsStoreMut, + module: &Module, + imports: &Imports, + ) -> Result { + let (_inner, exports) = instance_imp::Instance::new(store, module, imports)?; + Ok(Self { + _inner, + module: module.clone(), + exports, + }) + } + + /// Creates a new `Instance` from a WebAssembly [`Module`] and a + /// vector of imports. + /// + /// ## Errors + /// + /// The function can return [`InstantiationError`]s. + /// + /// Those are, as defined by the spec: + /// * Link errors that happen when plugging the imports into the instance + /// * Runtime errors that happen when running the module `start` function. + pub fn new_by_index( + store: &mut impl AsStoreMut, + module: &Module, + externs: &[Extern], + ) -> Result { + let (_inner, exports) = instance_imp::Instance::new_by_index(store, module, externs)?; + Ok(Self { + _inner, + module: module.clone(), + exports, + }) + } + + /// Gets the [`Module`] associated with this instance. + pub fn module(&self) -> &Module { + &self.module + } +} + +impl fmt::Debug for Instance { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Instance") + .field("exports", &self.exports) + .finish() + } +} diff --git a/lib/api/src/js/as_js.rs b/lib/api/src/js/as_js.rs index 680fb9473a0..5dad4e6d093 100644 --- a/lib/api/src/js/as_js.rs +++ b/lib/api/src/js/as_js.rs @@ -288,7 +288,7 @@ impl AsJs for Extern { impl AsJs for Instance { type DefinitionType = crate::module::Module; fn as_jsvalue(&self, store: &impl AsStoreRef) -> wasm_bindgen::JsValue { - self.handle.clone().into() + self._handle.clone().into() } fn from_jsvalue( @@ -296,8 +296,9 @@ impl AsJs for Instance { module: &Self::DefinitionType, value: &JsValue, ) -> Result { - let instance: js_sys::WebAssembly::Instance = value.clone().into(); - Self::from_module_and_instance(store, module, instance) - .map_err(|e| JsError::new(&format!("Can't get the instance: {:?}", e))) + let js_instance: js_sys::WebAssembly::Instance = value.clone().into(); + let (instance, _exports) = Self::from_module_and_instance(store, module, js_instance) + .map_err(|e| JsError::new(&format!("Can't get the instance: {:?}", e)))?; + Ok(instance) } } diff --git a/lib/api/src/js/error.rs b/lib/api/src/js/error.rs index d2d2a9070cf..11d0a0aeaa3 100644 --- a/lib/api/src/js/error.rs +++ b/lib/api/src/js/error.rs @@ -8,54 +8,17 @@ use std::borrow::Cow; use thiserror::Error; use wasmer_types::{CompileError, ImportError}; -/// A WebAssembly translation error. -/// -/// When a WebAssembly function can't be translated, one of these error codes will be returned -/// to describe the failure. -#[derive(Debug)] -#[cfg_attr(feature = "std", derive(Error))] -pub enum WasmError { - /// The input WebAssembly code is invalid. - /// - /// This error code is used by a WebAssembly translator when it encounters invalid WebAssembly - /// code. This should never happen for validated WebAssembly code. - #[cfg_attr( - feature = "std", - error("Invalid input WebAssembly code at offset {offset}: {message}") - )] - InvalidWebAssembly { - /// A string describing the validation error. - message: String, - /// The bytecode offset where the error occurred. - offset: usize, - }, - - /// A feature used by the WebAssembly code is not supported by the embedding environment. - /// - /// Embedding environments may have their own limitations and feature restrictions. - #[cfg_attr(feature = "std", error("Unsupported feature: {0}"))] - Unsupported(String), - - /// A Javascript value could not be converted to the requested type. - #[cfg_attr(feature = "std", error("{0} doesn't match js value type {1}"))] - TypeMismatch(Cow<'static, str>, Cow<'static, str>), - - /// A generic error. - #[cfg_attr(feature = "std", error("{0}"))] - Generic(String), -} - -impl From for WasmError { - fn from(err: wasm_bindgen::JsValue) -> Self { - Self::Generic( - if err.is_string() && err.as_string().filter(|s| !s.is_empty()).is_some() { - err.as_string().unwrap_or_default() - } else { - format!("Unexpected Javascript error: {:?}", err) - }, - ) - } -} +// impl From for WasmError { +// fn from(err: wasm_bindgen::JsValue) -> Self { +// Self::Generic( +// if err.is_string() && err.as_string().filter(|s| !s.is_empty()).is_some() { +// err.as_string().unwrap_or_default() +// } else { +// format!("Unexpected Javascript error: {:?}", err) +// }, +// ) +// } +// } /// The Serialize error can occur when serializing a /// compiled Module into a binary. diff --git a/lib/api/src/js/instance.rs b/lib/api/src/js/instance.rs index 44c915097a0..2a54097ea37 100644 --- a/lib/api/src/js/instance.rs +++ b/lib/api/src/js/instance.rs @@ -8,91 +8,33 @@ use crate::module::Module; use crate::store::{AsStoreMut, AsStoreRef}; use crate::{LinkError, RuntimeError}; use js_sys::WebAssembly; -use std::fmt; -/// A WebAssembly Instance is a stateful, executable -/// instance of a WebAssembly [`Module`]. -/// -/// Instance objects contain all the exported WebAssembly -/// functions, memories, tables and globals that allow -/// interacting with WebAssembly. -/// -/// Spec: #[derive(Clone)] pub struct Instance { - pub(crate) handle: VMInstance, - pub(crate) module: Module, - /// The exports for an instance. - pub exports: Exports, + pub(crate) _handle: VMInstance, } +unsafe impl Send for Instance {} + impl Instance { - /// Creates a new `Instance` from a WebAssembly [`Module`] and a - /// set of imports resolved by the [`Resolver`]. - /// - /// The resolver can be anything that implements the [`Resolver`] trait, - /// so you can plug custom resolution for the imports, if you wish not - /// to use [`ImportObject`]. - /// - /// The [`ImportObject`] is the easiest way to provide imports to the instance. - /// - /// [`ImportObject`]: crate::js::ImportObject - /// - /// ``` - /// # use wasmer::{imports, Store, Module, Global, Value, Instance}; - /// # fn main() -> anyhow::Result<()> { - /// let mut store = Store::default(); - /// let module = Module::new(&store, "(module)")?; - /// let imports = imports!{ - /// "host" => { - /// "var" => Global::new(&store, Value::I32(2)) - /// } - /// }; - /// let instance = Instance::new(&module, &imports)?; - /// # Ok(()) - /// # } - /// ``` - /// - /// ## Errors - /// - /// The function can return [`InstantiationError`]s. - /// - /// Those are, as defined by the spec: - /// * Link errors that happen when plugging the imports into the instance - /// * Runtime errors that happen when running the module `start` function. - pub fn new( + pub(crate) fn new( mut store: &mut impl AsStoreMut, module: &Module, imports: &Imports, - ) -> Result { + ) -> Result<(Self, Exports), InstantiationError> { let instance = module .0 .instantiate(&mut store, imports) .map_err(|e| InstantiationError::Start(e))?; - let self_instance = Self::from_jsvalue(store, &module, &instance).map_err(|e| { - let js_err: wasm_bindgen::JsValue = e.into(); - let err: RuntimeError = js_err.into(); - InstantiationError::Link(LinkError::Trap(err)) - })?; - Ok(self_instance) + Self::from_module_and_instance(store, &module, instance) } - /// Creates a new `Instance` from a WebAssembly [`Module`] and a - /// vector of imports. - /// - /// ## Errors - /// - /// The function can return [`InstantiationError`]s. - /// - /// Those are, as defined by the spec: - /// * Link errors that happen when plugging the imports into the instance - /// * Runtime errors that happen when running the module `start` function. - pub fn new_by_index( + pub(crate) fn new_by_index( store: &mut impl AsStoreMut, module: &Module, externs: &[Extern], - ) -> Result { + ) -> Result<(Self, Exports), InstantiationError> { let mut imports = Imports::new(); for (import_ty, extern_ty) in module.imports().zip(externs.iter()) { imports.define(import_ty.module(), import_ty.name(), extern_ty.clone()); @@ -101,11 +43,11 @@ impl Instance { } /// Creates a Wasmer `Instance` from a Wasmer `Module` and a WebAssembly Instance - pub fn from_module_and_instance( + pub(crate) fn from_module_and_instance( mut store: &mut impl AsStoreMut, module: &Module, instance: WebAssembly::Instance, - ) -> Result { + ) -> Result<(Self, Exports), InstantiationError> { let instance_exports = instance.exports(); let exports = module @@ -124,23 +66,6 @@ impl Instance { }) .collect::>()?; - Ok(Self { - handle: instance, - module: module.clone(), - exports, - }) - } - - /// Gets the [`Module`] associated with this instance. - pub fn module(&self) -> &Module { - &self.module - } -} - -impl fmt::Debug for Instance { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("Instance") - .field("exports", &self.exports) - .finish() + Ok((Self { _handle: instance }, exports)) } } diff --git a/lib/api/src/js/mod.rs b/lib/api/src/js/mod.rs index 578ba4b1bd3..7457b4a4e27 100644 --- a/lib/api/src/js/mod.rs +++ b/lib/api/src/js/mod.rs @@ -28,7 +28,7 @@ pub(crate) mod engine; pub(crate) mod error; pub(crate) mod extern_ref; pub(crate) mod externals; -mod instance; +pub(crate) mod instance; pub(crate) mod module; #[cfg(feature = "wasm-types-polyfill")] mod module_info_polyfill; diff --git a/lib/api/src/js/module.rs b/lib/api/src/js/module.rs index a0af2775747..53b36422ecf 100644 --- a/lib/api/src/js/module.rs +++ b/lib/api/src/js/module.rs @@ -1,7 +1,5 @@ use crate::errors::InstantiationError; use crate::imports::Imports; -#[cfg(feature = "wat")] -use crate::js::error::WasmError; use crate::js::externals::Extern; use crate::js::vm::VMInstance; use crate::js::AsJs; @@ -60,6 +58,8 @@ pub struct Module { raw_bytes: Option, } +unsafe impl Send for Module {} + impl Module { /// Creates a new WebAssembly module from a file path. pub fn from_file( diff --git a/lib/api/src/js/vm.rs b/lib/api/src/js/vm.rs index 84baabb35b3..460f66474b6 100644 --- a/lib/api/src/js/vm.rs +++ b/lib/api/src/js/vm.rs @@ -4,7 +4,6 @@ /// This module should not be needed any longer (with the exception of the memory) /// once the type reflection is added to the WebAssembly JS API. /// https://github.com/WebAssembly/js-types/ -use crate::js::error::WasmError; use crate::js::wasm_bindgen_polyfill::Global as JsGlobal; use crate::store::{AsStoreMut, AsStoreRef}; use crate::MemoryView; diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index 930816fb764..e4db3104bf7 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -435,6 +435,7 @@ mod exports; mod extern_ref; mod function_env; mod imports; +mod instance; mod into_bytes; mod mem_access; mod module; @@ -462,6 +463,7 @@ pub use exports::{ExportError, Exportable, Exports, ExportsIterator}; pub use extern_ref::ExternRef; pub use function_env::{FunctionEnv, FunctionEnvMut}; pub use imports::Imports; +pub use instance::Instance; pub use into_bytes::IntoBytes; pub use mem_access::{MemoryAccessError, WasmRef, WasmSlice, WasmSliceIter}; pub use module::{IoCompileError, Module}; diff --git a/lib/api/src/sys/instance.rs b/lib/api/src/sys/instance.rs index 660ec375b7d..d616141bf89 100644 --- a/lib/api/src/sys/instance.rs +++ b/lib/api/src/sys/instance.rs @@ -1,7 +1,6 @@ use crate::errors::InstantiationError; use crate::exports::Exports; use crate::module::Module; -use std::fmt; use wasmer_vm::{StoreHandle, VMInstance}; use crate::imports::Imports; @@ -19,23 +18,6 @@ use crate::sys::externals::Extern; #[derive(Clone)] pub struct Instance { _handle: StoreHandle, - module: Module, - /// The exports for an instance. - pub exports: Exports, -} - -#[cfg(test)] -mod send_test { - use super::*; - - fn is_send() -> bool { - true - } - - #[test] - fn instance_is_send() { - assert!(is_send::()); - } } impl From for InstantiationError { @@ -49,41 +31,11 @@ impl From for InstantiationError { } impl Instance { - /// Creates a new `Instance` from a WebAssembly [`Module`] and a - /// set of imports using [`Imports`] or the [`imports`] macro helper. - /// - /// [`imports`]: crate::imports - /// [`Imports`]: crate::Imports - /// - /// ``` - /// # use wasmer::{imports, Store, Module, Global, Value, Instance}; - /// # use wasmer::FunctionEnv; - /// # fn main() -> anyhow::Result<()> { - /// let mut store = Store::default(); - /// let env = FunctionEnv::new(&mut store, ()); - /// let module = Module::new(&store, "(module)")?; - /// let imports = imports!{ - /// "host" => { - /// "var" => Global::new(&mut store, Value::I32(2)) - /// } - /// }; - /// let instance = Instance::new(&mut store, &module, &imports)?; - /// # Ok(()) - /// # } - /// ``` - /// - /// ## Errors - /// - /// The function can return [`InstantiationError`]s. - /// - /// Those are, as defined by the spec: - /// * Link errors that happen when plugging the imports into the instance - /// * Runtime errors that happen when running the module `start` function. - pub fn new( + pub(crate) fn new( store: &mut impl AsStoreMut, module: &Module, imports: &Imports, - ) -> Result { + ) -> Result<(Self, Exports), InstantiationError> { let externs = imports .imports_for_module(module) .map_err(InstantiationError::Link)?; @@ -92,38 +44,24 @@ impl Instance { let instance = Self { _handle: StoreHandle::new(store.objects_mut(), handle), - module: module.clone(), - exports, }; - Ok(instance) + Ok((instance, exports)) } - /// Creates a new `Instance` from a WebAssembly [`Module`] and a - /// vector of imports. - /// - /// ## Errors - /// - /// The function can return [`InstantiationError`]s. - /// - /// Those are, as defined by the spec: - /// * Link errors that happen when plugging the imports into the instance - /// * Runtime errors that happen when running the module `start` function. - pub fn new_by_index( + pub(crate) fn new_by_index( store: &mut impl AsStoreMut, module: &Module, externs: &[Extern], - ) -> Result { + ) -> Result<(Self, Exports), InstantiationError> { let externs = externs.to_vec(); let mut handle = module.0.instantiate(store, &externs)?; let exports = Self::get_exports(store, module, &mut handle); let instance = Self { _handle: StoreHandle::new(store.objects_mut(), handle), - module: module.clone(), - exports, }; - Ok(instance) + Ok((instance, exports)) } fn get_exports( @@ -141,17 +79,4 @@ impl Instance { }) .collect::() } - - /// Gets the [`Module`] associated with this instance. - pub fn module(&self) -> &Module { - &self.module - } -} - -impl fmt::Debug for Instance { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("Instance") - .field("exports", &self.exports) - .finish() - } } diff --git a/lib/api/src/sys/mod.rs b/lib/api/src/sys/mod.rs index 325a74e477e..48cfab57f79 100644 --- a/lib/api/src/sys/mod.rs +++ b/lib/api/src/sys/mod.rs @@ -1,7 +1,7 @@ pub(crate) mod engine; pub(crate) mod extern_ref; pub(crate) mod externals; -mod instance; +pub(crate) mod instance; pub(crate) mod module; mod tunables; pub(crate) mod typed_function; From f72220e9d741883da31eaad98d7a8f2d22022319 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Sat, 11 Feb 2023 18:10:22 -0800 Subject: [PATCH 34/81] Removed repeated comments --- lib/api/src/js/module.rs | 8 -------- lib/api/src/sys/instance.rs | 8 -------- lib/api/src/sys/module.rs | 8 -------- 3 files changed, 24 deletions(-) diff --git a/lib/api/src/js/module.rs b/lib/api/src/js/module.rs index 53b36422ecf..fdf51527517 100644 --- a/lib/api/src/js/module.rs +++ b/lib/api/src/js/module.rs @@ -40,14 +40,6 @@ pub struct ModuleTypeHints { pub exports: Vec, } -/// 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 { module: WebAssembly::Module, diff --git a/lib/api/src/sys/instance.rs b/lib/api/src/sys/instance.rs index d616141bf89..88a6dee3869 100644 --- a/lib/api/src/sys/instance.rs +++ b/lib/api/src/sys/instance.rs @@ -7,14 +7,6 @@ use crate::imports::Imports; use crate::store::AsStoreMut; use crate::sys::externals::Extern; -/// A WebAssembly Instance is a stateful, executable -/// instance of a WebAssembly [`Module`]. -/// -/// Instance objects contain all the exported WebAssembly -/// functions, memories, tables and globals that allow -/// interacting with WebAssembly. -/// -/// Spec: #[derive(Clone)] pub struct Instance { _handle: StoreHandle, diff --git a/lib/api/src/sys/module.rs b/lib/api/src/sys/module.rs index c42c55af740..78c0d228083 100644 --- a/lib/api/src/sys/module.rs +++ b/lib/api/src/sys/module.rs @@ -12,14 +12,6 @@ use wasmer_types::{ExportType, ImportType}; use crate::{AsStoreMut, AsStoreRef, InstantiationError, IntoBytes}; use wasmer_vm::VMInstance; -/// 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 { // The field ordering here is actually significant because of the drop From 1d85b301ef913acae26a102bc163cf5f23610eaf Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Sat, 11 Feb 2023 18:31:01 -0800 Subject: [PATCH 35/81] Moved reexports one level down --- lib/api/src/js/as_js.rs | 18 +++++++++--------- lib/api/src/js/externals/function.rs | 2 +- lib/api/src/js/externals/global.rs | 4 ++-- lib/api/src/js/externals/memory.rs | 2 +- lib/api/src/js/externals/table.rs | 2 +- lib/api/src/js/mod.rs | 19 ------------------- lib/api/src/lib.rs | 19 +++++++++++++++++++ lib/api/src/sys/externals/global.rs | 4 ++-- lib/api/src/sys/externals/memory.rs | 2 +- lib/api/src/sys/externals/mod.rs | 2 +- lib/api/src/sys/externals/table.rs | 2 +- lib/api/src/sys/mod.rs | 17 ----------------- 12 files changed, 38 insertions(+), 55 deletions(-) diff --git a/lib/api/src/js/as_js.rs b/lib/api/src/js/as_js.rs index 5dad4e6d093..974ae681204 100644 --- a/lib/api/src/js/as_js.rs +++ b/lib/api/src/js/as_js.rs @@ -3,13 +3,13 @@ // use crate::js::RuntimeError; use crate::imports::Imports; use crate::js::externals::{Extern, Function, Global, Memory, Table}; +use crate::js::instance::Instance; use crate::js::vm::{VMExtern, VMFunction, VMGlobal, VMMemory, VMTable}; use crate::js::wasm_bindgen_polyfill::Global as JsGlobal; -use crate::js::Instance; use crate::store::{AsStoreMut, AsStoreRef}; use crate::value::Value; use crate::Exports; -use crate::ValType; +use crate::Type; use js_sys::Function as JsFunction; use js_sys::WebAssembly::{Memory as JsMemory, Table as JsTable}; use std::collections::HashMap; @@ -32,12 +32,12 @@ pub trait AsJs: Sized { } #[inline] -pub fn param_from_js(ty: &ValType, js_val: &JsValue) -> Value { +pub fn param_from_js(ty: &Type, js_val: &JsValue) -> Value { match ty { - ValType::I32 => Value::I32(js_val.as_f64().unwrap() as _), - ValType::I64 => Value::I64(js_val.as_f64().unwrap() as _), - ValType::F32 => Value::F32(js_val.as_f64().unwrap() as _), - ValType::F64 => Value::F64(js_val.as_f64().unwrap()), + Type::I32 => Value::I32(js_val.as_f64().unwrap() as _), + Type::I64 => Value::I64(js_val.as_f64().unwrap() as _), + Type::F32 => Value::F32(js_val.as_f64().unwrap() as _), + Type::F64 => Value::F64(js_val.as_f64().unwrap()), t => unimplemented!( "The type `{:?}` is not yet supported in the JS Function API", t @@ -46,7 +46,7 @@ pub fn param_from_js(ty: &ValType, js_val: &JsValue) -> Value { } impl AsJs for Value { - type DefinitionType = ValType; + type DefinitionType = Type; fn as_jsvalue(&self, _store: &impl AsStoreRef) -> JsValue { match self { @@ -71,7 +71,7 @@ impl AsJs for Value { } impl AsJs for wasmer_types::RawValue { - type DefinitionType = ValType; + type DefinitionType = Type; fn as_jsvalue(&self, _store: &impl AsStoreRef) -> JsValue { unsafe { JsValue::from_f64(self.into()) } diff --git a/lib/api/src/js/externals/function.rs b/lib/api/src/js/externals/function.rs index 1ab9fac2356..bfd527394d3 100644 --- a/lib/api/src/js/externals/function.rs +++ b/lib/api/src/js/externals/function.rs @@ -4,10 +4,10 @@ use crate::function_env::{FunctionEnv, FunctionEnvMut}; use crate::js::as_js::{param_from_js, AsJs}; /* ValFuncRef */ use crate::js::externals::Extern; use crate::js::vm::VMExtern; -use crate::js::FunctionType; use crate::js::RuntimeError; use crate::store::{AsStoreMut, AsStoreRef, StoreMut}; use crate::value::Value; +use crate::FunctionType; use crate::TypedFunction; use js_sys::{Array, Function as JSFunction}; use std::iter::FromIterator; diff --git a/lib/api/src/js/externals/global.rs b/lib/api/src/js/externals/global.rs index e18b1c3f5dd..410803f7dab 100644 --- a/lib/api/src/js/externals/global.rs +++ b/lib/api/src/js/externals/global.rs @@ -2,11 +2,11 @@ use crate::exports::{ExportError, Exportable}; use crate::js::externals::Extern; use crate::js::vm::{VMExtern, VMGlobal}; use crate::js::wasm_bindgen_polyfill::Global as JSGlobal; -use crate::js::GlobalType; -use crate::js::Mutability; use crate::js::RuntimeError; use crate::store::{AsStoreMut, AsStoreRef}; use crate::value::Value; +use crate::GlobalType; +use crate::Mutability; use wasm_bindgen::JsValue; use wasmer_types::{RawValue, Type}; diff --git a/lib/api/src/js/externals/memory.rs b/lib/api/src/js/externals/memory.rs index 98d52ccb43c..4b45ba90892 100644 --- a/lib/api/src/js/externals/memory.rs +++ b/lib/api/src/js/externals/memory.rs @@ -1,9 +1,9 @@ use crate::exports::{ExportError, Exportable}; use crate::js::externals::Extern; use crate::js::vm::{VMExtern, VMMemory}; -use crate::js::MemoryType; use crate::mem_access::MemoryAccessError; use crate::store::{AsStoreMut, AsStoreRef, StoreObjects}; +use crate::MemoryType; use std::marker::PhantomData; use std::mem::MaybeUninit; use std::slice; diff --git a/lib/api/src/js/externals/table.rs b/lib/api/src/js/externals/table.rs index e616d5031d5..63118660224 100644 --- a/lib/api/src/js/externals/table.rs +++ b/lib/api/src/js/externals/table.rs @@ -2,9 +2,9 @@ use crate::exports::{ExportError, Exportable}; use crate::js::externals::Extern; use crate::js::vm::{VMExtern, VMFunction, VMTable}; use crate::js::RuntimeError; -use crate::js::{FunctionType, TableType}; use crate::store::{AsStoreMut, AsStoreRef}; use crate::value::Value; +use crate::{FunctionType, TableType}; use js_sys::Function; /// A WebAssembly `table` instance. diff --git a/lib/api/src/js/mod.rs b/lib/api/src/js/mod.rs index 7457b4a4e27..aab009b62e3 100644 --- a/lib/api/src/js/mod.rs +++ b/lib/api/src/js/mod.rs @@ -39,33 +39,14 @@ pub(crate) mod vm; mod wasm_bindgen_polyfill; pub use crate::js::as_js::AsJs; -pub use crate::js::engine::Engine; pub use crate::js::error::{DeserializeError, LinkError, SerializeError}; pub use crate::js::externals::{ Extern, FromToNativeWasmType, Function, Global, HostFunction, Memory, MemoryError, MemoryView, Table, WasmTypeList, }; -pub use crate::js::instance::Instance; pub use crate::js::module::{Module, ModuleTypeHints}; pub use crate::js::store::StoreObjects; pub use crate::js::trap::RuntimeError; -pub use wasmer_types::is_wasm; -// TODO: OnCalledAction is needed for asyncify. It will be refactored with https://github.com/wasmerio/wasmer/issues/3451 -pub use wasmer_types::{ - Bytes, ExportIndex, GlobalInit, LocalFunctionIndex, OnCalledAction, Pages, ValueType, - WASM_MAX_PAGES, WASM_MIN_PAGES, WASM_PAGE_SIZE, -}; -pub use wasmer_types::{ - ExportType, ExternType, FunctionType, GlobalType, ImportType, MemoryType, Mutability, - TableType, Type as ValType, Type, -}; - -#[cfg(feature = "wat")] -pub use wat::parse_bytes as wat2wasm; - #[cfg(feature = "wasm-types-polyfill")] pub use wasmparser; - -/// Version number of this crate. -pub const VERSION: &str = env!("CARGO_PKG_VERSION"); diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index e4db3104bf7..907d1a9fab2 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -475,9 +475,28 @@ pub use store::{TrapHandlerFn, Tunables}; pub use typed_function::TypedFunction; pub use value::Value; +// Reexport from other modules + +pub use wasmer_derive::ValueType; +// TODO: OnCalledAction is needed for asyncify. It will be refactored with https://github.com/wasmerio/wasmer/issues/3451 +pub use wasmer_types::{ + is_wasm, Bytes, CompileError, CpuFeature, DeserializeError, ExportIndex, ExportType, + ExternType, FunctionType, GlobalInit, GlobalType, ImportType, LocalFunctionIndex, MemoryType, + MiddlewareError, Mutability, OnCalledAction, Pages, ParseCpuFeatureError, SerializeError, + TableType, Target, Type, ValueType, WasmError, WasmResult, WASM_MAX_PAGES, WASM_MIN_PAGES, + WASM_PAGE_SIZE, +}; +#[cfg(feature = "wat")] +pub use wat::parse_bytes as wat2wasm; + +// Deprecated types + /// This type is deprecated, it has been replaced by TypedFunction. #[deprecated( since = "3.0.0", note = "NativeFunc has been replaced by TypedFunction" )] pub type NativeFunc = TypedFunction; + +/// Version number of this crate. +pub const VERSION: &str = env!("CARGO_PKG_VERSION"); diff --git a/lib/api/src/sys/externals/global.rs b/lib/api/src/sys/externals/global.rs index 5c053cd47d8..58394d3306b 100644 --- a/lib/api/src/sys/externals/global.rs +++ b/lib/api/src/sys/externals/global.rs @@ -1,10 +1,10 @@ use crate::exports::{ExportError, Exportable}; use crate::store::{AsStoreMut, AsStoreRef}; use crate::sys::externals::Extern; -use crate::sys::GlobalType; -use crate::sys::Mutability; use crate::sys::RuntimeError; use crate::value::Value; +use crate::GlobalType; +use crate::Mutability; use wasmer_vm::{InternalStoreHandle, StoreHandle, VMExtern, VMGlobal}; /// A WebAssembly `global` instance. diff --git a/lib/api/src/sys/externals/memory.rs b/lib/api/src/sys/externals/memory.rs index b81285583f9..364f6fac582 100644 --- a/lib/api/src/sys/externals/memory.rs +++ b/lib/api/src/sys/externals/memory.rs @@ -1,8 +1,8 @@ use crate::exports::{ExportError, Exportable}; use crate::store::{AsStoreMut, AsStoreRef}; use crate::sys::externals::Extern; -use crate::sys::MemoryType; use crate::MemoryAccessError; +use crate::MemoryType; use std::convert::TryInto; use std::marker::PhantomData; use std::mem; diff --git a/lib/api/src/sys/externals/mod.rs b/lib/api/src/sys/externals/mod.rs index 84999e61616..f2d63fe8b46 100644 --- a/lib/api/src/sys/externals/mod.rs +++ b/lib/api/src/sys/externals/mod.rs @@ -12,7 +12,7 @@ pub use self::memory_view::MemoryView; pub use self::table::Table; use crate::exports::{ExportError, Exportable}; -use crate::sys::ExternType; +use crate::ExternType; use std::fmt; use wasmer_vm::VMExtern; diff --git a/lib/api/src/sys/externals/table.rs b/lib/api/src/sys/externals/table.rs index d4d735da675..66942d47023 100644 --- a/lib/api/src/sys/externals/table.rs +++ b/lib/api/src/sys/externals/table.rs @@ -1,7 +1,7 @@ use crate::exports::{ExportError, Exportable}; use crate::store::{AsStoreMut, AsStoreRef}; use crate::sys::externals::Extern; -use crate::sys::TableType; +use crate::TableType; use crate::Value; use crate::{sys::RuntimeError, ExternRef, Function}; use wasmer_vm::{InternalStoreHandle, StoreHandle, TableElement, VMExtern, VMTable}; diff --git a/lib/api/src/sys/mod.rs b/lib/api/src/sys/mod.rs index 48cfab57f79..312effcfd19 100644 --- a/lib/api/src/sys/mod.rs +++ b/lib/api/src/sys/mod.rs @@ -10,7 +10,6 @@ pub use crate::sys::externals::{ Extern, FromToNativeWasmType, Function, Global, HostFunction, Memory, MemoryView, Table, WasmTypeList, }; -pub use crate::sys::instance::Instance; pub use crate::sys::tunables::BaseTunables; pub use target_lexicon::{Architecture, CallingConvention, OperatingSystem, Triple, HOST}; @@ -19,19 +18,6 @@ pub use wasmer_compiler::{ wasmparser, CompilerConfig, FunctionMiddleware, MiddlewareReaderState, ModuleMiddleware, }; pub use wasmer_compiler::{Features, FrameInfo, LinkError, RuntimeError, Tunables}; -pub use wasmer_derive::ValueType; -pub use wasmer_types::is_wasm; -// TODO: OnCalledAction is needed for asyncify. It will be refactored with https://github.com/wasmerio/wasmer/issues/3451 -pub use wasmer_types::{ - CpuFeature, ExportType, ExternType, FunctionType, GlobalType, ImportType, MemoryType, - Mutability, OnCalledAction, TableType, Target, Type, -}; - -pub use wasmer_types::{ - Bytes, CompileError, DeserializeError, ExportIndex, GlobalInit, LocalFunctionIndex, - MiddlewareError, Pages, ParseCpuFeatureError, SerializeError, ValueType, WasmError, WasmResult, - WASM_MAX_PAGES, WASM_MIN_PAGES, WASM_PAGE_SIZE, -}; // TODO: should those be moved into wasmer::vm as well? pub use wasmer_vm::{raise_user_trap, MemoryError}; @@ -58,6 +44,3 @@ pub use wasmer_compiler_llvm::{LLVMOptLevel, LLVM}; #[cfg(feature = "compiler")] pub use wasmer_compiler::{Artifact, EngineBuilder}; - -/// Version number of this crate. -pub const VERSION: &str = env!("CARGO_PKG_VERSION"); From db6430c0b36046be27826988bdb310fa1b2275a5 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Sat, 11 Feb 2023 19:32:01 -0800 Subject: [PATCH 36/81] Unified Extern in js/sys --- lib/api/src/externals/function.rs | 8 ++ lib/api/src/externals/global.rs | 4 + lib/api/src/externals/memory.rs | 4 + lib/api/src/externals/memory_view.rs | 4 + lib/api/src/externals/mod.rs | 126 +++++++++++++++++++++++ lib/api/src/externals/table.rs | 4 + lib/api/src/js/as_js.rs | 2 +- lib/api/src/js/externals/function.rs | 2 +- lib/api/src/js/externals/global.rs | 2 +- lib/api/src/js/externals/memory.rs | 4 +- lib/api/src/js/externals/memory_view.rs | 3 +- lib/api/src/js/externals/mod.rs | 116 --------------------- lib/api/src/js/externals/table.rs | 4 +- lib/api/src/js/instance.rs | 2 +- lib/api/src/js/mod.rs | 4 - lib/api/src/js/module.rs | 2 +- lib/api/src/js/typed_function.rs | 4 +- lib/api/src/lib.rs | 13 ++- lib/api/src/sys/externals/function.rs | 2 +- lib/api/src/sys/externals/global.rs | 2 +- lib/api/src/sys/externals/memory.rs | 4 +- lib/api/src/sys/externals/memory_view.rs | 3 +- lib/api/src/sys/externals/mod.rs | 118 --------------------- lib/api/src/sys/externals/table.rs | 2 +- lib/api/src/sys/instance.rs | 2 +- lib/api/src/sys/mod.rs | 5 - lib/api/src/sys/tunables.rs | 2 +- 27 files changed, 179 insertions(+), 269 deletions(-) create mode 100644 lib/api/src/externals/function.rs create mode 100644 lib/api/src/externals/global.rs create mode 100644 lib/api/src/externals/memory.rs create mode 100644 lib/api/src/externals/memory_view.rs create mode 100644 lib/api/src/externals/mod.rs create mode 100644 lib/api/src/externals/table.rs diff --git a/lib/api/src/externals/function.rs b/lib/api/src/externals/function.rs new file mode 100644 index 00000000000..05b873265d8 --- /dev/null +++ b/lib/api/src/externals/function.rs @@ -0,0 +1,8 @@ +#[cfg(feature = "js")] +pub use crate::js::externals::function::{ + FromToNativeWasmType, Function, HostFunction, WasmTypeList, +}; +#[cfg(feature = "sys")] +pub use crate::sys::externals::function::{ + FromToNativeWasmType, Function, HostFunction, WasmTypeList, +}; diff --git a/lib/api/src/externals/global.rs b/lib/api/src/externals/global.rs new file mode 100644 index 00000000000..72fc12150a5 --- /dev/null +++ b/lib/api/src/externals/global.rs @@ -0,0 +1,4 @@ +#[cfg(feature = "js")] +pub use crate::js::externals::global::Global; +#[cfg(feature = "sys")] +pub use crate::sys::externals::global::Global; diff --git a/lib/api/src/externals/memory.rs b/lib/api/src/externals/memory.rs new file mode 100644 index 00000000000..b8c9ee92165 --- /dev/null +++ b/lib/api/src/externals/memory.rs @@ -0,0 +1,4 @@ +#[cfg(feature = "js")] +pub use crate::js::externals::memory::Memory; +#[cfg(feature = "sys")] +pub use crate::sys::externals::memory::Memory; diff --git a/lib/api/src/externals/memory_view.rs b/lib/api/src/externals/memory_view.rs new file mode 100644 index 00000000000..20076158386 --- /dev/null +++ b/lib/api/src/externals/memory_view.rs @@ -0,0 +1,4 @@ +#[cfg(feature = "js")] +pub use crate::js::externals::memory_view::MemoryView; +#[cfg(feature = "sys")] +pub use crate::sys::externals::memory_view::MemoryView; diff --git a/lib/api/src/externals/mod.rs b/lib/api/src/externals/mod.rs new file mode 100644 index 00000000000..50d2b7c55ec --- /dev/null +++ b/lib/api/src/externals/mod.rs @@ -0,0 +1,126 @@ +mod function; +mod global; +mod memory; +mod memory_view; +mod table; + +pub use self::function::{FromToNativeWasmType, Function, HostFunction, WasmTypeList}; +pub use self::global::Global; +pub use self::memory::Memory; +pub use self::memory_view::MemoryView; +pub use self::table::Table; + +use crate::exports::{ExportError, Exportable}; +use crate::ExternType; +use std::fmt; + +#[cfg(feature = "js")] +use crate::js::vm::VMExtern; +#[cfg(feature = "sys")] +use wasmer_vm::VMExtern; + +use crate::store::{AsStoreMut, AsStoreRef}; + +/// An `Extern` is the runtime representation of an entity that +/// can be imported or exported. +/// +/// Spec: +#[derive(Clone)] +pub enum Extern { + /// A external [`Function`]. + Function(Function), + /// A external [`Global`]. + Global(Global), + /// A external [`Table`]. + Table(Table), + /// A external [`Memory`]. + Memory(Memory), +} + +impl Extern { + /// Return the underlying type of the inner `Extern`. + pub fn ty(&self, store: &impl AsStoreRef) -> ExternType { + match self { + Self::Function(ft) => ExternType::Function(ft.ty(store)), + Self::Memory(ft) => ExternType::Memory(ft.ty(store)), + Self::Table(tt) => ExternType::Table(tt.ty(store)), + Self::Global(gt) => ExternType::Global(gt.ty(store)), + } + } + + /// Create an `Extern` from an `wasmer_engine::Export`. + pub fn from_vm_extern(store: &mut impl AsStoreMut, vm_extern: VMExtern) -> Self { + match vm_extern { + VMExtern::Function(f) => Self::Function(Function::from_vm_extern(store, f)), + VMExtern::Memory(m) => Self::Memory(Memory::from_vm_extern(store, m)), + VMExtern::Global(g) => Self::Global(Global::from_vm_extern(store, g)), + VMExtern::Table(t) => Self::Table(Table::from_vm_extern(store, t)), + } + } + + /// Checks whether this `Extern` can be used with the given context. + pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool { + match self { + Self::Function(f) => f.is_from_store(store), + Self::Global(g) => g.is_from_store(store), + Self::Memory(m) => m.is_from_store(store), + Self::Table(t) => t.is_from_store(store), + } + } + + /// To `VMExtern`. + pub fn to_vm_extern(&self) -> VMExtern { + match self { + Self::Function(f) => f.to_vm_extern(), + Self::Global(g) => g.to_vm_extern(), + Self::Memory(m) => m.to_vm_extern(), + Self::Table(t) => t.to_vm_extern(), + } + } +} + +impl<'a> Exportable<'a> for Extern { + fn get_self_from_extern(_extern: &'a Self) -> Result<&'a Self, ExportError> { + // Since this is already an extern, we can just return it. + Ok(_extern) + } +} + +impl fmt::Debug for Extern { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "{}", + match self { + Self::Function(_) => "Function(...)", + Self::Global(_) => "Global(...)", + Self::Memory(_) => "Memory(...)", + Self::Table(_) => "Table(...)", + } + ) + } +} + +impl From for Extern { + fn from(r: Function) -> Self { + Self::Function(r) + } +} + +impl From for Extern { + fn from(r: Global) -> Self { + Self::Global(r) + } +} + +impl From for Extern { + fn from(r: Memory) -> Self { + Self::Memory(r) + } +} + +impl From for Extern { + fn from(r: Table) -> Self { + Self::Table(r) + } +} diff --git a/lib/api/src/externals/table.rs b/lib/api/src/externals/table.rs new file mode 100644 index 00000000000..498eb6a1b6b --- /dev/null +++ b/lib/api/src/externals/table.rs @@ -0,0 +1,4 @@ +#[cfg(feature = "js")] +pub use crate::js::externals::table::Table; +#[cfg(feature = "sys")] +pub use crate::sys::externals::table::Table; diff --git a/lib/api/src/js/as_js.rs b/lib/api/src/js/as_js.rs index 974ae681204..15d417ea047 100644 --- a/lib/api/src/js/as_js.rs +++ b/lib/api/src/js/as_js.rs @@ -2,7 +2,6 @@ // use crate::store::{Store, StoreObject}; // use crate::js::RuntimeError; use crate::imports::Imports; -use crate::js::externals::{Extern, Function, Global, Memory, Table}; use crate::js::instance::Instance; use crate::js::vm::{VMExtern, VMFunction, VMGlobal, VMMemory, VMTable}; use crate::js::wasm_bindgen_polyfill::Global as JsGlobal; @@ -10,6 +9,7 @@ use crate::store::{AsStoreMut, AsStoreRef}; use crate::value::Value; use crate::Exports; use crate::Type; +use crate::{Extern, Function, Global, Memory, Table}; use js_sys::Function as JsFunction; use js_sys::WebAssembly::{Memory as JsMemory, Table as JsTable}; use std::collections::HashMap; diff --git a/lib/api/src/js/externals/function.rs b/lib/api/src/js/externals/function.rs index bfd527394d3..02ab10e78bf 100644 --- a/lib/api/src/js/externals/function.rs +++ b/lib/api/src/js/externals/function.rs @@ -2,11 +2,11 @@ pub use self::inner::{FromToNativeWasmType, HostFunction, WasmTypeList, WithEnv, use crate::exports::{ExportError, Exportable}; use crate::function_env::{FunctionEnv, FunctionEnvMut}; use crate::js::as_js::{param_from_js, AsJs}; /* ValFuncRef */ -use crate::js::externals::Extern; use crate::js::vm::VMExtern; use crate::js::RuntimeError; use crate::store::{AsStoreMut, AsStoreRef, StoreMut}; use crate::value::Value; +use crate::Extern; use crate::FunctionType; use crate::TypedFunction; use js_sys::{Array, Function as JSFunction}; diff --git a/lib/api/src/js/externals/global.rs b/lib/api/src/js/externals/global.rs index 410803f7dab..e926447dd14 100644 --- a/lib/api/src/js/externals/global.rs +++ b/lib/api/src/js/externals/global.rs @@ -1,10 +1,10 @@ use crate::exports::{ExportError, Exportable}; -use crate::js::externals::Extern; use crate::js::vm::{VMExtern, VMGlobal}; use crate::js::wasm_bindgen_polyfill::Global as JSGlobal; use crate::js::RuntimeError; use crate::store::{AsStoreMut, AsStoreRef}; use crate::value::Value; +use crate::Extern; use crate::GlobalType; use crate::Mutability; use wasm_bindgen::JsValue; diff --git a/lib/api/src/js/externals/memory.rs b/lib/api/src/js/externals/memory.rs index 4b45ba90892..bed54b9a31c 100644 --- a/lib/api/src/js/externals/memory.rs +++ b/lib/api/src/js/externals/memory.rs @@ -1,8 +1,8 @@ use crate::exports::{ExportError, Exportable}; -use crate::js::externals::Extern; use crate::js::vm::{VMExtern, VMMemory}; use crate::mem_access::MemoryAccessError; use crate::store::{AsStoreMut, AsStoreRef, StoreObjects}; +use crate::Extern; use crate::MemoryType; use std::marker::PhantomData; use std::mem::MaybeUninit; @@ -14,7 +14,7 @@ use wasm_bindgen::prelude::*; use wasm_bindgen::JsCast; use wasmer_types::{Pages, WASM_PAGE_SIZE}; -use super::MemoryView; +use super::memory_view::MemoryView; pub use wasmer_types::MemoryError; diff --git a/lib/api/src/js/externals/memory_view.rs b/lib/api/src/js/externals/memory_view.rs index 03619cda812..230d4aee734 100644 --- a/lib/api/src/js/externals/memory_view.rs +++ b/lib/api/src/js/externals/memory_view.rs @@ -9,8 +9,7 @@ use tracing::warn; use wasmer_types::{Bytes, Pages}; -use super::memory::MemoryBuffer; -use super::Memory; +use super::memory::{Memory, MemoryBuffer}; /// A WebAssembly `memory` view. /// diff --git a/lib/api/src/js/externals/mod.rs b/lib/api/src/js/externals/mod.rs index b58e17ae15c..3575fe23bb5 100644 --- a/lib/api/src/js/externals/mod.rs +++ b/lib/api/src/js/externals/mod.rs @@ -3,119 +3,3 @@ pub(crate) mod global; pub(crate) mod memory; pub(crate) mod memory_view; pub(crate) mod table; - -pub use self::function::{FromToNativeWasmType, Function, HostFunction, WasmTypeList}; -pub use self::global::Global; -pub use self::memory::{Memory, MemoryError}; -pub use self::memory_view::MemoryView; -pub use self::table::Table; - -use crate::exports::{ExportError, Exportable}; -use crate::js::vm::VMExtern; -use crate::store::{AsStoreMut, AsStoreRef}; -use std::fmt; -use wasmer_types::ExternType; - -/// An `Extern` is the runtime representation of an entity that -/// can be imported or exported. -/// -/// Spec: -#[derive(Clone)] -pub enum Extern { - /// A external [`Function`]. - Function(Function), - /// A external [`Global`]. - Global(Global), - /// A external [`Table`]. - Table(Table), - /// A external [`Memory`]. - Memory(Memory), -} - -impl Extern { - /// Return the underlying type of the inner `Extern`. - pub fn ty(&self, store: &impl AsStoreRef) -> ExternType { - match self { - Self::Function(ft) => ExternType::Function(ft.ty(store)), - Self::Memory(ft) => ExternType::Memory(ft.ty(store)), - Self::Table(tt) => ExternType::Table(tt.ty(store)), - Self::Global(gt) => ExternType::Global(gt.ty(store)), - } - } - - /// Create an `Extern` from an `wasmer_engine::Export`. - pub fn from_vm_extern(store: &mut impl AsStoreMut, vm_extern: VMExtern) -> Self { - match vm_extern { - VMExtern::Function(f) => Self::Function(Function::from_vm_extern(store, f)), - VMExtern::Memory(m) => Self::Memory(Memory::from_vm_extern(store, m)), - VMExtern::Global(g) => Self::Global(Global::from_vm_extern(store, g)), - VMExtern::Table(t) => Self::Table(Table::from_vm_extern(store, t)), - } - } - - /// To `VMExtern`. - pub fn to_vm_extern(&self) -> VMExtern { - match self { - Self::Function(f) => f.to_vm_extern(), - Self::Global(g) => g.to_vm_extern(), - Self::Memory(m) => m.to_vm_extern(), - Self::Table(t) => t.to_vm_extern(), - } - } - - /// Checks whether this `Extern` can be used with the given context. - pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool { - match self { - Self::Function(val) => val.is_from_store(store), - Self::Memory(val) => val.is_from_store(store), - Self::Global(val) => val.is_from_store(store), - Self::Table(val) => val.is_from_store(store), - } - } -} - -impl<'a> Exportable<'a> for Extern { - fn get_self_from_extern(_extern: &'a Self) -> Result<&'a Self, ExportError> { - // Since this is already an extern, we can just return it. - Ok(_extern) - } -} - -impl fmt::Debug for Extern { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "{}", - match self { - Self::Function(_) => "Function(...)", - Self::Global(_) => "Global(...)", - Self::Memory(_) => "Memory(...)", - Self::Table(_) => "Table(...)", - } - ) - } -} - -impl From for Extern { - fn from(r: Function) -> Self { - Self::Function(r) - } -} - -impl From for Extern { - fn from(r: Global) -> Self { - Self::Global(r) - } -} - -impl From for Extern { - fn from(r: Memory) -> Self { - Self::Memory(r) - } -} - -impl From
for Extern { - fn from(r: Table) -> Self { - Self::Table(r) - } -} diff --git a/lib/api/src/js/externals/table.rs b/lib/api/src/js/externals/table.rs index 63118660224..ab3357ee967 100644 --- a/lib/api/src/js/externals/table.rs +++ b/lib/api/src/js/externals/table.rs @@ -1,9 +1,9 @@ use crate::exports::{ExportError, Exportable}; -use crate::js::externals::Extern; use crate::js::vm::{VMExtern, VMFunction, VMTable}; use crate::js::RuntimeError; use crate::store::{AsStoreMut, AsStoreRef}; use crate::value::Value; +use crate::Extern; use crate::{FunctionType, TableType}; use js_sys::Function; @@ -83,7 +83,7 @@ impl Table { if let Some(func) = self.handle.table.get(index).ok() { let ty = FunctionType::new(vec![], vec![]); let vm_function = VMFunction::new(func, ty); - let function = crate::js::externals::Function::from_vm_extern(store, vm_function); + let function = crate::Function::from_vm_extern(store, vm_function); Some(Value::FuncRef(Some(function))) } else { None diff --git a/lib/api/src/js/instance.rs b/lib/api/src/js/instance.rs index 2a54097ea37..f392ea17216 100644 --- a/lib/api/src/js/instance.rs +++ b/lib/api/src/js/instance.rs @@ -2,10 +2,10 @@ use crate::errors::InstantiationError; use crate::exports::Exports; use crate::imports::Imports; use crate::js::as_js::AsJs; -use crate::js::externals::Extern; use crate::js::vm::{VMExtern, VMInstance}; use crate::module::Module; use crate::store::{AsStoreMut, AsStoreRef}; +use crate::Extern; use crate::{LinkError, RuntimeError}; use js_sys::WebAssembly; diff --git a/lib/api/src/js/mod.rs b/lib/api/src/js/mod.rs index aab009b62e3..e7d13645070 100644 --- a/lib/api/src/js/mod.rs +++ b/lib/api/src/js/mod.rs @@ -40,10 +40,6 @@ mod wasm_bindgen_polyfill; pub use crate::js::as_js::AsJs; pub use crate::js::error::{DeserializeError, LinkError, SerializeError}; -pub use crate::js::externals::{ - Extern, FromToNativeWasmType, Function, Global, HostFunction, Memory, MemoryError, MemoryView, - Table, WasmTypeList, -}; pub use crate::js::module::{Module, ModuleTypeHints}; pub use crate::js::store::StoreObjects; pub use crate::js::trap::RuntimeError; diff --git a/lib/api/src/js/module.rs b/lib/api/src/js/module.rs index fdf51527517..85c6d2f3c14 100644 --- a/lib/api/src/js/module.rs +++ b/lib/api/src/js/module.rs @@ -1,11 +1,11 @@ use crate::errors::InstantiationError; use crate::imports::Imports; -use crate::js::externals::Extern; use crate::js::vm::VMInstance; use crate::js::AsJs; use crate::js::RuntimeError; use crate::module::IoCompileError; use crate::store::AsStoreMut; +use crate::Extern; use crate::IntoBytes; use crate::{AsEngineRef, ExportType, ImportType}; use bytes::Bytes; diff --git a/lib/api/src/js/typed_function.rs b/lib/api/src/js/typed_function.rs index 075872f4684..71faffa1c24 100644 --- a/lib/api/src/js/typed_function.rs +++ b/lib/api/src/js/typed_function.rs @@ -9,10 +9,10 @@ //! ``` use std::marker::PhantomData; -use crate::js::externals::Function; -use crate::js::{FromToNativeWasmType, RuntimeError, WasmTypeList}; use crate::native_type::NativeWasmTypeInto; +use crate::Function; use crate::{AsStoreMut, AsStoreRef, TypedFunction}; +use crate::{FromToNativeWasmType, RuntimeError, WasmTypeList}; // use std::panic::{catch_unwind, AssertUnwindSafe}; use crate::js::as_js::{param_from_js, AsJs}; use js_sys::Array; diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index 907d1a9fab2..d6f9c152036 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -433,6 +433,7 @@ mod engine; mod errors; mod exports; mod extern_ref; +mod externals; mod function_env; mod imports; mod instance; @@ -457,6 +458,10 @@ mod js; #[cfg(feature = "js")] pub use js::*; +pub use crate::externals::{ + Extern, FromToNativeWasmType, Function, Global, HostFunction, Memory, MemoryView, Table, + WasmTypeList, +}; pub use engine::{AsEngineRef, Engine}; pub use errors::InstantiationError; pub use exports::{ExportError, Exportable, Exports, ExportsIterator}; @@ -481,10 +486,10 @@ pub use wasmer_derive::ValueType; // TODO: OnCalledAction is needed for asyncify. It will be refactored with https://github.com/wasmerio/wasmer/issues/3451 pub use wasmer_types::{ is_wasm, Bytes, CompileError, CpuFeature, DeserializeError, ExportIndex, ExportType, - ExternType, FunctionType, GlobalInit, GlobalType, ImportType, LocalFunctionIndex, MemoryType, - MiddlewareError, Mutability, OnCalledAction, Pages, ParseCpuFeatureError, SerializeError, - TableType, Target, Type, ValueType, WasmError, WasmResult, WASM_MAX_PAGES, WASM_MIN_PAGES, - WASM_PAGE_SIZE, + ExternType, FunctionType, GlobalInit, GlobalType, ImportType, LocalFunctionIndex, MemoryError, + MemoryType, MiddlewareError, Mutability, OnCalledAction, Pages, ParseCpuFeatureError, + SerializeError, TableType, Target, Type, ValueType, WasmError, WasmResult, WASM_MAX_PAGES, + WASM_MIN_PAGES, WASM_PAGE_SIZE, }; #[cfg(feature = "wat")] pub use wat::parse_bytes as wat2wasm; diff --git a/lib/api/src/sys/externals/function.rs b/lib/api/src/sys/externals/function.rs index 13144c39cd8..a5d1ea1c44c 100644 --- a/lib/api/src/sys/externals/function.rs +++ b/lib/api/src/sys/externals/function.rs @@ -7,7 +7,7 @@ use wasmer_vm::{ use crate::exports::{ExportError, Exportable}; use crate::store::{AsStoreMut, AsStoreRef}; -use crate::sys::externals::Extern; +use crate::Extern; use crate::FunctionEnv; use crate::{FunctionType, RuntimeError, TypedFunction}; diff --git a/lib/api/src/sys/externals/global.rs b/lib/api/src/sys/externals/global.rs index 58394d3306b..c16c7b2125c 100644 --- a/lib/api/src/sys/externals/global.rs +++ b/lib/api/src/sys/externals/global.rs @@ -1,8 +1,8 @@ use crate::exports::{ExportError, Exportable}; use crate::store::{AsStoreMut, AsStoreRef}; -use crate::sys::externals::Extern; use crate::sys::RuntimeError; use crate::value::Value; +use crate::Extern; use crate::GlobalType; use crate::Mutability; use wasmer_vm::{InternalStoreHandle, StoreHandle, VMExtern, VMGlobal}; diff --git a/lib/api/src/sys/externals/memory.rs b/lib/api/src/sys/externals/memory.rs index 364f6fac582..c4619df4218 100644 --- a/lib/api/src/sys/externals/memory.rs +++ b/lib/api/src/sys/externals/memory.rs @@ -1,6 +1,6 @@ use crate::exports::{ExportError, Exportable}; use crate::store::{AsStoreMut, AsStoreRef}; -use crate::sys::externals::Extern; +use crate::Extern; use crate::MemoryAccessError; use crate::MemoryType; use std::convert::TryInto; @@ -13,7 +13,7 @@ use tracing::warn; use wasmer_types::Pages; use wasmer_vm::{InternalStoreHandle, LinearMemory, MemoryError, StoreHandle, VMExtern, VMMemory}; -use super::MemoryView; +use super::memory_view::MemoryView; /// A WebAssembly `memory` instance. /// diff --git a/lib/api/src/sys/externals/memory_view.rs b/lib/api/src/sys/externals/memory_view.rs index 94044f8770e..8adc29d91e7 100644 --- a/lib/api/src/sys/externals/memory_view.rs +++ b/lib/api/src/sys/externals/memory_view.rs @@ -7,8 +7,7 @@ use std::slice; use wasmer_types::Pages; use wasmer_vm::LinearMemory; -use super::memory::MemoryBuffer; -use super::Memory; +use super::memory::{Memory, MemoryBuffer}; /// A WebAssembly `memory` view. /// diff --git a/lib/api/src/sys/externals/mod.rs b/lib/api/src/sys/externals/mod.rs index f2d63fe8b46..3575fe23bb5 100644 --- a/lib/api/src/sys/externals/mod.rs +++ b/lib/api/src/sys/externals/mod.rs @@ -3,121 +3,3 @@ pub(crate) mod global; pub(crate) mod memory; pub(crate) mod memory_view; pub(crate) mod table; - -pub use self::function::{FromToNativeWasmType, Function, HostFunction, WasmTypeList}; - -pub use self::global::Global; -pub use self::memory::Memory; -pub use self::memory_view::MemoryView; -pub use self::table::Table; - -use crate::exports::{ExportError, Exportable}; -use crate::ExternType; -use std::fmt; -use wasmer_vm::VMExtern; - -use crate::store::{AsStoreMut, AsStoreRef}; - -/// An `Extern` is the runtime representation of an entity that -/// can be imported or exported. -/// -/// Spec: -#[derive(Clone)] -pub enum Extern { - /// A external [`Function`]. - Function(Function), - /// A external [`Global`]. - Global(Global), - /// A external [`Table`]. - Table(Table), - /// A external [`Memory`]. - Memory(Memory), -} - -impl Extern { - /// Return the underlying type of the inner `Extern`. - pub fn ty(&self, store: &impl AsStoreRef) -> ExternType { - match self { - Self::Function(ft) => ExternType::Function(ft.ty(store)), - Self::Memory(ft) => ExternType::Memory(ft.ty(store)), - Self::Table(tt) => ExternType::Table(tt.ty(store)), - Self::Global(gt) => ExternType::Global(gt.ty(store)), - } - } - - /// Create an `Extern` from an `wasmer_engine::Export`. - pub fn from_vm_extern(store: &mut impl AsStoreMut, vm_extern: VMExtern) -> Self { - match vm_extern { - VMExtern::Function(f) => Self::Function(Function::from_vm_extern(store, f)), - VMExtern::Memory(m) => Self::Memory(Memory::from_vm_extern(store, m)), - VMExtern::Global(g) => Self::Global(Global::from_vm_extern(store, g)), - VMExtern::Table(t) => Self::Table(Table::from_vm_extern(store, t)), - } - } - - /// Checks whether this `Extern` can be used with the given context. - pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool { - match self { - Self::Function(f) => f.is_from_store(store), - Self::Global(g) => g.is_from_store(store), - Self::Memory(m) => m.is_from_store(store), - Self::Table(t) => t.is_from_store(store), - } - } - - /// To `VMExtern`. - pub fn to_vm_extern(&self) -> VMExtern { - match self { - Self::Function(f) => f.to_vm_extern(), - Self::Global(g) => g.to_vm_extern(), - Self::Memory(m) => m.to_vm_extern(), - Self::Table(t) => t.to_vm_extern(), - } - } -} - -impl<'a> Exportable<'a> for Extern { - fn get_self_from_extern(_extern: &'a Self) -> Result<&'a Self, ExportError> { - // Since this is already an extern, we can just return it. - Ok(_extern) - } -} - -impl fmt::Debug for Extern { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "{}", - match self { - Self::Function(_) => "Function(...)", - Self::Global(_) => "Global(...)", - Self::Memory(_) => "Memory(...)", - Self::Table(_) => "Table(...)", - } - ) - } -} - -impl From for Extern { - fn from(r: Function) -> Self { - Self::Function(r) - } -} - -impl From for Extern { - fn from(r: Global) -> Self { - Self::Global(r) - } -} - -impl From for Extern { - fn from(r: Memory) -> Self { - Self::Memory(r) - } -} - -impl From
for Extern { - fn from(r: Table) -> Self { - Self::Table(r) - } -} diff --git a/lib/api/src/sys/externals/table.rs b/lib/api/src/sys/externals/table.rs index 66942d47023..b64e955b02d 100644 --- a/lib/api/src/sys/externals/table.rs +++ b/lib/api/src/sys/externals/table.rs @@ -1,6 +1,6 @@ use crate::exports::{ExportError, Exportable}; use crate::store::{AsStoreMut, AsStoreRef}; -use crate::sys::externals::Extern; +use crate::Extern; use crate::TableType; use crate::Value; use crate::{sys::RuntimeError, ExternRef, Function}; diff --git a/lib/api/src/sys/instance.rs b/lib/api/src/sys/instance.rs index 88a6dee3869..a2ef1cbc334 100644 --- a/lib/api/src/sys/instance.rs +++ b/lib/api/src/sys/instance.rs @@ -5,7 +5,7 @@ use wasmer_vm::{StoreHandle, VMInstance}; use crate::imports::Imports; use crate::store::AsStoreMut; -use crate::sys::externals::Extern; +use crate::Extern; #[derive(Clone)] pub struct Instance { diff --git a/lib/api/src/sys/mod.rs b/lib/api/src/sys/mod.rs index 312effcfd19..dc6bf5cddcd 100644 --- a/lib/api/src/sys/mod.rs +++ b/lib/api/src/sys/mod.rs @@ -6,11 +6,6 @@ pub(crate) mod module; mod tunables; pub(crate) mod typed_function; -pub use crate::sys::externals::{ - Extern, FromToNativeWasmType, Function, Global, HostFunction, Memory, MemoryView, Table, - WasmTypeList, -}; - pub use crate::sys::tunables::BaseTunables; pub use target_lexicon::{Architecture, CallingConvention, OperatingSystem, Triple, HOST}; #[cfg(feature = "compiler")] diff --git a/lib/api/src/sys/tunables.rs b/lib/api/src/sys/tunables.rs index 51d2f9ffda2..0e7946b8203 100644 --- a/lib/api/src/sys/tunables.rs +++ b/lib/api/src/sys/tunables.rs @@ -6,7 +6,7 @@ pub use wasmer_compiler::BaseTunables; #[cfg(test)] mod tests { use super::*; - use crate::sys::TableType; + use crate::TableType; use std::cell::UnsafeCell; use std::ptr::NonNull; use wasmer_compiler::Tunables; From fcad0fa5defdecc1a0f9e02920b6dbe5eb0a2bd6 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Sat, 11 Feb 2023 19:49:48 -0800 Subject: [PATCH 37/81] Make AsJs work with unified Instance --- lib/api/src/instance.rs | 4 ++-- lib/api/src/js/as_js.rs | 13 +++++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/lib/api/src/instance.rs b/lib/api/src/instance.rs index 14a8b5fb4dc..348633f60f8 100644 --- a/lib/api/src/instance.rs +++ b/lib/api/src/instance.rs @@ -21,8 +21,8 @@ use crate::sys::instance as instance_imp; /// Spec: #[derive(Clone)] pub struct Instance { - _inner: instance_imp::Instance, - module: Module, + pub(crate) _inner: instance_imp::Instance, + pub(crate) module: Module, /// The exports for an instance. pub exports: Exports, } diff --git a/lib/api/src/js/as_js.rs b/lib/api/src/js/as_js.rs index 15d417ea047..6560b1d33ca 100644 --- a/lib/api/src/js/as_js.rs +++ b/lib/api/src/js/as_js.rs @@ -2,7 +2,8 @@ // use crate::store::{Store, StoreObject}; // use crate::js::RuntimeError; use crate::imports::Imports; -use crate::js::instance::Instance; +use crate::instance::Instance; +use crate::js::instance::Instance as JsInstance; use crate::js::vm::{VMExtern, VMFunction, VMGlobal, VMMemory, VMTable}; use crate::js::wasm_bindgen_polyfill::Global as JsGlobal; use crate::store::{AsStoreMut, AsStoreRef}; @@ -288,7 +289,7 @@ impl AsJs for Extern { impl AsJs for Instance { type DefinitionType = crate::module::Module; fn as_jsvalue(&self, store: &impl AsStoreRef) -> wasm_bindgen::JsValue { - self._handle.clone().into() + self._inner._handle.clone().into() } fn from_jsvalue( @@ -297,8 +298,12 @@ impl AsJs for Instance { value: &JsValue, ) -> Result { let js_instance: js_sys::WebAssembly::Instance = value.clone().into(); - let (instance, _exports) = Self::from_module_and_instance(store, module, js_instance) + let (instance, exports) = JsInstance::from_module_and_instance(store, module, js_instance) .map_err(|e| JsError::new(&format!("Can't get the instance: {:?}", e)))?; - Ok(instance) + Ok(Instance { + _inner: instance, + module: module.clone(), + exports, + }) } } From 3b0ee715f7edabed7fa4206c63b19d3012eace82 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Mon, 13 Feb 2023 17:05:46 -0800 Subject: [PATCH 38/81] Created vm module --- lib/api/src/function_env.rs | 5 +---- lib/api/src/js/vm.rs | 5 +++++ lib/api/src/lib.rs | 1 + lib/api/src/sys/mod.rs | 16 +++++++++++----- lib/api/src/vm.rs | 22 ++++++++++++++++++++++ 5 files changed, 40 insertions(+), 9 deletions(-) create mode 100644 lib/api/src/vm.rs diff --git a/lib/api/src/function_env.rs b/lib/api/src/function_env.rs index c5f65a64068..beac6c520c2 100644 --- a/lib/api/src/function_env.rs +++ b/lib/api/src/function_env.rs @@ -1,9 +1,6 @@ use std::{any::Any, marker::PhantomData}; -#[cfg(feature = "js")] -use crate::js::vm::VMFunctionEnvironment; -#[cfg(feature = "sys")] -use wasmer_vm::VMFunctionEnvironment; +use crate::vm::VMFunctionEnvironment; use crate::store::{AsStoreMut, AsStoreRef, StoreHandle, StoreMut, StoreObjects, StoreRef}; diff --git a/lib/api/src/js/vm.rs b/lib/api/src/js/vm.rs index 460f66474b6..1960c71a19d 100644 --- a/lib/api/src/js/vm.rs +++ b/lib/api/src/js/vm.rs @@ -211,3 +211,8 @@ impl VMFunctionEnvironment { &mut *self.contents } } + +pub(crate) type VMExternTable = VMTable; +pub(crate) type VMExternMemory = VMMemory; +pub(crate) type VMExternGlobal = VMGlobal; +pub(crate) type VMExternFunction = VMFunction; diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index d6f9c152036..4e0207b445b 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -445,6 +445,7 @@ mod ptr; mod store; mod typed_function; mod value; +pub mod vm; #[cfg(feature = "sys")] mod sys; diff --git a/lib/api/src/sys/mod.rs b/lib/api/src/sys/mod.rs index dc6bf5cddcd..8a38f9f9456 100644 --- a/lib/api/src/sys/mod.rs +++ b/lib/api/src/sys/mod.rs @@ -16,13 +16,19 @@ pub use wasmer_compiler::{Features, FrameInfo, LinkError, RuntimeError, Tunables // TODO: should those be moved into wasmer::vm as well? pub use wasmer_vm::{raise_user_trap, MemoryError}; -pub mod vm { +pub(crate) mod vm { //! The `vm` module re-exports wasmer-vm types. - - pub use wasmer_vm::{ - MemoryError, MemoryStyle, TableStyle, VMExtern, VMMemory, VMMemoryDefinition, - VMOwnedMemory, VMSharedMemory, VMTable, VMTableDefinition, + use wasmer_vm::InternalStoreHandle; + pub(crate) use wasmer_vm::{ + MemoryError, MemoryStyle, TableStyle, VMExtern, VMFunction, VMFunctionEnvironment, + VMGlobal, VMMemory, VMMemoryDefinition, VMOwnedMemory, VMSharedMemory, VMTable, + VMTableDefinition, }; + + pub(crate) type VMExternTable = InternalStoreHandle; + pub(crate) type VMExternMemory = InternalStoreHandle; + pub(crate) type VMExternGlobal = InternalStoreHandle; + pub(crate) type VMExternFunction = InternalStoreHandle; } #[cfg(feature = "wat")] diff --git a/lib/api/src/vm.rs b/lib/api/src/vm.rs new file mode 100644 index 00000000000..40f59a50a60 --- /dev/null +++ b/lib/api/src/vm.rs @@ -0,0 +1,22 @@ +//! The `vm` module re-exports wasmer-vm types. + +#[cfg(feature = "js")] +pub(crate) use crate::js::vm::{ + VMExtern, VMExternFunction, VMExternGlobal, VMExternMemory, VMExternTable, VMFunction, + VMFunctionEnvironment, VMGlobal, VMMemory, VMTable, +}; + +#[cfg(feature = "sys")] +pub(crate) use crate::sys::vm::{ + VMExtern, VMExternFunction, VMExternGlobal, VMExternMemory, VMExternTable, + VMFunctionEnvironment, +}; + +// Needed for tunables customization +#[cfg(feature = "sys")] +pub use wasmer_vm::{ + VMFunction, VMGlobal, VMMemory, VMMemoryDefinition, VMTable, VMTableDefinition, +}; + +// Deprecated exports +pub use wasmer_types::{MemoryError, MemoryStyle, TableStyle}; From 1966af3703e3f5e51b318b765dfc3672b95e74d0 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Mon, 13 Feb 2023 17:06:15 -0800 Subject: [PATCH 39/81] Unified extern::Table in js/sys --- lib/api/src/externals/table.rs | 150 ++++++++++++++++++++++++++++- lib/api/src/js/as_js.rs | 2 +- lib/api/src/js/externals/table.rs | 67 +------------ lib/api/src/sys/externals/table.rs | 78 +-------------- 4 files changed, 157 insertions(+), 140 deletions(-) diff --git a/lib/api/src/externals/table.rs b/lib/api/src/externals/table.rs index 498eb6a1b6b..f21554fdd35 100644 --- a/lib/api/src/externals/table.rs +++ b/lib/api/src/externals/table.rs @@ -1,4 +1,150 @@ #[cfg(feature = "js")] -pub use crate::js::externals::table::Table; +use crate::js::externals::table as table_impl; #[cfg(feature = "sys")] -pub use crate::sys::externals::table::Table; +use crate::sys::externals::table as table_impl; + +use crate::exports::{ExportError, Exportable}; +use crate::store::{AsStoreMut, AsStoreRef}; +use crate::vm::{VMExtern, VMExternTable}; +use crate::Extern; +use crate::RuntimeError; +use crate::TableType; +use crate::Value; + +/// A WebAssembly `table` instance. +/// +/// The `Table` struct is an array-like structure representing a WebAssembly Table, +/// which stores function references. +/// +/// A table created by the host or in WebAssembly code will be accessible and +/// mutable from both host and WebAssembly. +/// +/// Spec: +#[derive(Debug, Clone)] +pub struct Table(pub(crate) table_impl::Table); + +impl Table { + /// Creates a new `Table` with the provided [`TableType`] definition. + /// + /// All the elements in the table will be set to the `init` value. + /// + /// This function will construct the `Table` using the store + /// [`BaseTunables`][crate::sys::BaseTunables]. + pub fn new( + store: &mut impl AsStoreMut, + ty: TableType, + init: Value, + ) -> Result { + Ok(Table(table_impl::Table::new(store, ty, init)?)) + } + + /// Returns the [`TableType`] of the `Table`. + pub fn ty(&self, store: &impl AsStoreRef) -> TableType { + self.0.ty(store) + } + + /// Retrieves an element of the table at the provided `index`. + pub fn get(&self, store: &mut impl AsStoreMut, index: u32) -> Option { + self.0.get(store, index) + } + + /// Sets an element `val` in the Table at the provided `index`. + pub fn set( + &self, + store: &mut impl AsStoreMut, + index: u32, + val: Value, + ) -> Result<(), RuntimeError> { + self.0.set(store, index, val) + } + + /// Retrieves the size of the `Table` (in elements) + pub fn size(&self, store: &impl AsStoreRef) -> u32 { + self.0.size(store) + } + + /// Grows the size of the `Table` by `delta`, initializating + /// the elements with the provided `init` value. + /// + /// It returns the previous size of the `Table` in case is able + /// to grow the Table successfully. + /// + /// # Errors + /// + /// Returns an error if the `delta` is out of bounds for the table. + pub fn grow( + &self, + store: &mut impl AsStoreMut, + delta: u32, + init: Value, + ) -> Result { + self.0.grow(store, delta, init) + } + + /// Copies the `len` elements of `src_table` starting at `src_index` + /// to the destination table `dst_table` at index `dst_index`. + /// + /// # Errors + /// + /// Returns an error if the range is out of bounds of either the source or + /// destination tables. + pub fn copy( + store: &mut impl AsStoreMut, + dst_table: &Self, + dst_index: u32, + src_table: &Self, + src_index: u32, + len: u32, + ) -> Result<(), RuntimeError> { + table_impl::Table::copy(store, &dst_table.0, dst_index, &src_table.0, src_index, len) + } + + pub(crate) fn from_vm_extern(store: &mut impl AsStoreMut, extern_: VMExternTable) -> Self { + Self(table_impl::Table::from_vm_extern(store, extern_)) + } + + /// Checks whether this `Table` can be used with the given context. + pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool { + self.0.is_from_store(store) + } + + pub(crate) fn to_vm_extern(&self) -> VMExtern { + self.0.to_vm_extern() + } +} + +impl std::cmp::PartialEq for Table { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } +} + +impl std::cmp::Eq for Table {} + +impl<'a> Exportable<'a> for Table { + fn get_self_from_extern(_extern: &'a Extern) -> Result<&'a Self, ExportError> { + match _extern { + Extern::Table(table) => Ok(table), + _ => Err(ExportError::IncompatibleType), + } + } +} + +/// Check the example from . +#[test] +fn test_table_grow_issue_3197() { + use crate::{imports, Instance, Module, Store, Table, TableType, Type, Value}; + + const WAT: &str = r#"(module (table (import "env" "table") 100 funcref))"#; + + // Tests that the table type of `table` is compatible with the export in the WAT + // This tests that `wasmer_types::types::is_table_compatible` works as expected. + let mut store = Store::default(); + let module = Module::new(&store, WAT).unwrap(); + let ty = TableType::new(Type::FuncRef, 0, None); + let table = Table::new(&mut store, ty, Value::FuncRef(None)).unwrap(); + table.grow(&mut store, 100, Value::FuncRef(None)).unwrap(); + assert_eq!(table.ty(&store).minimum, 0); + let imports = imports! {"env" => {"table" => table}}; + let _instance = Instance::new(&mut store, &module, &imports).unwrap(); +} diff --git a/lib/api/src/js/as_js.rs b/lib/api/src/js/as_js.rs index 6560b1d33ca..0b3aa7fc59e 100644 --- a/lib/api/src/js/as_js.rs +++ b/lib/api/src/js/as_js.rs @@ -208,7 +208,7 @@ impl AsJs for Extern { match self { Self::Memory(memory) => memory.handle.memory.clone().into(), Self::Function(function) => function.handle.function.clone().into(), - Self::Table(table) => table.handle.table.clone().into(), + Self::Table(table) => table.0.handle.table.clone().into(), Self::Global(global) => global.handle.global.clone().into(), } } diff --git a/lib/api/src/js/externals/table.rs b/lib/api/src/js/externals/table.rs index ab3357ee967..0562a42c128 100644 --- a/lib/api/src/js/externals/table.rs +++ b/lib/api/src/js/externals/table.rs @@ -1,21 +1,12 @@ -use crate::exports::{ExportError, Exportable}; use crate::js::vm::{VMExtern, VMFunction, VMTable}; use crate::js::RuntimeError; use crate::store::{AsStoreMut, AsStoreRef}; use crate::value::Value; +use crate::vm::VMExternTable; use crate::Extern; use crate::{FunctionType, TableType}; use js_sys::Function; -/// A WebAssembly `table` instance. -/// -/// The `Table` struct is an array-like structure representing a WebAssembly Table, -/// which stores function references. -/// -/// A table created by the host or in WebAssembly code will be accessible and -/// mutable from both host and WebAssembly. -/// -/// Spec: #[derive(Debug, Clone, PartialEq)] pub struct Table { pub(crate) handle: VMTable, @@ -37,12 +28,6 @@ fn get_function(store: &mut impl AsStoreMut, val: Value) -> Result VMExtern { VMExtern::Table(self.handle.clone()) } - /// Returns the [`TableType`] of the `Table`. pub fn ty(&self, _store: &impl AsStoreRef) -> TableType { self.handle.ty } - /// Retrieves an element of the table at the provided `index`. pub fn get(&self, store: &mut impl AsStoreMut, index: u32) -> Option { if let Some(func) = self.handle.table.get(index).ok() { let ty = FunctionType::new(vec![], vec![]); @@ -90,7 +72,6 @@ impl Table { } } - /// Sets an element `val` in the Table at the provided `index`. pub fn set( &self, store: &mut impl AsStoreMut, @@ -101,20 +82,10 @@ impl Table { set_table_item(&self.handle, index, &item) } - /// Retrieves the size of the `Table` (in elements) pub fn size(&self, _store: &impl AsStoreRef) -> u32 { self.handle.table.length() } - /// Grows the size of the `Table` by `delta`, initializating - /// the elements with the provided `init` value. - /// - /// It returns the previous size of the `Table` in case is able - /// to grow the Table successfully. - /// - /// # Errors - /// - /// Returns an error if the `delta` is out of bounds for the table. pub fn grow( &self, _store: &mut impl AsStoreMut, @@ -124,13 +95,6 @@ impl Table { unimplemented!(); } - /// Copies the `len` elements of `src_table` starting at `src_index` - /// to the destination table `dst_table` at index `dst_index`. - /// - /// # Errors - /// - /// Returns an error if the range is out of bounds of either the source or - /// destination tables. pub fn copy( _store: &mut impl AsStoreMut, _dst_table: &Self, @@ -142,36 +106,11 @@ impl Table { unimplemented!("Table.copy is not natively supported in Javascript"); } - pub(crate) fn from_vm_extern(_store: &mut impl AsStoreMut, internal: VMTable) -> Self { - Self { handle: internal } + pub(crate) fn from_vm_extern(_store: &mut impl AsStoreMut, vm_extern: VMExternTable) -> Self { + Self { handle: vm_extern } } - /// Checks whether this `Table` can be used with the given context. pub fn is_from_store(&self, _store: &impl AsStoreRef) -> bool { true } - - /// Get access to the backing VM value for this extern. This function is for - /// tests it should not be called by users of the Wasmer API. - /// - /// # Safety - /// This function is unsafe to call outside of tests for the wasmer crate - /// because there is no stability guarantee for the returned type and we may - /// make breaking changes to it at any time or remove this method. - #[doc(hidden)] - pub unsafe fn get_vm_table<'context>( - &'context self, - _store: &'context impl AsStoreRef, - ) -> &'context VMTable { - &self.handle - } -} - -impl<'a> Exportable<'a> for Table { - fn get_self_from_extern(_extern: &'a Extern) -> Result<&'a Self, ExportError> { - match _extern { - Extern::Table(table) => Ok(table), - _ => Err(ExportError::IncompatibleType), - } - } } diff --git a/lib/api/src/sys/externals/table.rs b/lib/api/src/sys/externals/table.rs index b64e955b02d..3067094c91b 100644 --- a/lib/api/src/sys/externals/table.rs +++ b/lib/api/src/sys/externals/table.rs @@ -1,20 +1,9 @@ -use crate::exports::{ExportError, Exportable}; use crate::store::{AsStoreMut, AsStoreRef}; -use crate::Extern; use crate::TableType; use crate::Value; -use crate::{sys::RuntimeError, ExternRef, Function}; -use wasmer_vm::{InternalStoreHandle, StoreHandle, TableElement, VMExtern, VMTable}; - -/// A WebAssembly `table` instance. -/// -/// The `Table` struct is an array-like structure representing a WebAssembly Table, -/// which stores function references. -/// -/// A table created by the host or in WebAssembly code will be accessible and -/// mutable from both host and WebAssembly. -/// -/// Spec: +use crate::{vm::VMExternTable, ExternRef, Function, RuntimeError}; +use wasmer_vm::{StoreHandle, TableElement, VMExtern, VMTable}; + #[derive(Debug, Clone)] pub struct Table { handle: StoreHandle, @@ -58,12 +47,6 @@ fn value_from_table_element(store: &mut impl AsStoreMut, item: wasmer_vm::TableE } impl Table { - /// Creates a new `Table` with the provided [`TableType`] definition. - /// - /// All the elements in the table will be set to the `init` value. - /// - /// This function will construct the `Table` using the store - /// [`BaseTunables`][crate::sys::BaseTunables]. pub fn new( mut store: &mut impl AsStoreMut, ty: TableType, @@ -87,18 +70,15 @@ impl Table { }) } - /// Returns the [`TableType`] of the `Table`. pub fn ty(&self, store: &impl AsStoreRef) -> TableType { *self.handle.get(store.as_store_ref().objects()).ty() } - /// Retrieves an element of the table at the provided `index`. pub fn get(&self, store: &mut impl AsStoreMut, index: u32) -> Option { let item = self.handle.get(store.as_store_ref().objects()).get(index)?; Some(value_from_table_element(store, item)) } - /// Sets an element `val` in the Table at the provided `index`. pub fn set( &self, store: &mut impl AsStoreMut, @@ -109,20 +89,10 @@ impl Table { set_table_item(self.handle.get_mut(store.objects_mut()), index, item) } - /// Retrieves the size of the `Table` (in elements) pub fn size(&self, store: &impl AsStoreRef) -> u32 { self.handle.get(store.as_store_ref().objects()).size() } - /// Grows the size of the `Table` by `delta`, initializating - /// the elements with the provided `init` value. - /// - /// It returns the previous size of the `Table` in case is able - /// to grow the Table successfully. - /// - /// # Errors - /// - /// Returns an error if the `delta` is out of bounds for the table. pub fn grow( &self, store: &mut impl AsStoreMut, @@ -136,13 +106,6 @@ impl Table { .ok_or_else(|| RuntimeError::new(format!("failed to grow table by `{}`", delta))) } - /// Copies the `len` elements of `src_table` starting at `src_index` - /// to the destination table `dst_table` at index `dst_index`. - /// - /// # Errors - /// - /// Returns an error if the range is out of bounds of either the source or - /// destination tables. pub fn copy( store: &mut impl AsStoreMut, dst_table: &Self, @@ -171,13 +134,10 @@ impl Table { Ok(()) } - pub(crate) fn from_vm_extern( - store: &mut impl AsStoreMut, - internal: InternalStoreHandle, - ) -> Self { + pub(crate) fn from_vm_extern(store: &mut impl AsStoreMut, vm_extern: VMExternTable) -> Self { Self { handle: unsafe { - StoreHandle::from_internal(store.as_store_ref().objects().id(), internal) + StoreHandle::from_internal(store.as_store_ref().objects().id(), vm_extern) }, } } @@ -199,31 +159,3 @@ impl std::cmp::PartialEq for Table { } impl std::cmp::Eq for Table {} - -impl<'a> Exportable<'a> for Table { - fn get_self_from_extern(_extern: &'a Extern) -> Result<&'a Self, ExportError> { - match _extern { - Extern::Table(table) => Ok(table), - _ => Err(ExportError::IncompatibleType), - } - } -} - -/// Check the example from . -#[test] -fn test_table_grow_issue_3197() { - use crate::{imports, Instance, Module, Store, Table, TableType, Type, Value}; - - const WAT: &str = r#"(module (table (import "env" "table") 100 funcref))"#; - - // Tests that the table type of `table` is compatible with the export in the WAT - // This tests that `wasmer_types::types::is_table_compatible` works as expected. - let mut store = Store::default(); - let module = Module::new(&store, WAT).unwrap(); - let ty = TableType::new(Type::FuncRef, 0, None); - let table = Table::new(&mut store, ty, Value::FuncRef(None)).unwrap(); - table.grow(&mut store, 100, Value::FuncRef(None)).unwrap(); - assert_eq!(table.ty(&store).minimum, 0); - let imports = imports! {"env" => {"table" => table}}; - let _instance = Instance::new(&mut store, &module, &imports).unwrap(); -} From 4c0bd5c9d8c497630c386fe3f07364ec2e18d543 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Tue, 14 Feb 2023 16:04:54 -0800 Subject: [PATCH 40/81] Unified Memory in js/sys --- lib/api/src/externals/memory.rs | 191 +++++++++++++++++++++++++- lib/api/src/js/as_js.rs | 2 +- lib/api/src/js/externals/memory.rs | 96 +------------ lib/api/src/js/vm.rs | 2 +- lib/api/src/sys/externals/function.rs | 12 +- lib/api/src/sys/externals/global.rs | 10 +- lib/api/src/sys/externals/memory.rs | 101 +------------- lib/api/src/sys/mod.rs | 4 +- lib/api/src/vm.rs | 9 +- 9 files changed, 219 insertions(+), 208 deletions(-) diff --git a/lib/api/src/externals/memory.rs b/lib/api/src/externals/memory.rs index b8c9ee92165..854220cba1d 100644 --- a/lib/api/src/externals/memory.rs +++ b/lib/api/src/externals/memory.rs @@ -1,4 +1,191 @@ #[cfg(feature = "js")] -pub use crate::js::externals::memory::Memory; +use crate::js::externals::memory as memory_impl; #[cfg(feature = "sys")] -pub use crate::sys::externals::memory::Memory; +use crate::sys::externals::memory as memory_impl; + +use super::memory_view::MemoryView; +use crate::exports::{ExportError, Exportable}; +use crate::store::{AsStoreMut, AsStoreRef}; +use crate::vm::{VMExtern, VMExternMemory, VMMemory}; +use crate::Extern; +use crate::MemoryAccessError; +use crate::MemoryType; +use std::mem::MaybeUninit; +use wasmer_types::{MemoryError, Pages}; + +/// A WebAssembly `memory` instance. +/// +/// A memory instance is the runtime representation of a linear memory. +/// It consists of a vector of bytes and an optional maximum size. +/// +/// The length of the vector always is a multiple of the WebAssembly +/// page size, which is defined to be the constant 65536 – abbreviated 64Ki. +/// Like in a memory type, the maximum size in a memory instance is +/// given in units of this page size. +/// +/// A memory created by the host or in WebAssembly code will be accessible and +/// mutable from both host and WebAssembly. +/// +/// Spec: +#[derive(Debug, Clone)] +pub struct Memory(pub(crate) memory_impl::Memory); + +impl Memory { + /// Creates a new host `Memory` from the provided [`MemoryType`]. + /// + /// This function will construct the `Memory` using the store + /// [`BaseTunables`][crate::sys::BaseTunables]. + /// + /// # Example + /// + /// ``` + /// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value}; + /// # let mut store = Store::default(); + /// # + /// let m = Memory::new(&mut store, MemoryType::new(1, None, false)).unwrap(); + /// ``` + pub fn new(store: &mut impl AsStoreMut, ty: MemoryType) -> Result { + Ok(Memory(memory_impl::Memory::new(store, ty)?)) + } + + /// Create a memory object from an existing memory and attaches it to the store + pub fn new_from_existing(new_store: &mut impl AsStoreMut, memory: VMMemory) -> Self { + Memory(memory_impl::Memory::new_from_existing(new_store, memory)) + } + + /// Returns the [`MemoryType`] of the `Memory`. + /// + /// # Example + /// + /// ``` + /// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value}; + /// # let mut store = Store::default(); + /// # + /// let mt = MemoryType::new(1, None, false); + /// let m = Memory::new(&mut store, mt).unwrap(); + /// + /// assert_eq!(m.ty(&mut store), mt); + /// ``` + pub fn ty(&self, store: &impl AsStoreRef) -> MemoryType { + self.0.ty(store) + } + + /// Creates a view into the memory that then allows for + /// read and write + pub fn view<'a>(&'a self, store: &impl AsStoreRef) -> MemoryView<'a> { + MemoryView::new(&self.0, store) + } + + /// Grow memory by the specified amount of WebAssembly [`Pages`] and return + /// the previous memory size. + /// + /// # Example + /// + /// ``` + /// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value, WASM_MAX_PAGES}; + /// # let mut store = Store::default(); + /// # + /// let m = Memory::new(&mut store, MemoryType::new(1, Some(3), false)).unwrap(); + /// let p = m.grow(&mut store, 2).unwrap(); + /// + /// assert_eq!(p, Pages(1)); + /// assert_eq!(m.view(&mut store).size(), Pages(3)); + /// ``` + /// + /// # Errors + /// + /// Returns an error if memory can't be grown by the specified amount + /// of pages. + /// + /// ```should_panic + /// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value, WASM_MAX_PAGES}; + /// # use wasmer::FunctionEnv; + /// # let mut store = Store::default(); + /// # let env = FunctionEnv::new(&mut store, ()); + /// # + /// let m = Memory::new(&mut store, MemoryType::new(1, Some(1), false)).unwrap(); + /// + /// // This results in an error: `MemoryError::CouldNotGrow`. + /// let s = m.grow(&mut store, 1).unwrap(); + /// ``` + pub fn grow( + &self, + store: &mut impl AsStoreMut, + delta: IntoPages, + ) -> Result + where + IntoPages: Into, + { + self.0.grow(store, delta) + } + + /// Copies the memory to a new store and returns a memory reference to it + pub fn copy_to_store( + &self, + store: &impl AsStoreRef, + new_store: &mut impl AsStoreMut, + ) -> Result { + Ok(Memory(self.0.copy_to_store(store, new_store)?)) + } + + pub(crate) fn from_vm_extern(store: &mut impl AsStoreMut, vm_extern: VMExternMemory) -> Self { + Memory(memory_impl::Memory::from_vm_extern(store, vm_extern)) + } + + /// Checks whether this `Memory` can be used with the given context. + pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool { + self.0.is_from_store(store) + } + + /// Attempts to clone this memory (if its clonable) + pub fn try_clone(&self, store: &impl AsStoreRef) -> Option { + self.0.try_clone(store) + } + + /// To `VMExtern`. + pub(crate) fn to_vm_extern(&self) -> VMExtern { + self.0.to_vm_extern() + } +} + +impl std::cmp::PartialEq for Memory { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } +} + +impl std::cmp::Eq for Memory {} + +impl<'a> Exportable<'a> for Memory { + fn get_self_from_extern(_extern: &'a Extern) -> Result<&'a Self, ExportError> { + match _extern { + Extern::Memory(memory) => Ok(memory), + _ => Err(ExportError::IncompatibleType), + } + } +} + +/// Underlying buffer for a memory. +#[derive(Debug, Copy, Clone)] +pub(crate) struct MemoryBuffer<'a>(pub(crate) memory_impl::MemoryBuffer<'a>); + +impl<'a> MemoryBuffer<'a> { + #[allow(unused)] + pub(crate) fn read(&self, offset: u64, buf: &mut [u8]) -> Result<(), MemoryAccessError> { + self.0.read(offset, buf) + } + + #[allow(unused)] + pub(crate) fn read_uninit<'b>( + &self, + offset: u64, + buf: &'b mut [MaybeUninit], + ) -> Result<&'b mut [u8], MemoryAccessError> { + self.0.read_uninit(offset, buf) + } + + #[allow(unused)] + pub(crate) fn write(&self, offset: u64, data: &[u8]) -> Result<(), MemoryAccessError> { + self.0.write(offset, data) + } +} diff --git a/lib/api/src/js/as_js.rs b/lib/api/src/js/as_js.rs index 0b3aa7fc59e..7f43aba509a 100644 --- a/lib/api/src/js/as_js.rs +++ b/lib/api/src/js/as_js.rs @@ -206,7 +206,7 @@ impl AsJs for Extern { fn as_jsvalue(&self, _store: &impl AsStoreRef) -> wasm_bindgen::JsValue { match self { - Self::Memory(memory) => memory.handle.memory.clone().into(), + Self::Memory(memory) => memory.0.handle.memory.clone().into(), Self::Function(function) => function.handle.function.clone().into(), Self::Table(table) => table.0.handle.table.clone().into(), Self::Global(global) => global.handle.global.clone().into(), diff --git a/lib/api/src/js/externals/memory.rs b/lib/api/src/js/externals/memory.rs index bed54b9a31c..a5526c2fc17 100644 --- a/lib/api/src/js/externals/memory.rs +++ b/lib/api/src/js/externals/memory.rs @@ -50,20 +50,6 @@ extern "C" { pub fn grow(this: &JSMemory, pages: u32) -> Result; } -/// A WebAssembly `memory` instance. -/// -/// A memory instance is the runtime representation of a linear memory. -/// It consists of a vector of bytes and an optional maximum size. -/// -/// The length of the vector always is a multiple of the WebAssembly -/// page size, which is defined to be the constant 65536 – abbreviated 64Ki. -/// Like in a memory type, the maximum size in a memory instance is -/// given in units of this page size. -/// -/// A memory created by the host or in WebAssembly code will be accessible and -/// mutable from both host and WebAssembly. -/// -/// Spec: #[derive(Debug, Clone)] pub struct Memory { pub(crate) handle: VMMemory, @@ -73,25 +59,14 @@ unsafe impl Send for Memory {} unsafe impl Sync for Memory {} impl Memory { - /// Creates a new host `Memory` from the provided [`MemoryType`]. - /// - /// This function will construct the `Memory` using the store - /// [`BaseTunables`][crate::js::tunables::BaseTunables]. - /// - /// # Example - /// - /// ``` - /// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value}; - /// # let mut store = Store::default(); - /// # - /// let m = Memory::new(&store, MemoryType::new(1, None, false)).unwrap(); - /// ``` pub fn new(store: &mut impl AsStoreMut, ty: MemoryType) -> Result { - let vm_memory = VMMemory::new(Self::new_internal(ty.clone())?, ty); + let vm_memory = VMMemory::new(Self::js_memory_from_type(&ty)?, ty); Ok(Self::from_vm_extern(store, vm_memory)) } - pub(crate) fn new_internal(ty: MemoryType) -> Result { + pub(crate) fn js_memory_from_type( + ty: &MemoryType, + ) -> Result { let descriptor = js_sys::Object::new(); // Annotation is here to prevent spurious IDE warnings. #[allow(unused_unsafe)] @@ -109,7 +84,6 @@ impl Memory { Ok(js_memory) } - /// Creates a new host `Memory` from provided JavaScript memory. pub fn new_raw( store: &mut impl AsStoreMut, js_memory: js_sys::WebAssembly::Memory, @@ -119,69 +93,22 @@ impl Memory { Ok(Self::from_vm_extern(store, vm_memory)) } - /// Create a memory object from an existing memory and attaches it to the store pub fn new_from_existing(new_store: &mut impl AsStoreMut, memory: VMMemory) -> Self { Self::from_vm_extern(new_store, memory) } - /// To `VMExtern`. pub(crate) fn to_vm_extern(&self) -> VMExtern { VMExtern::Memory(self.handle.clone()) } - /// Returns the [`MemoryType`] of the `Memory`. - /// - /// # Example - /// - /// ``` - /// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value}; - /// # let mut store = Store::default(); - /// # - /// let mt = MemoryType::new(1, None, false); - /// let m = Memory::new(&store, mt).unwrap(); - /// - /// assert_eq!(m.ty(), mt); - /// ``` pub fn ty(&self, _store: &impl AsStoreRef) -> MemoryType { self.handle.ty } - /// Creates a view into the memory that then allows for - /// read and write pub fn view(&self, store: &impl AsStoreRef) -> MemoryView { MemoryView::new(self, store) } - /// Grow memory by the specified amount of WebAssembly [`Pages`] and return - /// the previous memory size. - /// - /// # Example - /// - /// ``` - /// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value, WASM_MAX_PAGES}; - /// # let mut store = Store::default(); - /// # - /// let m = Memory::new(&store, MemoryType::new(1, Some(3), false)).unwrap(); - /// let p = m.grow(2).unwrap(); - /// - /// assert_eq!(p, Pages(1)); - /// assert_eq!(m.size(), Pages(3)); - /// ``` - /// - /// # Errors - /// - /// Returns an error if memory can't be grown by the specified amount - /// of pages. - /// - /// ```should_panic - /// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value, WASM_MAX_PAGES}; - /// # let mut store = Store::default(); - /// # - /// let m = Memory::new(&store, MemoryType::new(1, Some(1), false)).unwrap(); - /// - /// // This results in an error: `MemoryError::CouldNotGrow`. - /// let s = m.grow(1).unwrap(); - /// ``` pub fn grow( &self, store: &mut impl AsStoreMut, @@ -206,7 +133,6 @@ impl Memory { Ok(Pages(new_pages)) } - /// Copies the memory to a new store and returns a memory reference to it pub fn copy_to_store( &self, store: &impl AsStoreRef, @@ -239,17 +165,14 @@ impl Memory { Self { handle: internal } } - /// Attempts to clone this memory (if its clonable) pub fn try_clone(&self, _store: &impl AsStoreRef) -> Option { self.handle.try_clone() } - /// Checks whether this `Global` can be used with the given context. pub fn is_from_store(&self, _store: &impl AsStoreRef) -> bool { true } - /// Copies this memory to a new memory pub fn duplicate(&mut self, _store: &impl AsStoreRef) -> Result { self.handle.duplicate() } @@ -261,17 +184,8 @@ impl std::cmp::PartialEq for Memory { } } -impl<'a> Exportable<'a> for Memory { - fn get_self_from_extern(_extern: &'a Extern) -> Result<&'a Self, ExportError> { - match _extern { - Extern::Memory(memory) => Ok(memory), - _ => Err(ExportError::IncompatibleType), - } - } -} - /// Underlying buffer for a memory. -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub(crate) struct MemoryBuffer<'a> { pub(crate) base: *mut js_sys::Uint8Array, pub(crate) marker: PhantomData<(&'a Memory, &'a StoreObjects)>, diff --git a/lib/api/src/js/vm.rs b/lib/api/src/js/vm.rs index 1960c71a19d..f9a08684e9b 100644 --- a/lib/api/src/js/vm.rs +++ b/lib/api/src/js/vm.rs @@ -61,7 +61,7 @@ impl VMMemory { /// Copies this memory to a new memory pub fn duplicate(&self) -> Result { - let new_memory = crate::Memory::new_internal(self.ty.clone())?; + let new_memory = crate::js::externals::memory::Memory::js_memory_from_type(&self.ty)?; #[cfg(feature = "tracing")] trace!("memory copy started"); diff --git a/lib/api/src/sys/externals/function.rs b/lib/api/src/sys/externals/function.rs index a5d1ea1c44c..1e09256f23f 100644 --- a/lib/api/src/sys/externals/function.rs +++ b/lib/api/src/sys/externals/function.rs @@ -1,12 +1,13 @@ use wasmer_types::RawValue; pub use wasmer_vm::VMFuncRef; use wasmer_vm::{ - on_host_stack, raise_user_trap, resume_panic, InternalStoreHandle, StoreHandle, VMContext, - VMDynamicFunctionContext, VMExtern, VMFunction, VMFunctionBody, VMFunctionKind, VMTrampoline, + on_host_stack, raise_user_trap, resume_panic, StoreHandle, VMContext, VMDynamicFunctionContext, + VMExtern, VMFunction, VMFunctionBody, VMFunctionKind, VMTrampoline, }; use crate::exports::{ExportError, Exportable}; use crate::store::{AsStoreMut, AsStoreRef}; +use crate::vm::VMExternFunction; use crate::Extern; use crate::FunctionEnv; use crate::{FunctionType, RuntimeError, TypedFunction}; @@ -739,13 +740,10 @@ impl Function { Ok(TypedFunction::new(store, self.clone())) } - pub(crate) fn from_vm_extern( - store: &mut impl AsStoreMut, - internal: InternalStoreHandle, - ) -> Self { + pub(crate) fn from_vm_extern(store: &mut impl AsStoreMut, vm_extern: VMExternFunction) -> Self { Self { handle: unsafe { - StoreHandle::from_internal(store.as_store_ref().objects().id(), internal) + StoreHandle::from_internal(store.as_store_ref().objects().id(), vm_extern) }, } } diff --git a/lib/api/src/sys/externals/global.rs b/lib/api/src/sys/externals/global.rs index c16c7b2125c..ee5a64f9264 100644 --- a/lib/api/src/sys/externals/global.rs +++ b/lib/api/src/sys/externals/global.rs @@ -2,10 +2,11 @@ use crate::exports::{ExportError, Exportable}; use crate::store::{AsStoreMut, AsStoreRef}; use crate::sys::RuntimeError; use crate::value::Value; +use crate::vm::VMExternGlobal; use crate::Extern; use crate::GlobalType; use crate::Mutability; -use wasmer_vm::{InternalStoreHandle, StoreHandle, VMExtern, VMGlobal}; +use wasmer_vm::{StoreHandle, VMExtern, VMGlobal}; /// A WebAssembly `global` instance. /// @@ -183,13 +184,10 @@ impl Global { Ok(()) } - pub(crate) fn from_vm_extern( - store: &mut impl AsStoreMut, - internal: InternalStoreHandle, - ) -> Self { + pub(crate) fn from_vm_extern(store: &mut impl AsStoreMut, vm_extern: VMExternGlobal) -> Self { Self { handle: unsafe { - StoreHandle::from_internal(store.as_store_ref().objects().id(), internal) + StoreHandle::from_internal(store.as_store_ref().objects().id(), vm_extern) }, } } diff --git a/lib/api/src/sys/externals/memory.rs b/lib/api/src/sys/externals/memory.rs index c4619df4218..e48be91f76a 100644 --- a/lib/api/src/sys/externals/memory.rs +++ b/lib/api/src/sys/externals/memory.rs @@ -1,6 +1,6 @@ -use crate::exports::{ExportError, Exportable}; +use super::memory_view::MemoryView; use crate::store::{AsStoreMut, AsStoreRef}; -use crate::Extern; +use crate::vm::VMExternMemory; use crate::MemoryAccessError; use crate::MemoryType; use std::convert::TryInto; @@ -11,43 +11,14 @@ use std::slice; #[cfg(feature = "tracing")] use tracing::warn; use wasmer_types::Pages; -use wasmer_vm::{InternalStoreHandle, LinearMemory, MemoryError, StoreHandle, VMExtern, VMMemory}; - -use super::memory_view::MemoryView; +use wasmer_vm::{LinearMemory, MemoryError, StoreHandle, VMExtern, VMMemory}; -/// A WebAssembly `memory` instance. -/// -/// A memory instance is the runtime representation of a linear memory. -/// It consists of a vector of bytes and an optional maximum size. -/// -/// The length of the vector always is a multiple of the WebAssembly -/// page size, which is defined to be the constant 65536 – abbreviated 64Ki. -/// Like in a memory type, the maximum size in a memory instance is -/// given in units of this page size. -/// -/// A memory created by the host or in WebAssembly code will be accessible and -/// mutable from both host and WebAssembly. -/// -/// Spec: #[derive(Debug, Clone)] pub struct Memory { pub(crate) handle: StoreHandle, } impl Memory { - /// Creates a new host `Memory` from the provided [`MemoryType`]. - /// - /// This function will construct the `Memory` using the store - /// [`BaseTunables`][crate::sys::BaseTunables]. - /// - /// # Example - /// - /// ``` - /// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value}; - /// # let mut store = Store::default(); - /// # - /// let m = Memory::new(&mut store, MemoryType::new(1, None, false)).unwrap(); - /// ``` pub fn new(store: &mut impl AsStoreMut, ty: MemoryType) -> Result { let mut store = store.as_store_mut(); let tunables = store.engine().tunables(); @@ -59,67 +30,19 @@ impl Memory { }) } - /// Create a memory object from an existing memory and attaches it to the store pub fn new_from_existing(new_store: &mut impl AsStoreMut, memory: VMMemory) -> Self { let handle = StoreHandle::new(new_store.objects_mut(), memory); Self::from_vm_extern(new_store, handle.internal_handle()) } - /// Returns the [`MemoryType`] of the `Memory`. - /// - /// # Example - /// - /// ``` - /// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value}; - /// # let mut store = Store::default(); - /// # - /// let mt = MemoryType::new(1, None, false); - /// let m = Memory::new(&mut store, mt).unwrap(); - /// - /// assert_eq!(m.ty(&mut store), mt); - /// ``` pub fn ty(&self, store: &impl AsStoreRef) -> MemoryType { self.handle.get(store.as_store_ref().objects()).ty() } - /// Creates a view into the memory that then allows for - /// read and write pub fn view<'a>(&'a self, store: &impl AsStoreRef) -> MemoryView<'a> { MemoryView::new(self, store) } - /// Grow memory by the specified amount of WebAssembly [`Pages`] and return - /// the previous memory size. - /// - /// # Example - /// - /// ``` - /// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value, WASM_MAX_PAGES}; - /// # let mut store = Store::default(); - /// # - /// let m = Memory::new(&mut store, MemoryType::new(1, Some(3), false)).unwrap(); - /// let p = m.grow(&mut store, 2).unwrap(); - /// - /// assert_eq!(p, Pages(1)); - /// assert_eq!(m.view(&mut store).size(), Pages(3)); - /// ``` - /// - /// # Errors - /// - /// Returns an error if memory can't be grown by the specified amount - /// of pages. - /// - /// ```should_panic - /// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value, WASM_MAX_PAGES}; - /// # use wasmer::FunctionEnv; - /// # let mut store = Store::default(); - /// # let env = FunctionEnv::new(&mut store, ()); - /// # - /// let m = Memory::new(&mut store, MemoryType::new(1, Some(1), false)).unwrap(); - /// - /// // This results in an error: `MemoryError::CouldNotGrow`. - /// let s = m.grow(&mut store, 1).unwrap(); - /// ``` pub fn grow( &self, store: &mut impl AsStoreMut, @@ -131,7 +54,6 @@ impl Memory { self.handle.get_mut(store.objects_mut()).grow(delta.into()) } - /// Copies the memory to a new store and returns a memory reference to it pub fn copy_to_store( &self, store: &impl AsStoreRef, @@ -160,13 +82,10 @@ impl Memory { Ok(new_memory) } - pub(crate) fn from_vm_extern( - store: &impl AsStoreRef, - internal: InternalStoreHandle, - ) -> Self { + pub(crate) fn from_vm_extern(store: &impl AsStoreRef, vm_extern: VMExternMemory) -> Self { Self { handle: unsafe { - StoreHandle::from_internal(store.as_store_ref().objects().id(), internal) + StoreHandle::from_internal(store.as_store_ref().objects().id(), vm_extern) }, } } @@ -176,7 +95,6 @@ impl Memory { self.handle.store_id() == store.as_store_ref().objects().id() } - /// Attempts to clone this memory (if its clonable) pub fn try_clone(&self, store: &impl AsStoreRef) -> Option { let mem = self.handle.get(store.as_store_ref().objects()); mem.try_clone().map(|mem| mem.into()) @@ -196,15 +114,6 @@ impl std::cmp::PartialEq for Memory { impl std::cmp::Eq for Memory {} -impl<'a> Exportable<'a> for Memory { - fn get_self_from_extern(_extern: &'a Extern) -> Result<&'a Self, ExportError> { - match _extern { - Extern::Memory(memory) => Ok(memory), - _ => Err(ExportError::IncompatibleType), - } - } -} - /// Underlying buffer for a memory. #[derive(Debug, Copy, Clone)] pub(crate) struct MemoryBuffer<'a> { diff --git a/lib/api/src/sys/mod.rs b/lib/api/src/sys/mod.rs index 8a38f9f9456..66efa3d0200 100644 --- a/lib/api/src/sys/mod.rs +++ b/lib/api/src/sys/mod.rs @@ -20,9 +20,7 @@ pub(crate) mod vm { //! The `vm` module re-exports wasmer-vm types. use wasmer_vm::InternalStoreHandle; pub(crate) use wasmer_vm::{ - MemoryError, MemoryStyle, TableStyle, VMExtern, VMFunction, VMFunctionEnvironment, - VMGlobal, VMMemory, VMMemoryDefinition, VMOwnedMemory, VMSharedMemory, VMTable, - VMTableDefinition, + VMExtern, VMFunction, VMFunctionEnvironment, VMGlobal, VMMemory, VMTable, }; pub(crate) type VMExternTable = InternalStoreHandle; diff --git a/lib/api/src/vm.rs b/lib/api/src/vm.rs index 40f59a50a60..30784231418 100644 --- a/lib/api/src/vm.rs +++ b/lib/api/src/vm.rs @@ -15,7 +15,14 @@ pub(crate) use crate::sys::vm::{ // Needed for tunables customization #[cfg(feature = "sys")] pub use wasmer_vm::{ - VMFunction, VMGlobal, VMMemory, VMMemoryDefinition, VMTable, VMTableDefinition, + // An extra one for VMMemory implementors + LinearMemory, + VMFunction, + VMGlobal, + VMMemory, + VMMemoryDefinition, + VMTable, + VMTableDefinition, }; // Deprecated exports From 4c0399f6744c25c0af8f0e77f1f4b14df89ba5a2 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Tue, 14 Feb 2023 16:41:39 -0800 Subject: [PATCH 41/81] Unified global into js/sys --- lib/api/src/externals/global.rs | 179 +++++++++++++++++++++++++++- lib/api/src/js/externals/global.rs | 122 +------------------ lib/api/src/sys/externals/global.rs | 121 +------------------ 3 files changed, 179 insertions(+), 243 deletions(-) diff --git a/lib/api/src/externals/global.rs b/lib/api/src/externals/global.rs index 72fc12150a5..8970d772e77 100644 --- a/lib/api/src/externals/global.rs +++ b/lib/api/src/externals/global.rs @@ -1,4 +1,179 @@ +use crate::exports::{ExportError, Exportable}; +use crate::store::{AsStoreMut, AsStoreRef}; +use crate::sys::RuntimeError; +use crate::value::Value; +use crate::vm::VMExternGlobal; +use crate::Extern; +use crate::GlobalType; +use crate::Mutability; +use wasmer_vm::{StoreHandle, VMExtern, VMGlobal}; + #[cfg(feature = "js")] -pub use crate::js::externals::global::Global; +use crate::js::externals::global as global_impl; #[cfg(feature = "sys")] -pub use crate::sys::externals::global::Global; +use crate::sys::externals::global as global_impl; + +/// A WebAssembly `global` instance. +/// +/// A global instance is the runtime representation of a global variable. +/// It consists of an individual value and a flag indicating whether it is mutable. +/// +/// Spec: +#[derive(Debug, Clone)] +pub struct Global(pub(crate) global_impl::Global); + +impl Global { + /// Create a new `Global` with the initial value [`Value`]. + /// + /// # Example + /// + /// ``` + /// # use wasmer::{Global, Mutability, Store, Value}; + /// # let mut store = Store::default(); + /// # + /// let g = Global::new(&mut store, Value::I32(1)); + /// + /// assert_eq!(g.get(&mut store), Value::I32(1)); + /// assert_eq!(g.ty(&mut store).mutability, Mutability::Const); + /// ``` + pub fn new(store: &mut impl AsStoreMut, val: Value) -> Self { + Self::from_value(store, val, Mutability::Const).unwrap() + } + + /// Create a mutable `Global` with the initial value [`Value`]. + /// + /// # Example + /// + /// ``` + /// # use wasmer::{Global, Mutability, Store, Value}; + /// # let mut store = Store::default(); + /// # + /// let g = Global::new_mut(&mut store, Value::I32(1)); + /// + /// assert_eq!(g.get(&mut store), Value::I32(1)); + /// assert_eq!(g.ty(&mut store).mutability, Mutability::Var); + /// ``` + pub fn new_mut(store: &mut impl AsStoreMut, val: Value) -> Self { + Self::from_value(store, val, Mutability::Var).unwrap() + } + + /// Create a `Global` with the initial value [`Value`] and the provided [`Mutability`]. + fn from_value( + store: &mut impl AsStoreMut, + val: Value, + mutability: Mutability, + ) -> Result { + Ok(Global(global_impl::Global::from_value( + store, val, mutability, + )?)) + } + + /// Returns the [`GlobalType`] of the `Global`. + /// + /// # Example + /// + /// ``` + /// # use wasmer::{Global, Mutability, Store, Type, Value, GlobalType}; + /// # let mut store = Store::default(); + /// # + /// let c = Global::new(&mut store, Value::I32(1)); + /// let v = Global::new_mut(&mut store, Value::I64(1)); + /// + /// assert_eq!(c.ty(&mut store), GlobalType::new(Type::I32, Mutability::Const)); + /// assert_eq!(v.ty(&mut store), GlobalType::new(Type::I64, Mutability::Var)); + /// ``` + pub fn ty(&self, store: &impl AsStoreRef) -> GlobalType { + self.0.ty(store) + } + + /// Retrieves the current value [`Value`] that the Global has. + /// + /// # Example + /// + /// ``` + /// # use wasmer::{Global, Store, Value}; + /// # let mut store = Store::default(); + /// # + /// let g = Global::new(&mut store, Value::I32(1)); + /// + /// assert_eq!(g.get(&mut store), Value::I32(1)); + /// ``` + pub fn get(&self, store: &mut impl AsStoreMut) -> Value { + self.0.get(store) + } + + /// Sets a custom value [`Value`] to the runtime Global. + /// + /// # Example + /// + /// ``` + /// # use wasmer::{Global, Store, Value}; + /// # let mut store = Store::default(); + /// # + /// let g = Global::new_mut(&mut store, Value::I32(1)); + /// + /// assert_eq!(g.get(&mut store), Value::I32(1)); + /// + /// g.set(&mut store, Value::I32(2)); + /// + /// assert_eq!(g.get(&mut store), Value::I32(2)); + /// ``` + /// + /// # Errors + /// + /// Trying to mutate a immutable global will raise an error: + /// + /// ```should_panic + /// # use wasmer::{Global, Store, Value}; + /// # let mut store = Store::default(); + /// # + /// let g = Global::new(&mut store, Value::I32(1)); + /// + /// g.set(&mut store, Value::I32(2)).unwrap(); + /// ``` + /// + /// Trying to set a value of a incompatible type will raise an error: + /// + /// ```should_panic + /// # use wasmer::{Global, Store, Value}; + /// # let mut store = Store::default(); + /// # + /// let g = Global::new(&mut store, Value::I32(1)); + /// + /// // This results in an error: `RuntimeError`. + /// g.set(&mut store, Value::I64(2)).unwrap(); + /// ``` + pub fn set(&self, store: &mut impl AsStoreMut, val: Value) -> Result<(), RuntimeError> { + self.0.set(store, val) + } + + pub(crate) fn from_vm_extern(store: &mut impl AsStoreMut, vm_extern: VMExternGlobal) -> Self { + Global(global_impl::Global::from_vm_extern(store, vm_extern)) + } + + /// Checks whether this `Global` can be used with the given context. + pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool { + self.0.is_from_store(store) + } + + pub(crate) fn to_vm_extern(&self) -> VMExtern { + self.0.to_vm_extern() + } +} + +impl std::cmp::PartialEq for Global { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } +} + +impl std::cmp::Eq for Global {} + +impl<'a> Exportable<'a> for Global { + fn get_self_from_extern(_extern: &'a Extern) -> Result<&'a Self, ExportError> { + match _extern { + Extern::Global(global) => Ok(global), + _ => Err(ExportError::IncompatibleType), + } + } +} diff --git a/lib/api/src/js/externals/global.rs b/lib/api/src/js/externals/global.rs index e926447dd14..c59315b63f1 100644 --- a/lib/api/src/js/externals/global.rs +++ b/lib/api/src/js/externals/global.rs @@ -1,68 +1,25 @@ -use crate::exports::{ExportError, Exportable}; use crate::js::vm::{VMExtern, VMGlobal}; use crate::js::wasm_bindgen_polyfill::Global as JSGlobal; use crate::js::RuntimeError; use crate::store::{AsStoreMut, AsStoreRef}; use crate::value::Value; -use crate::Extern; use crate::GlobalType; use crate::Mutability; use wasm_bindgen::JsValue; use wasmer_types::{RawValue, Type}; -/// A WebAssembly `global` instance. -/// -/// A global instance is the runtime representation of a global variable. -/// It consists of an individual value and a flag indicating whether it is mutable. -/// -/// Spec: #[derive(Debug, Clone, PartialEq)] pub struct Global { pub(crate) handle: VMGlobal, } impl Global { - /// Create a new `Global` with the initial value [`Value`]. - /// - /// # Example - /// - /// ``` - /// # use wasmer::{Global, Mutability, Store, Value}; - /// # let mut store = Store::default(); - /// # - /// let g = Global::new(&store, Value::I32(1)); - /// - /// assert_eq!(g.get(), Value::I32(1)); - /// assert_eq!(g.ty().mutability, Mutability::Const); - /// ``` - pub fn new(store: &mut impl AsStoreMut, val: Value) -> Self { - Self::from_value(store, val, Mutability::Const).unwrap() - } - - /// Create a mutable `Global` with the initial value [`Value`]. - /// - /// # Example - /// - /// ``` - /// # use wasmer::{Global, Mutability, Store, Value}; - /// # let mut store = Store::default(); - /// # - /// let g = Global::new_mut(&store, Value::I32(1)); - /// - /// assert_eq!(g.get(), Value::I32(1)); - /// assert_eq!(g.ty().mutability, Mutability::Var); - /// ``` - pub fn new_mut(store: &mut impl AsStoreMut, val: Value) -> Self { - Self::from_value(store, val, Mutability::Var).unwrap() - } - - /// To `VMExtern`. pub(crate) fn to_vm_extern(&self) -> VMExtern { VMExtern::Global(self.handle.clone()) } /// Create a `Global` with the initial value [`Value`] and the provided [`Mutability`]. - fn from_value( + pub(crate) fn from_value( store: &mut impl AsStoreMut, val: Value, mutability: Mutability, @@ -99,36 +56,10 @@ impl Global { Ok(Self::from_vm_extern(store, vm_global)) } - /// Returns the [`GlobalType`] of the `Global`. - /// - /// # Example - /// - /// ``` - /// # use wasmer::{Global, Mutability, Store, Type, Value, GlobalType}; - /// # let mut store = Store::default(); - /// # - /// let c = Global::new(&store, Value::I32(1)); - /// let v = Global::new_mut(&store, Value::I64(1)); - /// - /// assert_eq!(c.ty(), &GlobalType::new(Type::I32, Mutability::Const)); - /// assert_eq!(v.ty(), &GlobalType::new(Type::I64, Mutability::Var)); - /// ``` pub fn ty(&self, _store: &impl AsStoreRef) -> GlobalType { self.handle.ty } - /// Retrieves the current value [`Value`] that the Global has. - /// - /// # Example - /// - /// ``` - /// # use wasmer::{Global, Store, Value}; - /// # let mut store = Store::default(); - /// # - /// let g = Global::new(&store, Value::I32(1)); - /// - /// assert_eq!(g.get(), Value::I32(1)); - /// ``` pub fn get(&self, store: &mut impl AsStoreMut) -> Value { unsafe { let value = self.handle.global.value(); @@ -164,47 +95,6 @@ impl Global { } } - /// Sets a custom value [`Value`] to the runtime Global. - /// - /// # Example - /// - /// ``` - /// # use wasmer::{Global, Store, Value}; - /// # let mut store = Store::default(); - /// # - /// let g = Global::new_mut(&store, Value::I32(1)); - /// - /// assert_eq!(g.get(), Value::I32(1)); - /// - /// g.set(Value::I32(2)); - /// - /// assert_eq!(g.get(), Value::I32(2)); - /// ``` - /// - /// # Errors - /// - /// Trying to mutate a immutable global will raise an error: - /// - /// ```should_panic - /// # use wasmer::{Global, Store, Value}; - /// # let mut store = Store::default(); - /// # - /// let g = Global::new(&store, Value::I32(1)); - /// - /// g.set(Value::I32(2)).unwrap(); - /// ``` - /// - /// Trying to set a value of a incompatible type will raise an error: - /// - /// ```should_panic - /// # use wasmer::{Global, Store, Value}; - /// # let mut store = Store::default(); - /// # - /// let g = Global::new(&store, Value::I32(1)); - /// - /// // This results in an error: `RuntimeError`. - /// g.set(Value::I64(2)).unwrap(); - /// ``` pub fn set(&self, store: &mut impl AsStoreMut, val: Value) -> Result<(), RuntimeError> { if !val.is_from_store(store) { return Err(RuntimeError::new( @@ -239,17 +129,7 @@ impl Global { Self { handle: vm_global } } - /// Checks whether this `Global` can be used with the given store. pub fn is_from_store(&self, _store: &impl AsStoreRef) -> bool { true } } - -impl<'a> Exportable<'a> for Global { - fn get_self_from_extern(_extern: &'a Extern) -> Result<&'a Self, ExportError> { - match _extern { - Extern::Global(global) => Ok(global), - _ => Err(ExportError::IncompatibleType), - } - } -} diff --git a/lib/api/src/sys/externals/global.rs b/lib/api/src/sys/externals/global.rs index ee5a64f9264..c45800faa40 100644 --- a/lib/api/src/sys/externals/global.rs +++ b/lib/api/src/sys/externals/global.rs @@ -1,61 +1,19 @@ -use crate::exports::{ExportError, Exportable}; use crate::store::{AsStoreMut, AsStoreRef}; use crate::sys::RuntimeError; use crate::value::Value; use crate::vm::VMExternGlobal; -use crate::Extern; use crate::GlobalType; use crate::Mutability; use wasmer_vm::{StoreHandle, VMExtern, VMGlobal}; -/// A WebAssembly `global` instance. -/// -/// A global instance is the runtime representation of a global variable. -/// It consists of an individual value and a flag indicating whether it is mutable. -/// -/// Spec: #[derive(Debug, Clone)] pub struct Global { handle: StoreHandle, } impl Global { - /// Create a new `Global` with the initial value [`Value`]. - /// - /// # Example - /// - /// ``` - /// # use wasmer::{Global, Mutability, Store, Value}; - /// # let mut store = Store::default(); - /// # - /// let g = Global::new(&mut store, Value::I32(1)); - /// - /// assert_eq!(g.get(&mut store), Value::I32(1)); - /// assert_eq!(g.ty(&mut store).mutability, Mutability::Const); - /// ``` - pub fn new(store: &mut impl AsStoreMut, val: Value) -> Self { - Self::from_value(store, val, Mutability::Const).unwrap() - } - - /// Create a mutable `Global` with the initial value [`Value`]. - /// - /// # Example - /// - /// ``` - /// # use wasmer::{Global, Mutability, Store, Value}; - /// # let mut store = Store::default(); - /// # - /// let g = Global::new_mut(&mut store, Value::I32(1)); - /// - /// assert_eq!(g.get(&mut store), Value::I32(1)); - /// assert_eq!(g.ty(&mut store).mutability, Mutability::Var); - /// ``` - pub fn new_mut(store: &mut impl AsStoreMut, val: Value) -> Self { - Self::from_value(store, val, Mutability::Var).unwrap() - } - /// Create a `Global` with the initial value [`Value`] and the provided [`Mutability`]. - fn from_value( + pub(crate) fn from_value( store: &mut impl AsStoreMut, val: Value, mutability: Mutability, @@ -76,36 +34,10 @@ impl Global { }) } - /// Returns the [`GlobalType`] of the `Global`. - /// - /// # Example - /// - /// ``` - /// # use wasmer::{Global, Mutability, Store, Type, Value, GlobalType}; - /// # let mut store = Store::default(); - /// # - /// let c = Global::new(&mut store, Value::I32(1)); - /// let v = Global::new_mut(&mut store, Value::I64(1)); - /// - /// assert_eq!(c.ty(&mut store), GlobalType::new(Type::I32, Mutability::Const)); - /// assert_eq!(v.ty(&mut store), GlobalType::new(Type::I64, Mutability::Var)); - /// ``` pub fn ty(&self, store: &impl AsStoreRef) -> GlobalType { *self.handle.get(store.as_store_ref().objects()).ty() } - /// Retrieves the current value [`Value`] that the Global has. - /// - /// # Example - /// - /// ``` - /// # use wasmer::{Global, Store, Value}; - /// # let mut store = Store::default(); - /// # - /// let g = Global::new(&mut store, Value::I32(1)); - /// - /// assert_eq!(g.get(&mut store), Value::I32(1)); - /// ``` pub fn get(&self, store: &mut impl AsStoreMut) -> Value { unsafe { let raw = self @@ -119,47 +51,6 @@ impl Global { } } - /// Sets a custom value [`Value`] to the runtime Global. - /// - /// # Example - /// - /// ``` - /// # use wasmer::{Global, Store, Value}; - /// # let mut store = Store::default(); - /// # - /// let g = Global::new_mut(&mut store, Value::I32(1)); - /// - /// assert_eq!(g.get(&mut store), Value::I32(1)); - /// - /// g.set(&mut store, Value::I32(2)); - /// - /// assert_eq!(g.get(&mut store), Value::I32(2)); - /// ``` - /// - /// # Errors - /// - /// Trying to mutate a immutable global will raise an error: - /// - /// ```should_panic - /// # use wasmer::{Global, Store, Value}; - /// # let mut store = Store::default(); - /// # - /// let g = Global::new(&mut store, Value::I32(1)); - /// - /// g.set(&mut store, Value::I32(2)).unwrap(); - /// ``` - /// - /// Trying to set a value of a incompatible type will raise an error: - /// - /// ```should_panic - /// # use wasmer::{Global, Store, Value}; - /// # let mut store = Store::default(); - /// # - /// let g = Global::new(&mut store, Value::I32(1)); - /// - /// // This results in an error: `RuntimeError`. - /// g.set(&mut store, Value::I64(2)).unwrap(); - /// ``` pub fn set(&self, store: &mut impl AsStoreMut, val: Value) -> Result<(), RuntimeError> { if !val.is_from_store(store) { return Err(RuntimeError::new("cross-`Store` values are not supported")); @@ -192,7 +83,6 @@ impl Global { } } - /// Checks whether this `Global` can be used with the given context. pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool { self.handle.store_id() == store.as_store_ref().objects().id() } @@ -209,12 +99,3 @@ impl std::cmp::PartialEq for Global { } impl std::cmp::Eq for Global {} - -impl<'a> Exportable<'a> for Global { - fn get_self_from_extern(_extern: &'a Extern) -> Result<&'a Self, ExportError> { - match _extern { - Extern::Global(global) => Ok(global), - _ => Err(ExportError::IncompatibleType), - } - } -} From 7bf1bd1dc1a3598a4571e6de26772e2c573fda9e Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Tue, 14 Feb 2023 17:08:05 -0800 Subject: [PATCH 42/81] Fixed as_js for global --- lib/api/src/js/as_js.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/api/src/js/as_js.rs b/lib/api/src/js/as_js.rs index 7f43aba509a..b18bfade310 100644 --- a/lib/api/src/js/as_js.rs +++ b/lib/api/src/js/as_js.rs @@ -209,7 +209,7 @@ impl AsJs for Extern { Self::Memory(memory) => memory.0.handle.memory.clone().into(), Self::Function(function) => function.handle.function.clone().into(), Self::Table(table) => table.0.handle.table.clone().into(), - Self::Global(global) => global.handle.global.clone().into(), + Self::Global(global) => global.0.handle.global.clone().into(), } } From 3e7552abc327811c7c43a8d8045903c205b26147 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Tue, 14 Feb 2023 17:58:42 -0800 Subject: [PATCH 43/81] Fix global --- lib/api/src/externals/global.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/api/src/externals/global.rs b/lib/api/src/externals/global.rs index 8970d772e77..47e66688dcc 100644 --- a/lib/api/src/externals/global.rs +++ b/lib/api/src/externals/global.rs @@ -1,12 +1,12 @@ use crate::exports::{ExportError, Exportable}; use crate::store::{AsStoreMut, AsStoreRef}; -use crate::sys::RuntimeError; +use crate::RuntimeError; use crate::value::Value; use crate::vm::VMExternGlobal; use crate::Extern; use crate::GlobalType; use crate::Mutability; -use wasmer_vm::{StoreHandle, VMExtern, VMGlobal}; +use crate::vm::VMExtern; #[cfg(feature = "js")] use crate::js::externals::global as global_impl; From e9b8868b63f03da39934e3e88bd6fb8687e3ecca Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Tue, 14 Feb 2023 18:07:05 -0800 Subject: [PATCH 44/81] Moved ExternRef and FuncRef into crate::vm for unification --- lib/api/src/extern_ref.rs | 5 ++-- lib/api/src/externals/global.rs | 4 +-- lib/api/src/js/extern_ref.rs | 18 +------------ lib/api/src/js/externals/function.rs | 33 ++++------------------- lib/api/src/js/vm.rs | 40 ++++++++++++++++++++++++++++ lib/api/src/native_type.rs | 7 +---- lib/api/src/sys/extern_ref.rs | 3 +-- lib/api/src/sys/mod.rs | 3 ++- lib/api/src/value.rs | 7 +---- lib/api/src/vm.rs | 8 +++--- 10 files changed, 60 insertions(+), 68 deletions(-) diff --git a/lib/api/src/extern_ref.rs b/lib/api/src/extern_ref.rs index db251a578d1..e118b210b28 100644 --- a/lib/api/src/extern_ref.rs +++ b/lib/api/src/extern_ref.rs @@ -6,6 +6,7 @@ use crate::store::{AsStoreMut, AsStoreRef}; use crate::js::extern_ref as extern_ref_imp; #[cfg(feature = "sys")] use crate::sys::extern_ref as extern_ref_imp; +use crate::vm::VMExternRef; #[derive(Debug, Clone)] #[repr(transparent)] @@ -29,13 +30,13 @@ impl ExternRef { self.0.downcast(store) } - pub(crate) fn vm_externref(&self) -> extern_ref_imp::VMExternRef { + pub(crate) fn vm_externref(&self) -> VMExternRef { self.0.vm_externref() } pub(crate) unsafe fn from_vm_externref( store: &mut impl AsStoreMut, - vm_externref: extern_ref_imp::VMExternRef, + vm_externref: VMExternRef, ) -> Self { ExternRef(extern_ref_imp::ExternRef::from_vm_externref( store, diff --git a/lib/api/src/externals/global.rs b/lib/api/src/externals/global.rs index 47e66688dcc..0fedb2bf03b 100644 --- a/lib/api/src/externals/global.rs +++ b/lib/api/src/externals/global.rs @@ -1,12 +1,12 @@ use crate::exports::{ExportError, Exportable}; use crate::store::{AsStoreMut, AsStoreRef}; -use crate::RuntimeError; use crate::value::Value; +use crate::vm::VMExtern; use crate::vm::VMExternGlobal; use crate::Extern; use crate::GlobalType; use crate::Mutability; -use crate::vm::VMExtern; +use crate::RuntimeError; #[cfg(feature = "js")] use crate::js::externals::global as global_impl; diff --git a/lib/api/src/js/extern_ref.rs b/lib/api/src/js/extern_ref.rs index fb8e1cb46db..7fad48ea9f2 100644 --- a/lib/api/src/js/extern_ref.rs +++ b/lib/api/src/js/extern_ref.rs @@ -1,25 +1,9 @@ use std::any::Any; +use crate::js::vm::VMExternRef; use crate::store::{AsStoreMut, AsStoreRef}; use wasmer_types::RawValue; -pub(crate) struct VMExternRef; - -impl VMExternRef { - /// Converts the `VMExternRef` into a `RawValue`. - pub fn into_raw(self) -> RawValue { - unimplemented!(); - } - - /// Extracts a `VMExternRef` from a `RawValue`. - /// - /// # Safety - /// `raw` must be a valid `VMExternRef` instance. - pub unsafe fn from_raw(raw: RawValue) -> Option { - unimplemented!(); - } -} - #[derive(Debug, Clone)] #[repr(transparent)] pub struct ExternRef; diff --git a/lib/api/src/js/externals/function.rs b/lib/api/src/js/externals/function.rs index 02ab10e78bf..60af891a184 100644 --- a/lib/api/src/js/externals/function.rs +++ b/lib/api/src/js/externals/function.rs @@ -13,33 +13,10 @@ use js_sys::{Array, Function as JSFunction}; use std::iter::FromIterator; use wasm_bindgen::prelude::*; use wasm_bindgen::JsCast; -use wasmer_types::RawValue; -use crate::js::vm::VMFunction; +use crate::js::vm::{VMFuncRef, VMFunction, VMFunctionBody}; use std::fmt; -#[repr(C)] -pub struct VMFunctionBody(u8); - -#[repr(transparent)] -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub(crate) struct VMFuncRef; - -impl VMFuncRef { - /// Converts the `VMFuncRef` into a `RawValue`. - pub fn into_raw(self) -> RawValue { - unimplemented!() - } - - /// Extracts a `VMFuncRef` from a `RawValue`. - /// - /// # Safety - /// `raw.funcref` must be a valid pointer. - pub unsafe fn from_raw(raw: RawValue) -> Option { - unimplemented!(); - } -} - #[inline] fn result_to_js(val: &Value) -> JsValue { match val { @@ -860,7 +837,7 @@ mod inner { /// Writes the contents of a C struct to an array of `f64`. /// /// # Safety - unsafe fn write_c_struct_to_ptr(c_struct: Self::CStruct, ptr: *mut f64); + unsafe fn write_c_struct_to_ptr(c_struct: Self::CStruct, ptr: *mut RawValue); /// Get the Wasm types for the tuple (list) of currently /// represented values. @@ -1122,7 +1099,7 @@ mod inner { ( $( - FromToNativeWasmType::from_native(NativeWasmTypeInto::from_abi(_store, $x.into())) + FromToNativeWasmType::from_native(NativeWasmTypeInto::from_abi(_store, $x)) ),* ) } @@ -1142,7 +1119,7 @@ mod inner { } #[allow(non_snake_case)] - unsafe fn write_c_struct_to_ptr(c_struct: Self::CStruct, _ptr: *mut f64) { + unsafe fn write_c_struct_to_ptr(c_struct: Self::CStruct, _ptr: *mut RawValue) { // Unpack items of the tuple. let $c_struct_name( $( $x ),* ) = c_struct; @@ -1349,7 +1326,7 @@ mod inner { self } - unsafe fn write_c_struct_to_ptr(_: Self::CStruct, _: *mut f64) {} + unsafe fn write_c_struct_to_ptr(_: Self::CStruct, _: *mut RawValue) {} fn wasm_types() -> &'static [Type] { &[] diff --git a/lib/api/src/js/vm.rs b/lib/api/src/js/vm.rs index f9a08684e9b..d27e1728471 100644 --- a/lib/api/src/js/vm.rs +++ b/lib/api/src/js/vm.rs @@ -16,6 +16,7 @@ use std::fmt; #[cfg(feature = "tracing")] use tracing::trace; use wasm_bindgen::{JsCast, JsValue}; +use wasmer_types::RawValue; use wasmer_types::{ ExternType, FunctionType, GlobalType, MemoryError, MemoryType, Pages, TableType, WASM_PAGE_SIZE, }; @@ -212,6 +213,45 @@ impl VMFunctionEnvironment { } } +pub(crate) struct VMExternRef; + +impl VMExternRef { + /// Converts the `VMExternRef` into a `RawValue`. + pub fn into_raw(self) -> RawValue { + unimplemented!(); + } + + /// Extracts a `VMExternRef` from a `RawValue`. + /// + /// # Safety + /// `raw` must be a valid `VMExternRef` instance. + pub unsafe fn from_raw(raw: RawValue) -> Option { + unimplemented!(); + } +} + +#[repr(C)] +pub struct VMFunctionBody(u8); + +#[repr(transparent)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub(crate) struct VMFuncRef; + +impl VMFuncRef { + /// Converts the `VMFuncRef` into a `RawValue`. + pub fn into_raw(self) -> RawValue { + unimplemented!() + } + + /// Extracts a `VMFuncRef` from a `RawValue`. + /// + /// # Safety + /// `raw.funcref` must be a valid pointer. + pub unsafe fn from_raw(raw: RawValue) -> Option { + unimplemented!(); + } +} + pub(crate) type VMExternTable = VMTable; pub(crate) type VMExternMemory = VMMemory; pub(crate) type VMExternGlobal = VMGlobal; diff --git a/lib/api/src/native_type.rs b/lib/api/src/native_type.rs index 3b13084ff62..2350f103861 100644 --- a/lib/api/src/native_type.rs +++ b/lib/api/src/native_type.rs @@ -3,12 +3,7 @@ use wasmer_types::{NativeWasmType, RawValue, Type}; -#[cfg(feature = "js")] -use crate::js::extern_ref::VMExternRef; -#[cfg(feature = "js")] -use crate::js::externals::function::VMFuncRef; -#[cfg(feature = "sys")] -use wasmer_vm::{VMExternRef, VMFuncRef}; +use crate::vm::{VMExternRef, VMFuncRef}; use crate::{ExternRef, Function, TypedFunction, WasmTypeList}; diff --git a/lib/api/src/sys/extern_ref.rs b/lib/api/src/sys/extern_ref.rs index 53b86d9b7c7..2f50751b6bb 100644 --- a/lib/api/src/sys/extern_ref.rs +++ b/lib/api/src/sys/extern_ref.rs @@ -1,6 +1,5 @@ use std::any::Any; - -pub use wasmer_vm::VMExternRef; +use wasmer_vm::VMExternRef; use wasmer_vm::{StoreHandle, VMExternObj}; use crate::store::{AsStoreMut, AsStoreRef}; diff --git a/lib/api/src/sys/mod.rs b/lib/api/src/sys/mod.rs index 66efa3d0200..0c7fb8cfb4f 100644 --- a/lib/api/src/sys/mod.rs +++ b/lib/api/src/sys/mod.rs @@ -20,7 +20,8 @@ pub(crate) mod vm { //! The `vm` module re-exports wasmer-vm types. use wasmer_vm::InternalStoreHandle; pub(crate) use wasmer_vm::{ - VMExtern, VMFunction, VMFunctionEnvironment, VMGlobal, VMMemory, VMTable, + VMExtern, VMExternRef, VMFuncRef, VMFunction, VMFunctionEnvironment, VMGlobal, VMMemory, + VMTable, }; pub(crate) type VMExternTable = InternalStoreHandle; diff --git a/lib/api/src/value.rs b/lib/api/src/value.rs index b06f01cc8a0..15ec16edeaa 100644 --- a/lib/api/src/value.rs +++ b/lib/api/src/value.rs @@ -4,12 +4,7 @@ use std::string::{String, ToString}; use wasmer_types::Type; -#[cfg(feature = "js")] -use crate::js::extern_ref::VMExternRef; -#[cfg(feature = "js")] -use crate::js::externals::function::VMFuncRef; -#[cfg(feature = "sys")] -use wasmer_vm::{VMExternRef, VMFuncRef}; +use crate::vm::{VMExternRef, VMFuncRef}; use crate::ExternRef; use crate::Function; diff --git a/lib/api/src/vm.rs b/lib/api/src/vm.rs index 30784231418..575f9cdd43d 100644 --- a/lib/api/src/vm.rs +++ b/lib/api/src/vm.rs @@ -2,14 +2,14 @@ #[cfg(feature = "js")] pub(crate) use crate::js::vm::{ - VMExtern, VMExternFunction, VMExternGlobal, VMExternMemory, VMExternTable, VMFunction, - VMFunctionEnvironment, VMGlobal, VMMemory, VMTable, + VMExtern, VMExternFunction, VMExternGlobal, VMExternMemory, VMExternRef, VMExternTable, + VMFuncRef, VMFunction, VMFunctionEnvironment, VMGlobal, VMMemory, VMTable, }; #[cfg(feature = "sys")] pub(crate) use crate::sys::vm::{ - VMExtern, VMExternFunction, VMExternGlobal, VMExternMemory, VMExternTable, - VMFunctionEnvironment, + VMExtern, VMExternFunction, VMExternGlobal, VMExternMemory, VMExternRef, VMExternTable, + VMFuncRef, VMFunctionEnvironment, }; // Needed for tunables customization From cd4cb7a75b2845700b6f57612bbc8b83800c8e8b Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Tue, 14 Feb 2023 18:10:37 -0800 Subject: [PATCH 45/81] Make function internal APIs closer --- lib/api/src/js/externals/function.rs | 4 ++-- lib/api/src/sys/externals/function.rs | 11 +++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/api/src/js/externals/function.rs b/lib/api/src/js/externals/function.rs index 60af891a184..f2138faf788 100644 --- a/lib/api/src/js/externals/function.rs +++ b/lib/api/src/js/externals/function.rs @@ -834,7 +834,7 @@ mod inner { /// # Safety unsafe fn into_c_struct(self, store: &mut impl AsStoreMut) -> Self::CStruct; - /// Writes the contents of a C struct to an array of `f64`. + /// Writes the contents of a C struct to an array of `RawValue`. /// /// # Safety unsafe fn write_c_struct_to_ptr(c_struct: Self::CStruct, ptr: *mut RawValue); @@ -1059,7 +1059,7 @@ mod inner { // Build the tuple. ( $( - FromToNativeWasmType::from_native(NativeWasmTypeInto::from_raw(_store, $x.into())) + FromToNativeWasmType::from_native(NativeWasmTypeInto::from_raw(_store, $x)) ),* ) } diff --git a/lib/api/src/sys/externals/function.rs b/lib/api/src/sys/externals/function.rs index 1e09256f23f..577f9f5a262 100644 --- a/lib/api/src/sys/externals/function.rs +++ b/lib/api/src/sys/externals/function.rs @@ -1002,6 +1002,9 @@ mod inner { /// Note that all values are stored in their binary form. type Array: AsMut<[RawValue]>; + /// The size of the array + fn size() -> u32; + /// Constructs `Self` based on an array of values. /// /// # Safety @@ -1220,6 +1223,10 @@ mod inner { type Array = [RawValue; count_idents!( $( $x ),* )]; + fn size() -> u32 { + count_idents!( $( $x ),* ) as _ + } + #[allow(unused_mut)] #[allow(clippy::unused_unit)] #[allow(clippy::missing_safety_doc)] @@ -1525,6 +1532,10 @@ mod inner { type CStruct = Self; type Array = [RawValue; 0]; + fn size() -> u32 { + 0 + } + unsafe fn from_array(_: &mut impl AsStoreMut, _: Self::Array) -> Self { unreachable!() } From b4c190bf7220ebb33632528f3a7b04e6eb91364b Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Wed, 15 Feb 2023 12:19:00 -0800 Subject: [PATCH 46/81] Unified Function into js/sys --- lib/api/src/externals/function.rs | 512 +++++++++++- lib/api/src/externals/mod.rs | 4 +- lib/api/src/js/as_js.rs | 4 +- lib/api/src/js/externals/function.rs | 1018 +++--------------------- lib/api/src/js/externals/table.rs | 2 +- lib/api/src/js/typed_function.rs | 2 +- lib/api/src/js/vm.rs | 2 + lib/api/src/lib.rs | 7 +- lib/api/src/native_type.rs | 508 +++++++++++- lib/api/src/sys/externals/function.rs | 1044 ++----------------------- lib/api/src/sys/mod.rs | 4 +- lib/api/src/sys/typed_function.rs | 4 +- lib/api/src/vm.rs | 5 +- 13 files changed, 1172 insertions(+), 1944 deletions(-) diff --git a/lib/api/src/externals/function.rs b/lib/api/src/externals/function.rs index 05b873265d8..6acefb7a8e7 100644 --- a/lib/api/src/externals/function.rs +++ b/lib/api/src/externals/function.rs @@ -1,8 +1,510 @@ #[cfg(feature = "js")] -pub use crate::js::externals::function::{ - FromToNativeWasmType, Function, HostFunction, WasmTypeList, -}; +use crate::js::externals::function as function_impl; #[cfg(feature = "sys")] -pub use crate::sys::externals::function::{ - FromToNativeWasmType, Function, HostFunction, WasmTypeList, +use crate::sys::externals::function as function_impl; + +use crate::exports::{ExportError, Exportable}; +use crate::store::{AsStoreMut, AsStoreRef}; +use crate::vm::{VMExtern, VMExternFunction, VMFuncRef, VMFunctionBody, VMTrampoline}; +use crate::{ + Extern, FunctionEnv, FunctionEnvMut, FunctionType, RuntimeError, TypedFunction, Value, }; +use wasmer_types::RawValue; + +use crate::native_type::WasmTypeList; + +/// The `HostFunction` trait represents the set of functions that +/// can be used as host function. To uphold this statement, it is +/// necessary for a function to be transformed into a pointer to +/// `VMFunctionBody`. +pub trait HostFunction +where + Args: WasmTypeList, + Rets: WasmTypeList, + Kind: HostFunctionKind, +{ + /// Get the pointer to the function body. + fn function_body_ptr(&self) -> *const VMFunctionBody; + + /// Get the pointer to the function call trampoline. + fn call_trampoline_address() -> VMTrampoline { + // This is not implemented in JS + unimplemented!(); + } +} + +/// Empty trait to specify the kind of `HostFunction`: With or +/// without an environment. +/// +/// This trait is never aimed to be used by a user. It is used by +/// the trait system to automatically generate the appropriate +/// host functions. +#[doc(hidden)] +pub trait HostFunctionKind: private::HostFunctionKindSealed {} + +/// An empty struct to help Rust typing to determine +/// when a `HostFunction` does have an environment. +pub struct WithEnv; + +impl HostFunctionKind for WithEnv {} + +/// An empty struct to help Rust typing to determine +/// when a `HostFunction` does not have an environment. +pub struct WithoutEnv; + +impl HostFunctionKind for WithoutEnv {} + +mod private { + //! Sealing the HostFunctionKind because it shouldn't be implemented + //! by any type outside. + //! See: + //! https://rust-lang.github.io/api-guidelines/future-proofing.html#c-sealed + pub trait HostFunctionKindSealed {} + impl HostFunctionKindSealed for super::WithEnv {} + impl HostFunctionKindSealed for super::WithoutEnv {} +} + +/// A WebAssembly `function` instance. +/// +/// A function instance is the runtime representation of a function. +/// It effectively is a closure of the original function (defined in either +/// the host or the WebAssembly module) over the runtime `Instance` of its +/// originating `Module`. +/// +/// The module instance is used to resolve references to other definitions +/// during execution of the function. +/// +/// Spec: +/// +/// # Panics +/// - Closures (functions with captured environments) are not currently supported +/// with native functions. Attempting to create a native `Function` with one will +/// result in a panic. +/// [Closures as host functions tracking issue](https://github.com/wasmerio/wasmer/issues/1840) +#[derive(Debug, Clone)] +pub struct Function(pub(crate) function_impl::Function); + +impl Function { + /// Creates a new host `Function` (dynamic) with the provided signature. + /// + /// If you know the signature of the host function at compile time, + /// consider using [`Function::new_typed`] for less runtime overhead. + pub fn new(store: &mut impl AsStoreMut, ty: FT, func: F) -> Self + where + FT: Into, + F: Fn(&[Value]) -> Result, RuntimeError> + 'static + Send + Sync, + { + let env = FunctionEnv::new(&mut store.as_store_mut(), ()); + let wrapped_func = move |_env: FunctionEnvMut<()>, + args: &[Value]| + -> Result, RuntimeError> { func(args) }; + Self::new_with_env(store, &env, ty, wrapped_func) + } + + /// Creates a new host `Function` (dynamic) with the provided signature. + /// + /// If you know the signature of the host function at compile time, + /// consider using [`Function::new_typed_with_env`] for less runtime overhead. + /// + /// Takes a [`FunctionEnv`] that is passed into func. If that is not required, + /// [`Function::new`] might be an option as well. + /// + /// # Examples + /// + /// ``` + /// # use wasmer::{Function, FunctionEnv, FunctionType, Type, Store, Value}; + /// # let mut store = Store::default(); + /// # let env = FunctionEnv::new(&mut store, ()); + /// # + /// let signature = FunctionType::new(vec![Type::I32, Type::I32], vec![Type::I32]); + /// + /// let f = Function::new_with_env(&mut store, &env, &signature, |_env, args| { + /// let sum = args[0].unwrap_i32() + args[1].unwrap_i32(); + /// Ok(vec![Value::I32(sum)]) + /// }); + /// ``` + /// + /// With constant signature: + /// + /// ``` + /// # use wasmer::{Function, FunctionEnv, FunctionType, Type, Store, Value}; + /// # let mut store = Store::default(); + /// # let env = FunctionEnv::new(&mut store, ()); + /// # + /// const I32_I32_TO_I32: ([Type; 2], [Type; 1]) = ([Type::I32, Type::I32], [Type::I32]); + /// + /// let f = Function::new_with_env(&mut store, &env, I32_I32_TO_I32, |_env, args| { + /// let sum = args[0].unwrap_i32() + args[1].unwrap_i32(); + /// Ok(vec![Value::I32(sum)]) + /// }); + /// ``` + pub fn new_with_env( + store: &mut impl AsStoreMut, + env: &FunctionEnv, + ty: FT, + func: F, + ) -> Self + where + FT: Into, + F: Fn(FunctionEnvMut, &[Value]) -> Result, RuntimeError> + + 'static + + Send + + Sync, + { + Function(function_impl::Function::new_with_env(store, env, ty, func)) + } + + #[deprecated( + since = "3.0.0", + note = "new_native() has been renamed to new_typed()." + )] + /// Creates a new host `Function` from a native function. + pub fn new_native(store: &mut impl AsStoreMut, func: F) -> Self + where + F: HostFunction<(), Args, Rets, WithoutEnv> + 'static + Send + Sync, + Args: WasmTypeList, + Rets: WasmTypeList, + { + Self::new_typed(store, func) + } + + /// Creates a new host `Function` from a native function. + pub fn new_typed(store: &mut impl AsStoreMut, func: F) -> Self + where + F: HostFunction<(), Args, Rets, WithoutEnv> + 'static + Send + Sync, + Args: WasmTypeList, + Rets: WasmTypeList, + { + Function(function_impl::Function::new_typed(store, func)) + } + + #[deprecated( + since = "3.0.0", + note = "new_native_with_env() has been renamed to new_typed_with_env()." + )] + /// Creates a new host `Function` with an environment from a native function. + pub fn new_native_with_env( + store: &mut impl AsStoreMut, + env: &FunctionEnv, + func: F, + ) -> Self + where + F: HostFunction + 'static + Send + Sync, + Args: WasmTypeList, + Rets: WasmTypeList, + { + Self::new_typed_with_env(store, env, func) + } + + /// Creates a new host `Function` with an environment from a typed function. + /// + /// The function signature is automatically retrieved using the + /// Rust typing system. + /// + /// # Example + /// + /// ``` + /// # use wasmer::{Store, Function, FunctionEnv, FunctionEnvMut}; + /// # let mut store = Store::default(); + /// # let env = FunctionEnv::new(&mut store, ()); + /// # + /// fn sum(_env: FunctionEnvMut<()>, a: i32, b: i32) -> i32 { + /// a + b + /// } + /// + /// let f = Function::new_typed_with_env(&mut store, &env, sum); + /// ``` + pub fn new_typed_with_env( + store: &mut impl AsStoreMut, + env: &FunctionEnv, + func: F, + ) -> Self + where + F: HostFunction + 'static + Send + Sync, + Args: WasmTypeList, + Rets: WasmTypeList, + { + Function(function_impl::Function::new_typed_with_env( + store, env, func, + )) + } + + /// Returns the [`FunctionType`] of the `Function`. + /// + /// # Example + /// + /// ``` + /// # use wasmer::{Function, FunctionEnv, FunctionEnvMut, Store, Type}; + /// # let mut store = Store::default(); + /// # let env = FunctionEnv::new(&mut store, ()); + /// # + /// fn sum(_env: FunctionEnvMut<()>, a: i32, b: i32) -> i32 { + /// a + b + /// } + /// + /// let f = Function::new_typed_with_env(&mut store, &env, sum); + /// + /// assert_eq!(f.ty(&mut store).params(), vec![Type::I32, Type::I32]); + /// assert_eq!(f.ty(&mut store).results(), vec![Type::I32]); + /// ``` + pub fn ty(&self, store: &impl AsStoreRef) -> FunctionType { + self.0.ty(store) + } + + /// Returns the number of parameters that this function takes. + /// + /// # Example + /// + /// ``` + /// # use wasmer::{Function, FunctionEnv, FunctionEnvMut, Store, Type}; + /// # let mut store = Store::default(); + /// # let env = FunctionEnv::new(&mut store, ()); + /// # + /// fn sum(_env: FunctionEnvMut<()>, a: i32, b: i32) -> i32 { + /// a + b + /// } + /// + /// let f = Function::new_typed_with_env(&mut store, &env, sum); + /// + /// assert_eq!(f.param_arity(&mut store), 2); + /// ``` + pub fn param_arity(&self, store: &impl AsStoreRef) -> usize { + self.ty(store).params().len() + } + + /// Returns the number of results this function produces. + /// + /// # Example + /// + /// ``` + /// # use wasmer::{Function, FunctionEnv, FunctionEnvMut, Store, Type}; + /// # let mut store = Store::default(); + /// # let env = FunctionEnv::new(&mut store, ()); + /// # + /// fn sum(_env: FunctionEnvMut<()>, a: i32, b: i32) -> i32 { + /// a + b + /// } + /// + /// let f = Function::new_typed_with_env(&mut store, &env, sum); + /// + /// assert_eq!(f.result_arity(&mut store), 1); + /// ``` + pub fn result_arity(&self, store: &impl AsStoreRef) -> usize { + self.ty(store).results().len() + } + + /// Call the `Function` function. + /// + /// Depending on where the Function is defined, it will call it. + /// 1. If the function is defined inside a WebAssembly, it will call the trampoline + /// for the function signature. + /// 2. If the function is defined in the host (in a native way), it will + /// call the trampoline. + /// + /// # Examples + /// + /// ``` + /// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value}; + /// # use wasmer::FunctionEnv; + /// # let mut store = Store::default(); + /// # let env = FunctionEnv::new(&mut store, ()); + /// # let wasm_bytes = wat2wasm(r#" + /// # (module + /// # (func (export "sum") (param $x i32) (param $y i32) (result i32) + /// # local.get $x + /// # local.get $y + /// # i32.add + /// # )) + /// # "#.as_bytes()).unwrap(); + /// # let module = Module::new(&store, wasm_bytes).unwrap(); + /// # let import_object = imports! {}; + /// # let instance = Instance::new(&mut store, &module, &import_object).unwrap(); + /// # + /// let sum = instance.exports.get_function("sum").unwrap(); + /// + /// assert_eq!(sum.call(&mut store, &[Value::I32(1), Value::I32(2)]).unwrap().to_vec(), vec![Value::I32(3)]); + /// ``` + pub fn call( + &self, + store: &mut impl AsStoreMut, + params: &[Value], + ) -> Result, RuntimeError> { + self.0.call(store, params) + } + + #[doc(hidden)] + #[allow(missing_docs)] + pub fn call_raw( + &self, + store: &mut impl AsStoreMut, + params: Vec, + ) -> Result, RuntimeError> { + self.0.call_raw(store, params) + } + + pub(crate) fn vm_funcref(&self, store: &impl AsStoreRef) -> VMFuncRef { + self.0.vm_funcref(store) + } + + pub(crate) unsafe fn from_vm_funcref(store: &mut impl AsStoreMut, funcref: VMFuncRef) -> Self { + Function(function_impl::Function::from_vm_funcref(store, funcref)) + } + + /// Transform this WebAssembly function into a native function. + /// See [`TypedFunction`] to learn more. + #[deprecated(since = "3.0.0", note = "native() has been renamed to typed().")] + pub fn native( + &self, + store: &impl AsStoreRef, + ) -> Result, RuntimeError> + where + Args: WasmTypeList, + Rets: WasmTypeList, + { + self.typed(store) + } + + /// Transform this WebAssembly function into a typed function. + /// See [`TypedFunction`] to learn more. + /// + /// # Examples + /// + /// ``` + /// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, TypedFunction, Value}; + /// # use wasmer::FunctionEnv; + /// # let mut store = Store::default(); + /// # let env = FunctionEnv::new(&mut store, ()); + /// # let wasm_bytes = wat2wasm(r#" + /// # (module + /// # (func (export "sum") (param $x i32) (param $y i32) (result i32) + /// # local.get $x + /// # local.get $y + /// # i32.add + /// # )) + /// # "#.as_bytes()).unwrap(); + /// # let module = Module::new(&store, wasm_bytes).unwrap(); + /// # let import_object = imports! {}; + /// # let instance = Instance::new(&mut store, &module, &import_object).unwrap(); + /// # + /// let sum = instance.exports.get_function("sum").unwrap(); + /// let sum_typed: TypedFunction<(i32, i32), i32> = sum.typed(&mut store).unwrap(); + /// + /// assert_eq!(sum_typed.call(&mut store, 1, 2).unwrap(), 3); + /// ``` + /// + /// # Errors + /// + /// If the `Args` generic parameter does not match the exported function + /// an error will be raised: + /// + /// ```should_panic + /// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, TypedFunction, Value}; + /// # use wasmer::FunctionEnv; + /// # let mut store = Store::default(); + /// # let env = FunctionEnv::new(&mut store, ()); + /// # let wasm_bytes = wat2wasm(r#" + /// # (module + /// # (func (export "sum") (param $x i32) (param $y i32) (result i32) + /// # local.get $x + /// # local.get $y + /// # i32.add + /// # )) + /// # "#.as_bytes()).unwrap(); + /// # let module = Module::new(&store, wasm_bytes).unwrap(); + /// # let import_object = imports! {}; + /// # let instance = Instance::new(&mut store, &module, &import_object).unwrap(); + /// # + /// let sum = instance.exports.get_function("sum").unwrap(); + /// + /// // This results in an error: `RuntimeError` + /// let sum_typed : TypedFunction<(i64, i64), i32> = sum.typed(&mut store).unwrap(); + /// ``` + /// + /// If the `Rets` generic parameter does not match the exported function + /// an error will be raised: + /// + /// ```should_panic + /// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, TypedFunction, Value}; + /// # use wasmer::FunctionEnv; + /// # let mut store = Store::default(); + /// # let env = FunctionEnv::new(&mut store, ()); + /// # let wasm_bytes = wat2wasm(r#" + /// # (module + /// # (func (export "sum") (param $x i32) (param $y i32) (result i32) + /// # local.get $x + /// # local.get $y + /// # i32.add + /// # )) + /// # "#.as_bytes()).unwrap(); + /// # let module = Module::new(&store, wasm_bytes).unwrap(); + /// # let import_object = imports! {}; + /// # let instance = Instance::new(&mut store, &module, &import_object).unwrap(); + /// # + /// let sum = instance.exports.get_function("sum").unwrap(); + /// + /// // This results in an error: `RuntimeError` + /// let sum_typed: TypedFunction<(i32, i32), i64> = sum.typed(&mut store).unwrap(); + /// ``` + pub fn typed( + &self, + store: &impl AsStoreRef, + ) -> Result, RuntimeError> + where + Args: WasmTypeList, + Rets: WasmTypeList, + { + let ty = self.ty(store); + + // type check + { + let expected = ty.params(); + let given = Args::wasm_types(); + + if expected != given { + return Err(RuntimeError::new(format!( + "given types (`{:?}`) for the function arguments don't match the actual types (`{:?}`)", + given, + expected, + ))); + } + } + + { + let expected = ty.results(); + let given = Rets::wasm_types(); + + if expected != given { + // todo: error result types don't match + return Err(RuntimeError::new(format!( + "given types (`{:?}`) for the function results don't match the actual types (`{:?}`)", + given, + expected, + ))); + } + } + + Ok(TypedFunction::new(store, self.clone())) + } + + pub(crate) fn from_vm_extern(store: &mut impl AsStoreMut, vm_extern: VMExternFunction) -> Self { + Function(function_impl::Function::from_vm_extern(store, vm_extern)) + } + + /// Checks whether this `Function` can be used with the given store. + pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool { + self.0.is_from_store(store) + } + + pub(crate) fn to_vm_extern(&self) -> VMExtern { + self.0.to_vm_extern() + } +} + +impl<'a> Exportable<'a> for Function { + fn get_self_from_extern(_extern: &'a Extern) -> Result<&'a Self, ExportError> { + match _extern { + Extern::Function(func) => Ok(func), + _ => Err(ExportError::IncompatibleType), + } + } +} diff --git a/lib/api/src/externals/mod.rs b/lib/api/src/externals/mod.rs index 50d2b7c55ec..5757ebdbe80 100644 --- a/lib/api/src/externals/mod.rs +++ b/lib/api/src/externals/mod.rs @@ -1,10 +1,10 @@ -mod function; +pub(crate) mod function; mod global; mod memory; mod memory_view; mod table; -pub use self::function::{FromToNativeWasmType, Function, HostFunction, WasmTypeList}; +pub use self::function::{Function, HostFunction}; pub use self::global::Global; pub use self::memory::Memory; pub use self::memory_view::MemoryView; diff --git a/lib/api/src/js/as_js.rs b/lib/api/src/js/as_js.rs index b18bfade310..d9272c972aa 100644 --- a/lib/api/src/js/as_js.rs +++ b/lib/api/src/js/as_js.rs @@ -56,7 +56,7 @@ impl AsJs for Value { Self::F32(f) => JsValue::from_f64(*f as f64), Self::F64(f) => JsValue::from_f64(*f), Self::V128(f) => JsValue::from_f64(*f as f64), - Self::FuncRef(Some(func)) => func.handle.function.clone().into(), + Self::FuncRef(Some(func)) => func.0.handle.function.clone().into(), Self::FuncRef(None) => JsValue::null(), Self::ExternRef(_) => unimplemented!(), } @@ -207,7 +207,7 @@ impl AsJs for Extern { fn as_jsvalue(&self, _store: &impl AsStoreRef) -> wasm_bindgen::JsValue { match self { Self::Memory(memory) => memory.0.handle.memory.clone().into(), - Self::Function(function) => function.handle.function.clone().into(), + Self::Function(function) => function.0.handle.function.clone().into(), Self::Table(table) => table.0.handle.table.clone().into(), Self::Global(global) => global.0.handle.global.clone().into(), } diff --git a/lib/api/src/js/externals/function.rs b/lib/api/src/js/externals/function.rs index f2138faf788..566ad8396a0 100644 --- a/lib/api/src/js/externals/function.rs +++ b/lib/api/src/js/externals/function.rs @@ -1,22 +1,29 @@ -pub use self::inner::{FromToNativeWasmType, HostFunction, WasmTypeList, WithEnv, WithoutEnv}; use crate::exports::{ExportError, Exportable}; +use crate::externals::function::{HostFunction, HostFunctionKind, WithEnv, WithoutEnv}; use crate::function_env::{FunctionEnv, FunctionEnvMut}; use crate::js::as_js::{param_from_js, AsJs}; /* ValFuncRef */ -use crate::js::vm::VMExtern; +use crate::js::store::{InternalStoreHandle, StoreHandle}; +use crate::js::vm::{VMExtern, VMFuncRef, VMFunction, VMFunctionBody, VMFunctionEnvironment}; use crate::js::RuntimeError; +use crate::native_type::{FromToNativeWasmType, IntoResult, NativeWasmTypeInto, WasmTypeList}; use crate::store::{AsStoreMut, AsStoreRef, StoreMut}; use crate::value::Value; use crate::Extern; -use crate::FunctionType; use crate::TypedFunction; -use js_sys::{Array, Function as JSFunction}; +use std::array::TryFromSliceError; +use std::convert::TryInto; +use std::error::Error; +use std::fmt; use std::iter::FromIterator; +use std::marker::PhantomData; +use std::panic::{self, AssertUnwindSafe}; + +use wasmer_types::{FunctionType, NativeWasmType, RawValue, Type}; + +use js_sys::{Array, Function as JSFunction}; use wasm_bindgen::prelude::*; use wasm_bindgen::JsCast; -use crate::js::vm::{VMFuncRef, VMFunction, VMFunctionBody}; -use std::fmt; - #[inline] fn result_to_js(val: &Value) -> JsValue { match val { @@ -37,23 +44,6 @@ fn results_to_js_array(values: &[Value]) -> Array { Array::from_iter(values.iter().map(result_to_js)) } -/// A WebAssembly `function` instance. -/// -/// A function instance is the runtime representation of a function. -/// It effectively is a closure of the original function (defined in either -/// the host or the WebAssembly module) over the runtime `Instance` of its -/// originating `Module`. -/// -/// The module instance is used to resolve references to other definitions -/// during execution of the function. -/// -/// Spec: -/// -/// # Panics -/// - Closures (functions with captured environments) are not currently supported -/// with native functions. Attempting to create a native `Function` with one will -/// result in a panic. -/// [Closures as host functions tracking issue](https://github.com/wasmerio/wasmer/issues/1840) #[derive(Clone, PartialEq)] pub struct Function { pub(crate) handle: VMFunction, @@ -66,60 +56,11 @@ impl From for Function { } impl Function { - /// Creates a new host `Function` (dynamic) with the provided signature. - /// - /// If you know the signature of the host function at compile time, - /// consider using [`Function::new_typed`] for less runtime overhead. - pub fn new(store: &mut impl AsStoreMut, ty: FT, func: F) -> Self - where - FT: Into, - F: Fn(&[Value]) -> Result, RuntimeError> + 'static + Send + Sync, - { - let env = FunctionEnv::new(&mut store.as_store_mut(), ()); - let wrapped_func = move |_env: FunctionEnvMut<()>, - args: &[Value]| - -> Result, RuntimeError> { func(args) }; - Self::new_with_env(store, &env, ty, wrapped_func) - } - /// To `VMExtern`. pub fn to_vm_extern(&self) -> VMExtern { VMExtern::Function(self.handle.clone()) } - /// Creates a new host `Function` (dynamic) with the provided signature. - /// - /// If you know the signature of the host function at compile time, - /// consider using [`Function::new_typed`] or [`Function::new_typed_with_env`] - /// for less runtime overhead. - /// - /// # Examples - /// - /// ``` - /// # use wasmer::{Function, FunctionType, Type, Store, Value}; - /// # let mut store = Store::default(); - /// # - /// let signature = FunctionType::new(vec![Type::I32, Type::I32], vec![Type::I32]); - /// - /// let f = Function::new_with_env(&store, &signature, |args| { - /// let sum = args[0].unwrap_i32() + args[1].unwrap_i32(); - /// Ok(vec![Value::I32(sum)]) - /// }); - /// ``` - /// - /// With constant signature: - /// - /// ``` - /// # use wasmer::{Function, FunctionType, Type, Store, Value}; - /// # let mut store = Store::default(); - /// # - /// const I32_I32_TO_I32: ([Type; 2], [Type; 1]) = ([Type::I32, Type::I32], [Type::I32]); - /// - /// let f = Function::new_with_env(&store, I32_I32_TO_I32, |args| { - /// let sum = args[0].unwrap_i32() + args[1].unwrap_i32(); - /// Ok(vec![Value::I32(sum)]) - /// }); - /// ``` #[allow(clippy::cast_ptr_alignment)] pub fn new_with_env( store: &mut impl AsStoreMut, @@ -191,20 +132,6 @@ impl Function { Self::from_vm_extern(&mut store, vm_function) } - #[deprecated( - since = "3.0.0", - note = "new_native() has been renamed to new_typed()." - )] - /// Creates a new host `Function` from a native function. - pub fn new_native(store: &mut impl AsStoreMut, func: F) -> Self - where - F: HostFunction<(), Args, Rets, WithoutEnv> + 'static + Send + Sync, - Args: WasmTypeList, - Rets: WasmTypeList, - { - Self::new_typed(store, func) - } - /// Creates a new host `Function` from a native function. pub fn new_typed(store: &mut impl AsStoreMut, func: F) -> Self where @@ -216,7 +143,7 @@ impl Function { if std::mem::size_of::() != 0 { Self::closures_unsupported_panic(); } - let function = inner::Function::::new(func); + let function = WasmFunction::::new(func); let address = function.address() as usize as u32; let ft = wasm_bindgen::function_table(); @@ -234,41 +161,6 @@ impl Function { } } - #[deprecated( - since = "3.0.0", - note = "new_native_with_env() has been renamed to new_typed_with_env()." - )] - /// Creates a new host `Function` with an environment from a typed function. - pub fn new_native_with_env( - store: &mut impl AsStoreMut, - env: &FunctionEnv, - func: F, - ) -> Self - where - F: HostFunction + 'static + Send + Sync, - Args: WasmTypeList, - Rets: WasmTypeList, - { - Self::new_typed_with_env(store, env, func) - } - - /// Creates a new host `Function` from a typed function. - /// - /// The function signature is automatically retrieved using the - /// Rust typing system. - /// - /// # Example - /// - /// ``` - /// # use wasmer::{Store, Function}; - /// # let mut store = Store::default(); - /// # - /// fn sum(a: i32, b: i32) -> i32 { - /// a + b - /// } - /// - /// let f = Function::new_typed_with_env(&store, sum); - /// ``` pub fn new_typed_with_env( store: &mut impl AsStoreMut, env: &FunctionEnv, @@ -283,7 +175,7 @@ impl Function { if std::mem::size_of::() != 0 { Self::closures_unsupported_panic(); } - let function = inner::Function::::new(func); + let function = WasmFunction::::new(func); let address = function.address() as usize as u32; let ft = wasm_bindgen::function_table(); @@ -302,96 +194,21 @@ impl Function { } } - /// Returns the [`FunctionType`] of the `Function`. - /// - /// # Example - /// - /// ``` - /// # use wasmer::{Function, Store, Type}; - /// # let mut store = Store::default(); - /// # - /// fn sum(a: i32, b: i32) -> i32 { - /// a + b - /// } - /// - /// let f = Function::new_typed(&store, sum); - /// - /// assert_eq!(f.ty().params(), vec![Type::I32, Type::I32]); - /// assert_eq!(f.ty().results(), vec![Type::I32]); - /// ``` pub fn ty(&self, _store: &impl AsStoreRef) -> FunctionType { self.handle.ty.clone() } - /// Returns the number of parameters that this function takes. - /// - /// # Example - /// - /// ``` - /// # use wasmer::{Function, FunctionEnv, FunctionEnvMut, Store, Type}; - /// # let mut store = Store::default(); - /// # - /// fn sum(a: i32, b: i32) -> i32 { - /// a + b - /// } - /// - /// let f = Function::new_typed(&store, sum); - /// - /// assert_eq!(f.param_arity(&store), 2); - /// ``` - pub fn param_arity(&self, store: &impl AsStoreRef) -> usize { - self.ty(store).params().len() - } - - /// Returns the number of results this function produces. - /// - /// # Example - /// - /// ``` - /// # use wasmer::{Function, FunctionEnv, FunctionEnvMut, Store, Type}; - /// # let mut store = Store::default(); - /// # - /// fn sum(a: i32, b: i32) -> i32 { - /// a + b - /// } - /// - /// let f = Function::new_typed(&store, sum); - /// - /// assert_eq!(f.result_arity(&store), 1); - /// ``` - pub fn result_arity(&self, store: &impl AsStoreRef) -> usize { - self.ty(store).results().len() + pub fn call_raw( + &self, + store: &mut impl AsStoreMut, + params: Vec, + ) -> Result, RuntimeError> { + // There is no optimal call_raw in JS, so we just + // simply rely the call + // self.call(store, params) + unimplemented!(); } - /// Call the `Function` function. - /// - /// Depending on where the Function is defined, it will call it. - /// 1. If the function is defined inside a WebAssembly, it will call the trampoline - /// for the function signature. - /// 2. If the function is defined in the host (in a native way), it will - /// call the trampoline. - /// - /// # Examples - /// - /// ``` - /// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value}; - /// # let mut store = Store::default(); - /// # let wasm_bytes = wat2wasm(r#" - /// # (module - /// # (func (export "sum") (param $x i32) (param $y i32) (result i32) - /// # local.get $x - /// # local.get $y - /// # i32.add - /// # )) - /// # "#.as_bytes()).unwrap(); - /// # let module = Module::new(&store, wasm_bytes).unwrap(); - /// # let import_object = imports! {}; - /// # let instance = Instance::new(&module, &import_object).unwrap(); - /// # - /// let sum = instance.exports.get_function("sum").unwrap(); - /// - /// assert_eq!(sum.call(&[Value::I32(1), Value::I32(2)]).unwrap().to_vec(), vec![Value::I32(3)]); - /// ``` pub fn call( &self, store: &mut impl AsStoreMut, @@ -467,134 +284,6 @@ impl Function { Self { handle: internal } } - #[deprecated(since = "3.0.0", note = "native() has been renamed to typed().")] - /// Transform this WebAssembly function into a typed function. - pub fn native( - &self, - store: &impl AsStoreRef, - ) -> Result, RuntimeError> - where - Args: WasmTypeList, - Rets: WasmTypeList, - { - self.typed(store) - } - - /// Transform this WebAssembly function into a typed function. - /// See [`TypedFunction`] to learn more. - /// - /// # Examples - /// - /// ``` - /// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value}; - /// # let mut store = Store::default(); - /// # let wasm_bytes = wat2wasm(r#" - /// # (module - /// # (func (export "sum") (param $x i32) (param $y i32) (result i32) - /// # local.get $x - /// # local.get $y - /// # i32.add - /// # )) - /// # "#.as_bytes()).unwrap(); - /// # let module = Module::new(&store, wasm_bytes).unwrap(); - /// # let import_object = imports! {}; - /// # let instance = Instance::new(&module, &import_object).unwrap(); - /// # - /// let sum = instance.exports.get_function("sum").unwrap(); - /// let sum_typed = sum.typed::<(i32, i32), i32>().unwrap(); - /// - /// assert_eq!(sum_typed.call(&mut store, 1, 2).unwrap(), 3); - /// ``` - /// - /// # Errors - /// - /// If the `Args` generic parameter does not match the exported function - /// an error will be raised: - /// - /// ```should_panic - /// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value}; - /// # let mut store = Store::default(); - /// # let wasm_bytes = wat2wasm(r#" - /// # (module - /// # (func (export "sum") (param $x i32) (param $y i32) (result i32) - /// # local.get $x - /// # local.get $y - /// # i32.add - /// # )) - /// # "#.as_bytes()).unwrap(); - /// # let module = Module::new(&store, wasm_bytes).unwrap(); - /// # let import_object = imports! {}; - /// # let instance = Instance::new(&module, &import_object).unwrap(); - /// # - /// let sum = instance.exports.get_function("sum").unwrap(); - /// - /// // This results in an error: `RuntimeError` - /// let sum_typed = sum.typed::<(i64, i64), i32>(&mut store).unwrap(); - /// ``` - /// - /// If the `Rets` generic parameter does not match the exported function - /// an error will be raised: - /// - /// ```should_panic - /// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value}; - /// # let mut store = Store::default(); - /// # let wasm_bytes = wat2wasm(r#" - /// # (module - /// # (func (export "sum") (param $x i32) (param $y i32) (result i32) - /// # local.get $x - /// # local.get $y - /// # i32.add - /// # )) - /// # "#.as_bytes()).unwrap(); - /// # let module = Module::new(&store, wasm_bytes).unwrap(); - /// # let import_object = imports! {}; - /// # let instance = Instance::new(&module, &import_object).unwrap(); - /// # - /// let sum = instance.exports.get_function("sum").unwrap(); - /// - /// // This results in an error: `RuntimeError` - /// let sum_typed = sum.typed::<(i32, i32), i64>(&mut store).unwrap(); - /// ``` - pub fn typed( - &self, - store: &impl AsStoreRef, - ) -> Result, RuntimeError> - where - Args: WasmTypeList, - Rets: WasmTypeList, - { - let ty = self.ty(store); - // type check - { - let expected = ty.params(); - let given = Args::wasm_types(); - - if expected != given { - return Err(RuntimeError::new(format!( - "given types (`{:?}`) for the function arguments don't match the actual types (`{:?}`)", - given, - expected, - ))); - } - } - - { - let expected = ty.results(); - let given = Rets::wasm_types(); - - if expected != given { - // todo: error result types don't match - return Err(RuntimeError::new(format!( - "given types (`{:?}`) for the function results don't match the actual types (`{:?}`)", - given, - expected, - ))); - } - } - - Ok(TypedFunction::new(store, self.clone())) - } - pub(crate) fn vm_funcref(&self, store: &impl AsStoreRef) -> VMFuncRef { unimplemented!(); } @@ -614,412 +303,55 @@ impl Function { } } -impl<'a> Exportable<'a> for Function { - fn get_self_from_extern(_extern: &'a Extern) -> Result<&'a Self, ExportError> { - match _extern { - Extern::Function(func) => Ok(func), - _ => Err(ExportError::IncompatibleType), - } - } -} - impl fmt::Debug for Function { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.debug_struct("Function").finish() } } -/// This private inner module contains the low-level implementation -/// for `Function` and its siblings. -mod inner { - use super::RuntimeError; - use super::VMFunctionBody; - use crate::function_env::{FunctionEnv, FunctionEnvMut}; - use crate::js::store::{InternalStoreHandle, StoreHandle}; - use crate::js::vm::VMFunctionEnvironment; - use crate::store::{AsStoreMut, AsStoreRef, StoreMut}; - use crate::NativeWasmTypeInto; - use std::array::TryFromSliceError; - use std::convert::{Infallible, TryInto}; - use std::error::Error; - use std::marker::PhantomData; - use std::panic::{self, AssertUnwindSafe}; - - use wasmer_types::{FunctionType, NativeWasmType, RawValue, Type}; - // use wasmer::{raise_user_trap, resume_panic}; - - /// A trait to convert a Rust value to a `WasmNativeType` value, - /// or to convert `WasmNativeType` value to a Rust value. - /// - /// This trait should ideally be split into two traits: - /// `FromNativeWasmType` and `ToNativeWasmType` but it creates a - /// non-negligible complexity in the `WasmTypeList` - /// implementation. - pub unsafe trait FromToNativeWasmType - where - Self: Sized, - { - /// Native Wasm type. - type Native: NativeWasmTypeInto; - - /// Convert a value of kind `Self::Native` to `Self`. - /// - /// # Panics - /// - /// This method panics if `native` cannot fit in the `Self` - /// type`. - fn from_native(native: Self::Native) -> Self; - - /// Convert self to `Self::Native`. - /// - /// # Panics - /// - /// This method panics if `self` cannot fit in the - /// `Self::Native` type. - fn to_native(self) -> Self::Native; - - /// Returns whether this native type belongs to the given store - fn is_from_store(&self, _store: &impl AsStoreRef) -> bool; - } - - macro_rules! from_to_native_wasm_type { - ( $( $type:ty => $native_type:ty ),* ) => { - $( - #[allow(clippy::use_self)] - unsafe impl FromToNativeWasmType for $type { - type Native = $native_type; - - #[inline] - fn from_native(native: Self::Native) -> Self { - native as Self - } - - #[inline] - fn to_native(self) -> Self::Native { - self as Self::Native - } - - #[inline] - fn is_from_store(&self, _store: &impl AsStoreRef) -> bool { - true // Javascript only has one store - } - } - )* - }; - } - - macro_rules! from_to_native_wasm_type_same_size { - ( $( $type:ty => $native_type:ty ),* ) => { - $( - #[allow(clippy::use_self)] - unsafe impl FromToNativeWasmType for $type { - type Native = $native_type; - - #[inline] - fn from_native(native: Self::Native) -> Self { - Self::from_ne_bytes(Self::Native::to_ne_bytes(native)) - } - - #[inline] - fn to_native(self) -> Self::Native { - Self::Native::from_ne_bytes(Self::to_ne_bytes(self)) - } - - #[inline] - fn is_from_store(&self, _store: &impl AsStoreRef) -> bool { - true // Javascript only has one store - } - } - )* - }; - } - - from_to_native_wasm_type!( - i8 => i32, - u8 => i32, - i16 => i32, - u16 => i32 - ); - - from_to_native_wasm_type_same_size!( - i32 => i32, - u32 => i32, - i64 => i64, - u64 => i64, - f32 => f32, - f64 => f64 - ); - - #[cfg(test)] - mod test_from_to_native_wasm_type { - use super::FromToNativeWasmType; - - #[test] - fn test_to_native() { - assert_eq!(7i8.to_native(), 7i32); - assert_eq!(7u8.to_native(), 7i32); - assert_eq!(7i16.to_native(), 7i32); - assert_eq!(7u16.to_native(), 7i32); - assert_eq!(u32::MAX.to_native(), -1); - } - - #[test] - fn test_to_native_same_size() { - assert_eq!(7i32.to_native(), 7i32); - assert_eq!(7u32.to_native(), 7i32); - assert_eq!(7i64.to_native(), 7i64); - assert_eq!(7u64.to_native(), 7i64); - assert_eq!(7f32.to_native(), 7f32); - assert_eq!(7f64.to_native(), 7f64); - } - } - - /// The `WasmTypeList` trait represents a tuple (list) of Wasm - /// typed values. It is used to get low-level representation of - /// such a tuple. - pub trait WasmTypeList - where - Self: Sized, - { - /// The C type (a struct) that can hold/represent all the - /// represented values. - type CStruct; - - /// The array type that can hold all the represented values. - /// - /// Note that all values are stored in their binary form. - type Array: AsMut<[RawValue]>; - - /// The size of the array - fn size() -> u32; - - /// Constructs `Self` based on an array of values. - /// - /// # Safety - unsafe fn from_array(store: &mut impl AsStoreMut, array: Self::Array) -> Self; - - /// Constructs `Self` based on a slice of values. - /// - /// `from_slice` returns a `Result` because it is possible - /// that the slice doesn't have the same size than - /// `Self::Array`, in which circumstance an error of kind - /// `TryFromSliceError` will be returned. - /// - /// # Safety - unsafe fn from_slice( - store: &mut impl AsStoreMut, - slice: &[RawValue], - ) -> Result; - - /// Builds and returns an array of type `Array` from a tuple - /// (list) of values. - /// - /// # Safety - unsafe fn into_array(self, store: &mut impl AsStoreMut) -> Self::Array; - - /// Allocates and return an empty array of type `Array` that - /// will hold a tuple (list) of values, usually to hold the - /// returned values of a WebAssembly function call. - fn empty_array() -> Self::Array; - - /// Builds a tuple (list) of values from a C struct of type - /// `CStruct`. - /// - /// # Safety - unsafe fn from_c_struct(store: &mut impl AsStoreMut, c_struct: Self::CStruct) -> Self; - - /// Builds and returns a C struct of type `CStruct` from a - /// tuple (list) of values. - /// - /// # Safety - unsafe fn into_c_struct(self, store: &mut impl AsStoreMut) -> Self::CStruct; - - /// Writes the contents of a C struct to an array of `RawValue`. - /// - /// # Safety - unsafe fn write_c_struct_to_ptr(c_struct: Self::CStruct, ptr: *mut RawValue); - - /// Get the Wasm types for the tuple (list) of currently - /// represented values. - fn wasm_types() -> &'static [Type]; - } - - /// The `IntoResult` trait turns a `WasmTypeList` into a - /// `Result`. - /// - /// It is mostly used to turn result values of a Wasm function - /// call into a `Result`. - pub trait IntoResult - where - T: WasmTypeList, - { - /// The error type for this trait. - type Error: Error + Sync + Send + 'static; - - /// Transforms `Self` into a `Result`. - fn into_result(self) -> Result; - } +/// Represents a low-level Wasm static host function. See +/// `super::Function::new` and `super::Function::new_env` to learn +/// more. +#[derive(Clone, Debug, Hash, PartialEq, Eq)] +pub struct WasmFunction { + address: *const VMFunctionBody, + _phantom: PhantomData<(Args, Rets)>, +} - impl IntoResult for T - where - T: WasmTypeList, - { - // `T` is not a `Result`, it's already a value, so no error - // can be built. - type Error = Infallible; +unsafe impl Send for WasmFunction {} - fn into_result(self) -> Result { - Ok(self) - } - } - - impl IntoResult for Result +impl WasmFunction +where + Args: WasmTypeList, + Rets: WasmTypeList, +{ + /// Creates a new `WasmFunction`. + #[allow(dead_code)] + pub fn new(function: F) -> Self where - T: WasmTypeList, - E: Error + Sync + Send + 'static, + F: HostFunction, + T: Sized, { - type Error = E; - - fn into_result(self) -> Self { - self - } - } - - #[cfg(test)] - mod test_into_result { - use super::*; - use std::convert::Infallible; - - #[test] - fn test_into_result_over_t() { - let x: i32 = 42; - let result_of_x: Result = x.into_result(); - - assert_eq!(result_of_x.unwrap(), x); - } - - #[test] - fn test_into_result_over_result() { - { - let x: Result = Ok(42); - let result_of_x: Result = x.into_result(); - - assert_eq!(result_of_x, x); - } - - { - use std::{error, fmt}; - - #[derive(Debug, PartialEq)] - struct E; - - impl fmt::Display for E { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(formatter, "E") - } - } - - impl error::Error for E {} - - let x: Result = Err(E); - let result_of_x: Result = x.into_result(); - - assert_eq!(result_of_x.unwrap_err(), E); - } + Self { + address: function.function_body_ptr(), + _phantom: PhantomData, } } - /// The `HostFunction` trait represents the set of functions that - /// can be used as host function. To uphold this statement, it is - /// necessary for a function to be transformed into a pointer to - /// `VMFunctionBody`. - pub trait HostFunction - where - Args: WasmTypeList, - Rets: WasmTypeList, - Kind: HostFunctionKind, - { - /// Get the pointer to the function body. - fn function_body_ptr(&self) -> *const VMFunctionBody; - - // /// Get the pointer to the function call trampoline. - // fn call_trampoline_address() -> VMTrampoline; - } - - /// Empty trait to specify the kind of `HostFunction`: With or - /// without an environment. - /// - /// This trait is never aimed to be used by a user. It is used by - /// the trait system to automatically generate the appropriate - /// host functions. - #[doc(hidden)] - pub trait HostFunctionKind: private::HostFunctionKindSealed {} - - /// An empty struct to help Rust typing to determine - /// when a `HostFunction` does have an environment. - pub struct WithEnv; - - impl HostFunctionKind for WithEnv {} - - /// An empty struct to help Rust typing to determine - /// when a `HostFunction` does not have an environment. - pub struct WithoutEnv; - - impl HostFunctionKind for WithoutEnv {} - - mod private { - //! Sealing the HostFunctionKind because it shouldn't be implemented - //! by any type outside. - //! See: - //! https://rust-lang.github.io/api-guidelines/future-proofing.html#c-sealed - pub trait HostFunctionKindSealed {} - impl HostFunctionKindSealed for super::WithEnv {} - impl HostFunctionKindSealed for super::WithoutEnv {} - } - - /// Represents a low-level Wasm static host function. See - /// `super::Function::new` and `super::Function::new_env` to learn - /// more. - #[derive(Clone, Debug, Hash, PartialEq, Eq)] - pub struct Function { - address: *const VMFunctionBody, - _phantom: PhantomData<(Args, Rets)>, + /// Get the function type of this `WasmFunction`. + #[allow(dead_code)] + pub fn ty(&self) -> FunctionType { + FunctionType::new(Args::wasm_types(), Rets::wasm_types()) } - unsafe impl Send for Function {} - - impl Function - where - Args: WasmTypeList, - Rets: WasmTypeList, - { - /// Creates a new `Function`. - #[allow(dead_code)] - pub fn new(function: F) -> Self - where - F: HostFunction, - T: Sized, - { - Self { - address: function.function_body_ptr(), - _phantom: PhantomData, - } - } - - /// Get the function type of this `Function`. - #[allow(dead_code)] - pub fn ty(&self) -> FunctionType { - FunctionType::new(Args::wasm_types(), Rets::wasm_types()) - } - - /// Get the address of this `Function`. - #[allow(dead_code)] - pub fn address(&self) -> *const VMFunctionBody { - self.address - } + /// Get the address of this `WasmFunction`. + #[allow(dead_code)] + pub fn address(&self) -> *const VMFunctionBody { + self.address } +} - macro_rules! impl_host_function { +macro_rules! impl_host_function { ( [$c_struct_representation:ident] $c_struct_name:ident, $( $x:ident ),* ) => { @@ -1245,8 +577,8 @@ mod inner { }; } - // Black-magic to count the number of identifiers at compile-time. - macro_rules! count_idents { +// Black-magic to count the number of identifiers at compile-time. +macro_rules! count_idents { ( $($idents:ident),* ) => { { #[allow(dead_code, non_camel_case_types)] @@ -1257,206 +589,32 @@ mod inner { }; } - // Here we go! Let's generate all the C struct, `WasmTypeList` - // implementations and `HostFunction` implementations. - impl_host_function!([C] S0,); - impl_host_function!([transparent] S1, A1); - impl_host_function!([C] S2, A1, A2); - impl_host_function!([C] S3, A1, A2, A3); - impl_host_function!([C] S4, A1, A2, A3, A4); - impl_host_function!([C] S5, A1, A2, A3, A4, A5); - impl_host_function!([C] S6, A1, A2, A3, A4, A5, A6); - impl_host_function!([C] S7, A1, A2, A3, A4, A5, A6, A7); - impl_host_function!([C] S8, A1, A2, A3, A4, A5, A6, A7, A8); - impl_host_function!([C] S9, A1, A2, A3, A4, A5, A6, A7, A8, A9); - impl_host_function!([C] S10, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10); - impl_host_function!([C] S11, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11); - impl_host_function!([C] S12, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12); - impl_host_function!([C] S13, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13); - impl_host_function!([C] S14, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14); - impl_host_function!([C] S15, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15); - impl_host_function!([C] S16, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16); - impl_host_function!([C] S17, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17); - impl_host_function!([C] S18, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18); - impl_host_function!([C] S19, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19); - impl_host_function!([C] S20, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20); - impl_host_function!([C] S21, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21); - impl_host_function!([C] S22, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22); - impl_host_function!([C] S23, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23); - impl_host_function!([C] S24, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24); - impl_host_function!([C] S25, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25); - impl_host_function!([C] S26, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25, A26); - - // Implement `WasmTypeList` on `Infallible`, which means that - // `Infallible` can be used as a returned type of a host function - // to express that it doesn't return, or to express that it cannot - // fail (with `Result<_, Infallible>`). - impl WasmTypeList for Infallible { - type CStruct = Self; - type Array = [RawValue; 0]; - - fn size() -> u32 { - 0 - } - - unsafe fn from_array(_: &mut impl AsStoreMut, _: Self::Array) -> Self { - unreachable!() - } - - unsafe fn from_slice( - _: &mut impl AsStoreMut, - _: &[RawValue], - ) -> Result { - unreachable!() - } - - unsafe fn into_array(self, _: &mut impl AsStoreMut) -> Self::Array { - [] - } - - fn empty_array() -> Self::Array { - [] - } - - unsafe fn from_c_struct(_: &mut impl AsStoreMut, self_: Self::CStruct) -> Self { - self_ - } - - unsafe fn into_c_struct(self, _: &mut impl AsStoreMut) -> Self::CStruct { - self - } - - unsafe fn write_c_struct_to_ptr(_: Self::CStruct, _: *mut RawValue) {} - - fn wasm_types() -> &'static [Type] { - &[] - } - } - - /* - #[cfg(test)] - mod test_wasm_type_list { - use super::*; - use wasmer_types::Type; - - fn test_from_array() { - assert_eq!(<()>::from_array([]), ()); - assert_eq!(::from_array([1]), (1i32)); - assert_eq!(<(i32, i64)>::from_array([1, 2]), (1i32, 2i64)); - assert_eq!( - <(i32, i64, f32, f64)>::from_array([ - 1, - 2, - (3.1f32).to_bits().into(), - (4.2f64).to_bits().into() - ]), - (1, 2, 3.1f32, 4.2f64) - ); - } - - fn test_into_array() { - assert_eq!(().into_array(), [0; 0]); - assert_eq!((1).into_array(), [1]); - assert_eq!((1i32, 2i64).into_array(), [1, 2]); - assert_eq!( - (1i32, 2i32, 3.1f32, 4.2f64).into_array(), - [1, 2, (3.1f32).to_bits().into(), (4.2f64).to_bits().into()] - ); - } - - fn test_empty_array() { - assert_eq!(<()>::empty_array().len(), 0); - assert_eq!(::empty_array().len(), 1); - assert_eq!(<(i32, i64)>::empty_array().len(), 2); - } - - fn test_from_c_struct() { - assert_eq!(<()>::from_c_struct(S0()), ()); - assert_eq!(::from_c_struct(S1(1)), (1i32)); - assert_eq!(<(i32, i64)>::from_c_struct(S2(1, 2)), (1i32, 2i64)); - assert_eq!( - <(i32, i64, f32, f64)>::from_c_struct(S4(1, 2, 3.1, 4.2)), - (1i32, 2i64, 3.1f32, 4.2f64) - ); - } - - fn test_wasm_types_for_uni_values() { - assert_eq!(::wasm_types(), [Type::I32]); - assert_eq!(::wasm_types(), [Type::I64]); - assert_eq!(::wasm_types(), [Type::F32]); - assert_eq!(::wasm_types(), [Type::F64]); - } - - fn test_wasm_types_for_multi_values() { - assert_eq!(<(i32, i32)>::wasm_types(), [Type::I32, Type::I32]); - assert_eq!(<(i64, i64)>::wasm_types(), [Type::I64, Type::I64]); - assert_eq!(<(f32, f32)>::wasm_types(), [Type::F32, Type::F32]); - assert_eq!(<(f64, f64)>::wasm_types(), [Type::F64, Type::F64]); - - assert_eq!( - <(i32, i64, f32, f64)>::wasm_types(), - [Type::I32, Type::I64, Type::F32, Type::F64] - ); - } - } - - #[allow(non_snake_case)] - #[cfg(test)] - mod test_function { - use super::*; - use wasmer_types::Type; - - fn func() {} - fn func__i32() -> i32 { - 0 - } - fn func_i32(_a: i32) {} - fn func_i32__i32(a: i32) -> i32 { - a * 2 - } - fn func_i32_i32__i32(a: i32, b: i32) -> i32 { - a + b - } - fn func_i32_i32__i32_i32(a: i32, b: i32) -> (i32, i32) { - (a, b) - } - fn func_f32_i32__i32_f32(a: f32, b: i32) -> (i32, f32) { - (b, a) - } - - fn test_function_types() { - assert_eq!(Function::new(func).ty(), FunctionType::new(vec![], vec![])); - assert_eq!( - Function::new(func__i32).ty(), - FunctionType::new(vec![], vec![Type::I32]) - ); - assert_eq!( - Function::new(func_i32).ty(), - FunctionType::new(vec![Type::I32], vec![]) - ); - assert_eq!( - Function::new(func_i32__i32).ty(), - FunctionType::new(vec![Type::I32], vec![Type::I32]) - ); - assert_eq!( - Function::new(func_i32_i32__i32).ty(), - FunctionType::new(vec![Type::I32, Type::I32], vec![Type::I32]) - ); - assert_eq!( - Function::new(func_i32_i32__i32_i32).ty(), - FunctionType::new(vec![Type::I32, Type::I32], vec![Type::I32, Type::I32]) - ); - assert_eq!( - Function::new(func_f32_i32__i32_f32).ty(), - FunctionType::new(vec![Type::F32, Type::I32], vec![Type::I32, Type::F32]) - ); - } - - fn test_function_pointer() { - let f = Function::new(func_i32__i32); - let function = unsafe { std::mem::transmute::<_, fn(usize, i32) -> i32>(f.address) }; - assert_eq!(function(0, 3), 6); - } - } - */ -} +// Here we go! Let's generate all the C struct, `WasmTypeList` +// implementations and `HostFunction` implementations. +impl_host_function!([C] S0,); +impl_host_function!([transparent] S1, A1); +impl_host_function!([C] S2, A1, A2); +impl_host_function!([C] S3, A1, A2, A3); +impl_host_function!([C] S4, A1, A2, A3, A4); +impl_host_function!([C] S5, A1, A2, A3, A4, A5); +impl_host_function!([C] S6, A1, A2, A3, A4, A5, A6); +impl_host_function!([C] S7, A1, A2, A3, A4, A5, A6, A7); +impl_host_function!([C] S8, A1, A2, A3, A4, A5, A6, A7, A8); +impl_host_function!([C] S9, A1, A2, A3, A4, A5, A6, A7, A8, A9); +impl_host_function!([C] S10, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10); +impl_host_function!([C] S11, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11); +impl_host_function!([C] S12, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12); +impl_host_function!([C] S13, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13); +impl_host_function!([C] S14, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14); +impl_host_function!([C] S15, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15); +impl_host_function!([C] S16, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16); +impl_host_function!([C] S17, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17); +impl_host_function!([C] S18, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18); +impl_host_function!([C] S19, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19); +impl_host_function!([C] S20, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20); +impl_host_function!([C] S21, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21); +impl_host_function!([C] S22, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22); +impl_host_function!([C] S23, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23); +impl_host_function!([C] S24, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24); +impl_host_function!([C] S25, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25); +impl_host_function!([C] S26, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25, A26); diff --git a/lib/api/src/js/externals/table.rs b/lib/api/src/js/externals/table.rs index 0562a42c128..cba4fc3909e 100644 --- a/lib/api/src/js/externals/table.rs +++ b/lib/api/src/js/externals/table.rs @@ -21,7 +21,7 @@ fn get_function(store: &mut impl AsStoreMut, val: Value) -> Result Ok(func.handle.function.clone().into()), + Value::FuncRef(Some(ref func)) => Ok(func.0.handle.function.clone().into()), // Only funcrefs is supported by the spec atm _ => unimplemented!(), } diff --git a/lib/api/src/js/typed_function.rs b/lib/api/src/js/typed_function.rs index 71faffa1c24..2c52350a0a1 100644 --- a/lib/api/src/js/typed_function.rs +++ b/lib/api/src/js/typed_function.rs @@ -45,7 +45,7 @@ macro_rules! impl_native_traits { let mut r; // TODO: This loop is needed for asyncify. It will be refactored with https://github.com/wasmerio/wasmer/issues/3451 loop { - r = self.func.handle.function.apply( + r = self.func.0.handle.function.apply( &JsValue::UNDEFINED, &Array::from_iter(params_list.iter()) ); diff --git a/lib/api/src/js/vm.rs b/lib/api/src/js/vm.rs index d27e1728471..09288349922 100644 --- a/lib/api/src/js/vm.rs +++ b/lib/api/src/js/vm.rs @@ -252,6 +252,8 @@ impl VMFuncRef { } } +pub struct VMTrampoline; + pub(crate) type VMExternTable = VMTable; pub(crate) type VMExternMemory = VMMemory; pub(crate) type VMExternGlobal = VMGlobal; diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index 4e0207b445b..366363977ea 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -459,10 +459,7 @@ mod js; #[cfg(feature = "js")] pub use js::*; -pub use crate::externals::{ - Extern, FromToNativeWasmType, Function, Global, HostFunction, Memory, MemoryView, Table, - WasmTypeList, -}; +pub use crate::externals::{Extern, Function, Global, HostFunction, Memory, MemoryView, Table}; pub use engine::{AsEngineRef, Engine}; pub use errors::InstantiationError; pub use exports::{ExportError, Exportable, Exports, ExportsIterator}; @@ -473,7 +470,7 @@ pub use instance::Instance; pub use into_bytes::IntoBytes; pub use mem_access::{MemoryAccessError, WasmRef, WasmSlice, WasmSliceIter}; pub use module::{IoCompileError, Module}; -pub use native_type::NativeWasmTypeInto; +pub use native_type::{FromToNativeWasmType, NativeWasmTypeInto, WasmTypeList}; pub use ptr::{Memory32, Memory64, MemorySize, WasmPtr, WasmPtr64}; pub use store::{AsStoreMut, AsStoreRef, OnCalledHandler, Store, StoreId, StoreMut, StoreRef}; #[cfg(feature = "sys")] diff --git a/lib/api/src/native_type.rs b/lib/api/src/native_type.rs index 2350f103861..4612fe6d4e5 100644 --- a/lib/api/src/native_type.rs +++ b/lib/api/src/native_type.rs @@ -3,9 +3,13 @@ use wasmer_types::{NativeWasmType, RawValue, Type}; +use crate::store::AsStoreRef; use crate::vm::{VMExternRef, VMFuncRef}; -use crate::{ExternRef, Function, TypedFunction, WasmTypeList}; +use crate::{ExternRef, Function, TypedFunction}; +use std::array::TryFromSliceError; +use std::convert::Infallible; +use std::error::Error; use crate::store::AsStoreMut; @@ -205,6 +209,508 @@ impl NativeWasmTypeInto for Option { } } +/// A trait to convert a Rust value to a `WasmNativeType` value, +/// or to convert `WasmNativeType` value to a Rust value. +/// +/// This trait should ideally be split into two traits: +/// `FromNativeWasmType` and `ToNativeWasmType` but it creates a +/// non-negligible complexity in the `WasmTypeList` +/// implementation. +/// +/// # Safety +/// This trait is unsafe given the nature of how values are written and read from the native +/// stack +pub unsafe trait FromToNativeWasmType +where + Self: Sized, +{ + /// Native Wasm type. + type Native: NativeWasmTypeInto; + + /// Convert a value of kind `Self::Native` to `Self`. + /// + /// # Panics + /// + /// This method panics if `native` cannot fit in the `Self` + /// type`. + fn from_native(native: Self::Native) -> Self; + + /// Convert self to `Self::Native`. + /// + /// # Panics + /// + /// This method panics if `self` cannot fit in the + /// `Self::Native` type. + fn to_native(self) -> Self::Native; + + /// Returns whether the given value is from the given store. + /// + /// This always returns true for primitive types that can be used with + /// any context. + fn is_from_store(&self, _store: &impl AsStoreRef) -> bool { + true + } +} + +macro_rules! from_to_native_wasm_type { + ( $( $type:ty => $native_type:ty ),* ) => { + $( + #[allow(clippy::use_self)] + unsafe impl FromToNativeWasmType for $type { + type Native = $native_type; + + #[inline] + fn from_native(native: Self::Native) -> Self { + native as Self + } + + #[inline] + fn to_native(self) -> Self::Native { + self as Self::Native + } + } + )* + }; +} + +macro_rules! from_to_native_wasm_type_same_size { + ( $( $type:ty => $native_type:ty ),* ) => { + $( + #[allow(clippy::use_self)] + unsafe impl FromToNativeWasmType for $type { + type Native = $native_type; + + #[inline] + fn from_native(native: Self::Native) -> Self { + Self::from_ne_bytes(Self::Native::to_ne_bytes(native)) + } + + #[inline] + fn to_native(self) -> Self::Native { + Self::Native::from_ne_bytes(Self::to_ne_bytes(self)) + } + } + )* + }; +} + +from_to_native_wasm_type!( + i8 => i32, + u8 => i32, + i16 => i32, + u16 => i32 +); + +from_to_native_wasm_type_same_size!( + i32 => i32, + u32 => i32, + i64 => i64, + u64 => i64, + f32 => f32, + f64 => f64 +); + +unsafe impl FromToNativeWasmType for Option { + type Native = Self; + + fn to_native(self) -> Self::Native { + self + } + fn from_native(n: Self::Native) -> Self { + n + } + fn is_from_store(&self, store: &impl AsStoreRef) -> bool { + self.as_ref().map_or(true, |e| e.is_from_store(store)) + } +} + +unsafe impl FromToNativeWasmType for Option { + type Native = Self; + + fn to_native(self) -> Self::Native { + self + } + fn from_native(n: Self::Native) -> Self { + n + } + fn is_from_store(&self, store: &impl AsStoreRef) -> bool { + self.as_ref().map_or(true, |f| f.is_from_store(store)) + } +} + +#[cfg(test)] +mod test_from_to_native_wasm_type { + use super::*; + + #[test] + fn test_to_native() { + assert_eq!(7i8.to_native(), 7i32); + assert_eq!(7u8.to_native(), 7i32); + assert_eq!(7i16.to_native(), 7i32); + assert_eq!(7u16.to_native(), 7i32); + assert_eq!(u32::MAX.to_native(), -1); + } + + #[test] + fn test_to_native_same_size() { + assert_eq!(7i32.to_native(), 7i32); + assert_eq!(7u32.to_native(), 7i32); + assert_eq!(7i64.to_native(), 7i64); + assert_eq!(7u64.to_native(), 7i64); + assert_eq!(7f32.to_native(), 7f32); + assert_eq!(7f64.to_native(), 7f64); + } +} + +/// The `WasmTypeList` trait represents a tuple (list) of Wasm +/// typed values. It is used to get low-level representation of +/// such a tuple. +pub trait WasmTypeList +where + Self: Sized, +{ + /// The C type (a struct) that can hold/represent all the + /// represented values. + type CStruct; + + /// The array type that can hold all the represented values. + /// + /// Note that all values are stored in their binary form. + type Array: AsMut<[RawValue]>; + + /// The size of the array + fn size() -> u32; + + /// Constructs `Self` based on an array of values. + /// + /// # Safety + unsafe fn from_array(store: &mut impl AsStoreMut, array: Self::Array) -> Self; + + /// Constructs `Self` based on a slice of values. + /// + /// `from_slice` returns a `Result` because it is possible + /// that the slice doesn't have the same size than + /// `Self::Array`, in which circumstance an error of kind + /// `TryFromSliceError` will be returned. + /// + /// # Safety + unsafe fn from_slice( + store: &mut impl AsStoreMut, + slice: &[RawValue], + ) -> Result; + + /// Builds and returns an array of type `Array` from a tuple + /// (list) of values. + /// + /// # Safety + unsafe fn into_array(self, store: &mut impl AsStoreMut) -> Self::Array; + + /// Allocates and return an empty array of type `Array` that + /// will hold a tuple (list) of values, usually to hold the + /// returned values of a WebAssembly function call. + fn empty_array() -> Self::Array; + + /// Builds a tuple (list) of values from a C struct of type + /// `CStruct`. + /// + /// # Safety + unsafe fn from_c_struct(store: &mut impl AsStoreMut, c_struct: Self::CStruct) -> Self; + + /// Builds and returns a C struct of type `CStruct` from a + /// tuple (list) of values. + /// + /// # Safety + unsafe fn into_c_struct(self, store: &mut impl AsStoreMut) -> Self::CStruct; + + /// Writes the contents of a C struct to an array of `RawValue`. + /// + /// # Safety + unsafe fn write_c_struct_to_ptr(c_struct: Self::CStruct, ptr: *mut RawValue); + + /// Get the Wasm types for the tuple (list) of currently + /// represented values. + fn wasm_types() -> &'static [Type]; +} + +/// The `IntoResult` trait turns a `WasmTypeList` into a +/// `Result`. +/// +/// It is mostly used to turn result values of a Wasm function +/// call into a `Result`. +pub trait IntoResult +where + T: WasmTypeList, +{ + /// The error type for this trait. + type Error: Error + Sync + Send + 'static; + + /// Transforms `Self` into a `Result`. + fn into_result(self) -> Result; +} + +impl IntoResult for T +where + T: WasmTypeList, +{ + // `T` is not a `Result`, it's already a value, so no error + // can be built. + type Error = Infallible; + + fn into_result(self) -> Result { + Ok(self) + } +} + +impl IntoResult for Result +where + T: WasmTypeList, + E: Error + Sync + Send + 'static, +{ + type Error = E; + + fn into_result(self) -> Self { + self + } +} + +#[cfg(test)] +mod test_into_result { + use super::*; + use std::convert::Infallible; + + #[test] + fn test_into_result_over_t() { + let x: i32 = 42; + let result_of_x: Result = x.into_result(); + + assert_eq!(result_of_x.unwrap(), x); + } + + #[test] + fn test_into_result_over_result() { + { + let x: Result = Ok(42); + let result_of_x: Result = x.into_result(); + + assert_eq!(result_of_x, x); + } + + { + use std::{error, fmt}; + + #[derive(Debug, PartialEq)] + struct E; + + impl fmt::Display for E { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(formatter, "E") + } + } + + impl error::Error for E {} + + let x: Result = Err(E); + let result_of_x: Result = x.into_result(); + + assert_eq!(result_of_x.unwrap_err(), E); + } + } +} + +// Implement `WasmTypeList` on `Infallible`, which means that +// `Infallible` can be used as a returned type of a host function +// to express that it doesn't return, or to express that it cannot +// fail (with `Result<_, Infallible>`). +impl WasmTypeList for Infallible { + type CStruct = Self; + type Array = [RawValue; 0]; + + fn size() -> u32 { + 0 + } + + unsafe fn from_array(_: &mut impl AsStoreMut, _: Self::Array) -> Self { + unreachable!() + } + + unsafe fn from_slice( + _: &mut impl AsStoreMut, + _: &[RawValue], + ) -> Result { + unreachable!() + } + + unsafe fn into_array(self, _: &mut impl AsStoreMut) -> Self::Array { + [] + } + + fn empty_array() -> Self::Array { + [] + } + + unsafe fn from_c_struct(_: &mut impl AsStoreMut, self_: Self::CStruct) -> Self { + self_ + } + + unsafe fn into_c_struct(self, _: &mut impl AsStoreMut) -> Self::CStruct { + self + } + + unsafe fn write_c_struct_to_ptr(_: Self::CStruct, _: *mut RawValue) {} + + fn wasm_types() -> &'static [Type] { + &[] + } +} + +#[cfg(test)] +mod test_wasm_type_list { + use super::*; + use wasmer_types::Type; + /* + #[test] + fn test_from_array() { + let mut store = Store::default(); + let env = FunctionEnv::new(&mut store, ()); + assert_eq!(<()>::from_array(&mut env, []), ()); + assert_eq!(::from_array(&mut env, [RawValue{i32: 1}]), (1i32)); + assert_eq!(<(i32, i64)>::from_array(&mut env, [RawValue{i32:1}, RawValue{i64:2}]), (1i32, 2i64)); + assert_eq!( + <(i32, i64, f32, f64)>::from_array(&mut env, [ + RawValue{i32:1}, + RawValue{i64:2}, + RawValue{f32: 3.1f32}, + RawValue{f64: 4.2f64} + ]), + (1, 2, 3.1f32, 4.2f64) + ); + } + + #[test] + fn test_into_array() { + let mut store = Store::default(); + let env = FunctionEnv::new(&mut store, ()); + assert_eq!(().into_array(&mut store), [0i128; 0]); + assert_eq!((1i32).into_array(&mut store), [1i32]); + assert_eq!((1i32, 2i64).into_array(&mut store), [RawValue{i32: 1}, RawValue{i64: 2}]); + assert_eq!( + (1i32, 2i32, 3.1f32, 4.2f64).into_array(&mut store), + [RawValue{i32: 1}, RawValue{i32: 2}, RawValue{ f32: 3.1f32}, RawValue{f64: 4.2f64}] + ); + } + */ + #[test] + fn test_empty_array() { + assert_eq!(<()>::empty_array().len(), 0); + assert_eq!(::empty_array().len(), 1); + assert_eq!(<(i32, i64)>::empty_array().len(), 2); + } + /* + #[test] + fn test_from_c_struct() { + let mut store = Store::default(); + let env = FunctionEnv::new(&mut store, ()); + assert_eq!(<()>::from_c_struct(&mut store, S0()), ()); + assert_eq!(::from_c_struct(&mut store, S1(1)), (1i32)); + assert_eq!(<(i32, i64)>::from_c_struct(&mut store, S2(1, 2)), (1i32, 2i64)); + assert_eq!( + <(i32, i64, f32, f64)>::from_c_struct(&mut store, S4(1, 2, 3.1, 4.2)), + (1i32, 2i64, 3.1f32, 4.2f64) + ); + } + */ + #[test] + fn test_wasm_types_for_uni_values() { + assert_eq!(::wasm_types(), [Type::I32]); + assert_eq!(::wasm_types(), [Type::I64]); + assert_eq!(::wasm_types(), [Type::F32]); + assert_eq!(::wasm_types(), [Type::F64]); + } + + #[test] + fn test_wasm_types_for_multi_values() { + assert_eq!(<(i32, i32)>::wasm_types(), [Type::I32, Type::I32]); + assert_eq!(<(i64, i64)>::wasm_types(), [Type::I64, Type::I64]); + assert_eq!(<(f32, f32)>::wasm_types(), [Type::F32, Type::F32]); + assert_eq!(<(f64, f64)>::wasm_types(), [Type::F64, Type::F64]); + + assert_eq!( + <(i32, i64, f32, f64)>::wasm_types(), + [Type::I32, Type::I64, Type::F32, Type::F64] + ); + } +} +/* + #[allow(non_snake_case)] + #[cfg(test)] + mod test_function { + use super::*; + use crate::Store; + use crate::FunctionEnv; + use wasmer_types::Type; + + fn func() {} + fn func__i32() -> i32 { + 0 + } + fn func_i32( _a: i32) {} + fn func_i32__i32( a: i32) -> i32 { + a * 2 + } + fn func_i32_i32__i32( a: i32, b: i32) -> i32 { + a + b + } + fn func_i32_i32__i32_i32( a: i32, b: i32) -> (i32, i32) { + (a, b) + } + fn func_f32_i32__i32_f32( a: f32, b: i32) -> (i32, f32) { + (b, a) + } + + #[test] + fn test_function_types() { + let mut store = Store::default(); + let env = FunctionEnv::new(&mut store, ()); + use wasmer_types::FunctionType; + assert_eq!( + StaticFunction::new(func).ty(&mut store), + FunctionType::new(vec![], vec![]) + ); + assert_eq!( + StaticFunction::new(func__i32).ty(&mut store), + FunctionType::new(vec![], vec![Type::I32]) + ); + assert_eq!( + StaticFunction::new(func_i32).ty(), + FunctionType::new(vec![Type::I32], vec![]) + ); + assert_eq!( + StaticFunction::new(func_i32__i32).ty(), + FunctionType::new(vec![Type::I32], vec![Type::I32]) + ); + assert_eq!( + StaticFunction::new(func_i32_i32__i32).ty(), + FunctionType::new(vec![Type::I32, Type::I32], vec![Type::I32]) + ); + assert_eq!( + StaticFunction::new(func_i32_i32__i32_i32).ty(), + FunctionType::new(vec![Type::I32, Type::I32], vec![Type::I32, Type::I32]) + ); + assert_eq!( + StaticFunction::new(func_f32_i32__i32_f32).ty(), + FunctionType::new(vec![Type::F32, Type::I32], vec![Type::I32, Type::F32]) + ); + } + + #[test] + fn test_function_pointer() { + let f = StaticFunction::new(func_i32__i32); + let function = unsafe { std::mem::transmute::<_, fn(usize, i32) -> i32>(f.address) }; + assert_eq!(function(0, 3), 6); + } + } +*/ + #[cfg(test)] mod test_native_type { use super::*; diff --git a/lib/api/src/sys/externals/function.rs b/lib/api/src/sys/externals/function.rs index 577f9f5a262..918737489d2 100644 --- a/lib/api/src/sys/externals/function.rs +++ b/lib/api/src/sys/externals/function.rs @@ -1,48 +1,19 @@ -use wasmer_types::RawValue; -pub use wasmer_vm::VMFuncRef; -use wasmer_vm::{ - on_host_stack, raise_user_trap, resume_panic, StoreHandle, VMContext, VMDynamicFunctionContext, - VMExtern, VMFunction, VMFunctionBody, VMFunctionKind, VMTrampoline, -}; - -use crate::exports::{ExportError, Exportable}; -use crate::store::{AsStoreMut, AsStoreRef}; +use crate::externals::function::{HostFunction, WithEnv, WithoutEnv}; +use crate::native_type::{FromToNativeWasmType, IntoResult, NativeWasmTypeInto, WasmTypeList}; +use crate::store::{AsStoreMut, AsStoreRef, StoreInner, StoreMut}; use crate::vm::VMExternFunction; -use crate::Extern; -use crate::FunctionEnv; -use crate::{FunctionType, RuntimeError, TypedFunction}; - -pub use inner::{FromToNativeWasmType, HostFunction, WasmTypeList, WithEnv, WithoutEnv}; - -use { - crate::{ - store::{StoreInner, StoreMut}, - FunctionEnvMut, Value, - }, - inner::StaticFunction, - std::{cell::UnsafeCell, cmp::max, ffi::c_void}, - wasmer_vm::{ - wasmer_call_trampoline, MaybeInstanceOwned, VMCallerCheckedAnyfunc, VMFunctionContext, - }, +use crate::{FunctionEnv, FunctionEnvMut, FunctionType, RuntimeError, Value}; +use std::array::TryFromSliceError; +use std::convert::TryInto; +use std::panic::{self, AssertUnwindSafe}; +use std::{cell::UnsafeCell, cmp::max, ffi::c_void}; +use wasmer_types::{NativeWasmType, RawValue, Type}; +use wasmer_vm::{ + on_host_stack, raise_user_trap, resume_panic, wasmer_call_trampoline, MaybeInstanceOwned, + StoreHandle, VMCallerCheckedAnyfunc, VMContext, VMDynamicFunctionContext, VMExtern, VMFuncRef, + VMFunction, VMFunctionBody, VMFunctionContext, VMFunctionKind, VMTrampoline, }; -/// A WebAssembly `function` instance. -/// -/// A function instance is the runtime representation of a function. -/// It effectively is a closure of the original function (defined in either -/// the host or the WebAssembly module) over the runtime `Instance` of its -/// originating `Module`. -/// -/// The module instance is used to resolve references to other definitions -/// during execution of the function. -/// -/// Spec: -/// -/// # Panics -/// - Closures (functions with captured environments) are not currently supported -/// with native functions. Attempting to create a native `Function` with one will -/// result in a panic. -/// [Closures as host functions tracking issue](https://github.com/wasmerio/wasmer/issues/1840) #[derive(Debug, Clone)] pub struct Function { pub(crate) handle: StoreHandle, @@ -55,59 +26,6 @@ impl From> for Function { } impl Function { - /// Creates a new host `Function` (dynamic) with the provided signature. - /// - /// If you know the signature of the host function at compile time, - /// consider using [`Function::new_typed`] for less runtime overhead. - pub fn new(store: &mut impl AsStoreMut, ty: FT, func: F) -> Self - where - FT: Into, - F: Fn(&[Value]) -> Result, RuntimeError> + 'static + Send + Sync, - { - let env = FunctionEnv::new(&mut store.as_store_mut(), ()); - let wrapped_func = move |_env: FunctionEnvMut<()>, - args: &[Value]| - -> Result, RuntimeError> { func(args) }; - Self::new_with_env(store, &env, ty, wrapped_func) - } - - /// Creates a new host `Function` (dynamic) with the provided signature. - /// - /// If you know the signature of the host function at compile time, - /// consider using [`Function::new_typed_with_env`] for less runtime overhead. - /// - /// Takes a [`FunctionEnv`] that is passed into func. If that is not required, - /// [`Function::new`] might be an option as well. - /// - /// # Examples - /// - /// ``` - /// # use wasmer::{Function, FunctionEnv, FunctionType, Type, Store, Value}; - /// # let mut store = Store::default(); - /// # let env = FunctionEnv::new(&mut store, ()); - /// # - /// let signature = FunctionType::new(vec![Type::I32, Type::I32], vec![Type::I32]); - /// - /// let f = Function::new_with_env(&mut store, &env, &signature, |_env, args| { - /// let sum = args[0].unwrap_i32() + args[1].unwrap_i32(); - /// Ok(vec![Value::I32(sum)]) - /// }); - /// ``` - /// - /// With constant signature: - /// - /// ``` - /// # use wasmer::{Function, FunctionEnv, FunctionType, Type, Store, Value}; - /// # let mut store = Store::default(); - /// # let env = FunctionEnv::new(&mut store, ()); - /// # - /// const I32_I32_TO_I32: ([Type; 2], [Type; 1]) = ([Type::I32, Type::I32], [Type::I32]); - /// - /// let f = Function::new_with_env(&mut store, &env, I32_I32_TO_I32, |_env, args| { - /// let sum = args[0].unwrap_i32() + args[1].unwrap_i32(); - /// Ok(vec![Value::I32(sum)]) - /// }); - /// ``` pub fn new_with_env( store: &mut impl AsStoreMut, env: &FunctionEnv, @@ -191,20 +109,6 @@ impl Function { } } - #[deprecated( - since = "3.0.0", - note = "new_native() has been renamed to new_typed()." - )] - /// Creates a new host `Function` from a native function. - pub fn new_native(store: &mut impl AsStoreMut, func: F) -> Self - where - F: HostFunction<(), Args, Rets, WithoutEnv> + 'static + Send + Sync, - Args: WasmTypeList, - Rets: WasmTypeList, - { - Self::new_typed(store, func) - } - /// Creates a new host `Function` from a native function. pub fn new_typed(store: &mut impl AsStoreMut, func: F) -> Self where @@ -248,42 +152,6 @@ impl Function { } } - #[deprecated( - since = "3.0.0", - note = "new_native_with_env() has been renamed to new_typed_with_env()." - )] - /// Creates a new host `Function` with an environment from a native function. - pub fn new_native_with_env( - store: &mut impl AsStoreMut, - env: &FunctionEnv, - func: F, - ) -> Self - where - F: HostFunction + 'static + Send + Sync, - Args: WasmTypeList, - Rets: WasmTypeList, - { - Self::new_typed_with_env(store, env, func) - } - - /// Creates a new host `Function` with an environment from a typed function. - /// - /// The function signature is automatically retrieved using the - /// Rust typing system. - /// - /// # Example - /// - /// ``` - /// # use wasmer::{Store, Function, FunctionEnv, FunctionEnvMut}; - /// # let mut store = Store::default(); - /// # let env = FunctionEnv::new(&mut store, ()); - /// # - /// fn sum(_env: FunctionEnvMut<()>, a: i32, b: i32) -> i32 { - /// a + b - /// } - /// - /// let f = Function::new_typed_with_env(&mut store, &env, sum); - /// ``` pub fn new_typed_with_env( store: &mut impl AsStoreMut, env: &FunctionEnv, @@ -294,8 +162,6 @@ impl Function { Args: WasmTypeList, Rets: WasmTypeList, { - // println!("new native {:p}", &new_env); - let func_ptr = func.function_body_ptr(); let host_data = Box::new(StaticFunction { raw_store: store.as_store_mut().as_raw() as *mut u8, @@ -331,24 +197,6 @@ impl Function { } } - /// Returns the [`FunctionType`] of the `Function`. - /// - /// # Example - /// - /// ``` - /// # use wasmer::{Function, FunctionEnv, FunctionEnvMut, Store, Type}; - /// # let mut store = Store::default(); - /// # let env = FunctionEnv::new(&mut store, ()); - /// # - /// fn sum(_env: FunctionEnvMut<()>, a: i32, b: i32) -> i32 { - /// a + b - /// } - /// - /// let f = Function::new_typed_with_env(&mut store, &env, sum); - /// - /// assert_eq!(f.ty(&mut store).params(), vec![Type::I32, Type::I32]); - /// assert_eq!(f.ty(&mut store).results(), vec![Type::I32]); - /// ``` pub fn ty(&self, store: &impl AsStoreRef) -> FunctionType { self.handle .get(store.as_store_ref().objects()) @@ -466,79 +314,10 @@ impl Function { Ok(()) } - /// Returns the number of parameters that this function takes. - /// - /// # Example - /// - /// ``` - /// # use wasmer::{Function, FunctionEnv, FunctionEnvMut, Store, Type}; - /// # let mut store = Store::default(); - /// # let env = FunctionEnv::new(&mut store, ()); - /// # - /// fn sum(_env: FunctionEnvMut<()>, a: i32, b: i32) -> i32 { - /// a + b - /// } - /// - /// let f = Function::new_typed_with_env(&mut store, &env, sum); - /// - /// assert_eq!(f.param_arity(&mut store), 2); - /// ``` - pub fn param_arity(&self, store: &impl AsStoreRef) -> usize { - self.ty(store).params().len() - } - - /// Returns the number of results this function produces. - /// - /// # Example - /// - /// ``` - /// # use wasmer::{Function, FunctionEnv, FunctionEnvMut, Store, Type}; - /// # let mut store = Store::default(); - /// # let env = FunctionEnv::new(&mut store, ()); - /// # - /// fn sum(_env: FunctionEnvMut<()>, a: i32, b: i32) -> i32 { - /// a + b - /// } - /// - /// let f = Function::new_typed_with_env(&mut store, &env, sum); - /// - /// assert_eq!(f.result_arity(&mut store), 1); - /// ``` pub fn result_arity(&self, store: &impl AsStoreRef) -> usize { self.ty(store).results().len() } - /// Call the `Function` function. - /// - /// Depending on where the Function is defined, it will call it. - /// 1. If the function is defined inside a WebAssembly, it will call the trampoline - /// for the function signature. - /// 2. If the function is defined in the host (in a native way), it will - /// call the trampoline. - /// - /// # Examples - /// - /// ``` - /// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value}; - /// # use wasmer::FunctionEnv; - /// # let mut store = Store::default(); - /// # let env = FunctionEnv::new(&mut store, ()); - /// # let wasm_bytes = wat2wasm(r#" - /// # (module - /// # (func (export "sum") (param $x i32) (param $y i32) (result i32) - /// # local.get $x - /// # local.get $y - /// # i32.add - /// # )) - /// # "#.as_bytes()).unwrap(); - /// # let module = Module::new(&store, wasm_bytes).unwrap(); - /// # let import_object = imports! {}; - /// # let instance = Instance::new(&mut store, &module, &import_object).unwrap(); - /// # - /// let sum = instance.exports.get_function("sum").unwrap(); - /// - /// assert_eq!(sum.call(&mut store, &[Value::I32(1), Value::I32(2)]).unwrap().to_vec(), vec![Value::I32(3)]); - /// ``` pub fn call( &self, store: &mut impl AsStoreMut, @@ -604,142 +383,6 @@ impl Function { } } - /// Transform this WebAssembly function into a native function. - /// See [`TypedFunction`] to learn more. - #[deprecated(since = "3.0.0", note = "native() has been renamed to typed().")] - pub fn native( - &self, - store: &impl AsStoreRef, - ) -> Result, RuntimeError> - where - Args: WasmTypeList, - Rets: WasmTypeList, - { - self.typed(store) - } - - /// Transform this WebAssembly function into a typed function. - /// See [`TypedFunction`] to learn more. - /// - /// # Examples - /// - /// ``` - /// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, TypedFunction, Value}; - /// # use wasmer::FunctionEnv; - /// # let mut store = Store::default(); - /// # let env = FunctionEnv::new(&mut store, ()); - /// # let wasm_bytes = wat2wasm(r#" - /// # (module - /// # (func (export "sum") (param $x i32) (param $y i32) (result i32) - /// # local.get $x - /// # local.get $y - /// # i32.add - /// # )) - /// # "#.as_bytes()).unwrap(); - /// # let module = Module::new(&store, wasm_bytes).unwrap(); - /// # let import_object = imports! {}; - /// # let instance = Instance::new(&mut store, &module, &import_object).unwrap(); - /// # - /// let sum = instance.exports.get_function("sum").unwrap(); - /// let sum_typed: TypedFunction<(i32, i32), i32> = sum.typed(&mut store).unwrap(); - /// - /// assert_eq!(sum_typed.call(&mut store, 1, 2).unwrap(), 3); - /// ``` - /// - /// # Errors - /// - /// If the `Args` generic parameter does not match the exported function - /// an error will be raised: - /// - /// ```should_panic - /// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, TypedFunction, Value}; - /// # use wasmer::FunctionEnv; - /// # let mut store = Store::default(); - /// # let env = FunctionEnv::new(&mut store, ()); - /// # let wasm_bytes = wat2wasm(r#" - /// # (module - /// # (func (export "sum") (param $x i32) (param $y i32) (result i32) - /// # local.get $x - /// # local.get $y - /// # i32.add - /// # )) - /// # "#.as_bytes()).unwrap(); - /// # let module = Module::new(&store, wasm_bytes).unwrap(); - /// # let import_object = imports! {}; - /// # let instance = Instance::new(&mut store, &module, &import_object).unwrap(); - /// # - /// let sum = instance.exports.get_function("sum").unwrap(); - /// - /// // This results in an error: `RuntimeError` - /// let sum_typed : TypedFunction<(i64, i64), i32> = sum.typed(&mut store).unwrap(); - /// ``` - /// - /// If the `Rets` generic parameter does not match the exported function - /// an error will be raised: - /// - /// ```should_panic - /// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, TypedFunction, Value}; - /// # use wasmer::FunctionEnv; - /// # let mut store = Store::default(); - /// # let env = FunctionEnv::new(&mut store, ()); - /// # let wasm_bytes = wat2wasm(r#" - /// # (module - /// # (func (export "sum") (param $x i32) (param $y i32) (result i32) - /// # local.get $x - /// # local.get $y - /// # i32.add - /// # )) - /// # "#.as_bytes()).unwrap(); - /// # let module = Module::new(&store, wasm_bytes).unwrap(); - /// # let import_object = imports! {}; - /// # let instance = Instance::new(&mut store, &module, &import_object).unwrap(); - /// # - /// let sum = instance.exports.get_function("sum").unwrap(); - /// - /// // This results in an error: `RuntimeError` - /// let sum_typed: TypedFunction<(i32, i32), i64> = sum.typed(&mut store).unwrap(); - /// ``` - pub fn typed( - &self, - store: &impl AsStoreRef, - ) -> Result, RuntimeError> - where - Args: WasmTypeList, - Rets: WasmTypeList, - { - let ty = self.ty(store); - - // type check - { - let expected = ty.params(); - let given = Args::wasm_types(); - - if expected != given { - return Err(RuntimeError::new(format!( - "given types (`{:?}`) for the function arguments don't match the actual types (`{:?}`)", - given, - expected, - ))); - } - } - - { - let expected = ty.results(); - let given = Rets::wasm_types(); - - if expected != given { - // todo: error result types don't match - return Err(RuntimeError::new(format!( - "given types (`{:?}`) for the function results don't match the actual types (`{:?}`)", - given, - expected, - ))); - } - } - - Ok(TypedFunction::new(store, self.clone())) - } - pub(crate) fn from_vm_extern(store: &mut impl AsStoreMut, vm_extern: VMExternFunction) -> Self { Self { handle: unsafe { @@ -758,15 +401,6 @@ impl Function { } } -impl<'a> Exportable<'a> for Function { - fn get_self_from_extern(_extern: &'a Extern) -> Result<&'a Self, ExportError> { - match _extern { - Extern::Function(func) => Ok(func), - _ => Err(ExportError::IncompatibleType), - } - } -} - /// Host state for a dynamic function. pub(crate) struct DynamicFunction { func: F, @@ -782,8 +416,6 @@ where this: &mut VMDynamicFunctionContext, values_vec: *mut RawValue, ) { - use std::panic::{self, AssertUnwindSafe}; - let result = on_host_stack(|| panic::catch_unwind(AssertUnwindSafe(|| (this.ctx.func)(values_vec)))); @@ -814,391 +446,16 @@ where } } -/// This private inner module contains the low-level implementation -/// for `Function` and its siblings. -mod inner { - use std::array::TryFromSliceError; - use std::convert::{Infallible, TryInto}; - use std::error::Error; - use std::panic::{self, AssertUnwindSafe}; - use wasmer_vm::{on_host_stack, VMContext, VMTrampoline}; - - use crate::function_env::FunctionEnvMut; - use wasmer_types::{NativeWasmType, RawValue, Type}; - use wasmer_vm::{raise_user_trap, resume_panic, VMFunctionBody}; - - use crate::native_type::NativeWasmTypeInto; - use crate::store::{AsStoreMut, AsStoreRef, StoreMut}; - use crate::{ExternRef, FunctionEnv}; - - use crate::Function; - - /// A trait to convert a Rust value to a `WasmNativeType` value, - /// or to convert `WasmNativeType` value to a Rust value. - /// - /// This trait should ideally be split into two traits: - /// `FromNativeWasmType` and `ToNativeWasmType` but it creates a - /// non-negligible complexity in the `WasmTypeList` - /// implementation. - /// - /// # Safety - /// This trait is unsafe given the nature of how values are written and read from the native - /// stack - pub unsafe trait FromToNativeWasmType - where - Self: Sized, - { - /// Native Wasm type. - type Native: NativeWasmTypeInto; - - /// Convert a value of kind `Self::Native` to `Self`. - /// - /// # Panics - /// - /// This method panics if `native` cannot fit in the `Self` - /// type`. - fn from_native(native: Self::Native) -> Self; - - /// Convert self to `Self::Native`. - /// - /// # Panics - /// - /// This method panics if `self` cannot fit in the - /// `Self::Native` type. - fn to_native(self) -> Self::Native; - - /// Returns whether the given value is from the given store. - /// - /// This always returns true for primitive types that can be used with - /// any context. - fn is_from_store(&self, _store: &impl AsStoreRef) -> bool { - true - } - } - - macro_rules! from_to_native_wasm_type { - ( $( $type:ty => $native_type:ty ),* ) => { - $( - #[allow(clippy::use_self)] - unsafe impl FromToNativeWasmType for $type { - type Native = $native_type; - - #[inline] - fn from_native(native: Self::Native) -> Self { - native as Self - } - - #[inline] - fn to_native(self) -> Self::Native { - self as Self::Native - } - } - )* - }; - } - - macro_rules! from_to_native_wasm_type_same_size { - ( $( $type:ty => $native_type:ty ),* ) => { - $( - #[allow(clippy::use_self)] - unsafe impl FromToNativeWasmType for $type { - type Native = $native_type; - - #[inline] - fn from_native(native: Self::Native) -> Self { - Self::from_ne_bytes(Self::Native::to_ne_bytes(native)) - } - - #[inline] - fn to_native(self) -> Self::Native { - Self::Native::from_ne_bytes(Self::to_ne_bytes(self)) - } - } - )* - }; - } - - from_to_native_wasm_type!( - i8 => i32, - u8 => i32, - i16 => i32, - u16 => i32 - ); - - from_to_native_wasm_type_same_size!( - i32 => i32, - u32 => i32, - i64 => i64, - u64 => i64, - f32 => f32, - f64 => f64 - ); - - unsafe impl FromToNativeWasmType for Option { - type Native = Self; - - fn to_native(self) -> Self::Native { - self - } - fn from_native(n: Self::Native) -> Self { - n - } - fn is_from_store(&self, store: &impl AsStoreRef) -> bool { - self.as_ref().map_or(true, |e| e.is_from_store(store)) - } - } - - unsafe impl FromToNativeWasmType for Option { - type Native = Self; - - fn to_native(self) -> Self::Native { - self - } - fn from_native(n: Self::Native) -> Self { - n - } - fn is_from_store(&self, store: &impl AsStoreRef) -> bool { - self.as_ref().map_or(true, |f| f.is_from_store(store)) - } - } - - #[cfg(test)] - mod test_from_to_native_wasm_type { - use super::*; - - #[test] - fn test_to_native() { - assert_eq!(7i8.to_native(), 7i32); - assert_eq!(7u8.to_native(), 7i32); - assert_eq!(7i16.to_native(), 7i32); - assert_eq!(7u16.to_native(), 7i32); - assert_eq!(u32::MAX.to_native(), -1); - } - - #[test] - fn test_to_native_same_size() { - assert_eq!(7i32.to_native(), 7i32); - assert_eq!(7u32.to_native(), 7i32); - assert_eq!(7i64.to_native(), 7i64); - assert_eq!(7u64.to_native(), 7i64); - assert_eq!(7f32.to_native(), 7f32); - assert_eq!(7f64.to_native(), 7f64); - } - } - - /// The `WasmTypeList` trait represents a tuple (list) of Wasm - /// typed values. It is used to get low-level representation of - /// such a tuple. - pub trait WasmTypeList - where - Self: Sized, - { - /// The C type (a struct) that can hold/represent all the - /// represented values. - type CStruct; - - /// The array type that can hold all the represented values. - /// - /// Note that all values are stored in their binary form. - type Array: AsMut<[RawValue]>; - - /// The size of the array - fn size() -> u32; - - /// Constructs `Self` based on an array of values. - /// - /// # Safety - unsafe fn from_array(store: &mut impl AsStoreMut, array: Self::Array) -> Self; - - /// Constructs `Self` based on a slice of values. - /// - /// `from_slice` returns a `Result` because it is possible - /// that the slice doesn't have the same size than - /// `Self::Array`, in which circumstance an error of kind - /// `TryFromSliceError` will be returned. - /// - /// # Safety - unsafe fn from_slice( - store: &mut impl AsStoreMut, - slice: &[RawValue], - ) -> Result; - - /// Builds and returns an array of type `Array` from a tuple - /// (list) of values. - /// - /// # Safety - unsafe fn into_array(self, store: &mut impl AsStoreMut) -> Self::Array; - - /// Allocates and return an empty array of type `Array` that - /// will hold a tuple (list) of values, usually to hold the - /// returned values of a WebAssembly function call. - fn empty_array() -> Self::Array; - - /// Builds a tuple (list) of values from a C struct of type - /// `CStruct`. - /// - /// # Safety - unsafe fn from_c_struct(store: &mut impl AsStoreMut, c_struct: Self::CStruct) -> Self; - - /// Builds and returns a C struct of type `CStruct` from a - /// tuple (list) of values. - /// - /// # Safety - unsafe fn into_c_struct(self, store: &mut impl AsStoreMut) -> Self::CStruct; - - /// Writes the contents of a C struct to an array of `RawValue`. - /// - /// # Safety - unsafe fn write_c_struct_to_ptr(c_struct: Self::CStruct, ptr: *mut RawValue); - - /// Get the Wasm types for the tuple (list) of currently - /// represented values. - fn wasm_types() -> &'static [Type]; - } - - /// The `IntoResult` trait turns a `WasmTypeList` into a - /// `Result`. - /// - /// It is mostly used to turn result values of a Wasm function - /// call into a `Result`. - pub trait IntoResult - where - T: WasmTypeList, - { - /// The error type for this trait. - type Error: Error + Sync + Send + 'static; - - /// Transforms `Self` into a `Result`. - fn into_result(self) -> Result; - } - - impl IntoResult for T - where - T: WasmTypeList, - { - // `T` is not a `Result`, it's already a value, so no error - // can be built. - type Error = Infallible; - - fn into_result(self) -> Result { - Ok(self) - } - } - - impl IntoResult for Result - where - T: WasmTypeList, - E: Error + Sync + Send + 'static, - { - type Error = E; - - fn into_result(self) -> Self { - self - } - } - - #[cfg(test)] - mod test_into_result { - use super::*; - use std::convert::Infallible; - - #[test] - fn test_into_result_over_t() { - let x: i32 = 42; - let result_of_x: Result = x.into_result(); - - assert_eq!(result_of_x.unwrap(), x); - } - - #[test] - fn test_into_result_over_result() { - { - let x: Result = Ok(42); - let result_of_x: Result = x.into_result(); - - assert_eq!(result_of_x, x); - } - - { - use std::{error, fmt}; - - #[derive(Debug, PartialEq)] - struct E; - - impl fmt::Display for E { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(formatter, "E") - } - } - - impl error::Error for E {} - - let x: Result = Err(E); - let result_of_x: Result = x.into_result(); - - assert_eq!(result_of_x.unwrap_err(), E); - } - } - } - - /// The `HostFunction` trait represents the set of functions that - /// can be used as host function. To uphold this statement, it is - /// necessary for a function to be transformed into a pointer to - /// `VMFunctionBody`. - pub trait HostFunction - where - Args: WasmTypeList, - Rets: WasmTypeList, - Kind: HostFunctionKind, - { - /// Get the pointer to the function body. - fn function_body_ptr(&self) -> *const VMFunctionBody; - - /// Get the pointer to the function call trampoline. - fn call_trampoline_address() -> VMTrampoline; - } - - /// Empty trait to specify the kind of `HostFunction`: With or - /// without an environment. - /// - /// This trait is never aimed to be used by a user. It is used by - /// the trait system to automatically generate the appropriate - /// host functions. - #[doc(hidden)] - pub trait HostFunctionKind: private::HostFunctionKindSealed {} - - /// An empty struct to help Rust typing to determine - /// when a `HostFunction` does have an environment. - pub struct WithEnv; - - impl HostFunctionKind for WithEnv {} - - /// An empty struct to help Rust typing to determine - /// when a `HostFunction` does not have an environment. - pub struct WithoutEnv; - - impl HostFunctionKind for WithoutEnv {} - - mod private { - //! Sealing the HostFunctionKind because it shouldn't be implemented - //! by any type outside. - //! See: - //! https://rust-lang.github.io/api-guidelines/future-proofing.html#c-sealed - pub trait HostFunctionKindSealed {} - impl HostFunctionKindSealed for super::WithEnv {} - impl HostFunctionKindSealed for super::WithoutEnv {} - } - - /// Represents a low-level Wasm static host function. See - /// [`super::Function::new_typed`] and - /// [`super::Function::new_typed_with_env`] to learn more. - pub(crate) struct StaticFunction { - pub(crate) raw_store: *mut u8, - pub(crate) env: FunctionEnv, - pub(crate) func: F, - } +/// Represents a low-level Wasm static host function. See +/// [`super::Function::new_typed`] and +/// [`super::Function::new_typed_with_env`] to learn more. +pub(crate) struct StaticFunction { + pub(crate) raw_store: *mut u8, + pub(crate) env: FunctionEnv, + pub(crate) func: F, +} - macro_rules! impl_host_function { +macro_rules! impl_host_function { ( [$c_struct_representation:ident] $c_struct_name:ident, $( $x:ident ),* ) => { @@ -1482,8 +739,8 @@ mod inner { }; } - // Black-magic to count the number of identifiers at compile-time. - macro_rules! count_idents { +// Black-magic to count the number of identifiers at compile-time. +macro_rules! count_idents { ( $($idents:ident),* ) => { { #[allow(dead_code, non_camel_case_types)] @@ -1494,227 +751,32 @@ mod inner { }; } - // Here we go! Let's generate all the C struct, `WasmTypeList` - // implementations and `HostFunction` implementations. - impl_host_function!([C] S0,); - impl_host_function!([transparent] S1, A1); - impl_host_function!([C] S2, A1, A2); - impl_host_function!([C] S3, A1, A2, A3); - impl_host_function!([C] S4, A1, A2, A3, A4); - impl_host_function!([C] S5, A1, A2, A3, A4, A5); - impl_host_function!([C] S6, A1, A2, A3, A4, A5, A6); - impl_host_function!([C] S7, A1, A2, A3, A4, A5, A6, A7); - impl_host_function!([C] S8, A1, A2, A3, A4, A5, A6, A7, A8); - impl_host_function!([C] S9, A1, A2, A3, A4, A5, A6, A7, A8, A9); - impl_host_function!([C] S10, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10); - impl_host_function!([C] S11, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11); - impl_host_function!([C] S12, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12); - impl_host_function!([C] S13, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13); - impl_host_function!([C] S14, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14); - impl_host_function!([C] S15, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15); - impl_host_function!([C] S16, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16); - impl_host_function!([C] S17, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17); - impl_host_function!([C] S18, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18); - impl_host_function!([C] S19, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19); - impl_host_function!([C] S20, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20); - impl_host_function!([C] S21, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21); - impl_host_function!([C] S22, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22); - impl_host_function!([C] S23, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23); - impl_host_function!([C] S24, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24); - impl_host_function!([C] S25, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25); - impl_host_function!([C] S26, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25, A26); - - // Implement `WasmTypeList` on `Infallible`, which means that - // `Infallible` can be used as a returned type of a host function - // to express that it doesn't return, or to express that it cannot - // fail (with `Result<_, Infallible>`). - impl WasmTypeList for Infallible { - type CStruct = Self; - type Array = [RawValue; 0]; - - fn size() -> u32 { - 0 - } - - unsafe fn from_array(_: &mut impl AsStoreMut, _: Self::Array) -> Self { - unreachable!() - } - - unsafe fn from_slice( - _: &mut impl AsStoreMut, - _: &[RawValue], - ) -> Result { - unreachable!() - } - - unsafe fn into_array(self, _: &mut impl AsStoreMut) -> Self::Array { - [] - } - - fn empty_array() -> Self::Array { - [] - } - - unsafe fn from_c_struct(_: &mut impl AsStoreMut, self_: Self::CStruct) -> Self { - self_ - } - - unsafe fn into_c_struct(self, _: &mut impl AsStoreMut) -> Self::CStruct { - self - } - - unsafe fn write_c_struct_to_ptr(_: Self::CStruct, _: *mut RawValue) {} - - fn wasm_types() -> &'static [Type] { - &[] - } - } - - #[cfg(test)] - mod test_wasm_type_list { - use super::*; - use wasmer_types::Type; - /* - #[test] - fn test_from_array() { - let mut store = Store::default(); - let env = FunctionEnv::new(&mut store, ()); - assert_eq!(<()>::from_array(&mut env, []), ()); - assert_eq!(::from_array(&mut env, [RawValue{i32: 1}]), (1i32)); - assert_eq!(<(i32, i64)>::from_array(&mut env, [RawValue{i32:1}, RawValue{i64:2}]), (1i32, 2i64)); - assert_eq!( - <(i32, i64, f32, f64)>::from_array(&mut env, [ - RawValue{i32:1}, - RawValue{i64:2}, - RawValue{f32: 3.1f32}, - RawValue{f64: 4.2f64} - ]), - (1, 2, 3.1f32, 4.2f64) - ); - } - - #[test] - fn test_into_array() { - let mut store = Store::default(); - let env = FunctionEnv::new(&mut store, ()); - assert_eq!(().into_array(&mut store), [0i128; 0]); - assert_eq!((1i32).into_array(&mut store), [1i32]); - assert_eq!((1i32, 2i64).into_array(&mut store), [RawValue{i32: 1}, RawValue{i64: 2}]); - assert_eq!( - (1i32, 2i32, 3.1f32, 4.2f64).into_array(&mut store), - [RawValue{i32: 1}, RawValue{i32: 2}, RawValue{ f32: 3.1f32}, RawValue{f64: 4.2f64}] - ); - } - */ - #[test] - fn test_empty_array() { - assert_eq!(<()>::empty_array().len(), 0); - assert_eq!(::empty_array().len(), 1); - assert_eq!(<(i32, i64)>::empty_array().len(), 2); - } - /* - #[test] - fn test_from_c_struct() { - let mut store = Store::default(); - let env = FunctionEnv::new(&mut store, ()); - assert_eq!(<()>::from_c_struct(&mut store, S0()), ()); - assert_eq!(::from_c_struct(&mut store, S1(1)), (1i32)); - assert_eq!(<(i32, i64)>::from_c_struct(&mut store, S2(1, 2)), (1i32, 2i64)); - assert_eq!( - <(i32, i64, f32, f64)>::from_c_struct(&mut store, S4(1, 2, 3.1, 4.2)), - (1i32, 2i64, 3.1f32, 4.2f64) - ); - } - */ - #[test] - fn test_wasm_types_for_uni_values() { - assert_eq!(::wasm_types(), [Type::I32]); - assert_eq!(::wasm_types(), [Type::I64]); - assert_eq!(::wasm_types(), [Type::F32]); - assert_eq!(::wasm_types(), [Type::F64]); - } - - #[test] - fn test_wasm_types_for_multi_values() { - assert_eq!(<(i32, i32)>::wasm_types(), [Type::I32, Type::I32]); - assert_eq!(<(i64, i64)>::wasm_types(), [Type::I64, Type::I64]); - assert_eq!(<(f32, f32)>::wasm_types(), [Type::F32, Type::F32]); - assert_eq!(<(f64, f64)>::wasm_types(), [Type::F64, Type::F64]); - - assert_eq!( - <(i32, i64, f32, f64)>::wasm_types(), - [Type::I32, Type::I64, Type::F32, Type::F64] - ); - } - } - /* - #[allow(non_snake_case)] - #[cfg(test)] - mod test_function { - use super::*; - use crate::Store; - use crate::FunctionEnv; - use wasmer_types::Type; - - fn func() {} - fn func__i32() -> i32 { - 0 - } - fn func_i32( _a: i32) {} - fn func_i32__i32( a: i32) -> i32 { - a * 2 - } - fn func_i32_i32__i32( a: i32, b: i32) -> i32 { - a + b - } - fn func_i32_i32__i32_i32( a: i32, b: i32) -> (i32, i32) { - (a, b) - } - fn func_f32_i32__i32_f32( a: f32, b: i32) -> (i32, f32) { - (b, a) - } - - #[test] - fn test_function_types() { - let mut store = Store::default(); - let env = FunctionEnv::new(&mut store, ()); - use wasmer_types::FunctionType; - assert_eq!( - StaticFunction::new(func).ty(&mut store), - FunctionType::new(vec![], vec![]) - ); - assert_eq!( - StaticFunction::new(func__i32).ty(&mut store), - FunctionType::new(vec![], vec![Type::I32]) - ); - assert_eq!( - StaticFunction::new(func_i32).ty(), - FunctionType::new(vec![Type::I32], vec![]) - ); - assert_eq!( - StaticFunction::new(func_i32__i32).ty(), - FunctionType::new(vec![Type::I32], vec![Type::I32]) - ); - assert_eq!( - StaticFunction::new(func_i32_i32__i32).ty(), - FunctionType::new(vec![Type::I32, Type::I32], vec![Type::I32]) - ); - assert_eq!( - StaticFunction::new(func_i32_i32__i32_i32).ty(), - FunctionType::new(vec![Type::I32, Type::I32], vec![Type::I32, Type::I32]) - ); - assert_eq!( - StaticFunction::new(func_f32_i32__i32_f32).ty(), - FunctionType::new(vec![Type::F32, Type::I32], vec![Type::I32, Type::F32]) - ); - } - - #[test] - fn test_function_pointer() { - let f = StaticFunction::new(func_i32__i32); - let function = unsafe { std::mem::transmute::<_, fn(usize, i32) -> i32>(f.address) }; - assert_eq!(function(0, 3), 6); - } - } - */ -} +// Here we go! Let's generate all the C struct, `WasmTypeList` +// implementations and `HostFunction` implementations. +impl_host_function!([C] S0,); +impl_host_function!([transparent] S1, A1); +impl_host_function!([C] S2, A1, A2); +impl_host_function!([C] S3, A1, A2, A3); +impl_host_function!([C] S4, A1, A2, A3, A4); +impl_host_function!([C] S5, A1, A2, A3, A4, A5); +impl_host_function!([C] S6, A1, A2, A3, A4, A5, A6); +impl_host_function!([C] S7, A1, A2, A3, A4, A5, A6, A7); +impl_host_function!([C] S8, A1, A2, A3, A4, A5, A6, A7, A8); +impl_host_function!([C] S9, A1, A2, A3, A4, A5, A6, A7, A8, A9); +impl_host_function!([C] S10, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10); +impl_host_function!([C] S11, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11); +impl_host_function!([C] S12, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12); +impl_host_function!([C] S13, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13); +impl_host_function!([C] S14, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14); +impl_host_function!([C] S15, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15); +impl_host_function!([C] S16, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16); +impl_host_function!([C] S17, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17); +impl_host_function!([C] S18, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18); +impl_host_function!([C] S19, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19); +impl_host_function!([C] S20, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20); +impl_host_function!([C] S21, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21); +impl_host_function!([C] S22, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22); +impl_host_function!([C] S23, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23); +impl_host_function!([C] S24, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24); +impl_host_function!([C] S25, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25); +impl_host_function!([C] S26, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25, A26); diff --git a/lib/api/src/sys/mod.rs b/lib/api/src/sys/mod.rs index 0c7fb8cfb4f..967d84fc7a6 100644 --- a/lib/api/src/sys/mod.rs +++ b/lib/api/src/sys/mod.rs @@ -20,8 +20,8 @@ pub(crate) mod vm { //! The `vm` module re-exports wasmer-vm types. use wasmer_vm::InternalStoreHandle; pub(crate) use wasmer_vm::{ - VMExtern, VMExternRef, VMFuncRef, VMFunction, VMFunctionEnvironment, VMGlobal, VMMemory, - VMTable, + VMExtern, VMExternRef, VMFuncRef, VMFunction, VMFunctionBody, VMFunctionEnvironment, + VMGlobal, VMMemory, VMTable, VMTrampoline, }; pub(crate) type VMExternTable = InternalStoreHandle; diff --git a/lib/api/src/sys/typed_function.rs b/lib/api/src/sys/typed_function.rs index 15f29a57db0..dd5f60e3378 100644 --- a/lib/api/src/sys/typed_function.rs +++ b/lib/api/src/sys/typed_function.rs @@ -17,7 +17,7 @@ macro_rules! impl_native_traits { #[allow(clippy::too_many_arguments)] pub fn call(&self, store: &mut impl AsStoreMut, $( $x: $x, )* ) -> Result { let anyfunc = unsafe { - *self.func + *self.func.0 .handle .get(store.as_store_ref().objects()) .anyfunc @@ -103,7 +103,7 @@ macro_rules! impl_native_traits { #[allow(clippy::too_many_arguments)] pub fn call_raw(&self, store: &mut impl AsStoreMut, mut params_list: Vec ) -> Result { let anyfunc = unsafe { - *self.func + *self.func.0 .handle .get(store.as_store_ref().objects()) .anyfunc diff --git a/lib/api/src/vm.rs b/lib/api/src/vm.rs index 575f9cdd43d..be3684d42d1 100644 --- a/lib/api/src/vm.rs +++ b/lib/api/src/vm.rs @@ -3,13 +3,14 @@ #[cfg(feature = "js")] pub(crate) use crate::js::vm::{ VMExtern, VMExternFunction, VMExternGlobal, VMExternMemory, VMExternRef, VMExternTable, - VMFuncRef, VMFunction, VMFunctionEnvironment, VMGlobal, VMMemory, VMTable, + VMFuncRef, VMFunction, VMFunctionBody, VMFunctionEnvironment, VMGlobal, VMMemory, VMTable, + VMTrampoline, }; #[cfg(feature = "sys")] pub(crate) use crate::sys::vm::{ VMExtern, VMExternFunction, VMExternGlobal, VMExternMemory, VMExternRef, VMExternTable, - VMFuncRef, VMFunctionEnvironment, + VMFuncRef, VMFunctionBody, VMFunctionEnvironment, VMTrampoline, }; // Needed for tunables customization From c45864ac2632a77e560772521dd5ec3bb120a015 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Wed, 15 Feb 2023 17:13:15 -0800 Subject: [PATCH 47/81] Universalize MemoryView in js/sys --- lib/api/src/externals/memory.rs | 2 +- lib/api/src/externals/memory_view.rs | 174 ++++++++++++++++++++++- lib/api/src/externals/mod.rs | 2 +- lib/api/src/js/externals/memory_view.rs | 6 +- lib/api/src/js/vm.rs | 6 +- lib/api/src/mem_access.rs | 6 +- lib/api/src/sys/externals/memory.rs | 2 +- lib/api/src/sys/externals/memory_view.rs | 2 + 8 files changed, 184 insertions(+), 16 deletions(-) diff --git a/lib/api/src/externals/memory.rs b/lib/api/src/externals/memory.rs index 854220cba1d..321b219ee23 100644 --- a/lib/api/src/externals/memory.rs +++ b/lib/api/src/externals/memory.rs @@ -73,7 +73,7 @@ impl Memory { /// Creates a view into the memory that then allows for /// read and write pub fn view<'a>(&'a self, store: &impl AsStoreRef) -> MemoryView<'a> { - MemoryView::new(&self.0, store) + MemoryView::new(&self, store) } /// Grow memory by the specified amount of WebAssembly [`Pages`] and return diff --git a/lib/api/src/externals/memory_view.rs b/lib/api/src/externals/memory_view.rs index 20076158386..54cb696a6a6 100644 --- a/lib/api/src/externals/memory_view.rs +++ b/lib/api/src/externals/memory_view.rs @@ -1,4 +1,174 @@ +use super::memory::{Memory, MemoryBuffer}; +use crate::store::AsStoreRef; +use crate::MemoryAccessError; +use std::mem::MaybeUninit; +use wasmer_types::Pages; + #[cfg(feature = "js")] -pub use crate::js::externals::memory_view::MemoryView; +use crate::js::externals::memory_view as memory_view_impl; #[cfg(feature = "sys")] -pub use crate::sys::externals::memory_view::MemoryView; +use crate::sys::externals::memory_view as memory_view_impl; + +/// A WebAssembly `memory` view. +/// +/// A memory view is used to read and write to the linear memory. +/// +/// After a memory is grown a view must not be used anymore. Views are +/// created using the Memory.grow() method. +#[derive(Debug)] +pub struct MemoryView<'a>(pub(crate) memory_view_impl::MemoryView<'a>); + +impl<'a> MemoryView<'a> { + pub(crate) fn new(memory: &'a Memory, store: &impl AsStoreRef) -> Self { + MemoryView(memory_view_impl::MemoryView::new(&memory.0, store)) + } + + /// Returns the pointer to the raw bytes of the `Memory`. + // + // This used by wasmer-emscripten and wasmer-c-api, but should be treated + // as deprecated and not used in future code. + #[doc(hidden)] + pub fn data_ptr(&self) -> *mut u8 { + self.0.data_ptr() + } + + /// Returns the size (in bytes) of the `Memory`. + pub fn data_size(&self) -> u64 { + self.0.data_size() + } + + /// Retrieve a slice of the memory contents. + /// + /// # Safety + /// + /// Until the returned slice is dropped, it is undefined behaviour to + /// modify the memory contents in any way including by calling a wasm + /// function that writes to the memory or by resizing the memory. + #[doc(hidden)] + pub unsafe fn data_unchecked(&self) -> &[u8] { + self.0.data_unchecked() + } + + /// Retrieve a mutable slice of the memory contents. + /// + /// # Safety + /// + /// This method provides interior mutability without an UnsafeCell. Until + /// the returned value is dropped, it is undefined behaviour to read or + /// write to the pointed-to memory in any way except through this slice, + /// including by calling a wasm function that reads the memory contents or + /// by resizing this Memory. + #[allow(clippy::mut_from_ref)] + #[doc(hidden)] + pub unsafe fn data_unchecked_mut(&self) -> &mut [u8] { + self.0.data_unchecked_mut() + } + + /// Returns the size (in [`Pages`]) of the `Memory`. + /// + /// # Example + /// + /// ``` + /// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value}; + /// # let mut store = Store::default(); + /// # + /// let m = Memory::new(&mut store, MemoryType::new(1, None, false)).unwrap(); + /// + /// assert_eq!(m.view(&mut store).size(), Pages(1)); + /// ``` + pub fn size(&self) -> Pages { + self.0.size() + } + + #[inline] + pub(crate) fn buffer(&'a self) -> MemoryBuffer<'a> { + MemoryBuffer(self.0.buffer()) + } + + /// Safely reads bytes from the memory at the given offset. + /// + /// The full buffer will be filled, otherwise a `MemoryAccessError` is returned + /// to indicate an out-of-bounds access. + /// + /// This method is guaranteed to be safe (from the host side) in the face of + /// concurrent writes. + pub fn read(&self, offset: u64, buf: &mut [u8]) -> Result<(), MemoryAccessError> { + self.0.read(offset, buf) + } + + /// Safely reads a single byte from memory at the given offset + /// + /// This method is guaranteed to be safe (from the host side) in the face of + /// concurrent writes. + pub fn read_u8(&self, offset: u64) -> Result { + self.0.read_u8(offset) + } + + /// Safely reads bytes from the memory at the given offset. + /// + /// This method is similar to `read` but allows reading into an + /// uninitialized buffer. An initialized view of the buffer is returned. + /// + /// The full buffer will be filled, otherwise a `MemoryAccessError` is returned + /// to indicate an out-of-bounds access. + /// + /// This method is guaranteed to be safe (from the host side) in the face of + /// concurrent writes. + pub fn read_uninit<'b>( + &self, + offset: u64, + buf: &'b mut [MaybeUninit], + ) -> Result<&'b mut [u8], MemoryAccessError> { + self.0.read_uninit(offset, buf) + } + + /// Safely writes bytes to the memory at the given offset. + /// + /// If the write exceeds the bounds of the memory then a `MemoryAccessError` is + /// returned. + /// + /// This method is guaranteed to be safe (from the host side) in the face of + /// concurrent reads/writes. + pub fn write(&self, offset: u64, data: &[u8]) -> Result<(), MemoryAccessError> { + self.0.write(offset, data) + } + + /// Safely reads a single byte from memory at the given offset + /// + /// This method is guaranteed to be safe (from the host side) in the face of + /// concurrent writes. + pub fn write_u8(&self, offset: u64, val: u8) -> Result<(), MemoryAccessError> { + self.0.write_u8(offset, val) + } + + /// Copies the memory and returns it as a vector of bytes + pub fn copy_to_vec(&self) -> Result, MemoryAccessError> { + let mut new_memory = Vec::new(); + let mut offset = 0; + let mut chunk = [0u8; 40960]; + while offset < self.data_size() { + let remaining = self.data_size() - offset; + let sublen = remaining.min(chunk.len() as u64) as usize; + self.read(offset, &mut chunk[..sublen])?; + new_memory.extend_from_slice(&chunk[..sublen]); + offset += sublen as u64; + } + Ok(new_memory) + } + + /// Copies the memory to another new memory object + pub fn copy_to_memory(&self, amount: u64, new_memory: &Self) -> Result<(), MemoryAccessError> { + let mut offset = 0; + let mut chunk = [0u8; 40960]; + while offset < amount { + let remaining = amount - offset; + let sublen = remaining.min(chunk.len() as u64) as usize; + self.read(offset, &mut chunk[..sublen])?; + + new_memory.write(offset, &chunk[..sublen])?; + + offset += sublen as u64; + } + Ok(()) + } +} diff --git a/lib/api/src/externals/mod.rs b/lib/api/src/externals/mod.rs index 5757ebdbe80..ea207bcd24e 100644 --- a/lib/api/src/externals/mod.rs +++ b/lib/api/src/externals/mod.rs @@ -1,6 +1,6 @@ pub(crate) mod function; mod global; -mod memory; +pub(crate) mod memory; mod memory_view; mod table; diff --git a/lib/api/src/js/externals/memory_view.rs b/lib/api/src/js/externals/memory_view.rs index 230d4aee734..c34692c89db 100644 --- a/lib/api/src/js/externals/memory_view.rs +++ b/lib/api/src/js/externals/memory_view.rs @@ -168,11 +168,11 @@ impl<'a> MemoryView<'a> { /// /// This method is guaranteed to be safe (from the host side) in the face of /// concurrent writes. - pub fn read_uninit( + pub fn read_uninit<'b>( &self, offset: u64, - buf: &'a mut [MaybeUninit], - ) -> Result<&'a mut [u8], MemoryAccessError> { + buf: &'b mut [MaybeUninit], + ) -> Result<&'b mut [u8], MemoryAccessError> { let view = &self.view; let offset: u32 = offset.try_into().map_err(|_| MemoryAccessError::Overflow)?; let len: u32 = buf diff --git a/lib/api/src/js/vm.rs b/lib/api/src/js/vm.rs index 09288349922..6d5d3284d2e 100644 --- a/lib/api/src/js/vm.rs +++ b/lib/api/src/js/vm.rs @@ -67,9 +67,9 @@ impl VMMemory { #[cfg(feature = "tracing")] trace!("memory copy started"); - let src = MemoryView::new_raw(&self.memory); + let src = crate::js::externals::memory_view::MemoryView::new_raw(&self.memory); let amount = src.data_size() as usize; - let mut dst = MemoryView::new_raw(&new_memory); + let mut dst = crate::js::externals::memory_view::MemoryView::new_raw(&new_memory); let dst_size = dst.data_size() as usize; if amount > dst_size { @@ -90,7 +90,7 @@ impl VMMemory { } })?; - dst = MemoryView::new_raw(&new_memory); + dst = crate::js::externals::memory_view::MemoryView::new_raw(&new_memory); } src.copy_to_memory(amount as u64, &dst).map_err(|err| { diff --git a/lib/api/src/mem_access.rs b/lib/api/src/mem_access.rs index 9bffc7a2a04..c4d40213c16 100644 --- a/lib/api/src/mem_access.rs +++ b/lib/api/src/mem_access.rs @@ -1,3 +1,4 @@ +use crate::externals::memory::MemoryBuffer; use crate::RuntimeError; #[allow(unused_imports)] use crate::{Memory, Memory32, Memory64, MemorySize, MemoryView, WasmPtr}; @@ -13,11 +14,6 @@ use std::{ use thiserror::Error; use wasmer_types::ValueType; -#[cfg(feature = "js")] -use crate::js::externals::memory::MemoryBuffer; -#[cfg(feature = "sys")] -use crate::sys::externals::memory::MemoryBuffer; - /// Error for invalid [`Memory`] access. #[derive(Clone, Copy, Debug, Error)] #[non_exhaustive] diff --git a/lib/api/src/sys/externals/memory.rs b/lib/api/src/sys/externals/memory.rs index e48be91f76a..f14caebd110 100644 --- a/lib/api/src/sys/externals/memory.rs +++ b/lib/api/src/sys/externals/memory.rs @@ -40,7 +40,7 @@ impl Memory { } pub fn view<'a>(&'a self, store: &impl AsStoreRef) -> MemoryView<'a> { - MemoryView::new(self, store) + MemoryView::new(&self, store) } pub fn grow( diff --git a/lib/api/src/sys/externals/memory_view.rs b/lib/api/src/sys/externals/memory_view.rs index 8adc29d91e7..05df80c0e38 100644 --- a/lib/api/src/sys/externals/memory_view.rs +++ b/lib/api/src/sys/externals/memory_view.rs @@ -160,6 +160,7 @@ impl<'a> MemoryView<'a> { Ok(()) } + #[allow(unused)] /// Copies the memory and returns it as a vector of bytes pub fn copy_to_vec(&self) -> Result, MemoryAccessError> { let mut new_memory = Vec::new(); @@ -175,6 +176,7 @@ impl<'a> MemoryView<'a> { Ok(new_memory) } + #[allow(unused)] /// Copies the memory to another new memory object pub fn copy_to_memory(&self, amount: u64, new_memory: &Self) -> Result<(), MemoryAccessError> { let mut offset = 0; From 99d3f8459076ad70f4afcf97124d06ac884ce2e9 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Wed, 15 Feb 2023 18:02:22 -0800 Subject: [PATCH 48/81] Simplified errors --- lib/api/src/js/error.rs | 50 ----------------------------------------- lib/api/src/js/mod.rs | 5 +---- lib/api/src/lib.rs | 3 +++ 3 files changed, 4 insertions(+), 54 deletions(-) diff --git a/lib/api/src/js/error.rs b/lib/api/src/js/error.rs index 11d0a0aeaa3..c86d4423614 100644 --- a/lib/api/src/js/error.rs +++ b/lib/api/src/js/error.rs @@ -8,56 +8,6 @@ use std::borrow::Cow; use thiserror::Error; use wasmer_types::{CompileError, ImportError}; -// impl From for WasmError { -// fn from(err: wasm_bindgen::JsValue) -> Self { -// Self::Generic( -// if err.is_string() && err.as_string().filter(|s| !s.is_empty()).is_some() { -// err.as_string().unwrap_or_default() -// } else { -// format!("Unexpected Javascript error: {:?}", err) -// }, -// ) -// } -// } - -/// The Serialize error can occur when serializing a -/// compiled Module into a binary. -/// Copied from wasmer_compiler::SerializeError -#[derive(Debug)] -#[cfg_attr(feature = "std", derive(Error))] -pub enum SerializeError { - /// An IO error - #[cfg_attr(feature = "std", error(transparent))] - Io(#[cfg_attr(feature = "std", from)] std::io::Error), - /// A generic serialization error - #[cfg_attr(feature = "std", error("{0}"))] - Generic(String), -} - -/// The Deserialize error can occur when loading a -/// compiled Module from a binary. -/// Copied from wasmer_compiler::DeSerializeError -#[derive(Debug)] -#[cfg_attr(feature = "std", derive(Error))] -pub enum DeserializeError { - /// An IO error - #[cfg_attr(feature = "std", error(transparent))] - Io(#[cfg_attr(feature = "std", from)] std::io::Error), - /// A generic deserialization error - #[cfg_attr(feature = "std", error("{0}"))] - Generic(String), - /// Incompatible serialized binary - #[cfg_attr(feature = "std", error("incompatible binary: {0}"))] - Incompatible(String), - /// The provided binary is corrupted - #[cfg_attr(feature = "std", error("corrupted binary: {0}"))] - CorruptedBinary(String), - /// The binary was valid, but we got an error when - /// trying to allocate the required resources. - #[cfg_attr(feature = "std", error(transparent))] - Compiler(CompileError), -} - /// The WebAssembly.LinkError object indicates an error during /// module instantiation (besides traps from the start function). /// diff --git a/lib/api/src/js/mod.rs b/lib/api/src/js/mod.rs index e7d13645070..bc43a14d5b6 100644 --- a/lib/api/src/js/mod.rs +++ b/lib/api/src/js/mod.rs @@ -39,10 +39,7 @@ pub(crate) mod vm; mod wasm_bindgen_polyfill; pub use crate::js::as_js::AsJs; -pub use crate::js::error::{DeserializeError, LinkError, SerializeError}; +pub use crate::js::error::{LinkError}; pub use crate::js::module::{Module, ModuleTypeHints}; pub use crate::js::store::StoreObjects; pub use crate::js::trap::RuntimeError; - -#[cfg(feature = "wasm-types-polyfill")] -pub use wasmparser; diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index 366363977ea..9c625f3a133 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -492,6 +492,9 @@ pub use wasmer_types::{ #[cfg(feature = "wat")] pub use wat::parse_bytes as wat2wasm; +#[cfg(feature = "wasmparser")] +pub use wasmparser; + // Deprecated types /// This type is deprecated, it has been replaced by TypedFunction. From 745a06b15a2c7c76b855014b140c1936f69feaa4 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Wed, 15 Feb 2023 18:12:18 -0800 Subject: [PATCH 49/81] Improved module imports --- lib/api/src/js/mod.rs | 4 ++-- lib/api/src/sys/mod.rs | 25 +++++++------------------ 2 files changed, 9 insertions(+), 20 deletions(-) diff --git a/lib/api/src/js/mod.rs b/lib/api/src/js/mod.rs index bc43a14d5b6..24afb0135ac 100644 --- a/lib/api/src/js/mod.rs +++ b/lib/api/src/js/mod.rs @@ -39,7 +39,7 @@ pub(crate) mod vm; mod wasm_bindgen_polyfill; pub use crate::js::as_js::AsJs; -pub use crate::js::error::{LinkError}; -pub use crate::js::module::{Module, ModuleTypeHints}; +pub use crate::js::error::LinkError; +pub use crate::js::module::ModuleTypeHints; pub use crate::js::store::StoreObjects; pub use crate::js::trap::RuntimeError; diff --git a/lib/api/src/sys/mod.rs b/lib/api/src/sys/mod.rs index 967d84fc7a6..5da2665afbd 100644 --- a/lib/api/src/sys/mod.rs +++ b/lib/api/src/sys/mod.rs @@ -12,10 +12,14 @@ pub use target_lexicon::{Architecture, CallingConvention, OperatingSystem, Tripl pub use wasmer_compiler::{ wasmparser, CompilerConfig, FunctionMiddleware, MiddlewareReaderState, ModuleMiddleware, }; -pub use wasmer_compiler::{Features, FrameInfo, LinkError, RuntimeError, Tunables}; +pub use wasmer_compiler::{Features, FrameInfo, LinkError, RuntimeError, Tunables, Artifact, EngineBuilder}; +#[cfg(feature = "singlepass")] +pub use wasmer_compiler_singlepass::Singlepass; +#[cfg(feature = "cranelift")] +pub use wasmer_compiler_cranelift::{Cranelift, CraneliftOptLevel}; +#[cfg(feature = "llvm")] +pub use wasmer_compiler_llvm::{LLVMOptLevel, LLVM}; -// TODO: should those be moved into wasmer::vm as well? -pub use wasmer_vm::{raise_user_trap, MemoryError}; pub(crate) mod vm { //! The `vm` module re-exports wasmer-vm types. use wasmer_vm::InternalStoreHandle; @@ -29,18 +33,3 @@ pub(crate) mod vm { pub(crate) type VMExternGlobal = InternalStoreHandle; pub(crate) type VMExternFunction = InternalStoreHandle; } - -#[cfg(feature = "wat")] -pub use wat::parse_bytes as wat2wasm; - -#[cfg(feature = "singlepass")] -pub use wasmer_compiler_singlepass::Singlepass; - -#[cfg(feature = "cranelift")] -pub use wasmer_compiler_cranelift::{Cranelift, CraneliftOptLevel}; - -#[cfg(feature = "llvm")] -pub use wasmer_compiler_llvm::{LLVMOptLevel, LLVM}; - -#[cfg(feature = "compiler")] -pub use wasmer_compiler::{Artifact, EngineBuilder}; From 5faa0364fc6deaef5305046306465fd67fcd54e2 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Wed, 15 Feb 2023 18:24:45 -0800 Subject: [PATCH 50/81] Improved module imports --- lib/api/src/errors.rs | 5 ++++- lib/api/src/js/{error.rs => errors.rs} | 2 +- lib/api/src/js/externals/function.rs | 2 +- lib/api/src/js/externals/global.rs | 4 ++-- lib/api/src/js/externals/table.rs | 4 ++-- lib/api/src/js/mod.rs | 5 +---- lib/api/src/js/module.rs | 4 ++-- lib/api/src/js/trap.rs | 1 - lib/api/src/lib.rs | 2 +- lib/api/src/mem_access.rs | 2 +- lib/api/src/sys/externals/global.rs | 2 +- lib/api/src/sys/mod.rs | 8 ++++---- lib/api/src/sys/module.rs | 2 +- lib/api/src/vm.rs | 6 +++--- 14 files changed, 24 insertions(+), 25 deletions(-) rename lib/api/src/js/{error.rs => errors.rs} (96%) diff --git a/lib/api/src/errors.rs b/lib/api/src/errors.rs index f984f7a9795..c5a9ad5ec94 100644 --- a/lib/api/src/errors.rs +++ b/lib/api/src/errors.rs @@ -1,5 +1,8 @@ -use crate::{LinkError, RuntimeError}; +#[cfg(feature = "js")] +pub use crate::js::errors::{LinkError, RuntimeError}; use thiserror::Error; +#[cfg(feature = "sys")] +pub use wasmer_compiler::{LinkError, RuntimeError}; // /// An error while instantiating a module. // /// diff --git a/lib/api/src/js/error.rs b/lib/api/src/js/errors.rs similarity index 96% rename from lib/api/src/js/error.rs rename to lib/api/src/js/errors.rs index c86d4423614..22efae26f3f 100644 --- a/lib/api/src/js/error.rs +++ b/lib/api/src/js/errors.rs @@ -1,7 +1,7 @@ #[cfg(feature = "core")] use crate::alloc::borrow::Cow; use crate::js::lib::std::string::String; -use crate::js::trap::RuntimeError; +pub use crate::js::trap::RuntimeError; #[cfg(feature = "std")] use std::borrow::Cow; #[cfg(feature = "std")] diff --git a/lib/api/src/js/externals/function.rs b/lib/api/src/js/externals/function.rs index 566ad8396a0..ad8e30d3d1d 100644 --- a/lib/api/src/js/externals/function.rs +++ b/lib/api/src/js/externals/function.rs @@ -1,10 +1,10 @@ +use crate::errors::RuntimeError; use crate::exports::{ExportError, Exportable}; use crate::externals::function::{HostFunction, HostFunctionKind, WithEnv, WithoutEnv}; use crate::function_env::{FunctionEnv, FunctionEnvMut}; use crate::js::as_js::{param_from_js, AsJs}; /* ValFuncRef */ use crate::js::store::{InternalStoreHandle, StoreHandle}; use crate::js::vm::{VMExtern, VMFuncRef, VMFunction, VMFunctionBody, VMFunctionEnvironment}; -use crate::js::RuntimeError; use crate::native_type::{FromToNativeWasmType, IntoResult, NativeWasmTypeInto, WasmTypeList}; use crate::store::{AsStoreMut, AsStoreRef, StoreMut}; use crate::value::Value; diff --git a/lib/api/src/js/externals/global.rs b/lib/api/src/js/externals/global.rs index c59315b63f1..f529fa47aab 100644 --- a/lib/api/src/js/externals/global.rs +++ b/lib/api/src/js/externals/global.rs @@ -1,8 +1,8 @@ -use crate::js::vm::{VMExtern, VMGlobal}; +use crate::errors::RuntimeError; use crate::js::wasm_bindgen_polyfill::Global as JSGlobal; -use crate::js::RuntimeError; use crate::store::{AsStoreMut, AsStoreRef}; use crate::value::Value; +use crate::vm::{VMExtern, VMGlobal}; use crate::GlobalType; use crate::Mutability; use wasm_bindgen::JsValue; diff --git a/lib/api/src/js/externals/table.rs b/lib/api/src/js/externals/table.rs index cba4fc3909e..41a6e876af6 100644 --- a/lib/api/src/js/externals/table.rs +++ b/lib/api/src/js/externals/table.rs @@ -1,8 +1,8 @@ -use crate::js::vm::{VMExtern, VMFunction, VMTable}; -use crate::js::RuntimeError; +use crate::errors::RuntimeError; use crate::store::{AsStoreMut, AsStoreRef}; use crate::value::Value; use crate::vm::VMExternTable; +use crate::vm::{VMExtern, VMFunction, VMTable}; use crate::Extern; use crate::{FunctionType, TableType}; use js_sys::Function; diff --git a/lib/api/src/js/mod.rs b/lib/api/src/js/mod.rs index 24afb0135ac..de8e3f5b49e 100644 --- a/lib/api/src/js/mod.rs +++ b/lib/api/src/js/mod.rs @@ -25,7 +25,7 @@ mod lib { mod as_js; pub(crate) mod engine; -pub(crate) mod error; +pub(crate) mod errors; pub(crate) mod extern_ref; pub(crate) mod externals; pub(crate) mod instance; @@ -39,7 +39,4 @@ pub(crate) mod vm; mod wasm_bindgen_polyfill; pub use crate::js::as_js::AsJs; -pub use crate::js::error::LinkError; pub use crate::js::module::ModuleTypeHints; -pub use crate::js::store::StoreObjects; -pub use crate::js::trap::RuntimeError; diff --git a/lib/api/src/js/module.rs b/lib/api/src/js/module.rs index 85c6d2f3c14..68245d6c5f8 100644 --- a/lib/api/src/js/module.rs +++ b/lib/api/src/js/module.rs @@ -1,10 +1,10 @@ use crate::errors::InstantiationError; +use crate::errors::RuntimeError; use crate::imports::Imports; -use crate::js::vm::VMInstance; use crate::js::AsJs; -use crate::js::RuntimeError; use crate::module::IoCompileError; use crate::store::AsStoreMut; +use crate::vm::VMInstance; use crate::Extern; use crate::IntoBytes; use crate::{AsEngineRef, ExportType, ImportType}; diff --git a/lib/api/src/js/trap.rs b/lib/api/src/js/trap.rs index f38aa13e7be..b9d3c96ba8e 100644 --- a/lib/api/src/js/trap.rs +++ b/lib/api/src/js/trap.rs @@ -1,4 +1,3 @@ -// use super::frame_info::{FrameInfo, GlobalFrameInfo, FRAME_INFO}; use std::error::Error; use std::fmt; use std::sync::Arc; diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index 9c625f3a133..3c4251a49f9 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -461,7 +461,7 @@ pub use js::*; pub use crate::externals::{Extern, Function, Global, HostFunction, Memory, MemoryView, Table}; pub use engine::{AsEngineRef, Engine}; -pub use errors::InstantiationError; +pub use errors::{InstantiationError, LinkError, RuntimeError}; pub use exports::{ExportError, Exportable, Exports, ExportsIterator}; pub use extern_ref::ExternRef; pub use function_env::{FunctionEnv, FunctionEnvMut}; diff --git a/lib/api/src/mem_access.rs b/lib/api/src/mem_access.rs index c4d40213c16..589981c8943 100644 --- a/lib/api/src/mem_access.rs +++ b/lib/api/src/mem_access.rs @@ -1,5 +1,5 @@ +use crate::errors::RuntimeError; use crate::externals::memory::MemoryBuffer; -use crate::RuntimeError; #[allow(unused_imports)] use crate::{Memory, Memory32, Memory64, MemorySize, MemoryView, WasmPtr}; use std::{ diff --git a/lib/api/src/sys/externals/global.rs b/lib/api/src/sys/externals/global.rs index c45800faa40..7b5accdbe24 100644 --- a/lib/api/src/sys/externals/global.rs +++ b/lib/api/src/sys/externals/global.rs @@ -1,5 +1,5 @@ +use crate::errors::RuntimeError; use crate::store::{AsStoreMut, AsStoreRef}; -use crate::sys::RuntimeError; use crate::value::Value; use crate::vm::VMExternGlobal; use crate::GlobalType; diff --git a/lib/api/src/sys/mod.rs b/lib/api/src/sys/mod.rs index 5da2665afbd..8132a827f31 100644 --- a/lib/api/src/sys/mod.rs +++ b/lib/api/src/sys/mod.rs @@ -12,20 +12,20 @@ pub use target_lexicon::{Architecture, CallingConvention, OperatingSystem, Tripl pub use wasmer_compiler::{ wasmparser, CompilerConfig, FunctionMiddleware, MiddlewareReaderState, ModuleMiddleware, }; -pub use wasmer_compiler::{Features, FrameInfo, LinkError, RuntimeError, Tunables, Artifact, EngineBuilder}; -#[cfg(feature = "singlepass")] -pub use wasmer_compiler_singlepass::Singlepass; +pub use wasmer_compiler::{Artifact, EngineBuilder, Features, FrameInfo, Tunables}; #[cfg(feature = "cranelift")] pub use wasmer_compiler_cranelift::{Cranelift, CraneliftOptLevel}; #[cfg(feature = "llvm")] pub use wasmer_compiler_llvm::{LLVMOptLevel, LLVM}; +#[cfg(feature = "singlepass")] +pub use wasmer_compiler_singlepass::Singlepass; pub(crate) mod vm { //! The `vm` module re-exports wasmer-vm types. use wasmer_vm::InternalStoreHandle; pub(crate) use wasmer_vm::{ VMExtern, VMExternRef, VMFuncRef, VMFunction, VMFunctionBody, VMFunctionEnvironment, - VMGlobal, VMMemory, VMTable, VMTrampoline, + VMGlobal, VMInstance, VMMemory, VMTable, VMTrampoline, }; pub(crate) type VMExternTable = InternalStoreHandle; diff --git a/lib/api/src/sys/module.rs b/lib/api/src/sys/module.rs index 46790c54104..9d38eb0cd7c 100644 --- a/lib/api/src/sys/module.rs +++ b/lib/api/src/sys/module.rs @@ -9,8 +9,8 @@ use wasmer_types::{ }; use wasmer_types::{ExportType, ImportType}; +use crate::vm::VMInstance; use crate::{AsStoreMut, AsStoreRef, InstantiationError, IntoBytes}; -use wasmer_vm::VMInstance; #[derive(Clone)] pub struct Module { diff --git a/lib/api/src/vm.rs b/lib/api/src/vm.rs index be3684d42d1..7681e14ae3e 100644 --- a/lib/api/src/vm.rs +++ b/lib/api/src/vm.rs @@ -3,14 +3,14 @@ #[cfg(feature = "js")] pub(crate) use crate::js::vm::{ VMExtern, VMExternFunction, VMExternGlobal, VMExternMemory, VMExternRef, VMExternTable, - VMFuncRef, VMFunction, VMFunctionBody, VMFunctionEnvironment, VMGlobal, VMMemory, VMTable, - VMTrampoline, + VMFuncRef, VMFunction, VMFunctionBody, VMFunctionEnvironment, VMGlobal, VMInstance, VMMemory, + VMTable, VMTrampoline, }; #[cfg(feature = "sys")] pub(crate) use crate::sys::vm::{ VMExtern, VMExternFunction, VMExternGlobal, VMExternMemory, VMExternRef, VMExternTable, - VMFuncRef, VMFunctionBody, VMFunctionEnvironment, VMTrampoline, + VMFuncRef, VMFunctionBody, VMFunctionEnvironment, VMInstance, VMTrampoline, }; // Needed for tunables customization From e9a4ba498afcea700bfc5739f6411c874a793b9d Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Wed, 15 Feb 2023 18:27:28 -0800 Subject: [PATCH 51/81] Fix linting --- lib/api/src/externals/memory.rs | 2 +- lib/api/src/sys/externals/memory.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/api/src/externals/memory.rs b/lib/api/src/externals/memory.rs index 321b219ee23..cb14da8f6db 100644 --- a/lib/api/src/externals/memory.rs +++ b/lib/api/src/externals/memory.rs @@ -73,7 +73,7 @@ impl Memory { /// Creates a view into the memory that then allows for /// read and write pub fn view<'a>(&'a self, store: &impl AsStoreRef) -> MemoryView<'a> { - MemoryView::new(&self, store) + MemoryView::new(self, store) } /// Grow memory by the specified amount of WebAssembly [`Pages`] and return diff --git a/lib/api/src/sys/externals/memory.rs b/lib/api/src/sys/externals/memory.rs index f14caebd110..e48be91f76a 100644 --- a/lib/api/src/sys/externals/memory.rs +++ b/lib/api/src/sys/externals/memory.rs @@ -40,7 +40,7 @@ impl Memory { } pub fn view<'a>(&'a self, store: &impl AsStoreRef) -> MemoryView<'a> { - MemoryView::new(&self, store) + MemoryView::new(self, store) } pub fn grow( From c85b2bf62e357f6bc1b86c1f49e108a80c23b9bd Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Thu, 16 Feb 2023 20:00:27 -0800 Subject: [PATCH 52/81] Implement PartialEq for all externals --- lib/api/src/externals/function.rs | 4 +++- lib/api/src/externals/global.rs | 8 +------- lib/api/src/externals/memory.rs | 8 +------- lib/api/src/externals/mod.rs | 2 +- lib/api/src/externals/table.rs | 8 +------- lib/api/src/imports.rs | 2 +- lib/api/src/js/externals/table.rs | 2 +- lib/api/src/sys/externals/function.rs | 2 +- lib/api/src/sys/tunables.rs | 6 ++++-- 9 files changed, 14 insertions(+), 28 deletions(-) diff --git a/lib/api/src/externals/function.rs b/lib/api/src/externals/function.rs index 6acefb7a8e7..6de013922d0 100644 --- a/lib/api/src/externals/function.rs +++ b/lib/api/src/externals/function.rs @@ -81,7 +81,7 @@ mod private { /// with native functions. Attempting to create a native `Function` with one will /// result in a panic. /// [Closures as host functions tracking issue](https://github.com/wasmerio/wasmer/issues/1840) -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct Function(pub(crate) function_impl::Function); impl Function { @@ -500,6 +500,8 @@ impl Function { } } +impl std::cmp::Eq for Function {} + impl<'a> Exportable<'a> for Function { fn get_self_from_extern(_extern: &'a Extern) -> Result<&'a Self, ExportError> { match _extern { diff --git a/lib/api/src/externals/global.rs b/lib/api/src/externals/global.rs index 0fedb2bf03b..2e9579e8862 100644 --- a/lib/api/src/externals/global.rs +++ b/lib/api/src/externals/global.rs @@ -19,7 +19,7 @@ use crate::sys::externals::global as global_impl; /// It consists of an individual value and a flag indicating whether it is mutable. /// /// Spec: -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct Global(pub(crate) global_impl::Global); impl Global { @@ -161,12 +161,6 @@ impl Global { } } -impl std::cmp::PartialEq for Global { - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 - } -} - impl std::cmp::Eq for Global {} impl<'a> Exportable<'a> for Global { diff --git a/lib/api/src/externals/memory.rs b/lib/api/src/externals/memory.rs index cb14da8f6db..5f725cc28ab 100644 --- a/lib/api/src/externals/memory.rs +++ b/lib/api/src/externals/memory.rs @@ -27,7 +27,7 @@ use wasmer_types::{MemoryError, Pages}; /// mutable from both host and WebAssembly. /// /// Spec: -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct Memory(pub(crate) memory_impl::Memory); impl Memory { @@ -148,12 +148,6 @@ impl Memory { } } -impl std::cmp::PartialEq for Memory { - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 - } -} - impl std::cmp::Eq for Memory {} impl<'a> Exportable<'a> for Memory { diff --git a/lib/api/src/externals/mod.rs b/lib/api/src/externals/mod.rs index ea207bcd24e..5ac16b4104d 100644 --- a/lib/api/src/externals/mod.rs +++ b/lib/api/src/externals/mod.rs @@ -25,7 +25,7 @@ use crate::store::{AsStoreMut, AsStoreRef}; /// can be imported or exported. /// /// Spec: -#[derive(Clone)] +#[derive(Clone, PartialEq)] pub enum Extern { /// A external [`Function`]. Function(Function), diff --git a/lib/api/src/externals/table.rs b/lib/api/src/externals/table.rs index f21554fdd35..873105016f2 100644 --- a/lib/api/src/externals/table.rs +++ b/lib/api/src/externals/table.rs @@ -20,7 +20,7 @@ use crate::Value; /// mutable from both host and WebAssembly. /// /// Spec: -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct Table(pub(crate) table_impl::Table); impl Table { @@ -113,12 +113,6 @@ impl Table { } } -impl std::cmp::PartialEq for Table { - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 - } -} - impl std::cmp::Eq for Table {} impl<'a> Exportable<'a> for Table { diff --git a/lib/api/src/imports.rs b/lib/api/src/imports.rs index f0b4f231c88..f50b2c2e7f7 100644 --- a/lib/api/src/imports.rs +++ b/lib/api/src/imports.rs @@ -304,7 +304,7 @@ macro_rules! import_namespace { #[cfg(test)] mod test { - use crate::store::{AsStoreMut, Store}; + use crate::store::Store; use crate::value::Value; use crate::Extern; use crate::Global; diff --git a/lib/api/src/js/externals/table.rs b/lib/api/src/js/externals/table.rs index 41a6e876af6..715829ccc11 100644 --- a/lib/api/src/js/externals/table.rs +++ b/lib/api/src/js/externals/table.rs @@ -23,7 +23,7 @@ fn get_function(store: &mut impl AsStoreMut, val: Value) -> Result Ok(func.0.handle.function.clone().into()), // Only funcrefs is supported by the spec atm - _ => unimplemented!(), + _ => unimplemented!("The {val:?} is not yet supported"), } } diff --git a/lib/api/src/sys/externals/function.rs b/lib/api/src/sys/externals/function.rs index 918737489d2..47f59b8053b 100644 --- a/lib/api/src/sys/externals/function.rs +++ b/lib/api/src/sys/externals/function.rs @@ -14,7 +14,7 @@ use wasmer_vm::{ VMFunction, VMFunctionBody, VMFunctionContext, VMFunctionKind, VMTrampoline, }; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct Function { pub(crate) handle: StoreHandle, } diff --git a/lib/api/src/sys/tunables.rs b/lib/api/src/sys/tunables.rs index 0e7946b8203..cc26e64b354 100644 --- a/lib/api/src/sys/tunables.rs +++ b/lib/api/src/sys/tunables.rs @@ -228,7 +228,7 @@ mod tests { #[test] fn check_customtunables() -> Result<(), Box> { - use crate::{imports, wat2wasm, Instance, Memory, Module, Store}; + use crate::{imports, wat2wasm, Engine, Instance, Memory, Module, Store}; use wasmer_compiler_cranelift::Cranelift; let wasm_bytes = wat2wasm( @@ -242,7 +242,9 @@ mod tests { let compiler = Cranelift::default(); let tunables = TinyTunables {}; - let mut store = Store::new_with_tunables(compiler, tunables); + let mut engine = Engine::new(compiler.into(), Default::default(), Default::default()); + engine.set_tunables(tunables); + let mut store = Store::new(engine); //let mut store = Store::new(compiler); let module = Module::new(&store, wasm_bytes)?; let import_object = imports! {}; From db6dd420e1b6aaf76f4a1aafbe48955c4b8cf94c Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Thu, 16 Feb 2023 20:44:49 -0800 Subject: [PATCH 53/81] Optimized ModuleInfo usage --- lib/api/src/module.rs | 4 ++-- lib/api/src/sys/module.rs | 21 +++++++------------ lib/compiler-singlepass/src/compiler.rs | 2 +- .../src/artifact_builders/artifact_builder.rs | 16 ++++++++++++-- lib/compiler/src/engine/artifact.rs | 18 +++++++++++----- lib/compiler/src/engine/trap/frame_info.rs | 6 +++--- lib/compiler/src/traits.rs | 9 +++++++- lib/types/src/compilation/module.rs | 3 ++- lib/types/src/serialize.rs | 7 ++++++- 9 files changed, 57 insertions(+), 29 deletions(-) diff --git a/lib/api/src/module.rs b/lib/api/src/module.rs index 0e53a9d8ef4..60dd287ac78 100644 --- a/lib/api/src/module.rs +++ b/lib/api/src/module.rs @@ -293,8 +293,8 @@ impl 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). + /// and return `false` otherwise (in case the module is cloned or + /// already instantiated). /// /// # Example /// diff --git a/lib/api/src/sys/module.rs b/lib/api/src/sys/module.rs index 9d38eb0cd7c..1ddb7d9b356 100644 --- a/lib/api/src/sys/module.rs +++ b/lib/api/src/sys/module.rs @@ -29,7 +29,6 @@ pub struct Module { // In the future, this code should be refactored to properly describe the // ownership of the code and its metadata. artifact: Arc, - module_info: Arc, } impl Module { @@ -91,10 +90,7 @@ impl Module { } fn from_artifact(artifact: Arc) -> Self { - Self { - module_info: Arc::new(artifact.create_module_info()), - artifact, - } + Self { artifact } } pub(crate) fn instantiate( @@ -140,32 +136,31 @@ impl Module { } pub(crate) fn name(&self) -> Option<&str> { - self.module_info.name.as_deref() + self.info().name.as_deref() } 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 + Arc::get_mut(&mut self.artifact).map_or(false, |artifact| { + artifact.set_module_info_name(name.to_string()) }) } pub(crate) fn imports(&self) -> ImportsIterator + '_> { - self.module_info.imports() + self.info().imports() } pub(crate) fn exports(&self) -> ExportsIterator + '_> { - self.module_info.exports() + self.info().exports() } pub(crate) fn custom_sections<'a>( &'a self, name: &'a str, ) -> impl Iterator> + 'a { - self.module_info.custom_sections(name) + self.info().custom_sections(name) } pub(crate) fn info(&self) -> &ModuleInfo { - &self.module_info + self.artifact.module_info() } } diff --git a/lib/compiler-singlepass/src/compiler.rs b/lib/compiler-singlepass/src/compiler.rs index 5cee5d4ec5b..961712556f5 100644 --- a/lib/compiler-singlepass/src/compiler.rs +++ b/lib/compiler-singlepass/src/compiler.rs @@ -302,7 +302,7 @@ mod tests { ) { let compile_info = CompileModuleInfo { features: Features::new(), - module: ModuleInfo::new(), + module: Arc::new(ModuleInfo::new()), memory_styles: PrimaryMap::::new(), table_styles: PrimaryMap::::new(), }; diff --git a/lib/compiler/src/artifact_builders/artifact_builder.rs b/lib/compiler/src/artifact_builders/artifact_builder.rs index f1940bdc1e6..cc79feb7b0d 100644 --- a/lib/compiler/src/artifact_builders/artifact_builder.rs +++ b/lib/compiler/src/artifact_builders/artifact_builder.rs @@ -8,6 +8,7 @@ use crate::EngineInner; use crate::Features; use crate::{ModuleEnvironment, ModuleMiddlewareChain}; use enumset::EnumSet; +use std::sync::Arc; use wasmer_types::entity::PrimaryMap; #[cfg(feature = "compiler")] use wasmer_types::CompileModuleInfo; @@ -57,7 +58,7 @@ impl ArtifactBuild { middlewares.apply_on_module_info(&mut module); let compile_info = CompileModuleInfo { - module, + module: Arc::new(module), features, memory_styles, table_styles, @@ -195,10 +196,21 @@ impl ArtifactBuild { } impl ArtifactCreate for ArtifactBuild { - fn create_module_info(&self) -> ModuleInfo { + fn create_module_info(&self) -> Arc { self.serializable.compile_info.module.clone() } + fn set_module_info_name(&mut self, name: String) -> bool { + Arc::get_mut(&mut self.serializable.compile_info.module).map_or(false, |mut module_info| { + module_info.name = Some(name.to_string()); + true + }) + } + + fn module_info(&self) -> &ModuleInfo { + &self.serializable.compile_info.module + } + fn features(&self) -> &Features { &self.serializable.compile_info.features } diff --git a/lib/compiler/src/engine/artifact.rs b/lib/compiler/src/engine/artifact.rs index a9f95b8873d..4ef218a8dc2 100644 --- a/lib/compiler/src/engine/artifact.rs +++ b/lib/compiler/src/engine/artifact.rs @@ -149,7 +149,7 @@ impl Artifact { allocated: None, }); } - let module_info = artifact.create_module_info(); + let module_info = artifact.module_info(); let ( finished_functions, finished_function_call_trampolines, @@ -237,10 +237,18 @@ impl Artifact { } impl ArtifactCreate for Artifact { - fn create_module_info(&self) -> ModuleInfo { + fn set_module_info_name(&mut self, name: String) -> bool { + self.artifact.set_module_info_name(name) + } + + fn create_module_info(&self) -> Arc { self.artifact.create_module_info() } + fn module_info(&self) -> &ModuleInfo { + self.artifact.module_info() + } + fn features(&self) -> &Features { self.artifact.features() } @@ -381,7 +389,7 @@ impl Artifact { self.preinstantiate()?; - let module = Arc::new(self.create_module_info()); + let module = self.create_module_info(); let imports = resolve_imports( &module, imports, @@ -499,7 +507,7 @@ impl Artifact { .collect(); let compile_info = CompileModuleInfo { - module, + module: Arc::new(module), features: features.clone(), memory_styles, table_styles, @@ -576,7 +584,7 @@ impl Artifact { features: &Features, ) -> Result< ( - ModuleInfo, + Arc, Object<'data>, usize, Box, diff --git a/lib/compiler/src/engine/trap/frame_info.rs b/lib/compiler/src/engine/trap/frame_info.rs index c7bf7034d73..a23f7607f94 100644 --- a/lib/compiler/src/engine/trap/frame_info.rs +++ b/lib/compiler/src/engine/trap/frame_info.rs @@ -13,7 +13,7 @@ //! ``` use std::cmp; use std::collections::BTreeMap; -use std::sync::RwLock; +use std::sync::{Arc, RwLock}; use wasmer_types::entity::{BoxedSlice, EntityRef, PrimaryMap}; use wasmer_types::{CompiledFunctionFrameInfo, SourceLoc, TrapInformation}; use wasmer_types::{LocalFunctionIndex, ModuleInfo}; @@ -54,7 +54,7 @@ pub struct GlobalFrameInfoRegistration { struct ModuleInfoFrameInfo { start: usize, functions: BTreeMap, - module: ModuleInfo, + module: Arc, frame_infos: PrimaryMap, } @@ -187,7 +187,7 @@ pub struct FunctionExtent { /// then `None` will be returned. Otherwise the returned object, when /// dropped, will be used to unregister all name information from this map. pub fn register( - module: ModuleInfo, + module: Arc, finished_functions: &BoxedSlice, frame_infos: PrimaryMap, ) -> Option { diff --git a/lib/compiler/src/traits.rs b/lib/compiler/src/traits.rs index 99b3c43e44a..b33426ad09f 100644 --- a/lib/compiler/src/traits.rs +++ b/lib/compiler/src/traits.rs @@ -3,6 +3,7 @@ use crate::Features; use enumset::EnumSet; use std::any::Any; +use std::sync::Arc; use wasmer_types::entity::PrimaryMap; use wasmer_types::SerializeError; use wasmer_types::{ @@ -17,7 +18,13 @@ use wasmer_types::{ /// module at runtime, such as [`ModuleInfo`] and [`Features`]. pub trait ArtifactCreate: Send + Sync + Upcastable { /// Create a `ModuleInfo` for instantiation - fn create_module_info(&self) -> ModuleInfo; + fn create_module_info(&self) -> Arc; + + /// Sets the `ModuleInfo` name + fn set_module_info_name(&mut self, name: String) -> bool; + + /// Returns the `ModuleInfo` for instantiation + fn module_info(&self) -> &ModuleInfo; /// Returns the features for this Artifact fn features(&self) -> &Features; diff --git a/lib/types/src/compilation/module.rs b/lib/types/src/compilation/module.rs index 461511de404..9869e6cfce3 100644 --- a/lib/types/src/compilation/module.rs +++ b/lib/types/src/compilation/module.rs @@ -4,6 +4,7 @@ use crate::{Features, MemoryIndex, MemoryStyle, ModuleInfo, TableIndex, TableSty use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize}; #[cfg(feature = "enable-serde")] use serde::{Deserialize, Serialize}; +use std::sync::Arc; /// The required info for compiling a module. /// @@ -16,7 +17,7 @@ pub struct CompileModuleInfo { /// The features used for compiling the module pub features: Features, /// The module information - pub module: ModuleInfo, + pub module: Arc, /// The memory styles used for compiling. /// /// The compiler will emit the most optimal code based diff --git a/lib/types/src/serialize.rs b/lib/types/src/serialize.rs index 4f04056134d..1d92854ddfd 100644 --- a/lib/types/src/serialize.rs +++ b/lib/types/src/serialize.rs @@ -128,7 +128,12 @@ impl SerializableModule { /// Create a `ModuleInfo` for instantiation pub fn create_module_info(&self) -> ModuleInfo { - self.compile_info.module.clone() + self.compile_info.module.as_ref().clone() + } + + /// Returns the `ModuleInfo` for instantiation + pub fn module_info(&self) -> &ModuleInfo { + &self.compile_info.module } /// Returns the features for this Artifact From d85297fddc9c7466f909ce11ce2813c42cad1cf0 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Thu, 16 Feb 2023 21:21:44 -0800 Subject: [PATCH 54/81] Fix linting and compilation --- lib/api/src/externals/mod.rs | 2 +- lib/api/src/sys/externals/function.rs | 2 +- lib/compiler/src/engine/artifact.rs | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/api/src/externals/mod.rs b/lib/api/src/externals/mod.rs index 5ac16b4104d..748a08834e3 100644 --- a/lib/api/src/externals/mod.rs +++ b/lib/api/src/externals/mod.rs @@ -25,7 +25,7 @@ use crate::store::{AsStoreMut, AsStoreRef}; /// can be imported or exported. /// /// Spec: -#[derive(Clone, PartialEq)] +#[derive(Clone, PartialEq, Eq)] pub enum Extern { /// A external [`Function`]. Function(Function), diff --git a/lib/api/src/sys/externals/function.rs b/lib/api/src/sys/externals/function.rs index 47f59b8053b..9448c967b5b 100644 --- a/lib/api/src/sys/externals/function.rs +++ b/lib/api/src/sys/externals/function.rs @@ -14,7 +14,7 @@ use wasmer_vm::{ VMFunction, VMFunctionBody, VMFunctionContext, VMFunctionKind, VMTrampoline, }; -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct Function { pub(crate) handle: StoreHandle, } diff --git a/lib/compiler/src/engine/artifact.rs b/lib/compiler/src/engine/artifact.rs index 4ef218a8dc2..d67a5748c12 100644 --- a/lib/compiler/src/engine/artifact.rs +++ b/lib/compiler/src/engine/artifact.rs @@ -156,7 +156,7 @@ impl Artifact { finished_dynamic_function_trampolines, custom_sections, ) = engine_inner.allocate( - &module_info, + module_info, artifact.get_function_bodies_ref(), artifact.get_function_call_trampolines_ref(), artifact.get_dynamic_function_trampolines_ref(), @@ -164,7 +164,7 @@ impl Artifact { )?; link_module( - &module_info, + module_info, &finished_functions, artifact.get_function_relocations(), &custom_sections, @@ -584,7 +584,7 @@ impl Artifact { features: &Features, ) -> Result< ( - Arc, + ModuleInfo, Object<'data>, usize, Box, @@ -646,7 +646,7 @@ impl Artifact { emit_compilation(&mut obj, compilation, &symbol_registry, target_triple) .map_err(to_compile_error)?; Ok(( - metadata.compile_info.module, + Arc::try_unwrap(metadata.compile_info.module).unwrap(), obj, metadata_binary.len(), Box::new(symbol_registry), From b61e2a128780c82089f52ccea5f0a25f4d5c1c97 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Thu, 16 Feb 2023 21:56:44 -0800 Subject: [PATCH 55/81] Added equality to instance, Module and Exports --- lib/api/src/exports.rs | 2 +- lib/api/src/instance.rs | 2 +- lib/api/src/js/instance.rs | 2 +- lib/api/src/js/module.rs | 4 +- lib/api/src/module.rs | 2 +- lib/api/src/sys/instance.rs | 2 +- lib/api/src/sys/module.rs | 2 +- lib/compiler/src/engine/artifact.rs | 59 +++++++++++++++++++++++++++++ 8 files changed, 67 insertions(+), 8 deletions(-) diff --git a/lib/api/src/exports.rs b/lib/api/src/exports.rs index b263ee7fd29..a9304341f7c 100644 --- a/lib/api/src/exports.rs +++ b/lib/api/src/exports.rs @@ -57,7 +57,7 @@ pub enum ExportError { /// the types of instances. /// /// TODO: add examples of using exports -#[derive(Clone, Default)] +#[derive(Clone, Default, PartialEq, Eq)] pub struct Exports { map: IndexMap, } diff --git a/lib/api/src/instance.rs b/lib/api/src/instance.rs index 348633f60f8..86ab381d3d8 100644 --- a/lib/api/src/instance.rs +++ b/lib/api/src/instance.rs @@ -19,7 +19,7 @@ use crate::sys::instance as instance_imp; /// interacting with WebAssembly. /// /// Spec: -#[derive(Clone)] +#[derive(Clone, PartialEq, Eq)] pub struct Instance { pub(crate) _inner: instance_imp::Instance, pub(crate) module: Module, diff --git a/lib/api/src/js/instance.rs b/lib/api/src/js/instance.rs index f392ea17216..1efac02eb92 100644 --- a/lib/api/src/js/instance.rs +++ b/lib/api/src/js/instance.rs @@ -9,7 +9,7 @@ use crate::Extern; use crate::{LinkError, RuntimeError}; use js_sys::WebAssembly; -#[derive(Clone)] +#[derive(Clone, PartialEq, Eq)] pub struct Instance { pub(crate) _handle: VMInstance, } diff --git a/lib/api/src/js/module.rs b/lib/api/src/js/module.rs index 68245d6c5f8..fb1476c4ee1 100644 --- a/lib/api/src/js/module.rs +++ b/lib/api/src/js/module.rs @@ -32,7 +32,7 @@ use wasmer_types::{ /// /// Until that happens, we annotate the module with the expected /// types so we can built on top of them at runtime. -#[derive(Clone)] +#[derive(Clone, PartialEq, Eq)] pub struct ModuleTypeHints { /// The type hints for the imported types pub imports: Vec, @@ -40,7 +40,7 @@ pub struct ModuleTypeHints { pub exports: Vec, } -#[derive(Clone)] +#[derive(Clone, PartialEq, Eq)] pub struct Module { module: WebAssembly::Module, name: Option, diff --git a/lib/api/src/module.rs b/lib/api/src/module.rs index 60dd287ac78..87cfb7b39e9 100644 --- a/lib/api/src/module.rs +++ b/lib/api/src/module.rs @@ -39,7 +39,7 @@ pub enum IoCompileError { /// /// Cloning a module is cheap: it does a shallow copy of the compiled /// contents rather than a deep copy. -#[derive(Clone)] +#[derive(Clone, PartialEq, Eq)] pub struct Module(pub(crate) module_imp::Module); impl Module { diff --git a/lib/api/src/sys/instance.rs b/lib/api/src/sys/instance.rs index a2ef1cbc334..3a23e360368 100644 --- a/lib/api/src/sys/instance.rs +++ b/lib/api/src/sys/instance.rs @@ -7,7 +7,7 @@ use crate::imports::Imports; use crate::store::AsStoreMut; use crate::Extern; -#[derive(Clone)] +#[derive(Clone, PartialEq, Eq)] pub struct Instance { _handle: StoreHandle, } diff --git a/lib/api/src/sys/module.rs b/lib/api/src/sys/module.rs index 1ddb7d9b356..42b951df4af 100644 --- a/lib/api/src/sys/module.rs +++ b/lib/api/src/sys/module.rs @@ -12,7 +12,7 @@ use wasmer_types::{ExportType, ImportType}; use crate::vm::VMInstance; use crate::{AsStoreMut, AsStoreRef, InstantiationError, IntoBytes}; -#[derive(Clone)] +#[derive(Clone, PartialEq, Eq)] pub struct Module { // The field ordering here is actually significant because of the drop // order: we want to drop the artifact before dropping the engine. diff --git a/lib/compiler/src/engine/artifact.rs b/lib/compiler/src/engine/artifact.rs index d67a5748c12..6505ed3dde2 100644 --- a/lib/compiler/src/engine/artifact.rs +++ b/lib/compiler/src/engine/artifact.rs @@ -16,6 +16,7 @@ use crate::{Engine, EngineInner}; use enumset::EnumSet; #[cfg(any(feature = "static-artifact-create", feature = "static-artifact-load"))] use std::mem; +use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; use std::sync::Arc; use std::sync::Mutex; #[cfg(feature = "static-artifact-create")] @@ -46,8 +47,38 @@ pub struct AllocatedArtifact { finished_function_lengths: BoxedSlice, } +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] +#[repr(transparent)] +/// A unique identifier for an Artifact. +pub struct ArtifactId { + id: usize, +} + +impl ArtifactId { + /// Format this identifier as a string. + pub fn id(&self) -> String { + format!("{}", &self.id) + } +} + +impl Clone for ArtifactId { + fn clone(&self) -> Self { + Self::default() + } +} + +impl Default for ArtifactId { + fn default() -> Self { + static NEXT_ID: AtomicUsize = AtomicUsize::new(0); + Self { + id: NEXT_ID.fetch_add(1, SeqCst), + } + } +} + /// A compiled wasm module, ready to be instantiated. pub struct Artifact { + id: ArtifactId, artifact: ArtifactBuild, // The artifact will only be allocated in memory in case we can execute it // (that means, if the target != host then this will be None). @@ -95,6 +126,15 @@ impl Artifact { self.allocated.is_some() } + /// A unique identifier for this object. + /// + /// This exists to allow us to compare two Artifacts for equality. Otherwise, + /// comparing two trait objects unsafely relies on implementation details + /// of trait representation. + pub fn id(&self) -> &ArtifactId { + &self.id + } + /// Compile a data buffer into a `ArtifactBuild`, which may then be instantiated. #[cfg(not(feature = "compiler"))] pub fn new(_engine: &Engine, _data: &[u8]) -> Result { @@ -145,6 +185,7 @@ impl Artifact { ) -> Result { if !target.is_native() { return Ok(Self { + id: Default::default(), artifact, allocated: None, }); @@ -218,6 +259,7 @@ impl Artifact { let signatures = signatures.into_boxed_slice(); Ok(Self { + id: Default::default(), artifact, allocated: Some(AllocatedArtifact { finished_functions, @@ -236,6 +278,22 @@ impl Artifact { } } +impl PartialEq for Artifact { + fn eq(&self, other: &Self) -> bool { + self.id == other.id + } +} +impl Eq for Artifact {} + +impl std::fmt::Debug for Artifact { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("Artifact") + .field("artifact_id", &self.id) + .field("module_info", &self.module_info()) + .finish() + } +} + impl ArtifactCreate for Artifact { fn set_module_info_name(&mut self, name: String) -> bool { self.artifact.set_module_info_name(name) @@ -783,6 +841,7 @@ impl Artifact { .into_boxed_slice(); Ok(Self { + id: Default::default(), artifact, allocated: Some(AllocatedArtifact { finished_functions: finished_functions.into_boxed_slice(), From bb9ac04336343224fce1c11fcfcb7abe1983df79 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Thu, 16 Feb 2023 22:45:28 -0800 Subject: [PATCH 56/81] Make API compatible changes with wasmer-js --- lib/api/src/js/as_js.rs | 5 ++--- lib/api/src/js/module.rs | 6 ++++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/api/src/js/as_js.rs b/lib/api/src/js/as_js.rs index d9272c972aa..c679638a248 100644 --- a/lib/api/src/js/as_js.rs +++ b/lib/api/src/js/as_js.rs @@ -4,11 +4,10 @@ use crate::imports::Imports; use crate::instance::Instance; use crate::js::instance::Instance as JsInstance; -use crate::js::vm::{VMExtern, VMFunction, VMGlobal, VMMemory, VMTable}; +use crate::js::vm::{VMFunction, VMGlobal, VMMemory, VMTable}; use crate::js::wasm_bindgen_polyfill::Global as JsGlobal; use crate::store::{AsStoreMut, AsStoreRef}; use crate::value::Value; -use crate::Exports; use crate::Type; use crate::{Extern, Function, Global, Memory, Table}; use js_sys::Function as JsFunction; @@ -88,7 +87,7 @@ impl AsJs for wasmer_types::RawValue { } impl AsJs for Imports { - type DefinitionType = crate::js::module::Module; + type DefinitionType = crate::module::Module; // Annotation is here to prevent spurious IDE warnings. #[allow(unused_unsafe)] diff --git a/lib/api/src/js/module.rs b/lib/api/src/js/module.rs index fb1476c4ee1..a45a5ead6fb 100644 --- a/lib/api/src/js/module.rs +++ b/lib/api/src/js/module.rs @@ -444,3 +444,9 @@ impl From for Module { } } } + +impl From for crate::module::Module { + fn from(module: WebAssembly::Module) -> crate::module::Module { + crate::module::Module(module.into()) + } +} From 1f64ba13e0f654a27c13152723c2d23be054a7d0 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Fri, 24 Feb 2023 13:35:46 -0800 Subject: [PATCH 57/81] Wrap engine --- lib/api/src/engine.rs | 51 ++++++++++++++----- lib/api/src/store.rs | 6 ++- lib/api/src/sys/engine.rs | 72 ++++++++++++++++++++++++++- lib/api/src/sys/externals/function.rs | 4 ++ lib/api/src/sys/externals/memory.rs | 1 + lib/api/src/sys/externals/table.rs | 1 + lib/api/src/sys/mod.rs | 1 + lib/api/src/sys/module.rs | 8 +-- lib/api/src/sys/tunables.rs | 1 + lib/cli/src/commands/create_exe.rs | 10 ++-- lib/compiler/src/engine/inner.rs | 14 +++--- 11 files changed, 138 insertions(+), 31 deletions(-) diff --git a/lib/api/src/engine.rs b/lib/api/src/engine.rs index a60b078b5b4..cd34b88ad38 100644 --- a/lib/api/src/engine.rs +++ b/lib/api/src/engine.rs @@ -1,4 +1,4 @@ -// use core::ops::Deref; +use core::ops::Deref; #[cfg(feature = "sys")] use crate::sys::engine as engine_imp; @@ -11,7 +11,7 @@ use crate::js::engine as engine_imp; pub(crate) use crate::js::engine::default_engine; /// The engine type -pub type Engine = engine_imp::Engine; +pub struct Engine(pub(crate) engine_imp::Engine); impl AsEngineRef for Engine { fn as_engine_ref(&self) -> EngineRef { @@ -19,6 +19,34 @@ impl AsEngineRef for Engine { } } +impl Default for Engine { + fn default() -> Self { + Engine(default_engine()) + } +} + +// impl Into for engine_imp::Engine { +// fn into(self) -> Engine { +// Engine(self) +// } +// } + +impl From for Engine { + fn from(inner: engine_imp::Engine) -> Self { + Self(inner) + } +} + +// impl

Into for P +// where +// P: Into +// { +// fn into(self) -> Engine { +// let inner_engine: engine_imp::Engine = self.into(); +// Engine(inner_engine) +// } +// } + /// A temporary handle to an [`Engine`] /// EngineRef can be used to build a [`Module`][wasmer::Module] /// It can be created directly with an [`Engine`] @@ -52,13 +80,12 @@ impl AsEngineRef for EngineRef<'_> { } } -// impl

AsEngineRef for P -// where -// P: Deref, -// P::Target: AsEngineRef, -// { -// fn as_engine_ref(&self) -> EngineRef<'_> { -// EngineRef { inner: **self } -// (**self).as_engine_ref() -// } -// } +impl

AsEngineRef for P +where + P: Deref, + P::Target: AsEngineRef, +{ + fn as_engine_ref(&self) -> EngineRef<'_> { + (**self).as_engine_ref() + } +} diff --git a/lib/api/src/store.rs b/lib/api/src/store.rs index 562a223578b..7111c50226d 100644 --- a/lib/api/src/store.rs +++ b/lib/api/src/store.rs @@ -1,4 +1,4 @@ -use crate::engine::{default_engine, AsEngineRef, Engine, EngineRef}; +use crate::engine::{AsEngineRef, Engine, EngineRef}; use derivative::Derivative; use std::{ fmt, @@ -12,6 +12,8 @@ use wasmer_vm::init_traps; #[cfg(feature = "sys")] pub use wasmer_vm::TrapHandlerFn; +#[cfg(feature = "sys")] +use crate::sys::WasmerCompilerEngine; #[cfg(feature = "sys")] pub use wasmer_vm::{StoreHandle, StoreObjects}; @@ -143,7 +145,7 @@ unsafe impl Sync for Store {} impl Default for Store { fn default() -> Self { - Self::new(default_engine()) + Self::new(Engine::default()) } } diff --git a/lib/api/src/sys/engine.rs b/lib/api/src/sys/engine.rs index 97e58841463..1eac9ab9056 100644 --- a/lib/api/src/sys/engine.rs +++ b/lib/api/src/sys/engine.rs @@ -1,5 +1,7 @@ -pub use wasmer_compiler::BaseTunables; -pub use wasmer_compiler::{Artifact, Engine, EngineBuilder}; +pub use wasmer_compiler::{ + Artifact, BaseTunables, CompilerConfig, Engine, EngineBuilder, Tunables, +}; +use wasmer_types::{Features, Target}; /// Returns the default engine for the Sys engine pub(crate) fn default_engine() -> Engine { @@ -48,3 +50,69 @@ pub(crate) fn default_engine() -> Engine { engine.set_tunables(tunables); engine } + +impl From for crate::engine::Engine { + fn from(builder: EngineBuilder) -> Self { + Self(builder.into()) + } +} + +// impl From for crate::engine::Engine { +// fn from(compiler: CompilerConfig) -> Self { +// Self(compiler.into()) +// } +// } + +/// The custom trait to access to all the `sys` function in the common +/// engine. +pub trait WasmerCompilerEngine { + /// Create a new `Engine` with the given config + #[cfg(feature = "compiler")] + fn new(compiler_config: Box, target: Target, features: Features) -> Self; + + /// Create a headless `Engine` + /// + /// A headless engine is an engine without any compiler attached. + /// This is useful for assuring a minimal runtime for running + /// WebAssembly modules. + /// + /// For example, for running in IoT devices where compilers are very + /// expensive, or also to optimize startup speed. + /// + /// # Important + /// + /// Headless engines can't compile or validate any modules, + /// they just take already processed Modules (via `Module::serialize`). + fn headless() -> Self; + + /// Gets the target + fn target(&self) -> &Target; + + /// Attach a Tunable to this engine + fn set_tunables(&mut self, tunables: impl Tunables + Send + Sync + 'static); + + /// Get a reference to attached Tunable of this engine + fn tunables(&self) -> &dyn Tunables; +} + +impl WasmerCompilerEngine for crate::engine::Engine { + fn new(compiler_config: Box, target: Target, features: Features) -> Self { + crate::engine::Engine(Engine::new(compiler_config, target, features)) + } + + fn headless() -> Self { + crate::engine::Engine(Engine::headless()) + } + + fn target(&self) -> &Target { + self.0.target() + } + + fn set_tunables(&mut self, tunables: impl Tunables + Send + Sync + 'static) { + self.0.set_tunables(tunables) + } + + fn tunables(&self) -> &dyn Tunables { + self.0.tunables() + } +} diff --git a/lib/api/src/sys/externals/function.rs b/lib/api/src/sys/externals/function.rs index 9448c967b5b..0cf970a1e4d 100644 --- a/lib/api/src/sys/externals/function.rs +++ b/lib/api/src/sys/externals/function.rs @@ -86,6 +86,7 @@ impl Function { let type_index = store .as_store_mut() .engine() + .0 .register_signature(&function_type); let vmctx = VMFunctionContext { host_env: host_data.as_ref() as *const _ as *mut c_void, @@ -128,6 +129,7 @@ impl Function { let type_index = store .as_store_mut() .engine() + .0 .register_signature(&function_type); let vmctx = VMFunctionContext { host_env: host_data.as_ref() as *const _ as *mut c_void, @@ -173,6 +175,7 @@ impl Function { let type_index = store .as_store_mut() .engine() + .0 .register_signature(&function_type); let vmctx = VMFunctionContext { host_env: host_data.as_ref() as *const _ as *mut c_void, @@ -368,6 +371,7 @@ impl Function { let signature = store .as_store_ref() .engine() + .0 .lookup_signature(funcref.0.as_ref().type_index) .expect("Signature not found in store"); let vm_function = VMFunction { diff --git a/lib/api/src/sys/externals/memory.rs b/lib/api/src/sys/externals/memory.rs index e48be91f76a..63c1711dd14 100644 --- a/lib/api/src/sys/externals/memory.rs +++ b/lib/api/src/sys/externals/memory.rs @@ -1,5 +1,6 @@ use super::memory_view::MemoryView; use crate::store::{AsStoreMut, AsStoreRef}; +use crate::sys::WasmerCompilerEngine; use crate::vm::VMExternMemory; use crate::MemoryAccessError; use crate::MemoryType; diff --git a/lib/api/src/sys/externals/table.rs b/lib/api/src/sys/externals/table.rs index 3067094c91b..646dd30e8a1 100644 --- a/lib/api/src/sys/externals/table.rs +++ b/lib/api/src/sys/externals/table.rs @@ -1,4 +1,5 @@ use crate::store::{AsStoreMut, AsStoreRef}; +use crate::sys::WasmerCompilerEngine; use crate::TableType; use crate::Value; use crate::{vm::VMExternTable, ExternRef, Function, RuntimeError}; diff --git a/lib/api/src/sys/mod.rs b/lib/api/src/sys/mod.rs index 8132a827f31..0fc537a546b 100644 --- a/lib/api/src/sys/mod.rs +++ b/lib/api/src/sys/mod.rs @@ -6,6 +6,7 @@ pub(crate) mod module; mod tunables; pub(crate) mod typed_function; +pub use crate::sys::engine::WasmerCompilerEngine; pub use crate::sys::tunables::BaseTunables; pub use target_lexicon::{Architecture, CallingConvention, OperatingSystem, Triple, HOST}; #[cfg(feature = "compiler")] diff --git a/lib/api/src/sys/module.rs b/lib/api/src/sys/module.rs index 42b951df4af..4d450b141e6 100644 --- a/lib/api/src/sys/module.rs +++ b/lib/api/src/sys/module.rs @@ -1,4 +1,5 @@ use crate::engine::AsEngineRef; +use crate::sys::engine::WasmerCompilerEngine; use bytes::Bytes; use std::path::Path; use std::sync::Arc; @@ -49,12 +50,12 @@ impl Module { } pub(crate) fn validate(engine: &impl AsEngineRef, binary: &[u8]) -> Result<(), CompileError> { - engine.as_engine_ref().engine().validate(binary) + engine.as_engine_ref().engine().0.validate(binary) } #[cfg(feature = "compiler")] fn compile(engine: &impl AsEngineRef, binary: &[u8]) -> Result { - let artifact = engine.as_engine_ref().engine().compile(binary)?; + let artifact = engine.as_engine_ref().engine().0.compile(binary)?; Ok(Self::from_artifact(artifact)) } @@ -74,7 +75,7 @@ impl Module { bytes: impl IntoBytes, ) -> Result { let bytes = bytes.into_bytes(); - let artifact = engine.as_engine_ref().engine().deserialize(&bytes)?; + let artifact = engine.as_engine_ref().engine().0.deserialize(&bytes)?; Ok(Self::from_artifact(artifact)) } @@ -85,6 +86,7 @@ impl Module { let artifact = engine .as_engine_ref() .engine() + .0 .deserialize_from_file(path.as_ref())?; Ok(Self::from_artifact(artifact)) } diff --git a/lib/api/src/sys/tunables.rs b/lib/api/src/sys/tunables.rs index cc26e64b354..379cedfcec8 100644 --- a/lib/api/src/sys/tunables.rs +++ b/lib/api/src/sys/tunables.rs @@ -6,6 +6,7 @@ pub use wasmer_compiler::BaseTunables; #[cfg(test)] mod tests { use super::*; + use crate::sys::WasmerCompilerEngine; use crate::TableType; use std::cell::UnsafeCell; use std::ptr::NonNull; diff --git a/lib/cli/src/commands/create_exe.rs b/lib/cli/src/commands/create_exe.rs index 6c0a9342c4c..4e3e7e74dc5 100644 --- a/lib/cli/src/commands/create_exe.rs +++ b/lib/cli/src/commands/create_exe.rs @@ -226,7 +226,7 @@ impl CreateExe { return Err(anyhow::anyhow!("input path cannot be a directory")); } - let (_, compiler_type) = self.compiler.get_store_for_target(target.clone())?; + let (store, compiler_type) = self.compiler.get_store_for_target(target.clone())?; println!("Compiler: {}", compiler_type.to_string()); println!("Target: {}", target.triple()); @@ -275,7 +275,7 @@ impl CreateExe { ) }?; - get_module_infos(&tempdir, &atoms, object_format)?; + get_module_infos(&mut store, &tempdir, &atoms, object_format)?; let mut entrypoint = get_entrypoint(&tempdir)?; create_header_files_in_dir(&tempdir, &mut entrypoint, &atoms, &self.precompiled_atom)?; link_exe_from_dir( @@ -963,6 +963,7 @@ pub(super) fn prepare_directory_from_single_wasm_file( // reads the module info from the wasm module and writes the ModuleInfo for each file // into the entrypoint.json file fn get_module_infos( + store: &mut Store, directory: &Path, atoms: &[(String, Vec)], object_format: ObjectFormat, @@ -972,9 +973,8 @@ fn get_module_infos( let mut module_infos = BTreeMap::new(); for (atom_name, atom_bytes) in atoms { - let module_info = Engine::get_module_info(atom_bytes.as_slice()) - .map_err(|e| anyhow::anyhow!("could not get module info for atom {atom_name}: {e}"))?; - + let module = Module::new(&mut store, atom_bytes.as_slice())?; + let module_info = module.info(); if let Some(s) = entrypoint .atoms .iter_mut() diff --git a/lib/compiler/src/engine/inner.rs b/lib/compiler/src/engine/inner.rs index 8b7e71d4fe9..6099be104f2 100644 --- a/lib/compiler/src/engine/inner.rs +++ b/lib/compiler/src/engine/inner.rs @@ -72,13 +72,13 @@ impl Engine { } } - /// Returns only the `ModuleInfo` given a `wasm` byte slice - #[cfg(feature = "compiler")] - pub fn get_module_info(data: &[u8]) -> Result { - // this is from `artifact_builder.rs` - let environ = crate::ModuleEnvironment::new(); - let translation = environ.translate(data).map_err(CompileError::Wasm)?; - Ok(translation.module) + #[cfg(not(feature = "compiler"))] + pub fn new( + compiler_config: Box, + target: Target, + features: Features, + ) -> Self { + panic!("The engine is not compiled with any compiler support") } /// Returns the name of this engine From 9ed86ad6dbba98ec1e93d7c6001118f77be5d545 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Fri, 24 Feb 2023 13:51:37 -0800 Subject: [PATCH 58/81] Make cli compilable again --- examples/tunables_limit_memory.rs | 2 ++ lib/cli/src/commands/create_exe.rs | 10 +++++----- lib/cli/src/commands/gen_c_header.rs | 5 ++--- lib/cli/src/store.rs | 7 +++++++ 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/examples/tunables_limit_memory.rs b/examples/tunables_limit_memory.rs index 8099aa4b19d..7902e5632ee 100644 --- a/examples/tunables_limit_memory.rs +++ b/examples/tunables_limit_memory.rs @@ -7,6 +7,8 @@ use wasmer::{ Target, Tunables, }; use wasmer_compiler_cranelift::Cranelift; +// This is to be able to set the tunables +use wasmer::WasmerCompilerEngine; /// A custom tunables that allows you to set a memory limit. /// diff --git a/lib/cli/src/commands/create_exe.rs b/lib/cli/src/commands/create_exe.rs index 4e3e7e74dc5..919c1ed98fb 100644 --- a/lib/cli/src/commands/create_exe.rs +++ b/lib/cli/src/commands/create_exe.rs @@ -226,7 +226,7 @@ impl CreateExe { return Err(anyhow::anyhow!("input path cannot be a directory")); } - let (store, compiler_type) = self.compiler.get_store_for_target(target.clone())?; + let (mut store, compiler_type) = self.compiler.get_store_for_target(target.clone())?; println!("Compiler: {}", compiler_type.to_string()); println!("Target: {}", target.triple()); @@ -749,14 +749,13 @@ fn compile_atoms( } continue; } - let (store, _) = compiler.get_store_for_target(target.clone())?; match object_format { ObjectFormat::Symbols => { - let engine = store.engine(); + let (engine, _) = compiler.get_engine_for_target(target.clone())?; let engine_inner = engine.inner(); let compiler = engine_inner.compiler()?; let features = engine_inner.features(); - let tunables = store.engine().tunables(); + let tunables = engine.tunables(); let (module_info, obj, _, _) = Artifact::generate_object( compiler, data, @@ -773,6 +772,7 @@ fn compile_atoms( writer.flush()?; } ObjectFormat::Serialized => { + let (store, _) = compiler.get_store_for_target(target.clone())?; let module_name = ModuleMetadataSymbolRegistry { prefix: prefix.clone(), } @@ -963,7 +963,7 @@ pub(super) fn prepare_directory_from_single_wasm_file( // reads the module info from the wasm module and writes the ModuleInfo for each file // into the entrypoint.json file fn get_module_infos( - store: &mut Store, + mut store: &mut Store, directory: &Path, atoms: &[(String, Vec)], object_format: ObjectFormat, diff --git a/lib/cli/src/commands/gen_c_header.rs b/lib/cli/src/commands/gen_c_header.rs index aa796408f58..7dd1847c22d 100644 --- a/lib/cli/src/commands/gen_c_header.rs +++ b/lib/cli/src/commands/gen_c_header.rs @@ -91,12 +91,11 @@ impl GenCHeader { &target_triple, &self.cpu_features, ); - let (store, _) = CompilerOptions::default().get_store_for_target(target.clone())?; - let engine = store.engine(); + let (engine, _) = CompilerOptions::default().get_engine_for_target(target.clone())?; let engine_inner = engine.inner(); let compiler = engine_inner.compiler()?; let features = engine_inner.features(); - let tunables = store.engine().tunables(); + let tunables = engine.tunables(); let (metadata, _, _) = Artifact::metadata( compiler, &file, diff --git a/lib/cli/src/store.rs b/lib/cli/src/store.rs index 49b897c7bc3..c78390c03a6 100644 --- a/lib/cli/src/store.rs +++ b/lib/cli/src/store.rs @@ -109,6 +109,13 @@ impl CompilerOptions { Ok((store, compiler_type)) } + /// Gets the Engine for a given target. + pub fn get_engine_for_target(&self, target: Target) -> Result<(Engine, CompilerType)> { + let (compiler_config, compiler_type) = self.get_compiler_config()?; + let engine = self.get_engine(target, compiler_config)?; + Ok((engine, compiler_type)) + } + #[cfg(feature = "compiler")] fn get_engine( &self, From a6ebf78fcbec16554311c4bcd1d7103a2f5ffc6f Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Fri, 24 Feb 2023 14:37:48 -0800 Subject: [PATCH 59/81] Verious fixes for the wasix merge --- lib/api/src/engine.rs | 17 +++++++++++++++++ lib/api/src/js/engine.rs | 9 ++++++++- lib/api/src/js/vm.rs | 5 ++++- lib/api/src/vm.rs | 5 +++-- lib/compiler/src/engine/inner.rs | 9 +++++++++ lib/wasi/src/bin_factory/exec.rs | 14 +++++--------- lib/wasi/src/bin_factory/module_cache.rs | 2 +- lib/wasi/src/lib.rs | 2 +- lib/wasi/src/state/env.rs | 4 +++- 9 files changed, 51 insertions(+), 16 deletions(-) diff --git a/lib/api/src/engine.rs b/lib/api/src/engine.rs index cd34b88ad38..605626aa493 100644 --- a/lib/api/src/engine.rs +++ b/lib/api/src/engine.rs @@ -11,8 +11,25 @@ use crate::js::engine as engine_imp; pub(crate) use crate::js::engine::default_engine; /// The engine type +#[derive(Clone, Debug)] pub struct Engine(pub(crate) engine_imp::Engine); +impl Engine { + #[deprecated( + since = "4.0.0", + note = "engine.cloned() has been deprecated in favor of engine.clone()" + )] + /// Returns the [`Tunables`]. + pub fn cloned(&self) -> Self { + self.clone() + } + + /// Returns the deterministic id of this engine + pub fn deterministic_id(&self) -> &str { + self.0.deterministic_id() + } +} + impl AsEngineRef for Engine { fn as_engine_ref(&self) -> EngineRef { EngineRef { inner: self } diff --git a/lib/api/src/js/engine.rs b/lib/api/src/js/engine.rs index 327d183bc65..a0930fb9bca 100644 --- a/lib/api/src/js/engine.rs +++ b/lib/api/src/js/engine.rs @@ -1,7 +1,14 @@ /// A WebAssembly `Universal` Engine. -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct Engine; +impl Engine { + pub(crate) fn deterministic_id(&self) -> &str { + // All js engines have the same id + "generic" + } +} + impl Default for Engine { fn default() -> Self { Engine diff --git a/lib/api/src/js/vm.rs b/lib/api/src/js/vm.rs index 6d5d3284d2e..98c367d88f8 100644 --- a/lib/api/src/js/vm.rs +++ b/lib/api/src/js/vm.rs @@ -107,6 +107,9 @@ impl VMMemory { } } +/// The shared memory is the same as the normal memory +pub type VMSharedMemory = VMMemory; + #[derive(Clone, Debug, PartialEq)] pub struct VMGlobal { pub(crate) global: JsGlobal, @@ -240,7 +243,7 @@ pub(crate) struct VMFuncRef; impl VMFuncRef { /// Converts the `VMFuncRef` into a `RawValue`. pub fn into_raw(self) -> RawValue { - unimplemented!() + Raw } /// Extracts a `VMFuncRef` from a `RawValue`. diff --git a/lib/api/src/vm.rs b/lib/api/src/vm.rs index 7681e14ae3e..e2dabb260d5 100644 --- a/lib/api/src/vm.rs +++ b/lib/api/src/vm.rs @@ -4,7 +4,7 @@ pub(crate) use crate::js::vm::{ VMExtern, VMExternFunction, VMExternGlobal, VMExternMemory, VMExternRef, VMExternTable, VMFuncRef, VMFunction, VMFunctionBody, VMFunctionEnvironment, VMGlobal, VMInstance, VMMemory, - VMTable, VMTrampoline, + VMSharedMemory, VMTable, VMTrampoline, }; #[cfg(feature = "sys")] @@ -13,7 +13,7 @@ pub(crate) use crate::sys::vm::{ VMFuncRef, VMFunctionBody, VMFunctionEnvironment, VMInstance, VMTrampoline, }; -// Needed for tunables customization +// Needed for tunables customization (those are public types now) #[cfg(feature = "sys")] pub use wasmer_vm::{ // An extra one for VMMemory implementors @@ -22,6 +22,7 @@ pub use wasmer_vm::{ VMGlobal, VMMemory, VMMemoryDefinition, + VMSharedMemory, VMTable, VMTableDefinition, }; diff --git a/lib/compiler/src/engine/inner.rs b/lib/compiler/src/engine/inner.rs index 6099be104f2..378d80daa9e 100644 --- a/lib/compiler/src/engine/inner.rs +++ b/lib/compiler/src/engine/inner.rs @@ -86,6 +86,15 @@ impl Engine { self.name.as_str() } + /// Returns the deterministic id of this engine + pub fn deterministic_id(&self) -> &str { + // TODO: add a `deterministic_id` to the Compiler, so two + // compilers can actually serialize into a different deterministic_id + // if their configuration is different (eg. LLVM with optimizations vs LLVM + // without optimizations) + self.name.as_str() + } + /// Create a headless `Engine` /// /// A headless engine is an engine without any compiler attached. diff --git a/lib/wasi/src/bin_factory/exec.rs b/lib/wasi/src/bin_factory/exec.rs index 0e7fcaedb2b..eec9ca32bbd 100644 --- a/lib/wasi/src/bin_factory/exec.rs +++ b/lib/wasi/src/bin_factory/exec.rs @@ -11,6 +11,8 @@ use crate::vbus::{ use futures::Future; use tokio::sync::mpsc; use tracing::*; +#[cfg(feature = "sys")] +use wasmer::WasmerCompilerEngine; use wasmer::{FunctionEnvMut, Instance, Memory, Module, Store}; use wasmer_wasi_types::wasi::{Errno, ExitCode}; @@ -28,16 +30,10 @@ pub fn spawn_exec( runtime: &Arc, compiled_modules: &ModuleCache, ) -> Result { - // Load the module - #[cfg(feature = "sys")] - let compiler = store.engine().name(); - #[cfg(not(feature = "sys"))] - let compiler = "generic"; + // The deterministic id for this engine + let compiler = store.engine().deterministic_id(); - #[cfg(feature = "sys")] let module = compiled_modules.get_compiled_module(&store, binary.hash().as_str(), compiler); - #[cfg(not(feature = "sys"))] - let module = compiled_modules.get_compiled_module(binary.hash().as_str(), compiler); let module = match (module, binary.entry.as_ref()) { (Some(a), _) => a, @@ -100,7 +96,7 @@ pub fn spawn_exec_module( let memory_spawn = match shared_memory { Some(ty) => { #[cfg(feature = "sys")] - let style = store.tunables().memory_style(&ty); + let style = store.engine().tunables().memory_style(&ty); SpawnType::CreateWithType(SpawnedMemory { ty, #[cfg(feature = "sys")] diff --git a/lib/wasi/src/bin_factory/module_cache.rs b/lib/wasi/src/bin_factory/module_cache.rs index 5e8ad83e788..b80ff6a9445 100644 --- a/lib/wasi/src/bin_factory/module_cache.rs +++ b/lib/wasi/src/bin_factory/module_cache.rs @@ -156,7 +156,7 @@ impl ModuleCache { pub fn get_compiled_module( &self, - #[cfg(feature = "sys")] engine: &impl wasmer::AsEngineRef, + engine: &impl wasmer::AsEngineRef, data_hash: &str, compiler: &str, ) -> Option { diff --git a/lib/wasi/src/lib.rs b/lib/wasi/src/lib.rs index 5757a4d4b0e..2b9c3055fbf 100644 --- a/lib/wasi/src/lib.rs +++ b/lib/wasi/src/lib.rs @@ -775,5 +775,5 @@ fn mem_error_to_bus(err: MemoryAccessError) -> BusErrno { #[cfg(all(feature = "sys"))] pub fn build_test_engine(features: Option) -> wasmer::Engine { let _ = features; - wasmer::Store::default().engine().cloned() + wasmer::Store::default().engine().clone() } diff --git a/lib/wasi/src/state/env.rs b/lib/wasi/src/state/env.rs index 60d50a7a30e..76690a517a7 100644 --- a/lib/wasi/src/state/env.rs +++ b/lib/wasi/src/state/env.rs @@ -3,6 +3,8 @@ use std::{collections::HashMap, ops::Deref, path::PathBuf, sync::Arc, time::Dura use derivative::Derivative; use rand::Rng; use tracing::{trace, warn}; +#[cfg(feature = "sys")] +use wasmer::WasmerCompilerEngine; use wasmer::{ AsStoreMut, AsStoreRef, FunctionEnvMut, Global, Instance, Memory, MemoryView, Module, TypedFunction, @@ -432,7 +434,7 @@ impl WasiEnv { match shared_memory { Some(ty) => { #[cfg(feature = "sys")] - let style = store.tunables().memory_style(&ty); + let style = store.engine().tunables().memory_style(&ty); SpawnType::CreateWithType(SpawnedMemory { ty, #[cfg(feature = "sys")] From 5bdf3d4e2b2482da76bcde6483f3e635fd80b241 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Fri, 24 Feb 2023 15:02:25 -0800 Subject: [PATCH 60/81] Fixed unimplemented --- lib/api/src/js/vm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/api/src/js/vm.rs b/lib/api/src/js/vm.rs index 98c367d88f8..1e48d0d676b 100644 --- a/lib/api/src/js/vm.rs +++ b/lib/api/src/js/vm.rs @@ -243,7 +243,7 @@ pub(crate) struct VMFuncRef; impl VMFuncRef { /// Converts the `VMFuncRef` into a `RawValue`. pub fn into_raw(self) -> RawValue { - Raw + unimplemented!(); } /// Extracts a `VMFuncRef` from a `RawValue`. From 93def03796e11e087f03a6943c96e6a3a353a6bd Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Sat, 25 Feb 2023 11:23:03 -0800 Subject: [PATCH 61/81] Address most of the comments --- lib/api/Cargo.toml | 1 + lib/api/src/engine.rs | 6 --- lib/api/src/errors.rs | 59 ++++++--------------- lib/api/src/js/extern_ref.rs | 8 +-- lib/api/src/js/module.rs | 3 +- lib/api/src/js/vm.rs | 5 ++ lib/api/src/store.rs | 2 +- lib/api/src/sys/engine.rs | 4 +- lib/api/src/sys/externals/memory.rs | 2 +- lib/api/src/sys/externals/table.rs | 2 +- lib/api/src/sys/mod.rs | 2 +- lib/api/src/sys/module.rs | 2 +- lib/api/src/sys/tunables.rs | 2 +- lib/api/src/vm.rs | 14 ++--- lib/wasi/src/bin_factory/exec.rs | 2 +- lib/wasi/src/runtime/task_manager/mod.rs | 7 +-- lib/wasi/src/state/env.rs | 2 +- lib/wasi/src/syscalls/wasix/proc_fork.rs | 3 -- lib/wasi/src/syscalls/wasix/thread_spawn.rs | 3 -- 19 files changed, 45 insertions(+), 84 deletions(-) diff --git a/lib/api/Cargo.toml b/lib/api/Cargo.toml index a08f8d87fb3..8817ba65fff 100644 --- a/lib/api/Cargo.toml +++ b/lib/api/Cargo.toml @@ -100,6 +100,7 @@ core = ["hashbrown"] sys = [ "wasmer-compiler/translator", "wasmer-compiler/compiler", + "std", ] sys-default = ["sys", "wat", "cranelift"] # - Compilers. diff --git a/lib/api/src/engine.rs b/lib/api/src/engine.rs index 605626aa493..10adb58189b 100644 --- a/lib/api/src/engine.rs +++ b/lib/api/src/engine.rs @@ -42,12 +42,6 @@ impl Default for Engine { } } -// impl Into for engine_imp::Engine { -// fn into(self) -> Engine { -// Engine(self) -// } -// } - impl From for Engine { fn from(inner: engine_imp::Engine) -> Self { Self(inner) diff --git a/lib/api/src/errors.rs b/lib/api/src/errors.rs index c5a9ad5ec94..4b65e654f46 100644 --- a/lib/api/src/errors.rs +++ b/lib/api/src/errors.rs @@ -4,43 +4,6 @@ use thiserror::Error; #[cfg(feature = "sys")] pub use wasmer_compiler::{LinkError, RuntimeError}; -// /// An error while instantiating a module. -// /// -// /// This is not a common WebAssembly error, however -// /// we need to differentiate from a `LinkError` (an error -// /// that happens while linking, on instantiation), a -// /// Trap that occurs when calling the WebAssembly module -// /// start function, and an error when initializing the user's -// /// host environments. -// #[derive(Debug)] -// #[cfg_attr(feature = "std", derive(Error))] -// pub enum InstantiationError { -// /// A linking ocurred during instantiation. -// #[cfg_attr(feature = "std", error(transparent))] -// Link(LinkError), - -// /// A runtime error occured while invoking the start function -// #[cfg_attr(feature = "std", error(transparent))] -// Start(RuntimeError), - -// /// The module was compiled with a CPU feature that is not available on -// /// the current host. -// #[cfg_attr(feature = "std", error("missing required CPU features: {0:?}"))] -// CpuFeature(String), - -// /// Import from a different [`Store`]. -// /// This error occurs when an import from a different store is used. -// #[cfg_attr(feature = "std", error("cannot mix imports from different stores"))] -// DifferentStores, -// } - -// #[cfg(feature = "core")] -// impl std::fmt::Display for InstantiationError { -// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { -// write!(f, "InstantiationError") -// } -// } - /// An error while instantiating a module. /// /// This is not a common WebAssembly error, however @@ -49,28 +12,36 @@ pub use wasmer_compiler::{LinkError, RuntimeError}; /// Trap that occurs when calling the WebAssembly module /// start function, and an error when initializing the user's /// host environments. -#[derive(Error, Debug)] +#[derive(Debug)] +#[cfg_attr(feature = "std", derive(Error))] pub enum InstantiationError { /// A linking ocurred during instantiation. - #[error(transparent)] + #[cfg_attr(feature = "std", error(transparent))] Link(LinkError), /// A runtime error occured while invoking the start function - #[error(transparent)] + #[cfg_attr(feature = "std", error(transparent))] Start(RuntimeError), /// The module was compiled with a CPU feature that is not available on /// the current host. - #[error("missing required CPU features: {0:?}")] + #[cfg_attr(feature = "std", error("missing required CPU features: {0:?}"))] CpuFeature(String), - /// Import from a different Store. + /// Import from a different [`Store`]. /// This error occurs when an import from a different store is used. - #[error("cannot mix imports from different stores")] + #[cfg_attr(feature = "std", error("cannot mix imports from different stores"))] DifferentStores, /// Import from a different Store. /// This error occurs when an import from a different store is used. - #[error("incorrect OS or architecture")] + #[cfg_attr(feature = "std", error("incorrect OS or architecture"))] DifferentArchOS, } + +#[cfg(feature = "core")] +impl std::fmt::Display for InstantiationError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "InstantiationError") + } +} diff --git a/lib/api/src/js/extern_ref.rs b/lib/api/src/js/extern_ref.rs index 7fad48ea9f2..a2ff0101673 100644 --- a/lib/api/src/js/extern_ref.rs +++ b/lib/api/src/js/extern_ref.rs @@ -13,25 +13,25 @@ impl ExternRef { where T: Any + Send + Sync + 'static + Sized, { - unimplemented!(); + unimplemented!("ExternRef is not yet supported in Javascript"); } pub fn downcast<'a, T>(&self, store: &'a impl AsStoreRef) -> Option<&'a T> where T: Any + Send + Sync + 'static + Sized, { - unimplemented!(); + unimplemented!("ExternRef is not yet supported in Javascript"); } pub(crate) fn vm_externref(&self) -> VMExternRef { - unimplemented!(); + unimplemented!("ExternRef is not yet supported in Javascript"); } pub(crate) unsafe fn from_vm_externref( store: &mut impl AsStoreMut, vm_externref: VMExternRef, ) -> Self { - unimplemented!(); + unimplemented!("ExternRef is not yet supported in Javascript"); } pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool { diff --git a/lib/api/src/js/module.rs b/lib/api/src/js/module.rs index a45a5ead6fb..0a8cee64fd3 100644 --- a/lib/api/src/js/module.rs +++ b/lib/api/src/js/module.rs @@ -237,7 +237,8 @@ impl Module { bytes: impl IntoBytes, ) -> Result { #[cfg(feature = "js-serializable-module")] - return Self::new(_engine, bytes.into_bytes()).map_err(|e| DeserializeError::Compiler(e)); + return Self::from_binary(_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())); diff --git a/lib/api/src/js/vm.rs b/lib/api/src/js/vm.rs index 1e48d0d676b..0ce76e489f6 100644 --- a/lib/api/src/js/vm.rs +++ b/lib/api/src/js/vm.rs @@ -110,6 +110,7 @@ impl VMMemory { /// The shared memory is the same as the normal memory pub type VMSharedMemory = VMMemory; +/// The VM Global type #[derive(Clone, Debug, PartialEq)] pub struct VMGlobal { pub(crate) global: JsGlobal, @@ -125,6 +126,7 @@ impl VMGlobal { unsafe impl Send for VMGlobal {} unsafe impl Sync for VMGlobal {} +/// The VM Table type #[derive(Clone, Debug, PartialEq)] pub struct VMTable { pub(crate) table: JsTable, @@ -138,11 +140,14 @@ impl VMTable { pub(crate) fn new(table: JsTable, ty: TableType) -> Self { Self { table, ty } } + + /// Get the table size at runtime pub fn get_runtime_size(&self) -> u32 { self.table.length() } } +/// The VM Function type #[derive(Clone)] pub struct VMFunction { pub(crate) function: JsFunction, diff --git a/lib/api/src/store.rs b/lib/api/src/store.rs index 7111c50226d..5e59b5113db 100644 --- a/lib/api/src/store.rs +++ b/lib/api/src/store.rs @@ -13,7 +13,7 @@ use wasmer_vm::init_traps; pub use wasmer_vm::TrapHandlerFn; #[cfg(feature = "sys")] -use crate::sys::WasmerCompilerEngine; +use crate::sys::NativeEngineExt; #[cfg(feature = "sys")] pub use wasmer_vm::{StoreHandle, StoreObjects}; diff --git a/lib/api/src/sys/engine.rs b/lib/api/src/sys/engine.rs index 1eac9ab9056..38700d1fe43 100644 --- a/lib/api/src/sys/engine.rs +++ b/lib/api/src/sys/engine.rs @@ -65,7 +65,7 @@ impl From for crate::engine::Engine { /// The custom trait to access to all the `sys` function in the common /// engine. -pub trait WasmerCompilerEngine { +pub trait NativeEngineExt { /// Create a new `Engine` with the given config #[cfg(feature = "compiler")] fn new(compiler_config: Box, target: Target, features: Features) -> Self; @@ -95,7 +95,7 @@ pub trait WasmerCompilerEngine { fn tunables(&self) -> &dyn Tunables; } -impl WasmerCompilerEngine for crate::engine::Engine { +impl NativeEngineExt for crate::engine::Engine { fn new(compiler_config: Box, target: Target, features: Features) -> Self { crate::engine::Engine(Engine::new(compiler_config, target, features)) } diff --git a/lib/api/src/sys/externals/memory.rs b/lib/api/src/sys/externals/memory.rs index 63c1711dd14..e61c3aeeb6e 100644 --- a/lib/api/src/sys/externals/memory.rs +++ b/lib/api/src/sys/externals/memory.rs @@ -1,6 +1,6 @@ use super::memory_view::MemoryView; use crate::store::{AsStoreMut, AsStoreRef}; -use crate::sys::WasmerCompilerEngine; +use crate::sys::NativeEngineExt; use crate::vm::VMExternMemory; use crate::MemoryAccessError; use crate::MemoryType; diff --git a/lib/api/src/sys/externals/table.rs b/lib/api/src/sys/externals/table.rs index 646dd30e8a1..7fc7b08cd47 100644 --- a/lib/api/src/sys/externals/table.rs +++ b/lib/api/src/sys/externals/table.rs @@ -1,5 +1,5 @@ use crate::store::{AsStoreMut, AsStoreRef}; -use crate::sys::WasmerCompilerEngine; +use crate::sys::NativeEngineExt; use crate::TableType; use crate::Value; use crate::{vm::VMExternTable, ExternRef, Function, RuntimeError}; diff --git a/lib/api/src/sys/mod.rs b/lib/api/src/sys/mod.rs index 0fc537a546b..254e13b03ed 100644 --- a/lib/api/src/sys/mod.rs +++ b/lib/api/src/sys/mod.rs @@ -6,7 +6,7 @@ pub(crate) mod module; mod tunables; pub(crate) mod typed_function; -pub use crate::sys::engine::WasmerCompilerEngine; +pub use crate::sys::engine::NativeEngineExt; pub use crate::sys::tunables::BaseTunables; pub use target_lexicon::{Architecture, CallingConvention, OperatingSystem, Triple, HOST}; #[cfg(feature = "compiler")] diff --git a/lib/api/src/sys/module.rs b/lib/api/src/sys/module.rs index 4d450b141e6..1eca3fa1978 100644 --- a/lib/api/src/sys/module.rs +++ b/lib/api/src/sys/module.rs @@ -1,5 +1,5 @@ use crate::engine::AsEngineRef; -use crate::sys::engine::WasmerCompilerEngine; +use crate::sys::engine::NativeEngineExt; use bytes::Bytes; use std::path::Path; use std::sync::Arc; diff --git a/lib/api/src/sys/tunables.rs b/lib/api/src/sys/tunables.rs index 379cedfcec8..80111464ff8 100644 --- a/lib/api/src/sys/tunables.rs +++ b/lib/api/src/sys/tunables.rs @@ -6,7 +6,7 @@ pub use wasmer_compiler::BaseTunables; #[cfg(test)] mod tests { use super::*; - use crate::sys::WasmerCompilerEngine; + use crate::sys::NativeEngineExt; use crate::TableType; use std::cell::UnsafeCell; use std::ptr::NonNull; diff --git a/lib/api/src/vm.rs b/lib/api/src/vm.rs index e2dabb260d5..8fc058d64af 100644 --- a/lib/api/src/vm.rs +++ b/lib/api/src/vm.rs @@ -3,8 +3,7 @@ #[cfg(feature = "js")] pub(crate) use crate::js::vm::{ VMExtern, VMExternFunction, VMExternGlobal, VMExternMemory, VMExternRef, VMExternTable, - VMFuncRef, VMFunction, VMFunctionBody, VMFunctionEnvironment, VMGlobal, VMInstance, VMMemory, - VMSharedMemory, VMTable, VMTrampoline, + VMFuncRef, VMFunctionBody, VMFunctionEnvironment, VMInstance, VMTrampoline, }; #[cfg(feature = "sys")] @@ -13,17 +12,18 @@ pub(crate) use crate::sys::vm::{ VMFuncRef, VMFunctionBody, VMFunctionEnvironment, VMInstance, VMTrampoline, }; +#[cfg(feature = "js")] +pub use crate::js::vm::{VMFunction, VMGlobal, VMMemory, VMSharedMemory, VMTable}; + +#[cfg(feature = "sys")] +pub use wasmer_vm::{VMFunction, VMGlobal, VMMemory, VMSharedMemory, VMTable}; + // Needed for tunables customization (those are public types now) #[cfg(feature = "sys")] pub use wasmer_vm::{ // An extra one for VMMemory implementors LinearMemory, - VMFunction, - VMGlobal, - VMMemory, VMMemoryDefinition, - VMSharedMemory, - VMTable, VMTableDefinition, }; diff --git a/lib/wasi/src/bin_factory/exec.rs b/lib/wasi/src/bin_factory/exec.rs index eec9ca32bbd..b53df25c02d 100644 --- a/lib/wasi/src/bin_factory/exec.rs +++ b/lib/wasi/src/bin_factory/exec.rs @@ -12,7 +12,7 @@ use futures::Future; use tokio::sync::mpsc; use tracing::*; #[cfg(feature = "sys")] -use wasmer::WasmerCompilerEngine; +use wasmer::NativeEngineExt; use wasmer::{FunctionEnvMut, Instance, Memory, Module, Store}; use wasmer_wasi_types::wasi::{Errno, ExitCode}; diff --git a/lib/wasi/src/runtime/task_manager/mod.rs b/lib/wasi/src/runtime/task_manager/mod.rs index 70fd9566443..d78e412f8c3 100644 --- a/lib/wasi/src/runtime/task_manager/mod.rs +++ b/lib/wasi/src/runtime/task_manager/mod.rs @@ -6,13 +6,8 @@ use std::{pin::Pin, time::Duration}; use ::tokio::runtime::Handle; use futures::Future; -use wasmer::MemoryType; - -#[cfg(feature = "js")] -use wasmer::VMMemory; - -#[cfg(not(target_family = "wasm"))] use wasmer::vm::VMMemory; +use wasmer::MemoryType; #[cfg(feature = "sys")] use wasmer_types::MemoryStyle; diff --git a/lib/wasi/src/state/env.rs b/lib/wasi/src/state/env.rs index 76690a517a7..246b0718866 100644 --- a/lib/wasi/src/state/env.rs +++ b/lib/wasi/src/state/env.rs @@ -4,7 +4,7 @@ use derivative::Derivative; use rand::Rng; use tracing::{trace, warn}; #[cfg(feature = "sys")] -use wasmer::WasmerCompilerEngine; +use wasmer::NativeEngineExt; use wasmer::{ AsStoreMut, AsStoreRef, FunctionEnvMut, Global, Instance, Memory, MemoryView, Module, TypedFunction, diff --git a/lib/wasi/src/syscalls/wasix/proc_fork.rs b/lib/wasi/src/syscalls/wasix/proc_fork.rs index ac4bdf3dfd5..7fdfe7deb30 100644 --- a/lib/wasi/src/syscalls/wasix/proc_fork.rs +++ b/lib/wasi/src/syscalls/wasix/proc_fork.rs @@ -1,10 +1,7 @@ use super::*; use crate::syscalls::*; -#[cfg(feature = "sys")] use wasmer::vm::VMMemory; -#[cfg(feature = "js")] -use wasmer::VMMemory; /// ### `proc_fork()` /// Forks the current process into a new subprocess. If the function diff --git a/lib/wasi/src/syscalls/wasix/thread_spawn.rs b/lib/wasi/src/syscalls/wasix/thread_spawn.rs index db866164986..d0df6631e3e 100644 --- a/lib/wasi/src/syscalls/wasix/thread_spawn.rs +++ b/lib/wasi/src/syscalls/wasix/thread_spawn.rs @@ -1,10 +1,7 @@ use super::*; use crate::syscalls::*; -#[cfg(feature = "sys")] use wasmer::vm::VMMemory; -#[cfg(feature = "js")] -use wasmer::VMMemory; /// ### `thread_spawn()` /// Creates a new thread by spawning that shares the same From 09427c3bb660ce7a414a7557a197aed4296dda4c Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Mon, 27 Feb 2023 23:25:17 -0800 Subject: [PATCH 62/81] Make automatically the trait Into conversions --- examples/imports_function_env_global.rs | 3 ++- examples/tunables_limit_memory.rs | 2 +- lib/api/src/engine.rs | 16 +++------------- lib/api/src/sys/engine.rs | 12 ------------ 4 files changed, 6 insertions(+), 27 deletions(-) diff --git a/examples/imports_function_env_global.rs b/examples/imports_function_env_global.rs index fb9cb41debd..6102905fe2d 100644 --- a/examples/imports_function_env_global.rs +++ b/examples/imports_function_env_global.rs @@ -92,7 +92,8 @@ fn main() -> Result<(), Box> { let global_count = data.g_counter.get(&mut storemut).unwrap_i32(); data.g_counter - .set(&mut storemut, Value::I32(global_count + add)); + .set(&mut storemut, Value::I32(global_count + add)) + .unwrap(); *counter_ref += add; *counter_ref diff --git a/examples/tunables_limit_memory.rs b/examples/tunables_limit_memory.rs index 7902e5632ee..da2c7a4ece1 100644 --- a/examples/tunables_limit_memory.rs +++ b/examples/tunables_limit_memory.rs @@ -8,7 +8,7 @@ use wasmer::{ }; use wasmer_compiler_cranelift::Cranelift; // This is to be able to set the tunables -use wasmer::WasmerCompilerEngine; +use wasmer::NativeEngineExt; /// A custom tunables that allows you to set a memory limit. /// diff --git a/lib/api/src/engine.rs b/lib/api/src/engine.rs index 10adb58189b..8ad6dcd5c12 100644 --- a/lib/api/src/engine.rs +++ b/lib/api/src/engine.rs @@ -42,22 +42,12 @@ impl Default for Engine { } } -impl From for Engine { - fn from(inner: engine_imp::Engine) -> Self { - Self(inner) +impl> From for Engine { + fn from(t: T) -> Self { + Self(t.into()) } } -// impl

Into for P -// where -// P: Into -// { -// fn into(self) -> Engine { -// let inner_engine: engine_imp::Engine = self.into(); -// Engine(inner_engine) -// } -// } - /// A temporary handle to an [`Engine`] /// EngineRef can be used to build a [`Module`][wasmer::Module] /// It can be created directly with an [`Engine`] diff --git a/lib/api/src/sys/engine.rs b/lib/api/src/sys/engine.rs index 38700d1fe43..73a2ad4d1b8 100644 --- a/lib/api/src/sys/engine.rs +++ b/lib/api/src/sys/engine.rs @@ -51,18 +51,6 @@ pub(crate) fn default_engine() -> Engine { engine } -impl From for crate::engine::Engine { - fn from(builder: EngineBuilder) -> Self { - Self(builder.into()) - } -} - -// impl From for crate::engine::Engine { -// fn from(compiler: CompilerConfig) -> Self { -// Self(compiler.into()) -// } -// } - /// The custom trait to access to all the `sys` function in the common /// engine. pub trait NativeEngineExt { From e26a78408c4c3c94874848a930d14a0c4257e359 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Mon, 27 Feb 2023 23:32:19 -0800 Subject: [PATCH 63/81] Remove unused code --- lib/api/src/js/as_js.rs | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/lib/api/src/js/as_js.rs b/lib/api/src/js/as_js.rs index c679638a248..44b31e7ab2b 100644 --- a/lib/api/src/js/as_js.rs +++ b/lib/api/src/js/as_js.rs @@ -92,39 +92,6 @@ impl AsJs for Imports { // Annotation is here to prevent spurious IDE warnings. #[allow(unused_unsafe)] fn as_jsvalue(&self, store: &impl AsStoreRef) -> wasm_bindgen::JsValue { - // /// Returns the `Imports` as a Javascript `Object` - // pub fn as_jsobject(&self, store: &impl AsStoreRef) -> js_sys::Object { - // let imports = js_sys::Object::new(); - // let namespaces: HashMap<&str, Vec<(&str, &Extern)>> = - // self.map - // .iter() - // .fold(HashMap::default(), |mut acc, ((ns, name), ext)| { - // acc.entry(ns.as_str()) - // .or_default() - // .push((name.as_str(), ext)); - // acc - // }); - - // for (ns, exports) in namespaces.into_iter() { - // let import_namespace = js_sys::Object::new(); - // for (name, ext) in exports { - // // Annotation is here to prevent spurious IDE warnings. - // #[allow(unused_unsafe)] - // unsafe { - // js_sys::Reflect::set(&import_namespace, &name.into(), &ext.as_jsvalue(store)) - // .expect("Error while setting into the js namespace object"); - // } - // } - // // Annotation is here to prevent spurious IDE warnings. - // #[allow(unused_unsafe)] - // unsafe { - // js_sys::Reflect::set(&imports, &ns.into(), &import_namespace.into()) - // .expect("Error while setting into the js imports object"); - // } - // } - // imports - // } - let imports_object = js_sys::Object::new(); for (namespace, name, extern_) in self.iter() { let val = unsafe { js_sys::Reflect::get(&imports_object, &namespace.into()).unwrap() }; From f342ebe8212ed08479fa58006308f8abab073db3 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Mon, 27 Feb 2023 23:49:08 -0800 Subject: [PATCH 64/81] Fix serialization --- tests/compilers/serialize.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compilers/serialize.rs b/tests/compilers/serialize.rs index 48997f0e484..fce0451402a 100644 --- a/tests/compilers/serialize.rs +++ b/tests/compilers/serialize.rs @@ -4,7 +4,7 @@ use wasmer::*; #[test] fn sanity_test_artifact_deserialize() { let engine = Engine::headless(); - let result = unsafe { Artifact::deserialize(&engine, &[]) }; + let result = unsafe { Module::deserialize(&engine, &[]) }; assert!(result.is_err()); } From c04e536701e08d579ccf66419485d5ce702a3cb3 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Tue, 28 Feb 2023 00:33:28 -0800 Subject: [PATCH 65/81] Fix code --- lib/api/src/module.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/api/src/module.rs b/lib/api/src/module.rs index 87cfb7b39e9..de4b3731cc3 100644 --- a/lib/api/src/module.rs +++ b/lib/api/src/module.rs @@ -107,8 +107,7 @@ impl Module { /// ``` /// # use wasmer::*; /// # - /// # let compiler = Cranelift::default(); - /// # let engine = EngineBuilder::new(compiler).engine(); + /// # let engine: Engine = Cranelift::default().into(); /// /// let module = Module::from_file(&engine, "path/to/foo.wasm"); /// ``` From a0e11bf1de774f82c18042de32cbb754668a3334 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Tue, 28 Feb 2023 00:37:42 -0800 Subject: [PATCH 66/81] Fixed linting --- lib/cli/src/commands/create_exe.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/cli/src/commands/create_exe.rs b/lib/cli/src/commands/create_exe.rs index 3f90c68d203..fe230c423fe 100644 --- a/lib/cli/src/commands/create_exe.rs +++ b/lib/cli/src/commands/create_exe.rs @@ -227,7 +227,7 @@ impl CreateExe { return Err(anyhow::anyhow!("input path cannot be a directory")); } - let (mut store, compiler_type) = self.compiler.get_store_for_target(target.clone())?; + let (store, compiler_type) = self.compiler.get_store_for_target(target.clone())?; println!("Compiler: {}", compiler_type.to_string()); println!("Target: {}", target.triple()); @@ -276,7 +276,7 @@ impl CreateExe { ) }?; - get_module_infos(&mut store, &tempdir, &atoms, object_format)?; + get_module_infos(&store, &tempdir, &atoms, object_format)?; let mut entrypoint = get_entrypoint(&tempdir)?; create_header_files_in_dir(&tempdir, &mut entrypoint, &atoms, &self.precompiled_atom)?; link_exe_from_dir( @@ -964,7 +964,7 @@ pub(super) fn prepare_directory_from_single_wasm_file( // reads the module info from the wasm module and writes the ModuleInfo for each file // into the entrypoint.json file fn get_module_infos( - mut store: &mut Store, + store: &Store, directory: &Path, atoms: &[(String, Vec)], object_format: ObjectFormat, @@ -974,7 +974,7 @@ fn get_module_infos( let mut module_infos = BTreeMap::new(); for (atom_name, atom_bytes) in atoms { - let module = Module::new(&mut store, atom_bytes.as_slice())?; + let module = Module::new(&store, atom_bytes.as_slice())?; let module_info = module.info(); if let Some(s) = entrypoint .atoms From b47cc839cdd39479ec98b0655dbcaaac42eb8973 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Tue, 28 Feb 2023 09:13:28 -0800 Subject: [PATCH 67/81] Removed unsafe js intos --- lib/api/src/js/as_js.rs | 16 -------------- lib/api/src/js/externals/function.rs | 7 ------- lib/api/src/js/typed_function.rs | 16 +++++++------- lib/types/src/value.rs | 31 ---------------------------- 4 files changed, 8 insertions(+), 62 deletions(-) diff --git a/lib/api/src/js/as_js.rs b/lib/api/src/js/as_js.rs index 44b31e7ab2b..be28b673962 100644 --- a/lib/api/src/js/as_js.rs +++ b/lib/api/src/js/as_js.rs @@ -70,22 +70,6 @@ impl AsJs for Value { } } -impl AsJs for wasmer_types::RawValue { - type DefinitionType = Type; - - fn as_jsvalue(&self, _store: &impl AsStoreRef) -> JsValue { - unsafe { JsValue::from_f64(self.into()) } - } - - fn from_jsvalue( - _store: &mut impl AsStoreMut, - type_: &Self::DefinitionType, - value: &JsValue, - ) -> Result { - unimplemented!(); - } -} - impl AsJs for Imports { type DefinitionType = crate::module::Module; diff --git a/lib/api/src/js/externals/function.rs b/lib/api/src/js/externals/function.rs index ad8e30d3d1d..af5e1e45b4f 100644 --- a/lib/api/src/js/externals/function.rs +++ b/lib/api/src/js/externals/function.rs @@ -215,13 +215,6 @@ impl Function { params: &[Value], ) -> Result, RuntimeError> { // Annotation is here to prevent spurious IDE warnings. - #[allow(unused_unsafe)] - let params: Vec<_> = unsafe { - params - .iter() - .map(|a| a.as_raw(&store.as_store_ref())) - .collect() - }; let arr = js_sys::Array::new_with_length(params.len() as u32); // let raw_env = env.as_raw() as *mut u8; diff --git a/lib/api/src/js/typed_function.rs b/lib/api/src/js/typed_function.rs index 2c52350a0a1..d6cfe7f4351 100644 --- a/lib/api/src/js/typed_function.rs +++ b/lib/api/src/js/typed_function.rs @@ -10,9 +10,9 @@ use std::marker::PhantomData; use crate::native_type::NativeWasmTypeInto; -use crate::Function; use crate::{AsStoreMut, AsStoreRef, TypedFunction}; use crate::{FromToNativeWasmType, RuntimeError, WasmTypeList}; +use crate::{Function, Value}; // use std::panic::{catch_unwind, AssertUnwindSafe}; use crate::js::as_js::{param_from_js, AsJs}; use js_sys::Array; @@ -34,20 +34,20 @@ macro_rules! impl_native_traits { $( $x: FromToNativeWasmType + NativeWasmTypeInto, )* { #[allow(unused_unsafe)] - let params_list: Vec = unsafe { - vec![ $( $x.into_raw(store) ),* ] + let params_list: Vec<_> = unsafe { + vec![ $( ($x::WASM_TYPE, $x.into_raw(store) ) ),* ] }; - let params_list: Vec = params_list - .into_iter() - .map(|a| a.as_jsvalue(&store.as_store_ref())) - .collect(); let results = { let mut r; // TODO: This loop is needed for asyncify. It will be refactored with https://github.com/wasmerio/wasmer/issues/3451 loop { r = self.func.0.handle.function.apply( &JsValue::UNDEFINED, - &Array::from_iter(params_list.iter()) + unsafe { + &Array::from_iter(params_list.clone() + .into_iter() + .map(|(b, a)| Value::from_raw(store, b, a).as_jsvalue(store))) + } ); let store_mut = store.as_store_mut(); if let Some(callback) = store_mut.inner.on_called.take() { diff --git a/lib/types/src/value.rs b/lib/types/src/value.rs index b4259e2f7bb..d5207295d6b 100644 --- a/lib/types/src/value.rs +++ b/lib/types/src/value.rs @@ -68,26 +68,6 @@ macro_rules! partial_eq { )*) } -macro_rules! into { - ($($t:ty => $f:tt),*) => ($( - impl From<&RawValue> for $t { - fn from(from: &RawValue) -> $t { - unsafe { - match &from { - RawValue { i32: i32 } => *i32 as _, - // RawValue { f32: f32 } => *f32 as _, - // RawValue { u32: u32 } => *u32 as _, - // RawValue { i64: i64 } => *i64 as _, - // RawValue { f64: f64 } => *f64 as _, - // RawValue { u64: u64 } => *u64 as _, - // _ => unimplemented!() - } - } - } - } - )*) -} - partial_eq! { i32 => i32, u32 => u32, @@ -99,17 +79,6 @@ partial_eq! { u128 => u128 } -into! { - i32 => i32, - u32 => u32, - i64 => i64, - u64 => u64, - f32 => f32, - f64 => f64, - i128 => i128, - u128 => u128 -} - impl PartialEq for RawValue { fn eq(&self, o: &Self) -> bool { unsafe { self.u128 == o.u128 } From d5c7b8ac183d0d504003a58bbd2a421230a88796 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Tue, 28 Feb 2023 09:17:18 -0800 Subject: [PATCH 68/81] Update lib/api/src/engine.rs --- lib/api/src/engine.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/api/src/engine.rs b/lib/api/src/engine.rs index 8ad6dcd5c12..4ad91ad0265 100644 --- a/lib/api/src/engine.rs +++ b/lib/api/src/engine.rs @@ -19,7 +19,7 @@ impl Engine { since = "4.0.0", note = "engine.cloned() has been deprecated in favor of engine.clone()" )] - /// Returns the [`Tunables`]. + /// Returns the [`Engine`]. pub fn cloned(&self) -> Self { self.clone() } From 4fb02b87dd739da17f4573ad38fd3669d2cd1091 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Tue, 28 Feb 2023 09:17:27 -0800 Subject: [PATCH 69/81] Update lib/api/src/engine.rs --- lib/api/src/engine.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/api/src/engine.rs b/lib/api/src/engine.rs index 4ad91ad0265..be6c92c401f 100644 --- a/lib/api/src/engine.rs +++ b/lib/api/src/engine.rs @@ -16,7 +16,7 @@ pub struct Engine(pub(crate) engine_imp::Engine); impl Engine { #[deprecated( - since = "4.0.0", + since = "3.2.0", note = "engine.cloned() has been deprecated in favor of engine.clone()" )] /// Returns the [`Engine`]. From fc64202104a4f3471327d2d13bbccd7a6bb4eeee Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Tue, 28 Feb 2023 09:24:21 -0800 Subject: [PATCH 70/81] Use AtomicUsize instead of AtomicU64 --- lib/types/src/store_id.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/types/src/store_id.rs b/lib/types/src/store_id.rs index 4c183f9d1c2..cd25a8ef3b0 100644 --- a/lib/types/src/store_id.rs +++ b/lib/types/src/store_id.rs @@ -1,6 +1,6 @@ use std::{ - num::NonZeroU64, - sync::atomic::{AtomicU64, Ordering}, + num::NonZeroUsize, + sync::atomic::{AtomicUsize, Ordering}, }; /// Unique ID to identify a context. @@ -9,14 +9,14 @@ use std::{ /// context. This is used to check that a handle is always used with the /// correct context. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub struct StoreId(NonZeroU64); +pub struct StoreId(NonZeroUsize); impl Default for StoreId { // Allocates a unique ID for a new context. fn default() -> Self { // No overflow checking is needed here: overflowing this would take // thousands of years. - static NEXT_ID: AtomicU64 = AtomicU64::new(1); - Self(NonZeroU64::new(NEXT_ID.fetch_add(1, Ordering::Relaxed)).unwrap()) + static NEXT_ID: AtomicUsize = AtomicUsize::new(1); + Self(NonZeroUsize::new(NEXT_ID.fetch_add(1, Ordering::Relaxed)).unwrap()) } } From 770bb404b1db16dbff841559232652c81f7067e8 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Tue, 28 Feb 2023 15:59:55 -0800 Subject: [PATCH 71/81] Fixed missing memory export in WASI as the API got simplified --- lib/wasi/src/bin_factory/exec.rs | 19 +++++++++++-------- lib/wasi/src/state/env.rs | 19 +++++++++++-------- lib/wasi/src/state/func_env.rs | 27 +++++++++++++++++++++++++-- 3 files changed, 47 insertions(+), 18 deletions(-) diff --git a/lib/wasi/src/bin_factory/exec.rs b/lib/wasi/src/bin_factory/exec.rs index 175bc14d2fe..1c066d49d65 100644 --- a/lib/wasi/src/bin_factory/exec.rs +++ b/lib/wasi/src/bin_factory/exec.rs @@ -123,13 +123,14 @@ pub fn spawn_exec_module( // Let's instantiate the module with the imports. let (mut import_object, init) = import_object_for_all_wasi_versions(&module, &mut store, &wasi_env.env); - if let Some(memory) = memory { - import_object.define( - "env", - "memory", - Memory::new_from_existing(&mut store, memory), - ); - } + let imported_memory = if let Some(memory) = memory { + let imported_memory = Memory::new_from_existing(&mut store, memory); + import_object.define("env", "memory", imported_memory.clone()); + Some(imported_memory) + } else { + None + }; + let instance = match Instance::new(&mut store, &module, &import_object) { Ok(a) => a, Err(err) => { @@ -144,7 +145,9 @@ pub fn spawn_exec_module( init(&instance, &store).unwrap(); // Initialize the WASI environment - if let Err(err) = wasi_env.initialize(&mut store, instance.clone()) { + if let Err(err) = + wasi_env.initialize_with_memory(&mut store, instance.clone(), imported_memory) + { error!("wasi[{}]::wasi initialize error ({})", pid, err); wasi_env .data(&store) diff --git a/lib/wasi/src/state/env.rs b/lib/wasi/src/state/env.rs index 928253391af..cc2615a0ba1 100644 --- a/lib/wasi/src/state/env.rs +++ b/lib/wasi/src/state/env.rs @@ -449,13 +449,14 @@ impl WasiEnv { // Let's instantiate the module with the imports. let (mut import_object, instance_init_callback) = import_object_for_all_wasi_versions(&module, &mut store, &func_env.env); - if let Some(memory) = memory { - import_object.define( - "env", - "memory", - Memory::new_from_existing(&mut store, memory), - ); - } + + let imported_memory = if let Some(memory) = memory { + let imported_memory = Memory::new_from_existing(&mut store, memory); + import_object.define("env", "memory", imported_memory.clone()); + Some(imported_memory) + } else { + None + }; // Construct the instance. let instance = match Instance::new(&mut store, &module, &import_object) { @@ -473,7 +474,9 @@ impl WasiEnv { instance_init_callback(&instance, &store).unwrap(); // Initialize the WASI environment - if let Err(err) = func_env.initialize(&mut store, instance.clone()) { + if let Err(err) = + func_env.initialize_with_memory(&mut store, instance.clone(), imported_memory) + { tracing::error!("wasi[{}]::wasi initialize error ({})", pid, err); func_env .data(&store) diff --git a/lib/wasi/src/state/func_env.rs b/lib/wasi/src/state/func_env.rs index dbb45e61006..900017f8fa1 100644 --- a/lib/wasi/src/state/func_env.rs +++ b/lib/wasi/src/state/func_env.rs @@ -1,5 +1,5 @@ use tracing::trace; -use wasmer::{AsStoreMut, AsStoreRef, ExportError, FunctionEnv, Imports, Instance, Module}; +use wasmer::{AsStoreMut, AsStoreRef, ExportError, FunctionEnv, Imports, Instance, Memory, Module}; use wasmer_wasi_types::wasi::ExitCode; use crate::{ @@ -51,6 +51,19 @@ impl WasiFunctionEnv { &mut self, store: &mut impl AsStoreMut, instance: Instance, + ) -> Result<(), ExportError> { + self.initialize_with_memory(store, instance, None) + } + + /// Initializes the WasiEnv using the instance exports and a provided optional memory + /// (this must be executed before attempting to use it) + /// (as the stores can not by themselves be passed between threads we can store the module + /// in a thread-local variables and use it later - for multithreading) + pub fn initialize_with_memory( + &mut self, + store: &mut impl AsStoreMut, + instance: Instance, + memory: Option, ) -> Result<(), ExportError> { // List all the exports and imports for ns in instance.module().exports() { @@ -65,7 +78,17 @@ impl WasiFunctionEnv { // First we get the malloc function which if it exists will be used to // create the pthread_self structure - let memory = instance.exports.get_memory("memory")?.clone(); + let memory = instance.exports.get_memory("memory").map_or_else( + |e| { + if let Some(memory) = memory { + Ok(memory) + } else { + Err(e) + } + }, + |v| Ok(v.clone()), + )?; + let new_inner = WasiInstanceHandles::new(memory, store, instance); let env = self.data_mut(store); From 4973be5ee248d55c82b70bd9155859eae310e66d Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Wed, 1 Mar 2023 11:47:18 -0800 Subject: [PATCH 72/81] Refactored common WasmTypeList implementations --- lib/api/src/js/externals/function.rs | 129 -------------------- lib/api/src/native_type.rs | 166 ++++++++++++++++++++++++++ lib/api/src/sys/externals/function.rs | 131 +------------------- 3 files changed, 167 insertions(+), 259 deletions(-) diff --git a/lib/api/src/js/externals/function.rs b/lib/api/src/js/externals/function.rs index af5e1e45b4f..7d39d58e5e8 100644 --- a/lib/api/src/js/externals/function.rs +++ b/lib/api/src/js/externals/function.rs @@ -10,8 +10,6 @@ use crate::store::{AsStoreMut, AsStoreRef, StoreMut}; use crate::value::Value; use crate::Extern; use crate::TypedFunction; -use std::array::TryFromSliceError; -use std::convert::TryInto; use std::error::Error; use std::fmt; use std::iter::FromIterator; @@ -349,121 +347,6 @@ macro_rules! impl_host_function { $c_struct_name:ident, $( $x:ident ),* ) => { - /// A structure with a C-compatible representation that can hold a set of Wasm values. - /// This type is used by `WasmTypeList::CStruct`. - #[repr($c_struct_representation)] - pub struct $c_struct_name< $( $x ),* > ( $( <<$x as FromToNativeWasmType>::Native as NativeWasmType>::Abi ),* ) - where - $( $x: FromToNativeWasmType ),*; - - // Implement `WasmTypeList` for a specific tuple. - #[allow(unused_parens, dead_code)] - impl< $( $x ),* > - WasmTypeList - for - ( $( $x ),* ) - where - $( $x: FromToNativeWasmType ),* - { - type CStruct = $c_struct_name< $( $x ),* >; - - type Array = [RawValue; count_idents!( $( $x ),* )]; - - fn size() -> u32 { - count_idents!( $( $x ),* ) as _ - } - - #[allow(unused_mut)] - #[allow(clippy::unused_unit)] - #[allow(clippy::missing_safety_doc)] - unsafe fn from_array(mut _store: &mut impl AsStoreMut, array: Self::Array) -> Self { - // Unpack items of the array. - #[allow(non_snake_case)] - let [ $( $x ),* ] = array; - - // Build the tuple. - ( - $( - FromToNativeWasmType::from_native(NativeWasmTypeInto::from_raw(_store, $x)) - ),* - ) - } - - #[allow(clippy::missing_safety_doc)] - unsafe fn from_slice(store: &mut impl AsStoreMut, slice: &[RawValue]) -> Result { - Ok(Self::from_array(store, slice.try_into()?)) - } - - #[allow(unused_mut)] - #[allow(clippy::missing_safety_doc)] - unsafe fn into_array(self, mut _store: &mut impl AsStoreMut) -> Self::Array { - // Unpack items of the tuple. - #[allow(non_snake_case)] - let ( $( $x ),* ) = self; - - // Build the array. - [ - $( - FromToNativeWasmType::to_native($x).into_raw(_store) - ),* - ] - } - - fn empty_array() -> Self::Array { - // Build an array initialized with `0`. - [RawValue { i32: 0 }; count_idents!( $( $x ),* )] - } - - #[allow(unused_mut)] - #[allow(clippy::unused_unit)] - #[allow(clippy::missing_safety_doc)] - unsafe fn from_c_struct(mut _store: &mut impl AsStoreMut, c_struct: Self::CStruct) -> Self { - // Unpack items of the C structure. - #[allow(non_snake_case)] - let $c_struct_name( $( $x ),* ) = c_struct; - - ( - $( - FromToNativeWasmType::from_native(NativeWasmTypeInto::from_abi(_store, $x)) - ),* - ) - } - - #[allow(unused_parens, non_snake_case, unused_mut)] - #[allow(clippy::missing_safety_doc)] - unsafe fn into_c_struct(self, mut _store: &mut impl AsStoreMut) -> Self::CStruct { - // Unpack items of the tuple. - let ( $( $x ),* ) = self; - - // Build the C structure. - $c_struct_name( - $( - FromToNativeWasmType::to_native($x).into_abi(_store) - ),* - ) - } - - #[allow(non_snake_case)] - unsafe fn write_c_struct_to_ptr(c_struct: Self::CStruct, _ptr: *mut RawValue) { - // Unpack items of the tuple. - let $c_struct_name( $( $x ),* ) = c_struct; - - let mut _n = 0; - $( - *_ptr.add(_n).cast() = $x; - _n += 1; - )* - } - - fn wasm_types() -> &'static [Type] { - &[ - $( - $x::Native::WASM_TYPE - ),* - ] - } - } - // Implement `HostFunction` for a function with a [`FunctionEnvMut`] that has the same // arity than the tuple. #[allow(unused_parens)] @@ -570,18 +453,6 @@ macro_rules! impl_host_function { }; } -// Black-magic to count the number of identifiers at compile-time. -macro_rules! count_idents { - ( $($idents:ident),* ) => { - { - #[allow(dead_code, non_camel_case_types)] - enum Idents { $( $idents, )* __CountIdentsLast } - const COUNT: usize = Idents::__CountIdentsLast as usize; - COUNT - } - }; - } - // Here we go! Let's generate all the C struct, `WasmTypeList` // implementations and `HostFunction` implementations. impl_host_function!([C] S0,); diff --git a/lib/api/src/native_type.rs b/lib/api/src/native_type.rs index 4612fe6d4e5..8b6f08bd91a 100644 --- a/lib/api/src/native_type.rs +++ b/lib/api/src/native_type.rs @@ -9,6 +9,7 @@ use crate::vm::{VMExternRef, VMFuncRef}; use crate::{ExternRef, Function, TypedFunction}; use std::array::TryFromSliceError; use std::convert::Infallible; +use std::convert::TryInto; use std::error::Error; use crate::store::AsStoreMut; @@ -563,6 +564,171 @@ impl WasmTypeList for Infallible { } } +macro_rules! impl_wasmtypelist { + ( [$c_struct_representation:ident] + $c_struct_name:ident, + $( $x:ident ),* ) => { + + /// A structure with a C-compatible representation that can hold a set of Wasm values. + /// This type is used by `WasmTypeList::CStruct`. + #[repr($c_struct_representation)] + pub struct $c_struct_name< $( $x ),* > ( $( <<$x as FromToNativeWasmType>::Native as NativeWasmType>::Abi ),* ) + where + $( $x: FromToNativeWasmType ),*; + + // Implement `WasmTypeList` for a specific tuple. + #[allow(unused_parens, dead_code)] + impl< $( $x ),* > + WasmTypeList + for + ( $( $x ),* ) + where + $( $x: FromToNativeWasmType ),* + { + type CStruct = $c_struct_name< $( $x ),* >; + + type Array = [RawValue; count_idents!( $( $x ),* )]; + + fn size() -> u32 { + count_idents!( $( $x ),* ) as _ + } + + #[allow(unused_mut)] + #[allow(clippy::unused_unit)] + #[allow(clippy::missing_safety_doc)] + unsafe fn from_array(mut _store: &mut impl AsStoreMut, array: Self::Array) -> Self { + // Unpack items of the array. + #[allow(non_snake_case)] + let [ $( $x ),* ] = array; + + // Build the tuple. + ( + $( + FromToNativeWasmType::from_native(NativeWasmTypeInto::from_raw(_store, $x)) + ),* + ) + } + + #[allow(clippy::missing_safety_doc)] + unsafe fn from_slice(store: &mut impl AsStoreMut, slice: &[RawValue]) -> Result { + Ok(Self::from_array(store, slice.try_into()?)) + } + + #[allow(unused_mut)] + #[allow(clippy::missing_safety_doc)] + unsafe fn into_array(self, mut _store: &mut impl AsStoreMut) -> Self::Array { + // Unpack items of the tuple. + #[allow(non_snake_case)] + let ( $( $x ),* ) = self; + + // Build the array. + [ + $( + FromToNativeWasmType::to_native($x).into_raw(_store) + ),* + ] + } + + fn empty_array() -> Self::Array { + // Build an array initialized with `0`. + [RawValue { i32: 0 }; count_idents!( $( $x ),* )] + } + + #[allow(unused_mut)] + #[allow(clippy::unused_unit)] + #[allow(clippy::missing_safety_doc)] + unsafe fn from_c_struct(mut _store: &mut impl AsStoreMut, c_struct: Self::CStruct) -> Self { + // Unpack items of the C structure. + #[allow(non_snake_case)] + let $c_struct_name( $( $x ),* ) = c_struct; + + ( + $( + FromToNativeWasmType::from_native(NativeWasmTypeInto::from_abi(_store, $x)) + ),* + ) + } + + #[allow(unused_parens, non_snake_case, unused_mut)] + #[allow(clippy::missing_safety_doc)] + unsafe fn into_c_struct(self, mut _store: &mut impl AsStoreMut) -> Self::CStruct { + // Unpack items of the tuple. + let ( $( $x ),* ) = self; + + // Build the C structure. + $c_struct_name( + $( + FromToNativeWasmType::to_native($x).into_abi(_store) + ),* + ) + } + + #[allow(non_snake_case)] + unsafe fn write_c_struct_to_ptr(c_struct: Self::CStruct, _ptr: *mut RawValue) { + // Unpack items of the tuple. + let $c_struct_name( $( $x ),* ) = c_struct; + + let mut _n = 0; + $( + *_ptr.add(_n).cast() = $x; + _n += 1; + )* + } + + fn wasm_types() -> &'static [Type] { + &[ + $( + $x::Native::WASM_TYPE + ),* + ] + } + } + + }; +} + +// Black-magic to count the number of identifiers at compile-time. +macro_rules! count_idents { + ( $($idents:ident),* ) => { + { + #[allow(dead_code, non_camel_case_types)] + enum Idents { $( $idents, )* __CountIdentsLast } + const COUNT: usize = Idents::__CountIdentsLast as usize; + COUNT + } + }; +} + +// Here we go! Let's generate all the C struct and `WasmTypeList` +// implementations. +impl_wasmtypelist!([C] S0,); +impl_wasmtypelist!([transparent] S1, A1); +impl_wasmtypelist!([C] S2, A1, A2); +impl_wasmtypelist!([C] S3, A1, A2, A3); +impl_wasmtypelist!([C] S4, A1, A2, A3, A4); +impl_wasmtypelist!([C] S5, A1, A2, A3, A4, A5); +impl_wasmtypelist!([C] S6, A1, A2, A3, A4, A5, A6); +impl_wasmtypelist!([C] S7, A1, A2, A3, A4, A5, A6, A7); +impl_wasmtypelist!([C] S8, A1, A2, A3, A4, A5, A6, A7, A8); +impl_wasmtypelist!([C] S9, A1, A2, A3, A4, A5, A6, A7, A8, A9); +impl_wasmtypelist!([C] S10, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10); +impl_wasmtypelist!([C] S11, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11); +impl_wasmtypelist!([C] S12, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12); +impl_wasmtypelist!([C] S13, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13); +impl_wasmtypelist!([C] S14, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14); +impl_wasmtypelist!([C] S15, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15); +impl_wasmtypelist!([C] S16, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16); +impl_wasmtypelist!([C] S17, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17); +impl_wasmtypelist!([C] S18, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18); +impl_wasmtypelist!([C] S19, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19); +impl_wasmtypelist!([C] S20, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20); +impl_wasmtypelist!([C] S21, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21); +impl_wasmtypelist!([C] S22, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22); +impl_wasmtypelist!([C] S23, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23); +impl_wasmtypelist!([C] S24, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24); +impl_wasmtypelist!([C] S25, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25); +impl_wasmtypelist!([C] S26, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25, A26); + #[cfg(test)] mod test_wasm_type_list { use super::*; diff --git a/lib/api/src/sys/externals/function.rs b/lib/api/src/sys/externals/function.rs index 0cf970a1e4d..30a89a1411e 100644 --- a/lib/api/src/sys/externals/function.rs +++ b/lib/api/src/sys/externals/function.rs @@ -3,11 +3,9 @@ use crate::native_type::{FromToNativeWasmType, IntoResult, NativeWasmTypeInto, W use crate::store::{AsStoreMut, AsStoreRef, StoreInner, StoreMut}; use crate::vm::VMExternFunction; use crate::{FunctionEnv, FunctionEnvMut, FunctionType, RuntimeError, Value}; -use std::array::TryFromSliceError; -use std::convert::TryInto; use std::panic::{self, AssertUnwindSafe}; use std::{cell::UnsafeCell, cmp::max, ffi::c_void}; -use wasmer_types::{NativeWasmType, RawValue, Type}; +use wasmer_types::{NativeWasmType, RawValue}; use wasmer_vm::{ on_host_stack, raise_user_trap, resume_panic, wasmer_call_trampoline, MaybeInstanceOwned, StoreHandle, VMCallerCheckedAnyfunc, VMContext, VMDynamicFunctionContext, VMExtern, VMFuncRef, @@ -464,121 +462,6 @@ macro_rules! impl_host_function { $c_struct_name:ident, $( $x:ident ),* ) => { - /// A structure with a C-compatible representation that can hold a set of Wasm values. - /// This type is used by `WasmTypeList::CStruct`. - #[repr($c_struct_representation)] - pub struct $c_struct_name< $( $x ),* > ( $( <<$x as FromToNativeWasmType>::Native as NativeWasmType>::Abi ),* ) - where - $( $x: FromToNativeWasmType ),*; - - // Implement `WasmTypeList` for a specific tuple. - #[allow(unused_parens, dead_code)] - impl< $( $x ),* > - WasmTypeList - for - ( $( $x ),* ) - where - $( $x: FromToNativeWasmType ),* - { - type CStruct = $c_struct_name< $( $x ),* >; - - type Array = [RawValue; count_idents!( $( $x ),* )]; - - fn size() -> u32 { - count_idents!( $( $x ),* ) as _ - } - - #[allow(unused_mut)] - #[allow(clippy::unused_unit)] - #[allow(clippy::missing_safety_doc)] - unsafe fn from_array(mut _store: &mut impl AsStoreMut, array: Self::Array) -> Self { - // Unpack items of the array. - #[allow(non_snake_case)] - let [ $( $x ),* ] = array; - - // Build the tuple. - ( - $( - FromToNativeWasmType::from_native(NativeWasmTypeInto::from_raw(_store, $x)) - ),* - ) - } - - #[allow(clippy::missing_safety_doc)] - unsafe fn from_slice(store: &mut impl AsStoreMut, slice: &[RawValue]) -> Result { - Ok(Self::from_array(store, slice.try_into()?)) - } - - #[allow(unused_mut)] - #[allow(clippy::missing_safety_doc)] - unsafe fn into_array(self, mut _store: &mut impl AsStoreMut) -> Self::Array { - // Unpack items of the tuple. - #[allow(non_snake_case)] - let ( $( $x ),* ) = self; - - // Build the array. - [ - $( - FromToNativeWasmType::to_native($x).into_raw(_store) - ),* - ] - } - - fn empty_array() -> Self::Array { - // Build an array initialized with `0`. - [RawValue { i32: 0 }; count_idents!( $( $x ),* )] - } - - #[allow(unused_mut)] - #[allow(clippy::unused_unit)] - #[allow(clippy::missing_safety_doc)] - unsafe fn from_c_struct(mut _store: &mut impl AsStoreMut, c_struct: Self::CStruct) -> Self { - // Unpack items of the C structure. - #[allow(non_snake_case)] - let $c_struct_name( $( $x ),* ) = c_struct; - - ( - $( - FromToNativeWasmType::from_native(NativeWasmTypeInto::from_abi(_store, $x)) - ),* - ) - } - - #[allow(unused_parens, non_snake_case, unused_mut)] - #[allow(clippy::missing_safety_doc)] - unsafe fn into_c_struct(self, mut _store: &mut impl AsStoreMut) -> Self::CStruct { - // Unpack items of the tuple. - let ( $( $x ),* ) = self; - - // Build the C structure. - $c_struct_name( - $( - FromToNativeWasmType::to_native($x).into_abi(_store) - ),* - ) - } - - #[allow(non_snake_case)] - unsafe fn write_c_struct_to_ptr(c_struct: Self::CStruct, _ptr: *mut RawValue) { - // Unpack items of the tuple. - let $c_struct_name( $( $x ),* ) = c_struct; - - let mut _n = 0; - $( - *_ptr.add(_n).cast() = $x; - _n += 1; - )* - } - - fn wasm_types() -> &'static [Type] { - &[ - $( - $x::Native::WASM_TYPE - ),* - ] - } - } - // Implement `HostFunction` for a function with a [`FunctionEnvMut`] that has the same // arity than the tuple. #[allow(unused_parens)] @@ -743,18 +626,6 @@ macro_rules! impl_host_function { }; } -// Black-magic to count the number of identifiers at compile-time. -macro_rules! count_idents { - ( $($idents:ident),* ) => { - { - #[allow(dead_code, non_camel_case_types)] - enum Idents { $( $idents, )* __CountIdentsLast } - const COUNT: usize = Idents::__CountIdentsLast as usize; - COUNT - } - }; - } - // Here we go! Let's generate all the C struct, `WasmTypeList` // implementations and `HostFunction` implementations. impl_host_function!([C] S0,); From 4629a32d5906789e95bd2b7294adc68c5bf42d27 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Wed, 1 Mar 2023 11:49:39 -0800 Subject: [PATCH 73/81] Use js-generic instead of generic for the js engine --- lib/api/src/js/engine.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/api/src/js/engine.rs b/lib/api/src/js/engine.rs index a0930fb9bca..b56d104ec12 100644 --- a/lib/api/src/js/engine.rs +++ b/lib/api/src/js/engine.rs @@ -5,7 +5,7 @@ pub struct Engine; impl Engine { pub(crate) fn deterministic_id(&self) -> &str { // All js engines have the same id - "generic" + "js-generic" } } From 9719630f0a2cb2899dd4e539c38172bd8b9c5466 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Thu, 2 Mar 2023 11:49:00 -0800 Subject: [PATCH 74/81] Improved linting --- lib/api/src/engine.rs | 2 +- lib/api/src/extern_ref.rs | 4 ++-- lib/api/src/externals/function.rs | 10 +++++----- lib/api/src/externals/global.rs | 4 ++-- lib/api/src/externals/memory.rs | 8 ++++---- lib/api/src/externals/table.rs | 2 +- lib/api/src/sys/engine.rs | 4 ++-- lib/types/src/value.rs | 8 ++++---- 8 files changed, 21 insertions(+), 21 deletions(-) diff --git a/lib/api/src/engine.rs b/lib/api/src/engine.rs index be6c92c401f..565a00da0be 100644 --- a/lib/api/src/engine.rs +++ b/lib/api/src/engine.rs @@ -38,7 +38,7 @@ impl AsEngineRef for Engine { impl Default for Engine { fn default() -> Self { - Engine(default_engine()) + Self(default_engine()) } } diff --git a/lib/api/src/extern_ref.rs b/lib/api/src/extern_ref.rs index e118b210b28..3b5bf1b8c74 100644 --- a/lib/api/src/extern_ref.rs +++ b/lib/api/src/extern_ref.rs @@ -19,7 +19,7 @@ impl ExternRef { where T: Any + Send + Sync + 'static + Sized, { - ExternRef(extern_ref_imp::ExternRef::new(store, value)) + Self(extern_ref_imp::ExternRef::new(store, value)) } /// Try to downcast to the given value. @@ -38,7 +38,7 @@ impl ExternRef { store: &mut impl AsStoreMut, vm_externref: VMExternRef, ) -> Self { - ExternRef(extern_ref_imp::ExternRef::from_vm_externref( + Self(extern_ref_imp::ExternRef::from_vm_externref( store, vm_externref, )) diff --git a/lib/api/src/externals/function.rs b/lib/api/src/externals/function.rs index 6de013922d0..1a2cbc3dab7 100644 --- a/lib/api/src/externals/function.rs +++ b/lib/api/src/externals/function.rs @@ -151,7 +151,7 @@ impl Function { + Send + Sync, { - Function(function_impl::Function::new_with_env(store, env, ty, func)) + Self(function_impl::Function::new_with_env(store, env, ty, func)) } #[deprecated( @@ -175,7 +175,7 @@ impl Function { Args: WasmTypeList, Rets: WasmTypeList, { - Function(function_impl::Function::new_typed(store, func)) + Self(function_impl::Function::new_typed(store, func)) } #[deprecated( @@ -224,7 +224,7 @@ impl Function { Args: WasmTypeList, Rets: WasmTypeList, { - Function(function_impl::Function::new_typed_with_env( + Self(function_impl::Function::new_typed_with_env( store, env, func, )) } @@ -347,7 +347,7 @@ impl Function { } pub(crate) unsafe fn from_vm_funcref(store: &mut impl AsStoreMut, funcref: VMFuncRef) -> Self { - Function(function_impl::Function::from_vm_funcref(store, funcref)) + Self(function_impl::Function::from_vm_funcref(store, funcref)) } /// Transform this WebAssembly function into a native function. @@ -487,7 +487,7 @@ impl Function { } pub(crate) fn from_vm_extern(store: &mut impl AsStoreMut, vm_extern: VMExternFunction) -> Self { - Function(function_impl::Function::from_vm_extern(store, vm_extern)) + Self(function_impl::Function::from_vm_extern(store, vm_extern)) } /// Checks whether this `Function` can be used with the given store. diff --git a/lib/api/src/externals/global.rs b/lib/api/src/externals/global.rs index 2e9579e8862..24d1279be3d 100644 --- a/lib/api/src/externals/global.rs +++ b/lib/api/src/externals/global.rs @@ -63,7 +63,7 @@ impl Global { val: Value, mutability: Mutability, ) -> Result { - Ok(Global(global_impl::Global::from_value( + Ok(Self(global_impl::Global::from_value( store, val, mutability, )?)) } @@ -148,7 +148,7 @@ impl Global { } pub(crate) fn from_vm_extern(store: &mut impl AsStoreMut, vm_extern: VMExternGlobal) -> Self { - Global(global_impl::Global::from_vm_extern(store, vm_extern)) + Self(global_impl::Global::from_vm_extern(store, vm_extern)) } /// Checks whether this `Global` can be used with the given context. diff --git a/lib/api/src/externals/memory.rs b/lib/api/src/externals/memory.rs index 5f725cc28ab..d29322c91e9 100644 --- a/lib/api/src/externals/memory.rs +++ b/lib/api/src/externals/memory.rs @@ -45,12 +45,12 @@ impl Memory { /// let m = Memory::new(&mut store, MemoryType::new(1, None, false)).unwrap(); /// ``` pub fn new(store: &mut impl AsStoreMut, ty: MemoryType) -> Result { - Ok(Memory(memory_impl::Memory::new(store, ty)?)) + Ok(Self(memory_impl::Memory::new(store, ty)?)) } /// Create a memory object from an existing memory and attaches it to the store pub fn new_from_existing(new_store: &mut impl AsStoreMut, memory: VMMemory) -> Self { - Memory(memory_impl::Memory::new_from_existing(new_store, memory)) + Self(memory_impl::Memory::new_from_existing(new_store, memory)) } /// Returns the [`MemoryType`] of the `Memory`. @@ -125,11 +125,11 @@ impl Memory { store: &impl AsStoreRef, new_store: &mut impl AsStoreMut, ) -> Result { - Ok(Memory(self.0.copy_to_store(store, new_store)?)) + Ok(Self(self.0.copy_to_store(store, new_store)?)) } pub(crate) fn from_vm_extern(store: &mut impl AsStoreMut, vm_extern: VMExternMemory) -> Self { - Memory(memory_impl::Memory::from_vm_extern(store, vm_extern)) + Self(memory_impl::Memory::from_vm_extern(store, vm_extern)) } /// Checks whether this `Memory` can be used with the given context. diff --git a/lib/api/src/externals/table.rs b/lib/api/src/externals/table.rs index 873105016f2..b2d8cde5535 100644 --- a/lib/api/src/externals/table.rs +++ b/lib/api/src/externals/table.rs @@ -35,7 +35,7 @@ impl Table { ty: TableType, init: Value, ) -> Result { - Ok(Table(table_impl::Table::new(store, ty, init)?)) + Ok(Self(table_impl::Table::new(store, ty, init)?)) } /// Returns the [`TableType`] of the `Table`. diff --git a/lib/api/src/sys/engine.rs b/lib/api/src/sys/engine.rs index 73a2ad4d1b8..4598bcc430a 100644 --- a/lib/api/src/sys/engine.rs +++ b/lib/api/src/sys/engine.rs @@ -85,11 +85,11 @@ pub trait NativeEngineExt { impl NativeEngineExt for crate::engine::Engine { fn new(compiler_config: Box, target: Target, features: Features) -> Self { - crate::engine::Engine(Engine::new(compiler_config, target, features)) + Self(Engine::new(compiler_config, target, features)) } fn headless() -> Self { - crate::engine::Engine(Engine::headless()) + Self(Engine::headless()) } fn target(&self) -> &Target { diff --git a/lib/types/src/value.rs b/lib/types/src/value.rs index d5207295d6b..045594673a0 100644 --- a/lib/types/src/value.rs +++ b/lib/types/src/value.rs @@ -22,25 +22,25 @@ pub union RawValue { impl From for RawValue { fn from(value: i32) -> Self { - RawValue { i32: value } + Self { i32: value } } } impl From for RawValue { fn from(value: i64) -> Self { - RawValue { i64: value } + Self { i64: value } } } impl From for RawValue { fn from(value: f32) -> Self { - RawValue { f32: value } + Self { f32: value } } } impl From for RawValue { fn from(value: f64) -> Self { - RawValue { f64: value } + Self { f64: value } } } From 7440c428a76ddd4a86fbbcd950520847ad9e39b1 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Thu, 2 Mar 2023 14:05:26 -0800 Subject: [PATCH 75/81] Trying to add support for BigInt --- lib/api/src/js/as_js.rs | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/lib/api/src/js/as_js.rs b/lib/api/src/js/as_js.rs index be28b673962..a896363419d 100644 --- a/lib/api/src/js/as_js.rs +++ b/lib/api/src/js/as_js.rs @@ -13,6 +13,7 @@ use crate::{Extern, Function, Global, Memory, Table}; use js_sys::Function as JsFunction; use js_sys::WebAssembly::{Memory as JsMemory, Table as JsTable}; use std::collections::HashMap; +use std::convert::TryInto; use wasm_bindgen::JsCast; use wasm_bindgen::{JsError, JsValue}; use wasmer_types::ExternType; @@ -35,12 +36,22 @@ pub trait AsJs: Sized { pub fn param_from_js(ty: &Type, js_val: &JsValue) -> Value { match ty { Type::I32 => Value::I32(js_val.as_f64().unwrap() as _), - Type::I64 => Value::I64(js_val.as_f64().unwrap() as _), + Type::I64 => { + let number = js_val.as_f64().unwrap_or_else(|| { + // To support BigInt + js_sys::Number::from(js_val.clone()).as_f64().unwrap() + }) as _; + Value::I64(number) + } Type::F32 => Value::F32(js_val.as_f64().unwrap() as _), Type::F64 => Value::F64(js_val.as_f64().unwrap()), - t => unimplemented!( + Type::V128 => { + let big_num: u128 = js_sys::BigInt::from(js_val.clone()).try_into().unwrap(); + Value::V128(big_num) + } + Type::ExternRef | Type::FuncRef => unimplemented!( "The type `{:?}` is not yet supported in the JS Function API", - t + ty ), } } @@ -50,11 +61,11 @@ impl AsJs for Value { fn as_jsvalue(&self, _store: &impl AsStoreRef) -> JsValue { match self { - Self::I32(i) => JsValue::from_f64(*i as f64), - Self::I64(i) => JsValue::from_f64(*i as f64), - Self::F32(f) => JsValue::from_f64(*f as f64), - Self::F64(f) => JsValue::from_f64(*f), - Self::V128(f) => JsValue::from_f64(*f as f64), + Self::I32(i) => JsValue::from(*i), + Self::I64(i) => JsValue::from(*i), + Self::F32(f) => JsValue::from(*f), + Self::F64(f) => JsValue::from(*f), + Self::V128(v) => JsValue::from(*v), Self::FuncRef(Some(func)) => func.0.handle.function.clone().into(), Self::FuncRef(None) => JsValue::null(), Self::ExternRef(_) => unimplemented!(), From 61ca01d341b97257bbd466e8e98c0e98dbe8eee1 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Thu, 2 Mar 2023 14:26:06 -0800 Subject: [PATCH 76/81] Fix linting errors --- lib/api/src/js/as_js.rs | 4 ++-- lib/api/src/js/errors.rs | 6 +----- lib/api/src/js/extern_ref.rs | 11 +++++------ lib/api/src/js/externals/function.rs | 17 ++++++++--------- lib/api/src/js/externals/memory.rs | 12 +----------- lib/api/src/js/externals/memory_view.rs | 1 + lib/api/src/js/externals/table.rs | 1 - lib/api/src/js/instance.rs | 5 ++--- lib/api/src/js/module.rs | 22 +++++----------------- lib/api/src/js/store.rs | 2 ++ lib/api/src/js/typed_function.rs | 6 ++---- lib/api/src/js/vm.rs | 8 +++----- lib/api/src/store.rs | 4 ---- 13 files changed, 32 insertions(+), 67 deletions(-) diff --git a/lib/api/src/js/as_js.rs b/lib/api/src/js/as_js.rs index a896363419d..dec2a758729 100644 --- a/lib/api/src/js/as_js.rs +++ b/lib/api/src/js/as_js.rs @@ -249,12 +249,12 @@ impl AsJs for Extern { impl AsJs for Instance { type DefinitionType = crate::module::Module; - fn as_jsvalue(&self, store: &impl AsStoreRef) -> wasm_bindgen::JsValue { + fn as_jsvalue(&self, _store: &impl AsStoreRef) -> wasm_bindgen::JsValue { self._inner._handle.clone().into() } fn from_jsvalue( - mut store: &mut impl AsStoreMut, + store: &mut impl AsStoreMut, module: &Self::DefinitionType, value: &JsValue, ) -> Result { diff --git a/lib/api/src/js/errors.rs b/lib/api/src/js/errors.rs index 22efae26f3f..2f93a80b119 100644 --- a/lib/api/src/js/errors.rs +++ b/lib/api/src/js/errors.rs @@ -1,12 +1,8 @@ -#[cfg(feature = "core")] -use crate::alloc::borrow::Cow; use crate::js::lib::std::string::String; pub use crate::js::trap::RuntimeError; #[cfg(feature = "std")] -use std::borrow::Cow; -#[cfg(feature = "std")] use thiserror::Error; -use wasmer_types::{CompileError, ImportError}; +use wasmer_types::ImportError; /// The WebAssembly.LinkError object indicates an error during /// module instantiation (besides traps from the start function). diff --git a/lib/api/src/js/extern_ref.rs b/lib/api/src/js/extern_ref.rs index a2ff0101673..fc0771e6123 100644 --- a/lib/api/src/js/extern_ref.rs +++ b/lib/api/src/js/extern_ref.rs @@ -2,21 +2,20 @@ use std::any::Any; use crate::js::vm::VMExternRef; use crate::store::{AsStoreMut, AsStoreRef}; -use wasmer_types::RawValue; #[derive(Debug, Clone)] #[repr(transparent)] pub struct ExternRef; impl ExternRef { - pub fn new(store: &mut impl AsStoreMut, value: T) -> Self + pub fn new(_store: &mut impl AsStoreMut, _value: T) -> Self where T: Any + Send + Sync + 'static + Sized, { unimplemented!("ExternRef is not yet supported in Javascript"); } - pub fn downcast<'a, T>(&self, store: &'a impl AsStoreRef) -> Option<&'a T> + pub fn downcast<'a, T>(&self, _store: &'a impl AsStoreRef) -> Option<&'a T> where T: Any + Send + Sync + 'static + Sized, { @@ -28,13 +27,13 @@ impl ExternRef { } pub(crate) unsafe fn from_vm_externref( - store: &mut impl AsStoreMut, - vm_externref: VMExternRef, + _store: &mut impl AsStoreMut, + _vm_externref: VMExternRef, ) -> Self { unimplemented!("ExternRef is not yet supported in Javascript"); } - pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool { + pub fn is_from_store(&self, _store: &impl AsStoreRef) -> bool { true } } diff --git a/lib/api/src/js/externals/function.rs b/lib/api/src/js/externals/function.rs index 7d39d58e5e8..08cc71d3031 100644 --- a/lib/api/src/js/externals/function.rs +++ b/lib/api/src/js/externals/function.rs @@ -1,5 +1,4 @@ use crate::errors::RuntimeError; -use crate::exports::{ExportError, Exportable}; use crate::externals::function::{HostFunction, HostFunctionKind, WithEnv, WithoutEnv}; use crate::function_env::{FunctionEnv, FunctionEnvMut}; use crate::js::as_js::{param_from_js, AsJs}; /* ValFuncRef */ @@ -8,15 +7,12 @@ use crate::js::vm::{VMExtern, VMFuncRef, VMFunction, VMFunctionBody, VMFunctionE use crate::native_type::{FromToNativeWasmType, IntoResult, NativeWasmTypeInto, WasmTypeList}; use crate::store::{AsStoreMut, AsStoreRef, StoreMut}; use crate::value::Value; -use crate::Extern; -use crate::TypedFunction; -use std::error::Error; use std::fmt; use std::iter::FromIterator; use std::marker::PhantomData; use std::panic::{self, AssertUnwindSafe}; -use wasmer_types::{FunctionType, NativeWasmType, RawValue, Type}; +use wasmer_types::{FunctionType, NativeWasmType, RawValue}; use js_sys::{Array, Function as JSFunction}; use wasm_bindgen::prelude::*; @@ -198,8 +194,8 @@ impl Function { pub fn call_raw( &self, - store: &mut impl AsStoreMut, - params: Vec, + _store: &mut impl AsStoreMut, + _params: Vec, ) -> Result, RuntimeError> { // There is no optimal call_raw in JS, so we just // simply rely the call @@ -275,11 +271,14 @@ impl Function { Self { handle: internal } } - pub(crate) fn vm_funcref(&self, store: &impl AsStoreRef) -> VMFuncRef { + pub(crate) fn vm_funcref(&self, _store: &impl AsStoreRef) -> VMFuncRef { unimplemented!(); } - pub(crate) unsafe fn from_vm_funcref(store: &mut impl AsStoreMut, funcref: VMFuncRef) -> Self { + pub(crate) unsafe fn from_vm_funcref( + _store: &mut impl AsStoreMut, + _funcref: VMFuncRef, + ) -> Self { unimplemented!(); } diff --git a/lib/api/src/js/externals/memory.rs b/lib/api/src/js/externals/memory.rs index a5526c2fc17..09a23d610e2 100644 --- a/lib/api/src/js/externals/memory.rs +++ b/lib/api/src/js/externals/memory.rs @@ -1,8 +1,6 @@ -use crate::exports::{ExportError, Exportable}; use crate::js::vm::{VMExtern, VMMemory}; use crate::mem_access::MemoryAccessError; use crate::store::{AsStoreMut, AsStoreRef, StoreObjects}; -use crate::Extern; use crate::MemoryType; use std::marker::PhantomData; use std::mem::MaybeUninit; @@ -84,15 +82,6 @@ impl Memory { Ok(js_memory) } - pub fn new_raw( - store: &mut impl AsStoreMut, - js_memory: js_sys::WebAssembly::Memory, - ty: MemoryType, - ) -> Result { - let vm_memory = VMMemory::new(js_memory, ty); - Ok(Self::from_vm_extern(store, vm_memory)) - } - pub fn new_from_existing(new_store: &mut impl AsStoreMut, memory: VMMemory) -> Self { Self::from_vm_extern(new_store, memory) } @@ -173,6 +162,7 @@ impl Memory { true } + #[allow(unused)] pub fn duplicate(&mut self, _store: &impl AsStoreRef) -> Result { self.handle.duplicate() } diff --git a/lib/api/src/js/externals/memory_view.rs b/lib/api/src/js/externals/memory_view.rs index e71c1566649..a5e6c4df5fa 100644 --- a/lib/api/src/js/externals/memory_view.rs +++ b/lib/api/src/js/externals/memory_view.rs @@ -254,6 +254,7 @@ impl<'a> MemoryView<'a> { } /// Copies the memory and returns it as a vector of bytes + #[allow(unused)] pub fn copy_to_vec(&self) -> Result, MemoryAccessError> { let mut new_memory = Vec::new(); let mut offset = 0; diff --git a/lib/api/src/js/externals/table.rs b/lib/api/src/js/externals/table.rs index 715829ccc11..c30471b0223 100644 --- a/lib/api/src/js/externals/table.rs +++ b/lib/api/src/js/externals/table.rs @@ -3,7 +3,6 @@ use crate::store::{AsStoreMut, AsStoreRef}; use crate::value::Value; use crate::vm::VMExternTable; use crate::vm::{VMExtern, VMFunction, VMTable}; -use crate::Extern; use crate::{FunctionType, TableType}; use js_sys::Function; diff --git a/lib/api/src/js/instance.rs b/lib/api/src/js/instance.rs index 1efac02eb92..1ecf1defed1 100644 --- a/lib/api/src/js/instance.rs +++ b/lib/api/src/js/instance.rs @@ -2,11 +2,10 @@ use crate::errors::InstantiationError; use crate::exports::Exports; use crate::imports::Imports; use crate::js::as_js::AsJs; -use crate::js::vm::{VMExtern, VMInstance}; +use crate::js::vm::VMInstance; use crate::module::Module; -use crate::store::{AsStoreMut, AsStoreRef}; +use crate::store::AsStoreMut; use crate::Extern; -use crate::{LinkError, RuntimeError}; use js_sys::WebAssembly; #[derive(Clone, PartialEq, Eq)] diff --git a/lib/api/src/js/module.rs b/lib/api/src/js/module.rs index c8ce4f36466..4ba496ff0b8 100644 --- a/lib/api/src/js/module.rs +++ b/lib/api/src/js/module.rs @@ -2,7 +2,6 @@ use crate::errors::InstantiationError; use crate::errors::RuntimeError; use crate::imports::Imports; use crate::js::AsJs; -use crate::module::IoCompileError; use crate::store::AsStoreMut; use crate::vm::VMInstance; use crate::Extern; @@ -10,11 +9,7 @@ use crate::IntoBytes; use crate::{AsEngineRef, ExportType, ImportType}; use bytes::Bytes; use js_sys::{Reflect, Uint8Array, WebAssembly}; -use std::fmt; -use std::io; use std::path::Path; -#[cfg(feature = "std")] -use thiserror::Error; #[cfg(feature = "tracing")] use tracing::{debug, warn}; use wasm_bindgen::JsValue; @@ -53,14 +48,6 @@ pub struct Module { unsafe impl Send for Module {} impl Module { - /// Creates a new WebAssembly module from a file path. - pub fn from_file( - _engine: &impl AsEngineRef, - _file: impl AsRef, - ) -> Result { - unimplemented!(); - } - pub(crate) fn from_binary( _engine: &impl AsEngineRef, binary: &[u8], @@ -234,10 +221,10 @@ impl Module { pub unsafe fn deserialize( _engine: &impl AsEngineRef, - bytes: impl IntoBytes, + _bytes: impl IntoBytes, ) -> Result { #[cfg(feature = "js-serializable-module")] - return Self::from_binary(_engine, &bytes.into_bytes()) + return Self::from_binary(_engine, &_bytes.into_bytes()) .map_err(|e| DeserializeError::Compiler(e)); #[cfg(not(feature = "js-serializable-module"))] @@ -330,6 +317,7 @@ impl Module { /// /// Returns an error if the hints doesn't match the shape of /// import or export types of the module. + #[allow(unused)] pub fn set_type_hints(&mut self, type_hints: ModuleTypeHints) -> Result<(), String> { let exports = WebAssembly::Module::exports(&self.module); // Check exports @@ -448,13 +436,13 @@ impl From for Module { impl From<(WebAssembly::Module, T)> for crate::module::Module { fn from(module_and_binary: (WebAssembly::Module, T)) -> crate::module::Module { - let (module, binary) = module_and_binary; + let (module, _binary) = module_and_binary; let module = Module { module, name: None, type_hints: None, #[cfg(feature = "js-serializable-module")] - raw_bytes: Some(binary.into_bytes()), + raw_bytes: Some(_binary.into_bytes()), }; crate::module::Module(module.into()) } diff --git a/lib/api/src/js/store.rs b/lib/api/src/js/store.rs index 29ffdfed4a6..86147f0e0f8 100644 --- a/lib/api/src/js/store.rs +++ b/lib/api/src/js/store.rs @@ -176,11 +176,13 @@ mod objects { } /// Returns the ID of the context associated with the handle. + #[allow(unused)] pub fn store_id(&self) -> StoreId { self.id } /// Overrides the store id with a new ID + #[allow(unused)] pub fn set_store_id(&mut self, id: StoreId) { self.id = id; } diff --git a/lib/api/src/js/typed_function.rs b/lib/api/src/js/typed_function.rs index d6cfe7f4351..22cd2bf9c58 100644 --- a/lib/api/src/js/typed_function.rs +++ b/lib/api/src/js/typed_function.rs @@ -7,12 +7,10 @@ //! let add_one = instance.exports.get_function("function_name")?; //! let add_one_native: TypedFunction = add_one.typed().unwrap(); //! ``` -use std::marker::PhantomData; - use crate::native_type::NativeWasmTypeInto; -use crate::{AsStoreMut, AsStoreRef, TypedFunction}; +use crate::Value; +use crate::{AsStoreMut, TypedFunction}; use crate::{FromToNativeWasmType, RuntimeError, WasmTypeList}; -use crate::{Function, Value}; // use std::panic::{catch_unwind, AssertUnwindSafe}; use crate::js::as_js::{param_from_js, AsJs}; use js_sys::Array; diff --git a/lib/api/src/js/vm.rs b/lib/api/src/js/vm.rs index b684d4f5128..10ebd67dd6e 100644 --- a/lib/api/src/js/vm.rs +++ b/lib/api/src/js/vm.rs @@ -5,8 +5,6 @@ /// once the type reflection is added to the WebAssembly JS API. /// https://github.com/WebAssembly/js-types/ use crate::js::wasm_bindgen_polyfill::Global as JsGlobal; -use crate::store::{AsStoreMut, AsStoreRef}; -use crate::MemoryView; use js_sys::Function as JsFunction; use js_sys::WebAssembly; use js_sys::WebAssembly::{Memory as JsMemory, Table as JsTable}; @@ -18,7 +16,7 @@ use tracing::trace; use wasm_bindgen::{JsCast, JsValue}; use wasmer_types::RawValue; use wasmer_types::{ - ExternType, FunctionType, GlobalType, MemoryError, MemoryType, Pages, TableType, WASM_PAGE_SIZE, + FunctionType, GlobalType, MemoryError, MemoryType, Pages, TableType, WASM_PAGE_SIZE, }; /// Represents linear memory that is managed by the javascript runtime @@ -239,7 +237,7 @@ impl VMExternRef { /// /// # Safety /// `raw` must be a valid `VMExternRef` instance. - pub unsafe fn from_raw(raw: RawValue) -> Option { + pub unsafe fn from_raw(_raw: RawValue) -> Option { unimplemented!(); } } @@ -261,7 +259,7 @@ impl VMFuncRef { /// /// # Safety /// `raw.funcref` must be a valid pointer. - pub unsafe fn from_raw(raw: RawValue) -> Option { + pub unsafe fn from_raw(_raw: RawValue) -> Option { unimplemented!(); } } diff --git a/lib/api/src/store.rs b/lib/api/src/store.rs index 5e59b5113db..138e453cd11 100644 --- a/lib/api/src/store.rs +++ b/lib/api/src/store.rs @@ -258,10 +258,6 @@ impl<'a> StoreMut<'a> { a.inner.objects.id() == b.inner.objects.id() } - pub(crate) fn engine_and_objects_mut(&mut self) -> (&Engine, &mut StoreObjects) { - (&self.inner.engine, &mut self.inner.objects) - } - pub(crate) fn as_raw(&self) -> *mut StoreInner { self.inner as *const StoreInner as *mut StoreInner } From 01dc38e6775327603c32bdd71bd45902e6df6a16 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Thu, 2 Mar 2023 14:28:23 -0800 Subject: [PATCH 77/81] Improved BigInt support --- lib/api/src/js/as_js.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/api/src/js/as_js.rs b/lib/api/src/js/as_js.rs index dec2a758729..c1347a90dc7 100644 --- a/lib/api/src/js/as_js.rs +++ b/lib/api/src/js/as_js.rs @@ -37,10 +37,15 @@ pub fn param_from_js(ty: &Type, js_val: &JsValue) -> Value { match ty { Type::I32 => Value::I32(js_val.as_f64().unwrap() as _), Type::I64 => { - let number = js_val.as_f64().unwrap_or_else(|| { - // To support BigInt - js_sys::Number::from(js_val.clone()).as_f64().unwrap() - }) as _; + let number = js_val.as_f64().map(|f| f as i64).unwrap_or_else(|| { + if js_val.is_bigint() { + // To support BigInt + let big_num: u128 = js_sys::BigInt::from(js_val.clone()).try_into().unwrap(); + big_num as i64 + } else { + (js_sys::Number::from(js_val.clone()).as_f64().unwrap()) as i64 + } + }); Value::I64(number) } Type::F32 => Value::F32(js_val.as_f64().unwrap() as _), From 69f5ec39815f9655f6db4930c5bf2c3cbccb4418 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Thu, 2 Mar 2023 15:14:48 -0800 Subject: [PATCH 78/81] Fixed missing api --- lib/api/src/store.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/api/src/store.rs b/lib/api/src/store.rs index 138e453cd11..4e5e058c2f4 100644 --- a/lib/api/src/store.rs +++ b/lib/api/src/store.rs @@ -258,6 +258,11 @@ impl<'a> StoreMut<'a> { a.inner.objects.id() == b.inner.objects.id() } + #[allow(unused)] + pub(crate) fn engine_and_objects_mut(&mut self) -> (&Engine, &mut StoreObjects) { + (&self.inner.engine, &mut self.inner.objects) + } + pub(crate) fn as_raw(&self) -> *mut StoreInner { self.inner as *const StoreInner as *mut StoreInner } From 8cbd9b6982e2f410d63dac5fc94d7a8ba0d6d8f5 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Fri, 3 Mar 2023 13:50:15 -0800 Subject: [PATCH 79/81] Added extra comments on what can be Send/Sync --- lib/api/src/js/externals/function.rs | 4 ++++ lib/api/src/js/externals/global.rs | 4 ++++ lib/api/src/js/externals/memory.rs | 12 ++++++++++++ lib/api/src/js/externals/table.rs | 4 ++++ lib/api/src/js/instance.rs | 4 +++- lib/api/src/js/module.rs | 9 +++++++++ 6 files changed, 36 insertions(+), 1 deletion(-) diff --git a/lib/api/src/js/externals/function.rs b/lib/api/src/js/externals/function.rs index 08cc71d3031..8ed64561849 100644 --- a/lib/api/src/js/externals/function.rs +++ b/lib/api/src/js/externals/function.rs @@ -43,6 +43,10 @@ pub struct Function { pub(crate) handle: VMFunction, } +// Function can't be Send in js because it dosen't support `structuredClone` +// https://developer.mozilla.org/en-US/docs/Web/API/structuredClone +// unsafe impl Send for Function {} + impl From for Function { fn from(handle: VMFunction) -> Self { Self { handle } diff --git a/lib/api/src/js/externals/global.rs b/lib/api/src/js/externals/global.rs index f529fa47aab..5e2f93b703d 100644 --- a/lib/api/src/js/externals/global.rs +++ b/lib/api/src/js/externals/global.rs @@ -13,6 +13,10 @@ pub struct Global { pub(crate) handle: VMGlobal, } +// Global can't be Send in js because it dosen't support `structuredClone` +// https://developer.mozilla.org/en-US/docs/Web/API/structuredClone +// unsafe impl Send for Global {} + impl Global { pub(crate) fn to_vm_extern(&self) -> VMExtern { VMExtern::Global(self.handle.clone()) diff --git a/lib/api/src/js/externals/memory.rs b/lib/api/src/js/externals/memory.rs index 09a23d610e2..3910000b03b 100644 --- a/lib/api/src/js/externals/memory.rs +++ b/lib/api/src/js/externals/memory.rs @@ -53,6 +53,18 @@ pub struct Memory { pub(crate) handle: VMMemory, } +// Only SharedMemories can be Send in js, becuase they support `structuredClone`. +// Normal memories will fail while doing structuredClone. +// In this case, we implement Send just in case as it can be a shared memory. +// https://developer.mozilla.org/en-US/docs/Web/API/structuredClone +// ```js +// const memory = new WebAssembly.Memory({ +// initial: 10, +// maximum: 100, +// shared: true // <--- It must be shared, otherwise structuredClone will fail +// }); +// structuredClone(memory) +// ``` unsafe impl Send for Memory {} unsafe impl Sync for Memory {} diff --git a/lib/api/src/js/externals/table.rs b/lib/api/src/js/externals/table.rs index c30471b0223..c16fee03230 100644 --- a/lib/api/src/js/externals/table.rs +++ b/lib/api/src/js/externals/table.rs @@ -11,6 +11,10 @@ pub struct Table { pub(crate) handle: VMTable, } +// Table can't be Send in js because it dosen't support `structuredClone` +// https://developer.mozilla.org/en-US/docs/Web/API/structuredClone +// unsafe impl Send for Table {} + fn set_table_item(table: &VMTable, item_index: u32, item: &Function) -> Result<(), RuntimeError> { table.table.set(item_index, item).map_err(|e| e.into()) } diff --git a/lib/api/src/js/instance.rs b/lib/api/src/js/instance.rs index 1ecf1defed1..30ff0b89d9b 100644 --- a/lib/api/src/js/instance.rs +++ b/lib/api/src/js/instance.rs @@ -13,7 +13,9 @@ pub struct Instance { pub(crate) _handle: VMInstance, } -unsafe impl Send for Instance {} +// Instance can't be Send in js because it dosen't support `structuredClone` +// https://developer.mozilla.org/en-US/docs/Web/API/structuredClone +// unsafe impl Send for Instance {} impl Instance { pub(crate) fn new( diff --git a/lib/api/src/js/module.rs b/lib/api/src/js/module.rs index 4ba496ff0b8..3be1e6d49a0 100644 --- a/lib/api/src/js/module.rs +++ b/lib/api/src/js/module.rs @@ -45,7 +45,16 @@ pub struct Module { raw_bytes: Option, } +// Module implements `structuredClone` in js, so it's safe it to make it Send. +// https://developer.mozilla.org/en-US/docs/Web/API/structuredClone +// ```js +// const module = new WebAssembly.Module(new Uint8Array([ +// 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00 +// ])); +// structuredClone(module) +// ``` unsafe impl Send for Module {} +unsafe impl Sync for Module {} impl Module { pub(crate) fn from_binary( From 07eb2f6ad71187223797949fad0deecece0999fa Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Mon, 6 Mar 2023 19:31:58 -0800 Subject: [PATCH 80/81] Improved mem_access --- lib/api/src/access.rs | 2 +- lib/api/src/js/mem_access.rs | 423 +++++++++++++++++- lib/api/src/js/mod.rs | 2 +- lib/api/src/js/module.rs | 23 +- lib/api/src/mem_access.rs | 819 +++++++++++++++++----------------- lib/api/src/sys/mem_access.rs | 425 +++++++++++++++++- lib/api/src/sys/mod.rs | 2 +- 7 files changed, 1259 insertions(+), 437 deletions(-) diff --git a/lib/api/src/access.rs b/lib/api/src/access.rs index da34c8ec407..288938c4722 100644 --- a/lib/api/src/access.rs +++ b/lib/api/src/access.rs @@ -1,6 +1,6 @@ use std::mem::MaybeUninit; -use crate::{WasmRef, WasmSlice}; +use crate::mem_access::{WasmRef, WasmSlice}; pub(super) enum SliceCow<'a, T> { #[allow(dead_code)] diff --git a/lib/api/src/js/mem_access.rs b/lib/api/src/js/mem_access.rs index efc0d544e2f..7ceaaef0a27 100644 --- a/lib/api/src/js/mem_access.rs +++ b/lib/api/src/js/mem_access.rs @@ -1,12 +1,429 @@ use crate::access::{RefCow, SliceCow, WasmRefAccess}; -use crate::mem_access::{MemoryAccessError, WasmRef, WasmSlice}; +use crate::js::externals::memory::MemoryBuffer; use crate::WasmSliceAccess; +use crate::{Memory32, Memory64, MemoryView, RuntimeError, WasmPtr}; +use std::{ + convert::TryInto, + fmt, + marker::PhantomData, + mem::{self, MaybeUninit}, + ops::Range, + slice, + string::FromUtf8Error, +}; +use thiserror::Error; +use wasmer_types::{MemorySize, ValueType}; + +/// Error for invalid [`Memory`] access. +#[derive(Clone, Copy, Debug, Error)] +#[non_exhaustive] +pub enum MemoryAccessError { + /// Memory access is outside heap bounds. + #[error("memory access out of bounds")] + HeapOutOfBounds, + /// Address calculation overflow. + #[error("address calculation overflow")] + Overflow, + /// String is not valid UTF-8. + #[error("string is not valid utf-8")] + NonUtf8String, +} + +impl From for RuntimeError { + fn from(err: MemoryAccessError) -> Self { + RuntimeError::new(err.to_string()) + } +} +impl From for MemoryAccessError { + fn from(_err: FromUtf8Error) -> Self { + MemoryAccessError::NonUtf8String + } +} + +/// Reference to a value in Wasm memory. +/// +/// The type of the value must satisfy the requirements of the `ValueType` +/// trait which guarantees that reading and writing such a value to untrusted +/// memory is safe. +/// +/// The address is not required to be aligned: unaligned accesses are fully +/// supported. +/// +/// This wrapper safely handles concurrent modifications of the data by another +/// thread. +#[derive(Clone, Copy)] +pub struct WasmRef<'a, T: ValueType> { + buffer: MemoryBuffer<'a>, + offset: u64, + marker: PhantomData<*mut T>, +} + +impl<'a, T: ValueType> WasmRef<'a, T> { + /// Creates a new `WasmRef` at the given offset in a memory. + #[inline] + pub fn new(view: &'a MemoryView, offset: u64) -> Self { + Self { + buffer: view.buffer().0, + offset, + marker: PhantomData, + } + } + + /// Get the offset into Wasm linear memory for this `WasmRef`. + #[inline] + pub fn offset(self) -> u64 { + self.offset + } + + /// Get a `WasmPtr` for this `WasmRef`. + #[inline] + pub fn as_ptr32(self) -> WasmPtr { + WasmPtr::new(self.offset as u32) + } + + /// Get a 64-bit `WasmPtr` for this `WasmRef`. + #[inline] + pub fn as_ptr64(self) -> WasmPtr { + WasmPtr::new(self.offset) + } + + /// Get a `WasmPtr` fror this `WasmRef`. + #[inline] + pub fn as_ptr(self) -> WasmPtr { + let offset: M::Offset = self + .offset + .try_into() + .map_err(|_| "invalid offset into memory") + .unwrap(); + WasmPtr::::new(offset) + } + + /// Reads the location pointed to by this `WasmRef`. + #[inline] + pub fn read(self) -> Result { + let mut out = MaybeUninit::uninit(); + let buf = + unsafe { slice::from_raw_parts_mut(out.as_mut_ptr() as *mut u8, mem::size_of::()) }; + self.buffer.read(self.offset, buf)?; + Ok(unsafe { out.assume_init() }) + } + + /// Writes to the location pointed to by this `WasmRef`. + #[inline] + pub fn write(self, val: T) -> Result<(), MemoryAccessError> { + let mut data = MaybeUninit::new(val); + let data = unsafe { + slice::from_raw_parts_mut( + data.as_mut_ptr() as *mut MaybeUninit, + mem::size_of::(), + ) + }; + val.zero_padding_bytes(data); + let data = unsafe { slice::from_raw_parts(data.as_ptr() as *const _, data.len()) }; + self.buffer.write(self.offset, data) + } + + /// Gains direct access to the memory of this slice + #[inline] + pub fn access(self) -> Result, MemoryAccessError> { + WasmRefAccess::new(self) + } +} + +impl<'a, T: ValueType> fmt::Debug for WasmRef<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "WasmRef(offset: {}, pointer: {:#x})", + self.offset, self.offset + ) + } +} + +/// Reference to an array of values in Wasm memory. +/// +/// The type of the value must satisfy the requirements of the `ValueType` +/// trait which guarantees that reading and writing such a value to untrusted +/// memory is safe. +/// +/// The address is not required to be aligned: unaligned accesses are fully +/// supported. +/// +/// This wrapper safely handles concurrent modifications of the data by another +/// thread. +#[derive(Clone, Copy)] +pub struct WasmSlice<'a, T: ValueType> { + buffer: MemoryBuffer<'a>, + offset: u64, + len: u64, + marker: PhantomData<*mut T>, +} + +impl<'a, T: ValueType> WasmSlice<'a, T> { + /// Creates a new `WasmSlice` starting at the given offset in memory and + /// with the given number of elements. + /// + /// Returns a `MemoryAccessError` if the slice length overflows. + #[inline] + pub fn new(memory: &'a MemoryView, offset: u64, len: u64) -> Result { + let total_len = len + .checked_mul(mem::size_of::() as u64) + .ok_or(MemoryAccessError::Overflow)?; + offset + .checked_add(total_len) + .ok_or(MemoryAccessError::Overflow)?; + Ok(Self { + buffer: memory.buffer().0, + offset, + len, + marker: PhantomData, + }) + } + + /// Get the offset into Wasm linear memory for this `WasmSlice`. + #[inline] + pub fn offset(self) -> u64 { + self.offset + } + + /// Get a 32-bit `WasmPtr` for this `WasmRef`. + #[inline] + pub fn as_ptr32(self) -> WasmPtr { + WasmPtr::new(self.offset as u32) + } + + /// Get a 64-bit `WasmPtr` for this `WasmRef`. + #[inline] + pub fn as_ptr64(self) -> WasmPtr { + WasmPtr::new(self.offset) + } + + /// Get the number of elements in this slice. + #[inline] + pub fn len(self) -> u64 { + self.len + } + + /// Return if the slice is empty. + #[inline] + pub fn is_empty(&self) -> bool { + self.len == 0 + } + + /// Get a `WasmRef` to an element in the slice. + #[inline] + pub fn index(self, idx: u64) -> WasmRef<'a, T> { + if idx >= self.len { + panic!("WasmSlice out of bounds"); + } + let offset = self.offset + idx * mem::size_of::() as u64; + WasmRef { + buffer: self.buffer, + offset, + marker: PhantomData, + } + } + + /// Get a `WasmSlice` for a subslice of this slice. + #[inline] + pub fn subslice(self, range: Range) -> WasmSlice<'a, T> { + if range.start > range.end || range.end > self.len { + panic!("WasmSlice out of bounds"); + } + let offset = self.offset + range.start * mem::size_of::() as u64; + Self { + buffer: self.buffer, + offset, + len: range.end - range.start, + marker: PhantomData, + } + } + + /// Get an iterator over the elements in this slice. + #[inline] + pub fn iter(self) -> WasmSliceIter<'a, T> { + WasmSliceIter { slice: self } + } + + /// Reads an element of this slice. + #[inline] + pub fn read(self, idx: u64) -> Result { + self.index(idx).read() + } + + /// Writes to an element of this slice. + #[inline] + pub fn write(self, idx: u64, val: T) -> Result<(), MemoryAccessError> { + self.index(idx).write(val) + } + + /// Gains direct access to the memory of this slice + #[inline] + pub fn access(self) -> Result, MemoryAccessError> { + WasmSliceAccess::new(self) + } + + /// Reads the entire slice into the given buffer. + /// + /// The length of the buffer must match the length of the slice. + #[inline] + pub fn read_slice(self, buf: &mut [T]) -> Result<(), MemoryAccessError> { + assert_eq!( + buf.len() as u64, + self.len, + "slice length doesn't match WasmSlice length" + ); + let bytes = unsafe { + slice::from_raw_parts_mut( + buf.as_mut_ptr() as *mut MaybeUninit, + buf.len() * mem::size_of::(), + ) + }; + self.buffer.read_uninit(self.offset, bytes)?; + Ok(()) + } + + /// Reads the entire slice into the given uninitialized buffer. + /// + /// The length of the buffer must match the length of the slice. + /// + /// This method returns an initialized view of the buffer. + #[inline] + pub fn read_slice_uninit( + self, + buf: &mut [MaybeUninit], + ) -> Result<&mut [T], MemoryAccessError> { + assert_eq!( + buf.len() as u64, + self.len, + "slice length doesn't match WasmSlice length" + ); + let bytes = unsafe { + slice::from_raw_parts_mut( + buf.as_mut_ptr() as *mut MaybeUninit, + buf.len() * mem::size_of::(), + ) + }; + self.buffer.read_uninit(self.offset, bytes)?; + Ok(unsafe { slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut T, buf.len()) }) + } + + /// Write the given slice into this `WasmSlice`. + /// + /// The length of the slice must match the length of the `WasmSlice`. + #[inline] + pub fn write_slice(self, data: &[T]) -> Result<(), MemoryAccessError> { + assert_eq!( + data.len() as u64, + self.len, + "slice length doesn't match WasmSlice length" + ); + let bytes = unsafe { + slice::from_raw_parts(data.as_ptr() as *const u8, data.len() * mem::size_of::()) + }; + self.buffer.write(self.offset, bytes) + } + + /// Reads this `WasmSlice` into a `slice`. + #[inline] + pub fn read_to_slice<'b>( + self, + buf: &'b mut [MaybeUninit], + ) -> Result { + let len = self.len.try_into().expect("WasmSlice length overflow"); + self.buffer.read_uninit(self.offset, buf)?; + Ok(len) + } + + /// Reads this `WasmSlice` into a `Vec`. + #[inline] + pub fn read_to_vec(self) -> Result, MemoryAccessError> { + let len = self.len.try_into().expect("WasmSlice length overflow"); + let mut vec = Vec::with_capacity(len); + let bytes = unsafe { + slice::from_raw_parts_mut( + vec.as_mut_ptr() as *mut MaybeUninit, + len * mem::size_of::(), + ) + }; + self.buffer.read_uninit(self.offset, bytes)?; + unsafe { + vec.set_len(len); + } + Ok(vec) + } + + /// Reads this `WasmSlice` into a `BytesMut` + #[inline] + pub fn read_to_bytes(self) -> Result { + let len = self.len.try_into().expect("WasmSlice length overflow"); + let mut ret = bytes::BytesMut::with_capacity(len); + let bytes = unsafe { + slice::from_raw_parts_mut( + ret.as_mut_ptr() as *mut MaybeUninit, + len * mem::size_of::(), + ) + }; + self.buffer.read_uninit(self.offset, bytes)?; + unsafe { + ret.set_len(len); + } + Ok(ret) + } +} + +impl<'a, T: ValueType> fmt::Debug for WasmSlice<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "WasmSlice(offset: {}, len: {}, pointer: {:#x})", + self.offset, self.len, self.offset + ) + } +} + +/// Iterator over the elements of a `WasmSlice`. +pub struct WasmSliceIter<'a, T: ValueType> { + slice: WasmSlice<'a, T>, +} + +impl<'a, T: ValueType> Iterator for WasmSliceIter<'a, T> { + type Item = WasmRef<'a, T>; + + fn next(&mut self) -> Option { + if self.slice.len() != 0 { + let elem = self.slice.index(0); + self.slice = self.slice.subslice(1..self.slice.len()); + Some(elem) + } else { + None + } + } + + fn size_hint(&self) -> (usize, Option) { + (0..self.slice.len()).size_hint() + } +} + +impl<'a, T: ValueType> DoubleEndedIterator for WasmSliceIter<'a, T> { + fn next_back(&mut self) -> Option { + if self.slice.len() != 0 { + let elem = self.slice.index(self.slice.len() - 1); + self.slice = self.slice.subslice(0..self.slice.len() - 1); + Some(elem) + } else { + None + } + } +} + +impl<'a, T: ValueType> ExactSizeIterator for WasmSliceIter<'a, T> {} impl<'a, T> WasmSliceAccess<'a, T> where T: wasmer_types::ValueType, { - pub(crate) fn new(slice: WasmSlice<'a, T>) -> Result { + fn new(slice: WasmSlice<'a, T>) -> Result { let buf = slice.read_to_vec()?; Ok(Self { slice, @@ -19,7 +436,7 @@ impl<'a, T> WasmRefAccess<'a, T> where T: wasmer_types::ValueType, { - pub(crate) fn new(ptr: WasmRef<'a, T>) -> Result { + fn new(ptr: WasmRef<'a, T>) -> Result { let val = ptr.read()?; Ok(Self { ptr, diff --git a/lib/api/src/js/mod.rs b/lib/api/src/js/mod.rs index ccafd8a9442..d8c82b7d28b 100644 --- a/lib/api/src/js/mod.rs +++ b/lib/api/src/js/mod.rs @@ -29,7 +29,7 @@ pub(crate) mod errors; pub(crate) mod extern_ref; pub(crate) mod externals; pub(crate) mod instance; -mod mem_access; +pub(crate) mod mem_access; pub(crate) mod module; #[cfg(feature = "wasm-types-polyfill")] mod module_info_polyfill; diff --git a/lib/api/src/js/module.rs b/lib/api/src/js/module.rs index 3be1e6d49a0..7fa896a0916 100644 --- a/lib/api/src/js/module.rs +++ b/lib/api/src/js/module.rs @@ -65,21 +65,20 @@ impl Module { } pub(crate) unsafe fn from_binary_unchecked( - engine: &impl AsEngineRef, + _engine: &impl AsEngineRef, binary: &[u8], ) -> Result { let js_bytes = Uint8Array::view(binary); let module = WebAssembly::Module::new(&js_bytes.into()).unwrap(); - Self::from_js_module(engine, module, binary) + Ok(Self::from_js_module(module, binary)) } /// Creates a new WebAssembly module skipping any kind of validation from a javascript module /// pub(crate) unsafe fn from_js_module( - _engine: &impl AsEngineRef, module: WebAssembly::Module, binary: impl IntoBytes, - ) -> Result { + ) -> Self { let binary = binary.into_bytes(); // The module is now validated, so we can safely parse it's types #[cfg(feature = "wasm-types-polyfill")] @@ -105,13 +104,13 @@ impl Module { #[cfg(not(feature = "wasm-types-polyfill"))] let (type_hints, name) = (None, None); - Ok(Self { + Self { module, type_hints, name, #[cfg(feature = "js-serializable-module")] raw_bytes: Some(binary.into_bytes()), - }) + } } pub fn validate(_engine: &impl AsEngineRef, binary: &[u8]) -> Result<(), CompileError> { @@ -444,16 +443,8 @@ impl From for Module { } impl From<(WebAssembly::Module, T)> for crate::module::Module { - fn from(module_and_binary: (WebAssembly::Module, T)) -> crate::module::Module { - let (module, _binary) = module_and_binary; - let module = Module { - module, - name: None, - type_hints: None, - #[cfg(feature = "js-serializable-module")] - raw_bytes: Some(_binary.into_bytes()), - }; - crate::module::Module(module.into()) + fn from((module, binary): (WebAssembly::Module, T)) -> crate::module::Module { + unsafe { crate::module::Module(Module::from_js_module(module, binary.into_bytes())) } } } diff --git a/lib/api/src/mem_access.rs b/lib/api/src/mem_access.rs index 5b099d41d15..6ddc38f27ed 100644 --- a/lib/api/src/mem_access.rs +++ b/lib/api/src/mem_access.rs @@ -1,404 +1,415 @@ -use crate::access::WasmRefAccess; -use crate::externals::memory::MemoryBuffer; -use crate::{Memory32, Memory64, MemorySize, MemoryView, WasmPtr}; -use crate::{RuntimeError, WasmSliceAccess}; -use std::convert::TryInto; -use std::fmt; -use std::marker::PhantomData; -use std::mem::{self, MaybeUninit}; -use std::ops::Range; -use std::slice; -use std::string::FromUtf8Error; -use thiserror::Error; -use wasmer_types::ValueType; - -/// Error for invalid [`Memory`] access. -#[derive(Clone, Copy, Debug, Error)] -#[non_exhaustive] -pub enum MemoryAccessError { - /// Memory access is outside heap bounds. - #[error("memory access out of bounds")] - HeapOutOfBounds, - /// Address calculation overflow. - #[error("address calculation overflow")] - Overflow, - /// String is not valid UTF-8. - #[error("string is not valid utf-8")] - NonUtf8String, -} - -impl From for RuntimeError { - fn from(err: MemoryAccessError) -> Self { - Self::new(err.to_string()) - } -} -impl From for MemoryAccessError { - fn from(_err: FromUtf8Error) -> Self { - Self::NonUtf8String - } -} - -/// Reference to a value in Wasm memory. -/// -/// The type of the value must satisfy the requirements of the `ValueType` -/// trait which guarantees that reading and writing such a value to untrusted -/// memory is safe. -/// -/// The address is not required to be aligned: unaligned accesses are fully -/// supported. -/// -/// This wrapper safely handles concurrent modifications of the data by another -/// thread. -#[derive(Clone, Copy)] -pub struct WasmRef<'a, T: ValueType> { - #[allow(unused)] - pub(crate) buffer: MemoryBuffer<'a>, - pub(crate) offset: u64, - marker: PhantomData<*mut T>, -} - -impl<'a, T: ValueType> WasmRef<'a, T> { - /// Creates a new `WasmRef` at the given offset in a memory. - #[inline] - pub fn new(view: &'a MemoryView, offset: u64) -> Self { - Self { - buffer: view.buffer(), - offset, - marker: PhantomData, - } - } - - /// Get the offset into Wasm linear memory for this `WasmRef`. - #[inline] - pub fn offset(self) -> u64 { - self.offset - } - - /// Get a `WasmPtr` for this `WasmRef`. - #[inline] - pub fn as_ptr32(self) -> WasmPtr { - WasmPtr::new(self.offset as u32) - } - - /// Get a 64-bit `WasmPtr` for this `WasmRef`. - #[inline] - pub fn as_ptr64(self) -> WasmPtr { - WasmPtr::new(self.offset) - } - - /// Get a `WasmPtr` fror this `WasmRef`. - #[inline] - pub fn as_ptr(self) -> WasmPtr { - let offset: M::Offset = self - .offset - .try_into() - .map_err(|_| "invalid offset into memory") - .unwrap(); - WasmPtr::::new(offset) - } - - /// Reads the location pointed to by this `WasmRef`. - #[inline] - pub fn read(self) -> Result { - Ok(self.access()?.read()) - } - - /// Writes to the location pointed to by this `WasmRef`. - #[inline] - pub fn write(self, val: T) -> Result<(), MemoryAccessError> { - self.access()?.write(val); - Ok(()) - } - - /// Gains direct access to the memory of this slice - #[inline] - pub fn access(self) -> Result, MemoryAccessError> { - WasmRefAccess::new(self) - } -} - -impl<'a, T: ValueType> fmt::Debug for WasmRef<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "WasmRef(offset: {}, pointer: {:#x})", - self.offset, self.offset - ) - } -} - -/// Reference to an array of values in Wasm memory. -/// -/// The type of the value must satisfy the requirements of the `ValueType` -/// trait which guarantees that reading and writing such a value to untrusted -/// memory is safe. -/// -/// The address is not required to be aligned: unaligned accesses are fully -/// supported. -/// -/// This wrapper safely handles concurrent modifications of the data by another -/// thread. -#[derive(Clone, Copy)] -pub struct WasmSlice<'a, T: ValueType> { - pub(crate) buffer: MemoryBuffer<'a>, - pub(crate) offset: u64, - pub(crate) len: u64, - marker: PhantomData<*mut T>, -} - -impl<'a, T: ValueType> WasmSlice<'a, T> { - /// Creates a new `WasmSlice` starting at the given offset in memory and - /// with the given number of elements. - /// - /// Returns a `MemoryAccessError` if the slice length overflows. - #[inline] - pub fn new(view: &'a MemoryView, offset: u64, len: u64) -> Result { - let total_len = len - .checked_mul(mem::size_of::() as u64) - .ok_or(MemoryAccessError::Overflow)?; - offset - .checked_add(total_len) - .ok_or(MemoryAccessError::Overflow)?; - Ok(Self { - buffer: view.buffer(), - offset, - len, - marker: PhantomData, - }) - } - - /// Get the offset into Wasm linear memory for this `WasmSlice`. - #[inline] - pub fn offset(self) -> u64 { - self.offset - } - - /// Get a 32-bit `WasmPtr` for this `WasmRef`. - #[inline] - pub fn as_ptr32(self) -> WasmPtr { - WasmPtr::new(self.offset as u32) - } - - /// Get a 64-bit `WasmPtr` for this `WasmRef`. - #[inline] - pub fn as_ptr64(self) -> WasmPtr { - WasmPtr::new(self.offset) - } - - /// Get the number of elements in this slice. - #[inline] - pub fn len(self) -> u64 { - self.len - } - - /// Returns `true` if the number of elements is 0. - #[inline] - pub fn is_empty(self) -> bool { - self.len == 0 - } - - /// Get a `WasmRef` to an element in the slice. - #[inline] - pub fn index(self, idx: u64) -> WasmRef<'a, T> { - if idx >= self.len { - panic!("WasmSlice out of bounds"); - } - let offset = self.offset + idx * mem::size_of::() as u64; - WasmRef { - buffer: self.buffer, - offset, - marker: PhantomData, - } - } - - /// Get a `WasmSlice` for a subslice of this slice. - #[inline] - pub fn subslice(self, range: Range) -> WasmSlice<'a, T> { - if range.start > range.end || range.end > self.len { - panic!("WasmSlice out of bounds"); - } - let offset = self.offset + range.start * mem::size_of::() as u64; - Self { - buffer: self.buffer, - offset, - len: range.end - range.start, - marker: PhantomData, - } - } - - /// Get an iterator over the elements in this slice. - #[inline] - pub fn iter(self) -> WasmSliceIter<'a, T> { - WasmSliceIter { slice: self } - } - - /// Gains direct access to the memory of this slice - #[inline] - pub fn access(self) -> Result, MemoryAccessError> { - WasmSliceAccess::new(self) - } - - /// Reads an element of this slice. - #[inline] - pub fn read(self, idx: u64) -> Result { - self.index(idx).read() - } - - /// Writes to an element of this slice. - #[inline] - pub fn write(self, idx: u64, val: T) -> Result<(), MemoryAccessError> { - self.index(idx).write(val) - } - - /// Reads the entire slice into the given buffer. - /// - /// The length of the buffer must match the length of the slice. - #[inline] - pub fn read_slice(self, buf: &mut [T]) -> Result<(), MemoryAccessError> { - assert_eq!( - buf.len() as u64, - self.len, - "slice length doesn't match WasmSlice length" - ); - let bytes = unsafe { - slice::from_raw_parts_mut( - buf.as_mut_ptr() as *mut MaybeUninit, - buf.len() * mem::size_of::(), - ) - }; - self.buffer.read_uninit(self.offset, bytes)?; - Ok(()) - } - - /// Reads the entire slice into the given uninitialized buffer. - /// - /// The length of the buffer must match the length of the slice. - /// - /// This method returns an initialized view of the buffer. - #[inline] - pub fn read_slice_uninit( - self, - buf: &mut [MaybeUninit], - ) -> Result<&mut [T], MemoryAccessError> { - assert_eq!( - buf.len() as u64, - self.len, - "slice length doesn't match WasmSlice length" - ); - let bytes = unsafe { - slice::from_raw_parts_mut( - buf.as_mut_ptr() as *mut MaybeUninit, - buf.len() * mem::size_of::(), - ) - }; - self.buffer.read_uninit(self.offset, bytes)?; - Ok(unsafe { slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut T, buf.len()) }) - } - - /// Write the given slice into this `WasmSlice`. - /// - /// The length of the slice must match the length of the `WasmSlice`. - #[inline] - pub fn write_slice(self, data: &[T]) -> Result<(), MemoryAccessError> { - assert_eq!( - data.len() as u64, - self.len, - "slice length doesn't match WasmSlice length" - ); - let bytes = unsafe { - slice::from_raw_parts(data.as_ptr() as *const u8, data.len() * mem::size_of::()) - }; - self.buffer.write(self.offset, bytes) - } - - /// Reads this `WasmSlice` into a `slice`. - #[inline] - pub fn read_to_slice(self, buf: &mut [MaybeUninit]) -> Result { - let len = self.len.try_into().expect("WasmSlice length overflow"); - self.buffer.read_uninit(self.offset, buf)?; - Ok(len) - } - - /// Reads this `WasmSlice` into a `Vec`. - #[inline] - pub fn read_to_vec(self) -> Result, MemoryAccessError> { - let len = self.len.try_into().expect("WasmSlice length overflow"); - let mut vec = Vec::with_capacity(len); - let bytes = unsafe { - slice::from_raw_parts_mut( - vec.as_mut_ptr() as *mut MaybeUninit, - len * mem::size_of::(), - ) - }; - self.buffer.read_uninit(self.offset, bytes)?; - unsafe { - vec.set_len(len); - } - Ok(vec) - } - - /// Reads this `WasmSlice` into a `BytesMut` - #[inline] - pub fn read_to_bytes(self) -> Result { - let len = self.len.try_into().expect("WasmSlice length overflow"); - let mut ret = bytes::BytesMut::with_capacity(len); - let bytes = unsafe { - slice::from_raw_parts_mut( - ret.as_mut_ptr() as *mut MaybeUninit, - len * mem::size_of::(), - ) - }; - self.buffer.read_uninit(self.offset, bytes)?; - unsafe { - ret.set_len(len); - } - Ok(ret) - } -} - -impl<'a, T: ValueType> fmt::Debug for WasmSlice<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "WasmSlice(offset: {}, len: {}, pointer: {:#x})", - self.offset, self.len, self.offset - ) - } -} - -/// Iterator over the elements of a `WasmSlice`. -pub struct WasmSliceIter<'a, T: ValueType> { - slice: WasmSlice<'a, T>, -} - -impl<'a, T: ValueType> Iterator for WasmSliceIter<'a, T> { - type Item = WasmRef<'a, T>; - - fn next(&mut self) -> Option { - if !self.slice.is_empty() { - let elem = self.slice.index(0); - self.slice = self.slice.subslice(1..self.slice.len()); - Some(elem) - } else { - None - } - } - - fn size_hint(&self) -> (usize, Option) { - (0..self.slice.len()).size_hint() - } -} - -impl<'a, T: ValueType> DoubleEndedIterator for WasmSliceIter<'a, T> { - fn next_back(&mut self) -> Option { - if !self.slice.is_empty() { - let elem = self.slice.index(self.slice.len() - 1); - self.slice = self.slice.subslice(0..self.slice.len() - 1); - Some(elem) - } else { - None - } - } -} - -impl<'a, T: ValueType> ExactSizeIterator for WasmSliceIter<'a, T> {} +#[cfg(feature = "js")] +pub use crate::js::mem_access::{MemoryAccessError, WasmRef, WasmSlice, WasmSliceIter}; + +#[cfg(feature = "sys")] +pub use crate::sys::mem_access::{MemoryAccessError, WasmRef, WasmSlice, WasmSliceIter}; + +// use crate::access::WasmRefAccess; +// use crate::externals::memory::MemoryBuffer; +// use crate::{Memory32, Memory64, MemorySize, MemoryView, WasmPtr}; +// use crate::{RuntimeError, WasmSliceAccess}; +// use std::convert::TryInto; +// use std::fmt; +// use std::marker::PhantomData; +// use std::mem::{self, MaybeUninit}; +// use std::ops::Range; +// use std::slice; +// use std::string::FromUtf8Error; +// use thiserror::Error; +// use wasmer_types::ValueType; + +// /// Error for invalid [`Memory`] access. +// #[derive(Clone, Copy, Debug, Error)] +// #[non_exhaustive] +// pub enum MemoryAccessError { +// /// Memory access is outside heap bounds. +// #[error("memory access out of bounds")] +// HeapOutOfBounds, +// /// Address calculation overflow. +// #[error("address calculation overflow")] +// Overflow, +// /// String is not valid UTF-8. +// #[error("string is not valid utf-8")] +// NonUtf8String, +// } + +// impl From for RuntimeError { +// fn from(err: MemoryAccessError) -> Self { +// Self::new(err.to_string()) +// } +// } +// impl From for MemoryAccessError { +// fn from(_err: FromUtf8Error) -> Self { +// Self::NonUtf8String +// } +// } + +// /// Reference to a value in Wasm memory. +// /// +// /// The type of the value must satisfy the requirements of the `ValueType` +// /// trait which guarantees that reading and writing such a value to untrusted +// /// memory is safe. +// /// +// /// The address is not required to be aligned: unaligned accesses are fully +// /// supported. +// /// +// /// This wrapper safely handles concurrent modifications of the data by another +// /// thread. +// #[derive(Clone, Copy)] +// pub struct WasmRef<'a, T: ValueType> { +// #[allow(unused)] +// pub(crate) buffer: MemoryBuffer<'a>, +// pub(crate) offset: u64, +// marker: PhantomData<*mut T>, +// } + +// impl<'a, T: ValueType> WasmRef<'a, T> { +// /// Creates a new `WasmRef` at the given offset in a memory. +// #[inline] +// pub fn new(view: &'a MemoryView, offset: u64) -> Self { +// Self { +// buffer: view.buffer(), +// offset, +// marker: PhantomData, +// } +// } + +// /// Get the offset into Wasm linear memory for this `WasmRef`. +// #[inline] +// pub fn offset(self) -> u64 { +// self.offset +// } + +// /// Get a `WasmPtr` for this `WasmRef`. +// #[inline] +// pub fn as_ptr32(self) -> WasmPtr { +// WasmPtr::new(self.offset as u32) +// } + +// /// Get a 64-bit `WasmPtr` for this `WasmRef`. +// #[inline] +// pub fn as_ptr64(self) -> WasmPtr { +// WasmPtr::new(self.offset) +// } + +// /// Get a `WasmPtr` fror this `WasmRef`. +// #[inline] +// pub fn as_ptr(self) -> WasmPtr { +// let offset: M::Offset = self +// .offset +// .try_into() +// .map_err(|_| "invalid offset into memory") +// .unwrap(); +// WasmPtr::::new(offset) +// } + +// /// Reads the location pointed to by this `WasmRef`. +// #[inline] +// pub fn read(self) -> Result { +// let mut out = MaybeUninit::uninit(); +// let buf = +// unsafe { slice::from_raw_parts_mut(out.as_mut_ptr() as *mut u8, mem::size_of::()) }; +// self.buffer.read(self.offset, buf)?; +// Ok(unsafe { out.assume_init() }) +// // Ok(self.access()?.read()) +// } + +// /// Writes to the location pointed to by this `WasmRef`. +// #[inline] +// pub fn write(self, val: T) -> Result<(), MemoryAccessError> { +// self.access()?.write(val); +// Ok(()) +// } + +// /// Gains direct access to the memory of this slice +// #[inline] +// pub fn access(self) -> Result, MemoryAccessError> { +// WasmRefAccess::new(self) +// } +// } + +// impl<'a, T: ValueType> fmt::Debug for WasmRef<'a, T> { +// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +// write!( +// f, +// "WasmRef(offset: {}, pointer: {:#x})", +// self.offset, self.offset +// ) +// } +// } + +// /// Reference to an array of values in Wasm memory. +// /// +// /// The type of the value must satisfy the requirements of the `ValueType` +// /// trait which guarantees that reading and writing such a value to untrusted +// /// memory is safe. +// /// +// /// The address is not required to be aligned: unaligned accesses are fully +// /// supported. +// /// +// /// This wrapper safely handles concurrent modifications of the data by another +// /// thread. +// #[derive(Clone, Copy)] +// pub struct WasmSlice<'a, T: ValueType> { +// pub(crate) buffer: MemoryBuffer<'a>, +// pub(crate) offset: u64, +// pub(crate) len: u64, +// marker: PhantomData<*mut T>, +// } + +// impl<'a, T: ValueType> WasmSlice<'a, T> { +// /// Creates a new `WasmSlice` starting at the given offset in memory and +// /// with the given number of elements. +// /// +// /// Returns a `MemoryAccessError` if the slice length overflows. +// #[inline] +// pub fn new(view: &'a MemoryView, offset: u64, len: u64) -> Result { +// let total_len = len +// .checked_mul(mem::size_of::() as u64) +// .ok_or(MemoryAccessError::Overflow)?; +// offset +// .checked_add(total_len) +// .ok_or(MemoryAccessError::Overflow)?; +// Ok(Self { +// buffer: view.buffer(), +// offset, +// len, +// marker: PhantomData, +// }) +// } + +// /// Get the offset into Wasm linear memory for this `WasmSlice`. +// #[inline] +// pub fn offset(self) -> u64 { +// self.offset +// } + +// /// Get a 32-bit `WasmPtr` for this `WasmRef`. +// #[inline] +// pub fn as_ptr32(self) -> WasmPtr { +// WasmPtr::new(self.offset as u32) +// } + +// /// Get a 64-bit `WasmPtr` for this `WasmRef`. +// #[inline] +// pub fn as_ptr64(self) -> WasmPtr { +// WasmPtr::new(self.offset) +// } + +// /// Get the number of elements in this slice. +// #[inline] +// pub fn len(self) -> u64 { +// self.len +// } + +// /// Returns `true` if the number of elements is 0. +// #[inline] +// pub fn is_empty(self) -> bool { +// self.len == 0 +// } + +// /// Get a `WasmRef` to an element in the slice. +// #[inline] +// pub fn index(self, idx: u64) -> WasmRef<'a, T> { +// if idx >= self.len { +// panic!("WasmSlice out of bounds"); +// } +// let offset = self.offset + idx * mem::size_of::() as u64; +// WasmRef { +// buffer: self.buffer, +// offset, +// marker: PhantomData, +// } +// } + +// /// Get a `WasmSlice` for a subslice of this slice. +// #[inline] +// pub fn subslice(self, range: Range) -> WasmSlice<'a, T> { +// if range.start > range.end || range.end > self.len { +// panic!("WasmSlice out of bounds"); +// } +// let offset = self.offset + range.start * mem::size_of::() as u64; +// Self { +// buffer: self.buffer, +// offset, +// len: range.end - range.start, +// marker: PhantomData, +// } +// } + +// /// Get an iterator over the elements in this slice. +// #[inline] +// pub fn iter(self) -> WasmSliceIter<'a, T> { +// WasmSliceIter { slice: self } +// } + +// /// Gains direct access to the memory of this slice +// #[inline] +// pub fn access(self) -> Result, MemoryAccessError> { +// WasmSliceAccess::new(self) +// } + +// /// Reads an element of this slice. +// #[inline] +// pub fn read(self, idx: u64) -> Result { +// self.index(idx).read() +// } + +// /// Writes to an element of this slice. +// #[inline] +// pub fn write(self, idx: u64, val: T) -> Result<(), MemoryAccessError> { +// self.index(idx).write(val) +// } + +// /// Reads the entire slice into the given buffer. +// /// +// /// The length of the buffer must match the length of the slice. +// #[inline] +// pub fn read_slice(self, buf: &mut [T]) -> Result<(), MemoryAccessError> { +// assert_eq!( +// buf.len() as u64, +// self.len, +// "slice length doesn't match WasmSlice length" +// ); +// let bytes = unsafe { +// slice::from_raw_parts_mut( +// buf.as_mut_ptr() as *mut MaybeUninit, +// buf.len() * mem::size_of::(), +// ) +// }; +// self.buffer.read_uninit(self.offset, bytes)?; +// Ok(()) +// } + +// /// Reads the entire slice into the given uninitialized buffer. +// /// +// /// The length of the buffer must match the length of the slice. +// /// +// /// This method returns an initialized view of the buffer. +// #[inline] +// pub fn read_slice_uninit( +// self, +// buf: &mut [MaybeUninit], +// ) -> Result<&mut [T], MemoryAccessError> { +// assert_eq!( +// buf.len() as u64, +// self.len, +// "slice length doesn't match WasmSlice length" +// ); +// let bytes = unsafe { +// slice::from_raw_parts_mut( +// buf.as_mut_ptr() as *mut MaybeUninit, +// buf.len() * mem::size_of::(), +// ) +// }; +// self.buffer.read_uninit(self.offset, bytes)?; +// Ok(unsafe { slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut T, buf.len()) }) +// } + +// /// Write the given slice into this `WasmSlice`. +// /// +// /// The length of the slice must match the length of the `WasmSlice`. +// #[inline] +// pub fn write_slice(self, data: &[T]) -> Result<(), MemoryAccessError> { +// assert_eq!( +// data.len() as u64, +// self.len, +// "slice length doesn't match WasmSlice length" +// ); +// let bytes = unsafe { +// slice::from_raw_parts(data.as_ptr() as *const u8, data.len() * mem::size_of::()) +// }; +// self.buffer.write(self.offset, bytes) +// } + +// /// Reads this `WasmSlice` into a `slice`. +// #[inline] +// pub fn read_to_slice(self, buf: &mut [MaybeUninit]) -> Result { +// let len = self.len.try_into().expect("WasmSlice length overflow"); +// self.buffer.read_uninit(self.offset, buf)?; +// Ok(len) +// } + +// /// Reads this `WasmSlice` into a `Vec`. +// #[inline] +// pub fn read_to_vec(self) -> Result, MemoryAccessError> { +// let len = self.len.try_into().expect("WasmSlice length overflow"); +// let mut vec = Vec::with_capacity(len); +// let bytes = unsafe { +// slice::from_raw_parts_mut( +// vec.as_mut_ptr() as *mut MaybeUninit, +// len * mem::size_of::(), +// ) +// }; +// self.buffer.read_uninit(self.offset, bytes)?; +// unsafe { +// vec.set_len(len); +// } +// Ok(vec) +// } + +// /// Reads this `WasmSlice` into a `BytesMut` +// #[inline] +// pub fn read_to_bytes(self) -> Result { +// let len = self.len.try_into().expect("WasmSlice length overflow"); +// let mut ret = bytes::BytesMut::with_capacity(len); +// let bytes = unsafe { +// slice::from_raw_parts_mut( +// ret.as_mut_ptr() as *mut MaybeUninit, +// len * mem::size_of::(), +// ) +// }; +// self.buffer.read_uninit(self.offset, bytes)?; +// unsafe { +// ret.set_len(len); +// } +// Ok(ret) +// } +// } + +// impl<'a, T: ValueType> fmt::Debug for WasmSlice<'a, T> { +// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +// write!( +// f, +// "WasmSlice(offset: {}, len: {}, pointer: {:#x})", +// self.offset, self.len, self.offset +// ) +// } +// } + +// /// Iterator over the elements of a `WasmSlice`. +// pub struct WasmSliceIter<'a, T: ValueType> { +// slice: WasmSlice<'a, T>, +// } + +// impl<'a, T: ValueType> Iterator for WasmSliceIter<'a, T> { +// type Item = WasmRef<'a, T>; + +// fn next(&mut self) -> Option { +// if !self.slice.is_empty() { +// let elem = self.slice.index(0); +// self.slice = self.slice.subslice(1..self.slice.len()); +// Some(elem) +// } else { +// None +// } +// } + +// fn size_hint(&self) -> (usize, Option) { +// (0..self.slice.len()).size_hint() +// } +// } + +// impl<'a, T: ValueType> DoubleEndedIterator for WasmSliceIter<'a, T> { +// fn next_back(&mut self) -> Option { +// if !self.slice.is_empty() { +// let elem = self.slice.index(self.slice.len() - 1); +// self.slice = self.slice.subslice(0..self.slice.len() - 1); +// Some(elem) +// } else { +// None +// } +// } +// } + +// impl<'a, T: ValueType> ExactSizeIterator for WasmSliceIter<'a, T> {} diff --git a/lib/api/src/sys/mem_access.rs b/lib/api/src/sys/mem_access.rs index 03a30c84998..02c2d931843 100644 --- a/lib/api/src/sys/mem_access.rs +++ b/lib/api/src/sys/mem_access.rs @@ -1,14 +1,417 @@ -use crate::access::{RefCow, SliceCow, WasmRefAccess}; -use crate::mem_access::MemoryAccessError; -use crate::WasmSlice; -use crate::{WasmRef, WasmSliceAccess}; -use std::mem; +use crate::sys::externals::memory::MemoryBuffer; +use crate::{ + access::{RefCow, SliceCow, WasmRefAccess}, + RuntimeError, WasmSliceAccess, +}; +#[allow(unused_imports)] +use crate::{Memory, Memory32, Memory64, MemorySize, MemoryView, WasmPtr}; +use std::{ + convert::TryInto, + fmt, + marker::PhantomData, + mem::{self, MaybeUninit}, + ops::Range, + slice, + string::FromUtf8Error, +}; +use thiserror::Error; +use wasmer_types::ValueType; + +/// Error for invalid [`Memory`] access. +#[derive(Clone, Copy, Debug, Error)] +#[non_exhaustive] +pub enum MemoryAccessError { + /// Memory access is outside heap bounds. + #[error("memory access out of bounds")] + HeapOutOfBounds, + /// Address calculation overflow. + #[error("address calculation overflow")] + Overflow, + /// String is not valid UTF-8. + #[error("string is not valid utf-8")] + NonUtf8String, +} + +impl From for RuntimeError { + fn from(err: MemoryAccessError) -> Self { + Self::new(err.to_string()) + } +} +impl From for MemoryAccessError { + fn from(_err: FromUtf8Error) -> Self { + Self::NonUtf8String + } +} + +/// Reference to a value in Wasm memory. +/// +/// The type of the value must satisfy the requirements of the `ValueType` +/// trait which guarantees that reading and writing such a value to untrusted +/// memory is safe. +/// +/// The address is not required to be aligned: unaligned accesses are fully +/// supported. +/// +/// This wrapper safely handles concurrent modifications of the data by another +/// thread. +#[derive(Clone, Copy)] +pub struct WasmRef<'a, T: ValueType> { + buffer: MemoryBuffer<'a>, + offset: u64, + marker: PhantomData<*mut T>, +} + +impl<'a, T: ValueType> WasmRef<'a, T> { + /// Creates a new `WasmRef` at the given offset in a memory. + #[inline] + pub fn new(view: &'a MemoryView, offset: u64) -> Self { + Self { + buffer: view.buffer().0, + offset, + marker: PhantomData, + } + } + + /// Get the offset into Wasm linear memory for this `WasmRef`. + #[inline] + pub fn offset(self) -> u64 { + self.offset + } + + /// Get a `WasmPtr` for this `WasmRef`. + #[inline] + pub fn as_ptr32(self) -> WasmPtr { + WasmPtr::new(self.offset as u32) + } + + /// Get a 64-bit `WasmPtr` for this `WasmRef`. + #[inline] + pub fn as_ptr64(self) -> WasmPtr { + WasmPtr::new(self.offset) + } + + /// Get a `WasmPtr` fror this `WasmRef`. + #[inline] + pub fn as_ptr(self) -> WasmPtr { + let offset: M::Offset = self + .offset + .try_into() + .map_err(|_| "invalid offset into memory") + .unwrap(); + WasmPtr::::new(offset) + } + + /// Reads the location pointed to by this `WasmRef`. + #[inline] + pub fn read(self) -> Result { + Ok(self.access()?.read()) + } + + /// Writes to the location pointed to by this `WasmRef`. + #[inline] + pub fn write(self, val: T) -> Result<(), MemoryAccessError> { + self.access()?.write(val); + Ok(()) + } + + /// Gains direct access to the memory of this slice + #[inline] + pub fn access(self) -> Result, MemoryAccessError> { + WasmRefAccess::new(self) + } +} + +impl<'a, T: ValueType> fmt::Debug for WasmRef<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "WasmRef(offset: {}, pointer: {:#x})", + self.offset, self.offset + ) + } +} + +/// Reference to an array of values in Wasm memory. +/// +/// The type of the value must satisfy the requirements of the `ValueType` +/// trait which guarantees that reading and writing such a value to untrusted +/// memory is safe. +/// +/// The address is not required to be aligned: unaligned accesses are fully +/// supported. +/// +/// This wrapper safely handles concurrent modifications of the data by another +/// thread. +#[derive(Clone, Copy)] +pub struct WasmSlice<'a, T: ValueType> { + buffer: MemoryBuffer<'a>, + offset: u64, + len: u64, + marker: PhantomData<*mut T>, +} + +impl<'a, T: ValueType> WasmSlice<'a, T> { + /// Creates a new `WasmSlice` starting at the given offset in memory and + /// with the given number of elements. + /// + /// Returns a `MemoryAccessError` if the slice length overflows. + #[inline] + pub fn new(view: &'a MemoryView, offset: u64, len: u64) -> Result { + let total_len = len + .checked_mul(mem::size_of::() as u64) + .ok_or(MemoryAccessError::Overflow)?; + offset + .checked_add(total_len) + .ok_or(MemoryAccessError::Overflow)?; + Ok(Self { + buffer: view.buffer().0, + offset, + len, + marker: PhantomData, + }) + } + + /// Get the offset into Wasm linear memory for this `WasmSlice`. + #[inline] + pub fn offset(self) -> u64 { + self.offset + } + + /// Get a 32-bit `WasmPtr` for this `WasmRef`. + #[inline] + pub fn as_ptr32(self) -> WasmPtr { + WasmPtr::new(self.offset as u32) + } + + /// Get a 64-bit `WasmPtr` for this `WasmRef`. + #[inline] + pub fn as_ptr64(self) -> WasmPtr { + WasmPtr::new(self.offset) + } + + /// Get the number of elements in this slice. + #[inline] + pub fn len(self) -> u64 { + self.len + } + + /// Returns `true` if the number of elements is 0. + #[inline] + pub fn is_empty(self) -> bool { + self.len == 0 + } + + /// Get a `WasmRef` to an element in the slice. + #[inline] + pub fn index(self, idx: u64) -> WasmRef<'a, T> { + if idx >= self.len { + panic!("WasmSlice out of bounds"); + } + let offset = self.offset + idx * mem::size_of::() as u64; + WasmRef { + buffer: self.buffer, + offset, + marker: PhantomData, + } + } + + /// Get a `WasmSlice` for a subslice of this slice. + #[inline] + pub fn subslice(self, range: Range) -> WasmSlice<'a, T> { + if range.start > range.end || range.end > self.len { + panic!("WasmSlice out of bounds"); + } + let offset = self.offset + range.start * mem::size_of::() as u64; + Self { + buffer: self.buffer, + offset, + len: range.end - range.start, + marker: PhantomData, + } + } + + /// Get an iterator over the elements in this slice. + #[inline] + pub fn iter(self) -> WasmSliceIter<'a, T> { + WasmSliceIter { slice: self } + } + + /// Gains direct access to the memory of this slice + #[inline] + pub fn access(self) -> Result, MemoryAccessError> { + WasmSliceAccess::new(self) + } + + /// Reads an element of this slice. + #[inline] + pub fn read(self, idx: u64) -> Result { + self.index(idx).read() + } + + /// Writes to an element of this slice. + #[inline] + pub fn write(self, idx: u64, val: T) -> Result<(), MemoryAccessError> { + self.index(idx).write(val) + } + + /// Reads the entire slice into the given buffer. + /// + /// The length of the buffer must match the length of the slice. + #[inline] + pub fn read_slice(self, buf: &mut [T]) -> Result<(), MemoryAccessError> { + assert_eq!( + buf.len() as u64, + self.len, + "slice length doesn't match WasmSlice length" + ); + let bytes = unsafe { + slice::from_raw_parts_mut( + buf.as_mut_ptr() as *mut MaybeUninit, + buf.len() * mem::size_of::(), + ) + }; + self.buffer.read_uninit(self.offset, bytes)?; + Ok(()) + } + + /// Reads the entire slice into the given uninitialized buffer. + /// + /// The length of the buffer must match the length of the slice. + /// + /// This method returns an initialized view of the buffer. + #[inline] + pub fn read_slice_uninit( + self, + buf: &mut [MaybeUninit], + ) -> Result<&mut [T], MemoryAccessError> { + assert_eq!( + buf.len() as u64, + self.len, + "slice length doesn't match WasmSlice length" + ); + let bytes = unsafe { + slice::from_raw_parts_mut( + buf.as_mut_ptr() as *mut MaybeUninit, + buf.len() * mem::size_of::(), + ) + }; + self.buffer.read_uninit(self.offset, bytes)?; + Ok(unsafe { slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut T, buf.len()) }) + } + + /// Write the given slice into this `WasmSlice`. + /// + /// The length of the slice must match the length of the `WasmSlice`. + #[inline] + pub fn write_slice(self, data: &[T]) -> Result<(), MemoryAccessError> { + assert_eq!( + data.len() as u64, + self.len, + "slice length doesn't match WasmSlice length" + ); + let bytes = unsafe { + slice::from_raw_parts(data.as_ptr() as *const u8, data.len() * mem::size_of::()) + }; + self.buffer.write(self.offset, bytes) + } + + /// Reads this `WasmSlice` into a `slice`. + #[inline] + pub fn read_to_slice(self, buf: &mut [MaybeUninit]) -> Result { + let len = self.len.try_into().expect("WasmSlice length overflow"); + self.buffer.read_uninit(self.offset, buf)?; + Ok(len) + } + + /// Reads this `WasmSlice` into a `Vec`. + #[inline] + pub fn read_to_vec(self) -> Result, MemoryAccessError> { + let len = self.len.try_into().expect("WasmSlice length overflow"); + let mut vec = Vec::with_capacity(len); + let bytes = unsafe { + slice::from_raw_parts_mut( + vec.as_mut_ptr() as *mut MaybeUninit, + len * mem::size_of::(), + ) + }; + self.buffer.read_uninit(self.offset, bytes)?; + unsafe { + vec.set_len(len); + } + Ok(vec) + } + + /// Reads this `WasmSlice` into a `BytesMut` + #[inline] + pub fn read_to_bytes(self) -> Result { + let len = self.len.try_into().expect("WasmSlice length overflow"); + let mut ret = bytes::BytesMut::with_capacity(len); + let bytes = unsafe { + slice::from_raw_parts_mut( + ret.as_mut_ptr() as *mut MaybeUninit, + len * mem::size_of::(), + ) + }; + self.buffer.read_uninit(self.offset, bytes)?; + unsafe { + ret.set_len(len); + } + Ok(ret) + } +} + +impl<'a, T: ValueType> fmt::Debug for WasmSlice<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "WasmSlice(offset: {}, len: {}, pointer: {:#x})", + self.offset, self.len, self.offset + ) + } +} + +/// Iterator over the elements of a `WasmSlice`. +pub struct WasmSliceIter<'a, T: ValueType> { + slice: WasmSlice<'a, T>, +} + +impl<'a, T: ValueType> Iterator for WasmSliceIter<'a, T> { + type Item = WasmRef<'a, T>; + + fn next(&mut self) -> Option { + if !self.slice.is_empty() { + let elem = self.slice.index(0); + self.slice = self.slice.subslice(1..self.slice.len()); + Some(elem) + } else { + None + } + } + + fn size_hint(&self) -> (usize, Option) { + (0..self.slice.len()).size_hint() + } +} + +impl<'a, T: ValueType> DoubleEndedIterator for WasmSliceIter<'a, T> { + fn next_back(&mut self) -> Option { + if !self.slice.is_empty() { + let elem = self.slice.index(self.slice.len() - 1); + self.slice = self.slice.subslice(0..self.slice.len() - 1); + Some(elem) + } else { + None + } + } +} + +impl<'a, T: ValueType> ExactSizeIterator for WasmSliceIter<'a, T> {} impl<'a, T> WasmSliceAccess<'a, T> where T: wasmer_types::ValueType, { - pub(crate) fn new(slice: WasmSlice<'a, T>) -> Result { + fn new(slice: WasmSlice<'a, T>) -> Result { let total_len = slice .len .checked_mul(mem::size_of::() as u64) @@ -17,7 +420,7 @@ where .offset .checked_add(total_len) .ok_or(MemoryAccessError::Overflow)?; - if end > slice.buffer.0.len as u64 { + if end > slice.buffer.len as u64 { #[cfg(feature = "tracing")] warn!( "attempted to read ({} bytes) beyond the bounds of the memory view ({} > {})", @@ -26,7 +429,7 @@ where return Err(MemoryAccessError::HeapOutOfBounds); } let buf = unsafe { - let buf_ptr: *mut u8 = slice.buffer.0.base.add(slice.offset as usize); + let buf_ptr: *mut u8 = slice.buffer.base.add(slice.offset as usize); let buf_ptr: *mut T = std::mem::transmute(buf_ptr); std::slice::from_raw_parts_mut(buf_ptr, slice.len as usize) }; @@ -41,13 +444,13 @@ impl<'a, T> WasmRefAccess<'a, T> where T: wasmer_types::ValueType, { - pub(crate) fn new(ptr: WasmRef<'a, T>) -> Result { + fn new(ptr: WasmRef<'a, T>) -> Result { let total_len = mem::size_of::() as u64; let end = ptr .offset .checked_add(total_len) .ok_or(MemoryAccessError::Overflow)?; - if end > ptr.buffer.0.len as u64 { + if end > ptr.buffer.len as u64 { #[cfg(feature = "tracing")] warn!( "attempted to read ({} bytes) beyond the bounds of the memory view ({} > {})", @@ -56,7 +459,7 @@ where return Err(MemoryAccessError::HeapOutOfBounds); } let val = unsafe { - let val_ptr: *mut u8 = ptr.buffer.0.base.add(ptr.offset as usize); + let val_ptr: *mut u8 = ptr.buffer.base.add(ptr.offset as usize); let val_ptr: *mut T = std::mem::transmute(val_ptr); &mut *val_ptr }; diff --git a/lib/api/src/sys/mod.rs b/lib/api/src/sys/mod.rs index 9cc30a90c1b..485b87f55b6 100644 --- a/lib/api/src/sys/mod.rs +++ b/lib/api/src/sys/mod.rs @@ -2,7 +2,7 @@ pub(crate) mod engine; pub(crate) mod extern_ref; pub(crate) mod externals; pub(crate) mod instance; -mod mem_access; +pub(crate) mod mem_access; pub(crate) mod module; mod tunables; pub(crate) mod typed_function; From 0a31d66c95822e215bf98042a5c2febd36934319 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Mon, 6 Mar 2023 20:42:14 -0800 Subject: [PATCH 81/81] Make WasmRef/WasmSlice access uniform --- lib/api/src/access.rs | 24 - lib/api/src/instance.rs | 14 - lib/api/src/js/mem_access.rs | 465 ++----------------- lib/api/src/mem_access.rs | 824 +++++++++++++++++----------------- lib/api/src/sys/instance.rs | 14 + lib/api/src/sys/mem_access.rs | 451 ++----------------- 6 files changed, 500 insertions(+), 1292 deletions(-) diff --git a/lib/api/src/access.rs b/lib/api/src/access.rs index 288938c4722..e1d5cc16c95 100644 --- a/lib/api/src/access.rs +++ b/lib/api/src/access.rs @@ -167,30 +167,6 @@ where } } -impl<'a, T> WasmRefAccess<'a, T> -where - T: wasmer_types::ValueType, -{ - /// Reads the address pointed to by this `WasmPtr` in a memory. - #[inline] - #[allow(clippy::clone_on_copy)] - pub fn read(&self) -> T - where - T: Clone, - { - self.as_ref().clone() - } - - /// Writes to the address pointed to by this `WasmPtr` in a memory. - #[inline] - pub fn write(&mut self, val: T) { - // Note: Zero padding is not required here as its a typed copy which does - // not leak the bytes into the memory - // https://stackoverflow.com/questions/61114026/does-stdptrwrite-transfer-the-uninitialized-ness-of-the-bytes-it-writes - *(self.as_mut()) = val; - } -} - impl<'a, T> Drop for WasmRefAccess<'a, T> where T: wasmer_types::ValueType, diff --git a/lib/api/src/instance.rs b/lib/api/src/instance.rs index 86ab381d3d8..14a8066e0ae 100644 --- a/lib/api/src/instance.rs +++ b/lib/api/src/instance.rs @@ -27,20 +27,6 @@ pub struct Instance { pub exports: Exports, } -#[cfg(test)] -mod send_test { - use super::*; - - fn is_send() -> bool { - true - } - - #[test] - fn instance_is_send() { - assert!(is_send::()); - } -} - impl Instance { /// Creates a new `Instance` from a WebAssembly [`Module`] and a /// set of imports using [`Imports`] or the [`imports`] macro helper. diff --git a/lib/api/src/js/mem_access.rs b/lib/api/src/js/mem_access.rs index 7ceaaef0a27..f8a822d1325 100644 --- a/lib/api/src/js/mem_access.rs +++ b/lib/api/src/js/mem_access.rs @@ -1,429 +1,13 @@ -use crate::access::{RefCow, SliceCow, WasmRefAccess}; -use crate::js::externals::memory::MemoryBuffer; -use crate::WasmSliceAccess; -use crate::{Memory32, Memory64, MemoryView, RuntimeError, WasmPtr}; -use std::{ - convert::TryInto, - fmt, - marker::PhantomData, - mem::{self, MaybeUninit}, - ops::Range, - slice, - string::FromUtf8Error, -}; -use thiserror::Error; -use wasmer_types::{MemorySize, ValueType}; - -/// Error for invalid [`Memory`] access. -#[derive(Clone, Copy, Debug, Error)] -#[non_exhaustive] -pub enum MemoryAccessError { - /// Memory access is outside heap bounds. - #[error("memory access out of bounds")] - HeapOutOfBounds, - /// Address calculation overflow. - #[error("address calculation overflow")] - Overflow, - /// String is not valid UTF-8. - #[error("string is not valid utf-8")] - NonUtf8String, -} - -impl From for RuntimeError { - fn from(err: MemoryAccessError) -> Self { - RuntimeError::new(err.to_string()) - } -} -impl From for MemoryAccessError { - fn from(_err: FromUtf8Error) -> Self { - MemoryAccessError::NonUtf8String - } -} - -/// Reference to a value in Wasm memory. -/// -/// The type of the value must satisfy the requirements of the `ValueType` -/// trait which guarantees that reading and writing such a value to untrusted -/// memory is safe. -/// -/// The address is not required to be aligned: unaligned accesses are fully -/// supported. -/// -/// This wrapper safely handles concurrent modifications of the data by another -/// thread. -#[derive(Clone, Copy)] -pub struct WasmRef<'a, T: ValueType> { - buffer: MemoryBuffer<'a>, - offset: u64, - marker: PhantomData<*mut T>, -} - -impl<'a, T: ValueType> WasmRef<'a, T> { - /// Creates a new `WasmRef` at the given offset in a memory. - #[inline] - pub fn new(view: &'a MemoryView, offset: u64) -> Self { - Self { - buffer: view.buffer().0, - offset, - marker: PhantomData, - } - } - - /// Get the offset into Wasm linear memory for this `WasmRef`. - #[inline] - pub fn offset(self) -> u64 { - self.offset - } - - /// Get a `WasmPtr` for this `WasmRef`. - #[inline] - pub fn as_ptr32(self) -> WasmPtr { - WasmPtr::new(self.offset as u32) - } - - /// Get a 64-bit `WasmPtr` for this `WasmRef`. - #[inline] - pub fn as_ptr64(self) -> WasmPtr { - WasmPtr::new(self.offset) - } - - /// Get a `WasmPtr` fror this `WasmRef`. - #[inline] - pub fn as_ptr(self) -> WasmPtr { - let offset: M::Offset = self - .offset - .try_into() - .map_err(|_| "invalid offset into memory") - .unwrap(); - WasmPtr::::new(offset) - } - - /// Reads the location pointed to by this `WasmRef`. - #[inline] - pub fn read(self) -> Result { - let mut out = MaybeUninit::uninit(); - let buf = - unsafe { slice::from_raw_parts_mut(out.as_mut_ptr() as *mut u8, mem::size_of::()) }; - self.buffer.read(self.offset, buf)?; - Ok(unsafe { out.assume_init() }) - } - - /// Writes to the location pointed to by this `WasmRef`. - #[inline] - pub fn write(self, val: T) -> Result<(), MemoryAccessError> { - let mut data = MaybeUninit::new(val); - let data = unsafe { - slice::from_raw_parts_mut( - data.as_mut_ptr() as *mut MaybeUninit, - mem::size_of::(), - ) - }; - val.zero_padding_bytes(data); - let data = unsafe { slice::from_raw_parts(data.as_ptr() as *const _, data.len()) }; - self.buffer.write(self.offset, data) - } - - /// Gains direct access to the memory of this slice - #[inline] - pub fn access(self) -> Result, MemoryAccessError> { - WasmRefAccess::new(self) - } -} - -impl<'a, T: ValueType> fmt::Debug for WasmRef<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "WasmRef(offset: {}, pointer: {:#x})", - self.offset, self.offset - ) - } -} - -/// Reference to an array of values in Wasm memory. -/// -/// The type of the value must satisfy the requirements of the `ValueType` -/// trait which guarantees that reading and writing such a value to untrusted -/// memory is safe. -/// -/// The address is not required to be aligned: unaligned accesses are fully -/// supported. -/// -/// This wrapper safely handles concurrent modifications of the data by another -/// thread. -#[derive(Clone, Copy)] -pub struct WasmSlice<'a, T: ValueType> { - buffer: MemoryBuffer<'a>, - offset: u64, - len: u64, - marker: PhantomData<*mut T>, -} - -impl<'a, T: ValueType> WasmSlice<'a, T> { - /// Creates a new `WasmSlice` starting at the given offset in memory and - /// with the given number of elements. - /// - /// Returns a `MemoryAccessError` if the slice length overflows. - #[inline] - pub fn new(memory: &'a MemoryView, offset: u64, len: u64) -> Result { - let total_len = len - .checked_mul(mem::size_of::() as u64) - .ok_or(MemoryAccessError::Overflow)?; - offset - .checked_add(total_len) - .ok_or(MemoryAccessError::Overflow)?; - Ok(Self { - buffer: memory.buffer().0, - offset, - len, - marker: PhantomData, - }) - } - - /// Get the offset into Wasm linear memory for this `WasmSlice`. - #[inline] - pub fn offset(self) -> u64 { - self.offset - } - - /// Get a 32-bit `WasmPtr` for this `WasmRef`. - #[inline] - pub fn as_ptr32(self) -> WasmPtr { - WasmPtr::new(self.offset as u32) - } - - /// Get a 64-bit `WasmPtr` for this `WasmRef`. - #[inline] - pub fn as_ptr64(self) -> WasmPtr { - WasmPtr::new(self.offset) - } - - /// Get the number of elements in this slice. - #[inline] - pub fn len(self) -> u64 { - self.len - } - - /// Return if the slice is empty. - #[inline] - pub fn is_empty(&self) -> bool { - self.len == 0 - } - - /// Get a `WasmRef` to an element in the slice. - #[inline] - pub fn index(self, idx: u64) -> WasmRef<'a, T> { - if idx >= self.len { - panic!("WasmSlice out of bounds"); - } - let offset = self.offset + idx * mem::size_of::() as u64; - WasmRef { - buffer: self.buffer, - offset, - marker: PhantomData, - } - } - - /// Get a `WasmSlice` for a subslice of this slice. - #[inline] - pub fn subslice(self, range: Range) -> WasmSlice<'a, T> { - if range.start > range.end || range.end > self.len { - panic!("WasmSlice out of bounds"); - } - let offset = self.offset + range.start * mem::size_of::() as u64; - Self { - buffer: self.buffer, - offset, - len: range.end - range.start, - marker: PhantomData, - } - } - - /// Get an iterator over the elements in this slice. - #[inline] - pub fn iter(self) -> WasmSliceIter<'a, T> { - WasmSliceIter { slice: self } - } - - /// Reads an element of this slice. - #[inline] - pub fn read(self, idx: u64) -> Result { - self.index(idx).read() - } - - /// Writes to an element of this slice. - #[inline] - pub fn write(self, idx: u64, val: T) -> Result<(), MemoryAccessError> { - self.index(idx).write(val) - } - - /// Gains direct access to the memory of this slice - #[inline] - pub fn access(self) -> Result, MemoryAccessError> { - WasmSliceAccess::new(self) - } - - /// Reads the entire slice into the given buffer. - /// - /// The length of the buffer must match the length of the slice. - #[inline] - pub fn read_slice(self, buf: &mut [T]) -> Result<(), MemoryAccessError> { - assert_eq!( - buf.len() as u64, - self.len, - "slice length doesn't match WasmSlice length" - ); - let bytes = unsafe { - slice::from_raw_parts_mut( - buf.as_mut_ptr() as *mut MaybeUninit, - buf.len() * mem::size_of::(), - ) - }; - self.buffer.read_uninit(self.offset, bytes)?; - Ok(()) - } - - /// Reads the entire slice into the given uninitialized buffer. - /// - /// The length of the buffer must match the length of the slice. - /// - /// This method returns an initialized view of the buffer. - #[inline] - pub fn read_slice_uninit( - self, - buf: &mut [MaybeUninit], - ) -> Result<&mut [T], MemoryAccessError> { - assert_eq!( - buf.len() as u64, - self.len, - "slice length doesn't match WasmSlice length" - ); - let bytes = unsafe { - slice::from_raw_parts_mut( - buf.as_mut_ptr() as *mut MaybeUninit, - buf.len() * mem::size_of::(), - ) - }; - self.buffer.read_uninit(self.offset, bytes)?; - Ok(unsafe { slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut T, buf.len()) }) - } - - /// Write the given slice into this `WasmSlice`. - /// - /// The length of the slice must match the length of the `WasmSlice`. - #[inline] - pub fn write_slice(self, data: &[T]) -> Result<(), MemoryAccessError> { - assert_eq!( - data.len() as u64, - self.len, - "slice length doesn't match WasmSlice length" - ); - let bytes = unsafe { - slice::from_raw_parts(data.as_ptr() as *const u8, data.len() * mem::size_of::()) - }; - self.buffer.write(self.offset, bytes) - } - - /// Reads this `WasmSlice` into a `slice`. - #[inline] - pub fn read_to_slice<'b>( - self, - buf: &'b mut [MaybeUninit], - ) -> Result { - let len = self.len.try_into().expect("WasmSlice length overflow"); - self.buffer.read_uninit(self.offset, buf)?; - Ok(len) - } - - /// Reads this `WasmSlice` into a `Vec`. - #[inline] - pub fn read_to_vec(self) -> Result, MemoryAccessError> { - let len = self.len.try_into().expect("WasmSlice length overflow"); - let mut vec = Vec::with_capacity(len); - let bytes = unsafe { - slice::from_raw_parts_mut( - vec.as_mut_ptr() as *mut MaybeUninit, - len * mem::size_of::(), - ) - }; - self.buffer.read_uninit(self.offset, bytes)?; - unsafe { - vec.set_len(len); - } - Ok(vec) - } - - /// Reads this `WasmSlice` into a `BytesMut` - #[inline] - pub fn read_to_bytes(self) -> Result { - let len = self.len.try_into().expect("WasmSlice length overflow"); - let mut ret = bytes::BytesMut::with_capacity(len); - let bytes = unsafe { - slice::from_raw_parts_mut( - ret.as_mut_ptr() as *mut MaybeUninit, - len * mem::size_of::(), - ) - }; - self.buffer.read_uninit(self.offset, bytes)?; - unsafe { - ret.set_len(len); - } - Ok(ret) - } -} - -impl<'a, T: ValueType> fmt::Debug for WasmSlice<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "WasmSlice(offset: {}, len: {}, pointer: {:#x})", - self.offset, self.len, self.offset - ) - } -} - -/// Iterator over the elements of a `WasmSlice`. -pub struct WasmSliceIter<'a, T: ValueType> { - slice: WasmSlice<'a, T>, -} - -impl<'a, T: ValueType> Iterator for WasmSliceIter<'a, T> { - type Item = WasmRef<'a, T>; - - fn next(&mut self) -> Option { - if self.slice.len() != 0 { - let elem = self.slice.index(0); - self.slice = self.slice.subslice(1..self.slice.len()); - Some(elem) - } else { - None - } - } - - fn size_hint(&self) -> (usize, Option) { - (0..self.slice.len()).size_hint() - } -} - -impl<'a, T: ValueType> DoubleEndedIterator for WasmSliceIter<'a, T> { - fn next_back(&mut self) -> Option { - if self.slice.len() != 0 { - let elem = self.slice.index(self.slice.len() - 1); - self.slice = self.slice.subslice(0..self.slice.len() - 1); - Some(elem) - } else { - None - } - } -} - -impl<'a, T: ValueType> ExactSizeIterator for WasmSliceIter<'a, T> {} +use crate::access::{RefCow, SliceCow, WasmRefAccess, WasmSliceAccess}; +use crate::{MemoryAccessError, WasmRef, WasmSlice}; +use std::mem::{self, MaybeUninit}; +use std::slice; impl<'a, T> WasmSliceAccess<'a, T> where T: wasmer_types::ValueType, { - fn new(slice: WasmSlice<'a, T>) -> Result { + pub(crate) fn new(slice: WasmSlice<'a, T>) -> Result { let buf = slice.read_to_vec()?; Ok(Self { slice, @@ -436,11 +20,46 @@ impl<'a, T> WasmRefAccess<'a, T> where T: wasmer_types::ValueType, { - fn new(ptr: WasmRef<'a, T>) -> Result { - let val = ptr.read()?; + pub(crate) fn new(ptr: WasmRef<'a, T>) -> Result { + let mut out = MaybeUninit::uninit(); + let buf = + unsafe { slice::from_raw_parts_mut(out.as_mut_ptr() as *mut u8, mem::size_of::()) }; + ptr.buffer.read(ptr.offset, buf)?; + let val = unsafe { out.assume_init() }; + Ok(Self { ptr, buf: RefCow::Owned(val, false), }) } } + +impl<'a, T> WasmRefAccess<'a, T> +where + T: wasmer_types::ValueType, +{ + /// Reads the address pointed to by this `WasmPtr` in a memory. + #[inline] + #[allow(clippy::clone_on_copy)] + pub fn read(&self) -> T + where + T: Clone, + { + self.as_ref().clone() + } + + /// Writes to the address pointed to by this `WasmPtr` in a memory. + #[inline] + pub fn write(&mut self, val: T) { + let mut data = MaybeUninit::new(val); + let data = unsafe { + slice::from_raw_parts_mut( + data.as_mut_ptr() as *mut MaybeUninit, + mem::size_of::(), + ) + }; + val.zero_padding_bytes(data); + let data = unsafe { slice::from_raw_parts(data.as_ptr() as *const _, data.len()) }; + self.ptr.buffer.write(self.ptr.offset, data).unwrap() + } +} diff --git a/lib/api/src/mem_access.rs b/lib/api/src/mem_access.rs index 6ddc38f27ed..b5c01df8f97 100644 --- a/lib/api/src/mem_access.rs +++ b/lib/api/src/mem_access.rs @@ -1,415 +1,409 @@ -#[cfg(feature = "js")] -pub use crate::js::mem_access::{MemoryAccessError, WasmRef, WasmSlice, WasmSliceIter}; - -#[cfg(feature = "sys")] -pub use crate::sys::mem_access::{MemoryAccessError, WasmRef, WasmSlice, WasmSliceIter}; - -// use crate::access::WasmRefAccess; -// use crate::externals::memory::MemoryBuffer; -// use crate::{Memory32, Memory64, MemorySize, MemoryView, WasmPtr}; -// use crate::{RuntimeError, WasmSliceAccess}; -// use std::convert::TryInto; -// use std::fmt; -// use std::marker::PhantomData; -// use std::mem::{self, MaybeUninit}; -// use std::ops::Range; -// use std::slice; -// use std::string::FromUtf8Error; -// use thiserror::Error; -// use wasmer_types::ValueType; - -// /// Error for invalid [`Memory`] access. -// #[derive(Clone, Copy, Debug, Error)] -// #[non_exhaustive] -// pub enum MemoryAccessError { -// /// Memory access is outside heap bounds. -// #[error("memory access out of bounds")] -// HeapOutOfBounds, -// /// Address calculation overflow. -// #[error("address calculation overflow")] -// Overflow, -// /// String is not valid UTF-8. -// #[error("string is not valid utf-8")] -// NonUtf8String, -// } - -// impl From for RuntimeError { -// fn from(err: MemoryAccessError) -> Self { -// Self::new(err.to_string()) -// } -// } -// impl From for MemoryAccessError { -// fn from(_err: FromUtf8Error) -> Self { -// Self::NonUtf8String -// } -// } - -// /// Reference to a value in Wasm memory. -// /// -// /// The type of the value must satisfy the requirements of the `ValueType` -// /// trait which guarantees that reading and writing such a value to untrusted -// /// memory is safe. -// /// -// /// The address is not required to be aligned: unaligned accesses are fully -// /// supported. -// /// -// /// This wrapper safely handles concurrent modifications of the data by another -// /// thread. -// #[derive(Clone, Copy)] -// pub struct WasmRef<'a, T: ValueType> { -// #[allow(unused)] -// pub(crate) buffer: MemoryBuffer<'a>, -// pub(crate) offset: u64, -// marker: PhantomData<*mut T>, -// } - -// impl<'a, T: ValueType> WasmRef<'a, T> { -// /// Creates a new `WasmRef` at the given offset in a memory. -// #[inline] -// pub fn new(view: &'a MemoryView, offset: u64) -> Self { -// Self { -// buffer: view.buffer(), -// offset, -// marker: PhantomData, -// } -// } - -// /// Get the offset into Wasm linear memory for this `WasmRef`. -// #[inline] -// pub fn offset(self) -> u64 { -// self.offset -// } - -// /// Get a `WasmPtr` for this `WasmRef`. -// #[inline] -// pub fn as_ptr32(self) -> WasmPtr { -// WasmPtr::new(self.offset as u32) -// } - -// /// Get a 64-bit `WasmPtr` for this `WasmRef`. -// #[inline] -// pub fn as_ptr64(self) -> WasmPtr { -// WasmPtr::new(self.offset) -// } - -// /// Get a `WasmPtr` fror this `WasmRef`. -// #[inline] -// pub fn as_ptr(self) -> WasmPtr { -// let offset: M::Offset = self -// .offset -// .try_into() -// .map_err(|_| "invalid offset into memory") -// .unwrap(); -// WasmPtr::::new(offset) -// } - -// /// Reads the location pointed to by this `WasmRef`. -// #[inline] -// pub fn read(self) -> Result { -// let mut out = MaybeUninit::uninit(); -// let buf = -// unsafe { slice::from_raw_parts_mut(out.as_mut_ptr() as *mut u8, mem::size_of::()) }; -// self.buffer.read(self.offset, buf)?; -// Ok(unsafe { out.assume_init() }) -// // Ok(self.access()?.read()) -// } - -// /// Writes to the location pointed to by this `WasmRef`. -// #[inline] -// pub fn write(self, val: T) -> Result<(), MemoryAccessError> { -// self.access()?.write(val); -// Ok(()) -// } - -// /// Gains direct access to the memory of this slice -// #[inline] -// pub fn access(self) -> Result, MemoryAccessError> { -// WasmRefAccess::new(self) -// } -// } - -// impl<'a, T: ValueType> fmt::Debug for WasmRef<'a, T> { -// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { -// write!( -// f, -// "WasmRef(offset: {}, pointer: {:#x})", -// self.offset, self.offset -// ) -// } -// } - -// /// Reference to an array of values in Wasm memory. -// /// -// /// The type of the value must satisfy the requirements of the `ValueType` -// /// trait which guarantees that reading and writing such a value to untrusted -// /// memory is safe. -// /// -// /// The address is not required to be aligned: unaligned accesses are fully -// /// supported. -// /// -// /// This wrapper safely handles concurrent modifications of the data by another -// /// thread. -// #[derive(Clone, Copy)] -// pub struct WasmSlice<'a, T: ValueType> { -// pub(crate) buffer: MemoryBuffer<'a>, -// pub(crate) offset: u64, -// pub(crate) len: u64, -// marker: PhantomData<*mut T>, -// } - -// impl<'a, T: ValueType> WasmSlice<'a, T> { -// /// Creates a new `WasmSlice` starting at the given offset in memory and -// /// with the given number of elements. -// /// -// /// Returns a `MemoryAccessError` if the slice length overflows. -// #[inline] -// pub fn new(view: &'a MemoryView, offset: u64, len: u64) -> Result { -// let total_len = len -// .checked_mul(mem::size_of::() as u64) -// .ok_or(MemoryAccessError::Overflow)?; -// offset -// .checked_add(total_len) -// .ok_or(MemoryAccessError::Overflow)?; -// Ok(Self { -// buffer: view.buffer(), -// offset, -// len, -// marker: PhantomData, -// }) -// } - -// /// Get the offset into Wasm linear memory for this `WasmSlice`. -// #[inline] -// pub fn offset(self) -> u64 { -// self.offset -// } - -// /// Get a 32-bit `WasmPtr` for this `WasmRef`. -// #[inline] -// pub fn as_ptr32(self) -> WasmPtr { -// WasmPtr::new(self.offset as u32) -// } - -// /// Get a 64-bit `WasmPtr` for this `WasmRef`. -// #[inline] -// pub fn as_ptr64(self) -> WasmPtr { -// WasmPtr::new(self.offset) -// } - -// /// Get the number of elements in this slice. -// #[inline] -// pub fn len(self) -> u64 { -// self.len -// } - -// /// Returns `true` if the number of elements is 0. -// #[inline] -// pub fn is_empty(self) -> bool { -// self.len == 0 -// } - -// /// Get a `WasmRef` to an element in the slice. -// #[inline] -// pub fn index(self, idx: u64) -> WasmRef<'a, T> { -// if idx >= self.len { -// panic!("WasmSlice out of bounds"); -// } -// let offset = self.offset + idx * mem::size_of::() as u64; -// WasmRef { -// buffer: self.buffer, -// offset, -// marker: PhantomData, -// } -// } - -// /// Get a `WasmSlice` for a subslice of this slice. -// #[inline] -// pub fn subslice(self, range: Range) -> WasmSlice<'a, T> { -// if range.start > range.end || range.end > self.len { -// panic!("WasmSlice out of bounds"); -// } -// let offset = self.offset + range.start * mem::size_of::() as u64; -// Self { -// buffer: self.buffer, -// offset, -// len: range.end - range.start, -// marker: PhantomData, -// } -// } - -// /// Get an iterator over the elements in this slice. -// #[inline] -// pub fn iter(self) -> WasmSliceIter<'a, T> { -// WasmSliceIter { slice: self } -// } - -// /// Gains direct access to the memory of this slice -// #[inline] -// pub fn access(self) -> Result, MemoryAccessError> { -// WasmSliceAccess::new(self) -// } - -// /// Reads an element of this slice. -// #[inline] -// pub fn read(self, idx: u64) -> Result { -// self.index(idx).read() -// } - -// /// Writes to an element of this slice. -// #[inline] -// pub fn write(self, idx: u64, val: T) -> Result<(), MemoryAccessError> { -// self.index(idx).write(val) -// } - -// /// Reads the entire slice into the given buffer. -// /// -// /// The length of the buffer must match the length of the slice. -// #[inline] -// pub fn read_slice(self, buf: &mut [T]) -> Result<(), MemoryAccessError> { -// assert_eq!( -// buf.len() as u64, -// self.len, -// "slice length doesn't match WasmSlice length" -// ); -// let bytes = unsafe { -// slice::from_raw_parts_mut( -// buf.as_mut_ptr() as *mut MaybeUninit, -// buf.len() * mem::size_of::(), -// ) -// }; -// self.buffer.read_uninit(self.offset, bytes)?; -// Ok(()) -// } - -// /// Reads the entire slice into the given uninitialized buffer. -// /// -// /// The length of the buffer must match the length of the slice. -// /// -// /// This method returns an initialized view of the buffer. -// #[inline] -// pub fn read_slice_uninit( -// self, -// buf: &mut [MaybeUninit], -// ) -> Result<&mut [T], MemoryAccessError> { -// assert_eq!( -// buf.len() as u64, -// self.len, -// "slice length doesn't match WasmSlice length" -// ); -// let bytes = unsafe { -// slice::from_raw_parts_mut( -// buf.as_mut_ptr() as *mut MaybeUninit, -// buf.len() * mem::size_of::(), -// ) -// }; -// self.buffer.read_uninit(self.offset, bytes)?; -// Ok(unsafe { slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut T, buf.len()) }) -// } - -// /// Write the given slice into this `WasmSlice`. -// /// -// /// The length of the slice must match the length of the `WasmSlice`. -// #[inline] -// pub fn write_slice(self, data: &[T]) -> Result<(), MemoryAccessError> { -// assert_eq!( -// data.len() as u64, -// self.len, -// "slice length doesn't match WasmSlice length" -// ); -// let bytes = unsafe { -// slice::from_raw_parts(data.as_ptr() as *const u8, data.len() * mem::size_of::()) -// }; -// self.buffer.write(self.offset, bytes) -// } - -// /// Reads this `WasmSlice` into a `slice`. -// #[inline] -// pub fn read_to_slice(self, buf: &mut [MaybeUninit]) -> Result { -// let len = self.len.try_into().expect("WasmSlice length overflow"); -// self.buffer.read_uninit(self.offset, buf)?; -// Ok(len) -// } - -// /// Reads this `WasmSlice` into a `Vec`. -// #[inline] -// pub fn read_to_vec(self) -> Result, MemoryAccessError> { -// let len = self.len.try_into().expect("WasmSlice length overflow"); -// let mut vec = Vec::with_capacity(len); -// let bytes = unsafe { -// slice::from_raw_parts_mut( -// vec.as_mut_ptr() as *mut MaybeUninit, -// len * mem::size_of::(), -// ) -// }; -// self.buffer.read_uninit(self.offset, bytes)?; -// unsafe { -// vec.set_len(len); -// } -// Ok(vec) -// } - -// /// Reads this `WasmSlice` into a `BytesMut` -// #[inline] -// pub fn read_to_bytes(self) -> Result { -// let len = self.len.try_into().expect("WasmSlice length overflow"); -// let mut ret = bytes::BytesMut::with_capacity(len); -// let bytes = unsafe { -// slice::from_raw_parts_mut( -// ret.as_mut_ptr() as *mut MaybeUninit, -// len * mem::size_of::(), -// ) -// }; -// self.buffer.read_uninit(self.offset, bytes)?; -// unsafe { -// ret.set_len(len); -// } -// Ok(ret) -// } -// } - -// impl<'a, T: ValueType> fmt::Debug for WasmSlice<'a, T> { -// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { -// write!( -// f, -// "WasmSlice(offset: {}, len: {}, pointer: {:#x})", -// self.offset, self.len, self.offset -// ) -// } -// } - -// /// Iterator over the elements of a `WasmSlice`. -// pub struct WasmSliceIter<'a, T: ValueType> { -// slice: WasmSlice<'a, T>, -// } - -// impl<'a, T: ValueType> Iterator for WasmSliceIter<'a, T> { -// type Item = WasmRef<'a, T>; - -// fn next(&mut self) -> Option { -// if !self.slice.is_empty() { -// let elem = self.slice.index(0); -// self.slice = self.slice.subslice(1..self.slice.len()); -// Some(elem) -// } else { -// None -// } -// } - -// fn size_hint(&self) -> (usize, Option) { -// (0..self.slice.len()).size_hint() -// } -// } - -// impl<'a, T: ValueType> DoubleEndedIterator for WasmSliceIter<'a, T> { -// fn next_back(&mut self) -> Option { -// if !self.slice.is_empty() { -// let elem = self.slice.index(self.slice.len() - 1); -// self.slice = self.slice.subslice(0..self.slice.len() - 1); -// Some(elem) -// } else { -// None -// } -// } -// } - -// impl<'a, T: ValueType> ExactSizeIterator for WasmSliceIter<'a, T> {} +use crate::access::WasmRefAccess; +use crate::externals::memory::MemoryBuffer; +use crate::{Memory32, Memory64, MemorySize, MemoryView, WasmPtr}; +use crate::{RuntimeError, WasmSliceAccess}; +use std::convert::TryInto; +use std::fmt; +use std::marker::PhantomData; +use std::mem::{self, MaybeUninit}; +use std::ops::Range; +use std::slice; +use std::string::FromUtf8Error; +use thiserror::Error; +use wasmer_types::ValueType; + +/// Error for invalid [`Memory`] access. +#[derive(Clone, Copy, Debug, Error)] +#[non_exhaustive] +pub enum MemoryAccessError { + /// Memory access is outside heap bounds. + #[error("memory access out of bounds")] + HeapOutOfBounds, + /// Address calculation overflow. + #[error("address calculation overflow")] + Overflow, + /// String is not valid UTF-8. + #[error("string is not valid utf-8")] + NonUtf8String, +} + +impl From for RuntimeError { + fn from(err: MemoryAccessError) -> Self { + Self::new(err.to_string()) + } +} +impl From for MemoryAccessError { + fn from(_err: FromUtf8Error) -> Self { + Self::NonUtf8String + } +} + +/// Reference to a value in Wasm memory. +/// +/// The type of the value must satisfy the requirements of the `ValueType` +/// trait which guarantees that reading and writing such a value to untrusted +/// memory is safe. +/// +/// The address is not required to be aligned: unaligned accesses are fully +/// supported. +/// +/// This wrapper safely handles concurrent modifications of the data by another +/// thread. +#[derive(Clone, Copy)] +pub struct WasmRef<'a, T: ValueType> { + #[allow(unused)] + pub(crate) buffer: MemoryBuffer<'a>, + pub(crate) offset: u64, + marker: PhantomData<*mut T>, +} + +impl<'a, T: ValueType> WasmRef<'a, T> { + /// Creates a new `WasmRef` at the given offset in a memory. + #[inline] + pub fn new(view: &'a MemoryView, offset: u64) -> Self { + Self { + buffer: view.buffer(), + offset, + marker: PhantomData, + } + } + + /// Get the offset into Wasm linear memory for this `WasmRef`. + #[inline] + pub fn offset(self) -> u64 { + self.offset + } + + /// Get a `WasmPtr` for this `WasmRef`. + #[inline] + pub fn as_ptr32(self) -> WasmPtr { + WasmPtr::new(self.offset as u32) + } + + /// Get a 64-bit `WasmPtr` for this `WasmRef`. + #[inline] + pub fn as_ptr64(self) -> WasmPtr { + WasmPtr::new(self.offset) + } + + /// Get a `WasmPtr` fror this `WasmRef`. + #[inline] + pub fn as_ptr(self) -> WasmPtr { + let offset: M::Offset = self + .offset + .try_into() + .map_err(|_| "invalid offset into memory") + .unwrap(); + WasmPtr::::new(offset) + } + + /// Reads the location pointed to by this `WasmRef`. + #[inline] + pub fn read(self) -> Result { + let mut out = MaybeUninit::uninit(); + let buf = + unsafe { slice::from_raw_parts_mut(out.as_mut_ptr() as *mut u8, mem::size_of::()) }; + self.buffer.read(self.offset, buf)?; + Ok(unsafe { out.assume_init() }) + // Ok(self.access()?.read()) + } + + /// Writes to the location pointed to by this `WasmRef`. + #[inline] + pub fn write(self, val: T) -> Result<(), MemoryAccessError> { + self.access()?.write(val); + Ok(()) + } + + /// Gains direct access to the memory of this slice + #[inline] + pub fn access(self) -> Result, MemoryAccessError> { + WasmRefAccess::new(self) + } +} + +impl<'a, T: ValueType> fmt::Debug for WasmRef<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "WasmRef(offset: {}, pointer: {:#x})", + self.offset, self.offset + ) + } +} + +/// Reference to an array of values in Wasm memory. +/// +/// The type of the value must satisfy the requirements of the `ValueType` +/// trait which guarantees that reading and writing such a value to untrusted +/// memory is safe. +/// +/// The address is not required to be aligned: unaligned accesses are fully +/// supported. +/// +/// This wrapper safely handles concurrent modifications of the data by another +/// thread. +#[derive(Clone, Copy)] +pub struct WasmSlice<'a, T: ValueType> { + pub(crate) buffer: MemoryBuffer<'a>, + pub(crate) offset: u64, + pub(crate) len: u64, + marker: PhantomData<*mut T>, +} + +impl<'a, T: ValueType> WasmSlice<'a, T> { + /// Creates a new `WasmSlice` starting at the given offset in memory and + /// with the given number of elements. + /// + /// Returns a `MemoryAccessError` if the slice length overflows. + #[inline] + pub fn new(view: &'a MemoryView, offset: u64, len: u64) -> Result { + let total_len = len + .checked_mul(mem::size_of::() as u64) + .ok_or(MemoryAccessError::Overflow)?; + offset + .checked_add(total_len) + .ok_or(MemoryAccessError::Overflow)?; + Ok(Self { + buffer: view.buffer(), + offset, + len, + marker: PhantomData, + }) + } + + /// Get the offset into Wasm linear memory for this `WasmSlice`. + #[inline] + pub fn offset(self) -> u64 { + self.offset + } + + /// Get a 32-bit `WasmPtr` for this `WasmRef`. + #[inline] + pub fn as_ptr32(self) -> WasmPtr { + WasmPtr::new(self.offset as u32) + } + + /// Get a 64-bit `WasmPtr` for this `WasmRef`. + #[inline] + pub fn as_ptr64(self) -> WasmPtr { + WasmPtr::new(self.offset) + } + + /// Get the number of elements in this slice. + #[inline] + pub fn len(self) -> u64 { + self.len + } + + /// Returns `true` if the number of elements is 0. + #[inline] + pub fn is_empty(self) -> bool { + self.len == 0 + } + + /// Get a `WasmRef` to an element in the slice. + #[inline] + pub fn index(self, idx: u64) -> WasmRef<'a, T> { + if idx >= self.len { + panic!("WasmSlice out of bounds"); + } + let offset = self.offset + idx * mem::size_of::() as u64; + WasmRef { + buffer: self.buffer, + offset, + marker: PhantomData, + } + } + + /// Get a `WasmSlice` for a subslice of this slice. + #[inline] + pub fn subslice(self, range: Range) -> WasmSlice<'a, T> { + if range.start > range.end || range.end > self.len { + panic!("WasmSlice out of bounds"); + } + let offset = self.offset + range.start * mem::size_of::() as u64; + Self { + buffer: self.buffer, + offset, + len: range.end - range.start, + marker: PhantomData, + } + } + + /// Get an iterator over the elements in this slice. + #[inline] + pub fn iter(self) -> WasmSliceIter<'a, T> { + WasmSliceIter { slice: self } + } + + /// Gains direct access to the memory of this slice + #[inline] + pub fn access(self) -> Result, MemoryAccessError> { + WasmSliceAccess::new(self) + } + + /// Reads an element of this slice. + #[inline] + pub fn read(self, idx: u64) -> Result { + self.index(idx).read() + } + + /// Writes to an element of this slice. + #[inline] + pub fn write(self, idx: u64, val: T) -> Result<(), MemoryAccessError> { + self.index(idx).write(val) + } + + /// Reads the entire slice into the given buffer. + /// + /// The length of the buffer must match the length of the slice. + #[inline] + pub fn read_slice(self, buf: &mut [T]) -> Result<(), MemoryAccessError> { + assert_eq!( + buf.len() as u64, + self.len, + "slice length doesn't match WasmSlice length" + ); + let bytes = unsafe { + slice::from_raw_parts_mut( + buf.as_mut_ptr() as *mut MaybeUninit, + buf.len() * mem::size_of::(), + ) + }; + self.buffer.read_uninit(self.offset, bytes)?; + Ok(()) + } + + /// Reads the entire slice into the given uninitialized buffer. + /// + /// The length of the buffer must match the length of the slice. + /// + /// This method returns an initialized view of the buffer. + #[inline] + pub fn read_slice_uninit( + self, + buf: &mut [MaybeUninit], + ) -> Result<&mut [T], MemoryAccessError> { + assert_eq!( + buf.len() as u64, + self.len, + "slice length doesn't match WasmSlice length" + ); + let bytes = unsafe { + slice::from_raw_parts_mut( + buf.as_mut_ptr() as *mut MaybeUninit, + buf.len() * mem::size_of::(), + ) + }; + self.buffer.read_uninit(self.offset, bytes)?; + Ok(unsafe { slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut T, buf.len()) }) + } + + /// Write the given slice into this `WasmSlice`. + /// + /// The length of the slice must match the length of the `WasmSlice`. + #[inline] + pub fn write_slice(self, data: &[T]) -> Result<(), MemoryAccessError> { + assert_eq!( + data.len() as u64, + self.len, + "slice length doesn't match WasmSlice length" + ); + let bytes = unsafe { + slice::from_raw_parts(data.as_ptr() as *const u8, data.len() * mem::size_of::()) + }; + self.buffer.write(self.offset, bytes) + } + + /// Reads this `WasmSlice` into a `slice`. + #[inline] + pub fn read_to_slice(self, buf: &mut [MaybeUninit]) -> Result { + let len = self.len.try_into().expect("WasmSlice length overflow"); + self.buffer.read_uninit(self.offset, buf)?; + Ok(len) + } + + /// Reads this `WasmSlice` into a `Vec`. + #[inline] + pub fn read_to_vec(self) -> Result, MemoryAccessError> { + let len = self.len.try_into().expect("WasmSlice length overflow"); + let mut vec = Vec::with_capacity(len); + let bytes = unsafe { + slice::from_raw_parts_mut( + vec.as_mut_ptr() as *mut MaybeUninit, + len * mem::size_of::(), + ) + }; + self.buffer.read_uninit(self.offset, bytes)?; + unsafe { + vec.set_len(len); + } + Ok(vec) + } + + /// Reads this `WasmSlice` into a `BytesMut` + #[inline] + pub fn read_to_bytes(self) -> Result { + let len = self.len.try_into().expect("WasmSlice length overflow"); + let mut ret = bytes::BytesMut::with_capacity(len); + let bytes = unsafe { + slice::from_raw_parts_mut( + ret.as_mut_ptr() as *mut MaybeUninit, + len * mem::size_of::(), + ) + }; + self.buffer.read_uninit(self.offset, bytes)?; + unsafe { + ret.set_len(len); + } + Ok(ret) + } +} + +impl<'a, T: ValueType> fmt::Debug for WasmSlice<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "WasmSlice(offset: {}, len: {}, pointer: {:#x})", + self.offset, self.len, self.offset + ) + } +} + +/// Iterator over the elements of a `WasmSlice`. +pub struct WasmSliceIter<'a, T: ValueType> { + slice: WasmSlice<'a, T>, +} + +impl<'a, T: ValueType> Iterator for WasmSliceIter<'a, T> { + type Item = WasmRef<'a, T>; + + fn next(&mut self) -> Option { + if !self.slice.is_empty() { + let elem = self.slice.index(0); + self.slice = self.slice.subslice(1..self.slice.len()); + Some(elem) + } else { + None + } + } + + fn size_hint(&self) -> (usize, Option) { + (0..self.slice.len()).size_hint() + } +} + +impl<'a, T: ValueType> DoubleEndedIterator for WasmSliceIter<'a, T> { + fn next_back(&mut self) -> Option { + if !self.slice.is_empty() { + let elem = self.slice.index(self.slice.len() - 1); + self.slice = self.slice.subslice(0..self.slice.len() - 1); + Some(elem) + } else { + None + } + } +} + +impl<'a, T: ValueType> ExactSizeIterator for WasmSliceIter<'a, T> {} diff --git a/lib/api/src/sys/instance.rs b/lib/api/src/sys/instance.rs index 3a23e360368..3b8396d11b4 100644 --- a/lib/api/src/sys/instance.rs +++ b/lib/api/src/sys/instance.rs @@ -12,6 +12,20 @@ pub struct Instance { _handle: StoreHandle, } +#[cfg(test)] +mod send_test { + use super::*; + + fn is_send() -> bool { + true + } + + #[test] + fn instance_is_send() { + assert!(is_send::()); + } +} + impl From for InstantiationError { fn from(other: wasmer_compiler::InstantiationError) -> Self { match other { diff --git a/lib/api/src/sys/mem_access.rs b/lib/api/src/sys/mem_access.rs index 02c2d931843..ad045eedc5d 100644 --- a/lib/api/src/sys/mem_access.rs +++ b/lib/api/src/sys/mem_access.rs @@ -1,417 +1,12 @@ -use crate::sys::externals::memory::MemoryBuffer; -use crate::{ - access::{RefCow, SliceCow, WasmRefAccess}, - RuntimeError, WasmSliceAccess, -}; -#[allow(unused_imports)] -use crate::{Memory, Memory32, Memory64, MemorySize, MemoryView, WasmPtr}; -use std::{ - convert::TryInto, - fmt, - marker::PhantomData, - mem::{self, MaybeUninit}, - ops::Range, - slice, - string::FromUtf8Error, -}; -use thiserror::Error; -use wasmer_types::ValueType; - -/// Error for invalid [`Memory`] access. -#[derive(Clone, Copy, Debug, Error)] -#[non_exhaustive] -pub enum MemoryAccessError { - /// Memory access is outside heap bounds. - #[error("memory access out of bounds")] - HeapOutOfBounds, - /// Address calculation overflow. - #[error("address calculation overflow")] - Overflow, - /// String is not valid UTF-8. - #[error("string is not valid utf-8")] - NonUtf8String, -} - -impl From for RuntimeError { - fn from(err: MemoryAccessError) -> Self { - Self::new(err.to_string()) - } -} -impl From for MemoryAccessError { - fn from(_err: FromUtf8Error) -> Self { - Self::NonUtf8String - } -} - -/// Reference to a value in Wasm memory. -/// -/// The type of the value must satisfy the requirements of the `ValueType` -/// trait which guarantees that reading and writing such a value to untrusted -/// memory is safe. -/// -/// The address is not required to be aligned: unaligned accesses are fully -/// supported. -/// -/// This wrapper safely handles concurrent modifications of the data by another -/// thread. -#[derive(Clone, Copy)] -pub struct WasmRef<'a, T: ValueType> { - buffer: MemoryBuffer<'a>, - offset: u64, - marker: PhantomData<*mut T>, -} - -impl<'a, T: ValueType> WasmRef<'a, T> { - /// Creates a new `WasmRef` at the given offset in a memory. - #[inline] - pub fn new(view: &'a MemoryView, offset: u64) -> Self { - Self { - buffer: view.buffer().0, - offset, - marker: PhantomData, - } - } - - /// Get the offset into Wasm linear memory for this `WasmRef`. - #[inline] - pub fn offset(self) -> u64 { - self.offset - } - - /// Get a `WasmPtr` for this `WasmRef`. - #[inline] - pub fn as_ptr32(self) -> WasmPtr { - WasmPtr::new(self.offset as u32) - } - - /// Get a 64-bit `WasmPtr` for this `WasmRef`. - #[inline] - pub fn as_ptr64(self) -> WasmPtr { - WasmPtr::new(self.offset) - } - - /// Get a `WasmPtr` fror this `WasmRef`. - #[inline] - pub fn as_ptr(self) -> WasmPtr { - let offset: M::Offset = self - .offset - .try_into() - .map_err(|_| "invalid offset into memory") - .unwrap(); - WasmPtr::::new(offset) - } - - /// Reads the location pointed to by this `WasmRef`. - #[inline] - pub fn read(self) -> Result { - Ok(self.access()?.read()) - } - - /// Writes to the location pointed to by this `WasmRef`. - #[inline] - pub fn write(self, val: T) -> Result<(), MemoryAccessError> { - self.access()?.write(val); - Ok(()) - } - - /// Gains direct access to the memory of this slice - #[inline] - pub fn access(self) -> Result, MemoryAccessError> { - WasmRefAccess::new(self) - } -} - -impl<'a, T: ValueType> fmt::Debug for WasmRef<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "WasmRef(offset: {}, pointer: {:#x})", - self.offset, self.offset - ) - } -} - -/// Reference to an array of values in Wasm memory. -/// -/// The type of the value must satisfy the requirements of the `ValueType` -/// trait which guarantees that reading and writing such a value to untrusted -/// memory is safe. -/// -/// The address is not required to be aligned: unaligned accesses are fully -/// supported. -/// -/// This wrapper safely handles concurrent modifications of the data by another -/// thread. -#[derive(Clone, Copy)] -pub struct WasmSlice<'a, T: ValueType> { - buffer: MemoryBuffer<'a>, - offset: u64, - len: u64, - marker: PhantomData<*mut T>, -} - -impl<'a, T: ValueType> WasmSlice<'a, T> { - /// Creates a new `WasmSlice` starting at the given offset in memory and - /// with the given number of elements. - /// - /// Returns a `MemoryAccessError` if the slice length overflows. - #[inline] - pub fn new(view: &'a MemoryView, offset: u64, len: u64) -> Result { - let total_len = len - .checked_mul(mem::size_of::() as u64) - .ok_or(MemoryAccessError::Overflow)?; - offset - .checked_add(total_len) - .ok_or(MemoryAccessError::Overflow)?; - Ok(Self { - buffer: view.buffer().0, - offset, - len, - marker: PhantomData, - }) - } - - /// Get the offset into Wasm linear memory for this `WasmSlice`. - #[inline] - pub fn offset(self) -> u64 { - self.offset - } - - /// Get a 32-bit `WasmPtr` for this `WasmRef`. - #[inline] - pub fn as_ptr32(self) -> WasmPtr { - WasmPtr::new(self.offset as u32) - } - - /// Get a 64-bit `WasmPtr` for this `WasmRef`. - #[inline] - pub fn as_ptr64(self) -> WasmPtr { - WasmPtr::new(self.offset) - } - - /// Get the number of elements in this slice. - #[inline] - pub fn len(self) -> u64 { - self.len - } - - /// Returns `true` if the number of elements is 0. - #[inline] - pub fn is_empty(self) -> bool { - self.len == 0 - } - - /// Get a `WasmRef` to an element in the slice. - #[inline] - pub fn index(self, idx: u64) -> WasmRef<'a, T> { - if idx >= self.len { - panic!("WasmSlice out of bounds"); - } - let offset = self.offset + idx * mem::size_of::() as u64; - WasmRef { - buffer: self.buffer, - offset, - marker: PhantomData, - } - } - - /// Get a `WasmSlice` for a subslice of this slice. - #[inline] - pub fn subslice(self, range: Range) -> WasmSlice<'a, T> { - if range.start > range.end || range.end > self.len { - panic!("WasmSlice out of bounds"); - } - let offset = self.offset + range.start * mem::size_of::() as u64; - Self { - buffer: self.buffer, - offset, - len: range.end - range.start, - marker: PhantomData, - } - } - - /// Get an iterator over the elements in this slice. - #[inline] - pub fn iter(self) -> WasmSliceIter<'a, T> { - WasmSliceIter { slice: self } - } - - /// Gains direct access to the memory of this slice - #[inline] - pub fn access(self) -> Result, MemoryAccessError> { - WasmSliceAccess::new(self) - } - - /// Reads an element of this slice. - #[inline] - pub fn read(self, idx: u64) -> Result { - self.index(idx).read() - } - - /// Writes to an element of this slice. - #[inline] - pub fn write(self, idx: u64, val: T) -> Result<(), MemoryAccessError> { - self.index(idx).write(val) - } - - /// Reads the entire slice into the given buffer. - /// - /// The length of the buffer must match the length of the slice. - #[inline] - pub fn read_slice(self, buf: &mut [T]) -> Result<(), MemoryAccessError> { - assert_eq!( - buf.len() as u64, - self.len, - "slice length doesn't match WasmSlice length" - ); - let bytes = unsafe { - slice::from_raw_parts_mut( - buf.as_mut_ptr() as *mut MaybeUninit, - buf.len() * mem::size_of::(), - ) - }; - self.buffer.read_uninit(self.offset, bytes)?; - Ok(()) - } - - /// Reads the entire slice into the given uninitialized buffer. - /// - /// The length of the buffer must match the length of the slice. - /// - /// This method returns an initialized view of the buffer. - #[inline] - pub fn read_slice_uninit( - self, - buf: &mut [MaybeUninit], - ) -> Result<&mut [T], MemoryAccessError> { - assert_eq!( - buf.len() as u64, - self.len, - "slice length doesn't match WasmSlice length" - ); - let bytes = unsafe { - slice::from_raw_parts_mut( - buf.as_mut_ptr() as *mut MaybeUninit, - buf.len() * mem::size_of::(), - ) - }; - self.buffer.read_uninit(self.offset, bytes)?; - Ok(unsafe { slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut T, buf.len()) }) - } - - /// Write the given slice into this `WasmSlice`. - /// - /// The length of the slice must match the length of the `WasmSlice`. - #[inline] - pub fn write_slice(self, data: &[T]) -> Result<(), MemoryAccessError> { - assert_eq!( - data.len() as u64, - self.len, - "slice length doesn't match WasmSlice length" - ); - let bytes = unsafe { - slice::from_raw_parts(data.as_ptr() as *const u8, data.len() * mem::size_of::()) - }; - self.buffer.write(self.offset, bytes) - } - - /// Reads this `WasmSlice` into a `slice`. - #[inline] - pub fn read_to_slice(self, buf: &mut [MaybeUninit]) -> Result { - let len = self.len.try_into().expect("WasmSlice length overflow"); - self.buffer.read_uninit(self.offset, buf)?; - Ok(len) - } - - /// Reads this `WasmSlice` into a `Vec`. - #[inline] - pub fn read_to_vec(self) -> Result, MemoryAccessError> { - let len = self.len.try_into().expect("WasmSlice length overflow"); - let mut vec = Vec::with_capacity(len); - let bytes = unsafe { - slice::from_raw_parts_mut( - vec.as_mut_ptr() as *mut MaybeUninit, - len * mem::size_of::(), - ) - }; - self.buffer.read_uninit(self.offset, bytes)?; - unsafe { - vec.set_len(len); - } - Ok(vec) - } - - /// Reads this `WasmSlice` into a `BytesMut` - #[inline] - pub fn read_to_bytes(self) -> Result { - let len = self.len.try_into().expect("WasmSlice length overflow"); - let mut ret = bytes::BytesMut::with_capacity(len); - let bytes = unsafe { - slice::from_raw_parts_mut( - ret.as_mut_ptr() as *mut MaybeUninit, - len * mem::size_of::(), - ) - }; - self.buffer.read_uninit(self.offset, bytes)?; - unsafe { - ret.set_len(len); - } - Ok(ret) - } -} - -impl<'a, T: ValueType> fmt::Debug for WasmSlice<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "WasmSlice(offset: {}, len: {}, pointer: {:#x})", - self.offset, self.len, self.offset - ) - } -} - -/// Iterator over the elements of a `WasmSlice`. -pub struct WasmSliceIter<'a, T: ValueType> { - slice: WasmSlice<'a, T>, -} - -impl<'a, T: ValueType> Iterator for WasmSliceIter<'a, T> { - type Item = WasmRef<'a, T>; - - fn next(&mut self) -> Option { - if !self.slice.is_empty() { - let elem = self.slice.index(0); - self.slice = self.slice.subslice(1..self.slice.len()); - Some(elem) - } else { - None - } - } - - fn size_hint(&self) -> (usize, Option) { - (0..self.slice.len()).size_hint() - } -} - -impl<'a, T: ValueType> DoubleEndedIterator for WasmSliceIter<'a, T> { - fn next_back(&mut self) -> Option { - if !self.slice.is_empty() { - let elem = self.slice.index(self.slice.len() - 1); - self.slice = self.slice.subslice(0..self.slice.len() - 1); - Some(elem) - } else { - None - } - } -} - -impl<'a, T: ValueType> ExactSizeIterator for WasmSliceIter<'a, T> {} +use crate::access::{RefCow, SliceCow, WasmRefAccess, WasmSliceAccess}; +use crate::{MemoryAccessError, WasmRef, WasmSlice}; +use std::mem; impl<'a, T> WasmSliceAccess<'a, T> where T: wasmer_types::ValueType, { - fn new(slice: WasmSlice<'a, T>) -> Result { + pub(crate) fn new(slice: WasmSlice<'a, T>) -> Result { let total_len = slice .len .checked_mul(mem::size_of::() as u64) @@ -420,16 +15,16 @@ where .offset .checked_add(total_len) .ok_or(MemoryAccessError::Overflow)?; - if end > slice.buffer.len as u64 { + if end > slice.buffer.0.len as u64 { #[cfg(feature = "tracing")] warn!( "attempted to read ({} bytes) beyond the bounds of the memory view ({} > {})", - total_len, end, slice.buffer.len + total_len, end, slice.buffer.0.len ); return Err(MemoryAccessError::HeapOutOfBounds); } let buf = unsafe { - let buf_ptr: *mut u8 = slice.buffer.base.add(slice.offset as usize); + let buf_ptr: *mut u8 = slice.buffer.0.base.add(slice.offset as usize); let buf_ptr: *mut T = std::mem::transmute(buf_ptr); std::slice::from_raw_parts_mut(buf_ptr, slice.len as usize) }; @@ -444,22 +39,22 @@ impl<'a, T> WasmRefAccess<'a, T> where T: wasmer_types::ValueType, { - fn new(ptr: WasmRef<'a, T>) -> Result { + pub(crate) fn new(ptr: WasmRef<'a, T>) -> Result { let total_len = mem::size_of::() as u64; let end = ptr .offset .checked_add(total_len) .ok_or(MemoryAccessError::Overflow)?; - if end > ptr.buffer.len as u64 { + if end > ptr.buffer.0.len as u64 { #[cfg(feature = "tracing")] warn!( "attempted to read ({} bytes) beyond the bounds of the memory view ({} > {})", - total_len, end, ptr.buffer.len + total_len, end, ptr.buffer.0.len ); return Err(MemoryAccessError::HeapOutOfBounds); } let val = unsafe { - let val_ptr: *mut u8 = ptr.buffer.base.add(ptr.offset as usize); + let val_ptr: *mut u8 = ptr.buffer.0.base.add(ptr.offset as usize); let val_ptr: *mut T = std::mem::transmute(val_ptr); &mut *val_ptr }; @@ -469,3 +64,27 @@ where }) } } + +impl<'a, T> WasmRefAccess<'a, T> +where + T: wasmer_types::ValueType, +{ + /// Reads the address pointed to by this `WasmPtr` in a memory. + #[inline] + #[allow(clippy::clone_on_copy)] + pub fn read(&self) -> T + where + T: Clone, + { + self.as_ref().clone() + } + + /// Writes to the address pointed to by this `WasmPtr` in a memory. + #[inline] + pub fn write(&mut self, val: T) { + // Note: Zero padding is not required here as its a typed copy which does + // not leak the bytes into the memory + // https://stackoverflow.com/questions/61114026/does-stdptrwrite-transfer-the-uninitialized-ness-of-the-bytes-it-writes + *(self.as_mut()) = val; + } +}