From 3838b579e44bf0c2db43171c3ce0da51eb6b05d5 Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Wed, 27 Sep 2023 19:26:01 +0000 Subject: [PATCH 1/9] deps: V8: cherry-pick 8ec2651fbdd8 Original commit message: fix: EmbeddedTargetOs on IBM i with Python 3.9 For some context, Python 3.9 on IBM i returns "os400" for sys.platform instead of "aix". We used to build with Python 3.6 which returned "aix" as the platform When attempting to build Node.js with python 3.9 on IBM i we run into a build error. Ref: https://github.com/nodejs/node/pull/48056 Ref: https://github.com/nodejs/node/pull/48056#issuecomment-1553719508 I'm not quite sure where target_os is being passed down to the function ToEmbeddedTargetOs. It seems as though target_os is being generated from sys.platform or similar call from python as we started running into this issue after building with Python 3.9. This PR supersedes initial changes proposed in: https://chromium-review.googlesource.com/c/v8/v8/+/4259330 This PR contains the minimal changes to successfully build Node.js (builds v8 as an internal dep) on IBM i with Python 3.9. Change-Id: I32d43197bce994a72a0d85091e91f80eeea4482d Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4846413 Commit-Queue: Jakob Linke Reviewed-by: Michael Achenbach Reviewed-by: Jakob Linke Cr-Commit-Position: refs/heads/main@{#89981} Refs: https://github.com/v8/v8/commit/8ec2651fbdd8adf054397ee832031c9ff7aa16ac PR-URL: https://github.com/nodejs/node/pull/49862 Reviewed-By: Richard Lau Reviewed-By: Michael Dawson --- common.gypi | 2 +- .../snapshot/embedded/platform-embedded-file-writer-base.cc | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/common.gypi b/common.gypi index 14f05fcf9ccb8d..909d09934a1b25 100644 --- a/common.gypi +++ b/common.gypi @@ -36,7 +36,7 @@ # Reset this number to 0 on major V8 upgrades. # Increment by one for each non-official patch applied to deps/v8. - 'v8_embedder_string': '-node.18', + 'v8_embedder_string': '-node.19', ##### V8 defaults for Node.js ##### diff --git a/deps/v8/src/snapshot/embedded/platform-embedded-file-writer-base.cc b/deps/v8/src/snapshot/embedded/platform-embedded-file-writer-base.cc index e0602edc7e1c6a..e4ca7bfdacb11c 100644 --- a/deps/v8/src/snapshot/embedded/platform-embedded-file-writer-base.cc +++ b/deps/v8/src/snapshot/embedded/platform-embedded-file-writer-base.cc @@ -130,7 +130,8 @@ EmbeddedTargetOs ToEmbeddedTargetOs(const char* s) { } std::string string(s); - if (string == "aix") { + // Python 3.9+ on IBM i returns os400 as sys.platform instead of aix + if (string == "aix" || string == "os400") { return EmbeddedTargetOs::kAIX; } else if (string == "chromeos") { return EmbeddedTargetOs::kChromeOS; From cc725a653af24bce6302a60c3f96a58ab3f4ee5b Mon Sep 17 00:00:00 2001 From: Aras Abbasi Date: Thu, 28 Sep 2023 11:57:38 +0200 Subject: [PATCH 2/9] errors: improve performance of instantiation PR-URL: https://github.com/nodejs/node/pull/49654 Reviewed-By: Matteo Collina Reviewed-By: Yagiz Nizipli Reviewed-By: Stephen Belanger Reviewed-By: Joyee Cheung Reviewed-By: Raz Luvaton --- benchmark/{misc => error}/hidestackframes.js | 0 benchmark/error/node-error-instantiation.js | 66 ++++++++ benchmark/error/node-error-stack.js | 62 ++++++++ benchmark/error/node-error.js | 21 --- lib/internal/crypto/hkdf.js | 2 +- lib/internal/errors.js | 150 +++++++++++++----- lib/internal/fs/streams.js | 4 +- lib/internal/modules/esm/hooks.js | 4 +- lib/internal/navigator.js | 2 +- lib/internal/url.js | 2 +- lib/stream.js | 4 +- test/common/index.js | 3 +- .../output/junit_reporter.snapshot | 102 ++++++------ .../test-runner/output/spec_reporter.snapshot | 8 +- .../output/spec_reporter_cli.snapshot | 8 +- test/message/internal_assert.out | 1 - test/message/internal_assert_fail.out | 1 - test/parallel/test-repl-top-level-await.js | 4 +- 18 files changed, 306 insertions(+), 138 deletions(-) rename benchmark/{misc => error}/hidestackframes.js (100%) create mode 100644 benchmark/error/node-error-instantiation.js create mode 100644 benchmark/error/node-error-stack.js delete mode 100644 benchmark/error/node-error.js diff --git a/benchmark/misc/hidestackframes.js b/benchmark/error/hidestackframes.js similarity index 100% rename from benchmark/misc/hidestackframes.js rename to benchmark/error/hidestackframes.js diff --git a/benchmark/error/node-error-instantiation.js b/benchmark/error/node-error-instantiation.js new file mode 100644 index 00000000000000..333087b9195894 --- /dev/null +++ b/benchmark/error/node-error-instantiation.js @@ -0,0 +1,66 @@ +'use strict'; + +const common = require('../common'); +const assert = require('assert'); + +const bench = common.createBenchmark(main, { + n: [1e6], + code: [ + 'built-in', + 'ERR_HTTP2_STREAM_SELF_DEPENDENCY', + 'ERR_INVALID_STATE', + 'ERR_INVALID_URL', + ], + stackTraceLimit: [0, 10], +}, { + flags: ['--expose-internals'], +}); + +function getErrorFactory(code) { + const { + ERR_HTTP2_STREAM_SELF_DEPENDENCY, + ERR_INVALID_STATE, + ERR_INVALID_URL, + } = require('internal/errors').codes; + + switch (code) { + case 'built-in': + return (n) => new Error(); + case 'ERR_HTTP2_STREAM_SELF_DEPENDENCY': + return (n) => new ERR_HTTP2_STREAM_SELF_DEPENDENCY(); + case 'ERR_INVALID_STATE': + return (n) => new ERR_INVALID_STATE(n + ''); + case 'ERR_INVALID_URL': + return (n) => new ERR_INVALID_URL({ input: n + '' }); + default: + throw new Error(`${code} not supported`); + } +} + +function main({ n, code, stackTraceLimit }) { + const getError = getErrorFactory(code); + + Error.stackTraceLimit = stackTraceLimit; + + // Warm up. + const length = 1024; + const array = []; + for (let i = 0; i < length; ++i) { + array.push(getError(i)); + } + + bench.start(); + + for (let i = 0; i < n; ++i) { + const index = i % length; + array[index] = getError(index); + } + + bench.end(n); + + // Verify the entries to prevent dead code elimination from making + // the benchmark invalid. + for (let i = 0; i < length; ++i) { + assert.strictEqual(typeof array[i], 'object'); + } +} diff --git a/benchmark/error/node-error-stack.js b/benchmark/error/node-error-stack.js new file mode 100644 index 00000000000000..06319ccd17105f --- /dev/null +++ b/benchmark/error/node-error-stack.js @@ -0,0 +1,62 @@ +'use strict'; + +const common = require('../common'); +const assert = require('assert'); + +const bench = common.createBenchmark(main, { + n: [1e6], + code: [ + 'built-in', + 'ERR_HTTP2_STREAM_SELF_DEPENDENCY', + 'ERR_INVALID_STATE', + ], + stackTraceLimit: [0, 10], +}, { + flags: ['--expose-internals'], +}); + +function getErrorStackFactory(code) { + const { + ERR_INVALID_STATE, + ERR_HTTP2_STREAM_SELF_DEPENDENCY, + } = require('internal/errors').codes; + + switch (code) { + case 'built-in': + return (n) => new Error().stack; + case 'ERR_HTTP2_STREAM_SELF_DEPENDENCY': + return (n) => new ERR_HTTP2_STREAM_SELF_DEPENDENCY().stack; + case 'ERR_INVALID_STATE': + return (n) => new ERR_INVALID_STATE(n + '').stack; + default: + throw new Error(`${code} not supported`); + } +} + +function main({ n, code, stackTraceLimit }) { + const getStack = getErrorStackFactory(code); + + Error.stackTraceLimit = stackTraceLimit; + + // Warm up. + const length = 1024; + const array = []; + for (let i = 0; i < length; ++i) { + array.push(getStack(i)); + } + + bench.start(); + + for (let i = 0; i < n; ++i) { + const index = i % length; + array[index] = getStack(index); + } + + bench.end(n); + + // Verify the entries to prevent dead code elimination from making + // the benchmark invalid. + for (let i = 0; i < length; ++i) { + assert.strictEqual(typeof array[i], 'string'); + } +} diff --git a/benchmark/error/node-error.js b/benchmark/error/node-error.js deleted file mode 100644 index 3a0aef91f04a06..00000000000000 --- a/benchmark/error/node-error.js +++ /dev/null @@ -1,21 +0,0 @@ -'use strict'; - -const common = require('../common'); - -const bench = common.createBenchmark(main, { - n: [1e7], -}, { - flags: ['--expose-internals'], -}); - -function main({ n }) { - const { - codes: { - ERR_INVALID_STATE, - }, - } = require('internal/errors'); - bench.start(); - for (let i = 0; i < n; ++i) - new ERR_INVALID_STATE.TypeError('test'); - bench.end(n); -} diff --git a/lib/internal/crypto/hkdf.js b/lib/internal/crypto/hkdf.js index 7f0fe5534ee843..cf3c39e8d9da5a 100644 --- a/lib/internal/crypto/hkdf.js +++ b/lib/internal/crypto/hkdf.js @@ -57,7 +57,7 @@ const validateParameters = hideStackFrames((hash, key, salt, info, length) => { validateInteger(length, 'length', 0, kMaxLength); if (info.byteLength > 1024) { - throw ERR_OUT_OF_RANGE( + throw new ERR_OUT_OF_RANGE( 'info', 'must not contain more than 1024 bytes', info.byteLength); diff --git a/lib/internal/errors.js b/lib/internal/errors.js index 4e332e1ce18d16..6bba8ec095e86e 100644 --- a/lib/internal/errors.js +++ b/lib/internal/errors.js @@ -175,9 +175,10 @@ const aggregateErrors = hideStackFrames((errors, message, code) => { return err; }); +const assert = require('internal/assert'); + // Lazily loaded let util; -let assert; let internalUtil = null; function lazyInternalUtil() { @@ -371,42 +372,103 @@ function makeSystemErrorWithCode(key) { } function makeNodeErrorWithCode(Base, key) { - return function NodeError(...args) { - const limit = Error.stackTraceLimit; - if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = 0; - const error = new Base(); - // Reset the limit and setting the name property. - if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = limit; - const message = getMessage(key, args, error); - ObjectDefineProperties(error, { - [kIsNodeError]: { - __proto__: null, - value: true, - enumerable: false, - writable: false, - configurable: true, - }, - message: { - __proto__: null, - value: message, - enumerable: false, - writable: true, - configurable: true, - }, - toString: { - __proto__: null, - value() { + const msg = messages.get(key); + const expectedLength = typeof msg !== 'string' ? -1 : getExpectedArgumentLength(msg); + + switch (expectedLength) { + case 0: { + class NodeError extends Base { + code = key; + + constructor(...args) { + assert( + args.length === 0, + `Code: ${key}; The provided arguments length (${args.length}) does not ` + + `match the required ones (${expectedLength}).`, + ); + super(msg); + } + + // This is a workaround for wpt tests that expect that the error + // constructor has a `name` property of the base class. + get ['constructor']() { + return Base; + } + + get [kIsNodeError]() { + return true; + } + + toString() { return `${this.name} [${key}]: ${this.message}`; - }, - enumerable: false, - writable: true, - configurable: true, - }, - }); - captureLargerStackTrace(error); - error.code = key; - return error; - }; + } + } + return NodeError; + } + case -1: { + class NodeError extends Base { + code = key; + + constructor(...args) { + super(); + ObjectDefineProperty(this, 'message', { + __proto__: null, + value: getMessage(key, args, this), + enumerable: false, + writable: true, + configurable: true, + }); + } + + // This is a workaround for wpt tests that expect that the error + // constructor has a `name` property of the base class. + get ['constructor']() { + return Base; + } + + get [kIsNodeError]() { + return true; + } + + toString() { + return `${this.name} [${key}]: ${this.message}`; + } + } + return NodeError; + } + default: { + + class NodeError extends Base { + code = key; + + constructor(...args) { + assert( + args.length === expectedLength, + `Code: ${key}; The provided arguments length (${args.length}) does not ` + + `match the required ones (${expectedLength}).`, + ); + + ArrayPrototypeUnshift(args, msg); + super(ReflectApply(lazyInternalUtilInspect().format, null, args)); + } + + // This is a workaround for wpt tests that expect that the error + // constructor has a `name` property of the base class. + get ['constructor']() { + return Base; + } + + get [kIsNodeError]() { + return true; + } + + toString() { + return `${this.name} [${key}]: ${this.message}`; + } + } + return NodeError; + } + } } /** @@ -443,11 +505,16 @@ function E(sym, val, def, ...otherClasses) { codes[sym] = def; } +function getExpectedArgumentLength(msg) { + let expectedLength = 0; + const regex = /%[dfijoOs]/g; + while (RegExpPrototypeExec(regex, msg) !== null) expectedLength++; + return expectedLength; +} + function getMessage(key, args, self) { const msg = messages.get(key); - assert ??= require('internal/assert'); - if (typeof msg === 'function') { assert( msg.length <= args.length, // Default options do not count. @@ -457,9 +524,7 @@ function getMessage(key, args, self) { return ReflectApply(msg, self, args); } - const regex = /%[dfijoOs]/g; - let expectedLength = 0; - while (RegExpPrototypeExec(regex, msg) !== null) expectedLength++; + const expectedLength = getExpectedArgumentLength(msg); assert( expectedLength === args.length, `Code: ${key}; The provided arguments length (${args.length}) does not ` + @@ -1476,8 +1541,7 @@ E('ERR_NETWORK_IMPORT_DISALLOWED', "import of '%s' by %s is not supported: %s", Error); E('ERR_NOT_BUILDING_SNAPSHOT', 'Operation cannot be invoked when not building startup snapshot', Error); -E('ERR_NOT_SUPPORTED_IN_SNAPSHOT', - '%s is not supported in startup snapshot', Error); +E('ERR_NOT_SUPPORTED_IN_SNAPSHOT', '%s is not supported in startup snapshot', Error); E('ERR_NO_CRYPTO', 'Node.js is not compiled with OpenSSL crypto support', Error); E('ERR_NO_ICU', diff --git a/lib/internal/fs/streams.js b/lib/internal/fs/streams.js index c317f3b9202af9..6a213693342b94 100644 --- a/lib/internal/fs/streams.js +++ b/lib/internal/fs/streams.js @@ -143,8 +143,8 @@ function importFd(stream, options) { return options.fd.fd; } - throw ERR_INVALID_ARG_TYPE('options.fd', - ['number', 'FileHandle'], options.fd); + throw new ERR_INVALID_ARG_TYPE('options.fd', + ['number', 'FileHandle'], options.fd); } function ReadStream(path, options) { diff --git a/lib/internal/modules/esm/hooks.js b/lib/internal/modules/esm/hooks.js index 8ad4d00bbfe06f..8dd81ca52c5318 100644 --- a/lib/internal/modules/esm/hooks.js +++ b/lib/internal/modules/esm/hooks.js @@ -407,7 +407,7 @@ class Hooks { !isAnyArrayBuffer(source) && !isArrayBufferView(source) ) { - throw ERR_INVALID_RETURN_PROPERTY_VALUE( + throw new ERR_INVALID_RETURN_PROPERTY_VALUE( 'a string, an ArrayBuffer, or a TypedArray', hookErrIdentifier, 'source', @@ -599,7 +599,7 @@ class HooksProxy { if (status === 'error') { if (body == null || typeof body !== 'object') { throw body; } if (body.serializationFailed || body.serialized == null) { - throw ERR_WORKER_UNSERIALIZABLE_ERROR(); + throw new ERR_WORKER_UNSERIALIZABLE_ERROR(); } // eslint-disable-next-line no-restricted-syntax diff --git a/lib/internal/navigator.js b/lib/internal/navigator.js index 3b8343cd7ed6f8..5971891ea73cc9 100644 --- a/lib/internal/navigator.js +++ b/lib/internal/navigator.js @@ -27,7 +27,7 @@ class Navigator { if (arguments[0] === kInitialize) { return; } - throw ERR_ILLEGAL_CONSTRUCTOR(); + throw new ERR_ILLEGAL_CONSTRUCTOR(); } /** diff --git a/lib/internal/url.js b/lib/internal/url.js index 13a9e287ffc47a..ca41c48582b19d 100644 --- a/lib/internal/url.js +++ b/lib/internal/url.js @@ -855,7 +855,7 @@ class URL { set href(value) { value = `${value}`; const href = bindingUrl.update(this.#context.href, updateActions.kHref, value); - if (!href) { throw ERR_INVALID_URL(value); } + if (!href) { throw new ERR_INVALID_URL(value); } this.#updateContext(href); } diff --git a/lib/stream.js b/lib/stream.js index 9a09401e7d016a..cdbc1fe0380694 100644 --- a/lib/stream.js +++ b/lib/stream.js @@ -64,7 +64,7 @@ for (const key of ObjectKeys(streamReturningOperators)) { const op = streamReturningOperators[key]; function fn(...args) { if (new.target) { - throw ERR_ILLEGAL_CONSTRUCTOR(); + throw new ERR_ILLEGAL_CONSTRUCTOR(); } return Stream.Readable.from(ReflectApply(op, this, args)); } @@ -82,7 +82,7 @@ for (const key of ObjectKeys(promiseReturningOperators)) { const op = promiseReturningOperators[key]; function fn(...args) { if (new.target) { - throw ERR_ILLEGAL_CONSTRUCTOR(); + throw new ERR_ILLEGAL_CONSTRUCTOR(); } return ReflectApply(op, this, args); } diff --git a/test/common/index.js b/test/common/index.js index c10dea59319264..338e773a353eff 100644 --- a/test/common/index.js +++ b/test/common/index.js @@ -720,9 +720,8 @@ function expectsError(validator, exact) { assert.fail(`Expected one argument, got ${inspect(args)}`); } const error = args.pop(); - const descriptor = Object.getOwnPropertyDescriptor(error, 'message'); // The error message should be non-enumerable - assert.strictEqual(descriptor.enumerable, false); + assert.strictEqual(Object.prototype.propertyIsEnumerable.call(error, 'message'), false); assert.throws(() => { throw error; }, validator); return true; diff --git a/test/fixtures/test-runner/output/junit_reporter.snapshot b/test/fixtures/test-runner/output/junit_reporter.snapshot index 6516387e7ed582..e0a4c331dd5c22 100644 --- a/test/fixtures/test-runner/output/junit_reporter.snapshot +++ b/test/fixtures/test-runner/output/junit_reporter.snapshot @@ -10,6 +10,7 @@ [Error [ERR_TEST_FAILURE]: thrown from sync fail todo] { + code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: Error: thrown from sync fail todo * @@ -18,8 +19,7 @@ * * * - at async Test.processPendingSubtests (node:internal/test_runner/test:374:7), - code: 'ERR_TEST_FAILURE' + * } @@ -27,6 +27,7 @@ [Error [ERR_TEST_FAILURE]: thrown from sync fail todo with message] { + code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: Error: thrown from sync fail todo with message * @@ -35,8 +36,7 @@ * * * - at async Test.processPendingSubtests (node:internal/test_runner/test:374:7), - code: 'ERR_TEST_FAILURE' + * } @@ -51,6 +51,7 @@ [Error [ERR_TEST_FAILURE]: thrown from sync throw fail] { + code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: Error: thrown from sync throw fail * @@ -59,8 +60,7 @@ * * * - at async Test.processPendingSubtests (node:internal/test_runner/test:374:7), - code: 'ERR_TEST_FAILURE' + * } @@ -71,6 +71,7 @@ [Error [ERR_TEST_FAILURE]: thrown from async throw fail] { + code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: Error: thrown from async throw fail * @@ -79,8 +80,7 @@ * * * - at async Test.processPendingSubtests (node:internal/test_runner/test:374:7), - code: 'ERR_TEST_FAILURE' + * } @@ -88,6 +88,7 @@ [Error [ERR_TEST_FAILURE]: thrown from async throw fail] { + code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: Error: thrown from async throw fail * @@ -96,8 +97,7 @@ * * * - at async Test.processPendingSubtests (node:internal/test_runner/test:374:7), - code: 'ERR_TEST_FAILURE' + * } @@ -107,6 +107,7 @@ true !== false ] { + code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: @@ -124,8 +125,7 @@ true !== false actual: true, expected: false, operator: 'strictEqual' - }, - code: 'ERR_TEST_FAILURE' + } } @@ -133,6 +133,7 @@ true !== false [Error [ERR_TEST_FAILURE]: rejected from reject fail] { + code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: Error: rejected from reject fail * @@ -141,8 +142,7 @@ true !== false * * * - at async Test.processPendingSubtests (node:internal/test_runner/test:374:7), - code: 'ERR_TEST_FAILURE' + * } @@ -156,6 +156,7 @@ true !== false Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fail * { + code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: Error: thrown from subtest sync throw fail * @@ -167,8 +168,7 @@ Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fail * * * - at Test.postRun (node:internal/test_runner/test:715:19), - code: 'ERR_TEST_FAILURE' + * } @@ -176,7 +176,7 @@ Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fail -[Error [ERR_TEST_FAILURE]: Symbol(thrown symbol from sync throw non-error fail)] { failureType: 'testCodeFailure', cause: Symbol(thrown symbol from sync throw non-error fail), code: 'ERR_TEST_FAILURE' } +[Error [ERR_TEST_FAILURE]: Symbol(thrown symbol from sync throw non-error fail)] { code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: Symbol(thrown symbol from sync throw non-error fail) } @@ -188,7 +188,7 @@ Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fail -[Error [ERR_TEST_FAILURE]: test did not finish before its parent and was cancelled] { failureType: 'cancelledByParent', cause: 'test did not finish before its parent and was cancelled', code: 'ERR_TEST_FAILURE' } +[Error [ERR_TEST_FAILURE]: test did not finish before its parent and was cancelled] { code: 'ERR_TEST_FAILURE', failureType: 'cancelledByParent', cause: 'test did not finish before its parent and was cancelled' } @@ -205,6 +205,7 @@ Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fail [Error [ERR_TEST_FAILURE]: this should be executed] { + code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: Error: this should be executed * @@ -213,8 +214,7 @@ Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fail * * * - at async Test.processPendingSubtests (node:internal/test_runner/test:374:7), - code: 'ERR_TEST_FAILURE' + * } @@ -236,11 +236,11 @@ Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fail [Error [ERR_TEST_FAILURE]: callback failure] { + code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: Error: callback failure * - at process.processImmediate (node:internal/timers:478:21), - code: 'ERR_TEST_FAILURE' + * } @@ -249,12 +249,13 @@ Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fail -[Error [ERR_TEST_FAILURE]: passed a callback but also returned a Promise] { failureType: 'callbackAndPromisePresent', cause: 'passed a callback but also returned a Promise', code: 'ERR_TEST_FAILURE' } +[Error [ERR_TEST_FAILURE]: passed a callback but also returned a Promise] { code: 'ERR_TEST_FAILURE', failureType: 'callbackAndPromisePresent', cause: 'passed a callback but also returned a Promise' } [Error [ERR_TEST_FAILURE]: thrown from callback throw] { + code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: Error: thrown from callback throw * @@ -263,8 +264,7 @@ Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fail * * * - at async Test.processPendingSubtests (node:internal/test_runner/test:374:7), - code: 'ERR_TEST_FAILURE' + * } @@ -273,9 +273,9 @@ Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fail Error [ERR_TEST_FAILURE]: callback invoked multiple times * * { + code: 'ERR_TEST_FAILURE', failureType: 'multipleCallbackInvocations', - cause: 'callback invoked multiple times', - code: 'ERR_TEST_FAILURE' + cause: 'callback invoked multiple times' } @@ -284,14 +284,14 @@ Error [ERR_TEST_FAILURE]: callback invoked multiple times Error [ERR_TEST_FAILURE]: callback invoked multiple times * { + code: 'ERR_TEST_FAILURE', failureType: 'uncaughtException', cause: Error [ERR_TEST_FAILURE]: callback invoked multiple times * { + code: 'ERR_TEST_FAILURE', failureType: 'multipleCallbackInvocations', - cause: 'callback invoked multiple times', - code: 'ERR_TEST_FAILURE' - }, - code: 'ERR_TEST_FAILURE' + cause: 'callback invoked multiple times' + } } @@ -299,11 +299,11 @@ Error [ERR_TEST_FAILURE]: callback invoked multiple times Error [ERR_TEST_FAILURE]: thrown from callback async throw * { + code: 'ERR_TEST_FAILURE', failureType: 'uncaughtException', cause: Error: thrown from callback async throw * - at process.processImmediate (node:internal/timers:478:21), - code: 'ERR_TEST_FAILURE' + * } @@ -319,7 +319,7 @@ Error [ERR_TEST_FAILURE]: thrown from callback async throw -[Error [ERR_TEST_FAILURE]: customized] { failureType: 'testCodeFailure', cause: customized, code: 'ERR_TEST_FAILURE' } +[Error [ERR_TEST_FAILURE]: customized] { code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: customized } @@ -328,9 +328,9 @@ Error [ERR_TEST_FAILURE]: thrown from callback async throw foo: 1, [Symbol(nodejs.util.inspect.custom)]: [Function: [nodejs.util.inspect.custom]] }] { + code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', - cause: { foo: 1, [Symbol(nodejs.util.inspect.custom)]: [Function: [nodejs.util.inspect.custom]] }, - code: 'ERR_TEST_FAILURE' + cause: { foo: 1, [Symbol(nodejs.util.inspect.custom)]: [Function: [nodejs.util.inspect.custom]] } } @@ -339,6 +339,7 @@ Error [ERR_TEST_FAILURE]: thrown from callback async throw Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fails at first * { + code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: Error: thrown from subtest sync throw fails at first * @@ -350,8 +351,7 @@ Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fails at first * * * - at Test.postRun (node:internal/test_runner/test:715:19), - code: 'ERR_TEST_FAILURE' + * } @@ -359,6 +359,7 @@ Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fails at first Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fails at second * { + code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: Error: thrown from subtest sync throw fails at second * @@ -370,20 +371,19 @@ Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fails at second * * * - at async Test.run (node:internal/test_runner/test:632:9), - code: 'ERR_TEST_FAILURE' + * } -[Error [ERR_TEST_FAILURE]: test timed out after 5ms] { failureType: 'testTimeoutFailure', cause: 'test timed out after 5ms', code: 'ERR_TEST_FAILURE' } +[Error [ERR_TEST_FAILURE]: test timed out after 5ms] { code: 'ERR_TEST_FAILURE', failureType: 'testTimeoutFailure', cause: 'test timed out after 5ms' } -[Error [ERR_TEST_FAILURE]: test timed out after 5ms] { failureType: 'testTimeoutFailure', cause: 'test timed out after 5ms', code: 'ERR_TEST_FAILURE' } +[Error [ERR_TEST_FAILURE]: test timed out after 5ms] { code: 'ERR_TEST_FAILURE', failureType: 'testTimeoutFailure', cause: 'test timed out after 5ms' } @@ -391,19 +391,19 @@ Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fails at second -[Error [ERR_TEST_FAILURE]: custom error] { failureType: 'testCodeFailure', cause: 'custom error', code: 'ERR_TEST_FAILURE' } +[Error [ERR_TEST_FAILURE]: custom error] { code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: 'custom error' } Error [ERR_TEST_FAILURE]: foo * { + code: 'ERR_TEST_FAILURE', failureType: 'uncaughtException', cause: Error: foo * * - at process.processTimers (node:internal/timers:514:7), - code: 'ERR_TEST_FAILURE' + * } @@ -411,12 +411,12 @@ Error [ERR_TEST_FAILURE]: foo Error [ERR_TEST_FAILURE]: bar * { + code: 'ERR_TEST_FAILURE', failureType: 'unhandledRejection', cause: Error: bar * * - at process.processTimers (node:internal/timers:514:7), - code: 'ERR_TEST_FAILURE' + * } @@ -435,6 +435,7 @@ should loosely deep-equal bar: 2, c: [Circular *1] }] { + code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: AssertionError [ERR_ASSERTION]: Expected values to be loosely deep-equal: @@ -455,8 +456,7 @@ should loosely deep-equal actual: [Object], expected: [Object], operator: 'deepEqual' - }, - code: 'ERR_TEST_FAILURE' + } } @@ -464,9 +464,9 @@ should loosely deep-equal Error [ERR_TEST_FAILURE]: test could not be started because its parent finished * { + code: 'ERR_TEST_FAILURE', failureType: 'parentAlreadyFinished', - cause: 'test could not be started because its parent finished', - code: 'ERR_TEST_FAILURE' + cause: 'test could not be started because its parent finished' } diff --git a/test/fixtures/test-runner/output/spec_reporter.snapshot b/test/fixtures/test-runner/output/spec_reporter.snapshot index 5dc05d5b43c12d..8f14dc7fc9bade 100644 --- a/test/fixtures/test-runner/output/spec_reporter.snapshot +++ b/test/fixtures/test-runner/output/spec_reporter.snapshot @@ -178,9 +178,9 @@ callback called twice in future tick (*ms) Error [ERR_TEST_FAILURE]: callback invoked multiple times * { + code: 'ERR_TEST_FAILURE', failureType: 'multipleCallbackInvocations', - cause: 'callback invoked multiple times', - code: 'ERR_TEST_FAILURE' + cause: 'callback invoked multiple times' } callback async throw (*ms) @@ -449,9 +449,9 @@ callback called twice in future tick (*ms) Error [ERR_TEST_FAILURE]: callback invoked multiple times * { + code: 'ERR_TEST_FAILURE', failureType: 'multipleCallbackInvocations', - cause: 'callback invoked multiple times', - code: 'ERR_TEST_FAILURE' + cause: 'callback invoked multiple times' } * diff --git a/test/fixtures/test-runner/output/spec_reporter_cli.snapshot b/test/fixtures/test-runner/output/spec_reporter_cli.snapshot index 25c22069c3b8e7..a9b70560d905b2 100644 --- a/test/fixtures/test-runner/output/spec_reporter_cli.snapshot +++ b/test/fixtures/test-runner/output/spec_reporter_cli.snapshot @@ -178,9 +178,9 @@ callback called twice in future tick (*ms) Error [ERR_TEST_FAILURE]: callback invoked multiple times * { + code: 'ERR_TEST_FAILURE', failureType: 'multipleCallbackInvocations', - cause: 'callback invoked multiple times', - code: 'ERR_TEST_FAILURE' + cause: 'callback invoked multiple times' } callback async throw (*ms) @@ -449,9 +449,9 @@ callback called twice in future tick (*ms) Error [ERR_TEST_FAILURE]: callback invoked multiple times * { + code: 'ERR_TEST_FAILURE', failureType: 'multipleCallbackInvocations', - cause: 'callback invoked multiple times', - code: 'ERR_TEST_FAILURE' + cause: 'callback invoked multiple times' } * diff --git a/test/message/internal_assert.out b/test/message/internal_assert.out index bd25c879478083..197b863bf6ae69 100644 --- a/test/message/internal_assert.out +++ b/test/message/internal_assert.out @@ -5,7 +5,6 @@ node:internal/assert:* Error [ERR_INTERNAL_ASSERTION]: This is caused by either a bug in Node.js or incorrect usage of Node.js internals. Please open an issue with this stack trace at https://github.com/nodejs/node/issues - at new NodeError (node:internal/errors:*:*) at assert (node:internal/assert:*:*) at * (*test*message*internal_assert.js:7:1) at * diff --git a/test/message/internal_assert_fail.out b/test/message/internal_assert_fail.out index 408d6d3364470d..e6895691cda9c1 100644 --- a/test/message/internal_assert_fail.out +++ b/test/message/internal_assert_fail.out @@ -6,7 +6,6 @@ Error [ERR_INTERNAL_ASSERTION]: Unreachable! This is caused by either a bug in Node.js or incorrect usage of Node.js internals. Please open an issue with this stack trace at https://github.com/nodejs/node/issues - at new NodeError (node:internal/errors:*:*) at Function.fail (node:internal/assert:*:*) at * (*test*message*internal_assert_fail.js:7:8) at * diff --git a/test/parallel/test-repl-top-level-await.js b/test/parallel/test-repl-top-level-await.js index 1abcca75f1e2a0..c8bc26fad62e5c 100644 --- a/test/parallel/test-repl-top-level-await.js +++ b/test/parallel/test-repl-top-level-await.js @@ -207,8 +207,8 @@ async function ctrlCTest() { assert.deepStrictEqual(output.slice(0, 3), [ 'await new Promise(() => {})\r', 'Uncaught:', - 'Error [ERR_SCRIPT_EXECUTION_INTERRUPTED]: ' + - 'Script execution was interrupted by `SIGINT`', + '[Error [ERR_SCRIPT_EXECUTION_INTERRUPTED]: ' + + 'Script execution was interrupted by `SIGINT`] {', ]); assert.deepStrictEqual(output.slice(-2), [ '}', From a4fdb1abe0844d86b4cbfcc4051794656e7d746e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Zasso?= Date: Thu, 28 Sep 2023 14:50:20 +0200 Subject: [PATCH 3/9] lib,test: do not hardcode Buffer.kMaxLength V8 will soon support typed arrays as large as the maximum array buffer length. This patch replaces hardcoded values related to Buffer.kMaxLength with the actual constant. It also fixes a test that was passing by accident. Refs: https://github.com/v8/v8/commit/44b299590083b888637c79fb5632806e607ab861 PR-URL: https://github.com/nodejs/node/pull/49876 Reviewed-By: Richard Lau Reviewed-By: Luigi Pinca Reviewed-By: Yagiz Nizipli --- lib/internal/blob.js | 8 +++++--- test/parallel/test-blob-buffer-too-large.js | 6 +++--- test/parallel/test-buffer-alloc.js | 9 ++++++--- test/parallel/test-buffer-over-max-length.js | 10 ---------- .../parallel/test-buffer-tostring-rangeerror.js | 17 +++++++++++------ 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/lib/internal/blob.js b/lib/internal/blob.js index a54adb615fbc17..b68037612ab8b3 100644 --- a/lib/internal/blob.js +++ b/lib/internal/blob.js @@ -24,6 +24,9 @@ const { concat, getDataObject, } = internalBinding('blob'); +const { + kMaxLength, +} = internalBinding('buffer'); const { TextDecoder, @@ -62,7 +65,6 @@ const { } = require('internal/errors'); const { - isUint32, validateDictionary, } = require('internal/validators'); @@ -160,8 +162,8 @@ class Blob { return src; }); - if (!isUint32(length)) - throw new ERR_BUFFER_TOO_LARGE(0xFFFFFFFF); + if (length > kMaxLength) + throw new ERR_BUFFER_TOO_LARGE(kMaxLength); this[kHandle] = _createBlob(sources_, length); this[kLength] = length; diff --git a/test/parallel/test-blob-buffer-too-large.js b/test/parallel/test-blob-buffer-too-large.js index 2fd8b8754bd593..a9cf53b025bbff 100644 --- a/test/parallel/test-blob-buffer-too-large.js +++ b/test/parallel/test-blob-buffer-too-large.js @@ -3,17 +3,17 @@ const common = require('../common'); const assert = require('assert'); -const { Blob } = require('buffer'); +const { Blob, kMaxLength } = require('buffer'); if (common.isFreeBSD) common.skip('Oversized buffer make the FreeBSD CI runner crash'); try { - new Blob([new Uint8Array(0xffffffff), [1]]); + new Blob([new Uint8Array(kMaxLength), [1]]); } catch (e) { if ( e.message === 'Array buffer allocation failed' || - e.message === 'Invalid typed array length: 4294967295' + e.message === `Invalid typed array length: ${kMaxLength}` ) { common.skip( 'Insufficient memory on this platform for oversized buffer test.' diff --git a/test/parallel/test-buffer-alloc.js b/test/parallel/test-buffer-alloc.js index c6b728027057ec..aad9c6bcab69e9 100644 --- a/test/parallel/test-buffer-alloc.js +++ b/test/parallel/test-buffer-alloc.js @@ -4,13 +4,16 @@ const common = require('../common'); const assert = require('assert'); const vm = require('vm'); -const SlowBuffer = require('buffer').SlowBuffer; +const { + SlowBuffer, + kMaxLength, +} = require('buffer'); // Verify the maximum Uint8Array size. There is no concrete limit by spec. The // internal limits should be updated if this fails. assert.throws( - () => new Uint8Array(2 ** 32 + 1), - { message: 'Invalid typed array length: 4294967297' } + () => new Uint8Array(kMaxLength + 1), + { message: `Invalid typed array length: ${kMaxLength + 1}` }, ); const b = Buffer.allocUnsafe(1024); diff --git a/test/parallel/test-buffer-over-max-length.js b/test/parallel/test-buffer-over-max-length.js index d2df358cc00ca4..f29d6b62d4aa40 100644 --- a/test/parallel/test-buffer-over-max-length.js +++ b/test/parallel/test-buffer-over-max-length.js @@ -12,18 +12,8 @@ const bufferMaxSizeMsg = { name: 'RangeError', }; -assert.throws(() => Buffer((-1 >>> 0) + 2), bufferMaxSizeMsg); -assert.throws(() => SlowBuffer((-1 >>> 0) + 2), bufferMaxSizeMsg); -assert.throws(() => Buffer.alloc((-1 >>> 0) + 2), bufferMaxSizeMsg); -assert.throws(() => Buffer.allocUnsafe((-1 >>> 0) + 2), bufferMaxSizeMsg); -assert.throws(() => Buffer.allocUnsafeSlow((-1 >>> 0) + 2), bufferMaxSizeMsg); - assert.throws(() => Buffer(kMaxLength + 1), bufferMaxSizeMsg); assert.throws(() => SlowBuffer(kMaxLength + 1), bufferMaxSizeMsg); assert.throws(() => Buffer.alloc(kMaxLength + 1), bufferMaxSizeMsg); assert.throws(() => Buffer.allocUnsafe(kMaxLength + 1), bufferMaxSizeMsg); assert.throws(() => Buffer.allocUnsafeSlow(kMaxLength + 1), bufferMaxSizeMsg); - -// issue GH-4331 -assert.throws(() => Buffer.allocUnsafe(0x100000001), bufferMaxSizeMsg); -assert.throws(() => Buffer.allocUnsafe(0xFFFFFFFFF), bufferMaxSizeMsg); diff --git a/test/parallel/test-buffer-tostring-rangeerror.js b/test/parallel/test-buffer-tostring-rangeerror.js index d2e1e0d6e46438..0ebea759b5c42b 100644 --- a/test/parallel/test-buffer-tostring-rangeerror.js +++ b/test/parallel/test-buffer-tostring-rangeerror.js @@ -1,17 +1,22 @@ 'use strict'; require('../common'); -// This test ensures that Node.js throws a RangeError when trying to convert a -// gigantic buffer into a string. +// This test ensures that Node.js throws an Error when trying to convert a +// large buffer into a string. // Regression test for https://github.com/nodejs/node/issues/649. const assert = require('assert'); -const SlowBuffer = require('buffer').SlowBuffer; +const { + SlowBuffer, + constants: { + MAX_STRING_LENGTH, + }, +} = require('buffer'); -const len = 1422561062959; +const len = MAX_STRING_LENGTH + 1; const message = { - code: 'ERR_OUT_OF_RANGE', - name: 'RangeError', + code: 'ERR_STRING_TOO_LONG', + name: 'Error', }; assert.throws(() => Buffer(len).toString('utf8'), message); assert.throws(() => SlowBuffer(len).toString('utf8'), message); From e28dbe1c2bcbd0d4eb82f22823ee045a2a8466eb Mon Sep 17 00:00:00 2001 From: Khafra Date: Thu, 28 Sep 2023 09:01:30 -0400 Subject: [PATCH 4/9] lib: add WebSocket client fixup add test lint fixup update doc/node.1 PR-URL: https://github.com/nodejs/node/pull/49830 Reviewed-By: Matteo Collina Reviewed-By: Robert Nagy --- .eslintrc.js | 1 + doc/api/cli.md | 10 ++++++ doc/api/globals.md | 13 ++++++++ doc/node.1 | 3 ++ lib/internal/process/pre_execution.js | 48 ++++++++++++++++----------- src/node_options.cc | 5 +++ src/node_options.h | 1 + test/common/globals.js | 1 + test/common/index.js | 3 ++ test/parallel/test-websocket.js | 7 ++++ 10 files changed, 72 insertions(+), 20 deletions(-) create mode 100644 test/parallel/test-websocket.js diff --git a/.eslintrc.js b/.eslintrc.js index f46a64bcbf2acd..8b462e0777c5d4 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -361,5 +361,6 @@ module.exports = { WritableStream: 'readable', WritableStreamDefaultWriter: 'readable', WritableStreamDefaultController: 'readable', + WebSocket: 'readable', }, }; diff --git a/doc/api/cli.md b/doc/api/cli.md index 1da38c1739126b..013256d776bac7 100644 --- a/doc/api/cli.md +++ b/doc/api/cli.md @@ -738,6 +738,14 @@ added: v12.3.0 Enable experimental WebAssembly module support. +### `--experimental-websocket` + + + +Enable experimental [`WebSocket`][] support. + ### `--force-context-aware` + +> Stability: 1 - Experimental. + +A browser-compatible implementation of [`WebSocket`][]. Enable this API +with the [`--experimental-websocket`][] CLI flag. + ## Class: `WritableStream` diff --git a/tools/doc/allhtml.mjs b/tools/doc/allhtml.mjs index cdf7140f728469..ccf3a10ea7f95b 100644 --- a/tools/doc/allhtml.mjs +++ b/tools/doc/allhtml.mjs @@ -27,7 +27,7 @@ for (const link of toc.match(//g)) { const data = fs.readFileSync(new URL(`./${href}`, source), 'utf8'); // Split the doc. - const match = /(<\/ul>\s*)?<\/\w+>\s*<\w+ id="apicontent">/.exec(data); + const match = /(<\/ul>\s*)?<\/\w+>\s*<\w+ role="main" id="apicontent">/.exec(data); // Get module name const moduleName = href.replace(/\.html$/, ''); @@ -89,7 +89,7 @@ all = all.slice(0, tocStart.index + tocStart[0].length) + all.slice(tocStart.index + tocStart[0].length); // Replace apicontent with the concatenated set of apicontents from each source. -const apiStart = /<\w+ id="apicontent">\s*/.exec(all); +const apiStart = /<\w+ role="main" id="apicontent">\s*/.exec(all); const apiEnd = all.lastIndexOf(''); all = all.slice(0, apiStart.index + apiStart[0].length) .replace( From 7f06c270c6a423e62e997650832f91a7ed96c5e4 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Tue, 26 Sep 2023 10:54:02 -0700 Subject: [PATCH 9/9] tools: add navigation ARIA landmark to generated API ToC As an accessibility improvement, specify the navigation landmark for the element of our docs that contains the table of contents generated for the specific API page. Ref: https://www.w3.org/WAI/ARIA/apg/practices/landmark-regions/ Ref: https://www.w3.org/WAI/WCAG21/Techniques/aria/ARIA20.html PR-URL: https://github.com/nodejs/node/pull/49882 Reviewed-By: Luigi Pinca Reviewed-By: Claudio Wunder Reviewed-By: LiviaMedeiros --- tools/doc/html.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/doc/html.mjs b/tools/doc/html.mjs index 168f68c1b03f21..95782efe03d554 100644 --- a/tools/doc/html.mjs +++ b/tools/doc/html.mjs @@ -467,7 +467,7 @@ export function buildToc({ filename, apilinks }) { .use(htmlStringify) .processSync(toc).toString(); - file.toc = `
Table of contents${inner}
`; + file.toc = ``; file.tocPicker = `
${inner}
`; } else { file.toc = file.tocPicker = '';