* Compute instance exports on demand.

Instead having instances eagerly compute a Vec of Externs, and bumping
the refcount for each Extern, compute Externs on demand.

This also enables `Instance::get_export` to avoid doing a linear search.

This also means that the closure returned by `get0` and friends now
holds an `InstanceHandle` to dynamically hold the instance live rather
than being scoped to a lifetime.

* Compute module imports and exports on demand too.

And compute Extern::ty on demand too.

* Add a utility function for computing an ExternType.

* Add a utility function for looking up a function's signature.

* Add a utility function for computing the ValType of a Global.

* Rename wasmtime_environ::Export to EntityIndex.

This helps differentiate it from other Export types in the tree, and
describes what it is.

* Fix a typo in a comment.

* Simplify module imports and exports.

* Make `Instance::exports` return the export names.

This significantly simplifies the public API, as it's relatively common
to need the names, and this avoids the need to do a zip with
`Module::exports`.

This also changes `ImportType` and `ExportType` to have public members
instead of private members and accessors, as I find that simplifies the
usage particularly in cases where there are temporary instances.

* Remove `Instance::module`.

This doesn't quite remove `Instance`'s `module` member, it gets a step
closer.

* Use a InstanceHandle utility function.

* Don't consume self in the `Func::get*` methods.

Instead, just create a closure containing the instance handle and the
export for them to call.

* Use `ExactSizeIterator` to avoid needing separate `num_*` methods.

* Rename `Extern::func()` etc. to `into_func()` etc.

* Revise examples to avoid using `nth`.

* Add convenience methods to instance for getting specific extern types.

* Use the convenience functions in more tests and examples.

* Avoid cloning strings for `ImportType` and `ExportType`.

* Remove more obviated clone() calls.

* Simplify `Func`'s closure state.

* Make wasmtime::Export's fields private.

This makes them more consistent with ExportType.

* Fix compilation error.

* Make a lifetime parameter explicit, and use better lifetime names.

Instead of 'me, use 'instance and 'module to make it clear what the
lifetime is.

* More lifetime cleanups.
This commit is contained in:
Dan Gohman
2020-04-20 13:55:33 -07:00
committed by GitHub
parent 967827f4b5
commit 9364eb1d98
57 changed files with 788 additions and 875 deletions

View File

@@ -166,7 +166,7 @@ impl Linker {
if !item.comes_from_same_store(&self.store) {
bail!("all linker items must be from the same store");
}
self.insert(module, name, &item.ty(), item)?;
self.insert(module, name, item)?;
Ok(self)
}
@@ -264,8 +264,8 @@ impl Linker {
if !Store::same(&self.store, instance.store()) {
bail!("all linker items must be from the same store");
}
for (export, item) in instance.module().exports().iter().zip(instance.exports()) {
self.insert(module_name, export.name(), export.ty(), item.clone())?;
for export in instance.exports() {
self.insert(module_name, export.name(), export.into_extern())?;
}
Ok(self)
}
@@ -283,7 +283,7 @@ impl Linker {
let items = self
.iter()
.filter(|(m, _, _)| *m == module)
.map(|(_, name, item)| (name.to_string(), item.clone()))
.map(|(_, name, item)| (name.to_string(), item))
.collect::<Vec<_>>();
for (name, item) in items {
self.define(as_module, &name, item)?;
@@ -291,8 +291,8 @@ impl Linker {
Ok(())
}
fn insert(&mut self, module: &str, name: &str, ty: &ExternType, item: Extern) -> Result<()> {
let key = self.import_key(module, name, ty);
fn insert(&mut self, module: &str, name: &str, item: Extern) -> Result<()> {
let key = self.import_key(module, name, item.ty());
match self.map.entry(key) {
Entry::Occupied(o) if !self.allow_shadowing => bail!(
"import of `{}::{}` with kind {:?} defined twice",
@@ -310,7 +310,7 @@ impl Linker {
Ok(())
}
fn import_key(&mut self, module: &str, name: &str, ty: &ExternType) -> ImportKey {
fn import_key(&mut self, module: &str, name: &str, ty: ExternType) -> ImportKey {
ImportKey {
module: self.intern_str(module),
name: self.intern_str(name),
@@ -318,10 +318,10 @@ impl Linker {
}
}
fn import_kind(&self, ty: &ExternType) -> ImportKind {
fn import_kind(&self, ty: ExternType) -> ImportKind {
match ty {
ExternType::Func(f) => ImportKind::Func(f.clone()),
ExternType::Global(f) => ImportKind::Global(f.clone()),
ExternType::Func(f) => ImportKind::Func(f),
ExternType::Global(f) => ImportKind::Global(f),
ExternType::Memory(_) => ImportKind::Memory,
ExternType::Table(_) => ImportKind::Table,
}
@@ -378,8 +378,8 @@ impl Linker {
pub fn instantiate(&self, module: &Module) -> Result<Instance> {
let mut imports = Vec::new();
for import in module.imports() {
if let Some(item) = self.get(import) {
imports.push(item.clone());
if let Some(item) = self.get(&import) {
imports.push(item);
continue;
}
@@ -429,23 +429,27 @@ impl Linker {
///
/// Note that multiple `Extern` items may be defined for the same
/// module/name pair.
pub fn iter(&self) -> impl Iterator<Item = (&str, &str, &Extern)> {
self.map
.iter()
.map(move |(key, item)| (&*self.strings[key.module], &*self.strings[key.name], item))
pub fn iter(&self) -> impl Iterator<Item = (&str, &str, Extern)> {
self.map.iter().map(move |(key, item)| {
(
&*self.strings[key.module],
&*self.strings[key.name],
item.clone(),
)
})
}
/// Looks up a value in this `Linker` which matches the `import` type
/// provided.
///
/// Returns `None` if no match was found.
pub fn get(&self, import: &ImportType) -> Option<&Extern> {
pub fn get(&self, import: &ImportType) -> Option<Extern> {
let key = ImportKey {
module: *self.string2idx.get(import.module())?,
name: *self.string2idx.get(import.name())?,
kind: self.import_kind(import.ty()),
};
self.map.get(&key)
self.map.get(&key).cloned()
}
/// Returns all items defined for the `module` and `name` pair.
@@ -468,10 +472,10 @@ impl Linker {
/// Returns the single item defined for the `module` and `name` pair.
///
/// Unlike the similar [`Linker::get_by_name`] method this function returns
/// a single `&Extern` item. If the `module` and `name` pair isn't defined
/// 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: &str) -> Result<Extern> {
let mut items = self.get_by_name(module, name);
let ret = items
.next()
@@ -479,6 +483,6 @@ impl Linker {
if items.next().is_some() {
bail!("too many items named `{}` in `{}`", name, module);
}
Ok(ret)
Ok(ret.clone())
}
}