Redesign import namespaces

This commit is contained in:
Lachlan Sneff
2019-01-12 16:24:17 -05:00
parent 8a0ea0b66d
commit 80a1fce329
6 changed files with 72 additions and 62 deletions

View File

@ -1,3 +1,4 @@
use hashbrown::HashMap;
use std::rc::Rc; use std::rc::Rc;
use wabt::wat2wasm; use wabt::wat2wasm;
use wasmer_clif_backend::CraneliftCompiler; use wasmer_clif_backend::CraneliftCompiler;
@ -15,9 +16,8 @@ fn main() -> Result<(), String> {
let wasm_binary = wat2wasm(IMPORT_MODULE.as_bytes()).expect("WAST not valid or malformed"); let wasm_binary = wat2wasm(IMPORT_MODULE.as_bytes()).expect("WAST not valid or malformed");
let inner_module = runtime::compile(&wasm_binary, &CraneliftCompiler::new())?; let inner_module = runtime::compile(&wasm_binary, &CraneliftCompiler::new())?;
let mut imports = Imports::new(); let mut env_namespace = HashMap::new();
imports.register_export( env_namespace.insert(
"env",
"print_i32", "print_i32",
Export::Function { Export::Function {
func: unsafe { FuncRef::new(print_num as _) }, func: unsafe { FuncRef::new(print_num as _) },
@ -28,13 +28,15 @@ fn main() -> Result<(), String> {
}, },
}, },
); );
let mut imports = Imports::new();
imports.register("env", env_namespace);
let imports = Rc::new(imports); let imports = Rc::new(imports);
let inner_instance = inner_module.instantiate(imports)?; let inner_instance = inner_module.instantiate(imports)?;
let mut outer_imports = Imports::new(); let mut outer_imports = Imports::new();
outer_imports.register_instance("env", inner_instance); outer_imports.register("env", inner_instance);
let outer_imports = Rc::new(outer_imports); let outer_imports = Rc::new(outer_imports);
let outer_module = runtime::compile(EXAMPLE_WASM, &CraneliftCompiler::new())?; let outer_module = runtime::compile(EXAMPLE_WASM, &CraneliftCompiler::new())?;
let mut outer_instance = outer_module.instantiate(outer_imports)?; let mut outer_instance = outer_module.instantiate(outer_imports)?;
@ -57,15 +59,3 @@ static IMPORT_MODULE: &str = r#"
get_local $p0 get_local $p0
call $print_i32)) call $print_i32))
"#; "#;
fn generate_imports() -> Rc<Imports> {
let wasm_binary = wat2wasm(IMPORT_MODULE.as_bytes()).expect("WAST not valid or malformed");
let module = wasmer_runtime::compile(&wasm_binary[..], &CraneliftCompiler::new())
.expect("WASM can't be compiled");
let instance = module
.instantiate(Rc::new(Imports::new()))
.expect("WASM can't be instantiated");
let mut imports = Imports::new();
imports.register_instance("env", instance);
Rc::new(imports)
}

View File

@ -21,7 +21,7 @@ fn generate_imports() -> Rc<Imports> {
// let module = wasmer_runtime::compile(&wasm_binary[..], &CraneliftCompiler::new()).expect("WASM can't be compiled"); // let module = wasmer_runtime::compile(&wasm_binary[..], &CraneliftCompiler::new()).expect("WASM can't be compiled");
// let instance = module.instantiate(Rc::new(Imports::new())).expect("WASM can't be instantiated"); // let instance = module.instantiate(Rc::new(Imports::new())).expect("WASM can't be instantiated");
let imports = Imports::new(); let imports = Imports::new();
// imports.register_instance("spectest", instance); // imports.register("spectest", instance);
Rc::new(imports) Rc::new(imports)
} }

View File

@ -4,7 +4,7 @@ use crate::{
vm, vm,
}; };
#[derive(Debug, Clone)] #[derive(Debug, Copy, Clone)]
pub enum Context { pub enum Context {
External(*mut vm::Ctx), External(*mut vm::Ctx),
Internal, Internal,

View File

@ -1,17 +1,27 @@
use crate::{export::Export, Instance}; use crate::export::Export;
use hashbrown::{hash_map::Entry, HashMap}; use hashbrown::{hash_map::Entry, HashMap};
pub trait ImportResolver { pub trait ImportResolver {
fn get(&self, namespace: &str, name: &str) -> Option<Export>; fn get(&self, namespace: &str, name: &str) -> Option<Export>;
} }
enum Namespace { pub trait Namespace {
Instance(Box<Instance>), fn get_export(&self, name: &str) -> Option<Export>;
UserSupplied(HashMap<String, Export>), }
impl Namespace for HashMap<String, Export> {
fn get_export(&self, name: &str) -> Option<Export> {
self.get(name).cloned()
}
}
impl<'a> Namespace for HashMap<&'a str, Export> {
fn get_export(&self, name: &str) -> Option<Export> {
self.get(name).cloned()
}
} }
pub struct Imports { pub struct Imports {
map: HashMap<String, Namespace>, map: HashMap<String, Box<dyn Namespace>>,
} }
impl Imports { impl Imports {
@ -21,38 +31,50 @@ impl Imports {
} }
} }
pub fn register_instance(&mut self, namespace: impl Into<String>, instance: Box<Instance>) { pub fn register(
match self.map.entry(namespace.into()) {
Entry::Vacant(empty) => empty.insert(Namespace::Instance(instance)),
Entry::Occupied(_) => {
panic!("cannot register an instance in a namespace that already exists")
}
};
}
pub fn register_export(
&mut self, &mut self,
namespace: impl Into<String>,
name: impl Into<String>, name: impl Into<String>,
export: Export, namespace: impl Namespace + 'static,
) { ) -> Option<Box<dyn Namespace>> {
let namespace_item = self match self.map.entry(name.into()) {
.map Entry::Vacant(empty) => {
.entry(namespace.into()) empty.insert(Box::new(namespace));
.or_insert_with(|| Namespace::UserSupplied(HashMap::new())); None
}
match namespace_item { Entry::Occupied(mut occupied) => Some(occupied.insert(Box::new(namespace))),
Namespace::UserSupplied(ref mut map) => map.insert(name.into(), export), }
Namespace::Instance(_) => panic!("cannot register an export in a namespace that has already been used to register an instance"),
};
} }
// pub fn register_instance(&mut self, namespace: impl Into<String>, instance: Box<Instance>) {
// match self.map.entry(namespace.into()) {
// Entry::Vacant(empty) => empty.insert(Namespace::Instance(instance)),
// Entry::Occupied(_) => {
// panic!("cannot register an instance in a namespace that already exists")
// }
// };
// }
// pub fn register_export(
// &mut self,
// namespace: impl Into<String>,
// name: impl Into<String>,
// export: Export,
// ) {
// let namespace_item = self
// .map
// .entry(namespace.into())
// .or_insert_with(|| Namespace::UserSupplied(HashMap::new()));
// match namespace_item {
// Namespace::UserSupplied(ref mut map) => map.insert(name.into(), export),
// Namespace::Instance(_) => panic!("cannot register an export in a namespace that has already been used to register an instance"),
// };
// }
} }
impl ImportResolver for Imports { impl ImportResolver for Imports {
fn get(&self, namespace: &str, name: &str) -> Option<Export> { fn get(&self, namespace_name: &str, name: &str) -> Option<Export> {
match self.map.get(namespace)? { let namespace = self.map.get(namespace_name)?;
Namespace::UserSupplied(map) => map.get(name).cloned(), namespace.get_export(name)
Namespace::Instance(instance) => instance.get_export(name).ok(),
}
} }
} }

View File

@ -2,7 +2,7 @@ use crate::recovery::call_protected;
use crate::{ use crate::{
backing::{ImportBacking, LocalBacking}, backing::{ImportBacking, LocalBacking},
export::{Context, Export}, export::{Context, Export},
import::ImportResolver, import::{ImportResolver, Namespace},
module::{ExportIndex, Module}, module::{ExportIndex, Module},
types::{FuncIndex, FuncSig, MapIndex, Memory, MemoryIndex, Type, Value}, types::{FuncIndex, FuncSig, MapIndex, Memory, MemoryIndex, Type, Value},
vm, vm,
@ -130,16 +130,6 @@ impl Instance {
}) })
} }
pub fn get_export(&self, name: &str) -> Result<Export, String> {
let export_index = self
.module
.exports
.get(name)
.ok_or_else(|| format!("there is no export with that name: {}", name))?;
Ok(self.get_export_from_index(export_index))
}
pub fn exports(&self) -> ExportIter { pub fn exports(&self) -> ExportIter {
ExportIter::new(self) ExportIter::new(self)
} }
@ -238,6 +228,14 @@ impl Instance {
} }
} }
impl Namespace for Box<Instance> {
fn get_export(&self, name: &str) -> Option<Export> {
let export_index = self.module.exports.get(name)?;
Some(self.get_export_from_index(export_index))
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct FuncRef(*const vm::Func); pub struct FuncRef(*const vm::Func);

View File

@ -22,7 +22,7 @@ pub fn generate_imports() -> Rc<Imports> {
.instantiate(Rc::new(Imports::new())) .instantiate(Rc::new(Imports::new()))
.expect("WASM can't be instantiated"); .expect("WASM can't be instantiated");
let mut imports = Imports::new(); let mut imports = Imports::new();
imports.register_instance("spectest", instance); imports.register("spectest", instance);
Rc::new(imports) Rc::new(imports)
} }