Skip to content

fix(codegen): retry oversized RS4GC functions with shadow roots, and CI hardening - #8696

Merged
proggeramlug merged 1 commit into
mainfrom
merge/b12
Aug 24, 2026
Merged

fix(codegen): retry oversized RS4GC functions with shadow roots, and CI hardening#8696
proggeramlug merged 1 commit into
mainfrom
merge/b12

Conversation

@proggeramlug

@proggeramlug proggeramlug commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Lands #8687, #8686 and #8684.

#8687 — RS4GC budget spill-retry (closes #8679)

Replaces the post-RS4GC instruction-budget hard refusal with a typed spill-retry: an already-lowered LlFunction switches from native statepoint roots to a complete precise shadow frame, and the unit is rebuilt at the originally requested optimization level. This is the durable handling for the estimator misses that #8678 could only make more accurate.

Retry termination is proven, not argued — the thing I most wanted to check before landing a retry loop:

pub fn request_shadow_frame_spill(&mut self) -> bool {
    if self.force_shadow_frame { return false; }   // latch
    self.force_shadow_frame = true;
    ...
    true
}

apply_budget_spill_retry inserts into changed only when that returned true, then hard-errors on any violation not in changed ("or were already retried"). A function that has already been spilled therefore returns false → lands in missing → fails loudly. It cannot be retried twice.

#8686 — share the gap suite's fast-mode build across shards

Builds the archives once in a dedicated gap-suite-build job. The skipped-vs-failed distinction — which has bitten this repo before, since a skipped job satisfies a dependency — is handled explicitly and correctly:

if: >-
  always() &&
  fromJSON(needs.plan.outputs.plan).jobs.gap_suite &&
  (needs.gap-suite-build.result == 'success' || needs.gap-suite-build.result == 'skipped')

always() keeps a SKIPPED build (full mode, where the job never runs) from cascading into skipped shards, while the guard still requires success or skipped — so a genuine build failure stops the shards rather than letting them run vacuously. The download step is itself mode-gated, the shard verifies the downloaded binary is runnable, and it exports PERRY_BIN / PERRY_RUNTIME_DIR (without which the wrapper exits 0 having run nothing).

#8684 — inline dtolnay/rust-toolchain, SHA-pin third-party actions

Audited for silently-dropped coverage, since that's the real risk in a CI-mechanics PR: no job removed, one job added (gap-suite-build), and the single removed step is the fast-mode archive build — which moved into that job rather than disappearing.

Validation (on the merged result)

  • All 30 lint-job checkers pass
  • perry-codegen --lib: 1202 passed, 0 failed
  • perry-codegen --features llvm-inprocess --lib: 1202 passed, 0 failed (the feature fix(codegen): retry oversized RS4GC functions with shadow roots (#8679) #8687 actually changes)
  • perry-runtime --lib (RUST_TEST_THREADS=1): 2655 passed, 0 failed
  • perry --bin perry: 1031 passed, 0 failed
  • Squashed tree verified identical to the validated tree

No version bump.

Summary by CodeRabbit

  • Bug Fixes

    • Large native functions that exceed optimization limits can now be automatically retried with a safer memory-management strategy instead of failing compilation.
    • Improved handling of root spilling during code generation, including more precise cleanup and recovery.
    • Added regression coverage for retry behavior and native compilation scenarios.
  • Chores

    • Strengthened automated build and release workflows by pinning action versions and standardizing Rust toolchain setup.

…CI hardening

Lands #8687, #8686 and #8684.

#8687 (closes #8679) replaces the post-RS4GC instruction-budget hard
refusal with a typed spill-retry: an already-lowered LlFunction switches
from native statepoint roots to a complete precise shadow frame and the
unit is rebuilt at the originally requested optimization level. This is
the durable handling for the estimator misses #8678 could only make more
accurate.

Retry termination is guaranteed rather than argued.
`request_shadow_frame_spill()` latches on `force_shadow_frame` and
returns false if already set; `apply_budget_spill_retry` records only the
functions where it returned true, and any violation not recorded becomes
a hard error naming it. A function therefore cannot be retried twice.

#8686 builds the gap suite's fast-mode archives once in a dedicated
`gap-suite-build` job and shares them across the six shards. The
skipped-vs-failed distinction is handled explicitly: `always()` keeps a
SKIPPED build (full mode, where the job never runs) from cascading into
skipped shards, while the guard still requires `success` or `skipped`, so
a genuine build FAILURE stops the shards. The shard also verifies the
downloaded binary is runnable and exports PERRY_BIN / PERRY_RUNTIME_DIR.

#8684 inlines dtolnay/rust-toolchain and SHA-pins every other
third-party action. Verified no job and no gate is dropped: the single
removed step is the fast-mode archive build, which moved into
gap-suite-build.

No version bump.
@coderabbitai

coderabbitai Bot commented Aug 24, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: dadbd85a-8d16-4ced-aea3-4382a5e86437

📥 Commits

Reviewing files that changed from the base of the PR and between 10d9ca5 and 67fe3c5.

📒 Files selected for processing (39)
  • .github/workflows/auto-opt-app-patterns.yml
  • .github/workflows/benchmark.yml
  • .github/workflows/container-tests.yml
  • .github/workflows/coverage.yml
  • .github/workflows/docs.yml
  • .github/workflows/eh-transport.yml
  • .github/workflows/ext-link.yml
  • .github/workflows/feature-matrix.yml
  • .github/workflows/gate-freshness.yml
  • .github/workflows/gc-moving-witnesses.yml
  • .github/workflows/gc-native-roots.yml
  • .github/workflows/gc-parse-churn-gate.yml
  • .github/workflows/gc-ptr-shape-off-witness.yml
  • .github/workflows/gc-ratchet.yml
  • .github/workflows/gc-root-dominance.yml
  • .github/workflows/llvm-inprocess.yml
  • .github/workflows/next-app-route.yml
  • .github/workflows/node-compat-matrix.yml
  • .github/workflows/node-core-subset.yml
  • .github/workflows/node-suite-guard.yml
  • .github/workflows/npm-launcher.yml
  • .github/workflows/npm-package-sweep.yml
  • .github/workflows/npm-publish-freshness.yml
  • .github/workflows/npm-stage-publish.yml
  • .github/workflows/release-hono-server.yml
  • .github/workflows/release-packages.yml
  • .github/workflows/security-audit.yml
  • .github/workflows/simctl-tests.yml
  • .github/workflows/test.yml
  • .github/workflows/tls-budget.yml
  • changelog.d/8679-rs4gc-budget-spill-retry.md
  • crates/perry-codegen/src/codegen/helpers.rs
  • crates/perry-codegen/src/codegen/mod.rs
  • crates/perry-codegen/src/function.rs
  • crates/perry-codegen/src/inprocess.rs
  • crates/perry-codegen/src/linker.rs
  • crates/perry-codegen/src/native_emit.rs
  • crates/perry/src/commands/compile/build_cache.rs
  • crates/perry/src/commands/compile/object_cache.rs

📝 Walkthrough

Walkthrough

Changes

RS4GC budget retry

Layer / File(s) Summary
Spill contract and budget detection
crates/perry-codegen/src/function.rs, crates/perry-codegen/src/inprocess.rs, crates/perry-codegen/src/codegen/helpers.rs, changelog.d/8679-rs4gc-budget-spill-retry.md
Late spill requests now convert functions to shadow-frame lowering. RS4GC budget violations now use typed retry data and apply only to rewritten functions.
Compilation retry orchestration
crates/perry-codegen/src/codegen/mod.rs, crates/perry-codegen/src/linker.rs, crates/perry-codegen/src/native_emit.rs
Text, native, differential, and split-unit compilation retries after budget violations. Affected functions are re-lowered, modules are rebuilt, and completed unit graphs are released.
Cache metadata
crates/perry/src/commands/compile/build_cache.rs, crates/perry/src/commands/compile/object_cache.rs
Cache comments now describe per-function RS4GC budget behavior and shadow-frame re-lowering.

CI workflow reproducibility

Layer / File(s) Summary
Pinned actions and Rust toolchains
.github/workflows/*
GitHub Actions references are pinned to immutable commits. Rust jobs install nightly-2026-08-20 directly with rustup.
Shared fast-mode gap build
.github/workflows/test.yml
Fast-mode gap shards download shared compiler and runtime artifacts instead of building them independently. Full mode keeps independent builds.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant LLVMCompilation
  participant RS4GCBudget
  participant ShadowFrameLowering
  participant NativeEmission
  LLVMCompilation->>RS4GCBudget: enforce rewritten-function instruction cap
  RS4GCBudget-->>LLVMCompilation: return typed budget violations
  LLVMCompilation->>ShadowFrameLowering: request spill for violating functions
  ShadowFrameLowering-->>LLVMCompilation: mutate lowering state
  LLVMCompilation->>NativeEmission: rebuild and emit compiled output
Loading

Suggested reviewers: jdalton

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch merge/b12

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant