diff --git a/Cargo.lock b/Cargo.lock index 00c3a078..9e9ee8b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" @@ -1052,6 +1052,7 @@ dependencies = [ "holochain_wasmer_common", "parking_lot", "serde", + "tempfile", "thiserror 2.0.8", "tracing", "wasmer", diff --git a/crates/common/src/result.rs b/crates/common/src/result.rs index 91c381a0..cc5928fe 100644 --- a/crates/common/src/result.rs +++ b/crates/common/src/result.rs @@ -35,8 +35,6 @@ pub enum WasmErrorInner { ModuleBuild(String), /// The host failed to call a function in the guest. CallError(String), - /// Host attempted to interact with the module cache before it was initialized. - UninitializedSerializedModuleCache, } impl WasmErrorInner { @@ -55,8 +53,6 @@ impl WasmErrorInner { | Self::ModuleBuild(_) // This is ambiguous so best to treat as potentially corrupt. | Self::CallError(_) - // We have no cache so cannot cache. - | Self::UninitializedSerializedModuleCache => true, // (De)serialization simply means some input/output data was // unrecognisable somehow, it doesn't corrupt the guest memory. diff --git a/crates/host/Cargo.toml b/crates/host/Cargo.toml index c3dd311f..ccecd681 100644 --- a/crates/host/Cargo.toml +++ b/crates/host/Cargo.toml @@ -6,6 +6,11 @@ version = "0.0.97" authors = ["thedavidmeister", "thedavidmeister@gmail.com"] edition = "2021" +[lib] +name = "holochain_wasmer_host" +crate-type = ["cdylib", "rlib"] +path = "src/lib.rs" + [dependencies] wasmer = { version = "5.0.2", default-features = false } wasmer-middlewares = { version = "5.0.2", optional = true } @@ -20,10 +25,8 @@ bytes = "1" hex = "0.4" thiserror = "2" -[lib] -name = "holochain_wasmer_host" -crate-type = ["cdylib", "rlib"] -path = "src/lib.rs" +[dev-dependencies] +tempfile = "3.14.0" [features] default = ["error_as_host", "wasmer_sys_dev"] diff --git a/crates/host/src/module.rs b/crates/host/src/module.rs index 871f7b0c..c75b7b97 100644 --- a/crates/host/src/module.rs +++ b/crates/host/src/module.rs @@ -22,11 +22,13 @@ use std::fs::OpenOptions; use std::io::Write; use std::path::PathBuf; use std::sync::Arc; -use wasmer::Engine; use wasmer::Instance; use wasmer::Module; use wasmer::Store; +mod builder; +pub use builder::ModuleBuilder; + #[cfg(feature = "wasmer_sys")] mod wasmer_sys; #[cfg(feature = "wasmer_sys")] @@ -43,8 +45,6 @@ pub type CacheKey = [u8; 32]; /// Plru uses a usize to track "recently used" so we need a map between 32 byte cache /// keys and the bits used to evict things from the cache. type PlruKeyMap = BiMap; -/// Modules serialize to a vec of bytes as per wasmer. -type SerializedModule = Bytes; #[derive(Clone, Debug)] pub struct ModuleWithStore { @@ -118,26 +118,19 @@ trait PlruCache { } } -/// Cache for serialized modules. These are fully compiled wasm modules that are -/// then serialized by wasmer and can be cached. A serialized wasm module must still -/// be deserialized before it can be used to build instances. The deserialization -/// process is far faster than compiling and much slower than instance building. -#[derive(Debug)] -pub struct SerializedModuleCache { - pub plru: MicroCache, - pub key_map: PlruKeyMap, - pub cache: BTreeMap>, - // a function to create a new compiler engine for every module - pub make_engine: fn() -> Engine, - // the runtime engine has to live as long as the module; - // keeping it in the cache and using it for all modules - // make sure of that - pub runtime_engine: Engine, - pub maybe_fs_dir: Option, +/// Caches deserialized wasm modules. +/// +/// Deserialization of cached modules from the cache to create callable instances is slow. +/// Therefore modules are cached in memory after deserialization. +#[derive(Default, Debug)] +struct InMemoryModuleCache { + plru: MicroCache, + key_map: PlruKeyMap, + cache: BTreeMap>, } -impl PlruCache for SerializedModuleCache { - type Item = SerializedModule; +impl PlruCache for InMemoryModuleCache { + type Item = Module; fn plru_mut(&mut self) -> &mut MicroCache { &mut self.plru @@ -160,100 +153,59 @@ impl PlruCache for SerializedModuleCache { } } -impl SerializedModuleCache { - /// Build a default `SerializedModuleCache` with a fn to create an `Engine` - /// that will be used to compile modules from wasms as needed. - pub fn default_with_engine(make_engine: fn() -> Engine, maybe_fs_dir: Option) -> Self { - Self { - make_engine, - // the engine to execute function calls on instances does not - // require a compiler - runtime_engine: make_runtime_engine(), - plru: MicroCache::default(), - key_map: PlruKeyMap::default(), - cache: BTreeMap::default(), - maybe_fs_dir, +#[derive(Debug)] +pub struct ModuleCache { + // The in-memory cache of deserialized modules + cache: Arc>, + + // Filesystem path where serialized modules are cached. + // + // A serialized wasm module must still be deserialized before it can be used to build instances. + // The deserialization process is far faster than compiling and much slower than instance building. + filesystem_path: Option, + + // Handles building wasm modules + // + // It includes the runtime engine that must live as long as the module, + // so we keep it in the cache and use for all modules. + builder: ModuleBuilder, +} + +impl ModuleCache { + pub fn new(builder: ModuleBuilder, filesystem_path: Option) -> Self { + let cache = Arc::new(RwLock::new(InMemoryModuleCache::default())); + ModuleCache { + cache, + filesystem_path, + builder, } } - fn module_path(&self, key: CacheKey) -> Option { - self.maybe_fs_dir - .as_ref() - .map(|dir_path| dir_path.clone().join(hex::encode(key))) - } + /// Get a module from the cache, or add it to both caches if not found + pub fn get(&self, key: CacheKey, wasm: &[u8]) -> Result, wasmer::RuntimeError> { + // Check in-memory cache for module + if let Some(module) = self.get_from_cache(key) { + return Ok(module); + } - /// Given a wasm, compiles with compiler engine, serializes the result, adds it to - /// the cache and returns that. - fn get_with_build_cache( - &mut self, - key: CacheKey, - wasm: &[u8], - ) -> Result, wasmer::RuntimeError> { - let maybe_module_path = self.module_path(key); - let module_load = maybe_module_path.as_ref().map(|module_path| { - // We do this the long way to get `Bytes` instead of `Vec` so - // that the clone when we both deserialize and cache is cheap. - let mut file = File::open(module_path).map_err(|e| { - wasm_error!(WasmErrorInner::ModuleBuild(format!( - "{} Path: {}", - e, - module_path.display() - ))) - })?; - let mut bytes_mut = BytesMut::new().writer(); - - std::io::copy(&mut file, &mut bytes_mut).map_err(|e| { - wasm_error!(WasmErrorInner::ModuleBuild(format!( - "{} Path: {}", - e, - module_path.display() - ))) - })?; - Ok::(bytes_mut.into_inner().freeze()) - }); - let (module, serialized_module) = match module_load { - Some(Ok(serialized_module)) => { - let deserialized_module = - unsafe { Module::deserialize(&self.runtime_engine, serialized_module.clone()) } - .map_err(|e| wasm_error!(WasmErrorInner::ModuleBuild(e.to_string())))?; - (deserialized_module, serialized_module) + // Check the filesystem for module + match self.get_from_filesystem(key) { + // Filesystem cache hit, deserialize and save to cache + Ok(Some(serialized_module)) => { + let module = self.builder.from_serialized_module(serialized_module)?; + self.add_to_cache(key, module.clone()); + + Ok(module) } - // no serialized module found on the file system, so serialize the - // wasm binary and write it to the file system - _fs_miss => { + + // Filesystem cache miss, build wasm and save to both caches + _ => { // Each module needs to be compiled with a new engine because // of middleware like metering. Middleware is compiled into the // module once and available in all instances created from it. - let compiler_engine = (self.make_engine)(); - let module = Module::from_binary(&compiler_engine, wasm) - .map_err(|e| wasm_error!(WasmErrorInner::ModuleBuild(e.to_string())))?; - let serialized_module = module - .serialize() - .map_err(|e| wasm_error!(WasmErrorInner::ModuleBuild(e.to_string())))?; + let module = self.builder.from_binary(wasm)?; - if let Some(module_path) = maybe_module_path { - match OpenOptions::new() - .write(true) - // Using create_new here so that cache stampedes don't - // cause corruption. Each file can only be written once. - .create_new(true) - .open(&module_path) - { - Ok(mut file) => { - if let Err(e) = file.write_all(&serialized_module) { - tracing::error!("{} Path: {}", e, module_path.display()); - } - } - Err(e) => { - // This is just a warning because it is expected that - // multiple concurrent calls to build the same wasm - // will sometimes happen. - tracing::warn!("{} Path: {}", e, module_path.display()); - } - } - } - - // deserialize the module to be returned for instantiation + // Round trip the wasmer Module through serialization. // // A new middleware per module is required, hence a new engine // per module is needed too. Serialization allows for uncoupling @@ -266,109 +218,101 @@ impl SerializedModuleCache { // instantiated with fresh stores free from state. Instance // creation is highly performant which makes caching of instances // and stores unnecessary. - let module = unsafe { - Module::deserialize(&self.runtime_engine, serialized_module.clone()) - .map_err(|e| wasm_error!(WasmErrorInner::ModuleBuild(e.to_string())))? - }; + // + // See https://github.com/wasmerio/wasmer/discussions/3829#discussioncomment-5790763 + let serialized_module = module + .serialize() + .map_err(|e| wasm_error!(WasmErrorInner::ModuleBuild(e.to_string())))?; + let module = self + .builder + .from_serialized_module(serialized_module.clone())?; - (module, serialized_module) - } - }; - self.put_item(key, Arc::new(serialized_module.clone())); + // Save serialized module to filesystem cache + self.add_to_filesystem(key, serialized_module)?; - Ok(Arc::new(module)) - } + // Save module to in-memory cache + self.add_to_cache(key, module.clone()); - /// Given a wasm, attempts to get the serialized module for it from the cache. - /// If the cache misses, a new serialized module will be built from the wasm. - pub fn get(&mut self, key: CacheKey, wasm: &[u8]) -> Result, wasmer::RuntimeError> { - match self.cache.get(&key) { - Some(serialized_module) => { - let module = unsafe { - Module::deserialize(&self.runtime_engine, (**serialized_module).clone()) - } - .map_err(|e| wasm_error!(WasmErrorInner::ModuleBuild(e.to_string())))?; - self.touch(&key); - Ok(Arc::new(module)) + Ok(module) } - None => self.get_with_build_cache(key, wasm), } } -} -/// Caches deserialized wasm modules. Deserialization of cached modules from -/// the cache to create callable instances is slow. Therefore modules are -/// cached in memory after deserialization. -#[derive(Default, Debug)] -struct DeserializedModuleCache { - plru: MicroCache, - key_map: PlruKeyMap, - cache: BTreeMap>, -} - -impl PlruCache for DeserializedModuleCache { - type Item = Module; - - fn plru_mut(&mut self) -> &mut MicroCache { - &mut self.plru + /// Get serialized module from filesystem + fn get_from_filesystem(&self, key: CacheKey) -> Result, wasmer::RuntimeError> { + self.filesystem_module_path(key) + .as_ref() + .map(|module_path| { + // Read file into `Bytes` instead of `Vec` so that the clone is cheap + let mut file = File::open(module_path).map_err(|e| { + wasm_error!(WasmErrorInner::ModuleBuild(format!( + "{} Path: {}", + e, + module_path.display() + ))) + })?; + + let mut bytes_mut = BytesMut::new().writer(); + std::io::copy(&mut file, &mut bytes_mut).map_err(|e| { + wasm_error!(WasmErrorInner::ModuleBuild(format!( + "{} Path: {}", + e, + module_path.display() + ))) + })?; + + Ok::(bytes_mut.into_inner().freeze()) + }) + .transpose() } - fn key_map_mut(&mut self) -> &mut PlruKeyMap { - &mut self.key_map - } + /// Add serialized module to filesystem cache + fn add_to_filesystem( + &self, + key: CacheKey, + serialized_module: Bytes, + ) -> Result<(), wasmer::RuntimeError> { + if let Some(fs_path) = self.filesystem_module_path(key) { + match OpenOptions::new() + .write(true) + // Using create_new here so that cache stampedes don't + // cause corruption. Each file can only be written once. + .create_new(true) + .open(&fs_path) + { + Ok(mut file) => { + if let Err(e) = file.write_all(&serialized_module) { + tracing::error!("{} Path: {}", e, fs_path.display()); + } + } + Err(e) => { + // This is just a warning because it is expected that + // multiple concurrent calls to build the same wasm + // will sometimes happen. + tracing::warn!("{} Path: {}", e, fs_path.display()); + } + } + } - fn key_map(&self) -> &PlruKeyMap { - &self.key_map + Ok(()) } - fn cache(&self) -> &BTreeMap> { - &self.cache + /// Check cache for module + fn get_from_cache(&self, key: CacheKey) -> Option> { + let mut cache = self.cache.write(); + cache.get_item(&key) } - fn cache_mut(&mut self) -> &mut BTreeMap> { - &mut self.cache + /// Add module to cache + fn add_to_cache(&self, key: CacheKey, module: Arc) { + let mut cache = self.cache.write(); + cache.put_item(key, module.clone()); } -} - -#[derive(Debug)] -pub struct ModuleCache { - serialized_module_cache: Arc>, - deserialized_module_cache: Arc>, -} -impl ModuleCache { - pub fn new(maybe_fs_dir: Option) -> Self { - let serialized_module_cache = Arc::new(RwLock::new( - SerializedModuleCache::default_with_engine(make_engine, maybe_fs_dir), - )); - let deserialized_module_cache = Arc::new(RwLock::new(DeserializedModuleCache::default())); - ModuleCache { - serialized_module_cache, - deserialized_module_cache, - } - } - - pub fn get(&self, key: CacheKey, wasm: &[u8]) -> Result, wasmer::RuntimeError> { - // check deserialized module cache first for module - { - let mut deserialized_cache = self.deserialized_module_cache.write(); - if let Some(module) = deserialized_cache.get_item(&key) { - return Ok(module); - } - } - // get module from serialized cache otherwise - // if cache does not contain module, it will be built from wasm bytes - // and then cached in serialized cache - let module; - { - let mut serialized_cache = self.serialized_module_cache.write(); - module = serialized_cache.get(key, wasm)?; - } - // cache in deserialized module cache too - { - let mut deserialized_cache = self.deserialized_module_cache.write(); - deserialized_cache.put_item(key, module.clone()); - } - Ok(module) + /// Get filesystem cache path for a given key + fn filesystem_module_path(&self, key: CacheKey) -> Option { + self.filesystem_path + .as_ref() + .map(|dir_path| dir_path.clone().join(hex::encode(key))) } } diff --git a/crates/host/src/module/builder.rs b/crates/host/src/module/builder.rs new file mode 100644 index 00000000..2969f34b --- /dev/null +++ b/crates/host/src/module/builder.rs @@ -0,0 +1,50 @@ +use crate::prelude::*; +use bytes::Bytes; +use std::sync::Arc; +use wasmer::{Engine, Module}; + +#[cfg(feature = "wasmer_sys")] +pub use super::wasmer_sys::*; + +#[cfg(feature = "wasmer_wamr")] +pub use super::wasmer_wamr::*; + +/// Responsible for storing the wasmer Engine used to build wasmer Modules. +#[derive(Debug)] +pub struct ModuleBuilder { + // A function to create a new Engine for every module + make_engine: fn() -> Engine, + + // The runtime engine is used only to execute function calls on instances, + // so it does not require a compiler. + runtime_engine: Engine, +} + +impl ModuleBuilder { + pub fn new(make_engine: fn() -> Engine) -> Self { + Self { + make_engine, + runtime_engine: make_runtime_engine(), + } + } + + pub fn from_binary(&self, wasm: &[u8]) -> Result, wasmer::RuntimeError> { + let compiler_engine = (self.make_engine)(); + let module = Arc::new( + Module::from_binary(&compiler_engine, wasm) + .map_err(|e| wasm_error!(WasmErrorInner::ModuleBuild(e.to_string())))?, + ); + Ok(module) + } + + pub fn from_serialized_module( + &self, + serialized_module: Bytes, + ) -> Result, wasmer::RuntimeError> { + let module = Arc::new(unsafe { + Module::deserialize(&self.runtime_engine, serialized_module.clone()) + .map_err(|e| wasm_error!(WasmErrorInner::ModuleBuild(e.to_string())))? + }); + Ok(module) + } +} diff --git a/crates/host/src/module/wasmer_sys.rs b/crates/host/src/module/wasmer_sys.rs index 69e12bca..98d86d94 100644 --- a/crates/host/src/module/wasmer_sys.rs +++ b/crates/host/src/module/wasmer_sys.rs @@ -77,10 +77,14 @@ pub fn get_ios_module_from_file(path: &Path) -> Result #[cfg(test)] mod tests { - use crate::module::{CacheKey, ModuleCache, PlruCache}; + use super::make_engine; + use crate::module::{builder::ModuleBuilder, CacheKey, ModuleCache, PlruCache}; + use std::io::Write; + use tempfile::tempdir; + use wasmer::Module; #[test] - fn cache_test() { + fn cache_save_to_memory_and_fs() { // simple example wasm taken from wasmer docs // https://docs.rs/wasmer/latest/wasmer/struct.Module.html#example let wasm: Vec = vec![ @@ -91,31 +95,110 @@ mod tests { 0x61, 0x64, 0x64, 0x5f, 0x6f, 0x6e, 0x65, 0x02, 0x07, 0x01, 0x00, 0x01, 0x00, 0x02, 0x70, 0x30, ]; - let module_cache = ModuleCache::new(None); - assert!(module_cache.serialized_module_cache.read().cache.is_empty()); + let tmp_fs_cache_dir = tempdir().unwrap().into_path(); + let module_builder = ModuleBuilder::new(make_engine); + let module_cache = ModuleCache::new(module_builder, Some(tmp_fs_cache_dir.clone())); assert!(module_cache - .deserialized_module_cache - .read() - .cache - .is_empty()); + .filesystem_path + .clone() + .unwrap() + .read_dir() + .unwrap() + .next() + .is_none()); + assert!(module_cache.cache.read().cache.is_empty()); let key: CacheKey = [0u8; 32]; let module = module_cache.get(key, &wasm).unwrap(); - // make sure module has been stored in serialized cache under key + // make sure module has been stored in the in-memory cache under `key` { - let serialized_cached_module = - module_cache.serialized_module_cache.write().get_item(&key); - assert!(serialized_cached_module.is_some()); + let deserialized_cached_module = module_cache.cache.write().get_item(&key).unwrap(); + assert_eq!(*deserialized_cached_module, *module); + } + + // make sure module has been stored in serialized filesystem cache + { + let serialized_module_path = + module_cache.filesystem_path.unwrap().join(hex::encode(key)); + assert!(std::fs::metadata(serialized_module_path).is_ok()); } + + std::fs::remove_dir_all(tmp_fs_cache_dir).unwrap(); + } + + #[test] + fn cache_save_to_memory_only() { + // simple example wasm taken from wasmer docs + // https://docs.rs/wasmer/latest/wasmer/struct.Module.html#example + let wasm: Vec = vec![ + 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x01, 0x60, 0x01, 0x7f, + 0x01, 0x7f, 0x03, 0x02, 0x01, 0x00, 0x07, 0x0b, 0x01, 0x07, 0x61, 0x64, 0x64, 0x5f, + 0x6f, 0x6e, 0x65, 0x00, 0x00, 0x0a, 0x09, 0x01, 0x07, 0x00, 0x20, 0x00, 0x41, 0x01, + 0x6a, 0x0b, 0x00, 0x1a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x01, 0x0a, 0x01, 0x00, 0x07, + 0x61, 0x64, 0x64, 0x5f, 0x6f, 0x6e, 0x65, 0x02, 0x07, 0x01, 0x00, 0x01, 0x00, 0x02, + 0x70, 0x30, + ]; + let module_builder = ModuleBuilder::new(make_engine); + let module_cache = ModuleCache::new(module_builder, None); + assert!(module_cache.cache.read().cache.is_empty()); + + let key: CacheKey = [0u8; 32]; + let module = module_cache.get(key, &wasm).unwrap(); + // make sure module has been stored in deserialized cache under key { - let deserialized_cached_module = module_cache - .deserialized_module_cache - .write() - .get_item(&key) - .unwrap(); + let deserialized_cached_module = module_cache.cache.write().get_item(&key).unwrap(); assert_eq!(*deserialized_cached_module, *module); } } + + #[test] + fn cache_get_from_fs() { + // simple example wasm taken from wasmer docs + // https://docs.rs/wasmer/latest/wasmer/struct.Module.html#example + let wasm: Vec = vec![ + 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x01, 0x60, 0x01, 0x7f, + 0x01, 0x7f, 0x03, 0x02, 0x01, 0x00, 0x07, 0x0b, 0x01, 0x07, 0x61, 0x64, 0x64, 0x5f, + 0x6f, 0x6e, 0x65, 0x00, 0x00, 0x0a, 0x09, 0x01, 0x07, 0x00, 0x20, 0x00, 0x41, 0x01, + 0x6a, 0x0b, 0x00, 0x1a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x01, 0x0a, 0x01, 0x00, 0x07, + 0x61, 0x64, 0x64, 0x5f, 0x6f, 0x6e, 0x65, 0x02, 0x07, 0x01, 0x00, 0x01, 0x00, 0x02, + 0x70, 0x30, + ]; + let tmp_fs_cache_dir = tempdir().unwrap().into_path(); + let module_builder = ModuleBuilder::new(make_engine); + let module_cache = ModuleCache::new(module_builder, Some(tmp_fs_cache_dir.clone())); + let key: CacheKey = [0u8; 32]; + + // Build module, serialize, save directly to filesystem + let compiler_engine = make_engine(); + let module = + std::sync::Arc::new(Module::from_binary(&compiler_engine, wasm.as_slice()).unwrap()); + let serialized_module = module.serialize().unwrap(); + let serialized_module_path = tmp_fs_cache_dir.clone().join(hex::encode(key)); + let mut file = std::fs::OpenOptions::new() + .write(true) + .create_new(true) + .open(&serialized_module_path) + .unwrap(); + file.write_all(&serialized_module).unwrap(); + + // make sure module can be retrieved from cache + let module_retreived = module_cache.get(key, &wasm).unwrap(); + assert_eq!( + *module_retreived.serialize().unwrap(), + *module.serialize().unwrap() + ); + + // make sure module is stored in deserialized cache + { + let deserialized_cached_module = module_cache.cache.write().get_item(&key).unwrap(); + assert_eq!( + *deserialized_cached_module.serialize().unwrap(), + *module.serialize().unwrap() + ); + } + + std::fs::remove_dir_all(tmp_fs_cache_dir).unwrap(); + } } diff --git a/test-crates/tests/src/wasms.rs b/test-crates/tests/src/wasms.rs index 4fbecd4a..cb6d95ac 100644 --- a/test-crates/tests/src/wasms.rs +++ b/test-crates/tests/src/wasms.rs @@ -2,7 +2,8 @@ use crate::import::imports; #[cfg(feature = "wasmer_wamr")] use holochain_wasmer_host::module::build_module; use holochain_wasmer_host::module::InstanceWithStore; -use holochain_wasmer_host::module::SerializedModuleCache; +use holochain_wasmer_host::module::ModuleBuilder; +use holochain_wasmer_host::module::ModuleCache; use holochain_wasmer_host::prelude::*; use once_cell::sync::OnceCell; use parking_lot::RwLock; @@ -29,9 +30,8 @@ pub enum TestWasm { Memory, } -pub static SERIALIZED_MODULE_CACHE: OnceCell> = OnceCell::new(); -pub static SERIALIZED_MODULE_CACHE_UNMETERED: OnceCell> = - OnceCell::new(); +pub static MODULE_CACHE: OnceCell> = OnceCell::new(); +pub static MODULE_CACHE_UNMETERED: OnceCell> = OnceCell::new(); impl TestWasm { pub fn bytes(&self) -> &[u8] { @@ -77,11 +77,11 @@ impl TestWasm { } } - pub fn module_cache(&self, metered: bool) -> &OnceCell> { + pub fn module_cache(&self, metered: bool) -> &OnceCell> { if metered { - &SERIALIZED_MODULE_CACHE + &MODULE_CACHE } else { - &SERIALIZED_MODULE_CACHE_UNMETERED + &MODULE_CACHE_UNMETERED } } @@ -116,16 +116,16 @@ impl TestWasm { // This will error if the cache is already initialized // which could happen if two tests are running in parallel. // It doesn't matter which one wins, so we just ignore the error. - let _did_init_ok = self.module_cache(metered).set(parking_lot::RwLock::new( - SerializedModuleCache::default_with_engine( - if metered { - cranelift_fn - } else { - compiler_fn_unmetered - }, - None, - ), - )); + let _did_init_ok = + self.module_cache(metered) + .set(parking_lot::RwLock::new(ModuleCache::new( + ModuleBuilder::new(if metered { + cranelift_fn + } else { + compiler_fn_unmetered + }), + None, + ))); // Just recurse now that the cache is initialized. self.module(metered)