From 678971ca7a92f56ee1ac32d5340522a318c0ff79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Thu, 25 Aug 2022 16:42:53 +0200 Subject: [PATCH] WIP: Change Export to VMExtern, fix all remaining functions --- lib/api/src/js/error.rs | 11 ++- lib/api/src/js/export.rs | 96 --------------------- lib/api/src/js/externals/mod.rs | 112 +++++++++++++++++++++---- lib/api/src/js/instance.rs | 35 ++------ lib/api/src/js/js_import_object.rs | 5 +- lib/api/src/js/mod.rs | 3 +- lib/api/src/js/module_info_polyfill.rs | 40 +++------ 7 files changed, 130 insertions(+), 172 deletions(-) diff --git a/lib/api/src/js/error.rs b/lib/api/src/js/error.rs index a999a4235f8..02d0dd6bb02 100644 --- a/lib/api/src/js/error.rs +++ b/lib/api/src/js/error.rs @@ -1,5 +1,5 @@ use crate::js::lib::std::string::String; -use crate::js::trap::RuntimeError; +use crate::js::trap::{RuntimeError, WasmerRuntimeError}; #[cfg(feature = "std")] use std::borrow::Cow; #[cfg(feature = "std")] @@ -199,6 +199,15 @@ pub enum InstantiationError { /// A generic error occured while invoking API functions #[cfg_attr(feature = "std", error(transparent))] Wasm(WasmError), + + #[cfg_attr(feature = "std", error(transparent))] + Runtime(WasmerRuntimeError), +} + +impl From for InstantiationError { + fn from(original: WasmerRuntimeError) -> Self { + Self::Runtime(original) + } } impl From for InstantiationError { diff --git a/lib/api/src/js/export.rs b/lib/api/src/js/export.rs index 0241899019f..321c8a3dbb6 100644 --- a/lib/api/src/js/export.rs +++ b/lib/api/src/js/export.rs @@ -86,99 +86,3 @@ impl fmt::Debug for VMFunction { .finish() } } - -/// The value of an export passed from one instance to another. -#[derive(Debug, Clone)] -pub enum Export { - /// A function export value. - Function(InternalStoreHandle), - - /// A table export value. - Table(InternalStoreHandle), - - /// A memory export value. - Memory(InternalStoreHandle), - - /// A global export value. - Global(InternalStoreHandle), -} - -impl Export { - /// Return the export as a `JSValue`. - pub fn as_jsvalue<'context>(&self, store: &'context impl AsStoreRef) -> &'context JsValue { - match self { - Self::Memory(js_wasm_memory) => js_wasm_memory - .get(store.as_store_ref().objects()) - .memory - .as_ref(), - Self::Function(js_func) => js_func - .get(store.as_store_ref().objects()) - .function - .as_ref(), - Self::Table(js_wasm_table) => js_wasm_table - .get(store.as_store_ref().objects()) - .table - .as_ref(), - Self::Global(js_wasm_global) => js_wasm_global - .get(store.as_store_ref().objects()) - .global - .as_ref(), - } - } - - /// Convert a `JsValue` into an `Export` within a given `Context`. - pub fn from_js_value( - val: JsValue, - store: &mut impl AsStoreMut, - extern_type: ExternType, - ) -> Result { - match extern_type { - ExternType::Memory(memory_type) => { - if val.is_instance_of::() { - Ok(Self::Memory(InternalStoreHandle::new( - &mut store.objects_mut(), - VMMemory::new(val.unchecked_into::(), memory_type), - ))) - } else { - Err(WasmError::TypeMismatch( - val.js_typeof() - .as_string() - .map(Into::into) - .unwrap_or("unknown".into()), - "Memory".into(), - )) - } - } - ExternType::Global(global_type) => { - if val.is_instance_of::() { - Ok(Self::Global(InternalStoreHandle::new( - &mut store.objects_mut(), - VMGlobal::new(val.unchecked_into::(), global_type), - ))) - } else { - panic!("Extern type doesn't match js value type"); - } - } - ExternType::Function(function_type) => { - if val.is_instance_of::() { - Ok(Self::Function(InternalStoreHandle::new( - &mut store.objects_mut(), - VMFunction::new(val.unchecked_into::(), function_type), - ))) - } else { - panic!("Extern type doesn't match js value type"); - } - } - ExternType::Table(table_type) => { - if val.is_instance_of::() { - Ok(Self::Table(InternalStoreHandle::new( - &mut store.objects_mut(), - VMTable::new(val.unchecked_into::
(), table_type), - ))) - } else { - panic!("Extern type doesn't match js value type"); - } - } - } - } -} diff --git a/lib/api/src/js/externals/mod.rs b/lib/api/src/js/externals/mod.rs index 5472ee52f70..d3588f9d5fd 100644 --- a/lib/api/src/js/externals/mod.rs +++ b/lib/api/src/js/externals/mod.rs @@ -4,19 +4,24 @@ pub(crate) mod memory; pub(crate) mod memory_view; mod table; -pub use self::function::{FromToNativeWasmType, Function, HostFunction, WasmTypeList}; -pub use self::global::Global; -pub use self::memory::{Memory, MemoryError}; +pub use self::function::{FromToNativeWasmType, HostFunction, WasmTypeList}; +pub use self::memory::MemoryError; pub use self::memory_view::MemoryView; -pub use self::table::Table; +pub use self::memory::Memory as CrateMemory; +pub use self::global::Global as CrateGlobal; +pub use self::function::Function as CrateFunction; +pub use self::table::Table as CrateTable; -use crate::js::export::{Export, VMFunction, VMGlobal, VMMemory, VMTable}; +use crate::js::export::{VMFunction, VMGlobal, VMMemory, VMTable}; use crate::js::exports::{ExportError, Exportable}; use crate::js::store::InternalStoreHandle; use crate::js::store::StoreObject; use crate::js::store::{AsStoreMut, AsStoreRef}; use crate::js::types::AsJs; use crate::js::ExternType; +use crate::js::error::WasmError; +use js_sys::WebAssembly::Memory as JsSysMemory; +use wasm_bindgen::{JsValue, JsCast}; use std::fmt; /// The value of an export passed from one instance to another. @@ -34,6 +39,86 @@ pub enum VMExtern { Global(InternalStoreHandle), } +impl VMExtern { + /// Return the export as a `JSValue`. + pub fn as_jsvalue<'context>(&self, store: &'context impl AsStoreRef) -> &'context JsValue { + match self { + Self::Memory(js_wasm_memory) => js_wasm_memory + .get(store.as_store_ref().objects()) + .memory + .as_ref(), + Self::Function(js_func) => js_func + .get(store.as_store_ref().objects()) + .function + .as_ref(), + Self::Table(js_wasm_table) => js_wasm_table + .get(store.as_store_ref().objects()) + .table + .as_ref(), + Self::Global(js_wasm_global) => js_wasm_global + .get(store.as_store_ref().objects()) + .global + .as_ref(), + } + } + + /// Convert a `JsValue` into an `Export` within a given `Context`. + pub fn from_js_value( + val: JsValue, + store: &mut impl AsStoreMut, + extern_type: ExternType, + ) -> Result { + match extern_type { + ExternType::Memory(memory_type) => { + if val.is_instance_of::() { + Ok(Self::Memory(InternalStoreHandle::new( + &mut store.objects_mut(), + VMMemory::new(val.unchecked_into::(), memory_type), + ))) + } else { + Err(WasmError::TypeMismatch( + val.js_typeof() + .as_string() + .map(Into::into) + .unwrap_or("unknown".into()), + "Memory".into(), + )) + } + } + ExternType::Global(global_type) => { + if val.is_instance_of::() { + Ok(Self::Global(InternalStoreHandle::new( + &mut store.objects_mut(), + VMGlobal::new(val.unchecked_into::(), global_type), + ))) + } else { + panic!("Extern type doesn't match js value type"); + } + } + ExternType::Function(function_type) => { + if val.is_instance_of::() { + Ok(Self::Function(InternalStoreHandle::new( + &mut store.objects_mut(), + VMFunction::new(val.unchecked_into::(), function_type), + ))) + } else { + panic!("Extern type doesn't match js value type"); + } + } + ExternType::Table(table_type) => { + if val.is_instance_of::
() { + Ok(Self::Table(InternalStoreHandle::new( + &mut store.objects_mut(), + VMTable::new(val.unchecked_into::
(), table_type), + ))) + } else { + panic!("Extern type doesn't match js value type"); + } + } + } + } +} + /// An `Extern` is the runtime representation of an entity that /// can be imported or exported. /// @@ -90,24 +175,15 @@ impl Extern { Self::Table(val) => val.is_from_store(store), } } - - fn to_export(&self) -> Export { - match self { - Self::Function(val) => Export::Function(val.handle.internal_handle()), - Self::Memory(val) => Export::Memory(val.handle.internal_handle()), - Self::Global(val) => Export::Global(val.handle.internal_handle()), - Self::Table(val) => Export::Table(val.handle.internal_handle()), - } - } } impl AsJs for Extern { fn as_jsvalue(&self, store: &impl AsStoreRef) -> wasm_bindgen::JsValue { match self { - Self::Function(_) => self.to_export().as_jsvalue(store), - Self::Global(_) => self.to_export().as_jsvalue(store), - Self::Table(_) => self.to_export().as_jsvalue(store), - Self::Memory(_) => self.to_export().as_jsvalue(store), + 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() } diff --git a/lib/api/src/js/instance.rs b/lib/api/src/js/instance.rs index 7ee379a7504..c4500f9bb2b 100644 --- a/lib/api/src/js/instance.rs +++ b/lib/api/src/js/instance.rs @@ -1,7 +1,6 @@ use crate::js::error::InstantiationError; -use crate::js::export::Export; use crate::js::exports::Exports; -use crate::js::externals::Extern; +use crate::js::externals::{Extern, VMExtern}; use crate::js::imports::Imports; use crate::js::module::Module; use crate::js::store::{AsStoreMut, AsStoreRef, StoreHandle}; @@ -90,25 +89,11 @@ impl Instance { module: &Module, externs: &[Extern], ) -> Result { - let imports = externs.to_vec(); - let mut handle = module.instantiate(store, &imports)?; - let exports = module - .exports() - .map(|export| { - let name = export.name().to_string(); - let export = handle.lookup(&name).expect("export"); - let extern_ = Extern::from_vm_extern(store, export); - (name, extern_) - }) - .collect::(); - - let instance = Self { - _handle: StoreHandle::new(store.objects_mut(), handle), - module: module.clone(), - exports, - }; - - Ok(instance) + let mut imports = Imports::new(); + for (import_ty, extern_ty) in module.imports().zip(externs.iter()) { + imports.define(import_ty.module(), import_ty.name(), extern_ty.clone()); + } + Self::new(store, module, &imports) } /// Creates a Wasmer `Instance` from a Wasmer `Module` and a WebAssembly Instance @@ -139,12 +124,10 @@ impl Instance { &name )) })?; - let export: Export = - Export::from_js_value(js_export, &mut store, extern_type)?.into(); - let extern_ = Extern::from_vm_extern(&mut store, export); - Ok((name.to_string(), extern_)) + + Ok((name.to_string(), )) }) - .collect::>()?; + .collect::, InstantiationError>>()?; Ok(Self { _handle: instance, diff --git a/lib/api/src/js/js_import_object.rs b/lib/api/src/js/js_import_object.rs index 1370d8bd336..0c42af2dc82 100644 --- a/lib/api/src/js/js_import_object.rs +++ b/lib/api/src/js/js_import_object.rs @@ -1,6 +1,7 @@ use crate::js::error::WasmError; use crate::js::store::AsStoreMut; -use crate::js::{Export, ExternType, Module}; +use crate::js::{ExternType, Module}; +use crate::js::externals::VMExtern; use std::collections::HashMap; /// This struct is used in case you want to create an `Instance` @@ -43,6 +44,7 @@ impl JsImportObject { } } + /* /// Gets an export given a module and a name /// /// # Usage @@ -74,6 +76,7 @@ impl JsImportObject { ))), } } + */ } impl Into for JsImportObject { diff --git a/lib/api/src/js/mod.rs b/lib/api/src/js/mod.rs index 7711cd85d4f..b4b7a3c296e 100644 --- a/lib/api/src/js/mod.rs +++ b/lib/api/src/js/mod.rs @@ -45,11 +45,10 @@ mod value; mod wasm_bindgen_polyfill; pub use crate::js::error::{DeserializeError, InstantiationError, SerializeError}; -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, MemoryView, - Table, WasmTypeList, + Table, WasmTypeList, VMExtern, }; pub use crate::js::function_env::{FunctionEnv, FunctionEnvMut}; pub use crate::js::imports::Imports; diff --git a/lib/api/src/js/module_info_polyfill.rs b/lib/api/src/js/module_info_polyfill.rs index 80f7cccfc21..77137507e75 100644 --- a/lib/api/src/js/module_info_polyfill.rs +++ b/lib/api/src/js/module_info_polyfill.rs @@ -505,41 +505,25 @@ pub fn parse_global_section( /// Parses the Export section of the wasm module. pub fn parse_export_section<'data>( - exports: ExportSectionReader<'data>, + exports: VMExternSectionReader<'data>, module_info: &mut ModuleInfoPolyfill, ) -> WasmResult<()> { module_info.reserve_exports(exports.get_count())?; - - for entry in exports { - let Export { - field, - ref kind, - index, - } = entry.map_err(transform_err)?; - - // The input has already been validated, so we should be able to - // assume valid UTF-8 and use `from_utf8_unchecked` if performance - // becomes a concern here. - let index = index as usize; - match *kind { - ExternalKind::Function => { + for (index, entry) in exports.enumerate() { + match entry { + VMExtern::Function(handle) => { module_info.declare_func_export(FunctionIndex::new(index), field)? - } - ExternalKind::Table => { + }, + VMExtern::Table(handle) => { module_info.declare_table_export(TableIndex::new(index), field)? - } - ExternalKind::Memory => { + + }, + VMExtern::Memory(handle) => { module_info.declare_memory_export(MemoryIndex::new(index), field)? - } - ExternalKind::Global => { + }, + VMExtern::Global(handle) => { module_info.declare_global_export(GlobalIndex::new(index), field)? - } - ExternalKind::Type | ExternalKind::Module | ExternalKind::Instance => { - unimplemented!("module linking not implemented yet") - } - ExternalKind::Tag => { - unimplemented!("exception handling not implemented yet") - } + }, } } Ok(())