mirror of
https://github.com/zebrajr/node.git
synced 2025-12-06 00:20:08 +01:00
perf_hooks: fix stack overflow error
PR-URL: https://github.com/nodejs/node/pull/60084 Fixes: https://github.com/nodejs/node/issues/54768 Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
This commit is contained in:
parent
985e2fb383
commit
822a8c3244
|
|
@ -270,6 +270,8 @@ const {
|
|||
Array: ArrayConstructor,
|
||||
ArrayPrototypeForEach,
|
||||
ArrayPrototypeMap,
|
||||
ArrayPrototypePushApply,
|
||||
ArrayPrototypeSlice,
|
||||
FinalizationRegistry,
|
||||
FunctionPrototypeCall,
|
||||
Map,
|
||||
|
|
@ -720,5 +722,26 @@ primordials.SafeStringPrototypeSearch = (str, regexp) => {
|
|||
return match ? match.index : -1;
|
||||
};
|
||||
|
||||
/**
|
||||
* Variadic functions with lots of arguments will cause stack overflow errors.
|
||||
* Use this function when `items` can be arbitrarily large, this function splits
|
||||
* it into chunks of size 2**16 making stack overflow less likely.
|
||||
* @param {Array<unknown>} arr
|
||||
* @param {Parameters<typeof Array.prototype.push>} items
|
||||
* @returns {ReturnType<typeof Array.prototype.push>}
|
||||
*/
|
||||
primordials.SafeArrayPrototypePushApply = (arr, items) => {
|
||||
let end = 0x10000;
|
||||
if (end < items.length) {
|
||||
let start = 0;
|
||||
do {
|
||||
ArrayPrototypePushApply(arr, ArrayPrototypeSlice(items, start, start = end));
|
||||
end += 0x10000;
|
||||
} while (end < items.length);
|
||||
items = ArrayPrototypeSlice(items, start);
|
||||
}
|
||||
return ArrayPrototypePushApply(arr, items);
|
||||
};
|
||||
|
||||
ObjectSetPrototypeOf(primordials, null);
|
||||
ObjectFreeze(primordials);
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ const {
|
|||
ArrayPrototypeFilter,
|
||||
ArrayPrototypeIncludes,
|
||||
ArrayPrototypePush,
|
||||
ArrayPrototypePushApply,
|
||||
ArrayPrototypeSlice,
|
||||
ArrayPrototypeSort,
|
||||
Error,
|
||||
|
|
@ -14,6 +13,7 @@ const {
|
|||
MathMin,
|
||||
ObjectDefineProperties,
|
||||
ObjectFreeze,
|
||||
SafeArrayPrototypePushApply,
|
||||
SafeMap,
|
||||
SafeSet,
|
||||
Symbol,
|
||||
|
|
@ -300,7 +300,7 @@ class PerformanceObserver {
|
|||
maybeIncrementObserverCount(type);
|
||||
if (buffered) {
|
||||
const entries = filterBufferMapByNameAndType(undefined, type);
|
||||
ArrayPrototypePushApply(this.#buffer, entries);
|
||||
SafeArrayPrototypePushApply(this.#buffer, entries);
|
||||
kPending.add(this);
|
||||
if (kPending.size)
|
||||
queuePending();
|
||||
|
|
@ -507,9 +507,9 @@ function filterBufferMapByNameAndType(name, type) {
|
|||
return [];
|
||||
} else {
|
||||
bufferList = [];
|
||||
ArrayPrototypePushApply(bufferList, markEntryBuffer);
|
||||
ArrayPrototypePushApply(bufferList, measureEntryBuffer);
|
||||
ArrayPrototypePushApply(bufferList, resourceTimingBuffer);
|
||||
SafeArrayPrototypePushApply(bufferList, markEntryBuffer);
|
||||
SafeArrayPrototypePushApply(bufferList, measureEntryBuffer);
|
||||
SafeArrayPrototypePushApply(bufferList, resourceTimingBuffer);
|
||||
}
|
||||
if (name !== undefined) {
|
||||
bufferList = ArrayPrototypeFilter(bufferList, (buffer) => buffer.name === name);
|
||||
|
|
|
|||
9
test/parallel/test-performance-many-marks.js
Normal file
9
test/parallel/test-performance-many-marks.js
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
'use strict';
|
||||
require('../common');
|
||||
|
||||
for (let i = 0; i < 1e6; i++) {
|
||||
performance.mark(`mark-${i}`);
|
||||
}
|
||||
|
||||
performance.getEntriesByName('mark-0');
|
||||
performance.clearMarks();
|
||||
|
|
@ -10,6 +10,7 @@ const {
|
|||
ArrayPrototypeUnshiftApply,
|
||||
MathMaxApply,
|
||||
MathMinApply,
|
||||
SafeArrayPrototypePushApply,
|
||||
StringPrototypeConcatApply,
|
||||
TypedArrayOfApply,
|
||||
} = require('internal/test/binding').primordials;
|
||||
|
|
@ -43,6 +44,26 @@ const {
|
|||
assert.deepStrictEqual(arr1, expected);
|
||||
}
|
||||
|
||||
{
|
||||
const arr1 = [1, 2, 3];
|
||||
const arr2 = [4, 5, 6];
|
||||
|
||||
const expected = [...arr1, ...arr2];
|
||||
|
||||
assert.strictEqual(SafeArrayPrototypePushApply(arr1, arr2), expected.length);
|
||||
assert.deepStrictEqual(arr1, expected);
|
||||
}
|
||||
|
||||
{
|
||||
const arr1 = [1, 2, 3];
|
||||
const arr2 = Array.from({ length: 1e6 }, (_, i) => i);
|
||||
|
||||
const expected = [...arr1, ...arr2];
|
||||
|
||||
assert.strictEqual(SafeArrayPrototypePushApply(arr1, arr2), expected.length);
|
||||
assert.deepStrictEqual(arr1, expected);
|
||||
}
|
||||
|
||||
{
|
||||
const arr1 = [1, 2, 3];
|
||||
const arr2 = [4, 5, 6];
|
||||
|
|
|
|||
1
typings/primordials.d.ts
vendored
1
typings/primordials.d.ts
vendored
|
|
@ -374,6 +374,7 @@ declare namespace primordials {
|
|||
export const RegExpPrototypeGetUnicode: UncurryGetter<typeof RegExp.prototype, "unicode">;
|
||||
export const RegExpPrototypeSymbolReplace: UncurryMethod<typeof RegExp.prototype, typeof Symbol.replace>
|
||||
export const RegExpPrototypeSymbolSplit: UncurryMethod<typeof RegExp.prototype, typeof Symbol.split>
|
||||
export const SafeArrayPrototypePushApply: typeof ArrayPrototypePushApply;
|
||||
export import Set = globalThis.Set;
|
||||
export const SetLength: typeof Set.length
|
||||
export const SetName: typeof Set.name
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user