mirror of
https://github.com/mii443/wasmer.git
synced 2025-09-02 07:29:21 +00:00
Add resolver chaining and recursive resolving
This commit is contained in:
@ -8,7 +8,7 @@ use std::{
|
|||||||
ffi::c_void,
|
ffi::c_void,
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
use wasmer_engine::NamedResolver;
|
use wasmer_engine::{ChainableResolver, NamedResolver};
|
||||||
use wasmer_runtime::Export;
|
use wasmer_runtime::Export;
|
||||||
|
|
||||||
/// The `LikeNamespace` trait represents objects that act as a namespace for imports.
|
/// The `LikeNamespace` trait represents objects that act as a namespace for imports.
|
||||||
@ -157,6 +157,8 @@ impl NamedResolver for ImportObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ChainableResolver for ImportObject {}
|
||||||
|
|
||||||
/// Iterator for an `ImportObject`'s exports.
|
/// Iterator for an `ImportObject`'s exports.
|
||||||
pub struct ImportObjectIterator {
|
pub struct ImportObjectIterator {
|
||||||
elements: VecDeque<((String, String), Export)>,
|
elements: VecDeque<((String, String), Export)>,
|
||||||
@ -180,12 +182,6 @@ impl IntoIterator for ImportObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Extend<((String, String), Export)> for ImportObject {
|
|
||||||
fn extend<T: IntoIterator<Item = ((String, String), Export)>>(&mut self, _iter: T) {
|
|
||||||
unimplemented!("Extend not yet implemented");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The import! macro for ImportObject
|
// The import! macro for ImportObject
|
||||||
|
|
||||||
/// Generate an [`ImportObject`] easily with the `imports!` macro.
|
/// Generate an [`ImportObject`] easily with the `imports!` macro.
|
||||||
@ -210,6 +206,7 @@ impl Extend<((String, String), Export)> for ImportObject {
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
|
// TOOD: port of lost fixes of imports macro from wasmer master/imports macro tests
|
||||||
macro_rules! imports {
|
macro_rules! imports {
|
||||||
( $( $ns_name:expr => $ns:tt ),* $(,)? ) => {{
|
( $( $ns_name:expr => $ns:tt ),* $(,)? ) => {{
|
||||||
use $crate::ImportObject;
|
use $crate::ImportObject;
|
||||||
@ -251,17 +248,17 @@ macro_rules! import_namespace {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
use super::*;
|
||||||
use crate::{Global, Store, Val};
|
use crate::{Global, Store, Val};
|
||||||
use wasm_common::Type;
|
use wasm_common::Type;
|
||||||
use wasmer_runtime::Export;
|
use wasmer_runtime::Export;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore]
|
fn chaining_works() {
|
||||||
fn extending_works() {
|
|
||||||
let store = Store::default();
|
let store = Store::default();
|
||||||
let g = Global::new(&store, Val::I32(0));
|
let g = Global::new(&store, Val::I32(0));
|
||||||
|
|
||||||
let mut imports1 = imports! {
|
let imports1 = imports! {
|
||||||
"dog" => {
|
"dog" => {
|
||||||
"happy" => g.clone()
|
"happy" => g.clone()
|
||||||
}
|
}
|
||||||
@ -276,19 +273,18 @@ mod test {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
imports1.extend(imports2);
|
let resolver = imports1.chain_front(imports2);
|
||||||
|
|
||||||
let small_cat_export = imports1.get_export("cat", "small");
|
let small_cat_export = resolver.resolve(0, "cat", "small");
|
||||||
assert!(small_cat_export.is_some());
|
assert!(small_cat_export.is_ok());
|
||||||
|
|
||||||
let happy = imports1.get_export("dog", "happy");
|
let happy = resolver.resolve(0, "dog", "happy");
|
||||||
let small = imports1.get_export("dog", "small");
|
let small = resolver.resolve(0, "dog", "small");
|
||||||
assert!(happy.is_some());
|
assert!(happy.is_ok());
|
||||||
assert!(small.is_some());
|
assert!(small.is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore]
|
|
||||||
fn extending_conflict_overwrites() {
|
fn extending_conflict_overwrites() {
|
||||||
let store = Store::default();
|
let store = Store::default();
|
||||||
let g1 = Global::new(&store, Val::I32(0));
|
let g1 = Global::new(&store, Val::I32(0));
|
||||||
@ -306,8 +302,8 @@ mod test {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
imports1.extend(imports2);
|
let resolver = imports1.chain_front(imports2);
|
||||||
let happy_dog_entry = imports1.get_export("dog", "happy").unwrap();
|
let happy_dog_entry = resolver.resolve(0, "dog", "happy").unwrap();
|
||||||
|
|
||||||
assert!(if let Export::Global(happy_dog_global) = happy_dog_entry {
|
assert!(if let Export::Global(happy_dog_global) = happy_dog_entry {
|
||||||
happy_dog_global.global.ty == Type::I64
|
happy_dog_global.global.ty == Type::I64
|
||||||
@ -327,7 +323,7 @@ mod test {
|
|||||||
"dog" => namespace
|
"dog" => namespace
|
||||||
};
|
};
|
||||||
|
|
||||||
let happy_dog_entry = imports1.get_export("dog", "happy").unwrap();
|
let happy_dog_entry = imports1.resolve(0, "dog", "happy").unwrap();
|
||||||
|
|
||||||
assert!(if let Export::Global(happy_dog_global) = happy_dog_entry {
|
assert!(if let Export::Global(happy_dog_global) = happy_dog_entry {
|
||||||
happy_dog_global.global.ty == Type::I32
|
happy_dog_global.global.ty == Type::I32
|
||||||
|
@ -32,8 +32,8 @@ pub use wasm_common::{Bytes, Pages, ValueType, WasmExternType, WasmTypeList};
|
|||||||
pub use wasmer_compiler::CompilerConfig;
|
pub use wasmer_compiler::CompilerConfig;
|
||||||
pub use wasmer_compiler::{Features, Target};
|
pub use wasmer_compiler::{Features, Target};
|
||||||
pub use wasmer_engine::{
|
pub use wasmer_engine::{
|
||||||
DeserializeError, Engine, InstantiationError, LinkError, NamedResolver, Resolver, RuntimeError,
|
ChainableResolver, DeserializeError, Engine, InstantiationError, LinkError, NamedResolver,
|
||||||
SerializeError,
|
Resolver, ResolverChain, RuntimeError, SerializeError,
|
||||||
};
|
};
|
||||||
pub use wasmer_runtime::{raise_user_trap, MemoryError};
|
pub use wasmer_runtime::{raise_user_trap, MemoryError};
|
||||||
|
|
||||||
|
@ -86,7 +86,6 @@ add_test(test-imports test-imports)
|
|||||||
|
|
||||||
target_link_libraries(test-import-object general ${WASMER_LIB})
|
target_link_libraries(test-import-object general ${WASMER_LIB})
|
||||||
target_compile_options(test-import-object PRIVATE ${COMPILER_OPTIONS})
|
target_compile_options(test-import-object PRIVATE ${COMPILER_OPTIONS})
|
||||||
# TODO: reenable this test
|
|
||||||
#add_test(test-import-object test-import-object)
|
#add_test(test-import-object test-import-object)
|
||||||
|
|
||||||
|
|
||||||
|
@ -34,7 +34,9 @@ pub use crate::engine::Engine;
|
|||||||
pub use crate::error::{
|
pub use crate::error::{
|
||||||
DeserializeError, ImportError, InstantiationError, LinkError, SerializeError,
|
DeserializeError, ImportError, InstantiationError, LinkError, SerializeError,
|
||||||
};
|
};
|
||||||
pub use crate::resolver::{resolve_imports, NamedResolver, NullResolver, Resolver};
|
pub use crate::resolver::{
|
||||||
|
resolve_imports, ChainableResolver, NamedResolver, NullResolver, Resolver, ResolverChain,
|
||||||
|
};
|
||||||
pub use crate::serialize::SerializableFunctionFrameInfo;
|
pub use crate::serialize::SerializableFunctionFrameInfo;
|
||||||
pub use crate::trap::*;
|
pub use crate::trap::*;
|
||||||
pub use crate::tunables::Tunables;
|
pub use crate::tunables::Tunables;
|
||||||
|
@ -63,8 +63,8 @@ impl<T: NamedResolver> Resolver for T {
|
|||||||
pub struct NullResolver {}
|
pub struct NullResolver {}
|
||||||
|
|
||||||
impl Resolver for NullResolver {
|
impl Resolver for NullResolver {
|
||||||
fn resolve(&self, _idx: u32, _module: &str, _field: &str) -> Option<Export> {
|
fn resolve(&self, _idx: u32, _module: &str, _field: &str) -> Result<Export, u32> {
|
||||||
None
|
Err(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,7 +136,7 @@ pub fn resolve_imports(
|
|||||||
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 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 = match resolved.ok() {
|
||||||
None => {
|
None => {
|
||||||
return Err(LinkError::Import(
|
return Err(LinkError::Import(
|
||||||
module_name.to_string(),
|
module_name.to_string(),
|
||||||
@ -229,3 +229,77 @@ pub fn resolve_imports(
|
|||||||
global_imports,
|
global_imports,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A [`Resolver`] that links two resolvers together in a chain.
|
||||||
|
pub struct ResolverChain<A: Resolver, B: Resolver> {
|
||||||
|
a: A,
|
||||||
|
b: B,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A trait for chaining resolvers together.
|
||||||
|
///
|
||||||
|
/// TODO: add example
|
||||||
|
pub trait ChainableResolver: Resolver + Sized {
|
||||||
|
/// Chain a resolver in front of the current resolver.
|
||||||
|
///
|
||||||
|
/// This will cause the second resolver to override the first.
|
||||||
|
///
|
||||||
|
/// TODO: add example
|
||||||
|
fn chain_front<U>(self, other: U) -> ResolverChain<U, Self>
|
||||||
|
where
|
||||||
|
U: Resolver,
|
||||||
|
{
|
||||||
|
ResolverChain { a: other, b: self }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Chain a resolver behind the current resolver.
|
||||||
|
///
|
||||||
|
/// This will cause the first resolver to override the second.
|
||||||
|
///
|
||||||
|
/// TODO: add example
|
||||||
|
fn chain_back<U>(self, other: U) -> ResolverChain<Self, U>
|
||||||
|
where
|
||||||
|
U: Resolver,
|
||||||
|
{
|
||||||
|
ResolverChain { a: self, b: other }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A, B> ChainableResolver for ResolverChain<A, B>
|
||||||
|
where
|
||||||
|
A: Resolver,
|
||||||
|
B: Resolver,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A, B> Resolver for ResolverChain<A, B>
|
||||||
|
where
|
||||||
|
A: Resolver,
|
||||||
|
B: Resolver,
|
||||||
|
{
|
||||||
|
fn resolve(&self, index: u32, module: &str, field: &str) -> Result<Export, u32> {
|
||||||
|
if index == 0 {
|
||||||
|
self.a
|
||||||
|
.resolve(0, module, field)
|
||||||
|
.or_else(|e1| self.b.resolve(0, module, field).map_err(|e2| e1 + e2))
|
||||||
|
} else {
|
||||||
|
match self.a.resolve(index, module, field) {
|
||||||
|
Ok(_) => self.b.resolve(index - 1, module, field).map_err(|e| e + 1),
|
||||||
|
Err(e1) => self.b.resolve(index, module, field).map_err(|e2| e1 + e2),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A, B> Clone for ResolverChain<A, B>
|
||||||
|
where
|
||||||
|
A: Resolver + Clone,
|
||||||
|
B: Resolver + Clone,
|
||||||
|
{
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
a: self.a.clone(),
|
||||||
|
b: self.b.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user