Ruby: Intern short token values - #2328
Closed
joelhawksley wants to merge 5 commits into
Closed
Conversation
Intern token values up to 16 bytes while preserving mutable, independently allocated long values. Add copy-on-write and replacement compatibility for consumers of frozen short values. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This was referenced Aug 20, 2026
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
joelhawksley
added a commit
to joelhawksley/herb
that referenced
this pull request
Aug 21, 2026
Follow-on to marcoroth#2328. Herb::Token was 27% of live parse objects, with its backing Range/Location/Position objects accounting for another 33%. This changes rb_token_from_c_struct to allocate the Herb::Token instance directly and set its ivars from the raw numeric range/location components (via cached ivar IDs) instead of eagerly constructing Range/Location/Position Ruby objects for every token. Those objects are now materialized lazily, memoized on first access to #range/#location. Benchmarked against marcoroth/herb-corpus (36,989 .erb files): Herb.lex: allocations: 85.98M -> 36.95M (-57%) wall time: 3.17s -> 2.13s (-33%) Herb.parse: allocations: 62.22M -> 42.48M (-32%) wall time: 4.93s -> 4.95s (~flat) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The types-only test in test/interned_type_test.rb asserted that all token values remain mutable and unshared. Short-value interning narrows that guarantee to values over 16 bytes, so rewrite the test to use a 17-byte tag name and drop the writer-absence assertion. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
marcoroth
marked this pull request as draft
August 21, 2026 03:31
joelhawksley
marked this pull request as ready for review
August 21, 2026 15:29
Contributor
Author
|
I'm going to close this for now as re-benchmarking has shown that it slows compilation by about a second on a benchmark I'm working on. |
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.
What
Follow-up split from #2234, as requested in the maintainer review.
Intern token values of 16 bytes or fewer with
rb_enc_interned_str. These common structural values are shared frozen strings; values over 16 bytes remain freshly allocated, independent, mutable strings. This PR intentionally does not include token or AST node type interning.Because short token values are frozen, this also:
Token#tree_inspectchange encoding on a copy rather than the token value;Token#value=writer (and RBS API) for visitors that replace values;Benchmarks
Re-benchmarked after merging the latest
main(parse + lex over 36,989 corpus files,GC.stat[:total_allocated_objects]):Short-value interning saves an incremental 15.8M allocations beyond the types-only variant on
main.Testing
ext/herb/extension_helpers.cagainst Ruby: Intern token and AST node type strings聽#2234 by keeping the newrb_interned_string_from_hb_string/rb_token_type_valuehelpers and routingrb_token_value_from_hb_stringthrough them.