Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JS API improvement #2694

Merged
merged 5 commits into from
Nov 25, 2021
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/api/src/js/export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
25 changes: 18 additions & 7 deletions lib/api/src/js/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand All @@ -112,29 +112,40 @@ 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)]
Amanieu marked this conversation as resolved.
Show resolved Hide resolved
pub fn from_module_and_instance(
module: &Module,
instance: WebAssembly::Instance,
) -> Result<Self, InstantiationError> {
let store = module.store();
let instance_exports = instance.exports();
let exports = module
.exports()
.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::<Exports>();
.collect::<Result<Exports, InstantiationError>>()?;

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 {
Expand Down
71 changes: 71 additions & 0 deletions lib/api/src/js/js_import_object.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
use crate::js::{Export, ExternType, Module, NamedResolver};
use std::collections::HashMap;

/// This struct is used in case you want to create an `Instance`
/// of a `Module` with imports that are provided directly from
/// Javascript with a JS Object.
#[derive(Clone, Default)]
pub struct JsImportObject {
module_imports: HashMap<(String, String), ExternType>,
object: js_sys::Object,
}

unsafe impl Send for JsImportObject {}
unsafe impl Sync for JsImportObject {}
Amanieu marked this conversation as resolved.
Show resolved Hide resolved

impl JsImportObject {
/// Create a new `JsImportObject`.
Amanieu marked this conversation as resolved.
Show resolved Hide resolved
///
/// # Usage
/// ```ignore
/// # use wasmer::JsImportObject;
/// let import_object = JsImportObject::new(&module, js_object);
/// ```
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::<HashMap<(String, String), ExternType>>();
Self {
module_imports,
object,
}
}

/// Gets an export given a module and a name
///
/// # Usage
/// ```ignore
/// # use wasmer::JsImportObject;
/// let import_object = JsImportObject::new(&module, js_object);
/// import_object.get_export("module", "name");
/// ```
pub fn get_export(&self, module: &str, name: &str) -> Option<Export> {
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<js_sys::Object> for JsImportObject {
fn into(self) -> js_sys::Object {
self.object
}
}

impl NamedResolver for JsImportObject {
fn resolve_by_name(&self, module: &str, name: &str) -> Option<Export> {
self.get_export(module, name)
}
}
3 changes: 3 additions & 0 deletions lib/api/src/js/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ mod exports;
mod externals;
mod import_object;
mod instance;
mod js_import_object;
mod module;
#[cfg(feature = "wasm-types-polyfill")]
mod module_info_polyfill;
Expand All @@ -50,13 +51,15 @@ 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,
WasmTypeList,
};
pub use crate::js::import_object::{ImportObject, ImportObjectIterator, LikeNamespace};
pub use crate::js::instance::{Instance, InstantiationError};
pub use crate::js::js_import_object::JsImportObject;
pub use crate::js::module::{Module, ModuleTypeHints};
pub use crate::js::native::NativeFunc;
pub use crate::js::ptr::{Array, Item, WasmPtr};
Expand Down