perf(alias): scan a packed first-byte array instead of striding over alias entries#1260
Merged
Conversation
…alias entries The alias fast-reject loop touched every ~100-byte CompiledAliasEntry per file candidate (load_browser_field_or_alias) and per require (load_alias), even though the cached first byte rejects nearly all entries. Profiling the resolver benchmark workloads attributed 12.5% (single-thread) and 31% (resolve from symlinks) of CPU to this pointer-chasing scan. Turn CompiledAlias into a struct that packs each entry's first byte into a contiguous side array plus a 256-bit presence mask: - may_match: O(1) exit when no entry's first byte is compatible. - matching: scans the byte array and only dereferences candidate entries. - any_key_matches: jumps straight to candidate indices with memchr on the per-candidate path. Criterion (macOS arm64): - resolver_memory/single-thread: 26.3 -> 21.9 us (-17%) - resolver_memory/resolve from symlinks: 5.0 -> 3.5 ms (-30%) - resolver_memory/multi-thread: 23.4 -> 20.6 us (-12%) - resolver_real/single-thread: 27.0 -> 23.5 us (-13%) - resolver_real/resolve from symlinks: 10.5 -> 7.5 ms (-29%) - resolver_real/multi-thread: 23.4 -> 21.0 us (-10%) - tsconfig/package_json groups: unchanged
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1260 +/- ##
==========================================
- Coverage 93.87% 93.85% -0.02%
==========================================
Files 21 21
Lines 4277 4313 +36
==========================================
+ Hits 4015 4048 +33
- Misses 262 265 +3 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Merging this PR will improve performance by 12.67%
Performance Changes
Tip Curious why this is faster? Comment Comparing Footnotes
|
Boshen
pushed a commit
that referenced
this pull request
Jul 2, 2026
## 🤖 New release * `oxc_resolver`: 11.22.0 -> 11.23.0 * `oxc_resolver_napi`: 11.22.0 -> 11.23.0 <details><summary><i><b>Changelog</b></i></summary><p> ## `oxc_resolver` <blockquote> ## [11.23.0](v11.22.0...v11.23.0) - 2026-07-02 ### <!-- 0 -->🚀 Features - *(tsconfig)* expose outDir, declarationDir, resolveJsonModule, checkJs ([#1257](#1257)) (by @Boshen) ### <!-- 1 -->🐛 Bug Fixes - *(exports)* propagate the last error in array target resolution ([#1267](#1267)) (by @Boshen) ### <!-- 2 -->🚜 Refactor - deduplicate cross-file helpers, drop stale lint allows ([#1269](#1269)) (by @Boshen) - *(dts)* deduplicate package entry selection and remove dead code ([#1266](#1266)) (by @Boshen) - *(tsconfig)* skip TsConfig deep clone for non-root configs ([#1265](#1265)) (by @Boshen) - *(alias)* compile fallback aliases once at construction ([#1264](#1264)) (by @Boshen) ### <!-- 4 -->⚡ Performance - *(alias)* scan a packed first-byte array instead of striding over alias entries ([#1260](#1260)) (by @Boshen) ### Contributors * @Boshen </blockquote> </p></details> --- This PR was generated with [release-plz](https://github.com/release-plz/release-plz/). Co-authored-by: oxc-guard[bot] <276638029+oxc-guard[bot]@users.noreply.github.com>
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.
What
Turn
CompiledAliasfrom aVec<CompiledAliasEntry>type alias into a struct that packs each entry's cached first byte into a contiguous side array plus a 256-bit presence mask:may_match— O(1) "no entry can match" exit via the mask, without touching any entry.matching— scans the packed byte array and only dereferences entries whose first byte is compatible.any_key_matches— the per-file-candidate check inload_browser_field_or_aliasjumps straight to candidate indices withmemchrwhen no always-evaluated entry exists.Matching semantics are unchanged: candidates are still confirmed with
key_matchesin declaration order (first match wins), and empty-key/empty-wildcard-prefix entries remain always-evaluated (stored as0in the byte array; a key genuinely starting with NUL also maps to0and just loses its fast-reject).Why
#1142 cached the first byte on each entry, but the reject loop still strides over every ~100-byte
CompiledAliasEntry— once per file candidate inload_browser_field_or_aliasand once per require inload_alias. With the benchmark's 23-entry alias list that is ~2.5 KiB of scattered loads per scan.samply profiles of the bench workloads attribute 12.5% of CPU on
resolver_memory/single-threadand ~31% onresolver_memory/resolve from symlinksto this scan (key_matchesself time plus theany()loop atlib.rs:935). After the change,key_matchesdrops out of the top self-time entries entirely in both profiles.Measured impact (criterion, macOS arm64)
tsconfig_paths_aliases_memory,package_json_deserialization, andresolver_memory/find tsconfigare unchanged. With an empty alias list the new fields are an empty box + 32 zero bytes andmay_matchexits on the first mask word.