Skip to content

Commit

Permalink
Expose ModuleExport to avoid repeated string lookups
Browse files Browse the repository at this point in the history
  • Loading branch information
grovesNL committed Jan 28, 2024
1 parent 5c0027b commit 3bb7413
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 16 deletions.
70 changes: 57 additions & 13 deletions crates/wasmtime/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@ use crate::linker::{Definition, DefinitionType};
use crate::store::{InstanceId, StoreOpaque, Stored};
use crate::types::matching;
use crate::{
AsContextMut, Engine, Export, Extern, Func, Global, Memory, Module, SharedMemory, StoreContext,
StoreContextMut, Table, TypedFunc,
AsContextMut, Engine, Export, Extern, Func, Global, Memory, Module, ModuleExport, SharedMemory,
StoreContext, StoreContextMut, Table, TypedFunc,
};
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::{
EntityIndex, EntityType, FuncIndex, GlobalIndex, MemoryIndex, PrimaryMap, TableIndex,
};
use wasmtime_runtime::{
Imports, InstanceAllocationRequest, StorePtr, VMContext, VMFuncRef, VMFunctionImport,
VMGlobalImport, VMMemoryImport, VMNativeCallFunction, VMOpaqueContext, VMTableImport,
Expand Down Expand Up @@ -395,8 +397,16 @@ impl Instance {
let InstanceData { exports, id, .. } = &store[self.0];
if exports.iter().any(|e| e.is_none()) {
let module = Arc::clone(store.instance(*id).module());
let data = &store[self.0];
let id = data.id;

for name in module.exports.keys() {
self._get_export(store, name);
let instance = store.instance(id);
if let Some((export_name_index, _, &entity)) =
instance.module().exports.get_full(name)
{
self._get_export(store, entity, export_name_index);
}
}
}

Expand Down Expand Up @@ -427,26 +437,60 @@ impl Instance {
/// instantiating a module faster, but also means this method requires a
/// mutable context.
pub fn get_export(&self, mut store: impl AsContextMut, name: &str) -> Option<Extern> {
self._get_export(store.as_context_mut().0, name)
let store = store.as_context_mut().0;
let data = &store[self.0];
let instance = store.instance(data.id);
let (export_name_index, _, &entity) = instance.module().exports.get_full(name)?;
self._get_export(store, entity, export_name_index)
}

/// Looks up an 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. [`ModuleExport`]s can be obtained by calling
/// [`Module::get_export_index`] on the [`Module`] that this instance was instantiated with.
///
/// 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;

// Verify the `ModuleExport` matches the module used in this instance.
if self._module(store).id() != export.module {
return None;
}

self._get_export(store, export.entity, export.export_name_index)
}

fn _get_export(&self, store: &mut StoreOpaque, name: &str) -> Option<Extern> {
fn _get_export(
&self,
store: &mut StoreOpaque,
entity: EntityIndex,
export_name_index: usize,
) -> Option<Extern> {
// Instantiated instances will lazily fill in exports, so we process
// all that lazy logic here.
let data = &store[self.0];

let instance = store.instance(data.id);
let (i, _, &index) = instance.module().exports.get_full(name)?;
if let Some(export) = &data.exports[i] {
if let Some(export) = &data.exports[export_name_index] {
return Some(export.clone());
}

let id = data.id;
let instance = store.instance_mut(id); // reborrow the &mut Instancehandle
let instance = store.instance_mut(data.id); // Reborrow the &mut InstanceHandle
let item =
unsafe { Extern::from_wasmtime_export(instance.get_export_by_index(index), store) };
unsafe { Extern::from_wasmtime_export(instance.get_export_by_index(entity), store) };
let data = &mut store[self.0];
data.exports[i] = Some(item.clone());
data.exports[export_name_index] = Some(item.clone());
Some(item)
}

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
34 changes: 32 additions & 2 deletions crates/wasmtime/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ 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 +897,25 @@ 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
/// [`ModuleExport`] can be stored and used to look up the export on the
/// [`Instance`](crate::Instance) later.
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: self.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 +1136,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(crate) module: CompiledModuleId,
/// A raw index into the wasm module.
pub(crate) entity: EntityIndex,
/// The index of the export name.
pub(crate) export_name_index: usize,
}

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

0 comments on commit 3bb7413

Please sign in to comment.