From 57991244c6b25960e1b8fa96990a35d20d34305e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=88=B1=E7=89=B9=E6=AF=8F=E7=BE=8A=E9=98=9F?= Date: Fri, 26 Jun 2026 16:20:45 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=B8=BA=20CodeForge=20=E7=BC=93?= =?UTF-8?q?=E5=AD=98=E5=91=BD=E4=B8=AD=E6=B7=BB=E5=8A=A0=20debug=20?= =?UTF-8?q?=E5=AD=97=E8=8A=82=E7=A0=81=E4=B8=80=E8=87=B4=E6=80=A7=E9=AA=8C?= =?UTF-8?q?=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/oxide_code_cache/src/lib.rs | 50 ++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/crates/oxide_code_cache/src/lib.rs b/crates/oxide_code_cache/src/lib.rs index fd70cf7..288094a 100644 --- a/crates/oxide_code_cache/src/lib.rs +++ b/crates/oxide_code_cache/src/lib.rs @@ -37,16 +37,22 @@ impl CodeForge { pub fn get_or_insert_with(&self, hash: u64, compile: F) -> Result, String> where - F: FnOnce() -> Result, + F: Fn() -> Result, { - // Two-phase: look up under the lock, then release the lock BEFORE - // running the compile closure so a slow compilation never blocks other - // cache users. Re-acquire the lock only to insert the freshly built - // module. { let mut cache = self.map.lock().unwrap(); if let Some(module) = cache.get(&hash) { - return Ok(Arc::clone(module)); + let module = Arc::clone(module); + drop(cache); + #[cfg(debug_assertions)] + { + let fresh = compile()?; + debug_assert_eq!( + module.bytecode, fresh.bytecode, + "structural hash collision: cached bytecode differs from recompiled for hash {hash}", + ); + } + return Ok(module); } } let module = Arc::new(compile()?); @@ -127,4 +133,36 @@ mod tests { } assert_eq!(forge.len(), 10); } + + #[test] + #[cfg_attr(debug_assertions, should_panic(expected = "structural hash collision"))] + fn cache_hit_debug_verifies_bytecode() { + let forge = forge(16); + let mut m1 = CompiledModule::new(); + m1.bytecode = vec![1, 2, 3]; + forge.insert(42, m1); + let _ = forge + .get_or_insert_with(42, || { + let mut m = CompiledModule::new(); + m.bytecode = vec![4, 5, 6]; + Ok(m) + }) + .unwrap(); + } + + #[test] + fn cache_hit_returns_cached_not_recompiled() { + let forge = forge(16); + let mut m = CompiledModule::new(); + m.bytecode = vec![1, 2, 3]; + let cached = forge.insert(99, m); + let result = forge + .get_or_insert_with(99, || { + let mut m = CompiledModule::new(); + m.bytecode = vec![1, 2, 3]; + Ok(m) + }) + .unwrap(); + assert!(Arc::ptr_eq(&cached, &result)); + } }