Skip to content

perf(gc): align barrier gate load ordering - #7935

Merged
proggeramlug merged 2 commits into
mainfrom
fix/7918-barrier-active-ordering
Aug 12, 2026
Merged

perf(gc): align barrier gate load ordering#7935
proggeramlug merged 2 commits into
mainfrom
fix/7918-barrier-active-ordering

Conversation

@proggeramlug

@proggeramlug proggeramlug commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Summary

  • emit every generated PERRY_INCREMENTAL_MARK_BARRIER_ACTIVE_COUNT gate as an LLVM monotonic load, matching Rust's Relaxed readers
  • route the remaining shadow-stack runtime gate through the shared relaxed helper
  • document why the counter is authoritative state rather than a publication fence, and correct the previously reversed enable/disable ordering descriptions
  • pin all three generated gate families and the live armed-barrier invariant at the relaxed ordering

Why Relaxed is sufficient

The counter does not publish the ValidPointerSet or any other memory. It only decides whether the current thread should pay for a TLS read and barrier call.

Arming increments the counter before installing the current thread's TLS pointer. Disarming clears that pointer before decrementing the counter. A later relaxed load on an armed thread therefore cannot observe a counter value preceding its own increment, and the count cannot return to zero until that thread removes its contribution. A thread with a null TLS pointer may conservatively observe either value: skipping the call on zero is equivalent to the call reading null and returning. There is no cross-thread data for an acquire load to publish.

Validation

  • pre-fix reproduction: both root-gate IR tests failed because the generated load was seq_cst
  • cargo test -p perry-codegen: passed in full
  • cargo test -p perry-runtime: 2,194 passed, 0 failed, 4 ignored
  • post-rebase focused ordering suite on current main: 5 passed, 0 failed
  • cargo fmt --all -- --check
  • bash scripts/check_file_size.sh

Performance

Built separate compiler/runtime pairs for base and fix and compiled gc-handoff/apps/interp.ts with each. Both arms printed 1708840, exited 0, and produced the same 13,709,320-byte executable size.

Machine code changed as intended: whole-binary ldar count 779 -> 44 and ldr count 229,093 -> 229,828 (735 matching replacements).

On the quiet M1 mini (load 1.60-1.99, no foreign benchmark/build processes), two order-reversed 31-pair sweeps were neutral:

arm best median
base 0.6277-0.6280 s 0.6288 s
fix 0.6276 s 0.6284 s

Instructions were unchanged, as expected for one instruction replacing one instruction; best cycles moved -0.14%. This resolves the reader/documentation disagreement without a measurable regression, but the profiled ldar was not a standalone speedup.

Closes #7918

Summary by CodeRabbit

  • Performance

    • Reduced synchronization overhead for incremental garbage-collection barriers by using lighter-weight atomic checks.
    • Replaced 735 unnecessary stronger loads in the interpreter without measurable runtime impact.
  • Bug Fixes

    • Improved consistency between generated barriers and runtime barrier state handling.
  • Tests

    • Expanded coverage to verify barrier ordering, atomicity, alignment, and all generated barrier variants.

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 495d5b33-1e77-4620-b1fe-c617895cf23b

📥 Commits

Reviewing files that changed from the base of the PR and between f110261 and 536ce35.

📒 Files selected for processing (10)
  • changelog.d/7935-barrier-gate-ordering.md
  • crates/perry-codegen/src/expr/class_field_barrier_tests.rs
  • crates/perry-codegen/src/expr/shadow_inline.rs
  • crates/perry-codegen/src/expr/shadow_slot.rs
  • crates/perry-codegen/src/expr/write_barrier.rs
  • crates/perry-codegen/tests/shadow_slot_hygiene.rs
  • crates/perry-runtime/src/gc/barrier/mod.rs
  • crates/perry-runtime/src/gc/roots/shadow_stack.rs
  • crates/perry-runtime/src/gc/tests/inline_generation_gate_contract.rs
  • crates/perry-runtime/src/gc/tests/shadow_stack_ops.rs

📝 Walkthrough

Walkthrough

The change aligns incremental-barrier active-counter reads across runtime and generated code. Runtime readers use relaxed ordering, generated LLVM loads use monotonic ordering, and tests verify the atomic load contract across barrier gate families.

Changes

Incremental barrier ordering

Layer / File(s) Summary
Runtime counter contract
crates/perry-runtime/src/gc/barrier/mod.rs, crates/perry-runtime/src/gc/roots/shadow_stack.rs, crates/perry-runtime/src/gc/tests/*
The runtime exposes incremental_mark_barrier_globally_idle within the crate, documents counter ordering, delegates root-shading checks to the helper, and updates runtime tests to use Relaxed loads.
Generated barrier gate ordering
crates/perry-codegen/src/expr/*barrier*, crates/perry-codegen/tests/shadow_slot_hygiene.rs, changelog.d/7935-barrier-gate-ordering.md
Generated barrier gates use LLVM monotonic loads. Tests verify atomicity, alignment, and ordering across gate families. The changelog records the ordering changes and benchmark observations.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

  • PerryTS/perry#7079: Modifies the same shadow-stack barrier gating and active-count checks.
  • PerryTS/perry#7088: Introduces the affected shadow_inline.rs and shadow_slot.rs barrier paths.
  • PerryTS/perry#7602: Modifies incremental-mark barrier gating in write_barrier.rs and related contract tests.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: aligning garbage-collection barrier gate load ordering.
Description check ✅ Passed The description covers the summary, rationale, changes, related issue, validation, performance results, and relevant checklist information.
Linked Issues check ✅ Passed The changes align codegen and runtime barrier-counter loads with relaxed ordering and address the documentation and consistency objectives in [#7918].
Out of Scope Changes check ✅ Passed The changes remain focused on barrier gate ordering, related documentation, tests, and the corresponding changelog entry.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ 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 fix/7918-barrier-active-ordering

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.

@proggeramlug
proggeramlug marked this pull request as ready for review August 12, 2026 08:51
@proggeramlug
proggeramlug merged commit 653ccc9 into main Aug 12, 2026
1 of 19 checks passed
@proggeramlug
proggeramlug deleted the fix/7918-barrier-active-ordering branch August 12, 2026 09:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

gc/codegen: barrier-active load is seq_cst in codegen but Relaxed in the runtime — the two readers disagree on ordering

1 participant