Merge pull request #2446 from alexcrichton/option-name
Propagate optional import names to the wasmtime/C API
This commit is contained in:
@@ -960,7 +960,8 @@
|
||||
*
|
||||
* This function takes ownership of the `module`, `name`, and
|
||||
* #wasm_externtype_t arguments. The caller is responsible for deleting the
|
||||
* returned value.
|
||||
* returned value. Note that `name` can be `NULL` where in the module linking
|
||||
* proposal the import name can be omitted.
|
||||
*
|
||||
* \fn const wasm_name_t* wasm_importtype_module(const wasm_importtype_t *);
|
||||
* \brief Returns the module this import is importing from.
|
||||
@@ -972,7 +973,9 @@
|
||||
* \brief Returns the name this import is importing from.
|
||||
*
|
||||
* The returned memory is owned by the #wasm_importtype_t argument, the caller
|
||||
* should not deallocate it.
|
||||
* should not deallocate it. Note that `NULL` can be returned which means
|
||||
* that the import name is not provided. This is for imports with the module
|
||||
* linking proposal that only have the module specified.
|
||||
*
|
||||
* \fn const wasm_externtype_t* wasm_importtype_type(const wasm_importtype_t *);
|
||||
* \brief Returns the type of item this import is importing.
|
||||
|
||||
@@ -116,7 +116,7 @@ pub extern "C" fn wasmtime_linker_get_default(
|
||||
pub extern "C" fn wasmtime_linker_get_one_by_name(
|
||||
linker: &wasmtime_linker_t,
|
||||
module: &wasm_name_t,
|
||||
name: &wasm_name_t,
|
||||
name: Option<&wasm_name_t>,
|
||||
item_ptr: &mut *mut wasm_extern_t,
|
||||
) -> Option<Box<wasmtime_error_t>> {
|
||||
let linker = &linker.linker;
|
||||
@@ -124,9 +124,12 @@ pub extern "C" fn wasmtime_linker_get_one_by_name(
|
||||
Ok(s) => s,
|
||||
Err(_) => return bad_utf8(),
|
||||
};
|
||||
let name = match str::from_utf8(name.as_slice()) {
|
||||
Ok(s) => s,
|
||||
Err(_) => return bad_utf8(),
|
||||
let name = match name {
|
||||
Some(name) => match str::from_utf8(name.as_slice()) {
|
||||
Ok(s) => Some(s),
|
||||
Err(_) => return bad_utf8(),
|
||||
},
|
||||
None => None,
|
||||
};
|
||||
handle_result(linker.get_one_by_name(module, name), |which| {
|
||||
*item_ptr = Box::into_raw(Box::new(wasm_extern_t { which }))
|
||||
|
||||
@@ -51,7 +51,13 @@ pub extern "C" fn wasmtime_module_new(
|
||||
handle_result(Module::from_binary(&engine.engine, binary), |module| {
|
||||
let imports = module
|
||||
.imports()
|
||||
.map(|i| wasm_importtype_t::new(i.module().to_owned(), i.name().to_owned(), i.ty()))
|
||||
.map(|i| {
|
||||
wasm_importtype_t::new(
|
||||
i.module().to_owned(),
|
||||
i.name().map(|s| s.to_owned()),
|
||||
i.ty(),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let exports = module
|
||||
.exports()
|
||||
@@ -118,7 +124,13 @@ pub extern "C" fn wasm_module_obtain(
|
||||
}
|
||||
let imports = module
|
||||
.imports()
|
||||
.map(|i| wasm_importtype_t::new(i.module().to_owned(), i.name().to_owned(), i.ty()))
|
||||
.map(|i| {
|
||||
wasm_importtype_t::new(
|
||||
i.module().to_owned(),
|
||||
i.name().map(|s| s.to_owned()),
|
||||
i.ty(),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let exports = module
|
||||
.exports()
|
||||
@@ -175,7 +187,13 @@ pub extern "C" fn wasmtime_module_deserialize(
|
||||
|module| {
|
||||
let imports = module
|
||||
.imports()
|
||||
.map(|i| wasm_importtype_t::new(i.module().to_owned(), i.name().to_owned(), i.ty()))
|
||||
.map(|i| {
|
||||
wasm_importtype_t::new(
|
||||
i.module().to_owned(),
|
||||
i.name().map(|s| s.to_owned()),
|
||||
i.ty(),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let exports = module
|
||||
.exports()
|
||||
|
||||
@@ -6,7 +6,7 @@ use wasmtime::ExternType;
|
||||
#[derive(Clone)]
|
||||
pub struct wasm_importtype_t {
|
||||
pub(crate) module: String,
|
||||
pub(crate) name: String,
|
||||
pub(crate) name: Option<String>,
|
||||
pub(crate) ty: ExternType,
|
||||
module_cache: OnceCell<wasm_name_t>,
|
||||
name_cache: OnceCell<wasm_name_t>,
|
||||
@@ -16,7 +16,7 @@ pub struct wasm_importtype_t {
|
||||
wasmtime_c_api_macros::declare_ty!(wasm_importtype_t);
|
||||
|
||||
impl wasm_importtype_t {
|
||||
pub(crate) fn new(module: String, name: String, ty: ExternType) -> wasm_importtype_t {
|
||||
pub(crate) fn new(module: String, name: Option<String>, ty: ExternType) -> wasm_importtype_t {
|
||||
wasm_importtype_t {
|
||||
module,
|
||||
name,
|
||||
@@ -31,13 +31,16 @@ impl wasm_importtype_t {
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wasm_importtype_new(
|
||||
module: &mut wasm_name_t,
|
||||
name: &mut wasm_name_t,
|
||||
name: Option<&mut wasm_name_t>,
|
||||
ty: Box<wasm_externtype_t>,
|
||||
) -> Option<Box<wasm_importtype_t>> {
|
||||
let module = module.take();
|
||||
let name = name.take();
|
||||
let name = name.map(|n| n.take());
|
||||
let module = String::from_utf8(module).ok()?;
|
||||
let name = String::from_utf8(name).ok()?;
|
||||
let name = match name {
|
||||
Some(name) => Some(String::from_utf8(name).ok()?),
|
||||
None => None,
|
||||
};
|
||||
Some(Box::new(wasm_importtype_t::new(module, name, ty.ty())))
|
||||
}
|
||||
|
||||
@@ -48,9 +51,12 @@ pub extern "C" fn wasm_importtype_module(it: &wasm_importtype_t) -> &wasm_name_t
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wasm_importtype_name(it: &wasm_importtype_t) -> &wasm_name_t {
|
||||
it.name_cache
|
||||
.get_or_init(|| wasm_name_t::from_name(it.name.clone()))
|
||||
pub extern "C" fn wasm_importtype_name(it: &wasm_importtype_t) -> Option<&wasm_name_t> {
|
||||
let name = it.name.as_ref()?;
|
||||
Some(
|
||||
it.name_cache
|
||||
.get_or_init(|| wasm_name_t::from_name(name.to_string())),
|
||||
)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
||||
@@ -328,7 +328,7 @@ pub extern "C" fn wasi_instance_bind_import<'a>(
|
||||
import: &wasm_importtype_t,
|
||||
) -> Option<&'a wasm_extern_t> {
|
||||
let module = &import.module;
|
||||
let name = str::from_utf8(import.name.as_bytes()).ok()?;
|
||||
let name = str::from_utf8(import.name.as_ref()?.as_bytes()).ok()?;
|
||||
|
||||
let export = match &instance.wasi {
|
||||
WasiInstance::Preview1(wasi) => {
|
||||
|
||||
@@ -163,7 +163,7 @@ pub struct Module {
|
||||
pub name: Option<String>,
|
||||
|
||||
/// All import records, in the order they are declared in the module.
|
||||
pub imports: Vec<(String, String, EntityIndex)>,
|
||||
pub imports: Vec<(String, Option<String>, EntityIndex)>,
|
||||
|
||||
/// Exported entities.
|
||||
pub exports: IndexMap<String, EntityIndex>,
|
||||
|
||||
@@ -264,7 +264,7 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data
|
||||
&mut self,
|
||||
index: TypeIndex,
|
||||
module: &str,
|
||||
field: &str,
|
||||
field: Option<&str>,
|
||||
) -> WasmResult<()> {
|
||||
debug_assert_eq!(
|
||||
self.result.module.functions.len(),
|
||||
@@ -275,7 +275,7 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data
|
||||
let func_index = self.result.module.functions.push(sig_index);
|
||||
self.result.module.imports.push((
|
||||
module.to_owned(),
|
||||
field.to_owned(),
|
||||
field.map(|s| s.to_owned()),
|
||||
EntityIndex::Function(func_index),
|
||||
));
|
||||
self.result.module.num_imported_funcs += 1;
|
||||
@@ -283,7 +283,12 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn declare_table_import(&mut self, table: Table, module: &str, field: &str) -> WasmResult<()> {
|
||||
fn declare_table_import(
|
||||
&mut self,
|
||||
table: Table,
|
||||
module: &str,
|
||||
field: Option<&str>,
|
||||
) -> WasmResult<()> {
|
||||
debug_assert_eq!(
|
||||
self.result.module.table_plans.len(),
|
||||
self.result.module.num_imported_tables,
|
||||
@@ -293,7 +298,7 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data
|
||||
let table_index = self.result.module.table_plans.push(plan);
|
||||
self.result.module.imports.push((
|
||||
module.to_owned(),
|
||||
field.to_owned(),
|
||||
field.map(|s| s.to_owned()),
|
||||
EntityIndex::Table(table_index),
|
||||
));
|
||||
self.result.module.num_imported_tables += 1;
|
||||
@@ -304,7 +309,7 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data
|
||||
&mut self,
|
||||
memory: Memory,
|
||||
module: &str,
|
||||
field: &str,
|
||||
field: Option<&str>,
|
||||
) -> WasmResult<()> {
|
||||
debug_assert_eq!(
|
||||
self.result.module.memory_plans.len(),
|
||||
@@ -318,7 +323,7 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data
|
||||
let memory_index = self.result.module.memory_plans.push(plan);
|
||||
self.result.module.imports.push((
|
||||
module.to_owned(),
|
||||
field.to_owned(),
|
||||
field.map(|s| s.to_owned()),
|
||||
EntityIndex::Memory(memory_index),
|
||||
));
|
||||
self.result.module.num_imported_memories += 1;
|
||||
@@ -329,7 +334,7 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data
|
||||
&mut self,
|
||||
global: Global,
|
||||
module: &str,
|
||||
field: &str,
|
||||
field: Option<&str>,
|
||||
) -> WasmResult<()> {
|
||||
debug_assert_eq!(
|
||||
self.result.module.globals.len(),
|
||||
@@ -339,7 +344,7 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data
|
||||
let global_index = self.result.module.globals.push(global);
|
||||
self.result.module.imports.push((
|
||||
module.to_owned(),
|
||||
field.to_owned(),
|
||||
field.map(|s| s.to_owned()),
|
||||
EntityIndex::Global(global_index),
|
||||
));
|
||||
self.result.module.num_imported_globals += 1;
|
||||
|
||||
@@ -309,8 +309,9 @@ fn with_imports<R>(
|
||||
};
|
||||
|
||||
for (expected, actual) in m.imports.iter().zip(externs) {
|
||||
process(&expected.2, actual).with_context(|| {
|
||||
format!("incompatible import type for {}/{}", expected.0, expected.1)
|
||||
process(&expected.2, actual).with_context(|| match &expected.1 {
|
||||
Some(name) => format!("incompatible import type for {}/{}", expected.0, name),
|
||||
None => format!("incompatible import type for {}", expected.0),
|
||||
})?;
|
||||
}
|
||||
|
||||
|
||||
@@ -371,7 +371,7 @@ impl Linker {
|
||||
/// "#;
|
||||
/// let module = Module::new(store.engine(), wat)?;
|
||||
/// linker.module("", &module)?;
|
||||
/// let count = linker.get_one_by_name("", "run")?.into_func().unwrap().get0::<i32>()?()?;
|
||||
/// let count = linker.get_one_by_name("", Some("run"))?.into_func().unwrap().get0::<i32>()?()?;
|
||||
/// assert_eq!(count, 0, "a Command should get a fresh instance on each invocation");
|
||||
///
|
||||
/// # Ok(())
|
||||
@@ -592,28 +592,27 @@ impl Linker {
|
||||
let mut options = Vec::new();
|
||||
for i in self.map.keys() {
|
||||
if &*self.strings[i.module] != import.module()
|
||||
|| &*self.strings[i.name] != import.name()
|
||||
|| self.strings.get(i.name).map(|s| &**s) != import.name()
|
||||
{
|
||||
continue;
|
||||
}
|
||||
options.push(format!(" * {:?}\n", i.kind));
|
||||
}
|
||||
let desc = match import.name() {
|
||||
Some(name) => format!("{}::{}", import.module(), name),
|
||||
None => import.module().to_string(),
|
||||
};
|
||||
if options.is_empty() {
|
||||
return anyhow!(
|
||||
"unknown import: `{}::{}` has not been defined",
|
||||
import.module(),
|
||||
import.name()
|
||||
);
|
||||
return anyhow!("unknown import: `{}` has not been defined", desc);
|
||||
}
|
||||
|
||||
options.sort();
|
||||
|
||||
anyhow!(
|
||||
"incompatible import type for `{}::{}` specified\n\
|
||||
desired signature was: {:?}\n\
|
||||
signatures available:\n\n{}",
|
||||
import.module(),
|
||||
import.name(),
|
||||
"incompatible import type for `{}` specified\n\
|
||||
desired signature was: {:?}\n\
|
||||
signatures available:\n\n{}",
|
||||
desc,
|
||||
import.ty(),
|
||||
options.concat(),
|
||||
)
|
||||
@@ -649,7 +648,10 @@ impl Linker {
|
||||
pub fn get(&self, import: &ImportType) -> Option<Extern> {
|
||||
let key = ImportKey {
|
||||
module: *self.string2idx.get(import.module())?,
|
||||
name: *self.string2idx.get(import.name())?,
|
||||
name: match import.name() {
|
||||
Some(name) => *self.string2idx.get(name)?,
|
||||
None => usize::max_value(),
|
||||
},
|
||||
kind: self.import_kind(import.ty()),
|
||||
};
|
||||
self.map.get(&key).cloned()
|
||||
@@ -662,12 +664,13 @@ impl Linker {
|
||||
pub fn get_by_name<'a: 'p, 'p>(
|
||||
&'a self,
|
||||
module: &'p str,
|
||||
name: &'p str,
|
||||
name: Option<&'p str>,
|
||||
) -> impl Iterator<Item = &'a Extern> + 'p {
|
||||
self.map
|
||||
.iter()
|
||||
.filter(move |(key, _item)| {
|
||||
&*self.strings[key.module] == module && &*self.strings[key.name] == name
|
||||
&*self.strings[key.module] == module
|
||||
&& self.strings.get(key.name).map(|s| &**s) == name
|
||||
})
|
||||
.map(|(_, item)| item)
|
||||
}
|
||||
@@ -678,13 +681,17 @@ impl Linker {
|
||||
/// a single `Extern` item. If the `module` and `name` pair isn't defined
|
||||
/// in this linker then an error is returned. If more than one value exists
|
||||
/// for the `module` and `name` pairs, then an error is returned as well.
|
||||
pub fn get_one_by_name(&self, module: &str, name: &str) -> Result<Extern> {
|
||||
pub fn get_one_by_name(&self, module: &str, name: Option<&str>) -> Result<Extern> {
|
||||
let err_msg = || match name {
|
||||
Some(name) => format!("named `{}` in `{}`", name, module),
|
||||
None => format!("named `{}`", module),
|
||||
};
|
||||
let mut items = self.get_by_name(module, name);
|
||||
let ret = items
|
||||
.next()
|
||||
.ok_or_else(|| anyhow!("no item named `{}` in `{}`", name, module))?;
|
||||
.ok_or_else(|| anyhow!("no item {}", err_msg()))?;
|
||||
if items.next().is_some() {
|
||||
bail!("too many items named `{}` in `{}`", name, module);
|
||||
bail!("too many items {}", err_msg());
|
||||
}
|
||||
Ok(ret.clone())
|
||||
}
|
||||
@@ -694,7 +701,7 @@ impl Linker {
|
||||
/// An export with an empty string is considered to be a "default export".
|
||||
/// "_start" is also recognized for compatibility.
|
||||
pub fn get_default(&self, module: &str) -> Result<Func> {
|
||||
let mut items = self.get_by_name(module, "");
|
||||
let mut items = self.get_by_name(module, Some(""));
|
||||
if let Some(external) = items.next() {
|
||||
if items.next().is_some() {
|
||||
bail!("too many items named `` in `{}`", module);
|
||||
@@ -706,7 +713,7 @@ impl Linker {
|
||||
}
|
||||
|
||||
// For compatibility, also recognize "_start".
|
||||
let mut items = self.get_by_name(module, "_start");
|
||||
let mut items = self.get_by_name(module, Some("_start"));
|
||||
if let Some(external) = items.next() {
|
||||
if items.next().is_some() {
|
||||
bail!("too many items named `_start` in `{}`", module);
|
||||
|
||||
@@ -406,7 +406,7 @@ impl Module {
|
||||
/// assert_eq!(module.imports().len(), 1);
|
||||
/// let import = module.imports().next().unwrap();
|
||||
/// assert_eq!(import.module(), "host");
|
||||
/// assert_eq!(import.name(), "foo");
|
||||
/// assert_eq!(import.name(), Some("foo"));
|
||||
/// match import.ty() {
|
||||
/// ExternType::Func(_) => { /* ... */ }
|
||||
/// _ => panic!("unexpected import type!"),
|
||||
@@ -423,7 +423,7 @@ impl Module {
|
||||
.iter()
|
||||
.map(move |(module_name, name, entity_index)| {
|
||||
let r#type = EntityType::new(entity_index, module);
|
||||
ImportType::new(module_name, name, r#type)
|
||||
ImportType::new(module_name, name.as_deref(), r#type)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -43,11 +43,9 @@ pub fn create_global(store: &Store, gt: &GlobalType, val: Val) -> Result<StoreIn
|
||||
let local_sig_index = module.signatures.push(wasm.clone());
|
||||
let func_index = module.functions.push(local_sig_index);
|
||||
module.num_imported_funcs = 1;
|
||||
module.imports.push((
|
||||
"".into(),
|
||||
"".into(),
|
||||
wasm::EntityIndex::Function(func_index),
|
||||
));
|
||||
module
|
||||
.imports
|
||||
.push(("".into(), None, wasm::EntityIndex::Function(func_index)));
|
||||
|
||||
let f = f.caller_checked_anyfunc();
|
||||
let f = unsafe { f.as_ref() };
|
||||
|
||||
@@ -483,13 +483,10 @@ impl ModuleType {
|
||||
|
||||
/// Returns the list of imports associated with this module type.
|
||||
pub fn imports(&self) -> impl ExactSizeIterator<Item = ImportType<'_>> {
|
||||
self.imports.iter().map(|(module, name, ty)| {
|
||||
ImportType {
|
||||
module,
|
||||
// FIXME(#2094) should thread through the `Option`
|
||||
name: name.as_ref().unwrap(),
|
||||
ty: EntityOrExtern::Extern(ty),
|
||||
}
|
||||
self.imports.iter().map(|(module, name, ty)| ImportType {
|
||||
module,
|
||||
name: name.as_deref(),
|
||||
ty: EntityOrExtern::Extern(ty),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -676,7 +673,7 @@ pub struct ImportType<'module> {
|
||||
module: &'module str,
|
||||
|
||||
/// The field of the import.
|
||||
name: &'module str,
|
||||
name: Option<&'module str>,
|
||||
|
||||
/// The type of the import.
|
||||
ty: EntityOrExtern<'module>,
|
||||
@@ -693,7 +690,7 @@ impl<'module> ImportType<'module> {
|
||||
/// is of type `ty`.
|
||||
pub(crate) fn new(
|
||||
module: &'module str,
|
||||
name: &'module str,
|
||||
name: Option<&'module str>,
|
||||
ty: EntityType<'module>,
|
||||
) -> ImportType<'module> {
|
||||
ImportType {
|
||||
@@ -710,7 +707,10 @@ impl<'module> ImportType<'module> {
|
||||
|
||||
/// Returns the field name of the module that this import is expected to
|
||||
/// come from.
|
||||
pub fn name(&self) -> &'module str {
|
||||
///
|
||||
/// Note that the name can be `None` for the module linking proposal. If the
|
||||
/// module linking proposal is not enabled it's safe to unwrap this.
|
||||
pub fn name(&self) -> Option<&'module str> {
|
||||
self.name
|
||||
}
|
||||
|
||||
@@ -726,8 +726,8 @@ impl<'module> ImportType<'module> {
|
||||
impl<'module> fmt::Debug for ImportType<'module> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("ImportType")
|
||||
.field("module", &self.module().to_owned())
|
||||
.field("name", &self.name().to_owned())
|
||||
.field("module", &self.module())
|
||||
.field("name", &self.name())
|
||||
.field("ty", &self.ty())
|
||||
.finish()
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ impl WastContext {
|
||||
|
||||
fn get_export(&self, module: Option<&str>, name: &str) -> Result<Extern> {
|
||||
match module {
|
||||
Some(module) => self.linker.get_one_by_name(module, name),
|
||||
Some(module) => self.linker.get_one_by_name(module, Some(name)),
|
||||
None => self
|
||||
.current
|
||||
.as_ref()
|
||||
|
||||
Reference in New Issue
Block a user