From 23ced7860ed2d759622d328de174caec6589da67 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 22 Jul 2026 21:38:54 +0000 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=20Bolt:=20Hoist=20priority=20scopes?= =?UTF-8?q?=20allocations=20in=20SearchEngine?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hoisted `BURST_PRIORITY_SCOPES` and `IS_BURST_PRIORITY_TYPE_ID` to module-level constants to eliminate unnecessary allocations and garbage collection overhead during burst searches. Co-authored-by: AhmmedSamier <17784876+AhmmedSamier@users.noreply.github.com> --- .jules/bolt.md | 3 +++ language-server/src/core/search-engine.ts | 32 ++++++++++------------- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/.jules/bolt.md b/.jules/bolt.md index 85ac831..d4eb94f 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -103,3 +103,6 @@ ## 2024-05-28 - Accurate Fast Git Status Parsing **Learning:** Using `git status --porcelain -z` without the `-uall` flag causes it to omit untracked files inside untracked directories, breaking parity with `git ls-files --others`. Also, when handling 'R' and 'C' rename statuses in porcelain v1, you must evaluate both the X (index) and Y (working tree) characters of the status prefix, and then ensure the old path string is also captured and added. **Action:** Always use `-uall` with `git status --porcelain -z` when tracking modified/untracked files, and correctly verify `statusX` and `statusY` before extracting the old path segment. +## 2025-07-22 - [Hoist Allocations Out of Search Hot Loops] +**Learning:** Creating `new Set` and `new Uint8Array(256)` dynamically within `searchRemainingItems` during burst searches adds redundant GC overhead. +**Action:** Hoist constant priority scope sets and type ID mappings to module-level precomputed constants to eliminate allocation during hot loops. diff --git a/language-server/src/core/search-engine.ts b/language-server/src/core/search-engine.ts index a346ce3..cf59f71 100644 --- a/language-server/src/core/search-engine.ts +++ b/language-server/src/core/search-engine.ts @@ -98,6 +98,17 @@ const ID_TO_SCOPE = [ SearchScope.ENDPOINTS, ]; +const BURST_PRIORITY_SCOPES = [SearchScope.TYPES, SearchScope.SYMBOLS, SearchScope.ENDPOINTS, SearchScope.FILES]; +const IS_BURST_PRIORITY_TYPE_ID = new Uint8Array(256); +{ + const prioritySet = new Set(BURST_PRIORITY_SCOPES); + for (let i = 0; i < ID_TO_SCOPE.length; i++) { + if (prioritySet.has(ID_TO_SCOPE[i])) { + IS_BURST_PRIORITY_TYPE_ID[i] = 1; + } + } +} + // Precompute bitflags table for O(1) lookup for the Basic Multilingual Plane (BMP) // Maps char code (0-65535) to a bitmask. const CHAR_TO_BITFLAG = new Uint32Array(65536); @@ -2528,13 +2539,11 @@ export class SearchEngine implements ISearchProvider { results: SearchResult[], token?: CancellationToken, ): void { - const priorityScopes = [SearchScope.TYPES, SearchScope.SYMBOLS, SearchScope.ENDPOINTS, SearchScope.FILES]; - - this.searchPriorityScopes(priorityScopes, maxResults, processItem, results, token); + this.searchPriorityScopes(BURST_PRIORITY_SCOPES, maxResults, processItem, results, token); // Pass 5: Everything else (e.g. Properties, Variables, Commands) if (results.length < maxResults && !token?.isCancellationRequested) { - this.searchRemainingItems(priorityScopes, maxResults, processItem, results, token); + this.searchRemainingItems(maxResults, processItem, results, token); } } @@ -2558,30 +2567,17 @@ export class SearchEngine implements ISearchProvider { } private searchRemainingItems( - priorityScopes: SearchScope[], maxResults: number, processItem: (i: number) => void, results: SearchResult[], token?: CancellationToken, ): void { - // ⚡ Bolt: Fast Remaining Scopes Iteration Optimization - // Instead of allocating a Uint8Array of size N to track already processed items, - // we precompute which type IDs belong to priority scopes and iterate sequentially. - // This avoids the large allocation while preserving the exact iteration order of the fallback pass. - const prioritySet = new Set(priorityScopes); - const isPriorityTypeId = new Uint8Array(256); - for (let i = 0; i < ID_TO_SCOPE.length; i++) { - if (prioritySet.has(ID_TO_SCOPE[i])) { - isPriorityTypeId[i] = 1; - } - } - const itemsLength = this.items.length; const itemTypeIds = this.itemTypeIds; for (let i = 0; i < itemsLength; i++) { if (results.length >= maxResults || token?.isCancellationRequested) break; - if (isPriorityTypeId[itemTypeIds[i]] === 0) { + if (IS_BURST_PRIORITY_TYPE_ID[itemTypeIds[i]] === 0) { processItem(i); } }