perf(semantic): improve SoA with multi index vec#19138
perf(semantic): improve SoA with multi index vec#19138graphite-app[bot] merged 1 commit intomainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR refactors oxc_semantic’s scope tree storage to reduce memory overhead by replacing multiple scope-indexed IndexVecs with a single struct-of-arrays container backed by one allocation.
Changes:
- Add a
multi_index_vec!macro to generate a single-allocation SoA container with typed per-field accessors. - Replace
scope_parent_ids,scope_node_ids, andscope_flagswith a unifiedScopeTableinScoping. - Wire the new module into the crate (
mod multi_index_vec;) and update scope operations to useScopeTable.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| crates/oxc_semantic/src/scoping.rs | Replaces three IndexVec scope fields with a single ScopeTable and updates callers. |
| crates/oxc_semantic/src/multi_index_vec.rs | Introduces the multi_index_vec! macro + generated container implementation. |
| crates/oxc_semantic/src/lib.rs | Registers the new multi_index_vec module. |
Merging this PR will improve performance by 3.31%
Performance Changes
Comparing Footnotes
|
8fad1f4 to
12bcb67
Compare
There was a problem hiding this comment.
I haven't reviewed this in full. The entire implementation being a huge macro doesn't make doing that very easy.
From a quick look, there's parts which are totally unsound because bounds checks have been removed when they shouldn't be. But, on other side, there's lots of calls to Idx::from_usize which introduce bounds checks where there don't need to be any!
The latter probably explains why the perf impact isn't as much as we could hope for from this change.
So, in my view, I think the aim of this PR is good, but this isn't the best way of going about it.
Personally, I would favour an approach which defines most of the logic in static code (a trait), and making the macro much more minimal - just sugar over that trait to provide nicely-named methods. That would make it a lot easier to review the code properly and write tests etc.
Also, Aapo from Nova has also written a crate for SoA. I've not looked at it yet, but I'd imagine it's more robust.
|
Pushed an update with safety/perf fixes for Changes in this update:
Validation run: AI-assisted update: I used Codex to prepare this patch and validated the results before pushing. |
6c9337c to
d92ee77
Compare
Merge activity
|
## Summary - Introduce `multi_index_vec!` macro (modeled on Zig's `MultiArrayList`) that generates a struct-of-arrays container backed by a single allocation - Replace 3 separate `IndexVec` fields (`scope_parent_ids`, `scope_node_ids`, `scope_flags`) with a single `ScopeTable` - Single `len`/`cap` (u32) instead of 3× `ptr+len+cap` (72 bytes → 24 bytes of metadata) - Single capacity check on `push`, single `reserve` call for scopes - Follow-up: extend to symbol fields, reference SOA split, arena allocation Ref: oxc-project/backlog#11 🤖 Generated with [Claude Code](https://claude.com/claude-code)
9f18fa3 to
5b90d46
Compare
## Summary Follow-up to #19138 after merge. This PR fixes panic-safety in `multi_index_vec!` clone and keeps strict lint clean for `oxc_semantic` tests. ### Changes - Make macro-generated `Clone` panic-safe by cloning row-by-row through `push`. - Avoids setting `len` before all elements are initialized. - Prevents dropping uninitialized elements if a field `clone()` panics. - Add `#[expect(clippy::unused_self)]` to cfg-disabled integration helper methods to keep `cargo clippy -p oxc_semantic --lib --tests -D warnings` green. ## Validation - `cargo clippy -p oxc_semantic --lib --tests -- -D warnings` - `just lint` ## AI disclosure AI-assisted: I used Codex to draft and apply this patch, then ran lint checks and reviewed the result before opening this PR.
## Summary - Introduce `multi_index_vec!` macro (modeled on Zig's `MultiArrayList`) that generates a struct-of-arrays container backed by a single allocation - Replace 3 separate `IndexVec` fields (`scope_parent_ids`, `scope_node_ids`, `scope_flags`) with a single `ScopeTable` - Single `len`/`cap` (u32) instead of 3× `ptr+len+cap` (72 bytes → 24 bytes of metadata) - Single capacity check on `push`, single `reserve` call for scopes - Follow-up: extend to symbol fields, reference SOA split, arena allocation Ref: oxc-project/backlog#11 🤖 Generated with [Claude Code](https://claude.com/claude-code)
## Summary Follow-up to oxc-project#19138 after merge. This PR fixes panic-safety in `multi_index_vec!` clone and keeps strict lint clean for `oxc_semantic` tests. ### Changes - Make macro-generated `Clone` panic-safe by cloning row-by-row through `push`. - Avoids setting `len` before all elements are initialized. - Prevents dropping uninitialized elements if a field `clone()` panics. - Add `#[expect(clippy::unused_self)]` to cfg-disabled integration helper methods to keep `cargo clippy -p oxc_semantic --lib --tests -D warnings` green. ## Validation - `cargo clippy -p oxc_semantic --lib --tests -- -D warnings` - `just lint` ## AI disclosure AI-assisted: I used Codex to draft and apply this patch, then ran lint checks and reviewed the result before opening this PR.
### 🚀 Features - 429d876 semantic: Assign ast node ids during semantic build (#19263) (Boshen) - ebb80b3 ast: Add `node_id` field to all AST struct nodes (#18138) (Boshen) ### 🐛 Bug Fixes - bfb15a3 semantic: Make multi_index_vec clone panic-safe (#19299) (Boshen) - 41c50a5 transformer: Ignore invalid JSX pragma identifiers (#19296) (Boshen) - deed3d8 transformer: Remove unnecessary trailing expression in object rest spread assignment (#19259) (Boshen) - 5bdaacc transformer: Propagate source spans for sourcemap correctness (#19258) (Boshen) - 3e0e5ba isolated-declarations: Align readonly class array initializer diagnostics with tsc (#19218) (camc314) ### ⚡ Performance - c169c77 syntax: Optimize `is_identifier_name_patched` (#19386) (sapphi-red) - aa1e1a8 allocator: Inline BitSet accessors (#19331) (Boshen) - 5b90d46 semantic: Improve SoA with multi index vec (#19138) (Boshen) - 99ce2a6 isolated_declarations: Mark all diagnostic functions as `#[cold]` (#19279) (camc314) - dd0220f transformer: Remove TS-only nodes earlier in `enter_statements` (#19166) (Dunqing) - e5baf60 isolated-declarations: Replace hash collections with index-based Vec (#19221) (Dunqing) ### 📚 Documentation - 569aa61 rust: Add missing rustdocs and remove missing_docs lint attrs (#19306) (Boshen)
## Summary - Introduce `multi_index_vec!` macro (modeled on Zig's `MultiArrayList`) that generates a struct-of-arrays container backed by a single allocation - Replace 3 separate `IndexVec` fields (`scope_parent_ids`, `scope_node_ids`, `scope_flags`) with a single `ScopeTable` - Single `len`/`cap` (u32) instead of 3× `ptr+len+cap` (72 bytes → 24 bytes of metadata) - Single capacity check on `push`, single `reserve` call for scopes - Follow-up: extend to symbol fields, reference SOA split, arena allocation Ref: oxc-project/backlog#11 🤖 Generated with [Claude Code](https://claude.com/claude-code)
## Summary Follow-up to oxc-project#19138 after merge. This PR fixes panic-safety in `multi_index_vec!` clone and keeps strict lint clean for `oxc_semantic` tests. ### Changes - Make macro-generated `Clone` panic-safe by cloning row-by-row through `push`. - Avoids setting `len` before all elements are initialized. - Prevents dropping uninitialized elements if a field `clone()` panics. - Add `#[expect(clippy::unused_self)]` to cfg-disabled integration helper methods to keep `cargo clippy -p oxc_semantic --lib --tests -D warnings` green. ## Validation - `cargo clippy -p oxc_semantic --lib --tests -- -D warnings` - `just lint` ## AI disclosure AI-assisted: I used Codex to draft and apply this patch, then ran lint checks and reviewed the result before opening this PR.
### 🚀 Features - 429d876 semantic: Assign ast node ids during semantic build (oxc-project#19263) (Boshen) - ebb80b3 ast: Add `node_id` field to all AST struct nodes (oxc-project#18138) (Boshen) ### 🐛 Bug Fixes - bfb15a3 semantic: Make multi_index_vec clone panic-safe (oxc-project#19299) (Boshen) - 41c50a5 transformer: Ignore invalid JSX pragma identifiers (oxc-project#19296) (Boshen) - deed3d8 transformer: Remove unnecessary trailing expression in object rest spread assignment (oxc-project#19259) (Boshen) - 5bdaacc transformer: Propagate source spans for sourcemap correctness (oxc-project#19258) (Boshen) - 3e0e5ba isolated-declarations: Align readonly class array initializer diagnostics with tsc (oxc-project#19218) (camc314) ### ⚡ Performance - c169c77 syntax: Optimize `is_identifier_name_patched` (oxc-project#19386) (sapphi-red) - aa1e1a8 allocator: Inline BitSet accessors (oxc-project#19331) (Boshen) - 5b90d46 semantic: Improve SoA with multi index vec (oxc-project#19138) (Boshen) - 99ce2a6 isolated_declarations: Mark all diagnostic functions as `#[cold]` (oxc-project#19279) (camc314) - dd0220f transformer: Remove TS-only nodes earlier in `enter_statements` (oxc-project#19166) (Dunqing) - e5baf60 isolated-declarations: Replace hash collections with index-based Vec (oxc-project#19221) (Dunqing) ### 📚 Documentation - 569aa61 rust: Add missing rustdocs and remove missing_docs lint attrs (oxc-project#19306) (Boshen)
Summary
multi_index_vec!macro (modeled on Zig'sMultiArrayList) that generates a struct-of-arrays container backed by a single allocationIndexVecfields (scope_parent_ids,scope_node_ids,scope_flags) with a singleScopeTablelen/cap(u32) instead of 3×ptr+len+cap(72 bytes → 24 bytes of metadata)push, singlereservecall for scopesRef: oxc-project/backlog#11
🤖 Generated with Claude Code