From 9f83b84e866c80a4961b15a32496ae8e2f699b82 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Fri, 10 Feb 2023 18:05:56 -0800 Subject: [PATCH] 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 000000000..d83523469 --- /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 6866a78ef..1ab9fac23 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 bd49012d4..b58e17ae1 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 8e38c7c43..56edd3b8a 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 9d0f35f5f..40e8355b4 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 ee884ed17..60a111be1 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 5c5fdb03c..075872f46 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 ecea9c64b..000000000 --- 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()) } - } -}