From b9d21187ed59c4d7bae5d5a6195e7d1fb65ef007 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Fri, 10 Feb 2023 18:53:18 -0800 Subject: [PATCH] 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 485f67e40..da8aba603 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 74d62bd64..b39d1bde2 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 e358d2abd..3e59fa573 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 12a57606e..de05531a1 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(),