Skip to content

Commit a1a5c04

Browse files
BridgeARTrott
authored andcommitted
lib: improve error creation performance
In case of an error where we only care about a cleaned up stack trace it is cheaper to reset the stack trace limit for the error that is created. That way the stack frames do not have to be computed twice. PR-URL: #24747 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>
1 parent c3dd0d0 commit a1a5c04

File tree

4 files changed

+51
-6
lines changed

4 files changed

+51
-6
lines changed

lib/_http_outgoing.js

+12
Original file line numberDiff line numberDiff line change
@@ -446,20 +446,32 @@ function matchHeader(self, state, field, value) {
446446

447447
function validateHeaderName(name) {
448448
if (typeof name !== 'string' || !name || !checkIsHttpToken(name)) {
449+
// Reducing the limit improves the performance significantly. We do not
450+
// lose the stack frames due to the `captureStackTrace()` function that is
451+
// called later.
452+
const tmpLimit = Error.stackTraceLimit;
453+
Error.stackTraceLimit = 0;
449454
const err = new ERR_INVALID_HTTP_TOKEN('Header name', name);
455+
Error.stackTraceLimit = tmpLimit;
450456
Error.captureStackTrace(err, validateHeaderName);
451457
throw err;
452458
}
453459
}
454460

455461
function validateHeaderValue(name, value) {
456462
let err;
463+
// Reducing the limit improves the performance significantly. We do not loose
464+
// the stack frames due to the `captureStackTrace()` function that is called
465+
// later.
466+
const tmpLimit = Error.stackTraceLimit;
467+
Error.stackTraceLimit = 0;
457468
if (value === undefined) {
458469
err = new ERR_HTTP_INVALID_HEADER_VALUE(value, name);
459470
} else if (checkInvalidHeaderChar(value)) {
460471
debug('Header "%s" contains invalid characters', name);
461472
err = new ERR_INVALID_CHAR('header content', name);
462473
}
474+
Error.stackTraceLimit = tmpLimit;
463475
if (err !== undefined) {
464476
Error.captureStackTrace(err, validateHeaderValue);
465477
throw err;

lib/internal/errors.js

+24
Original file line numberDiff line numberDiff line change
@@ -261,10 +261,16 @@ function uvException(ctx) {
261261
message += ` -> '${dest}'`;
262262
}
263263

264+
// Reducing the limit improves the performance significantly. We do not loose
265+
// the stack frames due to the `captureStackTrace()` function that is called
266+
// later.
267+
const tmpLimit = Error.stackTraceLimit;
268+
Error.stackTraceLimit = 0;
264269
// Pass the message to the constructor instead of setting it on the object
265270
// to make sure it is the same as the one created in C++
266271
// eslint-disable-next-line no-restricted-syntax
267272
const err = new Error(message);
273+
Error.stackTraceLimit = tmpLimit;
268274

269275
for (const prop of Object.keys(ctx)) {
270276
if (prop === 'message' || prop === 'path' || prop === 'dest') {
@@ -307,8 +313,14 @@ function uvExceptionWithHostPort(err, syscall, address, port) {
307313
details = ` ${address}`;
308314
}
309315

316+
// Reducing the limit improves the performance significantly. We do not loose
317+
// the stack frames due to the `captureStackTrace()` function that is called
318+
// later.
319+
const tmpLimit = Error.stackTraceLimit;
320+
Error.stackTraceLimit = 0;
310321
// eslint-disable-next-line no-restricted-syntax
311322
const ex = new Error(`${message}${details}`);
323+
Error.stackTraceLimit = tmpLimit;
312324
ex.code = code;
313325
ex.errno = code;
314326
ex.syscall = syscall;
@@ -377,9 +389,15 @@ function exceptionWithHostPort(err, syscall, address, port, additional) {
377389
details += ` - Local (${additional})`;
378390
}
379391

392+
// Reducing the limit improves the performance significantly. We do not loose
393+
// the stack frames due to the `captureStackTrace()` function that is called
394+
// later.
395+
const tmpLimit = Error.stackTraceLimit;
396+
Error.stackTraceLimit = 0;
380397
// eslint-disable-next-line no-restricted-syntax
381398
const ex = new Error(`${syscall} ${code}${details}`);
382399
// TODO(joyeecheung): errno is supposed to err, like in uvException
400+
Error.stackTraceLimit = tmpLimit;
383401
ex.code = ex.errno = code;
384402
ex.syscall = syscall;
385403
ex.address = address;
@@ -410,9 +428,15 @@ function dnsException(code, syscall, hostname) {
410428
}
411429
}
412430
const message = `${syscall} ${code}${hostname ? ` ${hostname}` : ''}`;
431+
// Reducing the limit improves the performance significantly. We do not loose
432+
// the stack frames due to the `captureStackTrace()` function that is called
433+
// later.
434+
const tmpLimit = Error.stackTraceLimit;
435+
Error.stackTraceLimit = 0;
413436
// eslint-disable-next-line no-restricted-syntax
414437
const ex = new Error(message);
415438
// TODO(joyeecheung): errno is supposed to be a number / err, like in
439+
Error.stackTraceLimit = tmpLimit;
416440
// uvException.
417441
ex.errno = code;
418442
ex.code = code;

lib/internal/fs/utils.js

+10-6
Original file line numberDiff line numberDiff line change
@@ -190,23 +190,27 @@ function nullCheck(path, propName, throwError = true) {
190190
const pathIsUint8Array = isUint8Array(path);
191191

192192
// We can only perform meaningful checks on strings and Uint8Arrays.
193-
if (!pathIsString && !pathIsUint8Array) {
193+
if (!pathIsString && !pathIsUint8Array ||
194+
pathIsString && path.indexOf('\u0000') === -1 ||
195+
pathIsUint8Array && path.indexOf(0) === -1) {
194196
return;
195197
}
196198

197-
if (pathIsString && path.indexOf('\u0000') === -1) {
198-
return;
199-
} else if (pathIsUint8Array && path.indexOf(0) === -1) {
200-
return;
199+
// Reducing the limit improves the performance significantly. We do not loose
200+
// the stack frames due to the `captureStackTrace()` function that is called
201+
// later.
202+
const tmpLimit = Error.stackTraceLimit;
203+
if (throwError) {
204+
Error.stackTraceLimit = 0;
201205
}
202-
203206
const err = new ERR_INVALID_ARG_VALUE(
204207
propName,
205208
path,
206209
'must be a string or Uint8Array without null bytes'
207210
);
208211

209212
if (throwError) {
213+
Error.stackTraceLimit = tmpLimit;
210214
Error.captureStackTrace(err, nullCheck);
211215
throw err;
212216
}

lib/internal/process/warning.js

+5
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,13 @@ function setupProcessWarnings() {
127127
throw new ERR_INVALID_ARG_TYPE('code', 'string', code);
128128
}
129129
if (typeof warning === 'string') {
130+
// Improve error creation performance by skipping the error frames.
131+
// They are added in the `captureStackTrace()` function below.
132+
const tmpStackLimit = Error.stackTraceLimit;
133+
Error.stackTraceLimit = 0;
130134
// eslint-disable-next-line no-restricted-syntax
131135
warning = new Error(warning);
136+
Error.stackTraceLimit = tmpStackLimit;
132137
warning.name = String(type || 'Warning');
133138
if (code !== undefined) warning.code = code;
134139
if (detail !== undefined) warning.detail = detail;

0 commit comments

Comments
 (0)