perf(gc): inline hot-TLS values in HotTls; leaf write-barrier entry (ECS round 4, +2.7%) - #8935
Conversation
…otTls A hot-TLS slot and a named pointer field both resolve as TSD base → HotTls → slot pointer → value. On the three probes that run on nearly every store or boxed read — the write barrier's one-entry dirty-page cache, the memoized Array.prototype / Object.prototype rows consulted by every indexed array write, and the direct-mapped box-pointer caches — the profile put the barrier's remaining self time on that dependent chain rather than on anything it computed. Small Copy values with a const initial state can live in HotTls itself (TSD base → HotTls → value), so these five now do; the generic slot mechanism is unchanged for everything else, and the collector's root rewrite of the prototype rows walks the inline cells exactly as it walked the slot. Claude-Session: https://claude.ai/code/session_01FUvFrRNZyc5qknBiJbYbby
Every pointer store into an old object reached js_write_barrier_slot_validated_parent, which made two out-of-line calls before anything was decided — decode_heap_addr for the child, and incremental_mark_barrier_value, whose "no cycle anywhere" test sat inside the callee — and then entered the outlined write_barrier_decoded_parent, whose frame saves six registers, to run the one-entry dirty-page cache compare that answers the second and third push into the same bucket. The tag decode and the idle test now inline (their slow arms are cold, out of line), and the cache test is hoisted into the entry ahead of the outlined body, so a hit is a leaf path: a tag test, two static loads, the hot-TLS page compare, return. The counters and the remembered set built are unchanged; the decoded-parent body keeps its own copy of the test for its other callers. Claude-Session: https://claude.ai/code/session_01FUvFrRNZyc5qknBiJbYbby
… now holds inline Claude-Session: https://claude.ai/code/session_01FUvFrRNZyc5qknBiJbYbby
|
Warning Review limit reachedNext included review available in 8 minutes. View limit detailsLimit details: You’ve used all 8 included reviews currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (10)
💤 Files with no reviewable changes (1)
Included review availability: Your plan provides up to 8 included reviews per hour; 2 remain after this review. 📝 WalkthroughWalkthroughThe runtime moves prototype, box-pointer, and dirty-page caches into ChangesRuntime and GC optimization
Estimated code review effort: 3 (Moderate) | ~25 minutes Merge Risk: ⚪ Minimal · up to The PR introduces localized GC/TLS performance optimizations while preserving the existing barrier controls and remembered-set behavior; no actionable merge-blocking risk remains beyond normal checks and review. Sequence Diagram(s)sequenceDiagram
participant SlotStore
participant CachedDirtyPageCheck
participant DirtyPageCache
participant DecodedWriteBarrier
SlotStore->>CachedDirtyPageCheck: Check parent_addr and slot_addr
CachedDirtyPageCheck->>DirtyPageCache: Read cached dirty page
DirtyPageCache-->>CachedDirtyPageCheck: Return hit or miss
alt Cache hit
CachedDirtyPageCheck-->>SlotStore: Return without outlined barrier
else Cache miss
SlotStore->>DecodedWriteBarrier: Invoke decoded-parent barrier
end
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Full details: Docstring CoverageExplanation Docstring coverage is 92.31% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 39 functions across 8 files. (1 skipped: 1 unsupported.) Full details: Description checkExplanation The description gives detailed summaries, benchmark results, implementation details, and test results. However, it does not use the required template sections and omits the Related issue and Checklist sections. Resolution Rewrite the description using the required headings: Summary, Changes, Related issue, Test plan, Screenshots / output, and Checklist. Add ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
…the leaf barrier Both are `-D warnings` errors, so the `warnings` job was red on this branch.
|
Composition check on current |
Two GC/TLS mechanisms from the ECS round-4 chain (each screened with paired alternating runs on the idle Mac mini and confirmed over 15 pairs on the
codehz/ecs"5k entities: 3 commands each + sync" row). They were pushed onto #8916 after it had already merged with only its first commit, so they never reached main — this PR re-cuts them from current main. Write-up:secret-tests/ecs-suite/PERRY_ECS_FOLLOWUP_2026-08-27_CLAUDE.md.HotTlsr4h-confirm.json)r4i-confirm.json)HotTls. A hot-TLS slot and a named pointer field both resolve as TSD base →HotTls→ slot pointer → value; PC histograms put the remaining self time of the write barrier,js_map_clear(10k calls/frame, both hot offsets on its two TLS probes),is_registered_box_ptrandarray_prototype_addron that dependent chain rather than on anything they compute. SmallCopyvalues with aconstinitial state can live inHotTlsitself (TSD base →HotTls→ value), so the barrier's one-entry dirty-page cache, the memoizedArray.prototype/Object.prototyperows and the three box-pointer caches now do; the generic slot mechanism is unchanged for everything else, the collector's root rewrite of the prototype rows walks the inline cells exactly as it walked the slot, and the custody audit's frontier entries for the removed box-cache statics are deleted (the deletion is the receipt).js_write_barrier_slot_validated_parent, which made two out-of-line calls before anything was decided —decode_heap_addrfor the child, andincremental_mark_barrier_value, whose "no cycle anywhere" test sat inside the callee — and then entered the outlinedwrite_barrier_decoded_parent(six callee-saved registers) to run the one-entry dirty-page compare that answers the second and third push into the same bucket. The tag decode and the idle test now inline (their slow arms are cold, out of line), and the cache test is hoisted into the entry ahead of the outlined body (gc/barrier/leaf.rs), so a hit is a leaf path. Counters and the remembered set built are unchanged; pinned byvalidated_parent_entry_answers_a_cached_dirty_page_store_before_the_body.Tests: runtime suite (2764) incl.
gc::tests::barrier(411, serial),runtime_roots,box::; custody audit + lint gates and merge-base ratchets replayed locally.https://claude.ai/code/session_01FUvFrRNZyc5qknBiJbYbby
Summary by CodeRabbit
Performance
Bug Fixes