diff --git a/lib/api/src/js/imports.rs b/lib/api/src/js/imports.rs index 4c98e38a0..193838e96 100644 --- a/lib/api/src/js/imports.rs +++ b/lib/api/src/js/imports.rs @@ -227,6 +227,36 @@ impl Imports { } } +impl AsJs for Imports { + 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 = js_sys::Reflect::get(&imports_object, &namespace.into()).unwrap(); + if !val.is_undefined() { + // If the namespace is already set + 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(); + 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() + } +} + pub struct ImportsIterator<'a> { iter: std::collections::hash_map::Iter<'a, (String, String), Extern>, } @@ -363,89 +393,18 @@ macro_rules! import_namespace { }; } -/* +#[cfg(test)] mod test { - use crate::js::exports::Exportable; - use crate::js::Type; - use crate::js::{Global, Store, Val}; + use crate::js::{Global, Store, Value}; - use crate::js::export::Export; + // use wasm_bindgen::*; use wasm_bindgen_test::*; - fn namespace() { - let mut store = Store::default(); - let g1 = Global::new(&store, Val::I32(0)); - let namespace = namespace! { - "happy" => g1 - }; - let imports1 = imports! { - "dog" => namespace - }; - - let happy_dog_entry = imports1.get_export("dog", "happy").unwrap(); - - assert!( - if let Export::Global(happy_dog_global) = happy_dog_entry.to_export() { - happy_dog_global.ty.ty == Type::I32 - } else { - false - } - ); - } - - fn imports_macro_allows_trailing_comma_and_none() { - use crate::js::Function; - - let mut store = Default::default(); - - fn func(arg: i32) -> i32 { - arg + 1 - } - - let _ = imports! { - "env" => { - "func" => Function::new_typed(&store, func), - }, - }; - let _ = imports! { - "env" => { - "func" => Function::new_typed(&store, func), - } - }; - let _ = imports! { - "env" => { - "func" => Function::new_typed(&store, func), - }, - "abc" => { - "def" => Function::new_typed(&store, func), - } - }; - let _ = imports! { - "env" => { - "func" => Function::new_typed(&store, func) - }, - }; - let _ = imports! { - "env" => { - "func" => Function::new_typed(&store, func) - } - }; - let _ = imports! { - "env" => { - "func1" => Function::new_typed(&store, func), - "func2" => Function::new_typed(&store, func) - } - }; - let _ = imports! { - "env" => { - "func1" => Function::new_typed(&store, func), - "func2" => Function::new_typed(&store, func), - } - }; - } + #[wasm_bindgen_test] fn chaining_works() { let mut store = Store::default(); - let g = Global::new(&store, Val::I32(0)); + + let g = Global::new(&mut store, Value::I32(0)); let mut imports1 = imports! { "dog" => { @@ -458,7 +417,7 @@ mod test { "small" => g.clone() }, "cat" => { - "small" => g.clone() + "small" => g } }; @@ -472,62 +431,162 @@ mod test { assert!(happy.is_some()); assert!(small.is_some()); } + // fn namespace() { + // let mut store = Store::default(); + // let g1 = Global::new(&store, Val::I32(0)); + // let namespace = namespace! { + // "happy" => g1 + // }; + // let imports1 = imports! { + // "dog" => namespace + // }; - fn extending_conflict_overwrites() { - let mut store = Store::default(); - let g1 = Global::new(&store, Val::I32(0)); - let g2 = Global::new(&store, Val::F32(0.)); + // let happy_dog_entry = imports1.get_export("dog", "happy").unwrap(); - let mut imports1 = imports! { - "dog" => { - "happy" => g1, - }, - }; + // assert!( + // if let Export::Global(happy_dog_global) = happy_dog_entry.to_export() { + // happy_dog_global.ty.ty == Type::I32 + // } else { + // false + // } + // ); + // } - let imports2 = imports! { - "dog" => { - "happy" => g2, - }, - }; + // fn imports_macro_allows_trailing_comma_and_none() { + // use crate::js::Function; - imports1.extend(&imports2); - let happy_dog_entry = imports1.get_export("dog", "happy").unwrap(); + // let mut store = Default::default(); - assert!( - if let Export::Global(happy_dog_global) = happy_dog_entry.to_export() { - happy_dog_global.ty.ty == Type::F32 - } else { - false - } - ); + // fn func(arg: i32) -> i32 { + // arg + 1 + // } - // now test it in reverse - let mut store = Store::default(); - let g1 = Global::new(&store, Val::I32(0)); - let g2 = Global::new(&store, Val::F32(0.)); + // let _ = imports! { + // "env" => { + // "func" => Function::new_typed(&store, func), + // }, + // }; + // let _ = imports! { + // "env" => { + // "func" => Function::new_typed(&store, func), + // } + // }; + // let _ = imports! { + // "env" => { + // "func" => Function::new_typed(&store, func), + // }, + // "abc" => { + // "def" => Function::new_typed(&store, func), + // } + // }; + // let _ = imports! { + // "env" => { + // "func" => Function::new_typed(&store, func) + // }, + // }; + // let _ = imports! { + // "env" => { + // "func" => Function::new_typed(&store, func) + // } + // }; + // let _ = imports! { + // "env" => { + // "func1" => Function::new_typed(&store, func), + // "func2" => Function::new_typed(&store, func) + // } + // }; + // let _ = imports! { + // "env" => { + // "func1" => Function::new_typed(&store, func), + // "func2" => Function::new_typed(&store, func), + // } + // }; + // } - let imports1 = imports! { - "dog" => { - "happy" => g1, - }, - }; + // fn chaining_works() { + // let mut store = Store::default(); + // let g = Global::new(&store, Val::I32(0)); - let mut imports2 = imports! { - "dog" => { - "happy" => g2, - }, - }; + // let mut imports1 = imports! { + // "dog" => { + // "happy" => g.clone() + // } + // }; - imports2.extend(&imports1); - let happy_dog_entry = imports2.get_export("dog", "happy").unwrap(); + // let imports2 = imports! { + // "dog" => { + // "small" => g.clone() + // }, + // "cat" => { + // "small" => g.clone() + // } + // }; - assert!( - if let Export::Global(happy_dog_global) = happy_dog_entry.to_export() { - happy_dog_global.ty.ty == Type::I32 - } else { - false - } - ); - } + // 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()); + // } + + // fn extending_conflict_overwrites() { + // let mut store = Store::default(); + // let g1 = Global::new(&store, Val::I32(0)); + // let g2 = Global::new(&store, Val::F32(0.)); + + // let mut imports1 = imports! { + // "dog" => { + // "happy" => g1, + // }, + // }; + + // let imports2 = imports! { + // "dog" => { + // "happy" => g2, + // }, + // }; + + // imports1.extend(&imports2); + // let happy_dog_entry = imports1.get_export("dog", "happy").unwrap(); + + // assert!( + // if let Export::Global(happy_dog_global) = happy_dog_entry.to_export() { + // happy_dog_global.ty.ty == Type::F32 + // } else { + // false + // } + // ); + + // // now test it in reverse + // let mut store = Store::default(); + // let g1 = Global::new(&store, Val::I32(0)); + // let g2 = Global::new(&store, Val::F32(0.)); + + // let imports1 = imports! { + // "dog" => { + // "happy" => g1, + // }, + // }; + + // let mut imports2 = imports! { + // "dog" => { + // "happy" => g2, + // }, + // }; + + // imports2.extend(&imports1); + // let happy_dog_entry = imports2.get_export("dog", "happy").unwrap(); + + // assert!( + // if let Export::Global(happy_dog_global) = happy_dog_entry.to_export() { + // happy_dog_global.ty.ty == Type::I32 + // } else { + // false + // } + // ); + // } } - */ diff --git a/lib/api/src/js/instance.rs b/lib/api/src/js/instance.rs index 1b1eb0898..fe914626f 100644 --- a/lib/api/src/js/instance.rs +++ b/lib/api/src/js/instance.rs @@ -20,8 +20,6 @@ use std::fmt; pub struct Instance { _handle: StoreHandle, module: Module, - #[allow(dead_code)] - imports: Imports, /// The exports for an instance. pub exports: Exports, } @@ -65,12 +63,11 @@ impl Instance { module: &Module, imports: &Imports, ) -> Result { - let import_copy = imports.clone(); - let (instance, _imports): (StoreHandle, Vec) = module + let instance: WebAssembly::Instance = module .instantiate(&mut store, imports) .map_err(|e| InstantiationError::Start(e))?; - let self_instance = Self::from_module_and_instance(store, module, instance, import_copy)?; + let self_instance = Self::from_module_and_instance(store, module, instance)?; //self_instance.init_envs(&imports.iter().map(Extern::to_export).collect::>())?; Ok(self_instance) } @@ -87,10 +84,9 @@ impl Instance { pub fn from_module_and_instance( mut store: &mut impl AsStoreMut, module: &Module, - instance: StoreHandle, - imports: Imports, + instance: WebAssembly::Instance, ) -> Result { - let instance_exports = instance.get(store.as_store_ref().objects()).exports(); + let instance_exports = instance.exports(); let exports = module .exports() .map(|export_type| { @@ -109,11 +105,10 @@ impl Instance { Ok((name.to_string(), extern_)) }) .collect::>()?; - + let handle = StoreHandle::new(store.as_store_mut().objects_mut(), instance); Ok(Self { - _handle: instance, + _handle: handle, module: module.clone(), - imports, exports, }) } diff --git a/lib/api/src/js/module.rs b/lib/api/src/js/module.rs index 975d1bee5..dc3df9075 100644 --- a/lib/api/src/js/module.rs +++ b/lib/api/src/js/module.rs @@ -3,9 +3,8 @@ 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, StoreHandle}; +use crate::js::store::AsStoreMut; use crate::js::types::{AsJs, ExportType, ImportType}; use crate::js::RuntimeError; use crate::AsStoreRef; @@ -222,7 +221,7 @@ impl Module { &self, store: &mut impl AsStoreMut, imports: &Imports, - ) -> Result<(StoreHandle, Vec), RuntimeError> { + ) -> Result { // Ensure all imports come from the same store. if imports .into_iter() @@ -232,46 +231,10 @@ impl Module { InstantiationError::DifferentStores, ))); } - let imports_object = js_sys::Object::new(); - let mut import_externs: Vec = vec![]; - for import_type in self.imports() { - let resolved_import = imports.get_export(import_type.module(), import_type.name()); - if let Some(import) = resolved_import { - let val = js_sys::Reflect::get(&imports_object, &import_type.module().into())?; - if !val.is_undefined() { - // If the namespace is already set - js_sys::Reflect::set( - &val, - &import_type.name().into(), - &import.as_jsvalue(&store.as_store_ref()), - )?; - } else { - // If the namespace doesn't exist - let import_namespace = js_sys::Object::new(); - js_sys::Reflect::set( - &import_namespace, - &import_type.name().into(), - &import.as_jsvalue(&store.as_store_ref()), - )?; - js_sys::Reflect::set( - &imports_object, - &import_type.module().into(), - &import_namespace.into(), - )?; - } - import_externs.push(import); - } - // in case the import is not found, the JS Wasm VM will handle - // the error for us, so we don't need to handle it - } - Ok(( - StoreHandle::new( - store.as_store_mut().objects_mut(), - WebAssembly::Instance::new(&self.module, &imports_object) - .map_err(|e: JsValue| -> RuntimeError { e.into() })?, - ), - import_externs, - )) + + let imports_js_obj = imports.as_jsvalue(store).into(); + Ok(WebAssembly::Instance::new(&self.module, &imports_js_obj) + .map_err(|e: JsValue| -> RuntimeError { e.into() })?) } /// Returns the name of the current module.