Skip to content

Commit

Permalink
Add ModuleExport to skip repeated string lookups
Browse files Browse the repository at this point in the history
  • Loading branch information
grovesNL committed Jan 27, 2024
1 parent 5c0027b commit 3bc1578
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 4 deletions.
37 changes: 36 additions & 1 deletion crates/wasmtime/src/instance.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::linker::{Definition, DefinitionType};
use crate::module::ModuleExport;
use crate::store::{InstanceId, StoreOpaque, Stored};
use crate::types::matching;
use crate::{
Expand All @@ -9,7 +10,9 @@ use anyhow::{anyhow, bail, Context, Result};
use std::mem;
use std::ptr::NonNull;
use std::sync::Arc;
use wasmtime_environ::{EntityType, FuncIndex, GlobalIndex, MemoryIndex, PrimaryMap, TableIndex};
use wasmtime_environ::{
EntityType, FuncIndex, GlobalIndex, MemoryIndex, PrimaryMap, TableIndex,
};
use wasmtime_runtime::{
Imports, InstanceAllocationRequest, StorePtr, VMContext, VMFuncRef, VMFunctionImport,
VMGlobalImport, VMMemoryImport, VMNativeCallFunction, VMOpaqueContext, VMTableImport,
Expand Down Expand Up @@ -450,6 +453,38 @@ impl Instance {
Some(item)
}

/// Looks up exported [`Extern`] value by a [`ModuleExport`] value.
///
/// This is similar to [`Instance::get_export`] but uses a [`ModuleExport`] value to avoid
/// string lookups where possible.
///
/// This method will search the module for an export with a matching entity index and return
/// the value, if found.
///
/// Returns `None` if there was no export with a matching entity index.
///
/// # Panics
///
/// Panics if `store` does not own this instance.
pub fn get_module_export(
&self,
mut store: impl AsContextMut,
export: &ModuleExport,
) -> Option<Extern> {
let store = store.as_context_mut().0;
let data = &store[self.0];

let id = data.id;
let instance = store.instance_mut(id);

let item = unsafe {
Extern::from_wasmtime_export(instance.get_export_by_index(export.entity), store)
};
let data = &mut store[self.0];
data.exports[export.export_name_index] = Some(item.clone());
Some(item)
}

/// Looks up an exported [`Func`] value by name.
///
/// Returns `None` if there was no export named `name`, or if there was but
Expand Down
2 changes: 1 addition & 1 deletion crates/wasmtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ pub use crate::instantiate::CompiledModule;
pub use crate::limits::*;
pub use crate::linker::*;
pub use crate::memory::*;
pub use crate::module::Module;
pub use crate::module::{Module, ModuleExport};
#[cfg(feature = "profiling")]
pub use crate::profiling::GuestProfiler;
pub use crate::r#ref::ExternRef;
Expand Down
60 changes: 58 additions & 2 deletions crates/wasmtime/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ use std::ptr::NonNull;
use std::sync::Arc;
use wasmparser::{Parser, ValidPayload, Validator};
use wasmtime_environ::{
CompiledModuleInfo, DefinedFuncIndex, DefinedMemoryIndex, HostPtr, ModuleEnvironment,
ModuleTypes, ObjectKind, VMOffsets,
CompiledModuleInfo, DefinedFuncIndex, DefinedMemoryIndex, EntityIndex, HostPtr, ModuleEnvironment, ModuleTypes, ObjectKind, VMOffsets
};
use wasmtime_runtime::{
CompiledModuleId, MemoryImage, MmapVec, ModuleMemoryImages, VMArrayCallFunction,
Expand Down Expand Up @@ -897,6 +896,52 @@ impl Module {
))
}

/// Looks up an export in this [`Module`] by name to get its index.
///
/// This function will return the index of an export with the given name. This can be useful
/// to avoid the cost of looking up the export by name multiple times. Instead the index can be
/// stored, and used to look up
///
/// # Examples
///
/// There may be no export with that name:
///
/// ```
/// # use wasmtime::*;
/// # fn main() -> anyhow::Result<()> {
/// # let engine = Engine::default();
/// let module = Module::new(&engine, "(module)")?;
/// assert!(module.get_export("foo").is_none());
/// # Ok(())
/// # }
/// ```
///
/// When there is an export with that name, it is returned:
///
/// ```
/// # use wasmtime::*;
/// # fn main() -> anyhow::Result<()> {
/// # let engine = Engine::default();
/// let wat = r#"
/// (module
/// (func (export "foo"))
/// (memory (export "memory") 1)
/// )
/// "#;
/// let module = Module::new(&engine, wat)?;
/// let foo = module.get_export_index("foo");
/// assert!(foo.is_some());
/// ```
pub fn get_export_index(&self, name: &str) -> Option<ModuleExport> {
let compiled_module = self.compiled_module();
let module = compiled_module.module();
module.exports.get_full(name).map(|(export_name_index, _, &entity)| ModuleExport {
module: compiled_module.unique_id(),
entity,
export_name_index,
})
}

/// Returns the [`Engine`] that this [`Module`] was compiled by.
pub fn engine(&self) -> &Engine {
&self.inner.engine
Expand Down Expand Up @@ -1117,6 +1162,17 @@ impl Drop for ModuleInner {
}
}

/// Describes the location of an export in a module.
#[derive(Copy, Clone)]
pub struct ModuleExport {
/// The module that this export is defined in.
pub module: CompiledModuleId,
/// A raw index into the wasm module.
pub entity: EntityIndex,
/// The index of the export name.
pub export_name_index: usize,
}

fn _assert_send_sync() {
fn _assert<T: Send + Sync>() {}
_assert::<Module>();
Expand Down

0 comments on commit 3bc1578

Please sign in to comment.