Skip to content

Commit 9c21fd1

Browse files
committed
Include dialect in module cache keys.
Prevent stale module artifacts from bypassing dialect-gated optimizer fixes by keying cached outputs on explicit dialect semantics.
1 parent 320cb6a commit 9c21fd1

2 files changed

Lines changed: 56 additions & 15 deletions

File tree

src/compiler/diskcache.rs

Lines changed: 54 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,25 @@ use crate::compiler::clvm::sha256tree_from_atom;
44
use crate::compiler::comptypes::{CompileErr, CompileForm, CompilerOpts};
55
use crate::compiler::sexp::decode_string;
66

7-
fn cache_key(cf: &CompileForm) -> String {
8-
let mut include_fingerprints = Vec::new();
7+
fn cache_key(opts: Rc<dyn CompilerOpts>, cf: &CompileForm) -> String {
8+
let dialect = opts.dialect();
9+
let mut key_material = b"module-cache-v2".to_vec();
10+
11+
if let Some(stepping) = dialect.stepping {
12+
key_material.push(1);
13+
key_material.extend_from_slice(&stepping.to_le_bytes());
14+
} else {
15+
key_material.push(0);
16+
}
17+
key_material.push(u8::from(dialect.strict));
18+
key_material.push(u8::from(dialect.int_fix));
19+
key_material.push(u8::from(dialect.extra_numeric_constants));
20+
key_material.push(u8::from(dialect.cse_dominance));
21+
922
for include in cf.include_forms.iter() {
10-
include_fingerprints.extend_from_slice(&include.fingerprint);
23+
key_material.extend_from_slice(&include.fingerprint);
1124
}
12-
hex::encode(sha256tree_from_atom(&include_fingerprints))
25+
hex::encode(sha256tree_from_atom(&key_material))
1326
}
1427

1528
/// Try to get an element from the cache, exposing errors.
@@ -30,7 +43,7 @@ pub fn try_element_from_cache(
3043
cf: &CompileForm,
3144
export_path: &str,
3245
) -> Option<String> {
33-
let key = cache_key(cf);
46+
let key = cache_key(opts.clone(), cf);
3447
let hex_file_name = format!(".chialisp/{key}/{export_path}");
3548
opts.read_new_file(cf.loc().file.to_string(), hex_file_name.clone())
3649
.ok()
@@ -43,7 +56,7 @@ pub fn set_cache_element_error(
4356
export_path: &str,
4457
export_hex: &str,
4558
) -> Result<(), CompileErr> {
46-
let key = cache_key(cf);
59+
let key = cache_key(opts.clone(), cf);
4760
let hex_file_name = format!(".chialisp/{key}/{export_path}");
4861
opts.write_new_file(&hex_file_name, export_hex.as_bytes())?;
4962
Ok(())
@@ -63,14 +76,16 @@ pub fn set_cache_element(
6376

6477
/// Exposes the cache-key segment used under `.chialisp/<key>/` (tests and tooling only).
6578
#[cfg(test)]
66-
pub fn module_cache_key_hex(cf: &CompileForm) -> String {
67-
cache_key(cf)
79+
pub fn module_cache_key_hex(opts: Rc<dyn CompilerOpts>, cf: &CompileForm) -> String {
80+
cache_key(opts, cf)
6881
}
6982

7083
#[cfg(test)]
7184
mod tests {
7285
use super::*;
86+
use crate::compiler::compiler::DefaultCompilerOpts;
7387
use crate::compiler::comptypes::{BodyForm, CompileForm, IncludeDesc, IncludeProcessType};
88+
use crate::compiler::dialect::AcceptedDialect;
7489
use crate::compiler::sexp::SExp;
7590
use crate::compiler::srcloc::Srcloc;
7691

@@ -84,14 +99,18 @@ mod tests {
8499
}
85100
}
86101

102+
fn default_opts(filename: &str) -> Rc<dyn CompilerOpts> {
103+
Rc::new(DefaultCompilerOpts::new(filename))
104+
}
105+
87106
#[test]
88107
fn cache_key_stable_for_empty_includes() {
89108
let loc = Srcloc::start(&"a.clsp".to_string());
90109
let cf = empty_compileform(loc);
91-
let k = cache_key(&cf);
110+
let k = cache_key(default_opts("a.clsp"), &cf);
92111
assert_eq!(
93112
k,
94-
"4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a"
113+
"bb1dfe276a7165264b23349a3d349c470f451aa964f89c172bfb5bc8fdf9d548"
95114
);
96115
}
97116

@@ -112,15 +131,36 @@ mod tests {
112131
fingerprint: fp,
113132
};
114133
cf.include_forms.push(desc(fp(&[1, 2, 3])));
115-
let k1 = cache_key(&cf);
134+
let k1 = cache_key(default_opts("b.clsp"), &cf);
116135
cf.include_forms.push(desc(fp(&[4, 5])));
117-
let k2 = cache_key(&cf);
136+
let k2 = cache_key(default_opts("b.clsp"), &cf);
118137
assert_ne!(k1, k2);
119138
cf.include_forms.truncate(1);
120-
let k1_again = cache_key(&cf);
139+
let k1_again = cache_key(default_opts("b.clsp"), &cf);
121140
assert_eq!(k1, k1_again);
122141
}
123142

143+
#[test]
144+
fn cache_key_changes_with_cse_dominance() {
145+
let loc = Srcloc::start(&"cse.clsp".to_string());
146+
let cf = empty_compileform(loc);
147+
let dialect_before = AcceptedDialect {
148+
stepping: Some(26),
149+
strict: true,
150+
int_fix: true,
151+
extra_numeric_constants: false,
152+
cse_dominance: false,
153+
};
154+
let dialect_after = AcceptedDialect {
155+
cse_dominance: true,
156+
..dialect_before.clone()
157+
};
158+
let before = default_opts("cse.clsp").set_dialect(dialect_before);
159+
let after = default_opts("cse.clsp").set_dialect(dialect_after);
160+
161+
assert_ne!(cache_key(before, &cf), cache_key(after, &cf));
162+
}
163+
124164
#[test]
125165
fn cache_key_main_fingerprint_style() {
126166
let loc = Srcloc::start(&"c.clsp".to_string());
@@ -135,7 +175,7 @@ mod tests {
135175
kind: Some(IncludeProcessType::Compiled),
136176
fingerprint: main_fp,
137177
});
138-
let k = cache_key(&cf);
178+
let k = cache_key(default_opts("c.clsp"), &cf);
139179
assert!(!k.is_empty());
140180
assert_ne!(
141181
k,

src/tests/compiler/module_cache.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ fn function_export(name: &[u8], as_name: Option<Vec<u8>>) -> Export {
6767
}
6868

6969
fn cache_dir_for(cf: &CompileForm) -> String {
70-
format!(".chialisp/{}/", module_cache_key_hex(cf))
70+
let opts: Rc<dyn CompilerOpts> = Rc::new(DefaultCompilerOpts::new(TEST_CLSP));
71+
format!(".chialisp/{}/", module_cache_key_hex(opts, cf))
7172
}
7273

7374
#[test]

0 commit comments

Comments
 (0)