perf(formatter): accumulate JSX child-list builders on the heap#24585
Conversation
How to use the Graphite Merge QueueAdd either label to this PR to merge it via the merge queue:
You must have a Graphite account in order to use the merge queue. Sign up using this link. An organization admin has enabled the Graphite Merge Queue in this repository. Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue. This stack of pull requests is managed by Graphite. Learn more about stacking. |
Merging this PR will not alter performance
Comparing Footnotes
|
0c8e314 to
4a5c078
Compare
Oxfmt Ecosystem CI
💥 = panic, |
72ae10f to
c835270
Compare
4a5c078 to
d9a6184
Compare
d9a6184 to
8510ba2
Compare
c835270 to
7aa30a3
Compare
7aa30a3 to
a9a2c78
Compare
8510ba2 to
0433b79
Compare
a9a2c78 to
c3b460b
Compare
0433b79 to
679a9e8
Compare
Merge activity
|
The JSX child-list builders (`MultilineBuilder` / `FlatBuilder` in `child_list.rs`) were the last IR staging path still growing vectors in the arena. They accumulate elements across the whole child-list loop while arbitrary child content is formatted in between, so every growth stranded its old allocation (the same pattern #24582 removed from `intern` / `BestFitting` / grouped arguments). They can't use `HeapVecBuffer`: the flat and multiline builders write *alternately* for each child, which would interleave their segments in the shared scratch vector and break its LIFO watermark discipline. The thread-local cache behind it has no such requirement though. So each builder now checks out its own `ScratchBuffer` and writes into it through a small private `Buffer` adapter (`ChildListBuffer`); the finished result reaches the arena as one exactly-sized copy via the new `Formatter::intern_elements`, which clears the source so its capacity returns to the cache on drop. Now arena reallocs for `RadixUIAdoptionSection.jsx` is 0.
c3b460b to
7810e8a
Compare
679a9e8 to
94de05f
Compare

The JSX child-list builders (
MultilineBuilder/FlatBuilderinchild_list.rs) were the last IR staging path still growing vectors in the arena.They accumulate elements across the whole child-list loop while arbitrary child content is
formatted in between, so every growth stranded its old allocation (the same pattern #24582 removed from
intern/BestFitting/ grouped arguments).They can't use
HeapVecBuffer: the flat and multiline builders write alternately for each child, which would interleave their segments in the shared scratch vector and break its LIFO watermark discipline. The thread-local cache behind it has no such requirement though.So each builder now checks out its own
ScratchBufferand writes into it through a small privateBufferadapter (ChildListBuffer); the finished result reaches the arena as one exactly-sized copy via the newFormatter::intern_elements, which clears the source so its capacity returns to the cache on drop.Now arena reallocs for
RadixUIAdoptionSection.jsxis 0.