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: https://github.com/nodejs/node/pull/24747 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>
This commit is contained in:
parent
c3dd0d001a
commit
a1a5c0419e
@ -446,7 +446,13 @@ function matchHeader(self, state, field, value) {
|
|||||||
|
|
||||||
function validateHeaderName(name) {
|
function validateHeaderName(name) {
|
||||||
if (typeof name !== 'string' || !name || !checkIsHttpToken(name)) {
|
if (typeof name !== 'string' || !name || !checkIsHttpToken(name)) {
|
||||||
|
// Reducing the limit improves the performance significantly. We do not
|
||||||
|
// lose the stack frames due to the `captureStackTrace()` function that is
|
||||||
|
// called later.
|
||||||
|
const tmpLimit = Error.stackTraceLimit;
|
||||||
|
Error.stackTraceLimit = 0;
|
||||||
const err = new ERR_INVALID_HTTP_TOKEN('Header name', name);
|
const err = new ERR_INVALID_HTTP_TOKEN('Header name', name);
|
||||||
|
Error.stackTraceLimit = tmpLimit;
|
||||||
Error.captureStackTrace(err, validateHeaderName);
|
Error.captureStackTrace(err, validateHeaderName);
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
@ -454,12 +460,18 @@ function validateHeaderName(name) {
|
|||||||
|
|
||||||
function validateHeaderValue(name, value) {
|
function validateHeaderValue(name, value) {
|
||||||
let err;
|
let err;
|
||||||
|
// Reducing the limit improves the performance significantly. We do not loose
|
||||||
|
// the stack frames due to the `captureStackTrace()` function that is called
|
||||||
|
// later.
|
||||||
|
const tmpLimit = Error.stackTraceLimit;
|
||||||
|
Error.stackTraceLimit = 0;
|
||||||
if (value === undefined) {
|
if (value === undefined) {
|
||||||
err = new ERR_HTTP_INVALID_HEADER_VALUE(value, name);
|
err = new ERR_HTTP_INVALID_HEADER_VALUE(value, name);
|
||||||
} else if (checkInvalidHeaderChar(value)) {
|
} else if (checkInvalidHeaderChar(value)) {
|
||||||
debug('Header "%s" contains invalid characters', name);
|
debug('Header "%s" contains invalid characters', name);
|
||||||
err = new ERR_INVALID_CHAR('header content', name);
|
err = new ERR_INVALID_CHAR('header content', name);
|
||||||
}
|
}
|
||||||
|
Error.stackTraceLimit = tmpLimit;
|
||||||
if (err !== undefined) {
|
if (err !== undefined) {
|
||||||
Error.captureStackTrace(err, validateHeaderValue);
|
Error.captureStackTrace(err, validateHeaderValue);
|
||||||
throw err;
|
throw err;
|
||||||
|
@ -261,10 +261,16 @@ function uvException(ctx) {
|
|||||||
message += ` -> '${dest}'`;
|
message += ` -> '${dest}'`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reducing the limit improves the performance significantly. We do not loose
|
||||||
|
// the stack frames due to the `captureStackTrace()` function that is called
|
||||||
|
// later.
|
||||||
|
const tmpLimit = Error.stackTraceLimit;
|
||||||
|
Error.stackTraceLimit = 0;
|
||||||
// Pass the message to the constructor instead of setting it on the object
|
// Pass the message to the constructor instead of setting it on the object
|
||||||
// to make sure it is the same as the one created in C++
|
// to make sure it is the same as the one created in C++
|
||||||
// eslint-disable-next-line no-restricted-syntax
|
// eslint-disable-next-line no-restricted-syntax
|
||||||
const err = new Error(message);
|
const err = new Error(message);
|
||||||
|
Error.stackTraceLimit = tmpLimit;
|
||||||
|
|
||||||
for (const prop of Object.keys(ctx)) {
|
for (const prop of Object.keys(ctx)) {
|
||||||
if (prop === 'message' || prop === 'path' || prop === 'dest') {
|
if (prop === 'message' || prop === 'path' || prop === 'dest') {
|
||||||
@ -307,8 +313,14 @@ function uvExceptionWithHostPort(err, syscall, address, port) {
|
|||||||
details = ` ${address}`;
|
details = ` ${address}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reducing the limit improves the performance significantly. We do not loose
|
||||||
|
// the stack frames due to the `captureStackTrace()` function that is called
|
||||||
|
// later.
|
||||||
|
const tmpLimit = Error.stackTraceLimit;
|
||||||
|
Error.stackTraceLimit = 0;
|
||||||
// eslint-disable-next-line no-restricted-syntax
|
// eslint-disable-next-line no-restricted-syntax
|
||||||
const ex = new Error(`${message}${details}`);
|
const ex = new Error(`${message}${details}`);
|
||||||
|
Error.stackTraceLimit = tmpLimit;
|
||||||
ex.code = code;
|
ex.code = code;
|
||||||
ex.errno = code;
|
ex.errno = code;
|
||||||
ex.syscall = syscall;
|
ex.syscall = syscall;
|
||||||
@ -377,9 +389,15 @@ function exceptionWithHostPort(err, syscall, address, port, additional) {
|
|||||||
details += ` - Local (${additional})`;
|
details += ` - Local (${additional})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reducing the limit improves the performance significantly. We do not loose
|
||||||
|
// the stack frames due to the `captureStackTrace()` function that is called
|
||||||
|
// later.
|
||||||
|
const tmpLimit = Error.stackTraceLimit;
|
||||||
|
Error.stackTraceLimit = 0;
|
||||||
// eslint-disable-next-line no-restricted-syntax
|
// eslint-disable-next-line no-restricted-syntax
|
||||||
const ex = new Error(`${syscall} ${code}${details}`);
|
const ex = new Error(`${syscall} ${code}${details}`);
|
||||||
// TODO(joyeecheung): errno is supposed to err, like in uvException
|
// TODO(joyeecheung): errno is supposed to err, like in uvException
|
||||||
|
Error.stackTraceLimit = tmpLimit;
|
||||||
ex.code = ex.errno = code;
|
ex.code = ex.errno = code;
|
||||||
ex.syscall = syscall;
|
ex.syscall = syscall;
|
||||||
ex.address = address;
|
ex.address = address;
|
||||||
@ -410,9 +428,15 @@ function dnsException(code, syscall, hostname) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const message = `${syscall} ${code}${hostname ? ` ${hostname}` : ''}`;
|
const message = `${syscall} ${code}${hostname ? ` ${hostname}` : ''}`;
|
||||||
|
// Reducing the limit improves the performance significantly. We do not loose
|
||||||
|
// the stack frames due to the `captureStackTrace()` function that is called
|
||||||
|
// later.
|
||||||
|
const tmpLimit = Error.stackTraceLimit;
|
||||||
|
Error.stackTraceLimit = 0;
|
||||||
// eslint-disable-next-line no-restricted-syntax
|
// eslint-disable-next-line no-restricted-syntax
|
||||||
const ex = new Error(message);
|
const ex = new Error(message);
|
||||||
// TODO(joyeecheung): errno is supposed to be a number / err, like in
|
// TODO(joyeecheung): errno is supposed to be a number / err, like in
|
||||||
|
Error.stackTraceLimit = tmpLimit;
|
||||||
// uvException.
|
// uvException.
|
||||||
ex.errno = code;
|
ex.errno = code;
|
||||||
ex.code = code;
|
ex.code = code;
|
||||||
|
@ -190,16 +190,19 @@ function nullCheck(path, propName, throwError = true) {
|
|||||||
const pathIsUint8Array = isUint8Array(path);
|
const pathIsUint8Array = isUint8Array(path);
|
||||||
|
|
||||||
// We can only perform meaningful checks on strings and Uint8Arrays.
|
// We can only perform meaningful checks on strings and Uint8Arrays.
|
||||||
if (!pathIsString && !pathIsUint8Array) {
|
if (!pathIsString && !pathIsUint8Array ||
|
||||||
|
pathIsString && path.indexOf('\u0000') === -1 ||
|
||||||
|
pathIsUint8Array && path.indexOf(0) === -1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pathIsString && path.indexOf('\u0000') === -1) {
|
// Reducing the limit improves the performance significantly. We do not loose
|
||||||
return;
|
// the stack frames due to the `captureStackTrace()` function that is called
|
||||||
} else if (pathIsUint8Array && path.indexOf(0) === -1) {
|
// later.
|
||||||
return;
|
const tmpLimit = Error.stackTraceLimit;
|
||||||
|
if (throwError) {
|
||||||
|
Error.stackTraceLimit = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const err = new ERR_INVALID_ARG_VALUE(
|
const err = new ERR_INVALID_ARG_VALUE(
|
||||||
propName,
|
propName,
|
||||||
path,
|
path,
|
||||||
@ -207,6 +210,7 @@ function nullCheck(path, propName, throwError = true) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (throwError) {
|
if (throwError) {
|
||||||
|
Error.stackTraceLimit = tmpLimit;
|
||||||
Error.captureStackTrace(err, nullCheck);
|
Error.captureStackTrace(err, nullCheck);
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
@ -127,8 +127,13 @@ function setupProcessWarnings() {
|
|||||||
throw new ERR_INVALID_ARG_TYPE('code', 'string', code);
|
throw new ERR_INVALID_ARG_TYPE('code', 'string', code);
|
||||||
}
|
}
|
||||||
if (typeof warning === 'string') {
|
if (typeof warning === 'string') {
|
||||||
|
// Improve error creation performance by skipping the error frames.
|
||||||
|
// They are added in the `captureStackTrace()` function below.
|
||||||
|
const tmpStackLimit = Error.stackTraceLimit;
|
||||||
|
Error.stackTraceLimit = 0;
|
||||||
// eslint-disable-next-line no-restricted-syntax
|
// eslint-disable-next-line no-restricted-syntax
|
||||||
warning = new Error(warning);
|
warning = new Error(warning);
|
||||||
|
Error.stackTraceLimit = tmpStackLimit;
|
||||||
warning.name = String(type || 'Warning');
|
warning.name = String(type || 'Warning');
|
||||||
if (code !== undefined) warning.code = code;
|
if (code !== undefined) warning.code = code;
|
||||||
if (detail !== undefined) warning.detail = detail;
|
if (detail !== undefined) warning.detail = detail;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user