Skip to content

perf(parser): shrink-wrap cold diagnostic tails out of hot frames#23159

Merged
graphite-app[bot] merged 1 commit into
mainfrom
perf/pattern-a-cold-tails
Jun 9, 2026
Merged

perf(parser): shrink-wrap cold diagnostic tails out of hot frames#23159
graphite-app[bot] merged 1 commit into
mainfrom
perf/pattern-a-cold-tails

Conversation

@Boshen

@Boshen Boshen commented Jun 9, 2026

Copy link
Copy Markdown
Member

Finding (Pattern A from assembly audit — highest-leverage)

An assembly audit found several hot lexer/parser functions carrying a large stack frame + callee-saved register spills unconditionally, purely to construct a ~232-byte OxcDiagnostic buffer on a cold error arm that almost never runs. Classic missed shrink-wrapping: the rare path's frame is paid on every hot return.

Change

Move each cold diagnostic arm out of line — cold_branch(...) (already the idiom for the sibling string-escape / line-break arms), or #[inline(never)] for the destructuring cover impls.

Function frame before → after notes
QOD / QOS (string handlers) 288 B → 0 B now frameless leaves
LSS (the < byte handler) 288 B → 32 B <!-- HTML-comment arm outlined
cursor::asi 288 B → 64 B ASI-failure diagnostic → closure
check_after_numeric_literal 336 B frame → fully inlined invalid-number tail outlined
AssignmentTarget::cover 3066 instr / 448 B / 3 panic-sites → 225 / 176 B / 0 #[inline(never)] on Array/ObjectAssignmentTarget::cover

These are the hottest-frame offenders the audit surfaced; the underlying pattern recurs elsewhere and could be pushed into the byte-handler macros as a follow-up.

Verification

  • Pure codegen change, no behavior change. Conformance: byte-identical to main across all 31 snapshot suites (test262/babel/typescript × parser/semantic/codegen/estree/transformer/minifier/formatter).
  • Each frame shrink re-verified by disassembling before/after (ARM64, release codegen).

Caveat

Frame-size wins are instruction-count-scale; net effect on the per-token path must be confirmed on CodSpeed before merge. The AssignmentTarget::cover change moves the (rare) destructuring-target conversion out of line — confirm that path doesn't regress.

🤖 Generated with Claude Code

@Boshen Boshen self-assigned this Jun 9, 2026
@github-actions github-actions Bot added the A-parser Area - Parser label Jun 9, 2026
@codspeed-hq

codspeed-hq Bot commented Jun 9, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 62 untouched benchmarks
⏩ 9 skipped benchmarks1


Comparing perf/pattern-a-cold-tails (3f6d6b3) with main (cd0b384)

Open in CodSpeed

Footnotes

  1. 9 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@Boshen Boshen marked this pull request as ready for review June 9, 2026 14:59
@Boshen Boshen added the 0-merge Merge with Graphite Merge Queue label Jun 9, 2026

Boshen commented Jun 9, 2026

Copy link
Copy Markdown
Member Author

Merge activity

…3159)

## Finding (Pattern A from assembly audit — highest-leverage)

An assembly audit found several hot lexer/parser functions carrying a large stack frame + callee-saved register spills **unconditionally**, purely to construct a ~232-byte `OxcDiagnostic` buffer on a cold error arm that almost never runs. Classic missed shrink-wrapping: the rare path's frame is paid on every hot return.

## Change

Move each cold diagnostic arm out of line — `cold_branch(...)` (already the idiom for the sibling string-escape / line-break arms), or `#[inline(never)]` for the destructuring `cover` impls.

| Function | frame before → after | notes |
|---|---|---|
| `QOD` / `QOS` (string handlers) | 288 B → **0 B** | now frameless leaves |
| `LSS` (the `<` byte handler) | 288 B → **32 B** | `<!--` HTML-comment arm outlined |
| `cursor::asi` | 288 B → **64 B** | ASI-failure diagnostic → closure |
| `check_after_numeric_literal` | 336 B frame → **fully inlined** | invalid-number tail outlined |
| `AssignmentTarget::cover` | 3066 instr / 448 B / 3 panic-sites → **225 / 176 B / 0** | `#[inline(never)]` on `Array`/`ObjectAssignmentTarget::cover` |

These are the hottest-frame offenders the audit surfaced; the underlying pattern recurs elsewhere and could be pushed into the byte-handler macros as a follow-up.

## Verification
- **Pure codegen change, no behavior change.** Conformance: **byte-identical** to `main` across all 31 snapshot suites (test262/babel/typescript × parser/semantic/codegen/estree/transformer/minifier/formatter).
- Each frame shrink re-verified by disassembling before/after (ARM64, release codegen).

## Caveat
Frame-size wins are instruction-count-scale; net effect on the per-token path must be confirmed on **CodSpeed** before merge. The `AssignmentTarget::cover` change moves the (rare) destructuring-target conversion out of line — confirm that path doesn't regress.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
@graphite-app graphite-app Bot force-pushed the perf/pattern-a-cold-tails branch from 3f6d6b3 to f0fda4d Compare June 9, 2026 15:22
@graphite-app graphite-app Bot merged commit f0fda4d into main Jun 9, 2026
30 checks passed
@graphite-app graphite-app Bot removed the 0-merge Merge with Graphite Merge Queue label Jun 9, 2026
@graphite-app graphite-app Bot deleted the perf/pattern-a-cold-tails branch June 9, 2026 15:27
Boshen added a commit that referenced this pull request Jun 15, 2026
### 💥 BREAKING CHANGES

- 7a24911 codegen: [**BREAKING**] Borrow sourcemaps from codegen
(#23422) (Boshen)
- bb0ed44 transformer: [**BREAKING**] Disable styled-components
transpileTemplateLiterals by default (#23171) (Boshen)

### 🚀 Features

- 1490a0a linter/react: Implement react-compiler rule (#23202) (Boshen)
- 6c0bdf0 transformer/react-refresh: Support `module.property.useHook()`
(#23190) (Dunqing)
- 47991bd semantic: Report TS1228 for invalid type predicates (#23174)
(camc314)
- 1d3af58 parser: Add TS2398 parameter property diagnostic (#23216)
(camc314)
- 44313da semantic: Add `scope_is_descendant_of` api (#22313) (camc314)
- e5050c0 parser: Improve diagnostic for rest initializer (#23205)
(camc314)
- ec266bb transformer: Run React Compiler as a feature-gated transform
pass (#23201) (Boshen)
- e7374fe parser: Report error for `const` modifier on interface type
parameter (#23173) (camc314)
- a7c1c9b parser: Report ambient definite variable assertions (#23165)
(camc314)
- d169fcd parser: Report invalid class definite assertions (#23164)
(camc314)
- 00244d8 parser: Report definite property initializer errors (#23160)
(camc314)

### 🐛 Bug Fixes

- 52d0c31 transformer: Replace ambient dot defines (#23231) (camc314)
- 2c28748 transformer/class: Parent generated constructors to class
scope (#23222) (camc314)
- 8edd234 parser: Report accessor definite assertion on token (#23203)
(camc314)
- de38a3f react_compiler: Keep imports referenced only by a local
re-export (#23176) (Boshen)
- f5721c2 codegen: Preserve parentheses around `intrinsic` type
reference (#23156) (Boshen)
- e89f81d parser: Don't emit TS1477 for parenthesized instantiation
expression (#23147) (Boshen)
- 8a04149 parser: Reject module-referencing imports/exports in a
namespace body (#22829) (Boshen)

### ⚡ Performance

- 2783295 parser: Table-driven operator precedence lookup (#23346)
(Boshen)
- 231d5de parser: Single-match member expression dispatch (#23347)
(Boshen)
- e89729b codegen: Accept one-shot wrap closures (#23265) (camc314)
- a6c11fa parser: Force-inline read_non_decimal to fold per-digit number
dispatch (#23157) (Boshen)
- d74964c parser: Store class definite assertion offset (#23170)
(camc314)
- f0fda4d parser: Shrink-wrap cold diagnostic tails out of hot frames
(#23159) (Boshen)
- a082180 parser: Store definite assertion offset (#23167) (camc314)
- 534f9c6 oxc: Conditionally rebuild semantic in compiler pipeline
(#23153) (Boshen)
- b435c6a parser: Skip checkpoint for `infer T extends U` constraint in
disallow context (#23128) (Boshen)
- 7464dce parser: Peek instead of checkpoint/rewind for `export default`
modifier (#23124) (Boshen)
- 80a9a32 parser: Fast-path single-keyword TS declarations (#23083)
(Boshen)
- da1a6c6 diagnostics: Migrate to allocation-optimized oxc-miette
(#23094) (Boshen)
- b7b08ce parser: Peek once for the static modifier disambiguation
(#23079) (Boshen)
- e7e07a3 parser: Fold unary dispatch into a single match (#23076)
(Boshen)

### 📚 Documentation

- d241add semantic: Add `AGENTS.md` test guidance for agents (#23441)
(camc314)
- 026f1ae parser: Add `AGENTS.md` test guidance for agents (#23440)
(camc314)
- 09755ac transformer: Add `AGENTS.md` test guidance for agents (#23439)
(camc314)
- e6bdfd4 lexer: Correct reference link for `byte_handlers!` (#23313)
(Dunqing)
- 65b6d7a allocator: Fix memory leaks in `Arena` examples (#23257)
(overlookmotel)

Co-authored-by: Boshen <1430279+Boshen@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-parser Area - Parser

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant