Skip to content

Commit

Permalink
Wasmtime: Add hash_key methods for Func and Table
Browse files Browse the repository at this point in the history
  • Loading branch information
fitzgen committed Sep 25, 2023
1 parent b56269f commit a22561f
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 0 deletions.
53 changes: 53 additions & 0 deletions crates/wasmtime/src/externals/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -346,4 +346,57 @@ impl Table {
vmctx: export.vmctx,
}
}

/// Get a stable hash key for this table.
///
/// Even if the same underlying table definition is added to the
/// `StoreData` multiple times and becomes multiple `wasmtime::Table`s,
/// this hash key will be consistent across all of these tables.
#[allow(dead_code)] // Not used yet, but added for consistency.
pub(crate) fn hash_key(&self, store: &StoreOpaque) -> impl std::hash::Hash + Eq {
store[self.0].definition as usize
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::{Instance, Module, Store};

#[test]
fn hash_key_is_stable_across_duplicate_store_data_entries() -> Result<()> {
let mut store = Store::<()>::default();
let module = Module::new(
store.engine(),
r#"
(module
(table (export "t") 1 1 externref)
)
"#,
)?;
let instance = Instance::new(&mut store, &module, &[])?;

// Each time we `get_table`, we call `Table::from_wasmtime` which adds
// a new entry to `StoreData`, so `t1` and `t2` will have different
// indices into `StoreData`.
let t1 = instance.get_table(&mut store, "t").unwrap();
let t2 = instance.get_table(&mut store, "t").unwrap();

// That said, they really point to the same table.
assert!(t1.get(&mut store, 0).unwrap().unwrap_externref().is_none());
assert!(t2.get(&mut store, 0).unwrap().unwrap_externref().is_none());
t1.set(&mut store, 0, Val::ExternRef(Some(ExternRef::new(42))))?;
assert!(t1.get(&mut store, 0).unwrap().unwrap_externref().is_some());
assert!(t2.get(&mut store, 0).unwrap().unwrap_externref().is_some());

// And therefore their hash keys are the same.
assert!(t1.hash_key(&store.as_context().0) == t2.hash_key(&store.as_context().0));

// But the hash keys are different from different tables.
let instance2 = Instance::new(&mut store, &module, &[])?;
let t3 = instance2.get_table(&mut store, "t").unwrap();
assert!(t1.hash_key(&store.as_context().0) != t3.hash_key(&store.as_context().0));

Ok(())
}
}
54 changes: 54 additions & 0 deletions crates/wasmtime/src/func.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1339,6 +1339,16 @@ impl Func {
// (unsafely), which should be safe since we just did the type check above.
unsafe { Ok(TypedFunc::new_unchecked(*self)) }
}

/// Get a stable hash key for this function.
///
/// Even if the same underlying function is added to the `StoreData`
/// multiple times and becomes multiple `wasmtime::Func`s, this hash key
/// will be consistent across all of these functions.
#[allow(dead_code)] // Not used yet, but added for consistency.
pub(crate) fn hash_key(&self, store: &mut StoreOpaque) -> impl std::hash::Hash + Eq {
self.caller_checked_func_ref(store).as_ptr() as usize
}
}

/// Prepares for entrance into WebAssembly.
Expand Down Expand Up @@ -2391,3 +2401,47 @@ mod rooted {
}
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::{Instance, Module, Store};

#[test]
fn hash_key_is_stable_across_duplicate_store_data_entries() -> Result<()> {
let mut store = Store::<()>::default();
let module = Module::new(
store.engine(),
r#"
(module
(func (export "f")
nop
)
)
"#,
)?;
let instance = Instance::new(&mut store, &module, &[])?;

// Each time we `get_func`, we call `Func::from_wasmtime` which adds a
// new entry to `StoreData`, so `f1` and `f2` will have different
// indices into `StoreData`.
let f1 = instance.get_func(&mut store, "f").unwrap();
let f2 = instance.get_func(&mut store, "f").unwrap();

// But their hash keys are the same.
assert!(
f1.hash_key(&mut store.as_context_mut().0)
== f2.hash_key(&mut store.as_context_mut().0)
);

// But the hash keys are different from different funcs.
let instance2 = Instance::new(&mut store, &module, &[])?;
let f3 = instance2.get_func(&mut store, "f").unwrap();
assert!(
f1.hash_key(&mut store.as_context_mut().0)
!= f3.hash_key(&mut store.as_context_mut().0)
);

Ok(())
}
}

0 comments on commit a22561f

Please sign in to comment.