Flat token buffer: lexer-fused parsing, flat mbe transcription, view-backed macro args, sink-replayed nonterminals [-1.14% incl tt-heavy, jemalloc, noise-controlled] - #57
Draft
xmakro wants to merge 12 commits into
Conversation
xmakro
force-pushed
the
perf/flat-token-cursor
branch
from
July 27, 2026 21:37
655edfd to
6728659
Compare
xmakro
force-pushed
the
perf/flat-token-cursor
branch
from
August 1, 2026 08:44
6728659 to
7646199
Compare
This was referenced Aug 1, 2026
xmakro
force-pushed
the
perf/flat-token-cursor
branch
from
August 3, 2026 22:48
7646199 to
0ba08c1
Compare
xmakro
force-pushed
the
perf/flat-token-cursor
branch
from
August 4, 2026 07:44
0ba08c1 to
e9ee005
Compare
xmakro
force-pushed
the
perf/flat-token-cursor
branch
from
August 6, 2026 10:42
e9ee005 to
98ddb58
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The full flat-token architecture. Twelve commits:
from_str, cmdline attrs, diagnostics fake streams) rebuild it from the buffer. Delimiter-recovery diagnostics are preserved byte-for-byte.$x:ttfragments are shared at capture (a buffer-slice refcount bump, like the old cursor's Arc clone atparse_token_tree); splicing a captured fragment into expansion output copies its entries once per substitution (splice_sliceextends the output buffer and rebases the match table). An earlier version of this description claimed splice-time sharing; that was wrong.LazyAttrTokenStreamInnerdrops from 88 to 64 bytes (vs main).Arcpointer-equality fast paths,u32::MAXentry guard,enclosing_delimitervia the match table, assorted assertion hardening.current_group_slicefails loudly in release builds on non-buffer-backed captures.TokenStreamInnerhad grown to 48 bytes: a dead 32-byteOnceLockin every eager stream, paying for the rare view case. TheFlatvariant is now a nichedBox; the enum is back atVecsize (24 bytes,static_assert_sized, so eager streams cost exactly what they did on main).TokenStreamIterhad regressed fromslice::Iterto a per-element re-resolution of the stream backing (enum match +OnceLockcheck on everynext()). It holds the materialized slice again;next()is a slice index.FlatSink(which gainedpatch_open_spacingfor the after-the-fact open-delimiter spacing), andFlatBuffer,FlatEntry's fields, andFlatTokenCursor::from_partsare private: the sink is the only producer.current_group_slice's token-equality debug assert compared spans thatParser::bumpdeliberately rewrites (dummy-span fixup); it compares kinds only now. The capture machinery's coupling tobump_with(injected tokens must not be open delimiters) is documented onbump_with.KeywordIdentsscans share one per-token helper so they cannot drift./6lexer presize and thefinishslack threshold are backed by measured token density over rust-lang/rust itself (byte-weighted ~7.0 bytes/token for compiler/, ~5.9 for library/, per-file quartiles ~5.1/6.1/7.4, stress files down to ~1.7) with the undershoot/overshoot cost asymmetry spelled out in the comment.metavar_expr_concatreturns aToken, deleting anunreachable!.flat_round_tripcompares rebuilt trees, which cannot see depth or match divergence).$e:expr/$t:ty/... is already a lazy replay over the flat buffer (LazyAttrTokenStreamInner::Pending); substituting it used to materialize that replay into anAttrTokenStream, convert to token trees, and re-flatten into the sink.FlatSink::splice_lazynow replays the capture token-by-token directly into the output. Fallbacks keep every hairy case on the tree path: attribute-bearing nodes, pending cfg/inner-attr replacements, broken last tokens, already-materialized streams, and captures starting with a metavar-invisible group (a conservative superset of the same-MetaVarKindunwrap rule). Delimiter balance is enforced with hard asserts, and underdebug_assertionsevery fast-path splice re-runs the materializing path and asserts tree-for-tree equality — so the debug-assertions ui suite differentially validates the new path against the old one across every macro expansion it contains.Known costs, stated plainly:
ttfragments and view-backedMacCallarguments pin their backing buffer; worst-case retention is (macro recursion depth) x (per-level buffer size) for tt-muncher-style recursion, since each level's output holds slices of the previous level's. The max-rss numbers below include the stress crates that hit this; worst measured cell is +1.8%.ttfragment into expansion output copies it once per substitution; non-ttmetavariables pay onesplice_streamflatten of theirfrom_aststream per substitution.from_strand the other cold tree consumers pay a rebuild pass over the buffer.Performance
Measured at the current head (all 12 commits) vs its base c9ff496: stage2 builds of both from the same worktree/config (CI LLVM, no PGO/BOLT), benched under jemalloc (LD_PRELOAD), instructions:u, Check+Debug, Full scenario, mbe/tt-heavy crate set. Noise floor established with a same-commit ThinLTO-control pair: base-vs-control geomean -0.000%, worst cell +/-0.036%, zero cells beyond +/-0.25%.
instructions:u geomean -1.141% (n=20), 12 cells improved >= 0.25%, 0 regressed >= 0.25%:
The only cells above the noise floor in the wrong direction are token-stream-stress (+0.23%/+0.18%, both under the 0.25% significance threshold): it is the proc-macro pass-through stress, and proc-macro output still pays a per-expansion flatten (callgrind attributes the residual to bridge-side tree conversions; bridge-side flat emission is the named follow-up). The nonterminal sink-replay commit alone contributed -0.51% geomean with zero regressions, including deep-vector -4.4% and more than halving the token-stream-stress residual.
max-rss geomean -1.24%: deep-vector -14.7% check / -4.7% debug, serde -1.9/-1.2%, syn check -1.7%; worst increase tt-muncher debug +0.54%.
Numbers previously in this description (-1.07% geomean) were measured on glibc against a pre-rebase base without a control pair, and are withdrawn; the current numbers supersede them.
Correctness at the current head
x check compilergreen at every commit of the seriesRemaining follow-ups (not blockers): bridge-side flat emission for proc-macro output (would remove the last sub-threshold residual); mbe attr/derive rules materialize a tree at the boundary; the commit stack should be squashed into its logical steps before an upstream submission.