diff --git a/CLAUDE.md b/CLAUDE.md index d419cf294a..da33091b9b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -211,6 +211,7 @@ to the same physical root still deduplicate by canonical path. ### LLVM Type Mismatches - Loop counter optimization produces i32 — always convert before passing to f64/i64 functions - Constructor parameters always f64 (NaN-boxed) at signature level +- A new `PERRY_*` environment variable read in codegen must be added to `BUILD_CACHE_ENV_VARS` in `crates/perry/src/commands/compile/build_cache.rs`, or to `BUILD_CACHE_ENV_EXCLUSIONS` with a reason it cannot change emitted code. Otherwise cached objects can silently serve a different setting. Run `cargo test -p perry codegen_env_vars_are_build_cache_inputs` to check registration. ### Async / Threading - Thread-local arenas: JSValues from tokio workers invalid on main thread diff --git a/changelog.d/9748-codegen-cache-guidance.md b/changelog.d/9748-codegen-cache-guidance.md new file mode 100644 index 0000000000..3650043e74 --- /dev/null +++ b/changelog.d/9748-codegen-cache-guidance.md @@ -0,0 +1,7 @@ +Make the codegen environment-variable registration failure name the registry +file, the input and exclusion declaration anchors, and the command to rerun. +Document the cache-registration requirement in the contributor guidance and +beside the OnceLock reader pattern so new switches are registered when added. +The existing missing-input and stale-exclusion checks remain enforced. +Also register `PERRY_CONCAT_SITE_CACHE`, another omission found by running the +gate: toggling its generated concatenation tables must invalidate the cache. diff --git a/crates/perry-codegen/src/codegen/helpers.rs b/crates/perry-codegen/src/codegen/helpers.rs index 504b743f79..f6a8e47d99 100644 --- a/crates/perry-codegen/src/codegen/helpers.rs +++ b/crates/perry-codegen/src/codegen/helpers.rs @@ -52,6 +52,12 @@ pub(crate) fn function_body_returns_generator_object(body: &[perry_hir::Stmt]) - /// Cached at first call so subsequent compile_* calls skip the /// env-var lookup. /// +/// When adding a `PERRY_*` reader using this pattern, register it in +/// `BUILD_CACHE_ENV_VARS` in `crates/perry/src/commands/compile/build_cache.rs`. +/// Only readers that cannot change emitted code belong in that file's +/// `BUILD_CACHE_ENV_EXCLUSIONS`, with a reason. The OnceLock caches the reader; +/// the registry keeps compiled objects from being reused across settings. +/// /// Why on by default now: the shadow stack precisely covers every /// pointer-typed local in compiled JS frames, complementing the /// conservative C-stack scan. With Phase A complete and the GC diff --git a/crates/perry/src/commands/compile/build_cache.rs b/crates/perry/src/commands/compile/build_cache.rs index 285918a5f9..ce3c8fa94f 100644 --- a/crates/perry/src/commands/compile/build_cache.rs +++ b/crates/perry/src/commands/compile/build_cache.rs @@ -141,6 +141,8 @@ const BUILD_CACHE_ENV_VARS: &[&str] = &[ "PERRY_CODEGEN_UNITS", "PERRY_CODEGEN_UNIT_BYTES", "PERRY_CODEGEN_UNIT_SIZE", + // Enables per-site concatenation tables and changes the emitted calls. + "PERRY_CONCAT_SITE_CACHE", "PERRY_ENTRY_SYMBOL", "PERRY_FULL_OUTLINE_IC", "PERRY_FULL_OUTLINE_IC_MIN_FUNCS", @@ -410,9 +412,13 @@ mod tests { assert!( missing.is_empty(), "these codegen env vars key neither the build cache nor an \ - exclusion (#6394's rule): {missing:?}. Add each to \ - BUILD_CACHE_ENV_VARS, or to BUILD_CACHE_ENV_EXCLUSIONS with a \ - reason it cannot change emitted code." + exclusion (#6394's rule): {missing:?}.\n\ + Edit crates/perry/src/commands/compile/build_cache.rs:\n\ + - Add switches that change emitted code at `const BUILD_CACHE_ENV_VARS`.\n\ + - Otherwise add them at `const BUILD_CACHE_ENV_EXCLUSIONS`, with a \ + reason they cannot change emitted code.\n\ + Unregistered switches can reuse objects compiled with a different setting.\n\ + Verify with: cargo test -p perry codegen_env_vars_are_build_cache_inputs" ); // A stale exclusion is also a defect: it claims a var exists and is