Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@
## 2026-04-08 - [Fast Dense Integer Set Tracking]
**Learning:** When keeping track of seen integer IDs that are dense and bounded (e.g. from 0 to N), using `new Set<number>()` incurs heavy allocation and insertion overhead compared to a fixed-size byte array.
**Action:** Replace `Set<number>` with `new Uint8Array(maxIndex)` and use `array[id] = 1` to track presence, which is ~15x faster and avoids garbage collection pauses in hot paths. (Benchmark context: `N=100,000` IDs, `bun` version 1.2.14, Linux x86_64, Intel Xeon 2.30GHz, 4 cores, 8GB RAM, averaged over 100 iterations comparing `Set<number>` addition vs `new Uint8Array(maxIndex)` indexed assignment `array[id] = 1`).
## 2026-04-30 - [Fast Safe Array Push]
**Learning:** Using the array spread operator (`array.push(...items)`) to merge arrays is convenient but dangerous when the source array is potentially unbounded (e.g., parsing results, large file system traversals). Node.js passes each element as an individual argument to the underlying function, which can trigger a `RangeError: Maximum call stack size exceeded` if the array exceeds ~65,535 items in V8.
**Action:** Replace `array.push(...items)` with a manual `for` loop (`for (let i = 0; i < items.length; i++) array.push(items[i]);`) in paths dealing with dynamically generated or unconstrained array sizes. This safely handles arrays of any length with consistent memory overhead.
6 changes: 5 additions & 1 deletion language-server/src/core/ripgrep-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,11 @@ export class RipgrepService {
try {
const batchResults = await this.runRgBatch(baseArgs, batches[batchIndex], remaining, token);
if (batchResults.length > 0) {
allResults.push(...batchResults);
// ⚑ Bolt: Fast safe array push
// Prevents 'Maximum Call Stack Size Exceeded' for very large arrays.
for (let i = 0; i < batchResults.length; i++) {
allResults.push(batchResults[i]);
}
}
} catch {
// Ignore batch failure
Expand Down
19 changes: 16 additions & 3 deletions language-server/src/core/search-engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,11 @@ export class SearchEngine implements ISearchProvider {
}

// Append items
this.items.push(...items);
// ⚑ Bolt: Fast safe array push
// Prevents 'Maximum Call Stack Size Exceeded' for very large arrays.
for (let i = 0; i < items.length; i++) {
this.items.push(items[i]);
}

const CHUNK_SIZE = 500;
for (let i = 0; i < items.length; i += CHUNK_SIZE) {
Expand Down Expand Up @@ -392,7 +396,11 @@ export class SearchEngine implements ISearchProvider {
if (indices && indices.length > 0) {
if (!normalizedRemovedPaths.has(normalized)) {
normalizedRemovedPaths.add(normalized);
indicesToRemove.push(...indices);
// ⚑ Bolt: Fast safe array push
// Prevents 'Maximum Call Stack Size Exceeded' for very large arrays.
for (let i = 0; i < indices.length; i++) {
indicesToRemove.push(indices[i]);
}
}
}
}
Expand Down Expand Up @@ -974,7 +982,12 @@ export class SearchEngine implements ISearchProvider {
return;
}

allResults.push(...providerResults);
// ⚑ Bolt: Fast safe array push
// Prevents 'Maximum Call Stack Size Exceeded' for very large arrays.
for (let i = 0; i < providerResults.length; i++) {
allResults.push(providerResults[i]);
}

if (onResult) {
for (const result of providerResults) {
if (token?.isCancellationRequested) {
Expand Down
6 changes: 5 additions & 1 deletion language-server/src/core/workspace-indexer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,11 @@ export class WorkspaceIndexer {
if (this.cancellationToken.cancelled) throw new CancellationError();

await this.indexFiles((items) => {
fileItems.push(...items);
// ⚑ Bolt: Fast safe array push
// Prevents 'Maximum Call Stack Size Exceeded' for very large arrays.
for (let i = 0; i < items.length; i++) {
fileItems.push(items[i]);
}
this.fireItemsAdded(items);
});

Expand Down
12 changes: 10 additions & 2 deletions language-server/src/indexer-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,11 @@ export class LspIndexerEnvironment implements IndexerEnvironment {
nodir: true,
});

results.push(...files);
// ⚑ Bolt: Fast safe array push
// Prevents 'Maximum Call Stack Size Exceeded' for very large arrays.
for (let i = 0; i < files.length; i++) {
results.push(files[i]);
}
}
return results;
}
Expand All @@ -58,7 +62,11 @@ export class LspIndexerEnvironment implements IndexerEnvironment {
for (const folder of this.workspaceFolders) {
try {
const files = await this.execRgFiles(folder, excludes);
results.push(...files);
// ⚑ Bolt: Fast safe array push
// Prevents 'Maximum Call Stack Size Exceeded' for very large arrays.
for (let i = 0; i < files.length; i++) {
results.push(files[i]);
}
} catch {
return [];
}
Expand Down
Loading