mirror of
https://github.com/mii443/wasmer.git
synced 2025-08-29 19:59:27 +00:00
api/sys: Replace ImportObject with new type Imports
This commit is contained in:
@ -1,6 +1,5 @@
|
|||||||
use crate::js::export::Export;
|
use crate::js::export::Export;
|
||||||
use crate::js::externals::{Extern, Function, Global, Memory, Table};
|
use crate::js::externals::{Extern, Function, Global, Memory, Table};
|
||||||
use crate::js::import_object::LikeNamespace;
|
|
||||||
use crate::js::native::NativeFunc;
|
use crate::js::native::NativeFunc;
|
||||||
use crate::js::WasmTypeList;
|
use crate::js::WasmTypeList;
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
@ -193,6 +192,32 @@ impl Exports {
|
|||||||
iter: self.map.iter(),
|
iter: self.map.iter(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// safa
|
||||||
|
pub fn get_namespace_export(&self, name: &str) -> Option<Export> {
|
||||||
|
self.map.get(name).map(|is_export| is_export.to_export())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// safa
|
||||||
|
pub fn get_namespace_externs(&self) -> Vec<(String, Extern)> {
|
||||||
|
self.map
|
||||||
|
.iter()
|
||||||
|
.map(|(k, v)| (k.clone(), v.clone()))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// safa
|
||||||
|
pub fn get_namespace_exports(&self) -> Vec<(String, Export)> {
|
||||||
|
self.map
|
||||||
|
.iter()
|
||||||
|
.map(|(k, v)| (k.clone(), v.to_export()))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// safa
|
||||||
|
pub fn as_exports(&self) -> Option<Exports> {
|
||||||
|
Some(self.clone())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Exports {
|
impl fmt::Debug for Exports {
|
||||||
@ -274,16 +299,21 @@ impl FromIterator<(String, Extern)> for Exports {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LikeNamespace for Exports {
|
impl IntoIterator for Exports {
|
||||||
fn get_namespace_export(&self, name: &str) -> Option<Export> {
|
type IntoIter = std::vec::IntoIter<(String, Extern)>;
|
||||||
self.map.get(name).map(|is_export| is_export.to_export())
|
type Item = (String, Extern);
|
||||||
}
|
|
||||||
|
|
||||||
fn get_namespace_exports(&self) -> Vec<(String, Export)> {
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
self.map
|
self.get_namespace_externs().into_iter()
|
||||||
.iter()
|
}
|
||||||
.map(|(k, v)| (k.clone(), v.to_export()))
|
}
|
||||||
.collect()
|
|
||||||
|
impl IntoIterator for &Exports {
|
||||||
|
type IntoIter = std::vec::IntoIter<(String, Extern)>;
|
||||||
|
type Item = (String, Extern);
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
self.get_namespace_externs().into_iter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,35 +2,25 @@
|
|||||||
//! manipulate and access a wasm module's imports including memories, tables, globals, and
|
//! manipulate and access a wasm module's imports including memories, tables, globals, and
|
||||||
//! functions.
|
//! functions.
|
||||||
use crate::js::export::Export;
|
use crate::js::export::Export;
|
||||||
|
use crate::js::exports::Exportable;
|
||||||
use crate::js::resolver::NamedResolver;
|
use crate::js::resolver::NamedResolver;
|
||||||
|
use crate::Extern;
|
||||||
use std::borrow::{Borrow, BorrowMut};
|
use std::borrow::{Borrow, BorrowMut};
|
||||||
use std::collections::VecDeque;
|
|
||||||
use std::collections::{hash_map::Entry, HashMap};
|
use std::collections::{hash_map::Entry, HashMap};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::sync::{Arc, Mutex};
|
|
||||||
|
|
||||||
/// The `LikeNamespace` trait represents objects that act as a namespace for imports.
|
|
||||||
/// For example, an `Instance` or `Namespace` could be
|
|
||||||
/// considered namespaces that could provide imports to an instance.
|
|
||||||
pub trait LikeNamespace {
|
|
||||||
/// Gets an export by name.
|
|
||||||
fn get_namespace_export(&self, name: &str) -> Option<Export>;
|
|
||||||
/// Gets all exports in the namespace.
|
|
||||||
fn get_namespace_exports(&self) -> Vec<(String, Export)>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// All of the import data used when instantiating.
|
/// All of the import data used when instantiating.
|
||||||
///
|
///
|
||||||
/// It's suggested that you use the [`imports!`] macro
|
/// It's suggested that you use the [`imports!`] macro
|
||||||
/// instead of creating an `ImportObject` by hand.
|
/// instead of creating an `Imports` by hand.
|
||||||
///
|
///
|
||||||
/// [`imports!`]: macro.imports.html
|
/// [`imports!`]: macro.imports.html
|
||||||
///
|
///
|
||||||
/// # Usage:
|
/// # Usage:
|
||||||
/// ```ignore
|
/// ```ignore
|
||||||
/// use wasmer::{Exports, ImportObject, Function};
|
/// use wasmer::{Exports, Imports, Function};
|
||||||
///
|
///
|
||||||
/// let mut import_object = ImportObject::new();
|
/// let mut import_object = Imports::new();
|
||||||
/// let mut env = Exports::new();
|
/// let mut env = Exports::new();
|
||||||
///
|
///
|
||||||
/// env.insert("foo", Function::new_native(foo));
|
/// env.insert("foo", Function::new_native(foo));
|
||||||
@ -41,134 +31,142 @@ pub trait LikeNamespace {
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
pub struct ImportObject {
|
pub struct Imports {
|
||||||
map: Arc<Mutex<HashMap<String, Box<dyn LikeNamespace + Send + Sync>>>>,
|
map: HashMap<(String, String), Extern>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ImportObject {
|
impl Imports {
|
||||||
/// Create a new `ImportObject`.
|
/// Create a new `Imports`.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Default::default()
|
Default::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets an export given a module and a name
|
/// Gets an export given a ns and a name
|
||||||
///
|
///
|
||||||
/// # Usage
|
/// # Usage
|
||||||
/// ```ignore
|
/// ```ignore
|
||||||
/// # use wasmer::{ImportObject, Instance, Namespace};
|
/// # use wasmer::{Imports, Instance, Namespace};
|
||||||
/// let mut import_object = ImportObject::new();
|
/// let mut import_object = Imports::new();
|
||||||
/// import_object.get_export("module", "name");
|
/// import_object.get_export("ns", "name");
|
||||||
/// ```
|
/// ```
|
||||||
pub fn get_export(&self, module: &str, name: &str) -> Option<Export> {
|
pub fn get_export(&self, ns: &str, name: &str) -> Option<Export> {
|
||||||
let guard = self.map.lock().unwrap();
|
if self.map.contains_key(&(ns.to_string(), name.to_string())) {
|
||||||
let map_ref = guard.borrow();
|
let ext = &self.map[&(ns.to_string(), name.to_string())];
|
||||||
if map_ref.contains_key(module) {
|
return Some(ext.to_export());
|
||||||
let namespace = map_ref[module].as_ref();
|
|
||||||
return namespace.get_namespace_export(name);
|
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the ImportObject contains namespace with the provided name.
|
/// Returns true if the Imports contains namespace with the provided name.
|
||||||
pub fn contains_namespace(&self, name: &str) -> bool {
|
pub fn contains_namespace(&self, name: &str) -> bool {
|
||||||
self.map.lock().unwrap().borrow().contains_key(name)
|
self.map.keys().any(|(k, _)| (k == name))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Register anything that implements `LikeNamespace` as a namespace.
|
/// TODO: Add doc
|
||||||
///
|
pub fn register_namespace(
|
||||||
/// # Usage:
|
&mut self,
|
||||||
/// ```ignore
|
ns: &str,
|
||||||
/// # use wasmer::{ImportObject, Instance, Namespace};
|
contents: impl IntoIterator<Item = (String, Extern)>,
|
||||||
/// let mut import_object = ImportObject::new();
|
) {
|
||||||
///
|
for (name, extern_) in contents.into_iter() {
|
||||||
/// import_object.register("namespace0", instance);
|
self.map.insert((ns.to_string(), name.clone()), extern_);
|
||||||
/// import_object.register("namespace1", namespace);
|
|
||||||
/// // ...
|
|
||||||
/// ```
|
|
||||||
pub fn register<S, N>(&mut self, name: S, namespace: N) -> Option<Box<dyn LikeNamespace>>
|
|
||||||
where
|
|
||||||
S: Into<String>,
|
|
||||||
N: LikeNamespace + Send + Sync + 'static,
|
|
||||||
{
|
|
||||||
let mut guard = self.map.lock().unwrap();
|
|
||||||
let map = guard.borrow_mut();
|
|
||||||
|
|
||||||
match map.entry(name.into()) {
|
|
||||||
Entry::Vacant(empty) => {
|
|
||||||
empty.insert(Box::new(namespace));
|
|
||||||
None
|
|
||||||
}
|
|
||||||
Entry::Occupied(mut occupied) => Some(occupied.insert(Box::new(namespace))),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_objects(&self) -> VecDeque<((String, String), Export)> {
|
/// TODO: Add doc
|
||||||
let mut out = VecDeque::new();
|
pub fn define(&mut self, ns: &str, name: &str, extern_: Extern) {
|
||||||
let guard = self.map.lock().unwrap();
|
self.map.insert((ns.to_string(), name.to_string()), extern_);
|
||||||
let map = guard.borrow();
|
|
||||||
for (name, ns) in map.iter() {
|
|
||||||
for (id, exp) in ns.get_namespace_exports() {
|
|
||||||
out.push_back(((name.clone(), id), exp));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the `ImportObject` as a Javascript `Object`
|
// /// Register anything that implements `LikeNamespace` as a namespace.
|
||||||
|
// ///
|
||||||
|
// /// # Usage:
|
||||||
|
// /// ```ignore
|
||||||
|
// /// # use wasmer::{Imports, Instance, Namespace};
|
||||||
|
// /// let mut import_object = Imports::new();
|
||||||
|
// ///
|
||||||
|
// /// import_object.register("namespace0", instance);
|
||||||
|
// /// import_object.register("namespace1", namespace);
|
||||||
|
// /// // ...
|
||||||
|
// /// ```
|
||||||
|
// pub fn register<S, N>(&mut self, name: S, namespace: N) -> Option<Box<dyn LikeNamespace>>
|
||||||
|
// where
|
||||||
|
// S: Into<String>,
|
||||||
|
// N: LikeNamespace + Send + Sync + 'static,
|
||||||
|
// {
|
||||||
|
// let mut guard = self.map.lock().unwrap();
|
||||||
|
// let map = guard.borrow_mut();
|
||||||
|
|
||||||
|
// match map.entry(name.into()) {
|
||||||
|
// Entry::Vacant(empty) => {
|
||||||
|
// empty.insert(Box::new(namespace));
|
||||||
|
// None
|
||||||
|
// }
|
||||||
|
// Entry::Occupied(mut occupied) => Some(occupied.insert(Box::new(namespace))),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
/// asdfsa
|
||||||
|
pub fn resolve_by_name(&self, ns: &str, name: &str) -> Option<Export> {
|
||||||
|
self.get_export(ns, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
//fn iter(&self) -> impl Iterator<(&str, &str, Extern)> {
|
||||||
|
// todo!()
|
||||||
|
//}
|
||||||
|
|
||||||
|
/// Returns the `Imports` as a Javascript `Object`
|
||||||
pub fn as_jsobject(&self) -> js_sys::Object {
|
pub fn as_jsobject(&self) -> js_sys::Object {
|
||||||
let guard = self.map.lock().expect("Can't get the map");
|
|
||||||
let map = guard.borrow();
|
|
||||||
|
|
||||||
let imports = js_sys::Object::new();
|
let imports = js_sys::Object::new();
|
||||||
for (module, ns) in map.iter() {
|
let namespaces: HashMap<&str, Vec<(&str, &Extern)>> =
|
||||||
|
self.map
|
||||||
|
.iter()
|
||||||
|
.fold(HashMap::default(), |mut acc, ((ns, name), ext)| {
|
||||||
|
acc.entry(ns.as_str())
|
||||||
|
.or_default()
|
||||||
|
.push((name.as_str(), ext));
|
||||||
|
acc
|
||||||
|
});
|
||||||
|
|
||||||
|
for (ns, exports) in namespaces.into_iter() {
|
||||||
let import_namespace = js_sys::Object::new();
|
let import_namespace = js_sys::Object::new();
|
||||||
for (name, exp) in ns.get_namespace_exports() {
|
for (name, ext) in exports {
|
||||||
js_sys::Reflect::set(&import_namespace, &name.into(), exp.as_jsvalue())
|
js_sys::Reflect::set(
|
||||||
.expect("Error while setting into the js namespace object");
|
&import_namespace,
|
||||||
|
&name.into(),
|
||||||
|
ext.to_export().as_jsvalue(),
|
||||||
|
)
|
||||||
|
.expect("Error while setting into the js namespace object");
|
||||||
}
|
}
|
||||||
js_sys::Reflect::set(&imports, &module.into(), &import_namespace.into())
|
js_sys::Reflect::set(&imports, &ns.into(), &import_namespace.into())
|
||||||
.expect("Error while setting into the js imports object");
|
.expect("Error while setting into the js imports object");
|
||||||
}
|
}
|
||||||
imports
|
imports
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<js_sys::Object> for ImportObject {
|
impl Into<js_sys::Object> for Imports {
|
||||||
fn into(self) -> js_sys::Object {
|
fn into(self) -> js_sys::Object {
|
||||||
self.as_jsobject()
|
self.as_jsobject()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NamedResolver for ImportObject {
|
impl NamedResolver for Imports {
|
||||||
fn resolve_by_name(&self, module: &str, name: &str) -> Option<Export> {
|
fn resolve_by_name(&self, ns: &str, name: &str) -> Option<Export> {
|
||||||
self.get_export(module, name)
|
self.get_export(ns, name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterator for an `ImportObject`'s exports.
|
impl IntoIterator for &Imports {
|
||||||
pub struct ImportObjectIterator {
|
type IntoIter = std::collections::hash_map::IntoIter<(String, String), Extern>;
|
||||||
elements: VecDeque<((String, String), Export)>,
|
type Item = ((String, String), Extern);
|
||||||
}
|
|
||||||
|
|
||||||
impl Iterator for ImportObjectIterator {
|
|
||||||
type Item = ((String, String), Export);
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
self.elements.pop_front()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IntoIterator for ImportObject {
|
|
||||||
type IntoIter = ImportObjectIterator;
|
|
||||||
type Item = ((String, String), Export);
|
|
||||||
|
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
ImportObjectIterator {
|
self.map.clone().into_iter()
|
||||||
elements: self.get_objects(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for ImportObject {
|
impl fmt::Debug for Imports {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
enum SecretMap {
|
enum SecretMap {
|
||||||
Empty,
|
Empty,
|
||||||
@ -194,20 +192,17 @@ impl fmt::Debug for ImportObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
f.debug_struct("ImportObject")
|
f.debug_struct("Imports")
|
||||||
.field(
|
.field("map", &SecretMap::new(self.map.len()))
|
||||||
"map",
|
|
||||||
&SecretMap::new(self.map.lock().unwrap().borrow().len()),
|
|
||||||
)
|
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The import! macro for ImportObject
|
// The import! macro for Imports
|
||||||
|
|
||||||
/// Generate an [`ImportObject`] easily with the `imports!` macro.
|
/// Generate an [`Imports`] easily with the `imports!` macro.
|
||||||
///
|
///
|
||||||
/// [`ImportObject`]: struct.ImportObject.html
|
/// [`Imports`]: struct.Imports.html
|
||||||
///
|
///
|
||||||
/// # Usage
|
/// # Usage
|
||||||
///
|
///
|
||||||
@ -230,12 +225,12 @@ impl fmt::Debug for ImportObject {
|
|||||||
macro_rules! imports {
|
macro_rules! imports {
|
||||||
( $( $ns_name:expr => $ns:tt ),* $(,)? ) => {
|
( $( $ns_name:expr => $ns:tt ),* $(,)? ) => {
|
||||||
{
|
{
|
||||||
let mut import_object = $crate::ImportObject::new();
|
let mut import_object = $crate::Imports::new();
|
||||||
|
|
||||||
$({
|
$({
|
||||||
let namespace = $crate::import_namespace!($ns);
|
let namespace = $crate::import_namespace!($ns);
|
||||||
|
|
||||||
import_object.register($ns_name, namespace);
|
import_object.register_namespace($ns_name, namespace);
|
||||||
})*
|
})*
|
||||||
|
|
||||||
import_object
|
import_object
|
@ -28,7 +28,7 @@ mod error;
|
|||||||
mod export;
|
mod export;
|
||||||
mod exports;
|
mod exports;
|
||||||
mod externals;
|
mod externals;
|
||||||
mod import_object;
|
mod imports;
|
||||||
mod instance;
|
mod instance;
|
||||||
mod js_import_object;
|
mod js_import_object;
|
||||||
mod mem_access;
|
mod mem_access;
|
||||||
@ -56,7 +56,7 @@ pub use crate::js::externals::{
|
|||||||
Extern, FromToNativeWasmType, Function, Global, HostFunction, Memory, MemoryError, Table,
|
Extern, FromToNativeWasmType, Function, Global, HostFunction, Memory, MemoryError, Table,
|
||||||
WasmTypeList,
|
WasmTypeList,
|
||||||
};
|
};
|
||||||
pub use crate::js::import_object::{ImportObject, ImportObjectIterator, LikeNamespace};
|
pub use crate::js::imports::Imports;
|
||||||
pub use crate::js::instance::{Instance, InstantiationError};
|
pub use crate::js::instance::{Instance, InstantiationError};
|
||||||
pub use crate::js::js_import_object::JsImportObject;
|
pub use crate::js::js_import_object::JsImportObject;
|
||||||
pub use crate::js::mem_access::{MemoryAccessError, WasmRef, WasmSlice, WasmSliceIter};
|
pub use crate::js::mem_access::{MemoryAccessError, WasmRef, WasmSlice, WasmSliceIter};
|
||||||
|
@ -156,8 +156,8 @@
|
|||||||
//! [`imports`] macro:
|
//! [`imports`] macro:
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//! # use wasmer::{imports, Function, Memory, MemoryType, Store, ImportObject};
|
//! # use wasmer::{imports, Function, Memory, MemoryType, Store, Imports};
|
||||||
//! # fn imports_example(store: &Store) -> ImportObject {
|
//! # fn imports_example(store: &Store) -> Imports {
|
||||||
//! let memory = Memory::new(&store, MemoryType::new(1, None, false)).unwrap();
|
//! let memory = Memory::new(&store, MemoryType::new(1, None, false)).unwrap();
|
||||||
//! imports! {
|
//! imports! {
|
||||||
//! "env" => {
|
//! "env" => {
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
use crate::sys::externals::{Extern, Function, Global, Memory, Table};
|
use crate::sys::externals::{Extern, Function, Global, Memory, Table};
|
||||||
use crate::sys::import_object::LikeNamespace;
|
|
||||||
use crate::sys::native::NativeFunc;
|
use crate::sys::native::NativeFunc;
|
||||||
use crate::sys::WasmTypeList;
|
use crate::sys::WasmTypeList;
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
@ -276,20 +275,21 @@ impl FromIterator<(String, Extern)> for Exports {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LikeNamespace for Exports {
|
impl IntoIterator for Exports {
|
||||||
fn get_namespace_export(&self, name: &str) -> Option<Export> {
|
type IntoIter = indexmap::map::IntoIter<String, Extern>;
|
||||||
self.map.get(name).map(|is_export| is_export.to_export())
|
type Item = (String, Extern);
|
||||||
}
|
|
||||||
|
|
||||||
fn get_namespace_exports(&self) -> Vec<(String, Export)> {
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
self.map
|
self.map.clone().into_iter()
|
||||||
.iter()
|
|
||||||
.map(|(k, v)| (k.clone(), v.to_export()))
|
|
||||||
.collect()
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn as_exports(&self) -> Option<Exports> {
|
impl<'a> IntoIterator for &'a Exports {
|
||||||
Some(self.clone())
|
type IntoIter = indexmap::map::Iter<'a, String, Extern>;
|
||||||
|
type Item = (&'a String, &'a Extern);
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
self.map.iter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,445 +0,0 @@
|
|||||||
//! The import module contains the implementation data structures and helper functions used to
|
|
||||||
//! manipulate and access a wasm module's imports including memories, tables, globals, and
|
|
||||||
//! functions.
|
|
||||||
use crate::Exports;
|
|
||||||
use crate::Extern;
|
|
||||||
use std::borrow::{Borrow, BorrowMut};
|
|
||||||
use std::collections::VecDeque;
|
|
||||||
use std::collections::{hash_map::Entry, HashMap};
|
|
||||||
use std::fmt;
|
|
||||||
use std::sync::{Arc, Mutex};
|
|
||||||
use wasmer_engine::{Export, NamedResolver};
|
|
||||||
|
|
||||||
/// The `LikeNamespace` trait represents objects that act as a namespace for imports.
|
|
||||||
/// For example, an `Instance` or `Namespace` could be
|
|
||||||
/// considered namespaces that could provide imports to an instance.
|
|
||||||
pub trait LikeNamespace {
|
|
||||||
/// Gets an export by name.
|
|
||||||
fn get_namespace_export(&self, name: &str) -> Option<Export>;
|
|
||||||
/// Gets all exports in the namespace.
|
|
||||||
fn get_namespace_exports(&self) -> Vec<(String, Export)>;
|
|
||||||
/// Returns the contents of this namespace as an `Exports`.
|
|
||||||
///
|
|
||||||
/// This is used by `ImportObject::get_namespace_exports`.
|
|
||||||
fn as_exports(&self) -> Option<Exports> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// All of the import data used when instantiating.
|
|
||||||
///
|
|
||||||
/// It's suggested that you use the [`imports!`] macro
|
|
||||||
/// instead of creating an `ImportObject` by hand.
|
|
||||||
///
|
|
||||||
/// [`imports!`]: macro.imports.html
|
|
||||||
///
|
|
||||||
/// # Usage:
|
|
||||||
/// ```ignore
|
|
||||||
/// use wasmer::{Exports, ImportObject, Function};
|
|
||||||
///
|
|
||||||
/// let mut import_object = ImportObject::new();
|
|
||||||
/// let mut env = Exports::new();
|
|
||||||
///
|
|
||||||
/// env.insert("foo", Function::new_native(foo));
|
|
||||||
/// import_object.register("env", env);
|
|
||||||
///
|
|
||||||
/// fn foo(n: i32) -> i32 {
|
|
||||||
/// n
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
#[derive(Clone, Default)]
|
|
||||||
pub struct ImportObject {
|
|
||||||
map: Arc<Mutex<HashMap<String, Box<dyn LikeNamespace + Send + Sync>>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ImportObject {
|
|
||||||
/// Create a new `ImportObject`.
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Default::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets an export given a module and a name
|
|
||||||
///
|
|
||||||
/// # Usage
|
|
||||||
/// ```ignore
|
|
||||||
/// # use wasmer_vm::{ImportObject, Instance, Namespace};
|
|
||||||
/// let mut import_object = ImportObject::new();
|
|
||||||
/// import_object.get_export("module", "name");
|
|
||||||
/// ```
|
|
||||||
pub fn get_export(&self, module: &str, name: &str) -> Option<Export> {
|
|
||||||
let guard = self.map.lock().unwrap();
|
|
||||||
let map_ref = guard.borrow();
|
|
||||||
if map_ref.contains_key(module) {
|
|
||||||
let namespace = map_ref[module].as_ref();
|
|
||||||
return namespace.get_namespace_export(name);
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if the ImportObject contains namespace with the provided name.
|
|
||||||
pub fn contains_namespace(&self, name: &str) -> bool {
|
|
||||||
self.map.lock().unwrap().borrow().contains_key(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Register anything that implements `LikeNamespace` as a namespace.
|
|
||||||
///
|
|
||||||
/// # Usage:
|
|
||||||
/// ```ignore
|
|
||||||
/// # use wasmer_vm::{ImportObject, Instance, Namespace};
|
|
||||||
/// let mut import_object = ImportObject::new();
|
|
||||||
///
|
|
||||||
/// import_object.register("namespace0", instance);
|
|
||||||
/// import_object.register("namespace1", namespace);
|
|
||||||
/// // ...
|
|
||||||
/// ```
|
|
||||||
pub fn register<S, N>(&mut self, name: S, namespace: N) -> Option<Box<dyn LikeNamespace>>
|
|
||||||
where
|
|
||||||
S: Into<String>,
|
|
||||||
N: LikeNamespace + Send + Sync + 'static,
|
|
||||||
{
|
|
||||||
let mut guard = self.map.lock().unwrap();
|
|
||||||
let map = guard.borrow_mut();
|
|
||||||
|
|
||||||
match map.entry(name.into()) {
|
|
||||||
Entry::Vacant(empty) => {
|
|
||||||
empty.insert(Box::new(namespace));
|
|
||||||
None
|
|
||||||
}
|
|
||||||
Entry::Occupied(mut occupied) => Some(occupied.insert(Box::new(namespace))),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the contents of a namespace as an `Exports`.
|
|
||||||
///
|
|
||||||
/// Returns `None` if the namespace doesn't exist or doesn't implement the
|
|
||||||
/// `as_exports` method.
|
|
||||||
pub fn get_namespace_exports(&self, name: &str) -> Option<Exports> {
|
|
||||||
let map = self.map.lock().unwrap();
|
|
||||||
map.get(name).and_then(|ns| ns.as_exports())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a list of all externs defined in all namespaces.
|
|
||||||
pub fn externs_vec(&self) -> Vec<(String, String, Extern)> {
|
|
||||||
let mut out = Vec::new();
|
|
||||||
let guard = self.map.lock().unwrap();
|
|
||||||
let map = guard.borrow();
|
|
||||||
for (namespace, ns) in map.iter() {
|
|
||||||
match ns.as_exports() {
|
|
||||||
Some(exports) => {
|
|
||||||
for (name, extern_) in exports.iter() {
|
|
||||||
out.push((namespace.clone(), name.clone(), extern_.clone()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_objects(&self) -> VecDeque<((String, String), Export)> {
|
|
||||||
let mut out = VecDeque::new();
|
|
||||||
let guard = self.map.lock().unwrap();
|
|
||||||
let map = guard.borrow();
|
|
||||||
for (name, ns) in map.iter() {
|
|
||||||
for (id, exp) in ns.get_namespace_exports() {
|
|
||||||
out.push_back(((name.clone(), id), exp));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NamedResolver for ImportObject {
|
|
||||||
fn resolve_by_name(&self, module: &str, name: &str) -> Option<Export> {
|
|
||||||
self.get_export(module, name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Iterator for an `ImportObject`'s exports.
|
|
||||||
pub struct ImportObjectIterator {
|
|
||||||
elements: VecDeque<((String, String), Export)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Iterator for ImportObjectIterator {
|
|
||||||
type Item = ((String, String), Export);
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
self.elements.pop_front()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IntoIterator for ImportObject {
|
|
||||||
type IntoIter = ImportObjectIterator;
|
|
||||||
type Item = ((String, String), Export);
|
|
||||||
|
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
|
||||||
ImportObjectIterator {
|
|
||||||
elements: self.get_objects(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for ImportObject {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
enum SecretMap {
|
|
||||||
Empty,
|
|
||||||
Some(usize),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SecretMap {
|
|
||||||
fn new(len: usize) -> Self {
|
|
||||||
if len == 0 {
|
|
||||||
Self::Empty
|
|
||||||
} else {
|
|
||||||
Self::Some(len)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for SecretMap {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
Self::Empty => write!(f, "(empty)"),
|
|
||||||
Self::Some(len) => write!(f, "(... {} item(s) ...)", len),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
f.debug_struct("ImportObject")
|
|
||||||
.field(
|
|
||||||
"map",
|
|
||||||
&SecretMap::new(self.map.lock().unwrap().borrow().len()),
|
|
||||||
)
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The import! macro for ImportObject
|
|
||||||
|
|
||||||
/// Generate an [`ImportObject`] easily with the `imports!` macro.
|
|
||||||
///
|
|
||||||
/// [`ImportObject`]: struct.ImportObject.html
|
|
||||||
///
|
|
||||||
/// # Usage
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use wasmer::{Function, Store};
|
|
||||||
/// # let store = Store::default();
|
|
||||||
/// use wasmer::imports;
|
|
||||||
///
|
|
||||||
/// let import_object = imports! {
|
|
||||||
/// "env" => {
|
|
||||||
/// "foo" => Function::new_native(&store, foo)
|
|
||||||
/// },
|
|
||||||
/// };
|
|
||||||
///
|
|
||||||
/// fn foo(n: i32) -> i32 {
|
|
||||||
/// n
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! imports {
|
|
||||||
( $( $ns_name:expr => $ns:tt ),* $(,)? ) => {
|
|
||||||
{
|
|
||||||
let mut import_object = $crate::ImportObject::new();
|
|
||||||
|
|
||||||
$({
|
|
||||||
let namespace = $crate::import_namespace!($ns);
|
|
||||||
|
|
||||||
import_object.register($ns_name, namespace);
|
|
||||||
})*
|
|
||||||
|
|
||||||
import_object
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
#[doc(hidden)]
|
|
||||||
macro_rules! namespace {
|
|
||||||
($( $import_name:expr => $import_item:expr ),* $(,)? ) => {
|
|
||||||
$crate::import_namespace!( { $( $import_name => $import_item, )* } )
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
#[doc(hidden)]
|
|
||||||
macro_rules! import_namespace {
|
|
||||||
( { $( $import_name:expr => $import_item:expr ),* $(,)? } ) => {{
|
|
||||||
let mut namespace = $crate::Exports::new();
|
|
||||||
|
|
||||||
$(
|
|
||||||
namespace.insert($import_name, $import_item);
|
|
||||||
)*
|
|
||||||
|
|
||||||
namespace
|
|
||||||
}};
|
|
||||||
|
|
||||||
( $namespace:ident ) => {
|
|
||||||
$namespace
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
use crate::sys::{Global, Store, Val};
|
|
||||||
use wasmer_engine::ChainableNamedResolver;
|
|
||||||
use wasmer_types::Type;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn chaining_works() {
|
|
||||||
let store = Store::default();
|
|
||||||
let g = Global::new(&store, Val::I32(0));
|
|
||||||
|
|
||||||
let imports1 = imports! {
|
|
||||||
"dog" => {
|
|
||||||
"happy" => g.clone()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let imports2 = imports! {
|
|
||||||
"dog" => {
|
|
||||||
"small" => g.clone()
|
|
||||||
},
|
|
||||||
"cat" => {
|
|
||||||
"small" => g.clone()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let resolver = imports1.chain_front(imports2);
|
|
||||||
|
|
||||||
let small_cat_export = resolver.resolve_by_name("cat", "small");
|
|
||||||
assert!(small_cat_export.is_some());
|
|
||||||
|
|
||||||
let happy = resolver.resolve_by_name("dog", "happy");
|
|
||||||
let small = resolver.resolve_by_name("dog", "small");
|
|
||||||
assert!(happy.is_some());
|
|
||||||
assert!(small.is_some());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn extending_conflict_overwrites() {
|
|
||||||
let store = Store::default();
|
|
||||||
let g1 = Global::new(&store, Val::I32(0));
|
|
||||||
let g2 = Global::new(&store, Val::I64(0));
|
|
||||||
|
|
||||||
let imports1 = imports! {
|
|
||||||
"dog" => {
|
|
||||||
"happy" => g1,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let imports2 = imports! {
|
|
||||||
"dog" => {
|
|
||||||
"happy" => g2,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let resolver = imports1.chain_front(imports2);
|
|
||||||
let happy_dog_entry = resolver.resolve_by_name("dog", "happy").unwrap();
|
|
||||||
|
|
||||||
assert!(if let Export::Global(happy_dog_global) = happy_dog_entry {
|
|
||||||
happy_dog_global.from.ty().ty == Type::I64
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
});
|
|
||||||
|
|
||||||
// now test it in reverse
|
|
||||||
let store = Store::default();
|
|
||||||
let g1 = Global::new(&store, Val::I32(0));
|
|
||||||
let g2 = Global::new(&store, Val::I64(0));
|
|
||||||
|
|
||||||
let imports1 = imports! {
|
|
||||||
"dog" => {
|
|
||||||
"happy" => g1,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let imports2 = imports! {
|
|
||||||
"dog" => {
|
|
||||||
"happy" => g2,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let resolver = imports1.chain_back(imports2);
|
|
||||||
let happy_dog_entry = resolver.resolve_by_name("dog", "happy").unwrap();
|
|
||||||
|
|
||||||
assert!(if let Export::Global(happy_dog_global) = happy_dog_entry {
|
|
||||||
happy_dog_global.from.ty().ty == Type::I32
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn namespace() {
|
|
||||||
let 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.resolve_by_name("dog", "happy").unwrap();
|
|
||||||
|
|
||||||
assert!(if let Export::Global(happy_dog_global) = happy_dog_entry {
|
|
||||||
happy_dog_global.from.ty().ty == Type::I32
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn imports_macro_allows_trailing_comma_and_none() {
|
|
||||||
use crate::sys::Function;
|
|
||||||
|
|
||||||
let store = Default::default();
|
|
||||||
|
|
||||||
fn func(arg: i32) -> i32 {
|
|
||||||
arg + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
let _ = imports! {
|
|
||||||
"env" => {
|
|
||||||
"func" => Function::new_native(&store, func),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
let _ = imports! {
|
|
||||||
"env" => {
|
|
||||||
"func" => Function::new_native(&store, func),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let _ = imports! {
|
|
||||||
"env" => {
|
|
||||||
"func" => Function::new_native(&store, func),
|
|
||||||
},
|
|
||||||
"abc" => {
|
|
||||||
"def" => Function::new_native(&store, func),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let _ = imports! {
|
|
||||||
"env" => {
|
|
||||||
"func" => Function::new_native(&store, func)
|
|
||||||
},
|
|
||||||
};
|
|
||||||
let _ = imports! {
|
|
||||||
"env" => {
|
|
||||||
"func" => Function::new_native(&store, func)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let _ = imports! {
|
|
||||||
"env" => {
|
|
||||||
"func1" => Function::new_native(&store, func),
|
|
||||||
"func2" => Function::new_native(&store, func)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let _ = imports! {
|
|
||||||
"env" => {
|
|
||||||
"func1" => Function::new_native(&store, func),
|
|
||||||
"func2" => Function::new_native(&store, func),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
436
lib/api/src/sys/imports.rs
Normal file
436
lib/api/src/sys/imports.rs
Normal file
@ -0,0 +1,436 @@
|
|||||||
|
//! The import module contains the implementation data structures and helper functions used to
|
||||||
|
//! manipulate and access a wasm module's imports including memories, tables, globals, and
|
||||||
|
//! functions.
|
||||||
|
use crate::{Exports, Extern, Module};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::fmt;
|
||||||
|
use wasmer_engine::{ImportError, LinkError};
|
||||||
|
|
||||||
|
/// All of the import data used when instantiating.
|
||||||
|
///
|
||||||
|
/// It's suggested that you use the [`imports!`] macro
|
||||||
|
/// instead of creating an `Imports` by hand.
|
||||||
|
///
|
||||||
|
/// [`imports!`]: macro.imports.html
|
||||||
|
///
|
||||||
|
/// # Usage:
|
||||||
|
/// ```no_run
|
||||||
|
/// use wasmer::{Exports, Module, Store, Instance, imports, Imports, Function};
|
||||||
|
/// # fn foo_test(module: Module, store: Store) {
|
||||||
|
///
|
||||||
|
/// let host_fn = Function::new_native(&store, foo);
|
||||||
|
/// let import_object: Imports = imports! {
|
||||||
|
/// "env" => {
|
||||||
|
/// "foo" => host_fn,
|
||||||
|
/// },
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// let instance = Instance::new(&module, &import_object).expect("Could not instantiate module.");
|
||||||
|
///
|
||||||
|
/// fn foo(n: i32) -> i32 {
|
||||||
|
/// n
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
#[derive(Clone, Default)]
|
||||||
|
pub struct Imports {
|
||||||
|
map: HashMap<(String, String), Extern>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Imports {
|
||||||
|
/// Create a new `Imports`.
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Default::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets an export given a module and a name
|
||||||
|
///
|
||||||
|
/// # Usage
|
||||||
|
/// ```no_run
|
||||||
|
/// # use wasmer::Imports;
|
||||||
|
/// let mut import_object = Imports::new();
|
||||||
|
/// import_object.get_export("module", "name");
|
||||||
|
/// ```
|
||||||
|
pub fn get_export(&self, module: &str, name: &str) -> Option<Extern> {
|
||||||
|
if self
|
||||||
|
.map
|
||||||
|
.contains_key(&(module.to_string(), name.to_string()))
|
||||||
|
{
|
||||||
|
let ext = &self.map[&(module.to_string(), name.to_string())];
|
||||||
|
return Some(ext.clone());
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if the Imports contains namespace with the provided name.
|
||||||
|
pub fn contains_namespace(&self, name: &str) -> bool {
|
||||||
|
self.map.keys().any(|(k, _)| (k == name))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Register a list of externs into a namespace.
|
||||||
|
///
|
||||||
|
/// # Usage:
|
||||||
|
/// ```no_run
|
||||||
|
/// # use wasmer::{Imports, Exports, Memory};
|
||||||
|
/// # fn foo_test(memory: Memory) {
|
||||||
|
/// let mut exports = Exports::new();
|
||||||
|
/// exports.insert("memory", memory);
|
||||||
|
///
|
||||||
|
/// let mut import_object = Imports::new();
|
||||||
|
/// import_object.register_namespace("env", exports);
|
||||||
|
/// // ...
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
pub fn register_namespace(
|
||||||
|
&mut self,
|
||||||
|
ns: &str,
|
||||||
|
contents: impl IntoIterator<Item = (String, Extern)>,
|
||||||
|
) {
|
||||||
|
for (name, extern_) in contents.into_iter() {
|
||||||
|
self.map.insert((ns.to_string(), name.clone()), extern_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a single import with a namespace `ns` and name `name`.
|
||||||
|
///
|
||||||
|
/// # Usage
|
||||||
|
/// ```no_run
|
||||||
|
/// # let store = Default::default();
|
||||||
|
/// use wasmer::{Imports, Function};
|
||||||
|
/// fn foo(n: i32) -> i32 {
|
||||||
|
/// n
|
||||||
|
/// }
|
||||||
|
/// let mut import_object = Imports::new();
|
||||||
|
/// import_object.define("env", "foo", Function::new_native(&store, foo));
|
||||||
|
/// ```
|
||||||
|
pub fn define(&mut self, ns: &str, name: &str, val: impl Into<Extern>) {
|
||||||
|
self.map
|
||||||
|
.insert((ns.to_string(), name.to_string()), val.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the contents of a namespace as an `Exports`.
|
||||||
|
///
|
||||||
|
/// Returns `None` if the namespace doesn't exist.
|
||||||
|
pub fn get_namespace_exports(&self, name: &str) -> Option<Exports> {
|
||||||
|
let ret: Exports = self
|
||||||
|
.map
|
||||||
|
.iter()
|
||||||
|
.filter(|((ns, _), _)| ns == name)
|
||||||
|
.map(|((_, name), e)| (name.clone(), e.clone()))
|
||||||
|
.collect();
|
||||||
|
if ret.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(ret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resolve and return a vector of imports in the order they are defined in the `module`'s source code.
|
||||||
|
///
|
||||||
|
/// This means the returned `Vec<Extern>` might be a subset of the imports contained in `self`.
|
||||||
|
pub fn imports_for_module(&self, module: &Module) -> Result<Vec<Extern>, LinkError> {
|
||||||
|
let mut ret = vec![];
|
||||||
|
for import in module.imports() {
|
||||||
|
if let Some(imp) = self
|
||||||
|
.map
|
||||||
|
.get(&(import.module().to_string(), import.name().to_string()))
|
||||||
|
{
|
||||||
|
ret.push(imp.clone());
|
||||||
|
} else {
|
||||||
|
return Err(LinkError::Import(
|
||||||
|
import.module().to_string(),
|
||||||
|
import.name().to_string(),
|
||||||
|
ImportError::UnknownImport(import.ty().clone()),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(ret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoIterator for &Imports {
|
||||||
|
type IntoIter = std::collections::hash_map::IntoIter<(String, String), Extern>;
|
||||||
|
type Item = ((String, String), Extern);
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
self.map.clone().into_iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Extend<((String, String), Extern)> for Imports {
|
||||||
|
fn extend<T: IntoIterator<Item = ((String, String), Extern)>>(&mut self, iter: T) {
|
||||||
|
for ((ns, name), ext) in iter.into_iter() {
|
||||||
|
self.define(&ns, &name, ext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for Imports {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
enum SecretMap {
|
||||||
|
Empty,
|
||||||
|
Some(usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SecretMap {
|
||||||
|
fn new(len: usize) -> Self {
|
||||||
|
if len == 0 {
|
||||||
|
Self::Empty
|
||||||
|
} else {
|
||||||
|
Self::Some(len)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for SecretMap {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Empty => write!(f, "(empty)"),
|
||||||
|
Self::Some(len) => write!(f, "(... {} item(s) ...)", len),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
f.debug_struct("Imports")
|
||||||
|
.field("map", &SecretMap::new(self.map.len()))
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The import! macro for Imports
|
||||||
|
|
||||||
|
/// Generate an [`Imports`] easily with the `imports!` macro.
|
||||||
|
///
|
||||||
|
/// [`Imports`]: struct.Imports.html
|
||||||
|
///
|
||||||
|
/// # Usage
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use wasmer::{Function, Store};
|
||||||
|
/// # let store = Store::default();
|
||||||
|
/// use wasmer::imports;
|
||||||
|
///
|
||||||
|
/// let import_object = imports! {
|
||||||
|
/// "env" => {
|
||||||
|
/// "foo" => Function::new_native(&store, foo)
|
||||||
|
/// },
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// fn foo(n: i32) -> i32 {
|
||||||
|
/// n
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! imports {
|
||||||
|
( $( $ns_name:expr => $ns:tt ),* $(,)? ) => {
|
||||||
|
{
|
||||||
|
let mut import_object = $crate::Imports::new();
|
||||||
|
|
||||||
|
$({
|
||||||
|
let namespace = $crate::import_namespace!($ns);
|
||||||
|
|
||||||
|
import_object.register_namespace($ns_name, namespace);
|
||||||
|
})*
|
||||||
|
|
||||||
|
import_object
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
#[doc(hidden)]
|
||||||
|
macro_rules! namespace {
|
||||||
|
($( $import_name:expr => $import_item:expr ),* $(,)? ) => {
|
||||||
|
$crate::import_namespace!( { $( $import_name => $import_item, )* } )
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
#[doc(hidden)]
|
||||||
|
macro_rules! import_namespace {
|
||||||
|
( { $( $import_name:expr => $import_item:expr ),* $(,)? } ) => {{
|
||||||
|
let mut namespace = $crate::Exports::new();
|
||||||
|
|
||||||
|
$(
|
||||||
|
namespace.insert($import_name, $import_item);
|
||||||
|
)*
|
||||||
|
|
||||||
|
namespace
|
||||||
|
}};
|
||||||
|
|
||||||
|
( $namespace:ident ) => {
|
||||||
|
$namespace
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use crate::sys::exports::Exportable;
|
||||||
|
use crate::sys::Export;
|
||||||
|
use crate::sys::{Global, Store, Val};
|
||||||
|
use wasmer_types::Type;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn namespace() {
|
||||||
|
let 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.from.ty().ty == Type::I32
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn imports_macro_allows_trailing_comma_and_none() {
|
||||||
|
use crate::sys::Function;
|
||||||
|
|
||||||
|
let store = Default::default();
|
||||||
|
|
||||||
|
fn func(arg: i32) -> i32 {
|
||||||
|
arg + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = imports! {
|
||||||
|
"env" => {
|
||||||
|
"func" => Function::new_native(&store, func),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let _ = imports! {
|
||||||
|
"env" => {
|
||||||
|
"func" => Function::new_native(&store, func),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let _ = imports! {
|
||||||
|
"env" => {
|
||||||
|
"func" => Function::new_native(&store, func),
|
||||||
|
},
|
||||||
|
"abc" => {
|
||||||
|
"def" => Function::new_native(&store, func),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let _ = imports! {
|
||||||
|
"env" => {
|
||||||
|
"func" => Function::new_native(&store, func)
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let _ = imports! {
|
||||||
|
"env" => {
|
||||||
|
"func" => Function::new_native(&store, func)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let _ = imports! {
|
||||||
|
"env" => {
|
||||||
|
"func1" => Function::new_native(&store, func),
|
||||||
|
"func2" => Function::new_native(&store, func)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let _ = imports! {
|
||||||
|
"env" => {
|
||||||
|
"func1" => Function::new_native(&store, func),
|
||||||
|
"func2" => Function::new_native(&store, func),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn chaining_works() {
|
||||||
|
let store = Store::default();
|
||||||
|
let g = Global::new(&store, Val::I32(0));
|
||||||
|
|
||||||
|
let mut imports1 = imports! {
|
||||||
|
"dog" => {
|
||||||
|
"happy" => g.clone()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let imports2 = imports! {
|
||||||
|
"dog" => {
|
||||||
|
"small" => g.clone()
|
||||||
|
},
|
||||||
|
"cat" => {
|
||||||
|
"small" => g.clone()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
imports1.extend(&imports2);
|
||||||
|
|
||||||
|
let small_cat_export = imports1.get_export("cat", "small");
|
||||||
|
assert!(small_cat_export.is_some());
|
||||||
|
|
||||||
|
let happy = imports1.get_export("dog", "happy");
|
||||||
|
let small = imports1.get_export("dog", "small");
|
||||||
|
assert!(happy.is_some());
|
||||||
|
assert!(small.is_some());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn extending_conflict_overwrites() {
|
||||||
|
let store = Store::default();
|
||||||
|
let g1 = Global::new(&store, Val::I32(0));
|
||||||
|
let g2 = Global::new(&store, Val::I64(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.from.ty().ty == Type::I64
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// now test it in reverse
|
||||||
|
let store = Store::default();
|
||||||
|
let g1 = Global::new(&store, Val::I32(0));
|
||||||
|
let g2 = Global::new(&store, Val::I64(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.from.ty().ty == Type::I32
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
use crate::sys::exports::Exports;
|
use crate::sys::exports::Exports;
|
||||||
use crate::sys::externals::Extern;
|
use crate::sys::externals::Extern;
|
||||||
|
use crate::sys::imports::Imports;
|
||||||
use crate::sys::module::Module;
|
use crate::sys::module::Module;
|
||||||
use crate::sys::store::Store;
|
use crate::sys::store::Store;
|
||||||
use crate::sys::{HostEnvInitError, LinkError, RuntimeError};
|
use crate::sys::{HostEnvInitError, LinkError, RuntimeError};
|
||||||
@ -7,7 +8,6 @@ use loupe::MemoryUsage;
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use wasmer_engine::Resolver;
|
|
||||||
use wasmer_vm::{InstanceHandle, VMContext};
|
use wasmer_vm::{InstanceHandle, VMContext};
|
||||||
|
|
||||||
/// A WebAssembly Instance is a stateful, executable
|
/// A WebAssembly Instance is a stateful, executable
|
||||||
@ -22,6 +22,8 @@ use wasmer_vm::{InstanceHandle, VMContext};
|
|||||||
pub struct Instance {
|
pub struct Instance {
|
||||||
handle: Arc<Mutex<InstanceHandle>>,
|
handle: Arc<Mutex<InstanceHandle>>,
|
||||||
module: Module,
|
module: Module,
|
||||||
|
#[allow(dead_code)]
|
||||||
|
imports: Vec<Extern>,
|
||||||
/// The exports for an instance.
|
/// The exports for an instance.
|
||||||
pub exports: Exports,
|
pub exports: Exports,
|
||||||
}
|
}
|
||||||
@ -86,15 +88,10 @@ impl From<HostEnvInitError> for InstantiationError {
|
|||||||
|
|
||||||
impl Instance {
|
impl Instance {
|
||||||
/// Creates a new `Instance` from a WebAssembly [`Module`] and a
|
/// Creates a new `Instance` from a WebAssembly [`Module`] and a
|
||||||
/// set of imports resolved by the [`Resolver`].
|
/// set of imports using [`Imports`] or the [`imports`] macro helper.
|
||||||
///
|
///
|
||||||
/// The resolver can be anything that implements the [`Resolver`] trait,
|
/// [`imports`]: crate::imports
|
||||||
/// so you can plug custom resolution for the imports, if you wish not
|
/// [`Imports`]: crate::Imports
|
||||||
/// to use [`ImportObject`].
|
|
||||||
///
|
|
||||||
/// The [`ImportObject`] is the easiest way to provide imports to the instance.
|
|
||||||
///
|
|
||||||
/// [`ImportObject`]: crate::ImportObject
|
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use wasmer::{imports, Store, Module, Global, Value, Instance};
|
/// # use wasmer::{imports, Store, Module, Global, Value, Instance};
|
||||||
@ -118,12 +115,12 @@ impl Instance {
|
|||||||
/// Those are, as defined by the spec:
|
/// Those are, as defined by the spec:
|
||||||
/// * Link errors that happen when plugging the imports into the instance
|
/// * Link errors that happen when plugging the imports into the instance
|
||||||
/// * Runtime errors that happen when running the module `start` function.
|
/// * Runtime errors that happen when running the module `start` function.
|
||||||
pub fn new(
|
pub fn new(module: &Module, imports: &Imports) -> Result<Self, InstantiationError> {
|
||||||
module: &Module,
|
|
||||||
resolver: &(dyn Resolver + Send + Sync),
|
|
||||||
) -> Result<Self, InstantiationError> {
|
|
||||||
let store = module.store();
|
let store = module.store();
|
||||||
let handle = module.instantiate(resolver)?;
|
let imports = imports
|
||||||
|
.imports_for_module(module)
|
||||||
|
.map_err(InstantiationError::Link)?;
|
||||||
|
let handle = module.instantiate(&imports)?;
|
||||||
let exports = module
|
let exports = module
|
||||||
.exports()
|
.exports()
|
||||||
.map(|export| {
|
.map(|export| {
|
||||||
@ -137,6 +134,57 @@ impl Instance {
|
|||||||
let instance = Self {
|
let instance = Self {
|
||||||
handle: Arc::new(Mutex::new(handle)),
|
handle: Arc::new(Mutex::new(handle)),
|
||||||
module: module.clone(),
|
module: module.clone(),
|
||||||
|
imports,
|
||||||
|
exports,
|
||||||
|
};
|
||||||
|
|
||||||
|
// # Safety
|
||||||
|
// `initialize_host_envs` should be called after instantiation but before
|
||||||
|
// returning an `Instance` to the user. We set up the host environments
|
||||||
|
// via `WasmerEnv::init_with_instance`.
|
||||||
|
//
|
||||||
|
// This usage is correct because we pass a valid pointer to `instance` and the
|
||||||
|
// correct error type returned by `WasmerEnv::init_with_instance` as a generic
|
||||||
|
// parameter.
|
||||||
|
unsafe {
|
||||||
|
instance
|
||||||
|
.handle
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.initialize_host_envs::<HostEnvInitError>(&instance as *const _ as *const _)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(instance)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new `Instance` from a WebAssembly [`Module`] and a
|
||||||
|
/// vector of imports.
|
||||||
|
///
|
||||||
|
/// ## Errors
|
||||||
|
///
|
||||||
|
/// The function can return [`InstantiationError`]s.
|
||||||
|
///
|
||||||
|
/// Those are, as defined by the spec:
|
||||||
|
/// * Link errors that happen when plugging the imports into the instance
|
||||||
|
/// * Runtime errors that happen when running the module `start` function.
|
||||||
|
pub fn new_by_index(module: &Module, externs: &[Extern]) -> Result<Self, InstantiationError> {
|
||||||
|
let store = module.store();
|
||||||
|
let imports = externs.iter().cloned().collect::<Vec<_>>();
|
||||||
|
let handle = module.instantiate(&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_export(store, export.into());
|
||||||
|
(name, extern_)
|
||||||
|
})
|
||||||
|
.collect::<Exports>();
|
||||||
|
|
||||||
|
let instance = Self {
|
||||||
|
handle: Arc::new(Mutex::new(handle)),
|
||||||
|
module: module.clone(),
|
||||||
|
imports,
|
||||||
exports,
|
exports,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
mod env;
|
mod env;
|
||||||
mod exports;
|
mod exports;
|
||||||
mod externals;
|
mod externals;
|
||||||
mod import_object;
|
mod imports;
|
||||||
mod instance;
|
mod instance;
|
||||||
mod mem_access;
|
mod mem_access;
|
||||||
mod module;
|
mod module;
|
||||||
@ -31,7 +31,7 @@ pub use crate::sys::exports::{ExportError, Exportable, Exports, ExportsIterator}
|
|||||||
pub use crate::sys::externals::{
|
pub use crate::sys::externals::{
|
||||||
Extern, FromToNativeWasmType, Function, Global, HostFunction, Memory, Table, WasmTypeList,
|
Extern, FromToNativeWasmType, Function, Global, HostFunction, Memory, Table, WasmTypeList,
|
||||||
};
|
};
|
||||||
pub use crate::sys::import_object::{ImportObject, ImportObjectIterator, LikeNamespace};
|
pub use crate::sys::imports::Imports;
|
||||||
pub use crate::sys::instance::{Instance, InstantiationError};
|
pub use crate::sys::instance::{Instance, InstantiationError};
|
||||||
pub use crate::sys::mem_access::{MemoryAccessError, WasmRef, WasmSlice, WasmSliceIter};
|
pub use crate::sys::mem_access::{MemoryAccessError, WasmRef, WasmSlice, WasmSliceIter};
|
||||||
pub use crate::sys::module::Module;
|
pub use crate::sys::module::Module;
|
||||||
@ -55,8 +55,7 @@ pub use wasmer_compiler::{
|
|||||||
};
|
};
|
||||||
pub use wasmer_derive::ValueType;
|
pub use wasmer_derive::ValueType;
|
||||||
pub use wasmer_engine::{
|
pub use wasmer_engine::{
|
||||||
ChainableNamedResolver, DeserializeError, Engine, Export, FrameInfo, LinkError, NamedResolver,
|
DeserializeError, Engine, Export, FrameInfo, LinkError, RuntimeError, SerializeError, Tunables,
|
||||||
NamedResolverChain, Resolver, RuntimeError, SerializeError, Tunables,
|
|
||||||
};
|
};
|
||||||
pub use wasmer_types::is_wasm;
|
pub use wasmer_types::is_wasm;
|
||||||
#[cfg(feature = "experimental-reference-types-extern-ref")]
|
#[cfg(feature = "experimental-reference-types-extern-ref")]
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use crate::sys::exports::Exportable;
|
||||||
use crate::sys::store::Store;
|
use crate::sys::store::Store;
|
||||||
use crate::sys::types::{ExportType, ImportType};
|
use crate::sys::types::{ExportType, ImportType};
|
||||||
use crate::sys::InstantiationError;
|
use crate::sys::InstantiationError;
|
||||||
@ -10,7 +11,7 @@ use thiserror::Error;
|
|||||||
use wasmer_compiler::CompileError;
|
use wasmer_compiler::CompileError;
|
||||||
#[cfg(feature = "wat")]
|
#[cfg(feature = "wat")]
|
||||||
use wasmer_compiler::WasmError;
|
use wasmer_compiler::WasmError;
|
||||||
use wasmer_engine::{Artifact, DeserializeError, Resolver, SerializeError};
|
use wasmer_engine::{Artifact, DeserializeError, SerializeError};
|
||||||
use wasmer_types::{ExportsIterator, ImportsIterator, ModuleInfo};
|
use wasmer_types::{ExportsIterator, ImportsIterator, ModuleInfo};
|
||||||
use wasmer_vm::InstanceHandle;
|
use wasmer_vm::InstanceHandle;
|
||||||
|
|
||||||
@ -276,12 +277,15 @@ impl Module {
|
|||||||
|
|
||||||
pub(crate) fn instantiate(
|
pub(crate) fn instantiate(
|
||||||
&self,
|
&self,
|
||||||
resolver: &dyn Resolver,
|
imports: &[crate::Extern],
|
||||||
) -> Result<InstanceHandle, InstantiationError> {
|
) -> Result<InstanceHandle, InstantiationError> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let instance_handle = self.artifact.instantiate(
|
let instance_handle = self.artifact.instantiate(
|
||||||
self.store.tunables(),
|
self.store.tunables(),
|
||||||
resolver,
|
&imports
|
||||||
|
.iter()
|
||||||
|
.map(crate::Extern::to_export)
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
Box::new(self.clone()),
|
Box::new(self.clone()),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
@ -19,8 +19,8 @@ mod sys {
|
|||||||
",
|
",
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let import_object = ImportObject::new();
|
let imports = Imports::new();
|
||||||
let instance = Instance::new(&module, &import_object)?;
|
let instance = Instance::new(&module, &imports)?;
|
||||||
let instance2 = instance.clone();
|
let instance2 = instance.clone();
|
||||||
let instance3 = instance.clone();
|
let instance3 = instance.clone();
|
||||||
|
|
||||||
|
@ -25,5 +25,4 @@
|
|||||||
)]
|
)]
|
||||||
|
|
||||||
pub mod error;
|
pub mod error;
|
||||||
mod ordered_resolver;
|
|
||||||
pub mod wasm_c_api;
|
pub mod wasm_c_api;
|
||||||
|
@ -1,34 +0,0 @@
|
|||||||
//! Ordered Resolvers are a custom kind of [`Resolver`] that retrieves
|
|
||||||
//! `EngineExport`s based on the index of the import, and not the module or name.
|
|
||||||
//!
|
|
||||||
//! This resolver is used in the Wasm-C-API as the imports are provided
|
|
||||||
//! by index and not by module and name.
|
|
||||||
|
|
||||||
use std::iter::FromIterator;
|
|
||||||
use wasmer_api::{Export, Exportable, Extern, Resolver};
|
|
||||||
|
|
||||||
/// An `OrderedResolver` stores all the `externs` provided to an Instance
|
|
||||||
/// in a Vec, so we can retrieve them later based on index.
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct OrderedResolver {
|
|
||||||
/// The externs to be resolved by index
|
|
||||||
externs: Vec<Extern>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Resolver for OrderedResolver {
|
|
||||||
fn resolve(&self, index: u32, _module: &str, _name: &str) -> Option<Export> {
|
|
||||||
self.externs
|
|
||||||
.get(index as usize)
|
|
||||||
.map(|extern_| extern_.to_export())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromIterator<Extern> for OrderedResolver {
|
|
||||||
fn from_iter<I: IntoIterator<Item = Extern>>(iter: I) -> Self {
|
|
||||||
let mut externs = Vec::new();
|
|
||||||
for extern_ in iter {
|
|
||||||
externs.push(extern_);
|
|
||||||
}
|
|
||||||
OrderedResolver { externs }
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,7 +2,6 @@ use super::externals::wasm_extern_vec_t;
|
|||||||
use super::module::wasm_module_t;
|
use super::module::wasm_module_t;
|
||||||
use super::store::wasm_store_t;
|
use super::store::wasm_store_t;
|
||||||
use super::trap::wasm_trap_t;
|
use super::trap::wasm_trap_t;
|
||||||
use crate::ordered_resolver::OrderedResolver;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use wasmer_api::{Extern, Instance, InstantiationError};
|
use wasmer_api::{Extern, Instance, InstantiationError};
|
||||||
|
|
||||||
@ -48,14 +47,14 @@ pub unsafe extern "C" fn wasm_instance_new(
|
|||||||
let wasm_module = &module.inner;
|
let wasm_module = &module.inner;
|
||||||
let module_imports = wasm_module.imports();
|
let module_imports = wasm_module.imports();
|
||||||
let module_import_count = module_imports.len();
|
let module_import_count = module_imports.len();
|
||||||
let resolver: OrderedResolver = imports
|
let externs = imports
|
||||||
.as_slice()
|
.as_slice()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|imp| Extern::from(imp.as_ref().unwrap().as_ref().clone()))
|
.map(|imp| Extern::from(imp.as_ref().unwrap().as_ref().clone()))
|
||||||
.take(module_import_count)
|
.take(module_import_count)
|
||||||
.collect();
|
.collect::<Vec<Extern>>();
|
||||||
|
|
||||||
let instance = match Instance::new(wasm_module, &resolver) {
|
let instance = match Instance::new_by_index(wasm_module, &externs) {
|
||||||
Ok(instance) => Arc::new(instance),
|
Ok(instance) => Arc::new(instance),
|
||||||
|
|
||||||
Err(InstantiationError::Link(link_error)) => {
|
Err(InstantiationError::Link(link_error)) => {
|
||||||
|
@ -5,7 +5,7 @@ use super::super::{
|
|||||||
externals::wasm_extern_t, module::wasm_module_t, store::wasm_store_t, types::wasm_name_t,
|
externals::wasm_extern_t, module::wasm_module_t, store::wasm_store_t, types::wasm_name_t,
|
||||||
wasi::wasi_env_t,
|
wasi::wasi_env_t,
|
||||||
};
|
};
|
||||||
use wasmer_api::Extern;
|
use wasmer_api::{Exportable, Extern};
|
||||||
use wasmer_wasi::{generate_import_object_from_env, get_wasi_version};
|
use wasmer_wasi::{generate_import_object_from_env, get_wasi_version};
|
||||||
|
|
||||||
/// Unstable non-standard type wrapping `wasm_extern_t` with the
|
/// Unstable non-standard type wrapping `wasm_extern_t` with the
|
||||||
@ -175,10 +175,10 @@ fn wasi_get_unordered_imports_inner(
|
|||||||
imports.set_buffer(
|
imports.set_buffer(
|
||||||
import_object
|
import_object
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|((module, name), export)| {
|
.map(|((module, name), extern_)| {
|
||||||
let module = module.into();
|
let module = module.into();
|
||||||
let name = name.into();
|
let name = name.into();
|
||||||
let extern_inner = Extern::from_vm_export(store, export);
|
let extern_inner = Extern::from_vm_export(store, extern_.to_export());
|
||||||
|
|
||||||
Some(Box::new(wasmer_named_extern_t {
|
Some(Box::new(wasmer_named_extern_t {
|
||||||
module,
|
module,
|
||||||
|
@ -17,7 +17,7 @@ use std::convert::TryFrom;
|
|||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
use std::os::raw::c_char;
|
use std::os::raw::c_char;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
use wasmer_api::{Extern, NamedResolver};
|
use wasmer_api::{Exportable, Extern};
|
||||||
use wasmer_wasi::{
|
use wasmer_wasi::{
|
||||||
generate_import_object_from_env, get_wasi_version, WasiEnv, WasiFile, WasiState,
|
generate_import_object_from_env, get_wasi_version, WasiEnv, WasiFile, WasiState,
|
||||||
WasiStateBuilder, WasiVersion,
|
WasiStateBuilder, WasiVersion,
|
||||||
@ -351,8 +351,8 @@ fn wasi_get_imports_inner(
|
|||||||
.inner
|
.inner
|
||||||
.imports()
|
.imports()
|
||||||
.map(|import_type| {
|
.map(|import_type| {
|
||||||
let export = import_object
|
let ext = import_object
|
||||||
.resolve_by_name(import_type.module(), import_type.name())
|
.get_export(import_type.module(), import_type.name())
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
format!(
|
format!(
|
||||||
"Failed to resolve import \"{}\" \"{}\"",
|
"Failed to resolve import \"{}\" \"{}\"",
|
||||||
@ -360,7 +360,7 @@ fn wasi_get_imports_inner(
|
|||||||
import_type.name()
|
import_type.name()
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
let inner = Extern::from_vm_export(store, export);
|
let inner = Extern::from_vm_export(store, ext.to_export());
|
||||||
|
|
||||||
Ok(Some(Box::new(inner.into())))
|
Ok(Some(Box::new(inner.into())))
|
||||||
})
|
})
|
||||||
|
@ -94,8 +94,8 @@ impl Wasi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut wasi_env = wasi_state_builder.finalize()?;
|
let mut wasi_env = wasi_state_builder.finalize()?;
|
||||||
let resolver = wasi_env.import_object_for_all_wasi_versions(&module)?;
|
let import_object = wasi_env.import_object_for_all_wasi_versions(&module)?;
|
||||||
let instance = Instance::new(&module, &resolver)?;
|
let instance = Instance::new(&module, &import_object)?;
|
||||||
Ok(instance)
|
Ok(instance)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ use std::f64;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::{Arc, Mutex, RwLock};
|
use std::sync::{Arc, Mutex, RwLock};
|
||||||
use wasmer::{
|
use wasmer::{
|
||||||
imports, namespace, Exports, Function, FunctionType, Global, ImportObject, Instance, LazyInit,
|
imports, namespace, Exports, Function, FunctionType, Global, Imports, Instance, LazyInit,
|
||||||
Memory, MemoryType, Module, NativeFunc, Pages, RuntimeError, Store, Table, TableType, Val,
|
Memory, MemoryType, Module, NativeFunc, Pages, RuntimeError, Store, Table, TableType, Val,
|
||||||
ValType, WasmPtr, WasmerEnv,
|
ValType, WasmPtr, WasmerEnv,
|
||||||
};
|
};
|
||||||
@ -539,7 +539,7 @@ pub fn generate_emscripten_env(
|
|||||||
store: &Store,
|
store: &Store,
|
||||||
globals: &mut EmscriptenGlobals,
|
globals: &mut EmscriptenGlobals,
|
||||||
env: &EmEnv,
|
env: &EmEnv,
|
||||||
) -> ImportObject {
|
) -> Imports {
|
||||||
let abort_on_cannot_grow_memory_export = if globals.data.use_old_abort_on_cannot_grow_memory {
|
let abort_on_cannot_grow_memory_export = if globals.data.use_old_abort_on_cannot_grow_memory {
|
||||||
Function::new_native_with_env(
|
Function::new_native_with_env(
|
||||||
store,
|
store,
|
||||||
@ -1016,7 +1016,7 @@ pub fn generate_emscripten_env(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let import_object: ImportObject = imports! {
|
let import_object: Imports = imports! {
|
||||||
"env" => env_ns,
|
"env" => env_ns,
|
||||||
"global" => {
|
"global" => {
|
||||||
"NaN" => Global::new(store, Val::F64(f64::NAN)),
|
"NaN" => Global::new(store, Val::F64(f64::NAN)),
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::{resolve_imports, InstantiationError, Resolver, RuntimeError, Tunables};
|
use crate::{resolve_imports, Export, InstantiationError, RuntimeError, Tunables};
|
||||||
use loupe::MemoryUsage;
|
use loupe::MemoryUsage;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
pub use wasmer_artifact::MetadataHeader;
|
pub use wasmer_artifact::MetadataHeader;
|
||||||
@ -56,7 +56,7 @@ pub trait Artifact: Send + Sync + Upcastable + MemoryUsage + ArtifactCreate {
|
|||||||
unsafe fn instantiate(
|
unsafe fn instantiate(
|
||||||
&self,
|
&self,
|
||||||
tunables: &dyn Tunables,
|
tunables: &dyn Tunables,
|
||||||
resolver: &dyn Resolver,
|
imports: &[Export],
|
||||||
host_state: Box<dyn Any>,
|
host_state: Box<dyn Any>,
|
||||||
) -> Result<InstanceHandle, InstantiationError> {
|
) -> Result<InstanceHandle, InstantiationError> {
|
||||||
// Validate the CPU features this module was compiled with against the
|
// Validate the CPU features this module was compiled with against the
|
||||||
@ -75,7 +75,7 @@ pub trait Artifact: Send + Sync + Upcastable + MemoryUsage + ArtifactCreate {
|
|||||||
let (imports, import_function_envs) = {
|
let (imports, import_function_envs) = {
|
||||||
let mut imports = resolve_imports(
|
let mut imports = resolve_imports(
|
||||||
&module,
|
&module,
|
||||||
resolver,
|
imports,
|
||||||
&self.finished_dynamic_function_trampolines(),
|
&self.finished_dynamic_function_trampolines(),
|
||||||
self.memory_styles(),
|
self.memory_styles(),
|
||||||
self.table_styles(),
|
self.table_styles(),
|
||||||
|
@ -3,7 +3,7 @@ use std::sync::Arc;
|
|||||||
use wasmer_vm::{ImportInitializerFuncPtr, VMExtern, VMFunction, VMGlobal, VMMemory, VMTable};
|
use wasmer_vm::{ImportInitializerFuncPtr, VMExtern, VMFunction, VMGlobal, VMMemory, VMTable};
|
||||||
|
|
||||||
/// The value of an export passed from one instance to another.
|
/// The value of an export passed from one instance to another.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, MemoryUsage, Clone)]
|
||||||
pub enum Export {
|
pub enum Export {
|
||||||
/// A function export value.
|
/// A function export value.
|
||||||
Function(ExportFunction),
|
Function(ExportFunction),
|
||||||
|
@ -127,7 +127,7 @@ fn get_extern_from_export(_module: &ModuleInfo, export: &Export) -> ExternType {
|
|||||||
/// If all imports are satisfied returns an `Imports` instance required for a module instantiation.
|
/// If all imports are satisfied returns an `Imports` instance required for a module instantiation.
|
||||||
pub fn resolve_imports(
|
pub fn resolve_imports(
|
||||||
module: &ModuleInfo,
|
module: &ModuleInfo,
|
||||||
resolver: &dyn Resolver,
|
imports: &[Export],
|
||||||
finished_dynamic_function_trampolines: &BoxedSlice<FunctionIndex, FunctionBodyPtr>,
|
finished_dynamic_function_trampolines: &BoxedSlice<FunctionIndex, FunctionBodyPtr>,
|
||||||
memory_styles: &PrimaryMap<MemoryIndex, MemoryStyle>,
|
memory_styles: &PrimaryMap<MemoryIndex, MemoryStyle>,
|
||||||
_table_styles: &PrimaryMap<TableIndex, TableStyle>,
|
_table_styles: &PrimaryMap<TableIndex, TableStyle>,
|
||||||
@ -140,17 +140,15 @@ pub fn resolve_imports(
|
|||||||
let mut global_imports = PrimaryMap::with_capacity(module.num_imported_globals);
|
let mut global_imports = PrimaryMap::with_capacity(module.num_imported_globals);
|
||||||
|
|
||||||
for ((module_name, field, import_idx), import_index) in module.imports.iter() {
|
for ((module_name, field, import_idx), import_index) in module.imports.iter() {
|
||||||
let resolved = resolver.resolve(*import_idx, module_name, field);
|
|
||||||
let import_extern = get_extern_from_import(module, import_index);
|
let import_extern = get_extern_from_import(module, import_index);
|
||||||
let resolved = match resolved {
|
let resolved = if let Some(r) = imports.get(*import_idx as usize) {
|
||||||
None => {
|
r
|
||||||
return Err(LinkError::Import(
|
} else {
|
||||||
module_name.to_string(),
|
return Err(LinkError::Import(
|
||||||
field.to_string(),
|
module_name.to_string(),
|
||||||
ImportError::UnknownImport(import_extern),
|
field.to_string(),
|
||||||
));
|
ImportError::UnknownImport(import_extern),
|
||||||
}
|
));
|
||||||
Some(r) => r,
|
|
||||||
};
|
};
|
||||||
let export_extern = get_extern_from_export(module, &resolved);
|
let export_extern = get_extern_from_export(module, &resolved);
|
||||||
if !export_extern.is_compatible_with(&import_extern) {
|
if !export_extern.is_compatible_with(&import_extern) {
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
//! Wasmer's WASI implementation
|
//! Wasmer's WASI implementation
|
||||||
//!
|
//!
|
||||||
//! Use `generate_import_object` to create an [`ImportObject`]. This [`ImportObject`]
|
//! Use `generate_import_object` to create an [`Imports`]. This [`Imports`]
|
||||||
//! can be combined with a module to create an `Instance` which can execute WASI
|
//! can be combined with a module to create an `Instance` which can execute WASI
|
||||||
//! Wasm functions.
|
//! Wasm functions.
|
||||||
//!
|
//!
|
||||||
@ -55,8 +55,7 @@ pub use wasmer_vfs::{FsError, VirtualFile};
|
|||||||
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use wasmer::{
|
use wasmer::{
|
||||||
imports, ChainableNamedResolver, Function, ImportObject, LazyInit, Memory, MemoryAccessError,
|
imports, Function, Imports, LazyInit, Memory, MemoryAccessError, Module, Store, WasmerEnv,
|
||||||
Module, NamedResolver, Store, WasmerEnv,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::sync::{Arc, Mutex, MutexGuard};
|
use std::sync::{Arc, Mutex, MutexGuard};
|
||||||
@ -93,8 +92,8 @@ impl WasiEnv {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get an `ImportObject` for a specific version of WASI detected in the module.
|
/// Get an `Imports` for a specific version of WASI detected in the module.
|
||||||
pub fn import_object(&mut self, module: &Module) -> Result<ImportObject, WasiError> {
|
pub fn import_object(&mut self, module: &Module) -> Result<Imports, WasiError> {
|
||||||
let wasi_version = get_wasi_version(module, false).ok_or(WasiError::UnknownWasiVersion)?;
|
let wasi_version = get_wasi_version(module, false).ok_or(WasiError::UnknownWasiVersion)?;
|
||||||
Ok(generate_import_object_from_env(
|
Ok(generate_import_object_from_env(
|
||||||
module.store(),
|
module.store(),
|
||||||
@ -108,16 +107,17 @@ impl WasiEnv {
|
|||||||
pub fn import_object_for_all_wasi_versions(
|
pub fn import_object_for_all_wasi_versions(
|
||||||
&mut self,
|
&mut self,
|
||||||
module: &Module,
|
module: &Module,
|
||||||
) -> Result<Box<dyn NamedResolver + Send + Sync>, WasiError> {
|
) -> Result<Imports, WasiError> {
|
||||||
let wasi_versions =
|
let wasi_versions =
|
||||||
get_wasi_versions(module, false).ok_or(WasiError::UnknownWasiVersion)?;
|
get_wasi_versions(module, false).ok_or(WasiError::UnknownWasiVersion)?;
|
||||||
|
|
||||||
let mut resolver: Box<dyn NamedResolver + Send + Sync> =
|
let mut resolver = Imports::new();
|
||||||
{ Box::new(()) as Box<dyn NamedResolver + Send + Sync> };
|
|
||||||
for version in wasi_versions.iter() {
|
for version in wasi_versions.iter() {
|
||||||
let new_import_object =
|
let new_import_object =
|
||||||
generate_import_object_from_env(module.store(), self.clone(), *version);
|
generate_import_object_from_env(module.store(), self.clone(), *version);
|
||||||
resolver = Box::new(new_import_object.chain_front(resolver));
|
for ((n, m), e) in new_import_object.into_iter() {
|
||||||
|
resolver.define(&n, &m, e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(resolver)
|
Ok(resolver)
|
||||||
}
|
}
|
||||||
@ -147,14 +147,14 @@ impl WasiEnv {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create an [`ImportObject`] with an existing [`WasiEnv`]. `WasiEnv`
|
/// Create an [`Imports`] with an existing [`WasiEnv`]. `WasiEnv`
|
||||||
/// needs a [`WasiState`], that can be constructed from a
|
/// needs a [`WasiState`], that can be constructed from a
|
||||||
/// [`WasiStateBuilder`](state::WasiStateBuilder).
|
/// [`WasiStateBuilder`](state::WasiStateBuilder).
|
||||||
pub fn generate_import_object_from_env(
|
pub fn generate_import_object_from_env(
|
||||||
store: &Store,
|
store: &Store,
|
||||||
wasi_env: WasiEnv,
|
wasi_env: WasiEnv,
|
||||||
version: WasiVersion,
|
version: WasiVersion,
|
||||||
) -> ImportObject {
|
) -> Imports {
|
||||||
match version {
|
match version {
|
||||||
WasiVersion::Snapshot0 => generate_import_object_snapshot0(store, wasi_env),
|
WasiVersion::Snapshot0 => generate_import_object_snapshot0(store, wasi_env),
|
||||||
WasiVersion::Snapshot1 | WasiVersion::Latest => {
|
WasiVersion::Snapshot1 | WasiVersion::Latest => {
|
||||||
@ -164,7 +164,7 @@ pub fn generate_import_object_from_env(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Combines a state generating function with the import list for legacy WASI
|
/// Combines a state generating function with the import list for legacy WASI
|
||||||
fn generate_import_object_snapshot0(store: &Store, env: WasiEnv) -> ImportObject {
|
fn generate_import_object_snapshot0(store: &Store, env: WasiEnv) -> Imports {
|
||||||
imports! {
|
imports! {
|
||||||
"wasi_unstable" => {
|
"wasi_unstable" => {
|
||||||
"args_get" => Function::new_native_with_env(store, env.clone(), args_get),
|
"args_get" => Function::new_native_with_env(store, env.clone(), args_get),
|
||||||
@ -217,7 +217,7 @@ fn generate_import_object_snapshot0(store: &Store, env: WasiEnv) -> ImportObject
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Combines a state generating function with the import list for snapshot 1
|
/// Combines a state generating function with the import list for snapshot 1
|
||||||
fn generate_import_object_snapshot1(store: &Store, env: WasiEnv) -> ImportObject {
|
fn generate_import_object_snapshot1(store: &Store, env: WasiEnv) -> Imports {
|
||||||
imports! {
|
imports! {
|
||||||
"wasi_snapshot_preview1" => {
|
"wasi_snapshot_preview1" => {
|
||||||
"args_get" => Function::new_native_with_env(store, env.clone(), args_get),
|
"args_get" => Function::new_native_with_env(store, env.clone(), args_get),
|
||||||
|
@ -63,7 +63,7 @@ fn issue_2329(mut config: crate::Config) -> Result<()> {
|
|||||||
"#;
|
"#;
|
||||||
let module = Module::new(&store, wat)?;
|
let module = Module::new(&store, wat)?;
|
||||||
let env = Env::new();
|
let env = Env::new();
|
||||||
let imports: ImportObject = imports! {
|
let imports: Imports = imports! {
|
||||||
"env" => {
|
"env" => {
|
||||||
"__read_memory" => Function::new_native_with_env(
|
"__read_memory" => Function::new_native_with_env(
|
||||||
&store,
|
&store,
|
||||||
@ -214,8 +214,8 @@ fn call_with_static_data_pointers(mut config: crate::Config) -> Result<()> {
|
|||||||
"gas",
|
"gas",
|
||||||
Function::new_native_with_env(&store, env.clone(), gas),
|
Function::new_native_with_env(&store, env.clone(), gas),
|
||||||
);
|
);
|
||||||
let mut imports = ImportObject::new();
|
let mut imports = Imports::new();
|
||||||
imports.register("env", exports);
|
imports.register_namespace("env", exports);
|
||||||
let instance = Instance::new(&module, &imports)?;
|
let instance = Instance::new(&module, &imports)?;
|
||||||
instance.exports.get_function("repro")?.call(&[])?;
|
instance.exports.get_function("repro")?.call(&[])?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -255,7 +255,7 @@ fn regression_gpr_exhaustion_for_calls(mut config: crate::Config) -> Result<()>
|
|||||||
(table (;0;) 1 1 funcref))
|
(table (;0;) 1 1 funcref))
|
||||||
"#;
|
"#;
|
||||||
let module = Module::new(&store, wat)?;
|
let module = Module::new(&store, wat)?;
|
||||||
let imports: ImportObject = imports! {};
|
let imports: Imports = imports! {};
|
||||||
let instance = Instance::new(&module, &imports)?;
|
let instance = Instance::new(&module, &imports)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ use wasmer::*;
|
|||||||
|
|
||||||
/// Return an instance implementing the "spectest" interface used in the
|
/// Return an instance implementing the "spectest" interface used in the
|
||||||
/// spec testsuite.
|
/// spec testsuite.
|
||||||
pub fn spectest_importobject(store: &Store) -> ImportObject {
|
pub fn spectest_importobject(store: &Store) -> Imports {
|
||||||
let print = Function::new_native(store, || {});
|
let print = Function::new_native(store, || {});
|
||||||
let print_i32 = Function::new_native(store, |val: i32| println!("{}: i32", val));
|
let print_i32 = Function::new_native(store, |val: i32| println!("{}: i32", val));
|
||||||
let print_i64 = Function::new_native(store, |val: i64| println!("{}: i64", val));
|
let print_i64 = Function::new_native(store, |val: i64| println!("{}: i64", val));
|
||||||
|
@ -2,7 +2,7 @@ use anyhow::Context;
|
|||||||
use std::fs::{read_dir, File, OpenOptions, ReadDir};
|
use std::fs::{read_dir, File, OpenOptions, ReadDir};
|
||||||
use std::io::{self, Read, Seek, Write};
|
use std::io::{self, Read, Seek, Write};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use wasmer::{ImportObject, Instance, Module, Store};
|
use wasmer::{Imports, Instance, Module, Store};
|
||||||
use wasmer_vfs::{host_fs, mem_fs, FileSystem};
|
use wasmer_vfs::{host_fs, mem_fs, FileSystem};
|
||||||
use wasmer_wasi::types::{__wasi_filesize_t, __wasi_timestamp_t};
|
use wasmer_wasi::types::{__wasi_filesize_t, __wasi_timestamp_t};
|
||||||
use wasmer_wasi::{
|
use wasmer_wasi::{
|
||||||
@ -236,12 +236,7 @@ impl<'a> WasiTest<'a> {
|
|||||||
|
|
||||||
/// Get the correct WASI import object for the given module and set it up with the
|
/// Get the correct WASI import object for the given module and set it up with the
|
||||||
/// [`WasiEnv`].
|
/// [`WasiEnv`].
|
||||||
fn get_imports(
|
fn get_imports(&self, store: &Store, module: &Module, env: WasiEnv) -> anyhow::Result<Imports> {
|
||||||
&self,
|
|
||||||
store: &Store,
|
|
||||||
module: &Module,
|
|
||||||
env: WasiEnv,
|
|
||||||
) -> anyhow::Result<ImportObject> {
|
|
||||||
let version = self.get_version(module)?;
|
let version = self.get_version(module)?;
|
||||||
Ok(generate_import_object_from_env(store, env, version))
|
Ok(generate_import_object_from_env(store, env, version))
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ pub struct Wast {
|
|||||||
/// recently defined.
|
/// recently defined.
|
||||||
current: Option<Instance>,
|
current: Option<Instance>,
|
||||||
/// The Import Object that all wast tests will have
|
/// The Import Object that all wast tests will have
|
||||||
import_object: ImportObject,
|
import_object: Imports,
|
||||||
/// The instances in the test
|
/// The instances in the test
|
||||||
instances: HashMap<String, Instance>,
|
instances: HashMap<String, Instance>,
|
||||||
/// Allowed failures (ideally this should be empty)
|
/// Allowed failures (ideally this should be empty)
|
||||||
@ -37,7 +37,7 @@ pub struct Wast {
|
|||||||
|
|
||||||
impl Wast {
|
impl Wast {
|
||||||
/// Construct a new instance of `Wast` with a given imports.
|
/// Construct a new instance of `Wast` with a given imports.
|
||||||
pub fn new(store: Store, import_object: ImportObject) -> Self {
|
pub fn new(store: Store, import_object: Imports) -> Self {
|
||||||
Self {
|
Self {
|
||||||
current: None,
|
current: None,
|
||||||
store,
|
store,
|
||||||
@ -382,7 +382,7 @@ impl Wast {
|
|||||||
.instances
|
.instances
|
||||||
.get(module_name)
|
.get(module_name)
|
||||||
.ok_or_else(|| anyhow!("constant expression required"))?;
|
.ok_or_else(|| anyhow!("constant expression required"))?;
|
||||||
imports.register(module_name, instance.exports.clone());
|
imports.register_namespace(module_name, instance.exports.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
let instance = Instance::new(&module, &imports)?;
|
let instance = Instance::new(&module, &imports)?;
|
||||||
|
Reference in New Issue
Block a user