Repository navigation
perf: one access seam for InternalValue outside wave 2's files (0140 P0a) - #453
Merged
Merged
Conversation
InternalValue's layout is about to change (P2: 32 B, trivially copyable immediate plus one intrusive pointer). Code outside internal_value.* now reads values through an interface that layout can keep: - ValueKind and InternalValue::Kind() say what a value is. - AsList/AsMap return non-owning ListRef/MapRef views; visitors receive the views (as const lvalues, so their overloads beat forwarding- reference templates) instead of the adapters. ToAdapter() makes the owning copy where a site keeps the list. - AsStringView<CharT> and TakeString read and take strings; IsStringValue moves next to them from markup.h and value_methods.cpp. - IMapAccessor::SetValue is const, so a value can hold its accessor as a const object. Instruction counts stay within 0.5% of master except Render/large_static (+0.55%, 150 instructions); mitsuhiko_table is 1.6% lower because ConvertToList now copies a list once instead of twice. Allocations are unchanged. reverse() of a plain std::string value (a key of dict.items()) now gives a string, as in Python, instead of a list of characters. The dictsort pair subscript gap found on the way is filed as 0159. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014gsczz1ZU7Lu24hymWrNJv
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014gsczz1ZU7Lu24hymWrNJv
rmorozov
marked this pull request as ready for review
October 11, 2026 08:06
rmorozov
added a commit
that referenced
this pull request
Oct 11, 2026
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.
Requested by Ruslan · project thread
Before: code all over
src/readInternalValuethrough how it is stored:GetIf<ListAdapter>,GetData(),std::get_ifon the variant, switches on its index. P2 (the 32 B layout in docs/design/0140-internal-value-plan.md) would have had to edit every one of those sites.After: outside
internal_value.*and wave 2's files, values are read through one seam that P2 can keep. Behaviour is unchanged except for one parity fix:reverseof adict.items()key now gives a string, as in Python. Before, it gave a list of characters.The seam, all in
src/internal_value.h:ValueKind/InternalValue::Kind()says what a value is.AsList/AsMapreturn non-owningListRef/MapRefviews. Overloads taking a temporary are deleted.const ListRef&overload beats a forwarding-reference template.ToAdapter()makes the owning copy where a site keeps the list.AsStringView<CharT>andTakeStringread and take strings.IsStringValuemoved here from markup.h and value_methods.cpp.IMapAccessor::SetValueis const, so a value can hold its accessor as a const object.Left for P0b, once wave 2 releases its files: the callers of
GetIf<ListAdapter>/GetIf<MapAdapter>,GetStringViewandNarrowStringViewin expression_evaluator.* and statements.*, thenGetData()itself.How. Each site was converted mechanically, then recounted under Callgrind. The first count was +0.2..+6.6% Render, so three hot paths were reworked:
IsNumberkeeps per-alternative tests. AKind()comparison cost +6.6% on expressions.OutStream::WriteValueTotests int, string, host value and bool in turn. Strings meet at oneWriteString, which GCC then keeps inline.ConvertToListreturns a list's copy in place. Before, it copied twice, throughstd::optional.Instruction counts (bench/count.py, Release, vs ec9e7b4; allocations and memory identical on every case):
Render/large_static's +0.55% is +150 instructions per render, about 2 per string write in
WriteValueTo. It is an interim cost of the seam. P2, the 32 B layout, recovers it, together with #445's Load/plain_text +0.75%; the 0140 task file records both.Parity. New corpus case
filters.reverse_dict_item_keypins the reverse fix.filters.dictsort_pair_subscriptpins a gap found on the way:p[0]of a dictsort pair is undefined. It is filed as docs/tasks/0159 and listed in divergences/filters.txt.Process. Two verifier rounds ran.
Red pushes so far: 0.
scripts/preflight.shpasses.🤖 Generated with Claude Code
https://claude.ai/code/session_014gsczz1ZU7Lu24hymWrNJv