diff --git a/crates/api/src/externals.rs b/crates/api/src/externals.rs index c5be5b27a0..c0b6156c77 100644 --- a/crates/api/src/externals.rs +++ b/crates/api/src/externals.rs @@ -56,7 +56,7 @@ impl Extern { } } - pub(crate) fn get_wasmtime_export(&mut self) -> wasmtime_runtime::Export { + pub(crate) fn get_wasmtime_export(&self) -> wasmtime_runtime::Export { match self { Extern::Func(f) => f.borrow().wasmtime_export().clone(), Extern::Global(g) => g.borrow().wasmtime_export().clone(), diff --git a/crates/api/src/instance.rs b/crates/api/src/instance.rs index 81b2a4ccee..166848cb12 100644 --- a/crates/api/src/instance.rs +++ b/crates/api/src/instance.rs @@ -12,23 +12,21 @@ use std::rc::Rc; use wasmtime_jit::{instantiate, Resolver, SetupError}; use wasmtime_runtime::{Export, InstanceHandle, InstantiationError}; -struct SimpleResolver { - imports: Vec<(String, String, Extern)>, +struct SimpleResolver<'a> { + imports: &'a [Extern], } -impl Resolver for SimpleResolver { - fn resolve(&mut self, name: &str, field: &str) -> Option { - // TODO speedup lookup +impl Resolver for SimpleResolver<'_> { + fn resolve(&mut self, idx: u32, _name: &str, _field: &str) -> Option { self.imports - .iter_mut() - .find(|(n, f, _)| name == n && field == f) - .map(|(_, _, e)| e.get_wasmtime_export()) + .get(idx as usize) + .map(|i| i.get_wasmtime_export()) } } pub fn instantiate_in_context( data: &[u8], - imports: Vec<(String, String, Extern)>, + imports: &[Extern], module_name: Option, context: Context, exports: Rc>>>, @@ -73,15 +71,9 @@ impl Instance { pub fn new(store: &Store, module: &Module, externs: &[Extern]) -> Result { let context = store.context().clone(); let exports = store.global_exports().clone(); - let imports = module - .imports() - .iter() - .zip(externs.iter()) - .map(|(i, e)| (i.module().to_string(), i.name().to_string(), e.clone())) - .collect::>(); let (mut instance_handle, contexts) = instantiate_in_context( module.binary().expect("binary"), - imports, + externs, module.name().cloned(), context, exports, diff --git a/crates/api/tests/import-indexes.rs b/crates/api/tests/import-indexes.rs new file mode 100644 index 0000000000..8e35f6cbf6 --- /dev/null +++ b/crates/api/tests/import-indexes.rs @@ -0,0 +1,68 @@ +use std::rc::Rc; +use wasmtime::*; + +#[test] +fn same_import_names_still_distinct() -> anyhow::Result<()> { + const WAT: &str = r#" +(module + (import "" "" (func $a (result i32))) + (import "" "" (func $b (result f32))) + (func (export "foo") (result i32) + call $a + call $b + i32.trunc_f32_u + i32.add) +) + "#; + + struct Ret1; + + impl Callable for Ret1 { + fn call(&self, params: &[Val], results: &mut [Val]) -> Result<(), Trap> { + assert!(params.is_empty()); + assert_eq!(results.len(), 1); + results[0] = 1i32.into(); + Ok(()) + } + } + + struct Ret2; + + impl Callable for Ret2 { + fn call(&self, params: &[Val], results: &mut [Val]) -> Result<(), Trap> { + assert!(params.is_empty()); + assert_eq!(results.len(), 1); + results[0] = 2.0f32.into(); + Ok(()) + } + } + + let store = Store::default(); + let wasm = wat::parse_str(WAT)?; + let module = Module::new(&store, &wasm)?; + + let imports = [ + HostRef::new(Func::new( + &store, + FuncType::new(Box::new([]), Box::new([ValType::I32])), + Rc::new(Ret1), + )) + .into(), + HostRef::new(Func::new( + &store, + FuncType::new(Box::new([]), Box::new([ValType::F32])), + Rc::new(Ret2), + )) + .into(), + ]; + let instance = Instance::new(&store, &module, &imports)?; + + let func = instance.find_export_by_name("foo").unwrap().func().unwrap(); + let results = func.borrow().call(&[])?; + assert_eq!(results.len(), 1); + match results[0] { + Val::I32(n) => assert_eq!(n, 3), + _ => panic!("unexpected type of return"), + } + Ok(()) +} diff --git a/crates/environ/src/module.rs b/crates/environ/src/module.rs index 0ff8c79d04..766eacf11c 100644 --- a/crates/environ/src/module.rs +++ b/crates/environ/src/module.rs @@ -136,17 +136,18 @@ pub struct Module { /// Unprocessed signatures exactly as provided by `declare_signature()`. pub signatures: PrimaryMap, - /// Names of imported functions. - pub imported_funcs: PrimaryMap, + /// Names of imported functions, as well as the index of the import that + /// performed this import. + pub imported_funcs: PrimaryMap, /// Names of imported tables. - pub imported_tables: PrimaryMap, + pub imported_tables: PrimaryMap, /// Names of imported memories. - pub imported_memories: PrimaryMap, + pub imported_memories: PrimaryMap, /// Names of imported globals. - pub imported_globals: PrimaryMap, + pub imported_globals: PrimaryMap, /// Types of functions, imported and local. pub functions: PrimaryMap, diff --git a/crates/environ/src/module_environ.rs b/crates/environ/src/module_environ.rs index 1acc61e63b..ee0ad17202 100644 --- a/crates/environ/src/module_environ.rs +++ b/crates/environ/src/module_environ.rs @@ -55,6 +55,7 @@ impl<'data> ModuleTranslation<'data> { pub struct ModuleEnvironment<'data> { /// The result to be filled in. result: ModuleTranslation<'data>, + imports: u32, } impl<'data> ModuleEnvironment<'data> { @@ -69,6 +70,7 @@ impl<'data> ModuleEnvironment<'data> { tunables, module_translation: None, }, + imports: 0, } } @@ -123,10 +125,12 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data ); self.result.module.functions.push(sig_index); - self.result - .module - .imported_funcs - .push((String::from(module), String::from(field))); + self.result.module.imported_funcs.push(( + String::from(module), + String::from(field), + self.imports, + )); + self.imports += 1; Ok(()) } @@ -139,10 +143,12 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data let plan = TablePlan::for_table(table, &self.result.tunables); self.result.module.table_plans.push(plan); - self.result - .module - .imported_tables - .push((String::from(module), String::from(field))); + self.result.module.imported_tables.push(( + String::from(module), + String::from(field), + self.imports, + )); + self.imports += 1; Ok(()) } @@ -160,10 +166,12 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data let plan = MemoryPlan::for_memory(memory, &self.result.tunables); self.result.module.memory_plans.push(plan); - self.result - .module - .imported_memories - .push((String::from(module), String::from(field))); + self.result.module.imported_memories.push(( + String::from(module), + String::from(field), + self.imports, + )); + self.imports += 1; Ok(()) } @@ -180,10 +188,12 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data ); self.result.module.globals.push(global); - self.result - .module - .imported_globals - .push((String::from(module), String::from(field))); + self.result.module.imported_globals.push(( + String::from(module), + String::from(field), + self.imports, + )); + self.imports += 1; Ok(()) } diff --git a/crates/jit/src/link.rs b/crates/jit/src/link.rs index 867ddea681..f8c9c62589 100644 --- a/crates/jit/src/link.rs +++ b/crates/jit/src/link.rs @@ -30,8 +30,8 @@ pub fn link_module( let mut dependencies = HashSet::new(); let mut function_imports = PrimaryMap::with_capacity(module.imported_funcs.len()); - for (index, (ref module_name, ref field)) in module.imported_funcs.iter() { - match resolver.resolve(module_name, field) { + for (index, (module_name, field, import_idx)) in module.imported_funcs.iter() { + match resolver.resolve(*import_idx, module_name, field) { Some(export_value) => match export_value { Export::Function { address, @@ -71,8 +71,8 @@ pub fn link_module( } let mut table_imports = PrimaryMap::with_capacity(module.imported_tables.len()); - for (index, (ref module_name, ref field)) in module.imported_tables.iter() { - match resolver.resolve(module_name, field) { + for (index, (module_name, field, import_idx)) in module.imported_tables.iter() { + match resolver.resolve(*import_idx, module_name, field) { Some(export_value) => match export_value { Export::Table { definition, @@ -110,8 +110,8 @@ pub fn link_module( } let mut memory_imports = PrimaryMap::with_capacity(module.imported_memories.len()); - for (index, (ref module_name, ref field)) in module.imported_memories.iter() { - match resolver.resolve(module_name, field) { + for (index, (module_name, field, import_idx)) in module.imported_memories.iter() { + match resolver.resolve(*import_idx, module_name, field) { Some(export_value) => match export_value { Export::Memory { definition, @@ -163,8 +163,8 @@ pub fn link_module( } let mut global_imports = PrimaryMap::with_capacity(module.imported_globals.len()); - for (index, (ref module_name, ref field)) in module.imported_globals.iter() { - match resolver.resolve(module_name, field) { + for (index, (module_name, field, import_idx)) in module.imported_globals.iter() { + match resolver.resolve(*import_idx, module_name, field) { Some(export_value) => match export_value { Export::Table { .. } | Export::Memory { .. } | Export::Function { .. } => { return Err(LinkError(format!( diff --git a/crates/jit/src/namespace.rs b/crates/jit/src/namespace.rs index dc2c0a9e1f..a8f5449c6f 100644 --- a/crates/jit/src/namespace.rs +++ b/crates/jit/src/namespace.rs @@ -36,7 +36,7 @@ impl Namespace { } impl Resolver for Namespace { - fn resolve(&mut self, name: &str, field: &str) -> Option { + fn resolve(&mut self, _idx: u32, name: &str, field: &str) -> Option { if let Some(instance) = self.names.get_mut(name) { instance.lookup(field) } else { diff --git a/crates/jit/src/resolver.rs b/crates/jit/src/resolver.rs index 9b8ba197cb..34f052c45a 100644 --- a/crates/jit/src/resolver.rs +++ b/crates/jit/src/resolver.rs @@ -5,15 +5,22 @@ use wasmtime_runtime::Export; /// Import resolver connects imports with available exported values. pub trait Resolver { - /// Resolve the given module/field combo. - fn resolve(&mut self, module: &str, field: &str) -> Option; + /// Resolves an import a WebAssembly module to an export it's hooked up to. + /// + /// The `index` provided is the index of the import in the wasm module + /// that's being resolved. For example 1 means that it's the second import + /// listed in the wasm module. + /// + /// The `module` and `field` arguments provided are the module/field names + /// listed on the import itself. + fn resolve(&mut self, index: u32, module: &str, field: &str) -> Option; } /// `Resolver` implementation that always resolves to `None`. pub struct NullResolver {} impl Resolver for NullResolver { - fn resolve(&mut self, _module: &str, _field: &str) -> Option { + fn resolve(&mut self, _idx: u32, _module: &str, _field: &str) -> Option { None } }