mirror of
https://github.com/mii443/wasmer.git
synced 2025-12-12 05:18:43 +00:00
Improved JS API a bit further
This commit is contained in:
@@ -227,6 +227,36 @@ impl Imports {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl AsJs for Imports {
|
||||||
|
fn as_jsvalue(&self, store: &impl AsStoreRef) -> wasm_bindgen::JsValue {
|
||||||
|
let imports_object = js_sys::Object::new();
|
||||||
|
for (namespace, name, extern_) in self.iter() {
|
||||||
|
let val = js_sys::Reflect::get(&imports_object, &namespace.into()).unwrap();
|
||||||
|
if !val.is_undefined() {
|
||||||
|
// If the namespace is already set
|
||||||
|
js_sys::Reflect::set(
|
||||||
|
&val,
|
||||||
|
&name.into(),
|
||||||
|
&extern_.as_jsvalue(&store.as_store_ref()),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
} else {
|
||||||
|
// If the namespace doesn't exist
|
||||||
|
let import_namespace = js_sys::Object::new();
|
||||||
|
js_sys::Reflect::set(
|
||||||
|
&import_namespace,
|
||||||
|
&name.into(),
|
||||||
|
&extern_.as_jsvalue(&store.as_store_ref()),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
js_sys::Reflect::set(&imports_object, &namespace.into(), &import_namespace.into())
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
imports_object.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ImportsIterator<'a> {
|
pub struct ImportsIterator<'a> {
|
||||||
iter: std::collections::hash_map::Iter<'a, (String, String), Extern>,
|
iter: std::collections::hash_map::Iter<'a, (String, String), Extern>,
|
||||||
}
|
}
|
||||||
@@ -363,89 +393,18 @@ macro_rules! import_namespace {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::js::exports::Exportable;
|
use crate::js::{Global, Store, Value};
|
||||||
use crate::js::Type;
|
|
||||||
use crate::js::{Global, Store, Val};
|
|
||||||
|
|
||||||
use crate::js::export::Export;
|
// use wasm_bindgen::*;
|
||||||
use wasm_bindgen_test::*;
|
use wasm_bindgen_test::*;
|
||||||
fn namespace() {
|
|
||||||
let mut store = Store::default();
|
|
||||||
let g1 = Global::new(&store, Val::I32(0));
|
|
||||||
let namespace = namespace! {
|
|
||||||
"happy" => g1
|
|
||||||
};
|
|
||||||
let imports1 = imports! {
|
|
||||||
"dog" => namespace
|
|
||||||
};
|
|
||||||
|
|
||||||
let happy_dog_entry = imports1.get_export("dog", "happy").unwrap();
|
|
||||||
|
|
||||||
assert!(
|
|
||||||
if let Export::Global(happy_dog_global) = happy_dog_entry.to_export() {
|
|
||||||
happy_dog_global.ty.ty == Type::I32
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn imports_macro_allows_trailing_comma_and_none() {
|
|
||||||
use crate::js::Function;
|
|
||||||
|
|
||||||
let mut store = Default::default();
|
|
||||||
|
|
||||||
fn func(arg: i32) -> i32 {
|
|
||||||
arg + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
let _ = imports! {
|
|
||||||
"env" => {
|
|
||||||
"func" => Function::new_typed(&store, func),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
let _ = imports! {
|
|
||||||
"env" => {
|
|
||||||
"func" => Function::new_typed(&store, func),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let _ = imports! {
|
|
||||||
"env" => {
|
|
||||||
"func" => Function::new_typed(&store, func),
|
|
||||||
},
|
|
||||||
"abc" => {
|
|
||||||
"def" => Function::new_typed(&store, func),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let _ = imports! {
|
|
||||||
"env" => {
|
|
||||||
"func" => Function::new_typed(&store, func)
|
|
||||||
},
|
|
||||||
};
|
|
||||||
let _ = imports! {
|
|
||||||
"env" => {
|
|
||||||
"func" => Function::new_typed(&store, func)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let _ = imports! {
|
|
||||||
"env" => {
|
|
||||||
"func1" => Function::new_typed(&store, func),
|
|
||||||
"func2" => Function::new_typed(&store, func)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let _ = imports! {
|
|
||||||
"env" => {
|
|
||||||
"func1" => Function::new_typed(&store, func),
|
|
||||||
"func2" => Function::new_typed(&store, func),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
fn chaining_works() {
|
fn chaining_works() {
|
||||||
let mut store = Store::default();
|
let mut store = Store::default();
|
||||||
let g = Global::new(&store, Val::I32(0));
|
|
||||||
|
let g = Global::new(&mut store, Value::I32(0));
|
||||||
|
|
||||||
let mut imports1 = imports! {
|
let mut imports1 = imports! {
|
||||||
"dog" => {
|
"dog" => {
|
||||||
@@ -458,7 +417,7 @@ mod test {
|
|||||||
"small" => g.clone()
|
"small" => g.clone()
|
||||||
},
|
},
|
||||||
"cat" => {
|
"cat" => {
|
||||||
"small" => g.clone()
|
"small" => g
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -472,62 +431,162 @@ mod test {
|
|||||||
assert!(happy.is_some());
|
assert!(happy.is_some());
|
||||||
assert!(small.is_some());
|
assert!(small.is_some());
|
||||||
}
|
}
|
||||||
|
// fn namespace() {
|
||||||
|
// let mut store = Store::default();
|
||||||
|
// let g1 = Global::new(&store, Val::I32(0));
|
||||||
|
// let namespace = namespace! {
|
||||||
|
// "happy" => g1
|
||||||
|
// };
|
||||||
|
// let imports1 = imports! {
|
||||||
|
// "dog" => namespace
|
||||||
|
// };
|
||||||
|
|
||||||
fn extending_conflict_overwrites() {
|
// let happy_dog_entry = imports1.get_export("dog", "happy").unwrap();
|
||||||
let mut store = Store::default();
|
|
||||||
let g1 = Global::new(&store, Val::I32(0));
|
|
||||||
let g2 = Global::new(&store, Val::F32(0.));
|
|
||||||
|
|
||||||
let mut imports1 = imports! {
|
// assert!(
|
||||||
"dog" => {
|
// if let Export::Global(happy_dog_global) = happy_dog_entry.to_export() {
|
||||||
"happy" => g1,
|
// happy_dog_global.ty.ty == Type::I32
|
||||||
},
|
// } else {
|
||||||
};
|
// false
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
let imports2 = imports! {
|
// fn imports_macro_allows_trailing_comma_and_none() {
|
||||||
"dog" => {
|
// use crate::js::Function;
|
||||||
"happy" => g2,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
imports1.extend(&imports2);
|
// let mut store = Default::default();
|
||||||
let happy_dog_entry = imports1.get_export("dog", "happy").unwrap();
|
|
||||||
|
|
||||||
assert!(
|
// fn func(arg: i32) -> i32 {
|
||||||
if let Export::Global(happy_dog_global) = happy_dog_entry.to_export() {
|
// arg + 1
|
||||||
happy_dog_global.ty.ty == Type::F32
|
// }
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// now test it in reverse
|
// let _ = imports! {
|
||||||
let mut store = Store::default();
|
// "env" => {
|
||||||
let g1 = Global::new(&store, Val::I32(0));
|
// "func" => Function::new_typed(&store, func),
|
||||||
let g2 = Global::new(&store, Val::F32(0.));
|
// },
|
||||||
|
// };
|
||||||
|
// let _ = imports! {
|
||||||
|
// "env" => {
|
||||||
|
// "func" => Function::new_typed(&store, func),
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
// let _ = imports! {
|
||||||
|
// "env" => {
|
||||||
|
// "func" => Function::new_typed(&store, func),
|
||||||
|
// },
|
||||||
|
// "abc" => {
|
||||||
|
// "def" => Function::new_typed(&store, func),
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
// let _ = imports! {
|
||||||
|
// "env" => {
|
||||||
|
// "func" => Function::new_typed(&store, func)
|
||||||
|
// },
|
||||||
|
// };
|
||||||
|
// let _ = imports! {
|
||||||
|
// "env" => {
|
||||||
|
// "func" => Function::new_typed(&store, func)
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
// let _ = imports! {
|
||||||
|
// "env" => {
|
||||||
|
// "func1" => Function::new_typed(&store, func),
|
||||||
|
// "func2" => Function::new_typed(&store, func)
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
// let _ = imports! {
|
||||||
|
// "env" => {
|
||||||
|
// "func1" => Function::new_typed(&store, func),
|
||||||
|
// "func2" => Function::new_typed(&store, func),
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
|
||||||
let imports1 = imports! {
|
// fn chaining_works() {
|
||||||
"dog" => {
|
// let mut store = Store::default();
|
||||||
"happy" => g1,
|
// let g = Global::new(&store, Val::I32(0));
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut imports2 = imports! {
|
// let mut imports1 = imports! {
|
||||||
"dog" => {
|
// "dog" => {
|
||||||
"happy" => g2,
|
// "happy" => g.clone()
|
||||||
},
|
// }
|
||||||
};
|
// };
|
||||||
|
|
||||||
imports2.extend(&imports1);
|
// let imports2 = imports! {
|
||||||
let happy_dog_entry = imports2.get_export("dog", "happy").unwrap();
|
// "dog" => {
|
||||||
|
// "small" => g.clone()
|
||||||
|
// },
|
||||||
|
// "cat" => {
|
||||||
|
// "small" => g.clone()
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
assert!(
|
// imports1.extend(&imports2);
|
||||||
if let Export::Global(happy_dog_global) = happy_dog_entry.to_export() {
|
|
||||||
happy_dog_global.ty.ty == Type::I32
|
// let small_cat_export = imports1.get_export("cat", "small");
|
||||||
} else {
|
// assert!(small_cat_export.is_some());
|
||||||
false
|
|
||||||
}
|
// let happy = imports1.get_export("dog", "happy");
|
||||||
);
|
// let small = imports1.get_export("dog", "small");
|
||||||
}
|
// assert!(happy.is_some());
|
||||||
|
// assert!(small.is_some());
|
||||||
|
// }
|
||||||
|
|
||||||
|
// fn extending_conflict_overwrites() {
|
||||||
|
// let mut store = Store::default();
|
||||||
|
// let g1 = Global::new(&store, Val::I32(0));
|
||||||
|
// let g2 = Global::new(&store, Val::F32(0.));
|
||||||
|
|
||||||
|
// let mut imports1 = imports! {
|
||||||
|
// "dog" => {
|
||||||
|
// "happy" => g1,
|
||||||
|
// },
|
||||||
|
// };
|
||||||
|
|
||||||
|
// let imports2 = imports! {
|
||||||
|
// "dog" => {
|
||||||
|
// "happy" => g2,
|
||||||
|
// },
|
||||||
|
// };
|
||||||
|
|
||||||
|
// imports1.extend(&imports2);
|
||||||
|
// let happy_dog_entry = imports1.get_export("dog", "happy").unwrap();
|
||||||
|
|
||||||
|
// assert!(
|
||||||
|
// if let Export::Global(happy_dog_global) = happy_dog_entry.to_export() {
|
||||||
|
// happy_dog_global.ty.ty == Type::F32
|
||||||
|
// } else {
|
||||||
|
// false
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
|
||||||
|
// // now test it in reverse
|
||||||
|
// let mut store = Store::default();
|
||||||
|
// let g1 = Global::new(&store, Val::I32(0));
|
||||||
|
// let g2 = Global::new(&store, Val::F32(0.));
|
||||||
|
|
||||||
|
// let imports1 = imports! {
|
||||||
|
// "dog" => {
|
||||||
|
// "happy" => g1,
|
||||||
|
// },
|
||||||
|
// };
|
||||||
|
|
||||||
|
// let mut imports2 = imports! {
|
||||||
|
// "dog" => {
|
||||||
|
// "happy" => g2,
|
||||||
|
// },
|
||||||
|
// };
|
||||||
|
|
||||||
|
// imports2.extend(&imports1);
|
||||||
|
// let happy_dog_entry = imports2.get_export("dog", "happy").unwrap();
|
||||||
|
|
||||||
|
// assert!(
|
||||||
|
// if let Export::Global(happy_dog_global) = happy_dog_entry.to_export() {
|
||||||
|
// happy_dog_global.ty.ty == Type::I32
|
||||||
|
// } else {
|
||||||
|
// false
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|||||||
@@ -20,8 +20,6 @@ use std::fmt;
|
|||||||
pub struct Instance {
|
pub struct Instance {
|
||||||
_handle: StoreHandle<WebAssembly::Instance>,
|
_handle: StoreHandle<WebAssembly::Instance>,
|
||||||
module: Module,
|
module: Module,
|
||||||
#[allow(dead_code)]
|
|
||||||
imports: Imports,
|
|
||||||
/// The exports for an instance.
|
/// The exports for an instance.
|
||||||
pub exports: Exports,
|
pub exports: Exports,
|
||||||
}
|
}
|
||||||
@@ -65,12 +63,11 @@ impl Instance {
|
|||||||
module: &Module,
|
module: &Module,
|
||||||
imports: &Imports,
|
imports: &Imports,
|
||||||
) -> Result<Self, InstantiationError> {
|
) -> Result<Self, InstantiationError> {
|
||||||
let import_copy = imports.clone();
|
let instance: WebAssembly::Instance = module
|
||||||
let (instance, _imports): (StoreHandle<WebAssembly::Instance>, Vec<Extern>) = module
|
|
||||||
.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, import_copy)?;
|
let self_instance = Self::from_module_and_instance(store, module, instance)?;
|
||||||
//self_instance.init_envs(&imports.iter().map(Extern::to_export).collect::<Vec<_>>())?;
|
//self_instance.init_envs(&imports.iter().map(Extern::to_export).collect::<Vec<_>>())?;
|
||||||
Ok(self_instance)
|
Ok(self_instance)
|
||||||
}
|
}
|
||||||
@@ -87,10 +84,9 @@ impl Instance {
|
|||||||
pub fn from_module_and_instance(
|
pub fn from_module_and_instance(
|
||||||
mut store: &mut impl AsStoreMut,
|
mut store: &mut impl AsStoreMut,
|
||||||
module: &Module,
|
module: &Module,
|
||||||
instance: StoreHandle<WebAssembly::Instance>,
|
instance: WebAssembly::Instance,
|
||||||
imports: Imports,
|
|
||||||
) -> Result<Self, InstantiationError> {
|
) -> Result<Self, InstantiationError> {
|
||||||
let instance_exports = instance.get(store.as_store_ref().objects()).exports();
|
let instance_exports = instance.exports();
|
||||||
let exports = module
|
let exports = module
|
||||||
.exports()
|
.exports()
|
||||||
.map(|export_type| {
|
.map(|export_type| {
|
||||||
@@ -109,11 +105,10 @@ impl Instance {
|
|||||||
Ok((name.to_string(), extern_))
|
Ok((name.to_string(), extern_))
|
||||||
})
|
})
|
||||||
.collect::<Result<Exports, InstantiationError>>()?;
|
.collect::<Result<Exports, InstantiationError>>()?;
|
||||||
|
let handle = StoreHandle::new(store.as_store_mut().objects_mut(), instance);
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
_handle: instance,
|
_handle: handle,
|
||||||
module: module.clone(),
|
module: module.clone(),
|
||||||
imports,
|
|
||||||
exports,
|
exports,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,8 @@ use crate::js::error::WasmError;
|
|||||||
use crate::js::error::{CompileError, InstantiationError};
|
use crate::js::error::{CompileError, InstantiationError};
|
||||||
#[cfg(feature = "js-serializable-module")]
|
#[cfg(feature = "js-serializable-module")]
|
||||||
use crate::js::error::{DeserializeError, SerializeError};
|
use crate::js::error::{DeserializeError, SerializeError};
|
||||||
use crate::js::externals::Extern;
|
|
||||||
use crate::js::imports::Imports;
|
use crate::js::imports::Imports;
|
||||||
use crate::js::store::{AsStoreMut, StoreHandle};
|
use crate::js::store::AsStoreMut;
|
||||||
use crate::js::types::{AsJs, ExportType, ImportType};
|
use crate::js::types::{AsJs, ExportType, ImportType};
|
||||||
use crate::js::RuntimeError;
|
use crate::js::RuntimeError;
|
||||||
use crate::AsStoreRef;
|
use crate::AsStoreRef;
|
||||||
@@ -222,7 +221,7 @@ impl Module {
|
|||||||
&self,
|
&self,
|
||||||
store: &mut impl AsStoreMut,
|
store: &mut impl AsStoreMut,
|
||||||
imports: &Imports,
|
imports: &Imports,
|
||||||
) -> Result<(StoreHandle<WebAssembly::Instance>, Vec<Extern>), RuntimeError> {
|
) -> Result<WebAssembly::Instance, RuntimeError> {
|
||||||
// Ensure all imports come from the same store.
|
// Ensure all imports come from the same store.
|
||||||
if imports
|
if imports
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@@ -232,46 +231,10 @@ impl Module {
|
|||||||
InstantiationError::DifferentStores,
|
InstantiationError::DifferentStores,
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
let imports_object = js_sys::Object::new();
|
|
||||||
let mut import_externs: Vec<Extern> = vec![];
|
let imports_js_obj = imports.as_jsvalue(store).into();
|
||||||
for import_type in self.imports() {
|
Ok(WebAssembly::Instance::new(&self.module, &imports_js_obj)
|
||||||
let resolved_import = imports.get_export(import_type.module(), import_type.name());
|
.map_err(|e: JsValue| -> RuntimeError { e.into() })?)
|
||||||
if let Some(import) = resolved_import {
|
|
||||||
let val = js_sys::Reflect::get(&imports_object, &import_type.module().into())?;
|
|
||||||
if !val.is_undefined() {
|
|
||||||
// If the namespace is already set
|
|
||||||
js_sys::Reflect::set(
|
|
||||||
&val,
|
|
||||||
&import_type.name().into(),
|
|
||||||
&import.as_jsvalue(&store.as_store_ref()),
|
|
||||||
)?;
|
|
||||||
} else {
|
|
||||||
// If the namespace doesn't exist
|
|
||||||
let import_namespace = js_sys::Object::new();
|
|
||||||
js_sys::Reflect::set(
|
|
||||||
&import_namespace,
|
|
||||||
&import_type.name().into(),
|
|
||||||
&import.as_jsvalue(&store.as_store_ref()),
|
|
||||||
)?;
|
|
||||||
js_sys::Reflect::set(
|
|
||||||
&imports_object,
|
|
||||||
&import_type.module().into(),
|
|
||||||
&import_namespace.into(),
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
import_externs.push(import);
|
|
||||||
}
|
|
||||||
// in case the import is not found, the JS Wasm VM will handle
|
|
||||||
// the error for us, so we don't need to handle it
|
|
||||||
}
|
|
||||||
Ok((
|
|
||||||
StoreHandle::new(
|
|
||||||
store.as_store_mut().objects_mut(),
|
|
||||||
WebAssembly::Instance::new(&self.module, &imports_object)
|
|
||||||
.map_err(|e: JsValue| -> RuntimeError { e.into() })?,
|
|
||||||
),
|
|
||||||
import_externs,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the name of the current module.
|
/// Returns the name of the current module.
|
||||||
|
|||||||
Reference in New Issue
Block a user