Skip to content
Closed
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
17 changes: 16 additions & 1 deletion apps/oxlint/src-js/plugins/comments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ let activeCommentsWithLocCount = 0;
let deserializedCommentIndexes = EMPTY_UINT32_ARRAY;
let deserializedCommentsLen = 0;

// Minimum capacity (in `u32`s) of `deserializedCommentIndexes`, when not empty.
// 16 elements = 64 bytes = 1 cache line.
const DESERIALIZED_COMMENT_INDEXES_MIN_CAPACITY = 16;

// Empty comments array.
// Reused for all files which don't have any comments. Frozen to avoid rules mutating it.
const EMPTY_COMMENTS: CommentType[] = Object.freeze([]) as unknown as CommentType[];
Expand Down Expand Up @@ -227,7 +231,18 @@ export function initCommentsBuffer(): void {
cachedComments.push(new Comment());
} while (cachedComments.length < commentsLen);

deserializedCommentIndexes = new Uint32Array(commentsLen);
// Grow `deserializedCommentIndexes` if needed.
// `Uint32Array`s can't grow in place, so allocate a new one.
// First allocation uses minimum capacity. Subsequent growths double, to avoid frequent reallocations.
const indexesLen = deserializedCommentIndexes.length;
if (indexesLen < commentsLen) {
deserializedCommentIndexes = new Uint32Array(
Math.max(
commentsLen,
indexesLen === 0 ? DESERIALIZED_COMMENT_INDEXES_MIN_CAPACITY : indexesLen << 1,
),
);
}
}

// If file has a hashbang, eagerly deserialize the first comment, and set its type to `Shebang`.
Expand Down
19 changes: 18 additions & 1 deletion apps/oxlint/src-js/plugins/tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,12 @@ const REGEX_INDEXES_MIN_CAPACITY = 16;
let deserializedTokenIndexes = EMPTY_UINT32_ARRAY;
let deserializedTokensLen = 0;

// Minimum capacity (in `u32`s) of `deserializedTokenIndexes`, when not empty.
// 16 elements = 64 bytes = 1 cache line.
// Note that this default aims to be a reasonable minimum for number of *deserialized* tokens,
// not *total* number of tokens.
const DESERIALIZED_TOKEN_INDEXES_MIN_CAPACITY = 16;

// Reset `#loc` field on a `Token` class instance
let resetLoc: (token: Token) => void;

Expand Down Expand Up @@ -318,7 +324,18 @@ export function initTokensBuffer(): void {
cachedTokens.push(new Token());
} while (cachedTokens.length < tokensLen);

deserializedTokenIndexes = new Uint32Array(tokensLen);
// Grow `deserializedTokenIndexes` if needed.
// `Uint32Array`s can't grow in place, so allocate a new one.
// First allocation uses minimum capacity. Subsequent growths double, to avoid frequent reallocations.
const indexesLen = deserializedTokenIndexes.length;
if (indexesLen < tokensLen) {
deserializedTokenIndexes = new Uint32Array(
Math.max(
tokensLen,
indexesLen === 0 ? DESERIALIZED_TOKEN_INDEXES_MIN_CAPACITY : indexesLen << 1,
),
);
}
}

// Check buffer data has valid ranges and ascending order
Expand Down
13 changes: 10 additions & 3 deletions apps/oxlint/src-js/plugins/tokens_and_comments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ export let tokensAndCommentsLen = 0;
// `tokensAndCommentsUint32` is a view over this buffer's prefix.
let tokensAndCommentsBackingUint32 = EMPTY_UINT32_ARRAY;

// Minimum capacity (in `u32`s) of `tokensAndCommentsBackingUint32`, when not empty.
// 256 elements = 1 KiB.
const MERGED_BACKING_MIN_CAPACITY = 256;

/**
* Initialize tokens-and-comments buffer.
*
Expand All @@ -117,14 +121,17 @@ export function initTokensAndCommentsBuffer(): void {

tokensAndCommentsLen = tokensLen + commentsLen;

// Reuse backing buffer across files. Grow (doubled) if needed, never shrink.
// Reuse backing buffer across files. Grow if needed, never shrink.
// After warm-up over first few files, the buffer will be large enough to hold all tokens and comments
// for all files, so we avoid allocating a large buffer each time.
// +1 entry for sentinel (see below).
// `Uint32Array`s can't grow in place, so allocate a new one.
// First allocation uses minimum capacity. Subsequent growths double, to avoid frequent reallocations.
const requiredLen32 = (tokensAndCommentsLen + 1) << MERGED_SIZE32_SHIFT;
if (tokensAndCommentsBackingUint32.length < requiredLen32) {
const backingLen = tokensAndCommentsBackingUint32.length;
if (backingLen < requiredLen32) {
tokensAndCommentsBackingUint32 = new Uint32Array(
Math.max(requiredLen32, tokensAndCommentsBackingUint32.length << 1),
Math.max(requiredLen32, backingLen === 0 ? MERGED_BACKING_MIN_CAPACITY : backingLen << 1),
);
}

Expand Down
Loading