Skip to content

perf(semantic): early-exit check_object_expression for objects with <2 properties#22668

Merged
graphite-app[bot] merged 1 commit into
mainfrom
claude/perf-semantic-checker-fast-paths
May 22, 2026
Merged

perf(semantic): early-exit check_object_expression for objects with <2 properties#22668
graphite-app[bot] merged 1 commit into
mainfrom
claude/perf-semantic-checker-fast-paths

Conversation

@Dunqing

@Dunqing Dunqing commented May 22, 2026

Copy link
Copy Markdown
Member

Summary

A duplicate __proto__ entry needs at least two property definitions — empty and single-property objects can't violate the rule. JSX/TSX call sites compile to enormous numbers of single-property object literals (<Foo prop={x}>{prop: x}), so bailing before the loop setup and prop_name() call skips per-call overhead for the vast majority of ObjectExpression nodes seen during semantic checking.

Context

The original version of this PR also reordered check_identifier, check_identifier_reference, and check_binding_identifier to defer expensive scope/symbol-flag loads behind a cheap name-match. While I was working on it, @camc314 shipped equivalent changes as three separate PRs (#22652, #22653, #22656). After rebasing onto main, only the check_object_expression early-exit remains as new work; the rest of the checker hot path is already covered.

This single change shows no measurable delta in cargo bench --bench semantic against current main (all five files within criterion's noise threshold) — JSX/TSX-heavy benches have already been driven down by the related PRs, and the property loop on a 1-property object is a fast path already. Pushing for completeness; happy to close if the maintainers would prefer to skip a change with no benchmark signal.

Verified by cargo test -p oxc_semantic --features cfg (72 tests) and cargo clippy -p oxc_semantic --all-features.

AI assisted.

@github-actions github-actions Bot added the A-semantic Area - Semantic label May 22, 2026
@codspeed-hq

codspeed-hq Bot commented May 22, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 57 untouched benchmarks
⏩ 3 skipped benchmarks1


Comparing claude/perf-semantic-checker-fast-paths (6dad508) with main (d721ad9)

Open in CodSpeed

Footnotes

  1. 3 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.

@Dunqing Dunqing force-pushed the claude/perf-semantic-checker-fast-paths branch 2 times, most recently from 1480c6b to 6dad508 Compare May 22, 2026 05:20
@Dunqing Dunqing changed the title perf(semantic): early-return fast paths in per-identifier checker functions perf(semantic): early-exit check_object_expression for objects with <2 properties May 22, 2026
@Dunqing Dunqing marked this pull request as ready for review May 22, 2026 08:03
@Dunqing Dunqing requested a review from camc314 May 22, 2026 08:03
@camc314 camc314 added the 0-merge Merge with Graphite Merge Queue label May 22, 2026

camc314 commented May 22, 2026

Copy link
Copy Markdown
Contributor

Merge activity

… <2 properties (#22668)

## Summary

A duplicate `__proto__` entry needs at least two property definitions — empty and single-property objects can't violate the rule. JSX/TSX call sites compile to enormous numbers of single-property object literals (`<Foo prop={x}>` → `{prop: x}`), so bailing before the loop setup and `prop_name()` call skips per-call overhead for the vast majority of `ObjectExpression` nodes seen during semantic checking.

## Context

The original version of this PR also reordered `check_identifier`, `check_identifier_reference`, and `check_binding_identifier` to defer expensive scope/symbol-flag loads behind a cheap name-match. While I was working on it, @camc314 shipped equivalent changes as three separate PRs (#22652, #22653, #22656). After rebasing onto `main`, only the `check_object_expression` early-exit remains as new work; the rest of the checker hot path is already covered.

This single change shows no measurable delta in `cargo bench --bench semantic` against current `main` (all five files within criterion's noise threshold) — JSX/TSX-heavy benches have already been driven down by the related PRs, and the property loop on a 1-property object is a fast path already. Pushing for completeness; happy to close if the maintainers would prefer to skip a change with no benchmark signal.

Verified by `cargo test -p oxc_semantic --features cfg` (72 tests) and `cargo clippy -p oxc_semantic --all-features`.

AI assisted.
@graphite-app graphite-app Bot force-pushed the claude/perf-semantic-checker-fast-paths branch from 6dad508 to 0d9553d Compare May 22, 2026 09:48
@graphite-app graphite-app Bot merged commit 0d9553d into main May 22, 2026
29 checks passed
@graphite-app graphite-app Bot removed the 0-merge Merge with Graphite Merge Queue label May 22, 2026
@graphite-app graphite-app Bot deleted the claude/perf-semantic-checker-fast-paths branch May 22, 2026 09:53
Dunqing added a commit that referenced this pull request May 26, 2026
### 🚀 Features

- e857b0c napi/minify: Expose legalComments option and result (#20370)
(Boshen)
- 661132d parser: More friendly error messages for rest assignment
target and rest binding element (#22719) (sapphi-red)
- ee659b6 transformer/legacy-decorator: Add `strictNullChecks` option
for nullable-union design:type (#22266) (Kyle Cannon)

### 🐛 Bug Fixes

- e1d064e transformer/class-properties: Reparent lifted private method
helpers (#22716) (Cameron)
- 4ac0fca minifier: Preserve `0 && (module.exports = { ... })`
cjs-module-lexer hint (#22729) (Dunqing)
- 40ff611 minifier: Mark peephole loop changed when dropping
dead-after-throw statement (#22722) (Dunqing)
- 2f7b210 codegen: Emit pife-arrow/function leading comments inside the
wrap (#22720) (Dunqing)
- e184f74 parser: Improve invalid `import` property access diagnostic
(#22693) (camc314)
- 7baed9c transformer/private-method: Clear inherited strict flags
(#22508) (camc314)
- a9ad27e parser: Keep annotation comments leading without preceding
newline (#22711) (Dunqing)
- 9ea4d64 minifier: Re-evaluate pure/no-side-effects flags after
peephole inlining (#22595) (Dunqing)
- 07afbb6 minifier: Drop empty-body IIFE wrapper when called with
arguments (#22589) (Dunqing)
- fa7c463 semantic: Correct TS enum member symbol spans (#22689)
(camc314)
- 26b9396 semantic: Resolve parameter decorators outside parameter scope
(#22623) (camc314)
- b284045 parser: Switch to module goal eagerly on `export` (#22684)
(Boshen)
- dfa931d semantic: Propagate unresolved auto-increment enum value
instead of defaulting to 0 (#22646) (Dunqing)
- 69a6ba6 transformer/legacy-decorator: Emit Array for ReadonlyArray<T>
in decorator metadata (#22265) (Kyle Cannon)
- e421ef0 transformer/legacy-decorator: Return runtime binding for
design:type (#22640) (Dunqing)
- d61e1d7 codegen: Preserve verbatim text of pure/no-side-effects
comments (#22525) (Dunqing)
- 702b14e minifier: Preserve IIFE structure in DCE-only mode (#22547)
(Dunqing)
- 917da24 parser: Apply PURE comment through member-access chains
(#22566) (Dunqing)
- a069b1c codegen: Preserve quotes for cjs-module-lexer equality strings
(#22551) (Dunqing)

### ⚡ Performance

- 2f623b0 semantic: Skip unresolved checks for re-exports (#22660)
(camc314)
- 0d9553d semantic: Early-exit `check_object_expression` for objects
with <2 properties (#22668) (Dunqing)
- d721ad9 semantic: Use direct grandparent lookup for TS type parameters
(#22658) (camc314)
- 0aff288 semantic: Reorder numeric literal strict mode checks (#22657)
(camc314)
- 4d5ddb1 semantic: Reorder binding identifier checks (#22656) (camc314)
- e32acd8 semantic: Reorder identifier ambient binding check (#22653)
(camc314)
- 09fe178 semantic: Reorder ident reference strict mode check (#22652)
(camc314)
- 4b6add2 semantic: Avoid duplicate ident clone for bindings (#22663)
(camc314)
- 82f9662 parser: Check identifier kind before context flag (#22662)
(camc314)
- d7cd951 parser: Fast path identifier parsing and inline operator
helpers (#22650) (Boshen)
- 7b84314 semantic: Use direct byte access for numeric leading-zero
check (#22642) (camc314)
- 0345a31 semantic: Pre-size class elements hash map (#22618) (camc314)
- 04d3065 minifier: Drop per-call buffers in try_fold_concat (#22596)
(Dunqing)
- 4f289f1 semantic: Resolve_references_for_current_scope without a temp
Vec (#22599) (Dunqing)
- e862c15 semantic: Avoid heap alloc for var hoist scope ids (#22603)
(Dunqing)
- 8ff8674 semantic: Early return if `excess` is `0` in
`Stats::increase_by` (#22616) (camc314)
- 7a4120e semantic: Pre-reserve unresolved_references using
Stats::references (#22580) (Dunqing)

Co-authored-by: Dunqing <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-semantic Area - Semantic

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants