Add Engine::precompile_compatibility_hash (#5826)

This method returns a Hash, the output of which can be used to index
precompiled binaries from one Engine instance that can be deserialized
by another Engine instance.
This commit is contained in:
Lann
2023-04-18 17:21:16 -04:00
committed by GitHub
parent a486aa37ad
commit 51ed20ab4d
2 changed files with 36 additions and 3 deletions

View File

@@ -239,6 +239,18 @@ impl Engine {
Ok(mmap.to_vec())
}
/// Returns a [`std::hash::Hash`] that can be used to check precompiled WebAssembly compatibility.
///
/// The outputs of [`Engine::precompile_module`] and [`Engine::precompile_component`]
/// are compatible with a different [`Engine`] instance only if the two engines use
/// compatible [`Config`]s. If this Hash matches between two [`Engine`]s then binaries
/// from one are guaranteed to deserialize in the other.
#[cfg(compiler)]
#[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
pub fn precompile_compatibility_hash(&self) -> impl std::hash::Hash + '_ {
crate::module::HashedEngineCompileEnv(self)
}
pub(crate) fn run_maybe_parallel<
A: Send,
B: Send,
@@ -628,6 +640,11 @@ impl Default for Engine {
#[cfg(test)]
mod tests {
use std::{
collections::hash_map::DefaultHasher,
hash::{Hash, Hasher},
};
use crate::{Config, Engine, Module, OptLevel};
use anyhow::Result;
@@ -693,4 +710,20 @@ mod tests {
Ok(())
}
#[test]
fn precompile_compatibility_key_accounts_for_opt_level() {
fn hash_for_config(cfg: &Config) -> u64 {
let engine = Engine::new(cfg).expect("Config should be valid");
let mut hasher = DefaultHasher::new();
engine.precompile_compatibility_hash().hash(&mut hasher);
hasher.finish()
}
let mut cfg = Config::new();
cfg.cranelift_opt_level(OptLevel::None);
let opt_none_hash = hash_for_config(&cfg);
cfg.cranelift_opt_level(OptLevel::Speed);
let opt_speed_hash = hash_for_config(&cfg);
assert_ne!(opt_none_hash, opt_speed_hash)
}
}

View File

@@ -1144,10 +1144,10 @@ fn _assert_send_sync() {
/// The hash computed for this structure is used to key the global wasmtime
/// cache and dictates whether artifacts are reused. Consequently the contents
/// of this hash dictate when artifacts are or aren't re-used.
#[cfg(all(feature = "cache", compiler))]
struct HashedEngineCompileEnv<'a>(&'a Engine);
#[cfg(compiler)]
pub(crate) struct HashedEngineCompileEnv<'a>(pub &'a Engine);
#[cfg(all(feature = "cache", compiler))]
#[cfg(compiler)]
impl std::hash::Hash for HashedEngineCompileEnv<'_> {
fn hash<H: std::hash::Hasher>(&self, hasher: &mut H) {
// Hash the compiler's state based on its target and configuration.