From c0913fa91309d55767134a33d88a2eecab8f6caf Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Wed, 24 Nov 2021 23:57:43 +0100 Subject: [PATCH] Added jsobjectresolver --- lib/api/src/js/export.rs | 1 + lib/api/src/js/instance.rs | 25 ++++++--- lib/api/src/js/jsobjectresolver.rs | 83 ++++++++++++++++++++++++++++++ lib/api/src/js/mod.rs | 3 ++ 4 files changed, 105 insertions(+), 7 deletions(-) create mode 100644 lib/api/src/js/jsobjectresolver.rs diff --git a/lib/api/src/js/export.rs b/lib/api/src/js/export.rs index 9eef75c98..fc5f638c4 100644 --- a/lib/api/src/js/export.rs +++ b/lib/api/src/js/export.rs @@ -118,6 +118,7 @@ pub enum Export { } impl Export { + /// Return the export as a `JSValue`. pub fn as_jsvalue(&self) -> &JsValue { match self { Export::Memory(js_wasm_memory) => js_wasm_memory.memory.as_ref(), diff --git a/lib/api/src/js/instance.rs b/lib/api/src/js/instance.rs index 6d19b0852..5dbd9b274 100644 --- a/lib/api/src/js/instance.rs +++ b/lib/api/src/js/instance.rs @@ -100,7 +100,7 @@ impl Instance { .instantiate(resolver) .map_err(|e| InstantiationError::Start(e))?; - let self_instance = Self::from_module_and_instance(module, instance); + let self_instance = Self::from_module_and_instance(module, instance)?; self_instance.init_envs(&imports)?; Ok(self_instance) } @@ -112,7 +112,11 @@ impl Instance { /// 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. - pub fn from_module_and_instance(module: &Module, instance: WebAssembly::Instance) -> Self { + #[doc(hidden)] + pub fn from_module_and_instance( + module: &Module, + instance: WebAssembly::Instance, + ) -> Result { let store = module.store(); let instance_exports = instance.exports(); let exports = module @@ -120,21 +124,28 @@ impl Instance { .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()).unwrap(); + 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 = (js_export, extern_type).into(); let extern_ = Extern::from_vm_export(store, export); - (name.to_string(), extern_) + Ok((name.to_string(), extern_)) }) - .collect::(); + .collect::>()?; - Self { + Ok(Self { instance, module: module.clone(), exports, - } + }) } /// Initialize the given extern imports with the Instance + #[doc(hidden)] pub fn init_envs(&self, imports: &[Export]) -> Result<(), InstantiationError> { for import in imports { if let Export::Function(func) = import { diff --git a/lib/api/src/js/jsobjectresolver.rs b/lib/api/src/js/jsobjectresolver.rs new file mode 100644 index 000000000..6b1708f53 --- /dev/null +++ b/lib/api/src/js/jsobjectresolver.rs @@ -0,0 +1,83 @@ +use crate::js::{Export, ExternType, Module, NamedResolver}; +use std::collections::HashMap; + +/// All of the import data used when instantiating. +/// +/// It's suggested that you use the [`imports!`] macro +/// instead of creating an `ImportObject` by hand. +/// +/// [`imports!`]: macro.imports.html +/// +/// # Usage: +/// ```ignore +/// use wasmer::{Exports, ImportObject, Function}; +/// +/// let mut import_object = ImportObject::new(); +/// let mut env = Exports::new(); +/// +/// env.insert("foo", Function::new_native(foo)); +/// import_object.register("env", env); +/// +/// fn foo(n: i32) -> i32 { +/// n +/// } +/// ``` +#[derive(Clone, Default)] +pub struct JSObjectResolver { + module_imports: HashMap<(String, String), ExternType>, + object: js_sys::Object, +} + +unsafe impl Send for JSObjectResolver {} +unsafe impl Sync for JSObjectResolver {} + +impl JSObjectResolver { + /// Create a new `ImportObject`. + pub fn new(module: &Module, object: js_sys::Object) -> Self { + let module_imports = module + .imports() + .map(|import| { + ( + (import.module().to_string(), import.name().to_string()), + import.ty().clone(), + ) + }) + .collect::>(); + Self { + module_imports, + object, + } + } + + /// Gets an export given a module and a name + /// + /// # Usage + /// ```ignore + /// # use wasmer::{ImportObject, Instance, Namespace}; + /// let mut import_object = ImportObject::new(); + /// import_object.get_export("module", "name"); + /// ``` + pub fn get_export(&self, module: &str, name: &str) -> Option { + let namespace = js_sys::Reflect::get(&self.object, &name.into()).ok()?; + let js_export = js_sys::Reflect::get(&namespace, &name.into()).ok()?; + match self + .module_imports + .get(&(module.to_string(), name.to_string())) + { + Some(extern_type) => Some((js_export, extern_type.clone()).into()), + None => None, + } + } +} + +impl Into for JSObjectResolver { + fn into(self) -> js_sys::Object { + self.object + } +} + +impl NamedResolver for JSObjectResolver { + fn resolve_by_name(&self, module: &str, name: &str) -> Option { + self.get_export(module, name) + } +} diff --git a/lib/api/src/js/mod.rs b/lib/api/src/js/mod.rs index b27d2756c..ae27e8337 100644 --- a/lib/api/src/js/mod.rs +++ b/lib/api/src/js/mod.rs @@ -31,6 +31,7 @@ mod exports; mod externals; mod import_object; mod instance; +mod jsobjectresolver; mod module; #[cfg(feature = "wasm-types-polyfill")] mod module_info_polyfill; @@ -50,6 +51,7 @@ pub use wasmer_derive::WasmerEnv; pub use crate::js::cell::WasmCell; pub use crate::js::env::{HostEnvInitError, LazyInit, WasmerEnv}; +pub use crate::js::export::Export; pub use crate::js::exports::{ExportError, Exportable, Exports, ExportsIterator}; pub use crate::js::externals::{ Extern, FromToNativeWasmType, Function, Global, HostFunction, Memory, MemoryError, Table, @@ -57,6 +59,7 @@ pub use crate::js::externals::{ }; pub use crate::js::import_object::{ImportObject, ImportObjectIterator, LikeNamespace}; pub use crate::js::instance::{Instance, InstantiationError}; +pub use crate::js::jsobjectresolver::JSObjectResolver; pub use crate::js::module::{Module, ModuleTypeHints}; pub use crate::js::native::NativeFunc; pub use crate::js::ptr::{Array, Item, WasmPtr};