Skip to content

[SwiftParser] Intern the whole source buffer for a full parse#3384

Open
rintaro wants to merge 1 commit into
swiftlang:mainfrom
rintaro:parser-fullparse-bulk-intern
Open

[SwiftParser] Intern the whole source buffer for a full parse#3384
rintaro wants to merge 1 commit into
swiftlang:mainfrom
rintaro:parser-fullparse-bulk-intern

Conversation

@rintaro

@rintaro rintaro commented Jul 14, 2026

Copy link
Copy Markdown
Member

748dde4 stopped copying the whole source buffer by interning each token's text individually — good for incremental reparsing memory, but it regressed full parses, which now copy the source in as many small pieces as there are tokens instead of one bulk copy.

This recovers most of that while keeping the self-contained tree. For a full (non-incremental) parse, the whole source is copied into the arena once and the lexer runs over that copy, so tokens point into arena-owned memory and internParsedTokenText returns their text unchanged instead of copying it. Incremental reparsing is unchanged (still per-token), so its new tree references only the re-lexed spans, not the whole buffer.

ParsingRawSyntaxArena.internSourceBuffer copies the buffer and returns the copy for Parser to lex over; internParsedTokenText returns text within the copy as-is and copies anything else (e.g. synthesized tokens). Since the arena owns the copy, a full parse no longer needs a separate parser-owned source copy and nothing points into the caller's buffer after parsing.

Measurements: instructions per full parse of a 178 KB source (release, whole-package cross-module optimization, RawSyntax validation off, deterministic instruction counts):

build instructions / parse
before 748dde4 (whole-buffer interning) ~84.8 M
main (748dde4, per-token interning) ~88.2 M
this PR ~85.3 M

So this recovers roughly 80% of the regression, with wall-clock back at the pre-748 level; the small remainder is the per-token internParsedTokenText call itself, which still runs (returning the text unchanged) but no longer copies.

748dde4 ([SwiftParser] Intern source text per parsed token) changed
parsing to intern each token's text individually instead of copying the
whole source buffer once, so a parsed tree no longer retains the source
buffer. That is important for incremental reparsing memory, but it
regressed full-parse performance: a full parse now copies the source in
as many pieces as there are tokens, each with its own bump-allocation
and memcpy, rather than in a single bulk copy.

For a full (non-incremental) parse, copy the whole source into the arena
once and lex over that copy. Parsed tokens then point directly into
arena-owned memory, so `internParsedTokenText` returns their text
unchanged instead of copying it, and the tree stays self-contained. An
incremental reparse keeps interning each re-lexed token individually, so
its new tree still references only the re-lexed spans and not the whole
buffer.

`ParsingRawSyntaxArena.internSourceBuffer` copies the buffer, records
its bounds, and returns the copy for `Parser` to lex over on a full
parse; `internParsedTokenText` returns text that lies within the copy
unchanged and copies anything else (e.g. synthesized tokens). Because
the copy is owned by the arena, a full parse needs no parser-owned
source copy, and nothing points into the caller's buffer once parsing
returns.
@rintaro rintaro force-pushed the parser-fullparse-bulk-intern branch from c044d1d to 1f6c623 Compare July 14, 2026 18:04
@rintaro

rintaro commented Jul 14, 2026

Copy link
Copy Markdown
Member Author

@swift-ci Please test

@rintaro

rintaro commented Jul 15, 2026

Copy link
Copy Markdown
Member Author

@swift-ci Please test Linux

2 similar comments
@rintaro

rintaro commented Jul 15, 2026

Copy link
Copy Markdown
Member Author

@swift-ci Please test Linux

@rintaro

rintaro commented Jul 16, 2026

Copy link
Copy Markdown
Member Author

@swift-ci Please test Linux

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.

1 participant