Skip to content
Merged
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
36 changes: 19 additions & 17 deletions apps/oxlint/src-js/plugins/visitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,10 +215,10 @@ let hasActiveVisitors = false;
// `compiledVisitor` may contain many `{ enter, exit }` objects.
// Use this cache to reuse those objects across all visitor compilations.
//
// `enterExitObjectCacheNextIndex` is the index of first object in cache which is currently unused.
// It may point to the end of the cache array.
// `activeNonLeafVisitorsCount` is the number of populated non-leaf visitors in `compiledVisitor`,
// and therefore the number of `EnterExit` objects currently in use.
const enterExitObjectCache: EnterExit[] = [];
let enterExitObjectCacheNextIndex = 0;
let activeNonLeafVisitorsCount = 0;

// `VisitProp` object cache.
//
Expand Down Expand Up @@ -417,21 +417,23 @@ export function finalizeCompiledVisitor(): VisitorState {
compiledVisitor[typeId] = mergeVisitFns(compilingLeafVisitor[typeId]!);
}

// Populate `enterExitObjectCache` with enough entries for all non-leaf visitors.
// After warming up over first few files, the cache will be large enough to service all files,
// and this loop will be skipped. This avoids the main loop below from having to branch repeatedly
// on whether there are enough `EnterExit` objects in cache, and to create one if not.
activeNonLeafVisitorsCount = activeNonLeafVisitorTypeIds.length;
while (enterExitObjectCache.length < activeNonLeafVisitorsCount) {
enterExitObjectCache.push({ enter: null, exit: null });
}

// Merge visitors for non-leaf nodes
for (let i = activeNonLeafVisitorTypeIds.length - 1; i >= 0; i--) {
for (let i = 0; i < activeNonLeafVisitorsCount; i++) {
const typeId = activeNonLeafVisitorTypeIds[i]!;
const entry = compilingNonLeafVisitor[typeId - LEAF_NODE_TYPES_COUNT]!;

// Get or create enter-exit object.
// Use an existing object from cache if available, otherwise create a new one.
let enterExit: EnterExit;
if (enterExitObjectCacheNextIndex < enterExitObjectCache.length) {
enterExit = enterExitObjectCache[enterExitObjectCacheNextIndex];
} else {
enterExit = { enter: null, exit: null };
enterExitObjectCache.push(enterExit);
}
enterExitObjectCacheNextIndex++;
// Use enter-exit object from cache. Loop above ensures cache is filled with enough objects.
const enterExit = enterExitObjectCache[i];
debugAssertIsNonNull(enterExit, "`enterExit` should not be null");

// Merge enter and exit visitors
const enterArr = entry.enter;
Expand Down Expand Up @@ -487,13 +489,13 @@ export function resetCompiledVisitor(): void {
// Reset `compiledVisitor` array
compiledVisitor.fill(null);

// Reset enter+exit objects
for (let i = 0; i < enterExitObjectCacheNextIndex; i++) {
// Reset `EnterExit` objects
for (let i = 0; i < activeNonLeafVisitorsCount; i++) {
const enterExit = enterExitObjectCache[i];
enterExit.enter = null;
enterExit.exit = null;
}
enterExitObjectCacheNextIndex = 0;
activeNonLeafVisitorsCount = 0;
}

// Array used by `mergeVisitFns` and `mergeCfgVisitFns` to store visit functions extracted from an array of `VisitProp`s.
Expand Down
Loading