diff --git a/CHANGELOG.md b/CHANGELOG.md index a95eed1368b..c2e7526f7da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ Looking for changes that affect our C API? See the [C API Changelog](lib/c-api/C ### Changed - #[3131](https://github.com/wasmerio/wasmer/pull/3131) Update migration docs for MemoryView changes +- #[3129](https://github.com/wasmerio/wasmer/pull/3129) Fix differences between -sys and -js API ### Fixed - #[3130](https://github.com/wasmerio/wasmer/pull/3130) Remove panics from Artifact::deserialize diff --git a/lib/api/src/js/error.rs b/lib/api/src/js/error.rs index f334b4a1cec..23df188dcc5 100644 --- a/lib/api/src/js/error.rs +++ b/lib/api/src/js/error.rs @@ -4,6 +4,7 @@ use crate::js::trap::RuntimeError; use std::borrow::Cow; #[cfg(feature = "std")] use thiserror::Error; +use wasmer_types::ImportError; // Compilation Errors // @@ -144,6 +145,28 @@ pub enum DeserializeError { Compiler(CompileError), } +/// The WebAssembly.LinkError object indicates an error during +/// module instantiation (besides traps from the start function). +/// +/// This is based on the [link error][link-error] API. +/// +/// [link-error]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/LinkError +#[derive(Error, Debug)] +#[error("Link error: {0}")] +pub enum LinkError { + /// An error occurred when checking the import types. + #[error("Error while importing {0:?}.{1:?}: {2}")] + Import(String, String, ImportError), + + #[cfg(not(target_arch = "wasm32"))] + /// A trap ocurred during linking. + #[error("RuntimeError occurred during linking: {0}")] + Trap(#[source] RuntimeError), + /// Insufficient resources available for linking. + #[error("Insufficient resources: {0}")] + Resource(String), +} + /// An error while instantiating a module. /// /// This is not a common WebAssembly error, however @@ -156,13 +179,18 @@ pub enum DeserializeError { #[cfg_attr(feature = "std", derive(Error))] pub enum InstantiationError { /// A linking ocurred during instantiation. - #[cfg_attr(feature = "std", error("Link error: {0}"))] - Link(String), + #[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"))] @@ -171,6 +199,10 @@ pub enum InstantiationError { /// 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 { diff --git a/lib/api/src/js/externals/function.rs b/lib/api/src/js/externals/function.rs index a74a3fa22e0..5e1d169eab4 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::js::exports::{ExportError, Exportable}; -use crate::js::externals::Extern; +use crate::js::externals::{Extern, VMExtern}; use crate::js::function_env::FunctionEnvMut; use crate::js::store::{AsStoreMut, AsStoreRef, InternalStoreHandle, StoreHandle, StoreMut}; use crate::js::types::{param_from_js, AsJs}; /* ValFuncRef */ @@ -26,6 +26,7 @@ fn result_to_js(val: &Value) -> JsValue { Value::I64(i) => JsValue::from_f64(*i as _), Value::F32(f) => JsValue::from_f64(*f as _), Value::F64(f) => JsValue::from_f64(*f), + Value::V128(f) => JsValue::from_f64(*f as _), val => unimplemented!( "The value `{:?}` is not yet supported in the JS Function API", val @@ -77,6 +78,11 @@ impl Function { Self::new_with_env(store, &env, ty, wrapped_func) } + /// To `VMExtern`. + pub fn to_vm_extern(&self) -> VMExtern { + VMExtern::Function(self.handle.internal_handle()) + } + /// Creates a new host `Function` (dynamic) with the provided signature. /// /// If you know the signature of the host function at compile time, @@ -229,13 +235,13 @@ impl Function { 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( + pub fn new_native_with_env( store: &mut impl AsStoreMut, env: &FunctionEnv, func: F, ) -> Self where - F: HostFunction, + F: HostFunction + 'static + Send + Sync, Args: WasmTypeList, Rets: WasmTypeList, { @@ -309,8 +315,8 @@ impl Function { /// assert_eq!(f.ty().params(), vec![Type::I32, Type::I32]); /// assert_eq!(f.ty().results(), vec![Type::I32]); /// ``` - pub fn ty<'context>(&self, store: &'context impl AsStoreRef) -> &'context FunctionType { - &self.handle.get(store.as_store_ref().objects()).ty + pub fn ty(&self, store: &impl AsStoreRef) -> FunctionType { + self.handle.get(store.as_store_ref().objects()).ty.clone() } /// Returns the number of parameters that this function takes. @@ -598,7 +604,7 @@ mod inner { use super::RuntimeError; use super::VMFunctionBody; use crate::js::function_env::{FunctionEnvMut, VMFunctionEnvironment}; - use crate::js::store::{AsStoreMut, InternalStoreHandle, StoreHandle, StoreMut}; + use crate::js::store::{AsStoreMut, AsStoreRef, InternalStoreHandle, StoreHandle, StoreMut}; use crate::js::FunctionEnv; use crate::js::NativeWasmTypeInto; use std::array::TryFromSliceError; @@ -639,6 +645,9 @@ mod inner { /// 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 { @@ -657,6 +666,11 @@ mod inner { 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 + } } )* }; @@ -678,6 +692,11 @@ mod inner { 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 + } } )* }; @@ -887,11 +906,12 @@ mod inner { Args: WasmTypeList, Rets: WasmTypeList, Kind: HostFunctionKind, - T: Sized, - Self: Sized, { /// Get the pointer to the function body. - fn function_body_ptr(self) -> *const VMFunctionBody; + 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 @@ -1102,7 +1122,7 @@ mod inner { Func: Fn(FunctionEnvMut<'_, T>, $( $x , )*) -> RetsAsResult + 'static, { #[allow(non_snake_case)] - fn function_body_ptr(self) -> *const VMFunctionBody { + fn function_body_ptr(&self) -> *const VMFunctionBody { /// This is a function that wraps the real host /// function. Its address will be used inside the /// runtime. @@ -1150,7 +1170,7 @@ mod inner { Func: Fn($( $x , )*) -> RetsAsResult + 'static, { #[allow(non_snake_case)] - fn function_body_ptr(self) -> *const VMFunctionBody { + fn function_body_ptr(&self) -> *const VMFunctionBody { /// This is a function that wraps the real host /// function. Its address will be used inside the /// runtime. diff --git a/lib/api/src/js/externals/global.rs b/lib/api/src/js/externals/global.rs index 35e2fa46438..69b9b9595b8 100644 --- a/lib/api/src/js/externals/global.rs +++ b/lib/api/src/js/externals/global.rs @@ -1,6 +1,6 @@ use crate::js::export::VMGlobal; use crate::js::exports::{ExportError, Exportable}; -use crate::js::externals::Extern; +use crate::js::externals::{Extern, VMExtern}; use crate::js::store::{AsStoreMut, AsStoreRef, InternalStoreHandle, StoreHandle}; use crate::js::value::Value; use crate::js::wasm_bindgen_polyfill::Global as JSGlobal; @@ -55,6 +55,11 @@ impl Global { Self::from_value(store, val, Mutability::Var).unwrap() } + /// To `VMExtern`. + pub(crate) fn to_vm_extern(&self) -> VMExtern { + VMExtern::Global(self.handle.internal_handle()) + } + /// Create a `Global` with the initial value [`Value`] and the provided [`Mutability`]. fn from_value( store: &mut impl AsStoreMut, @@ -135,15 +140,6 @@ impl Global { let ty = self.handle.get(store.as_store_ref().objects()).ty; Value::from_raw(store, ty.ty, raw) } - /* - match self.vm_global.ty.ty { - ValType::I32 => Value::I32(self.vm_global.global.value().as_f64().unwrap() as _), - ValType::I64 => Value::I64(self.vm_global.global.value().as_f64().unwrap() as _), - ValType::F32 => Value::F32(self.vm_global.global.value().as_f64().unwrap() as _), - ValType::F64 => Value::F64(self.vm_global.global.value().as_f64().unwrap()), - _ => unimplemented!("The type is not yet supported in the JS Global API"), - } - */ } /// Sets a custom value [`Value`] to the runtime Global. diff --git a/lib/api/src/js/externals/memory.rs b/lib/api/src/js/externals/memory.rs index 015769b896e..b57639b4897 100644 --- a/lib/api/src/js/externals/memory.rs +++ b/lib/api/src/js/externals/memory.rs @@ -1,6 +1,6 @@ use crate::js::export::VMMemory; use crate::js::exports::{ExportError, Exportable}; -use crate::js::externals::Extern; +use crate::js::externals::{Extern, VMExtern}; use crate::js::store::{AsStoreMut, AsStoreRef, InternalStoreHandle, StoreHandle, StoreObjects}; use crate::js::{MemoryAccessError, MemoryType}; use std::marker::PhantomData; @@ -118,6 +118,11 @@ impl Memory { Self::from_vm_extern(new_store, handle.internal_handle()) } + /// To `VMExtern`. + pub(crate) fn to_vm_extern(&self) -> VMExtern { + VMExtern::Memory(self.handle.internal_handle()) + } + /// Returns the [`MemoryType`] of the `Memory`. /// /// # Example @@ -218,6 +223,12 @@ impl Memory { } } +impl std::cmp::PartialEq for Memory { + fn eq(&self, other: &Self) -> bool { + self.handle == other.handle + } +} + impl<'a> Exportable<'a> for Memory { fn get_self_from_extern(_extern: &'a Extern) -> Result<&'a Self, ExportError> { match _extern { diff --git a/lib/api/src/js/externals/mod.rs b/lib/api/src/js/externals/mod.rs index 2748e08b124..60ed02f1879 100644 --- a/lib/api/src/js/externals/mod.rs +++ b/lib/api/src/js/externals/mod.rs @@ -10,13 +10,122 @@ pub use self::memory::{Memory, MemoryError}; pub use self::memory_view::MemoryView; pub use self::table::Table; -use crate::js::export::Export; +use crate::js::export::{Export, VMFunction, VMGlobal, VMMemory, VMTable}; use crate::js::exports::{ExportError, Exportable}; use crate::js::store::StoreObject; -use crate::js::store::{AsStoreMut, AsStoreRef}; use crate::js::types::AsJs; + +/* + + +use crate::js::store::InternalStoreHandle; +use crate::js::store::{AsStoreMut, AsStoreRef}; use crate::js::ExternType; use std::fmt; +*/ +use crate::js::error::WasmError; +use crate::js::store::{AsStoreMut, AsStoreRef, InternalStoreHandle}; +use crate::js::wasm_bindgen_polyfill::Global as JsGlobal; +use js_sys::Function as JsFunction; +use js_sys::WebAssembly::{Memory as JsMemory, Table as JsTable}; +use std::fmt; +use wasm_bindgen::{JsCast, JsValue}; +use wasmer_types::{ExternType, FunctionType, GlobalType, MemoryType, TableType}; + +/// The value of an export passed from one instance to another. +pub enum VMExtern { + /// A function export value. + Function(InternalStoreHandle), + + /// A table export value. + Table(InternalStoreHandle), + + /// A memory export value. + Memory(InternalStoreHandle), + + /// A global export value. + Global(InternalStoreHandle), +} + +impl VMExtern { + /// Return the export as a `JSValue`. + pub fn as_jsvalue<'context>(&self, store: &'context impl AsStoreRef) -> &'context JsValue { + match self { + Self::Memory(js_wasm_memory) => js_wasm_memory + .get(store.as_store_ref().objects()) + .memory + .as_ref(), + Self::Function(js_func) => js_func + .get(store.as_store_ref().objects()) + .function + .as_ref(), + Self::Table(js_wasm_table) => js_wasm_table + .get(store.as_store_ref().objects()) + .table + .as_ref(), + Self::Global(js_wasm_global) => js_wasm_global + .get(store.as_store_ref().objects()) + .global + .as_ref(), + } + } + + /// 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(InternalStoreHandle::new( + &mut store.objects_mut(), + 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(InternalStoreHandle::new( + &mut store.objects_mut(), + 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(InternalStoreHandle::new( + &mut store.objects_mut(), + 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(InternalStoreHandle::new( + &mut store.objects_mut(), + VMTable::new(val.unchecked_into::(), table_type), + ))) + } else { + panic!("Extern type doesn't match js value type"); + } + } + } + } +} /// An `Extern` is the runtime representation of an entity that /// can be imported or exported. @@ -45,13 +154,23 @@ impl Extern { } } - /// Create an `Extern` from an `wasmer_compiler::Export`. - pub fn from_vm_extern(store: &mut impl AsStoreMut, export: Export) -> Self { - match export { - Export::Function(f) => Self::Function(Function::from_vm_extern(store, f)), - Export::Memory(m) => Self::Memory(Memory::from_vm_extern(store, m)), - Export::Global(g) => Self::Global(Global::from_vm_extern(store, g)), - Export::Table(t) => Self::Table(Table::from_vm_extern(store, t)), + /// 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(), } } diff --git a/lib/api/src/js/externals/table.rs b/lib/api/src/js/externals/table.rs index 3cd9882fed6..e81400bb60d 100644 --- a/lib/api/src/js/externals/table.rs +++ b/lib/api/src/js/externals/table.rs @@ -1,6 +1,6 @@ use crate::js::export::{VMFunction, VMTable}; use crate::js::exports::{ExportError, Exportable}; -use crate::js::externals::Extern; +use crate::js::externals::{Extern, VMExtern}; use crate::js::store::{AsStoreMut, AsStoreRef, InternalStoreHandle, StoreHandle}; use crate::js::value::Value; use crate::js::RuntimeError; @@ -75,6 +75,11 @@ impl Table { }) } + /// To `VMExtern`. + pub fn to_vm_extern(&self) -> VMExtern { + VMExtern::Table(self.handle.internal_handle()) + } + /// Returns the [`TableType`] of the `Table`. pub fn ty(&self, store: &impl AsStoreRef) -> TableType { self.handle.get(store.as_store_ref().objects()).ty @@ -143,6 +148,7 @@ impl Table { /// 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, diff --git a/lib/api/src/js/imports.rs b/lib/api/src/js/imports.rs index 193838e9670..a668b96d5fd 100644 --- a/lib/api/src/js/imports.rs +++ b/lib/api/src/js/imports.rs @@ -1,7 +1,7 @@ //! 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::js::error::{InstantiationError, WasmError}; +use crate::js::error::{InstantiationError, LinkError, WasmError}; use crate::js::export::Export; use crate::js::exports::Exports; use crate::js::module::Module; @@ -11,6 +11,7 @@ use crate::js::ExternType; use crate::Extern; use std::collections::HashMap; use std::fmt; +use wasmer_types::ImportError; /// All of the import data used when instantiating. /// @@ -132,7 +133,7 @@ impl Imports { /// 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) -> Result, InstantiationError> { + pub fn imports_for_module(&self, module: &Module) -> Result, LinkError> { let mut ret = vec![]; for import in module.imports() { if let Some(imp) = self @@ -141,12 +142,11 @@ impl Imports { { ret.push(imp.clone()); } else { - return Err(InstantiationError::Link(format!( - "Error while importing {0:?}.{1:?}: unknown import. Expected {2:?}", - import.module(), - import.name(), - import.ty() - ))); + return Err(LinkError::Import( + import.module().to_string(), + import.name().to_string(), + ImportError::UnknownImport(import.ty().clone()), + )); } } Ok(ret) @@ -195,6 +195,7 @@ impl Imports { module: &Module, object: js_sys::Object, ) -> Result { + use crate::js::externals::VMExtern; let module_imports: HashMap<(String, String), ExternType> = module .imports() .map(|import| { @@ -217,7 +218,7 @@ impl 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 = Export::from_js_value(import_js, store, extern_type.clone())?; + let export = VMExtern::from_js_value(import_js, store, extern_type.clone())?; let extern_ = Extern::from_vm_extern(store, export); map.insert(key, extern_); } diff --git a/lib/api/src/js/instance.rs b/lib/api/src/js/instance.rs index fe914626fa0..5e1ddbf2e45 100644 --- a/lib/api/src/js/instance.rs +++ b/lib/api/src/js/instance.rs @@ -72,6 +72,28 @@ impl Instance { Ok(self_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( + store: &mut impl AsStoreMut, + module: &Module, + externs: &[Extern], + ) -> Result { + 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()); + } + Self::new(store, module, &imports) + } + /// Creates a Wasmer `Instance` from a Wasmer `Module` and a WebAssembly Instance /// /// # Important @@ -86,21 +108,17 @@ impl Instance { module: &Module, instance: WebAssembly::Instance, ) -> Result { + use crate::js::externals::VMExtern; let instance_exports = instance.exports(); let exports = module .exports() .map(|export_type| { let name = export_type.name(); let extern_type = export_type.ty().clone(); - let js_export = - js_sys::Reflect::get(&instance_exports, &name.into()).map_err(|_e| { - InstantiationError::Link(format!( - "Can't get {} from the instance exports", - &name - )) - })?; - let export: Export = - Export::from_js_value(js_export, &mut store, extern_type)?.into(); + let js_export = 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_)) }) diff --git a/lib/api/src/js/mem_access.rs b/lib/api/src/js/mem_access.rs index 1e697d4cbfb..ac0a543436f 100644 --- a/lib/api/src/js/mem_access.rs +++ b/lib/api/src/js/mem_access.rs @@ -197,6 +197,12 @@ impl<'a, T: ValueType> WasmSlice<'a, T> { 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> { diff --git a/lib/api/src/js/mod.rs b/lib/api/src/js/mod.rs index a642e14b5b9..a3c55228557 100644 --- a/lib/api/src/js/mod.rs +++ b/lib/api/src/js/mod.rs @@ -86,6 +86,9 @@ pub use wasmer_types::{ #[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/js/module.rs b/lib/api/src/js/module.rs index dc3df907562..8170bb14526 100644 --- a/lib/api/src/js/module.rs +++ b/lib/api/src/js/module.rs @@ -281,6 +281,32 @@ impl Module { Self::new(_store, bytes).map_err(|e| DeserializeError::Compiler(e)) } + #[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, + path: impl AsRef, + ) -> Result { + let artifact = std::fs::read(path.as_ref())?; + Ok(Self::new(store, bytes).map_err(|e| DeserializeError::Compiler(e))) + } + /// Sets the name of the current module. /// This is normally useful for stacktraces and debugging. /// @@ -488,16 +514,26 @@ 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 { - // unimplemented!(); - // } + /// 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 { + // TODO: implement on JavaScript + DefaultCustomSectionsIterator {} + } +} + +pub struct DefaultCustomSectionsIterator {} + +impl Iterator for DefaultCustomSectionsIterator { + type Item = Box<[u8]>; + fn next(&mut self) -> Option { + None + } } impl fmt::Debug for Module { diff --git a/lib/api/src/js/native_type.rs b/lib/api/src/js/native_type.rs index 814abf4c1fb..a12a186ce48 100644 --- a/lib/api/src/js/native_type.rs +++ b/lib/api/src/js/native_type.rs @@ -114,6 +114,28 @@ impl NativeWasmTypeInto for 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) -> f64 { + self as _ + } + + #[inline] + unsafe fn from_raw(_store: &mut impl AsStoreMut, raw: f64) -> Self { + raw as _ + } +} + impl NativeWasmType for Function { const WASM_TYPE: Type = Type::FuncRef; type Abi = f64; diff --git a/lib/api/src/js/ptr.rs b/lib/api/src/js/ptr.rs index b7b812c434a..f9ecc19a679 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::{js::NativeWasmTypeInto, AsStoreRef}; use std::convert::TryFrom; use std::{fmt, marker::PhantomData, mem}; pub use wasmer_types::Memory32; @@ -234,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/js/types.rs b/lib/api/src/js/types.rs index 0e9716073f4..c7a4efd9f53 100644 --- a/lib/api/src/js/types.rs +++ b/lib/api/src/js/types.rs @@ -43,6 +43,7 @@ impl AsJs for Value { 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 .get(store.as_store_ref().objects()) diff --git a/lib/api/src/js/value.rs b/lib/api/src/js/value.rs index a285abe3f13..6eb2cb512aa 100644 --- a/lib/api/src/js/value.rs +++ b/lib/api/src/js/value.rs @@ -7,7 +7,7 @@ use wasmer_types::Type; //use crate::ExternRef; use crate::js::externals::function::Function; -use super::store::AsStoreRef; +use super::store::{AsStoreMut, AsStoreRef}; /// WebAssembly computations manipulate values of basic value types: /// * Integers (32 or 64 bit width) @@ -37,6 +37,9 @@ pub enum Value { /// A first-class reference to a WebAssembly function. FuncRef(Option), + + /// A 128-bit number + V128(u128), } macro_rules! accessors { @@ -76,6 +79,7 @@ impl Value { Self::I64(_) => Type::I64, Self::F32(_) => Type::F32, Self::F64(_) => Type::F64, + Self::V128(_) => Type::V128, //Self::ExternRef(_) => Type::ExternRef, Self::FuncRef(_) => Type::FuncRef, } @@ -88,6 +92,7 @@ impl Value { 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 .get(store.as_store_ref().objects()) @@ -107,12 +112,12 @@ impl Value { /// pub unsafe fn from_raw(_store: &impl AsStoreRef, ty: Type, raw: f64) -> Self { match ty { - Type::I32 => Self::I32(raw as i32), - Type::I64 => Self::I64(raw as i64), - Type::F32 => Self::F32(raw as f32), + 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::V128 => todo!(), Type::ExternRef => todo!(), //Self::ExternRef( //{ @@ -134,6 +139,7 @@ impl Value { | Self::I64(_) | Self::F32(_) | Self::F64(_) + | Self::V128(_) //| Self::ExternRef(None) | Self::FuncRef(None) => true, //Self::ExternRef(Some(e)) => e.is_from_store(store), @@ -147,6 +153,7 @@ impl Value { (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) } @@ -159,6 +166,7 @@ impl fmt::Debug for Value { 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"), @@ -174,12 +182,19 @@ impl ToString for Value { 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) @@ -246,9 +261,18 @@ 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; diff --git a/lib/api/src/sys/externals/function.rs b/lib/api/src/sys/externals/function.rs index 87bfa8237eb..1b90a43c462 100644 --- a/lib/api/src/sys/externals/function.rs +++ b/lib/api/src/sys/externals/function.rs @@ -204,6 +204,7 @@ impl Function { Rets: WasmTypeList, { let env = FunctionEnv::new(store, ()); + let func_ptr = func.function_body_ptr(); let host_data = Box::new(StaticFunction { raw_store: store.as_store_mut().as_raw() as *mut u8, env, @@ -211,7 +212,6 @@ impl Function { }); let function_type = FunctionType::new(Args::wasm_types(), Rets::wasm_types()); - let func_ptr = >::function_body_ptr(); let type_index = store .as_store_mut() .engine() @@ -289,6 +289,7 @@ impl Function { { // 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, env: env.clone(), @@ -296,7 +297,6 @@ impl Function { }); let function_type = FunctionType::new(Args::wasm_types(), Rets::wasm_types()); - let func_ptr = >::function_body_ptr(); let type_index = store .as_store_mut() .engine() @@ -1092,7 +1092,7 @@ mod inner { Kind: HostFunctionKind, { /// Get the pointer to the function body. - fn function_body_ptr() -> *const VMFunctionBody; + fn function_body_ptr(&self) -> *const VMFunctionBody; /// Get the pointer to the function call trampoline. fn call_trampoline_address() -> VMTrampoline; @@ -1268,7 +1268,7 @@ mod inner { Func: Fn(FunctionEnvMut, $( $x , )*) -> RetsAsResult + 'static, { #[allow(non_snake_case)] - fn function_body_ptr() -> *const VMFunctionBody { + fn function_body_ptr(&self) -> *const VMFunctionBody { /// This is a function that wraps the real host /// function. Its address will be used inside the /// runtime. @@ -1352,7 +1352,7 @@ mod inner { Func: Fn($( $x , )*) -> RetsAsResult + 'static, { #[allow(non_snake_case)] - fn function_body_ptr() -> *const VMFunctionBody { + fn function_body_ptr(&self) -> *const VMFunctionBody { /// This is a function that wraps the real host /// function. Its address will be used inside the /// runtime. diff --git a/lib/api/src/sys/externals/memory.rs b/lib/api/src/sys/externals/memory.rs index 285acb231c6..0793513f5be 100644 --- a/lib/api/src/sys/externals/memory.rs +++ b/lib/api/src/sys/externals/memory.rs @@ -154,6 +154,7 @@ impl Memory { mem.try_clone().map(|mem| mem.into()) } + /// To `VMExtern`. pub(crate) fn to_vm_extern(&self) -> VMExtern { VMExtern::Memory(self.handle.internal_handle()) } diff --git a/lib/api/src/sys/native.rs b/lib/api/src/sys/native.rs index 827931aefd1..d5d3bc5aaa5 100644 --- a/lib/api/src/sys/native.rs +++ b/lib/api/src/sys/native.rs @@ -17,7 +17,7 @@ use wasmer_types::RawValue; /// A WebAssembly function that can be called natively /// (using the Native ABI). pub struct TypedFunction { - func: Function, + pub(crate) func: Function, _phantom: PhantomData Rets>, } @@ -45,16 +45,6 @@ impl Clone for TypedFunction } } -impl From> for Function -where - Args: WasmTypeList, - Rets: WasmTypeList, -{ - fn from(other: TypedFunction) -> Self { - other.func - } -} - macro_rules! impl_native_traits { ( $( $x:ident ),* ) => { #[allow(unused_parens, non_snake_case)] diff --git a/lib/api/src/sys/native_type.rs b/lib/api/src/sys/native_type.rs index 8446e95b350..42f3f23939c 100644 --- a/lib/api/src/sys/native_type.rs +++ b/lib/api/src/sys/native_type.rs @@ -4,7 +4,7 @@ use wasmer_types::{NativeWasmType, RawValue, Type}; use wasmer_vm::{VMExternRef, VMFuncRef}; -use crate::{ExternRef, Function}; +use crate::{ExternRef, Function, TypedFunction, WasmTypeList}; use super::store::AsStoreMut; @@ -165,6 +165,16 @@ impl NativeWasmTypeInto for Option { } } +impl From> for Function +where + Args: WasmTypeList, + Rets: WasmTypeList, +{ + fn from(other: TypedFunction) -> Self { + other.func + } +} + impl NativeWasmType for Function { const WASM_TYPE: Type = Type::FuncRef; type Abi = usize; diff --git a/lib/api/tests/js_externals.rs b/lib/api/tests/js_externals.rs index 4795c1ba49e..90a181ec874 100644 --- a/lib/api/tests/js_externals.rs +++ b/lib/api/tests/js_externals.rs @@ -29,7 +29,7 @@ mod js { fn global_get() { let mut store = Store::default(); let global_i32 = Global::new(&mut store, Value::I32(10)); - assert_eq!(global_i32.get(&store), Value::I32(10)); + assert_eq!(global_i32.get(&mut store), Value::I32(10)); // 64-bit values are not yet fully supported in some versions of Node // Commenting this tests for now: