Propagate optional import names to the wasmtime/C API

With the module linking proposal the field name on imports is now
optional, and only the module is required to be specified. This commit
propagates this API change to the boundary of wasmtime's API, ensuring
consumers are aware of what's optional with module linking and what
isn't. Note that it's expected that all existing users will either
update accordingly or unwrap the result since module linking is
presumably disabled.
This commit is contained in:
Alex Crichton
2020-11-23 15:17:34 -08:00
parent 1dd20b4371
commit 62be6841e4
18 changed files with 132 additions and 93 deletions

View File

@@ -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),
})?;
}

View File

@@ -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);

View File

@@ -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)
})
}

View File

@@ -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() };

View File

@@ -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()
}