fix: 缓存 debug 校验递归比子模块,赋值目标属性名按键粒度计入

This commit is contained in:
2026-10-10 07:36:31 +00:00
parent 7ef19347c8
commit ab16e9ce79
6 changed files with 95 additions and 26 deletions
+5 -3
View File
@@ -59,7 +59,7 @@ impl CodeForge {
}
/// 命中返回缓存模块,未命中则调用 `compile` 编译后缓存并返回。
/// debug 构建下命中时会重编译校验 bytecode,检测结构哈希碰撞。
/// debug 构建下命中时会重编译校验整模块(含子模块树),检测结构哈希碰撞。
pub fn get_or_insert_with<F>(&self, hash: u64, compile: F) -> Result<Arc<CompiledModule>, String>
where
F: Fn() -> Result<CompiledModule, String>,
@@ -73,9 +73,11 @@ impl CodeForge {
#[cfg(debug_assertions)]
{
let fresh = compile()?;
// 整结构比较(递归覆盖子模块树):只比顶层字节码会漏检嵌套
// 函数体内的同键异码。
debug_assert_eq!(
module.bytecode, fresh.bytecode,
"structural hash collision: cached bytecode differs from recompiled for hash {hash}",
module.as_ref(), &fresh,
"structural hash collision: cached module differs from recompiled for hash {hash}",
);
}
return Ok(module);
@@ -85,6 +85,67 @@ fn cache_hit_debug_verifies_bytecode() {
.unwrap();
}
/// 构造带指定字节码的子模块(嵌套函数体夹具)。
fn submodule(bytecode: Vec<u32>) -> CompiledModule {
let mut m = CompiledModule::new();
m.bytecode = Arc::from(bytecode);
m
}
#[test]
fn cache_hit_debug_verifies_nested_submodules_identical() {
let forge = forge(16);
let mut m1 = CompiledModule::new();
m1.bytecode = Arc::from(vec![1, 2, 3]);
m1.sub_modules = vec![Arc::new(submodule(vec![4, 5, 6]))];
let cached = forge.insert(7, m1);
let result = forge
.get_or_insert_with(7, || {
let mut m = CompiledModule::new();
m.bytecode = Arc::from(vec![1, 2, 3]);
m.sub_modules = vec![Arc::new(submodule(vec![4, 5, 6]))];
Ok(m)
})
.unwrap();
assert!(Arc::ptr_eq(&cached, &result));
}
#[test]
#[cfg_attr(debug_assertions, should_panic(expected = "structural hash collision"))]
fn cache_hit_debug_verifies_nested_submodule_differs() {
let forge = forge(16);
let mut m1 = CompiledModule::new();
m1.bytecode = Arc::from(vec![1, 2, 3]);
m1.sub_modules = vec![Arc::new(submodule(vec![4, 5, 6]))];
forge.insert(8, m1);
let _ = forge
.get_or_insert_with(8, || {
let mut m = CompiledModule::new();
m.bytecode = Arc::from(vec![1, 2, 3]);
m.sub_modules = vec![Arc::new(submodule(vec![7, 8, 9]))];
Ok(m)
})
.unwrap();
}
#[test]
#[cfg_attr(debug_assertions, should_panic(expected = "structural hash collision"))]
fn cache_hit_debug_verifies_top_level_differs_keeps_prefix() {
let forge = forge(16);
let mut m1 = CompiledModule::new();
m1.bytecode = Arc::from(vec![1, 2, 3]);
m1.sub_modules = vec![Arc::new(submodule(vec![4, 5, 6]))];
forge.insert(9, m1);
let _ = forge
.get_or_insert_with(9, || {
let mut m = CompiledModule::new();
m.bytecode = Arc::from(vec![9, 8, 7]);
m.sub_modules = vec![Arc::new(submodule(vec![4, 5, 6]))];
Ok(m)
})
.unwrap();
}
#[test]
fn cache_hit_returns_cached_not_recompiled() {
let forge = forge(16);