diff --git a/Cargo.toml b/Cargo.toml index fe2e0dd..287df87 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ canary-script = { path = "crates/script" } lyon = "1" ouroboros = "^0.15" parking_lot = "0.12" +prehash = "0.3.3" slab = "0.4" wasmtime = "0.38" diff --git a/src/backend/wasmtime.rs b/src/backend/wasmtime.rs index 73b3133..db4f831 100644 --- a/src/backend/wasmtime.rs +++ b/src/backend/wasmtime.rs @@ -1,6 +1,8 @@ // Copyright (c) 2022 Marceline Cramer // SPDX-License-Identifier: LGPL-3.0-or-later +use std::collections::{hash_map::DefaultHasher, HashMap}; +use std::hash::Hasher; use std::ops::DerefMut; use super::{Arc, Backend, Instance, PanelId, ScriptAbi}; @@ -8,34 +10,57 @@ use crate::DrawCommand; use canary_script::{Color, CursorEventKind, Rect, Vec2}; use parking_lot::Mutex; +use prehash::{DefaultPrehasher, Prehashed, Prehasher}; type Caller<'a> = wasmtime::Caller<'a, Arc>; type Store = wasmtime::Store>; type Linker = wasmtime::Linker>; +type ModuleCache = Mutex, wasmtime::Module, DefaultPrehasher>>; pub struct WasmtimeBackend { engine: wasmtime::Engine, + module_cache: ModuleCache, } + impl WasmtimeBackend { pub fn new() -> anyhow::Result { let mut config = wasmtime::Config::new(); config.wasm_simd(true); config.wasm_bulk_memory(true); config.cranelift_opt_level(wasmtime::OptLevel::Speed); + config.cache_config_load_default()?; let engine = wasmtime::Engine::new(&config)?; - - Ok(Self { engine }) + let module_cache = Default::default(); + Ok(Self { + engine, + module_cache, + }) } } impl Backend for WasmtimeBackend { fn load_module(&self, abi: Arc, module: &[u8]) -> anyhow::Result> { - let module = wasmtime::Module::new(&self.engine, module)?; + let mut hasher = DefaultHasher::new(); + hasher.write(module); + let hashed = hasher.finish(); + + let prehasher = DefaultPrehasher::new(); + let prehashed = prehasher.prehash(hashed); + let mut cache = self.module_cache.lock(); + + let module = if let Some(module) = cache.get(&prehashed) { + module + } else { + let module = wasmtime::Module::new(&self.engine, module)?; + cache.insert(prehashed, module); + cache.get(&prehashed).unwrap() + }; + let mut store = wasmtime::Store::new(&self.engine, abi); let mut linker = Linker::new(&self.engine); WasmtimeInstance::link(&mut linker)?; - let instance = linker.instantiate(&mut store, &module)?; + let instance = linker.instantiate(&mut store, module)?; let bind_panel = instance.get_typed_func(&mut store, "bind_panel")?; let update = instance.get_typed_func(&mut store, "update")?; let draw = instance.get_typed_func(&mut store, "draw")?;