Skip to content

Per-module object cache (.perry-cache/objects/) returns stale .o when only HIR-pass code changes #544

Description

@proggeramlug

Summary

The per-module object cache at .perry-cache/objects/ is keyed by hash-of-source only. When HIR-level transform passes (e.g. crates/perry-transform/src/state_desugar.rs) change but the user's .ts file doesn't, the cache returns a .o produced by the old pass — even though the new pass would emit different LLVM IR for the same source.

This silently masks correctness regressions during local development of new HIR passes.

How to reproduce

  1. Add a new HIR transform pass that rewrites some shape into runtime FFI calls.
  2. Build & run a .ts file that exercises the pass — it works (cache miss, fresh codegen).
  3. Edit the pass (introduce a regression, or a new branch). Rebuild perry. Don't touch the .ts.
  4. Re-run on the same .ts — the cached .o is reused, the pass change is invisible at runtime.

What I hit

While shipping #535 Layer 1 (commit be071793), I spent ~45 minutes debugging a runtime TypeError on count.set(count.get() + 1) that was fully resolved at the HIR level (verified via --print-hir). The runtime kept calling js_state_init correctly because the cached .o from an earlier successful build had the right calls baked in — but the new debug code paths I added to the codegen never executed. Confirmed by strings ./perry | grep CODEGEN-DBG showing the eprintln strings present in the perry binary, but no output at runtime. rm -rf /tmp/.perry-cache && rebuild immediately exposed the actual bug (a mismatched pre-Pass-update cached object).

Suggested fix

Two options, in order of effort:

  • Quick: include perry's own version (workspace.package.version) or a build-id of libperry_codegen.a in the cache key. Any cargo build -p perry-codegen invalidates everything, which is what we want during pass development.
  • Better: include hashes of the perry-codegen / perry-transform / perry-hir crate .rlibs in the cache key. Less aggressive — only HIR/codegen/transform changes invalidate.

The status-quo (hash-of-source-only) is fine for cargo run against an unchanged perry binary, but pretty hostile to anyone working on a new HIR pass.

Discovery context

Found while implementing #535 Layer 1. Cost: ~45 min of debugging a phantom bug. Filing as a separate issue so the workaround (rm -rf <project>/.perry-cache) is documented and the cache-key invalidation gets a real fix.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions