Make instance more uniform

This commit is contained in:
Syrus Akbary
2023-02-10 18:53:18 -08:00
parent 4eaddb5ce4
commit b9d21187ed
4 changed files with 70 additions and 90 deletions

View File

@@ -4,26 +4,27 @@
use crate::imports::Imports; use crate::imports::Imports;
use crate::js::externals::Extern; use crate::js::externals::Extern;
use crate::js::vm::VMExtern; use crate::js::vm::VMExtern;
use crate::js::Instance;
use crate::store::{AsStoreMut, AsStoreRef}; use crate::store::{AsStoreMut, AsStoreRef};
use crate::value::Value; use crate::value::Value;
use crate::Exports;
use crate::ValType; use crate::ValType;
use std::collections::HashMap; use std::collections::HashMap;
use wasm_bindgen::JsValue; use wasm_bindgen::{JsError, JsValue};
use wasmer_types::ExternType; use wasmer_types::ExternType;
/// Convert the given type to a [`JsValue`]. /// Convert the given type to a [`JsValue`].
pub trait AsJs { pub trait AsJs: Sized {
/// The inner definition type from this Javascript object /// The inner definition type from this Javascript object
type DefinitionType; type DefinitionType;
/// Convert the given type to a [`JsValue`]. /// Convert the given type to a [`JsValue`].
fn as_jsvalue(&self, store: &impl AsStoreRef) -> JsValue; fn as_jsvalue(&self, store: &impl AsStoreRef) -> JsValue;
/// Convert the given type to a [`JsValue`]. /// Convert the given type to a [`JsValue`].
fn from_jsvalue( fn from_jsvalue(
&self,
store: &mut impl AsStoreMut, store: &mut impl AsStoreMut,
type_: &Self::DefinitionType, type_: &Self::DefinitionType,
value: &JsValue, value: &JsValue,
) -> Self; ) -> Result<Self, JsError>;
} }
#[inline] #[inline]
@@ -57,12 +58,11 @@ impl AsJs for Value {
} }
fn from_jsvalue( fn from_jsvalue(
&self,
_store: &mut impl AsStoreMut, _store: &mut impl AsStoreMut,
type_: &Self::DefinitionType, type_: &Self::DefinitionType,
value: &JsValue, value: &JsValue,
) -> Self { ) -> Result<Self, JsError> {
param_from_js(type_, value) Ok(param_from_js(type_, value))
} }
} }
@@ -74,11 +74,10 @@ impl AsJs for wasmer_types::RawValue {
} }
fn from_jsvalue( fn from_jsvalue(
&self,
_store: &mut impl AsStoreMut, _store: &mut impl AsStoreMut,
type_: &Self::DefinitionType, type_: &Self::DefinitionType,
value: &JsValue, value: &JsValue,
) -> Self { ) -> Result<Self, JsError> {
unimplemented!(); unimplemented!();
} }
} }
@@ -162,11 +161,10 @@ impl AsJs for Imports {
} }
fn from_jsvalue( fn from_jsvalue(
&self,
store: &mut impl AsStoreMut, store: &mut impl AsStoreMut,
module: &Self::DefinitionType, module: &Self::DefinitionType,
value: &JsValue, value: &JsValue,
) -> Self { ) -> Result<Self, JsError> {
let module_imports: HashMap<(String, String), ExternType> = module let module_imports: HashMap<(String, String), ExternType> = module
.imports() .imports()
.map(|import| { .map(|import| {
@@ -196,7 +194,7 @@ impl AsJs for Imports {
} }
} }
Self { map } Ok(Self { map })
} }
} }
@@ -213,11 +211,60 @@ impl AsJs for Extern {
.clone() .clone()
} }
fn from_jsvalue( fn from_jsvalue(
&self,
_store: &mut impl AsStoreMut, _store: &mut impl AsStoreMut,
type_: &Self::DefinitionType, type_: &Self::DefinitionType,
value: &JsValue, value: &JsValue,
) -> Self { ) -> Result<Self, JsError> {
unimplemented!(); 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<Self, JsError> {
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::<Result<Exports, JsError>>()?;
Ok(Self {
handle: instance,
module: module.clone(),
exports,
})
}
}

View File

@@ -109,7 +109,6 @@ pub enum LinkError {
#[cfg_attr(feature = "std", error("Error while importing {0:?}.{1:?}: {2}"))] #[cfg_attr(feature = "std", error("Error while importing {0:?}.{1:?}: {2}"))]
Import(String, String, ImportError), Import(String, String, ImportError),
#[cfg(not(target_arch = "wasm32"))]
/// A trap ocurred during linking. /// A trap ocurred during linking.
#[cfg_attr(feature = "std", error("RuntimeError occurred during linking: {0}"))] #[cfg_attr(feature = "std", error("RuntimeError occurred during linking: {0}"))]
Trap(#[source] RuntimeError), Trap(#[source] RuntimeError),
@@ -146,20 +145,6 @@ pub enum InstantiationError {
/// This error occurs when an import from a different store is used. /// This error occurs when an import from a different store is used.
#[cfg_attr(feature = "std", error("cannot mix imports from different stores"))] #[cfg_attr(feature = "std", error("cannot mix imports from different stores"))]
DifferentStores, 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<WasmError> for InstantiationError {
fn from(original: WasmError) -> Self {
Self::Wasm(original)
}
} }
#[cfg(feature = "core")] #[cfg(feature = "core")]

View File

@@ -1,10 +1,12 @@
use crate::exports::Exports; use crate::exports::Exports;
use crate::imports::Imports; use crate::imports::Imports;
use crate::js::as_js::AsJs;
use crate::js::error::InstantiationError; use crate::js::error::InstantiationError;
use crate::js::externals::Extern; use crate::js::externals::Extern;
use crate::js::vm::{VMExtern, VMInstance}; use crate::js::vm::{VMExtern, VMInstance};
use crate::module::Module; use crate::module::Module;
use crate::store::{AsStoreMut, AsStoreRef}; use crate::store::{AsStoreMut, AsStoreRef};
use crate::{LinkError, RuntimeError};
use js_sys::WebAssembly; use js_sys::WebAssembly;
use std::fmt; use std::fmt;
@@ -18,8 +20,8 @@ use std::fmt;
/// Spec: <https://webassembly.github.io/spec/core/exec/runtime.html#module-instances> /// Spec: <https://webassembly.github.io/spec/core/exec/runtime.html#module-instances>
#[derive(Clone)] #[derive(Clone)]
pub struct Instance { pub struct Instance {
handle: VMInstance, pub(crate) handle: VMInstance,
module: Module, pub(crate) module: Module,
/// The exports for an instance. /// The exports for an instance.
pub exports: Exports, pub exports: Exports,
} }
@@ -68,7 +70,11 @@ impl Instance {
.instantiate(&mut store, imports) .instantiate(&mut store, imports)
.map_err(|e| InstantiationError::Start(e))?; .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) Ok(self_instance)
} }
@@ -94,60 +100,10 @@ impl Instance {
Self::new(store, module, &imports) 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<Self, InstantiationError> {
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::<Result<Exports, InstantiationError>>()?;
Ok(Self {
handle: instance,
module: module.clone(),
exports,
})
}
/// Gets the [`Module`] associated with this instance. /// Gets the [`Module`] associated with this instance.
pub fn module(&self) -> &Module { pub fn module(&self) -> &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 { impl fmt::Debug for Instance {

View File

@@ -172,14 +172,6 @@ impl Instance {
}) })
.collect::<Exports>(); .collect::<Exports>();
// 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 { let instance = Self {
_handle: StoreHandle::new(store.objects_mut(), handle), _handle: StoreHandle::new(store.objects_mut(), handle),
module: module.clone(), module: module.clone(),