Repository navigation
perf(string): repeated immutable prefix + number materializes separate flat strings; measure prefix-sharing opportunity #11745
Description
Problem and measured evidence
Each document node creates a distinct string from the same long immutable prefix plus a seed number:
const TEXT = 'A collaborative document revision contains paragraphs, comments, edits, and history. '.repeat(3);
// DocNode constructor:
this.text = TEXT + seed;Measured 2026-10-01 on macOS arm64, Perry main d40ed1a47019bcae547819ebb5756bcd96ba1057 (v0.5.1655), with matching compiler and runtime archives. This snapshot already includes #11645. These are diagnostic probes; no compiler/runtime fix was applied and the original comparison remains unchanged.
Three external 8-second stack captures at 1 ms (19,648 main-thread observations) attribute 8.33% inclusive / 7.22% exclusive observations to js_string_concat_value. This includes formatting and flat-string construction; it does not isolate prefix copying from numeric conversion.
A separate explicit-full-GC census with the cache populated reports approximately 3.08 MiB of strings out of 5.16 MiB reachable tracked heap data (largest live category), with 10,920 DocNodes. Census scheduling/observer allocations differ from the ordinary run. No shared-prefix or rope implementation was benchmarked.
Distinct from existing tickets
- perf: number-to-string is 6.6x-15.9x bun, and four spellings of it differ by 2.6x inside perry while bun spans 30-34 instructions #10762 covers numeric formatting and conversion-path differences; that is a component of this operation.
- perf: no rope/cons-string representation makes accumulator concatenation quadratic (514x Node at n=16000; 17.9% of iso_miss) #8394 was closed by perf(codegen): retain string accumulators in concat chains #8417's unique-owner accumulator append selection. This workload creates separate strings from an immutable shared prefix, not a growing accumulator.
- perf(codegen): str.concat(a, b, …) copies the accumulator once per argument — fold into one js_string_concat_chain call #8433 covers multi-argument
.concat()fusion, not this two-operand construction.
Track the remaining opportunity to reduce repeated immutable-prefix materialization/copying where semantics permit. A shared immutable prefix/cons representation is one possible approach; a rope architecture is not a required solution.
Next measurement and acceptance
First isolate numeric formatting, result allocation and prefix-copy cost with varying prefix lengths and equivalent outputs; the 8.33% figure must not be claimed as copying alone. Then measure any candidate against the unchanged cyclic workload, including downstream .length, charCodeAt, indexing/traversal and GC cost, plus retained/released strings.
Preserve independent string values, Unicode/WTF-8 joins, conversion/evaluation order, equality and GC lifetime semantics. Report end-to-end CPU, peak RSS and live string bytes; avoid trading cheaper construction for greater downstream cost without making that trade explicit.
Complete unchanged workload and method: #11743.
Evidence in the project-comparison workspace: demo/results/stress/perry-profile/summary.md, profile-manifest.json, cpu-summary.json, experiment-summary.json, experiments.json, gc-diagnostics.stderr, nursery-4-gc-diagnostics.stderr, census.jsonl, vmmap-*.txt, and the original/typed-receiver makeTree disassemblies. These paths are local artifacts, not publicly hosted links.
Activity