diff --git a/COLLABORATOR_GUIDE.md b/COLLABORATOR_GUIDE.md index 5a1d51dafe375c..95ef0653552c1e 100644 --- a/COLLABORATOR_GUIDE.md +++ b/COLLABORATOR_GUIDE.md @@ -368,7 +368,10 @@ Node.js uses three Deprecation levels: being staged for deprecation in a future Node.js major release. An explicit notice indicating the deprecated status is added to the API documentation but no functional changes are implemented in the code. There will be no - runtime deprecation warnings emitted for such deprecations. + runtime deprecation warnings emitted for such deprecations by default. + Documentation-only deprecations may trigger a runtime warning when launched + with [`--pending-deprecation`][] flag (or its alternative, + `NODE_PENDING_DEPRECATION=1` environment variable). * *Runtime Deprecation* refers to the use of process warnings emitted at runtime the first time that a deprecated API is used. A command-line @@ -593,20 +596,20 @@ Validate that the commit message is properly formatted using $ git rev-list upstream/master...HEAD | xargs core-validate-commit ``` +Optional: When landing your own commits, force push the amended commit to the +branch you used to open the pull request. If your branch is called `bugfix`, +then the command would be `git push --force-with-lease origin master:bugfix`. +When the pull request is closed, this will cause the pull request to +show the purple merged status rather than the red closed status that is +usually used for pull requests that weren't merged. + Time to push it: ```text $ git push upstream master ``` -* Optional: Force push the amended commit to the branch you used to -open the pull request. If your branch is called `bugfix`, then the -command would be `git push --force-with-lease origin master:bugfix`. -When the pull request is closed, this will cause the pull request to -show the purple merged status rather than the red closed status that is -usually used for pull requests that weren't merged. Only do this when -landing your own contributions. -* Close the pull request with a "Landed in ``" comment. If +Close the pull request with a "Landed in ``" comment. If your pull request shows the purple merged status then you should still add the "Landed in .." comment if you added multiple commits. @@ -744,6 +747,7 @@ LTS working group and the Release team. [backporting guide]: doc/guides/backporting-to-release-lines.md [Stability Index]: doc/api/documentation.md#stability-index [Enhancement Proposal]: https://github.com/nodejs/node-eps +[`--pending-deprecation`]: doc/api/cli.md#--pending-deprecation [git-username]: https://help.github.com/articles/setting-your-username-in-git/ [`node-core-utils`]: https://github.com/nodejs/node-core-utils [TSC]: https://github.com/nodejs/TSC diff --git a/Makefile b/Makefile index eaebe4f2b55a4b..d7158eed378f97 100644 --- a/Makefile +++ b/Makefile @@ -616,7 +616,7 @@ doc-only: $(apidoc_dirs) $(apiassets) ## Builds the docs with the local or the if [ ! -d doc/api/assets ]; then \ $(MAKE) tools/doc/node_modules/js-yaml/package.json; \ fi; - @$(MAKE) -s $(apidocs_html) $(apidocs_json) + @$(MAKE) $(apidocs_html) $(apidocs_json) .PHONY: doc doc: $(NODE_EXE) doc-only @@ -1183,6 +1183,7 @@ lint: ## Run JS, C++, MD and doc linters. $(MAKE) lint-js || EXIT_STATUS=$$? ; \ $(MAKE) lint-cpp || EXIT_STATUS=$$? ; \ $(MAKE) lint-addon-docs || EXIT_STATUS=$$? ; \ + $(MAKE) lint-md || EXIT_STATUS=$$? ; \ exit $$EXIT_STATUS CONFLICT_RE=^>>>>>>> [0-9A-Fa-f]+|^<<<<<<< [A-Za-z]+ diff --git a/README.md b/README.md index 47b8694797637b..714fde2c143cf7 100644 --- a/README.md +++ b/README.md @@ -7,10 +7,9 @@

-Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine. Node.js -uses an event-driven, non-blocking I/O model that makes it lightweight and -efficient. The Node.js package ecosystem, [npm][], is the largest ecosystem of -open source libraries in the world. +Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine. For +more information on using Node.js, see the +[Node.js Website][]. The Node.js project is supported by the [Node.js Foundation](https://nodejs.org/en/foundation/). Contributions, @@ -245,6 +244,8 @@ For more information about the governance of the Node.js project, see **Franziska Hinkelmann** <franziska.hinkelmann@gmail.com> (she/her) * [Fishrock123](https://github.com/Fishrock123) - **Jeremiah Senkpiel** <fishrock123@rocketmail.com> +* [gibfahn](https://github.com/gibfahn) - +**Gibson Fahnestock** <gibfahn@gmail.com> (he/him) * [indutny](https://github.com/indutny) - **Fedor Indutny** <fedor.indutny@gmail.com> * [jasnell](https://github.com/jasnell) - @@ -255,8 +256,6 @@ For more information about the governance of the Node.js project, see **Matteo Collina** <matteo.collina@gmail.com> (he/him) * [mhdawson](https://github.com/mhdawson) - **Michael Dawson** <michael_dawson@ca.ibm.com> (he/him) -* [mscdex](https://github.com/mscdex) - -**Brian White** <mscdex@mscdex.net> * [MylesBorins](https://github.com/MylesBorins) - **Myles Borins** <myles.borins@gmail.com> (he/him) * [ofrobots](https://github.com/ofrobots) - @@ -282,6 +281,8 @@ For more information about the governance of the Node.js project, see **Isaac Z. Schlueter** <i@izs.me> * [joshgav](https://github.com/joshgav) - **Josh Gavant** <josh.gavant@outlook.com> +* [mscdex](https://github.com/mscdex) - +**Brian White** <mscdex@mscdex.net> * [nebrius](https://github.com/nebrius) - **Bryan Hughes** <bryan@nebri.us> * [orangemocha](https://github.com/orangemocha) - @@ -339,6 +340,8 @@ For more information about the governance of the Node.js project, see **Daniel Bevenius** <daniel.bevenius@gmail.com> * [DavidCai1993](https://github.com/DavidCai1993) - **David Cai** <davidcai1993@yahoo.com> (he/him) +* [devsnek](https://github.com/devsnek) - +**Gus Caplan** <me@gus.host> (he/him) * [edsadr](https://github.com/edsadr) - **Adrian Estrada** <edsadr@gmail.com> (he/him) * [eljefedelrodeodeljefe](https://github.com/eljefedelrodeodeljefe) - @@ -590,12 +593,13 @@ Previous releases may also have been signed with one of the following GPG keys: * [Contributing to the project][] * [Working Groups][] +* [Strategic Initiatives][] -[npm]: https://www.npmjs.com [Code of Conduct]: https://github.com/nodejs/admin/blob/master/CODE_OF_CONDUCT.md [Contributing to the project]: CONTRIBUTING.md [Node.js Help]: https://github.com/nodejs/help [Node.js Website]: https://nodejs.org/en/ [Questions tagged 'node.js' on StackOverflow]: https://stackoverflow.com/questions/tagged/node.js [Working Groups]: https://github.com/nodejs/TSC/blob/master/WORKING_GROUPS.md +[Strategic Initiatives]: https://github.com/nodejs/TSC/blob/master/Strategic-Initiatives.md [#node.js channel on chat.freenode.net]: https://webchat.freenode.net?channels=node.js&uio=d4 diff --git a/benchmark/_http-benchmarkers.js b/benchmark/_http-benchmarkers.js index 55ebcc96ba21ed..76e02504b27ec1 100644 --- a/benchmark/_http-benchmarkers.js +++ b/benchmark/_http-benchmarkers.js @@ -185,7 +185,7 @@ exports.run = function(options, callback) { port: exports.PORT, path: '/', connections: 100, - duration: 10, + duration: 5, benchmarker: exports.default_http_benchmarker }, options); if (!options.benchmarker) { diff --git a/benchmark/assert/deepequal-buffer.js b/benchmark/assert/deepequal-buffer.js index 0e7494544d3387..9556a81ec3b151 100644 --- a/benchmark/assert/deepequal-buffer.js +++ b/benchmark/assert/deepequal-buffer.js @@ -14,8 +14,6 @@ const bench = common.createBenchmark(main, { }); function main({ len, n, method }) { - var i; - const data = Buffer.allocUnsafe(len + 1); const actual = Buffer.alloc(len); const expected = Buffer.alloc(len); @@ -24,40 +22,13 @@ function main({ len, n, method }) { data.copy(expected); data.copy(expectedWrong); - switch (method) { - case '': - // Empty string falls through to next line as default, mostly for tests. - case 'deepEqual': - bench.start(); - for (i = 0; i < n; ++i) { - // eslint-disable-next-line no-restricted-properties - assert.deepEqual(actual, expected); - } - bench.end(n); - break; - case 'deepStrictEqual': - bench.start(); - for (i = 0; i < n; ++i) { - assert.deepStrictEqual(actual, expected); - } - bench.end(n); - break; - case 'notDeepEqual': - bench.start(); - for (i = 0; i < n; ++i) { - // eslint-disable-next-line no-restricted-properties - assert.notDeepEqual(actual, expectedWrong); - } - bench.end(n); - break; - case 'notDeepStrictEqual': - bench.start(); - for (i = 0; i < n; ++i) { - assert.notDeepStrictEqual(actual, expectedWrong); - } - bench.end(n); - break; - default: - throw new Error('Unsupported method'); + // eslint-disable-next-line no-restricted-properties + const fn = method !== '' ? assert[method] : assert.deepEqual; + const value2 = method.includes('not') ? expectedWrong : expected; + + bench.start(); + for (var i = 0; i < n; ++i) { + fn(actual, value2); } + bench.end(n); } diff --git a/benchmark/assert/deepequal-map.js b/benchmark/assert/deepequal-map.js index 085274e8bfb943..bdd3c5c6b8c514 100644 --- a/benchmark/assert/deepequal-map.js +++ b/benchmark/assert/deepequal-map.js @@ -117,6 +117,6 @@ function main({ n, len, method }) { benchmark(assert.notDeepEqual, n, values, values2); break; default: - throw new Error('Unsupported method'); + throw new Error(`Unsupported method ${method}`); } } diff --git a/benchmark/assert/deepequal-object.js b/benchmark/assert/deepequal-object.js index 2c2549d58485fc..4c95006b3b8bc7 100644 --- a/benchmark/assert/deepequal-object.js +++ b/benchmark/assert/deepequal-object.js @@ -28,47 +28,19 @@ function createObj(source, add = '') { function main({ size, n, method }) { // TODO: Fix this "hack". `n` should not be manipulated. n = n / size; - var i; const source = Array.apply(null, Array(size)); const actual = createObj(source); const expected = createObj(source); const expectedWrong = createObj(source, '4'); - switch (method) { - case '': - // Empty string falls through to next line as default, mostly for tests. - case 'deepEqual': - bench.start(); - for (i = 0; i < n; ++i) { - // eslint-disable-next-line no-restricted-properties - assert.deepEqual(actual, expected); - } - bench.end(n); - break; - case 'deepStrictEqual': - bench.start(); - for (i = 0; i < n; ++i) { - assert.deepStrictEqual(actual, expected); - } - bench.end(n); - break; - case 'notDeepEqual': - bench.start(); - for (i = 0; i < n; ++i) { - // eslint-disable-next-line no-restricted-properties - assert.notDeepEqual(actual, expectedWrong); - } - bench.end(n); - break; - case 'notDeepStrictEqual': - bench.start(); - for (i = 0; i < n; ++i) { - assert.notDeepStrictEqual(actual, expectedWrong); - } - bench.end(n); - break; - default: - throw new Error('Unsupported method'); + // eslint-disable-next-line no-restricted-properties + const fn = method !== '' ? assert[method] : assert.deepEqual; + const value2 = method.includes('not') ? expectedWrong : expected; + + bench.start(); + for (var i = 0; i < n; ++i) { + fn(actual, value2); } + bench.end(n); } diff --git a/benchmark/assert/deepequal-prims-and-objs-big-array-set.js b/benchmark/assert/deepequal-prims-and-objs-big-array-set.js index 04802a76928cb2..90dbf1059361a5 100644 --- a/benchmark/assert/deepequal-prims-and-objs-big-array-set.js +++ b/benchmark/assert/deepequal-prims-and-objs-big-array-set.js @@ -30,12 +30,19 @@ const bench = common.createBenchmark(main, { ] }); +function run(fn, n, actual, expected) { + bench.start(); + for (var i = 0; i < n; ++i) { + fn(actual, expected); + } + bench.end(n); +} + function main({ n, len, primitive, method }) { const prim = primValues[primitive]; const actual = []; const expected = []; const expectedWrong = []; - var i; for (var x = 0; x < len; x++) { actual.push(prim); @@ -51,69 +58,37 @@ function main({ n, len, primitive, method }) { const expectedWrongSet = new Set(expectedWrong); switch (method) { + // Empty string falls through to next line as default, mostly for tests. case '': - // Empty string falls through to next line as default, mostly for tests. case 'deepEqual_Array': - bench.start(); - for (i = 0; i < n; ++i) { - // eslint-disable-next-line no-restricted-properties - assert.deepEqual(actual, expected); - } - bench.end(n); + // eslint-disable-next-line no-restricted-properties + run(assert.deepEqual, n, actual, expected); break; case 'deepStrictEqual_Array': - bench.start(); - for (i = 0; i < n; ++i) { - assert.deepStrictEqual(actual, expected); - } - bench.end(n); + run(assert.deepStrictEqual, n, actual, expected); break; case 'notDeepEqual_Array': - bench.start(); - for (i = 0; i < n; ++i) { - // eslint-disable-next-line no-restricted-properties - assert.notDeepEqual(actual, expectedWrong); - } - bench.end(n); + // eslint-disable-next-line no-restricted-properties + run(assert.notDeepEqual, n, actual, expectedWrong); break; case 'notDeepStrictEqual_Array': - bench.start(); - for (i = 0; i < n; ++i) { - assert.notDeepStrictEqual(actual, expectedWrong); - } - bench.end(n); + run(assert.notDeepStrictEqual, n, actual, expectedWrong); break; case 'deepEqual_Set': - bench.start(); - for (i = 0; i < n; ++i) { - // eslint-disable-next-line no-restricted-properties - assert.deepEqual(actualSet, expectedSet); - } - bench.end(n); + // eslint-disable-next-line no-restricted-properties + run(assert.deepEqual, n, actualSet, expectedSet); break; case 'deepStrictEqual_Set': - bench.start(); - for (i = 0; i < n; ++i) { - assert.deepStrictEqual(actualSet, expectedSet); - } - bench.end(n); + run(assert.deepStrictEqual, n, actualSet, expectedSet); break; case 'notDeepEqual_Set': - bench.start(); - for (i = 0; i < n; ++i) { - // eslint-disable-next-line no-restricted-properties - assert.notDeepEqual(actualSet, expectedWrongSet); - } - bench.end(n); + // eslint-disable-next-line no-restricted-properties + run(assert.notDeepEqual, n, actualSet, expectedWrongSet); break; case 'notDeepStrictEqual_Set': - bench.start(); - for (i = 0; i < n; ++i) { - assert.notDeepStrictEqual(actualSet, expectedWrongSet); - } - bench.end(n); + run(assert.notDeepStrictEqual, n, actualSet, expectedWrongSet); break; default: - throw new Error('Unsupported method'); + throw new Error(`Unsupported method "${method}"`); } } diff --git a/benchmark/assert/deepequal-prims-and-objs-big-loop.js b/benchmark/assert/deepequal-prims-and-objs-big-loop.js index 09797dfaf2df21..ec51201d51839d 100644 --- a/benchmark/assert/deepequal-prims-and-objs-big-loop.js +++ b/benchmark/assert/deepequal-prims-and-objs-big-loop.js @@ -29,43 +29,14 @@ function main({ n, primitive, method }) { const actual = prim; const expected = prim; const expectedWrong = 'b'; - var i; - // Creates new array to avoid loop invariant code motion - switch (method) { - case '': - // Empty string falls through to next line as default, mostly for tests. - case 'deepEqual': - bench.start(); - for (i = 0; i < n; ++i) { - // eslint-disable-next-line no-restricted-properties - assert.deepEqual([actual], [expected]); - } - bench.end(n); - break; - case 'deepStrictEqual': - bench.start(); - for (i = 0; i < n; ++i) { - assert.deepStrictEqual([actual], [expected]); - } - bench.end(n); - break; - case 'notDeepEqual': - bench.start(); - for (i = 0; i < n; ++i) { - // eslint-disable-next-line no-restricted-properties - assert.notDeepEqual([actual], [expectedWrong]); - } - bench.end(n); - break; - case 'notDeepStrictEqual': - bench.start(); - for (i = 0; i < n; ++i) { - assert.notDeepStrictEqual([actual], [expectedWrong]); - } - bench.end(n); - break; - default: - throw new Error('Unsupported method'); + // eslint-disable-next-line no-restricted-properties + const fn = method !== '' ? assert[method] : assert.deepEqual; + const value2 = method.includes('not') ? expectedWrong : expected; + + bench.start(); + for (var i = 0; i < n; ++i) { + fn([actual], [value2]); } + bench.end(n); } diff --git a/benchmark/assert/deepequal-set.js b/benchmark/assert/deepequal-set.js index ebcf33cc6d5254..e70ddf10e93626 100644 --- a/benchmark/assert/deepequal-set.js +++ b/benchmark/assert/deepequal-set.js @@ -126,6 +126,6 @@ function main({ n, len, method }) { benchmark(assert.notDeepEqual, n, values, values2); break; default: - throw new Error('Unsupported method'); + throw new Error(`Unsupported method "${method}"`); } } diff --git a/benchmark/assert/deepequal-typedarrays.js b/benchmark/assert/deepequal-typedarrays.js index 01546801ff3004..50e6e525b20a0c 100644 --- a/benchmark/assert/deepequal-typedarrays.js +++ b/benchmark/assert/deepequal-typedarrays.js @@ -31,42 +31,14 @@ function main({ type, n, len, method }) { const expectedWrong = Buffer.alloc(len); const wrongIndex = Math.floor(len / 2); expectedWrong[wrongIndex] = 123; - var i; - switch (method) { - case '': - // Empty string falls through to next line as default, mostly for tests. - case 'deepEqual': - bench.start(); - for (i = 0; i < n; ++i) { - // eslint-disable-next-line no-restricted-properties - assert.deepEqual(actual, expected); - } - bench.end(n); - break; - case 'deepStrictEqual': - bench.start(); - for (i = 0; i < n; ++i) { - assert.deepStrictEqual(actual, expected); - } - bench.end(n); - break; - case 'notDeepEqual': - bench.start(); - for (i = 0; i < n; ++i) { - // eslint-disable-next-line no-restricted-properties - assert.notDeepEqual(actual, expectedWrong); - } - bench.end(n); - break; - case 'notDeepStrictEqual': - bench.start(); - for (i = 0; i < n; ++i) { - assert.notDeepStrictEqual(actual, expectedWrong); - } - bench.end(n); - break; - default: - throw new Error('Unsupported method'); + // eslint-disable-next-line no-restricted-properties + const fn = method !== '' ? assert[method] : assert.deepEqual; + const value2 = method.includes('not') ? expectedWrong : expected; + + bench.start(); + for (var i = 0; i < n; ++i) { + fn(actual, value2); } + bench.end(n); } diff --git a/benchmark/async_hooks/gc-tracking.js b/benchmark/async_hooks/gc-tracking.js index a569fb8fa92485..d74b2bac463e28 100644 --- a/benchmark/async_hooks/gc-tracking.js +++ b/benchmark/async_hooks/gc-tracking.js @@ -22,22 +22,23 @@ function endAfterGC(n) { } function main({ n, method }) { + var i; switch (method) { case 'trackingEnabled': bench.start(); - for (let i = 0; i < n; i++) { + for (i = 0; i < n; i++) { new AsyncResource('foobar'); } endAfterGC(n); break; case 'trackingDisabled': bench.start(); - for (let i = 0; i < n; i++) { + for (i = 0; i < n; i++) { new AsyncResource('foobar', { requireManualDestroy: true }); } endAfterGC(n); break; default: - throw new Error('Unsupported method'); + throw new Error(`Unsupported method "${method}"`); } } diff --git a/benchmark/buffers/buffer-bytelength.js b/benchmark/buffers/buffer-bytelength.js index 0617b4feb3f140..fa8852a233ea88 100644 --- a/benchmark/buffers/buffer-bytelength.js +++ b/benchmark/buffers/buffer-bytelength.js @@ -17,10 +17,9 @@ const chars = [ function main({ n, len, encoding }) { var strings = []; - var results; + var results = [ len * 16 ]; if (encoding === 'buffer') { strings = [ Buffer.alloc(len * 16, 'a') ]; - results = [ len * 16 ]; } else { for (const string of chars) { // Strings must be built differently, depending on encoding diff --git a/benchmark/buffers/buffer-compare-offset.js b/benchmark/buffers/buffer-compare-offset.js index 850fe11d3f429e..551fcd2f0cec37 100644 --- a/benchmark/buffers/buffer-compare-offset.js +++ b/benchmark/buffers/buffer-compare-offset.js @@ -8,26 +8,22 @@ const bench = common.createBenchmark(main, { }); function compareUsingSlice(b0, b1, len, iter) { - var i; - bench.start(); - for (i = 0; i < iter; i++) + for (var i = 0; i < iter; i++) Buffer.compare(b0.slice(1, len), b1.slice(1, len)); - bench.end(iter / 1e6); } function compareUsingOffset(b0, b1, len, iter) { - var i; - bench.start(); - for (i = 0; i < iter; i++) + for (var i = 0; i < iter; i++) b0.compare(b1, 1, len, 1, len); - bench.end(iter / 1e6); } function main({ millions, size, method }) { const iter = millions * 1e6; const fn = method === 'slice' ? compareUsingSlice : compareUsingOffset; + bench.start(); fn(Buffer.alloc(size, 'a'), Buffer.alloc(size, 'b'), size >> 1, iter); + bench.end(millions); } diff --git a/benchmark/buffers/buffer-creation.js b/benchmark/buffers/buffer-creation.js index 73e620955e91db..a7b340131eb8aa 100644 --- a/benchmark/buffers/buffer-creation.js +++ b/benchmark/buffers/buffer-creation.js @@ -16,51 +16,38 @@ const bench = common.createBenchmark(main, { }); function main({ len, n, type }) { + let fn, i; switch (type) { case '': case 'fast-alloc': - bench.start(); - for (let i = 0; i < n * 1024; i++) { - Buffer.alloc(len); - } - bench.end(n); + fn = Buffer.alloc; break; case 'fast-alloc-fill': bench.start(); - for (let i = 0; i < n * 1024; i++) { + for (i = 0; i < n * 1024; i++) { Buffer.alloc(len, 0); } bench.end(n); - break; + return; case 'fast-allocUnsafe': - bench.start(); - for (let i = 0; i < n * 1024; i++) { - Buffer.allocUnsafe(len); - } - bench.end(n); + fn = Buffer.allocUnsafe; break; case 'slow-allocUnsafe': - bench.start(); - for (let i = 0; i < n * 1024; i++) { - Buffer.allocUnsafeSlow(len); - } - bench.end(n); + fn = Buffer.allocUnsafeSlow; break; case 'slow': - bench.start(); - for (let i = 0; i < n * 1024; i++) { - SlowBuffer(len); - } - bench.end(n); + fn = SlowBuffer; break; case 'buffer()': - bench.start(); - for (let i = 0; i < n * 1024; i++) { - Buffer(len); - } - bench.end(n); + fn = Buffer; break; default: - assert.fail(null, null, 'Should not get here'); + assert.fail('Should not get here'); + } + + bench.start(); + for (i = 0; i < n * 1024; i++) { + fn(len); } + bench.end(n); } diff --git a/benchmark/buffers/buffer-hex.js b/benchmark/buffers/buffer-hex.js index 1bdef81139ffe7..4d87313961aa67 100644 --- a/benchmark/buffers/buffer-hex.js +++ b/benchmark/buffers/buffer-hex.js @@ -9,15 +9,16 @@ const bench = common.createBenchmark(main, { function main({ len, n }) { const buf = Buffer.alloc(len); + var i; - for (let i = 0; i < buf.length; i++) + for (i = 0; i < buf.length; i++) buf[i] = i & 0xff; const hex = buf.toString('hex'); bench.start(); - for (let i = 0; i < n; i += 1) + for (i = 0; i < n; i += 1) Buffer.from(hex, 'hex'); bench.end(n); diff --git a/benchmark/buffers/buffer-iterate.js b/benchmark/buffers/buffer-iterate.js index 8531e1cae82115..7a275b0bcb8182 100644 --- a/benchmark/buffers/buffer-iterate.js +++ b/benchmark/buffers/buffer-iterate.js @@ -20,36 +20,30 @@ function main({ size, type, method, n }) { const clazz = type === 'fast' ? Buffer : SlowBuffer; const buffer = new clazz(size); buffer.fill(0); - methods[method || 'for'](buffer, n); -} - + const fn = methods[method || 'for']; -function benchFor(buffer, n) { bench.start(); + fn(buffer, n); + bench.end(n); +} +function benchFor(buffer, n) { for (var k = 0; k < n; k++) { for (var i = 0; i < buffer.length; i++) { assert(buffer[i] === 0); } } - - bench.end(n); } function benchForOf(buffer, n) { - bench.start(); - for (var k = 0; k < n; k++) { for (const b of buffer) { assert(b === 0); } } - bench.end(n); } function benchIterator(buffer, n) { - bench.start(); - for (var k = 0; k < n; k++) { const iter = buffer[Symbol.iterator](); var cur = iter.next(); @@ -60,6 +54,4 @@ function benchIterator(buffer, n) { } } - - bench.end(n); } diff --git a/benchmark/buffers/buffer-read-float.js b/benchmark/buffers/buffer-read-float.js index 5dda2486c6711a..afd9edf5578308 100644 --- a/benchmark/buffers/buffer-read-float.js +++ b/benchmark/buffers/buffer-read-float.js @@ -9,12 +9,10 @@ const bench = common.createBenchmark(main, { millions: [1] }); -function main(conf) { - const noAssert = conf.noAssert === 'true'; - const len = +conf.millions * 1e6; +function main({ noAssert, millions, type, endian, value }) { + noAssert = noAssert === 'true'; + type = type || 'Double'; const buff = Buffer.alloc(8); - const type = conf.type || 'Double'; - const endian = conf.endian; const fn = `read${type}${endian}`; const values = { Double: { @@ -32,15 +30,12 @@ function main(conf) { nan: NaN, }, }; - const value = values[type][conf.value]; - buff[`write${type}${endian}`](value, 0, noAssert); - const testFunction = new Function('buff', ` - for (var i = 0; i !== ${len}; i++) { - buff.${fn}(0, ${JSON.stringify(noAssert)}); - } - `); + buff[`write${type}${endian}`](values[type][value], 0, noAssert); + bench.start(); - testFunction(buff); - bench.end(len / 1e6); + for (var i = 0; i !== millions * 1e6; i++) { + buff[fn](0, noAssert); + } + bench.end(millions); } diff --git a/benchmark/buffers/buffer-read.js b/benchmark/buffers/buffer-read.js index 41e842f3123623..868f5cede8bd2d 100644 --- a/benchmark/buffers/buffer-read.js +++ b/benchmark/buffers/buffer-read.js @@ -27,18 +27,14 @@ const bench = common.createBenchmark(main, { function main({ noAssert, millions, buf, type }) { noAssert = noAssert === 'true'; - const len = millions * 1e6; const clazz = buf === 'fast' ? Buffer : require('buffer').SlowBuffer; const buff = new clazz(8); const fn = `read${type || 'UInt8'}`; buff.writeDoubleLE(0, 0, noAssert); - const testFunction = new Function('buff', ` - for (var i = 0; i !== ${len}; i++) { - buff.${fn}(0, ${JSON.stringify(noAssert)}); - } - `); bench.start(); - testFunction(buff); - bench.end(len / 1e6); + for (var i = 0; i !== millions * 1e6; i++) { + buff[fn](0, noAssert); + } + bench.end(millions); } diff --git a/benchmark/buffers/buffer-write.js b/benchmark/buffers/buffer-write.js index ce2fbe3103cb83..823e95bf15d704 100644 --- a/benchmark/buffers/buffer-write.js +++ b/benchmark/buffers/buffer-write.js @@ -46,36 +46,29 @@ const mod = { }; function main({ noAssert, millions, buf, type }) { - const len = millions * 1e6; const clazz = buf === 'fast' ? Buffer : require('buffer').SlowBuffer; const buff = new clazz(8); const fn = `write${type || 'UInt8'}`; if (/Int/.test(fn)) - benchInt(buff, fn, len, noAssert); + benchInt(buff, fn, millions, noAssert); else - benchFloat(buff, fn, len, noAssert); + benchFloat(buff, fn, millions, noAssert); } -function benchInt(buff, fn, len, noAssert) { +function benchInt(buff, fn, millions, noAssert) { const m = mod[fn]; - const testFunction = new Function('buff', ` - for (var i = 0; i !== ${len}; i++) { - buff.${fn}(i & ${m}, 0, ${noAssert}); - } - `); bench.start(); - testFunction(buff); - bench.end(len / 1e6); + for (var i = 0; i !== millions * 1e6; i++) { + buff[fn](i & m, 0, noAssert); + } + bench.end(millions); } -function benchFloat(buff, fn, len, noAssert) { - const testFunction = new Function('buff', ` - for (var i = 0; i !== ${len}; i++) { - buff.${fn}(i, 0, ${noAssert}); - } - `); +function benchFloat(buff, fn, millions, noAssert) { bench.start(); - testFunction(buff); - bench.end(len / 1e6); + for (var i = 0; i !== millions * 1e6; i++) { + buff[fn](i, 0, noAssert); + } + bench.end(millions); } diff --git a/benchmark/buffers/buffer_zero.js b/benchmark/buffers/buffer_zero.js index 06b68c313f1241..1263732dce8e43 100644 --- a/benchmark/buffers/buffer_zero.js +++ b/benchmark/buffers/buffer_zero.js @@ -11,12 +11,9 @@ const zeroBuffer = Buffer.alloc(0); const zeroString = ''; function main({ n, type }) { - bench.start(); - - if (type === 'buffer') - for (let i = 0; i < n * 1024; i++) Buffer.from(zeroBuffer); - else if (type === 'string') - for (let i = 0; i < n * 1024; i++) Buffer.from(zeroString); + const data = type === 'buffer' ? zeroBuffer : zeroString; + bench.start(); + for (var i = 0; i < n * 1024; i++) Buffer.from(data); bench.end(n); } diff --git a/benchmark/compare.js b/benchmark/compare.js index 6b51a70eb9a41b..e7866b60e36418 100644 --- a/benchmark/compare.js +++ b/benchmark/compare.js @@ -1,6 +1,7 @@ 'use strict'; -const fork = require('child_process').fork; +const { fork } = require('child_process'); +const { inspect } = require('util'); const path = require('path'); const CLI = require('./_cli.js'); const BenchmarkProgress = require('./_benchmark_progress.js'); @@ -76,7 +77,7 @@ if (showProgress) { // Construct configuration string, " A=a, B=b, ..." let conf = ''; for (const key of Object.keys(data.conf)) { - conf += ` ${key}=${JSON.stringify(data.conf[key])}`; + conf += ` ${key}=${inspect(data.conf[key])}`; } conf = conf.slice(1); // Escape quotes (") for correct csv formatting diff --git a/benchmark/crypto/aes-gcm-throughput.js b/benchmark/crypto/aes-gcm-throughput.js index 246455de78ad88..5c1e71e7280575 100644 --- a/benchmark/crypto/aes-gcm-throughput.js +++ b/benchmark/crypto/aes-gcm-throughput.js @@ -8,13 +8,13 @@ const bench = common.createBenchmark(main, { len: [1024, 4 * 1024, 16 * 1024, 64 * 1024, 256 * 1024, 1024 * 1024] }); -function main(conf) { - const message = Buffer.alloc(conf.len, 'b'); - const key = crypto.randomBytes(keylen[conf.cipher]); +function main({ n, len, cipher }) { + const message = Buffer.alloc(len, 'b'); + const key = crypto.randomBytes(keylen[cipher]); const iv = crypto.randomBytes(12); const associate_data = Buffer.alloc(16, 'z'); bench.start(); - AEAD_Bench(conf.cipher, message, associate_data, key, iv, conf.n, conf.len); + AEAD_Bench(cipher, message, associate_data, key, iv, n, len); } function AEAD_Bench(cipher, message, associate_data, key, iv, n, len) { diff --git a/benchmark/crypto/cipher-stream.js b/benchmark/crypto/cipher-stream.js index ca36bd736d9aea..64f6ff7b7292be 100644 --- a/benchmark/crypto/cipher-stream.js +++ b/benchmark/crypto/cipher-stream.js @@ -9,8 +9,7 @@ const bench = common.createBenchmark(main, { api: ['legacy', 'stream'] }); -function main(conf) { - var api = conf.api; +function main({ api, cipher, type, len, writes }) { if (api === 'stream' && /^v0\.[0-8]\./.test(process.version)) { console.error('Crypto streams not available until v0.10'); // use the legacy, just so that we can compare them. @@ -33,25 +32,25 @@ function main(conf) { // alice_secret and bob_secret should be the same assert(alice_secret === bob_secret); - const alice_cipher = crypto.createCipher(conf.cipher, alice_secret); - const bob_cipher = crypto.createDecipher(conf.cipher, bob_secret); + const alice_cipher = crypto.createCipher(cipher, alice_secret); + const bob_cipher = crypto.createDecipher(cipher, bob_secret); var message; var encoding; - switch (conf.type) { + switch (type) { case 'asc': - message = 'a'.repeat(conf.len); + message = 'a'.repeat(len); encoding = 'ascii'; break; case 'utf': - message = 'ü'.repeat(conf.len / 2); + message = 'ü'.repeat(len / 2); encoding = 'utf8'; break; case 'buf': - message = Buffer.alloc(conf.len, 'b'); + message = Buffer.alloc(len, 'b'); break; default: - throw new Error(`unknown message type: ${conf.type}`); + throw new Error(`unknown message type: ${type}`); } const fn = api === 'stream' ? streamWrite : legacyWrite; @@ -59,7 +58,7 @@ function main(conf) { // write data as fast as possible to alice, and have bob decrypt. // use old API for comparison to v0.8 bench.start(); - fn(alice_cipher, bob_cipher, message, encoding, conf.writes); + fn(alice_cipher, bob_cipher, message, encoding, writes); } function streamWrite(alice, bob, message, encoding, writes) { diff --git a/benchmark/crypto/get-ciphers.js b/benchmark/crypto/get-ciphers.js index 3f5ad17ad38716..d4c10a2427d360 100644 --- a/benchmark/crypto/get-ciphers.js +++ b/benchmark/crypto/get-ciphers.js @@ -7,12 +7,10 @@ const bench = common.createBenchmark(main, { v: ['crypto', 'tls'] }); -function main(conf) { - const n = +conf.n; - const v = conf.v; +function main({ n, v }) { const method = require(v).getCiphers; var i = 0; - // first call to getChipers will dominate the results + // First call to getChipers will dominate the results if (n > 1) { for (; i < n; i++) method(); diff --git a/benchmark/crypto/hash-stream-creation.js b/benchmark/crypto/hash-stream-creation.js index 5ac5a4f70b5c55..faaa12a9e5d484 100644 --- a/benchmark/crypto/hash-stream-creation.js +++ b/benchmark/crypto/hash-stream-creation.js @@ -13,8 +13,7 @@ const bench = common.createBenchmark(main, { api: ['legacy', 'stream'] }); -function main(conf) { - var api = conf.api; +function main({ api, type, len, out, writes, algo }) { if (api === 'stream' && /^v0\.[0-8]\./.test(process.version)) { console.error('Crypto streams not available until v0.10'); // use the legacy, just so that we can compare them. @@ -23,26 +22,26 @@ function main(conf) { var message; var encoding; - switch (conf.type) { + switch (type) { case 'asc': - message = 'a'.repeat(conf.len); + message = 'a'.repeat(len); encoding = 'ascii'; break; case 'utf': - message = 'ü'.repeat(conf.len / 2); + message = 'ü'.repeat(len / 2); encoding = 'utf8'; break; case 'buf': - message = Buffer.alloc(conf.len, 'b'); + message = Buffer.alloc(len, 'b'); break; default: - throw new Error(`unknown message type: ${conf.type}`); + throw new Error(`unknown message type: ${type}`); } const fn = api === 'stream' ? streamWrite : legacyWrite; bench.start(); - fn(conf.algo, message, encoding, conf.writes, conf.len, conf.out); + fn(algo, message, encoding, writes, len, out); } function legacyWrite(algo, message, encoding, writes, len, outEnc) { diff --git a/benchmark/crypto/hash-stream-throughput.js b/benchmark/crypto/hash-stream-throughput.js index 21ec3c7902b367..934e7a0b11bdae 100644 --- a/benchmark/crypto/hash-stream-throughput.js +++ b/benchmark/crypto/hash-stream-throughput.js @@ -12,8 +12,7 @@ const bench = common.createBenchmark(main, { api: ['legacy', 'stream'] }); -function main(conf) { - var api = conf.api; +function main({ api, type, len, algo, writes }) { if (api === 'stream' && /^v0\.[0-8]\./.test(process.version)) { console.error('Crypto streams not available until v0.10'); // use the legacy, just so that we can compare them. @@ -22,26 +21,26 @@ function main(conf) { var message; var encoding; - switch (conf.type) { + switch (type) { case 'asc': - message = 'a'.repeat(conf.len); + message = 'a'.repeat(len); encoding = 'ascii'; break; case 'utf': - message = 'ü'.repeat(conf.len / 2); + message = 'ü'.repeat(len / 2); encoding = 'utf8'; break; case 'buf': - message = Buffer.alloc(conf.len, 'b'); + message = Buffer.alloc(len, 'b'); break; default: - throw new Error(`unknown message type: ${conf.type}`); + throw new Error(`unknown message type: ${type}`); } const fn = api === 'stream' ? streamWrite : legacyWrite; bench.start(); - fn(conf.algo, message, encoding, conf.writes, conf.len); + fn(algo, message, encoding, writes, len); } function legacyWrite(algo, message, encoding, writes, len) { diff --git a/benchmark/crypto/rsa-encrypt-decrypt-throughput.js b/benchmark/crypto/rsa-encrypt-decrypt-throughput.js index edab5ae08f7d63..40b69c31f977ca 100644 --- a/benchmark/crypto/rsa-encrypt-decrypt-throughput.js +++ b/benchmark/crypto/rsa-encrypt-decrypt-throughput.js @@ -22,10 +22,10 @@ const bench = common.createBenchmark(main, { len: [16, 32, 64] }); -function main(conf) { - const message = Buffer.alloc(conf.len, 'b'); +function main({ len, algo, keylen, n }) { + const message = Buffer.alloc(len, 'b'); bench.start(); - StreamWrite(conf.algo, conf.keylen, message, conf.n, conf.len); + StreamWrite(algo, keylen, message, n, len); } function StreamWrite(algo, keylen, message, n, len) { diff --git a/benchmark/crypto/rsa-sign-verify-throughput.js b/benchmark/crypto/rsa-sign-verify-throughput.js index bcde3a43d4d77a..3a0373b57d0bba 100644 --- a/benchmark/crypto/rsa-sign-verify-throughput.js +++ b/benchmark/crypto/rsa-sign-verify-throughput.js @@ -23,10 +23,10 @@ const bench = common.createBenchmark(main, { len: [1024, 102400, 2 * 102400, 3 * 102400, 1024 * 1024] }); -function main(conf) { - const message = Buffer.alloc(conf.len, 'b'); +function main({ len, algo, keylen, writes }) { + const message = Buffer.alloc(len, 'b'); bench.start(); - StreamWrite(conf.algo, conf.keylen, message, conf.writes, conf.len); + StreamWrite(algo, keylen, message, writes, len); } function StreamWrite(algo, keylen, message, writes, len) { diff --git a/benchmark/dgram/bind-params.js b/benchmark/dgram/bind-params.js index 5f7999f7a39241..ea1f430eed929b 100644 --- a/benchmark/dgram/bind-params.js +++ b/benchmark/dgram/bind-params.js @@ -15,10 +15,11 @@ const noop = () => {}; function main({ n, port, address }) { port = port === 'true' ? 0 : undefined; address = address === 'true' ? '0.0.0.0' : undefined; + var i; if (port !== undefined && address !== undefined) { bench.start(); - for (let i = 0; i < n; i++) { + for (i = 0; i < n; i++) { dgram.createSocket('udp4').bind(port, address) .on('error', noop) .unref(); @@ -26,7 +27,7 @@ function main({ n, port, address }) { bench.end(n); } else if (port !== undefined) { bench.start(); - for (let i = 0; i < n; i++) { + for (i = 0; i < n; i++) { dgram.createSocket('udp4') .bind(port) .on('error', noop) @@ -35,7 +36,7 @@ function main({ n, port, address }) { bench.end(n); } else if (port === undefined && address === undefined) { bench.start(); - for (let i = 0; i < n; i++) { + for (i = 0; i < n; i++) { dgram.createSocket('udp4') .bind() .on('error', noop) diff --git a/benchmark/domain/domain-fn-args.js b/benchmark/domain/domain-fn-args.js index fe912e34d206e8..c889b35442d046 100644 --- a/benchmark/domain/domain-fn-args.js +++ b/benchmark/domain/domain-fn-args.js @@ -28,15 +28,6 @@ function main({ n, args }) { bench.end(n); } -function fn(a, b, c) { - if (!a) - a = 1; - - if (!b) - b = 2; - - if (!c) - c = 3; - +function fn(a = 1, b = 2, c = 3) { return a + b + c; } diff --git a/benchmark/es/defaultparams-bench.js b/benchmark/es/defaultparams-bench.js index ce2132718ca369..a00b50137c1af3 100644 --- a/benchmark/es/defaultparams-bench.js +++ b/benchmark/es/defaultparams-bench.js @@ -20,37 +20,31 @@ function defaultParams(x = 1, y = 2) { assert.strictEqual(y, 2); } -function runOldStyleDefaults(n) { - - var i = 0; +function runOldStyleDefaults(millions) { bench.start(); - for (; i < n; i++) + for (var i = 0; i < millions * 1e6; i++) oldStyleDefaults(); - bench.end(n / 1e6); + bench.end(millions); } -function runDefaultParams(n) { - - var i = 0; +function runDefaultParams(millions) { bench.start(); - for (; i < n; i++) + for (var i = 0; i < millions * 1e6; i++) defaultParams(); - bench.end(n / 1e6); + bench.end(millions); } function main({ millions, method }) { - const n = millions * 1e6; - switch (method) { case '': // Empty string falls through to next line as default, mostly for tests. case 'withoutdefaults': - runOldStyleDefaults(n); + runOldStyleDefaults(millions); break; case 'withdefaults': - runDefaultParams(n); + runDefaultParams(millions); break; default: - throw new Error('Unexpected method'); + throw new Error(`Unexpected method "${method}"`); } } diff --git a/benchmark/es/destructuring-bench.js b/benchmark/es/destructuring-bench.js index f244506860d248..2168940bdc44f0 100644 --- a/benchmark/es/destructuring-bench.js +++ b/benchmark/es/destructuring-bench.js @@ -8,10 +8,10 @@ const bench = common.createBenchmark(main, { millions: [100] }); -function runSwapManual(n) { +function runSwapManual(millions) { var x, y, r; bench.start(); - for (var i = 0; i < n; i++) { + for (var i = 0; i < millions * 1e6; i++) { x = 1, y = 2; r = x; x = y; @@ -19,34 +19,32 @@ function runSwapManual(n) { assert.strictEqual(x, 2); assert.strictEqual(y, 1); } - bench.end(n / 1e6); + bench.end(millions); } -function runSwapDestructured(n) { +function runSwapDestructured(millions) { var x, y; bench.start(); - for (var i = 0; i < n; i++) { + for (var i = 0; i < millions * 1e6; i++) { x = 1, y = 2; [x, y] = [y, x]; assert.strictEqual(x, 2); assert.strictEqual(y, 1); } - bench.end(n / 1e6); + bench.end(millions); } function main({ millions, method }) { - const n = millions * 1e6; - switch (method) { case '': // Empty string falls through to next line as default, mostly for tests. case 'swap': - runSwapManual(n); + runSwapManual(millions); break; case 'destructure': - runSwapDestructured(n); + runSwapDestructured(millions); break; default: - throw new Error('Unexpected method'); + throw new Error(`Unexpected method "${method}"`); } } diff --git a/benchmark/es/destructuring-object-bench.js b/benchmark/es/destructuring-object-bench.js index 73687f018de9dd..a84977c59bc2cd 100644 --- a/benchmark/es/destructuring-object-bench.js +++ b/benchmark/es/destructuring-object-bench.js @@ -7,45 +7,43 @@ const bench = common.createBenchmark(main, { millions: [100] }); -function runNormal(n) { +function runNormal(millions) { var i = 0; const o = { x: 0, y: 1 }; bench.start(); - for (; i < n; i++) { + for (; i < millions * 1e6; i++) { /* eslint-disable no-unused-vars */ const x = o.x; const y = o.y; const r = o.r || 2; /* eslint-enable no-unused-vars */ } - bench.end(n / 1e6); + bench.end(millions); } -function runDestructured(n) { +function runDestructured(millions) { var i = 0; const o = { x: 0, y: 1 }; bench.start(); - for (; i < n; i++) { + for (; i < millions * 1e6; i++) { /* eslint-disable no-unused-vars */ const { x, y, r = 2 } = o; /* eslint-enable no-unused-vars */ } - bench.end(n / 1e6); + bench.end(millions); } function main({ millions, method }) { - const n = millions * 1e6; - switch (method) { case '': // Empty string falls through to next line as default, mostly for tests. case 'normal': - runNormal(n); + runNormal(millions); break; case 'destructureObject': - runDestructured(n); + runDestructured(millions); break; default: - throw new Error('Unexpected method'); + throw new Error(`Unexpected method "${method}"`); } } diff --git a/benchmark/es/foreach-bench.js b/benchmark/es/foreach-bench.js index c7caa7cee6f461..e9179ed8dedb6d 100644 --- a/benchmark/es/foreach-bench.js +++ b/benchmark/es/foreach-bench.js @@ -8,56 +8,51 @@ const bench = common.createBenchmark(main, { millions: [5] }); -function useFor(n, items, count) { - var i, j; +function useFor(millions, items, count) { bench.start(); - for (i = 0; i < n; i++) { - for (j = 0; j < count; j++) { + for (var i = 0; i < millions * 1e6; i++) { + for (var j = 0; j < count; j++) { /* eslint-disable no-unused-vars */ const item = items[j]; /* esline-enable no-unused-vars */ } } - bench.end(n / 1e6); + bench.end(millions); } -function useForOf(n, items) { - var i, item; +function useForOf(millions, items) { + var item; bench.start(); - for (i = 0; i < n; i++) { + for (var i = 0; i < millions * 1e6; i++) { for (item of items) {} } - bench.end(n / 1e6); + bench.end(millions); } -function useForIn(n, items) { - var i, j, item; +function useForIn(millions, items) { bench.start(); - for (i = 0; i < n; i++) { - for (j in items) { + for (var i = 0; i < millions * 1e6; i++) { + for (var j in items) { /* eslint-disable no-unused-vars */ - item = items[j]; + const item = items[j]; /* esline-enable no-unused-vars */ } } - bench.end(n / 1e6); + bench.end(millions); } -function useForEach(n, items) { - var i; +function useForEach(millions, items) { bench.start(); - for (i = 0; i < n; i++) { + for (var i = 0; i < millions * 1e6; i++) { items.forEach((item) => {}); } - bench.end(n / 1e6); + bench.end(millions); } function main({ millions, count, method }) { - const n = millions * 1e6; const items = new Array(count); - var i; var fn; - for (i = 0; i < count; i++) + for (var i = 0; i < count; i++) items[i] = i; switch (method) { @@ -76,7 +71,7 @@ function main({ millions, count, method }) { fn = useForEach; break; default: - throw new Error('Unexpected method'); + throw new Error(`Unexpected method "${method}"`); } - fn(n, items, count); + fn(millions, items, count); } diff --git a/benchmark/es/map-bench.js b/benchmark/es/map-bench.js index ba8e35c2eb934f..445031aa9831de 100644 --- a/benchmark/es/map-bench.js +++ b/benchmark/es/map-bench.js @@ -11,63 +11,59 @@ const bench = common.createBenchmark(main, { millions: [1] }); -function runObject(n) { +function runObject(millions) { const m = {}; - var i = 0; bench.start(); - for (; i < n; i++) { + for (var i = 0; i < millions * 1e6; i++) { m[`i${i}`] = i; m[`s${i}`] = String(i); assert.strictEqual(String(m[`i${i}`]), m[`s${i}`]); m[`i${i}`] = undefined; m[`s${i}`] = undefined; } - bench.end(n / 1e6); + bench.end(millions); } -function runNullProtoObject(n) { +function runNullProtoObject(millions) { const m = Object.create(null); - var i = 0; bench.start(); - for (; i < n; i++) { + for (var i = 0; i < millions * 1e6; i++) { m[`i${i}`] = i; m[`s${i}`] = String(i); assert.strictEqual(String(m[`i${i}`]), m[`s${i}`]); m[`i${i}`] = undefined; m[`s${i}`] = undefined; } - bench.end(n / 1e6); + bench.end(millions); } -function runNullProtoLiteralObject(n) { +function runNullProtoLiteralObject(millions) { const m = { __proto__: null }; - var i = 0; bench.start(); - for (; i < n; i++) { + for (var i = 0; i < millions * 1e6; i++) { m[`i${i}`] = i; m[`s${i}`] = String(i); assert.strictEqual(String(m[`i${i}`]), m[`s${i}`]); m[`i${i}`] = undefined; m[`s${i}`] = undefined; } - bench.end(n / 1e6); + bench.end(millions); } function StorageObject() {} StorageObject.prototype = Object.create(null); -function runStorageObject(n) { +function runStorageObject(millions) { const m = new StorageObject(); - var i = 0; bench.start(); - for (; i < n; i++) { + for (var i = 0; i < millions * 1e6; i++) { m[`i${i}`] = i; m[`s${i}`] = String(i); assert.strictEqual(String(m[`i${i}`]), m[`s${i}`]); m[`i${i}`] = undefined; m[`s${i}`] = undefined; } - bench.end(n / 1e6); + bench.end(millions); } function fakeMap() { @@ -80,59 +76,55 @@ function fakeMap() { }; } -function runFakeMap(n) { +function runFakeMap(millions) { const m = fakeMap(); - var i = 0; bench.start(); - for (; i < n; i++) { + for (var i = 0; i < millions * 1e6; i++) { m.set(`i${i}`, i); m.set(`s${i}`, String(i)); assert.strictEqual(String(m.get(`i${i}`)), m.get(`s${i}`)); m.set(`i${i}`, undefined); m.set(`s${i}`, undefined); } - bench.end(n / 1e6); + bench.end(millions); } -function runMap(n) { +function runMap(millions) { const m = new Map(); - var i = 0; bench.start(); - for (; i < n; i++) { + for (var i = 0; i < millions * 1e6; i++) { m.set(`i${i}`, i); m.set(`s${i}`, String(i)); assert.strictEqual(String(m.get(`i${i}`)), m.get(`s${i}`)); m.set(`i${i}`, undefined); m.set(`s${i}`, undefined); } - bench.end(n / 1e6); + bench.end(millions); } function main({ millions, method }) { - const n = millions * 1e6; - switch (method) { case '': // Empty string falls through to next line as default, mostly for tests. case 'object': - runObject(n); + runObject(millions); break; case 'nullProtoObject': - runNullProtoObject(n); + runNullProtoObject(millions); break; case 'nullProtoLiteralObject': - runNullProtoLiteralObject(n); + runNullProtoLiteralObject(millions); break; case 'storageObject': - runStorageObject(n); + runStorageObject(millions); break; case 'fakeMap': - runFakeMap(n); + runFakeMap(millions); break; case 'map': - runMap(n); + runMap(millions); break; default: - throw new Error('Unexpected method'); + throw new Error(`Unexpected method "${method}"`); } } diff --git a/benchmark/es/restparams-bench.js b/benchmark/es/restparams-bench.js index 78299d292ce6f6..6ad766f10f16f6 100644 --- a/benchmark/es/restparams-bench.js +++ b/benchmark/es/restparams-bench.js @@ -33,49 +33,39 @@ function useArguments() { assert.strictEqual(arguments[3], 'b'); } -function runCopyArguments(n) { - - var i = 0; - bench.start(); - for (; i < n; i++) +function runCopyArguments(millions) { + for (var i = 0; i < millions * 1e6; i++) copyArguments(1, 2, 'a', 'b'); - bench.end(n / 1e6); } -function runRestArguments(n) { - - var i = 0; - bench.start(); - for (; i < n; i++) +function runRestArguments(millions) { + for (var i = 0; i < millions * 1e6; i++) restArguments(1, 2, 'a', 'b'); - bench.end(n / 1e6); } -function runUseArguments(n) { - - var i = 0; - bench.start(); - for (; i < n; i++) +function runUseArguments(millions) { + for (var i = 0; i < millions * 1e6; i++) useArguments(1, 2, 'a', 'b'); - bench.end(n / 1e6); } function main({ millions, method }) { - const n = millions * 1e6; - + var fn; switch (method) { case '': // Empty string falls through to next line as default, mostly for tests. case 'copy': - runCopyArguments(n); + fn = runCopyArguments; break; case 'rest': - runRestArguments(n); + fn = runRestArguments; break; case 'arguments': - runUseArguments(n); + fn = runUseArguments; break; default: - throw new Error('Unexpected method'); + throw new Error(`Unexpected method "${method}"`); } + bench.start(); + fn(millions); + bench.end(millions); } diff --git a/benchmark/es/spread-assign.js b/benchmark/es/spread-assign.js new file mode 100644 index 00000000000000..00c634ff879501 --- /dev/null +++ b/benchmark/es/spread-assign.js @@ -0,0 +1,46 @@ +'use strict'; + +const common = require('../common.js'); +const util = require('util'); + +const bench = common.createBenchmark(main, { + method: ['spread', 'assign', '_extend'], + count: [5, 10, 20], + millions: [1] +}); + +function main({ millions, context, count, rest, method }) { + const n = millions * 1e6; + + const src = {}; + for (let n = 0; n < count; n++) + src[`p${n}`] = n; + + let obj; // eslint-disable-line + let i; + + switch (method) { + case '': + // Empty string falls through to next line as default, mostly for tests. + case '_extend': + bench.start(); + for (i = 0; i < n; i++) + obj = util._extend({}, src); + bench.end(n); + break; + case 'assign': + bench.start(); + for (i = 0; i < n; i++) + obj = Object.assign({}, src); + bench.end(n); + break; + case 'spread': + bench.start(); + for (i = 0; i < n; i++) + obj = { ...src }; + bench.end(n); + break; + default: + throw new Error('Unexpected method'); + } +} diff --git a/benchmark/es/spread-bench.js b/benchmark/es/spread-bench.js index 3c6cc93ea4f817..067299cd650919 100644 --- a/benchmark/es/spread-bench.js +++ b/benchmark/es/spread-bench.js @@ -24,7 +24,6 @@ function makeTest(count, rest) { } function main({ millions, context, count, rest, method }) { - const n = millions * 1e6; const ctx = context === 'context' ? {} : null; var fn = makeTest(count, rest); const args = new Array(count); @@ -37,25 +36,25 @@ function main({ millions, context, count, rest, method }) { // Empty string falls through to next line as default, mostly for tests. case 'apply': bench.start(); - for (i = 0; i < n; i++) + for (i = 0; i < millions * 1e6; i++) fn.apply(ctx, args); - bench.end(n / 1e6); + bench.end(millions); break; case 'spread': if (ctx !== null) fn = fn.bind(ctx); bench.start(); - for (i = 0; i < n; i++) + for (i = 0; i < millions * 1e6; i++) fn(...args); - bench.end(n / 1e6); + bench.end(millions); break; case 'call-spread': bench.start(); - for (i = 0; i < n; i++) + for (i = 0; i < millions * 1e6; i++) fn.call(ctx, ...args); - bench.end(n / 1e6); + bench.end(millions); break; default: - throw new Error('Unexpected method'); + throw new Error(`Unexpected method "${method}"`); } } diff --git a/benchmark/es/string-concatenations.js b/benchmark/es/string-concatenations.js index a40b7fa8c3b9f9..72fb7f9969b604 100644 --- a/benchmark/es/string-concatenations.js +++ b/benchmark/es/string-concatenations.js @@ -16,7 +16,6 @@ const configs = { const bench = common.createBenchmark(main, configs); - function main({ n, mode }) { const str = 'abc'; const num = 123; @@ -63,7 +62,7 @@ function main({ n, mode }) { bench.end(n); break; default: - throw new Error('Unexpected method'); + throw new Error(`Unexpected method "${mode}"`); } return string; diff --git a/benchmark/es/string-repeat.js b/benchmark/es/string-repeat.js index e5bdbb5cc193c1..9e33e4acf47118 100644 --- a/benchmark/es/string-repeat.js +++ b/benchmark/es/string-repeat.js @@ -33,7 +33,7 @@ function main({ n, size, encoding, mode }) { bench.end(n); break; default: - throw new Error('Unexpected method'); + throw new Error(`Unexpected method "${mode}"`); } assert.strictEqual([...str].length, size); diff --git a/benchmark/fs/bench-realpath.js b/benchmark/fs/bench-realpath.js index 6690d7e87b091f..de03e71b42d585 100644 --- a/benchmark/fs/bench-realpath.js +++ b/benchmark/fs/bench-realpath.js @@ -16,10 +16,8 @@ function main({ n, pathType }) { bench.start(); if (pathType === 'relative') relativePath(n); - else if (pathType === 'resolved') - resolvedPath(n); else - throw new Error(`unknown "pathType": ${pathType}`); + resolvedPath(n); } function relativePath(n) { diff --git a/benchmark/fs/bench-realpathSync.js b/benchmark/fs/bench-realpathSync.js index 1c751156f73d53..7a01bd18cb72bf 100644 --- a/benchmark/fs/bench-realpathSync.js +++ b/benchmark/fs/bench-realpathSync.js @@ -15,24 +15,10 @@ const bench = common.createBenchmark(main, { function main({ n, pathType }) { + const path = pathType === 'relative' ? relative_path : resolved_path; bench.start(); - if (pathType === 'relative') - relativePath(n); - else if (pathType === 'resolved') - resolvedPath(n); - else - throw new Error(`unknown "pathType": ${pathType}`); - bench.end(n); -} - -function relativePath(n) { - for (var i = 0; i < n; i++) { - fs.realpathSync(relative_path); - } -} - -function resolvedPath(n) { for (var i = 0; i < n; i++) { - fs.realpathSync(resolved_path); + fs.realpathSync(path); } + bench.end(n); } diff --git a/benchmark/fs/write-stream-throughput.js b/benchmark/fs/write-stream-throughput.js index 6fe00cde48cabb..60ad47bc4eabe1 100644 --- a/benchmark/fs/write-stream-throughput.js +++ b/benchmark/fs/write-stream-throughput.js @@ -36,7 +36,6 @@ function main({ dur, encodingType, size }) { try { fs.unlinkSync(filename); } catch (e) {} var started = false; - var ending = false; var ended = false; var f = fs.createWriteStream(filename); @@ -52,15 +51,9 @@ function main({ dur, encodingType, size }) { function write() { - // don't try to write after we end, even if a 'drain' event comes. - // v0.8 streams are so sloppy! - if (ending) - return; - if (!started) { started = true; setTimeout(function() { - ending = true; f.end(); }, dur * 1000); bench.start(); diff --git a/benchmark/http/bench-parser.js b/benchmark/http/bench-parser.js index 4c691d71345da3..d629fe67e59e76 100644 --- a/benchmark/http/bench-parser.js +++ b/benchmark/http/bench-parser.js @@ -14,7 +14,6 @@ const bench = common.createBenchmark(main, { n: [1e5], }); - function main({ len, n }) { var header = `GET /hello HTTP/1.1${CRLF}Content-Type: text/plain${CRLF}`; @@ -26,7 +25,6 @@ function main({ len, n }) { processHeader(Buffer.from(header), n); } - function processHeader(header, n) { const parser = newParser(REQUEST); @@ -38,7 +36,6 @@ function processHeader(header, n) { bench.end(n); } - function newParser(type) { const parser = new HTTPParser(type); diff --git a/benchmark/http/check_invalid_header_char.js b/benchmark/http/check_invalid_header_char.js index b9933d690e25cc..399e71b2dfcc88 100644 --- a/benchmark/http/check_invalid_header_char.js +++ b/benchmark/http/check_invalid_header_char.js @@ -3,6 +3,10 @@ const common = require('../common.js'); const _checkInvalidHeaderChar = require('_http_common')._checkInvalidHeaderChar; +// Put it here so the benchmark result lines will not be super long. +const LONG_AND_INVALID = 'Here is a value that is really a folded header ' + + 'value\r\n this should be supported, but it is not currently'; + const bench = common.createBenchmark(main, { key: [ // Valid @@ -21,8 +25,7 @@ const bench = common.createBenchmark(main, { 'en-US', // Invalid - 'Here is a value that is really a folded header value\r\n this should be \ - supported, but it is not currently', + 'LONG_AND_INVALID', '中文呢', // unicode 'foo\nbar', '\x7F' @@ -31,6 +34,9 @@ const bench = common.createBenchmark(main, { }); function main({ n, key }) { + if (key === 'LONG_AND_INVALID') { + key = LONG_AND_INVALID; + } bench.start(); for (var i = 0; i < n; i++) { _checkInvalidHeaderChar(key); diff --git a/benchmark/http/http_server_for_chunky_client.js b/benchmark/http/http_server_for_chunky_client.js index f079544e03d48e..1e5a4583669c0f 100644 --- a/benchmark/http/http_server_for_chunky_client.js +++ b/benchmark/http/http_server_for_chunky_client.js @@ -2,22 +2,15 @@ const assert = require('assert'); const http = require('http'); -const fs = require('fs'); const { fork } = require('child_process'); const common = require('../common.js'); -const { PIPE, tmpDir } = require('../../test/common'); +const { PIPE } = require('../../test/common'); +const tmpdir = require('../../test/common/tmpdir'); process.env.PIPE_NAME = PIPE; -try { - fs.accessSync(tmpDir, fs.F_OK); -} catch (e) { - fs.mkdirSync(tmpDir); -} +tmpdir.refresh(); var server; -try { - fs.unlinkSync(process.env.PIPE_NAME); -} catch (e) { /* ignore */ } server = http.createServer(function(req, res) { const headers = { diff --git a/benchmark/http/set-header.js b/benchmark/http/set-header.js new file mode 100644 index 00000000000000..f0987f2cc77150 --- /dev/null +++ b/benchmark/http/set-header.js @@ -0,0 +1,32 @@ +'use strict'; +const common = require('../common.js'); +const PORT = common.PORT; + +const bench = common.createBenchmark(main, { + res: ['normal', 'setHeader', 'setHeaderWH'] +}); + +const type = 'bytes'; +const len = 4; +const chunks = 0; +const chunkedEnc = 0; +const c = 50; + +// normal: writeHead(status, {...}) +// setHeader: statusCode = status, setHeader(...) x2 +// setHeaderWH: setHeader(...), writeHead(status, ...) +function main({ res }) { + process.env.PORT = PORT; + var server = require('../fixtures/simple-http-server.js') + .listen(PORT) + .on('listening', function() { + const path = `/${type}/${len}/${chunks}/normal/${chunkedEnc}`; + + bench.http({ + path: path, + connections: c + }, function() { + server.close(); + }); + }); +} diff --git a/benchmark/http/set_header.js b/benchmark/http/set_header.js new file mode 100644 index 00000000000000..22de61b3f847a3 --- /dev/null +++ b/benchmark/http/set_header.js @@ -0,0 +1,30 @@ +'use strict'; + +const common = require('../common.js'); +const { OutgoingMessage } = require('_http_outgoing'); + +const bench = common.createBenchmark(main, { + value: [ + 'X-Powered-By', + 'Vary', + 'Set-Cookie', + 'Content-Type', + 'Content-Length', + 'Connection', + 'Transfer-Encoding' + ], + n: [1e6], +}); + +function main(conf) { + const n = +conf.n; + const value = conf.value; + + const og = new OutgoingMessage(); + + bench.start(); + for (var i = 0; i < n; i++) { + og.setHeader(value, ''); + } + bench.end(n); +} diff --git a/benchmark/http/simple.js b/benchmark/http/simple.js index d5351815fc1b7e..6d1851c45e17b2 100644 --- a/benchmark/http/simple.js +++ b/benchmark/http/simple.js @@ -1,6 +1,5 @@ 'use strict'; const common = require('../common.js'); -const PORT = common.PORT; const bench = common.createBenchmark(main, { // unicode confuses ab on os x. @@ -8,16 +7,14 @@ const bench = common.createBenchmark(main, { len: [4, 1024, 102400], chunks: [1, 4], c: [50, 500], - chunkedEnc: [1, 0], - res: ['normal', 'setHeader', 'setHeaderWH'] + chunkedEnc: [1, 0] }); function main({ type, len, chunks, c, chunkedEnc, res }) { - process.env.PORT = PORT; var server = require('../fixtures/simple-http-server.js') - .listen(PORT) + .listen(common.PORT) .on('listening', function() { - const path = `/${type}/${len}/${chunks}/${res}/${chunkedEnc}`; + const path = `/${type}/${len}/${chunks}/normal/${chunkedEnc}`; bench.http({ path: path, diff --git a/benchmark/http/upgrade.js b/benchmark/http/upgrade.js index 0feaecc8ff19e6..6b39323396a2e3 100644 --- a/benchmark/http/upgrade.js +++ b/benchmark/http/upgrade.js @@ -1,7 +1,6 @@ 'use strict'; const common = require('../common.js'); -const PORT = common.PORT; const net = require('net'); const bench = common.createBenchmark(main, { @@ -20,7 +19,6 @@ const resData = 'HTTP/1.1 101 Web Socket Protocol Handshake\r\n' + '\r\n\r\n'; function main({ n }) { - process.env.PORT = PORT; var server = require('../fixtures/simple-http-server.js') .listen(common.PORT) .on('listening', function() { diff --git a/benchmark/http2/respond-with-fd.js b/benchmark/http2/respond-with-fd.js index 6076cf91be9d84..fa7b2fbd16b3e6 100644 --- a/benchmark/http2/respond-with-fd.js +++ b/benchmark/http2/respond-with-fd.js @@ -1,7 +1,6 @@ 'use strict'; const common = require('../common.js'); -const PORT = common.PORT; const path = require('path'); const fs = require('fs'); @@ -25,7 +24,7 @@ function main({ requests, streams, clients }) { stream.respondWithFD(fd); stream.on('error', (err) => {}); }); - server.listen(PORT, () => { + server.listen(common.PORT, () => { bench.http({ path: '/', requests, diff --git a/benchmark/http2/simple.js b/benchmark/http2/simple.js index 37c78d340181a8..cf017e6735411e 100644 --- a/benchmark/http2/simple.js +++ b/benchmark/http2/simple.js @@ -1,11 +1,8 @@ 'use strict'; const common = require('../common.js'); -const PORT = common.PORT; - const path = require('path'); const fs = require('fs'); - const file = path.join(path.resolve(__dirname, '../fixtures'), 'alice.html'); const bench = common.createBenchmark(main, { @@ -24,7 +21,7 @@ function main({ requests, streams, clients }) { out.pipe(stream); stream.on('error', (err) => {}); }); - server.listen(PORT, () => { + server.listen(common.PORT, () => { bench.http({ path: '/', requests, diff --git a/benchmark/http2/write.js b/benchmark/http2/write.js index 7a802ef84fd9ed..6fcb1254ca3f05 100644 --- a/benchmark/http2/write.js +++ b/benchmark/http2/write.js @@ -1,7 +1,6 @@ 'use strict'; const common = require('../common.js'); -const PORT = common.PORT; const bench = common.createBenchmark(main, { streams: [100, 200, 1000], @@ -26,7 +25,7 @@ function main({ streams, length, size }) { } write(); }); - server.listen(PORT, () => { + server.listen(common.PORT, () => { bench.http({ path: '/', requests: 10000, diff --git a/benchmark/misc/freelist.js b/benchmark/misc/freelist.js index 0530255728ffeb..8c3281cc407363 100644 --- a/benchmark/misc/freelist.js +++ b/benchmark/misc/freelist.js @@ -12,7 +12,6 @@ function main({ n }) { const FreeList = require('internal/freelist'); const poolSize = 1000; const list = new FreeList('test', poolSize, Object); - var i; var j; const used = []; @@ -23,7 +22,7 @@ function main({ n }) { bench.start(); - for (i = 0; i < n; i++) { + for (var i = 0; i < n; i++) { // Return all the items to the pool for (j = 0; j < poolSize; j++) { list.free(used[j]); diff --git a/benchmark/misc/function_call/index.js b/benchmark/misc/function_call/index.js index 91efa573597cc7..28561bc48cd7c3 100644 --- a/benchmark/misc/function_call/index.js +++ b/benchmark/misc/function_call/index.js @@ -32,11 +32,9 @@ const bench = common.createBenchmark(main, { }); function main({ millions, type }) { - const n = millions * 1e6; - const fn = type === 'cxx' ? cxx : js; bench.start(); - for (var i = 0; i < n; i++) { + for (var i = 0; i < millions * 1e6; i++) { fn(); } bench.end(millions); diff --git a/benchmark/misc/object-property-bench.js b/benchmark/misc/object-property-bench.js index 37da82d88758fd..ddc6faed7fc8b7 100644 --- a/benchmark/misc/object-property-bench.js +++ b/benchmark/misc/object-property-bench.js @@ -78,6 +78,6 @@ function main({ millions, method }) { runSymbol(n); break; default: - throw new Error('Unexpected method'); + throw new Error(`Unexpected method "${method}"`); } } diff --git a/benchmark/misc/punycode.js b/benchmark/misc/punycode.js index 7016fa11712bbc..369adcf17d3973 100644 --- a/benchmark/misc/punycode.js +++ b/benchmark/misc/punycode.js @@ -55,9 +55,8 @@ function runPunycode(n, val) { } function runICU(n, val) { - var i = 0; bench.start(); - for (; i < n; i++) + for (var i = 0; i < n; i++) usingICU(val); bench.end(n); } @@ -76,6 +75,6 @@ function main({ n, val, method }) { } // fallthrough default: - throw new Error('Unexpected method'); + throw new Error(`Unexpected method "${method}"`); } } diff --git a/benchmark/module/module-loader.js b/benchmark/module/module-loader.js index 8393d1f92e0e6c..58d4dcf81c9316 100644 --- a/benchmark/module/module-loader.js +++ b/benchmark/module/module-loader.js @@ -3,8 +3,8 @@ const fs = require('fs'); const path = require('path'); const common = require('../common.js'); -const { refreshTmpDir, tmpDir } = require('../../test/common'); -const benchmarkDirectory = path.join(tmpDir, 'nodejs-benchmark-module'); +const tmpdir = require('../../test/common/tmpdir'); +const benchmarkDirectory = path.join(tmpdir.path, 'nodejs-benchmark-module'); const bench = common.createBenchmark(main, { thousands: [50], @@ -13,12 +13,10 @@ const bench = common.createBenchmark(main, { }); function main({ thousands, fullPath, useCache }) { - const n = thousands * 1e3; - - refreshTmpDir(); + tmpdir.refresh(); try { fs.mkdirSync(benchmarkDirectory); } catch (e) {} - for (var i = 0; i <= n; i++) { + for (var i = 0; i <= thousands * 1e3; i++) { fs.mkdirSync(`${benchmarkDirectory}${i}`); fs.writeFileSync( `${benchmarkDirectory}${i}/package.json`, @@ -31,37 +29,37 @@ function main({ thousands, fullPath, useCache }) { } if (fullPath === 'true') - measureFull(n, useCache === 'true'); + measureFull(thousands, useCache === 'true'); else - measureDir(n, useCache === 'true'); + measureDir(thousands, useCache === 'true'); - refreshTmpDir(); + tmpdir.refresh(); } -function measureFull(n, useCache) { +function measureFull(thousands, useCache) { var i; if (useCache) { - for (i = 0; i <= n; i++) { + for (i = 0; i <= thousands * 1e3; i++) { require(`${benchmarkDirectory}${i}/index.js`); } } bench.start(); - for (i = 0; i <= n; i++) { + for (i = 0; i <= thousands * 1e3; i++) { require(`${benchmarkDirectory}${i}/index.js`); } - bench.end(n / 1e3); + bench.end(thousands); } -function measureDir(n, useCache) { +function measureDir(thousands, useCache) { var i; if (useCache) { - for (i = 0; i <= n; i++) { + for (i = 0; i <= thousands * 1e3; i++) { require(`${benchmarkDirectory}${i}`); } } bench.start(); - for (i = 0; i <= n; i++) { + for (i = 0; i <= thousands * 1e3; i++) { require(`${benchmarkDirectory}${i}`); } - bench.end(n / 1e3); + bench.end(thousands); } diff --git a/benchmark/path/basename-win32.js b/benchmark/path/basename-win32.js index 8a66f56d6e3295..937dc6f6948c5d 100644 --- a/benchmark/path/basename-win32.js +++ b/benchmark/path/basename-win32.js @@ -1,6 +1,6 @@ 'use strict'; const common = require('../common.js'); -const { posix } = require('path'); +const { win32 } = require('path'); const bench = common.createBenchmark(main, { pathext: [ @@ -28,7 +28,7 @@ function main({ n, pathext }) { bench.start(); for (var i = 0; i < n; i++) { - posix.basename(pathext, ext); + win32.basename(pathext, ext); } bench.end(n); } diff --git a/benchmark/timers/set-immediate-breadth.js b/benchmark/timers/set-immediate-breadth.js index a4b217b5bff8d6..4f7d2cd2761334 100644 --- a/benchmark/timers/set-immediate-breadth.js +++ b/benchmark/timers/set-immediate-breadth.js @@ -9,7 +9,7 @@ function main({ millions }) { const N = millions * 1e6; process.on('exit', function() { - bench.end(N / 1e6); + bench.end(millions); }); function cb() {} diff --git a/benchmark/timers/set-immediate-depth-args.js b/benchmark/timers/set-immediate-depth-args.js index fe1340c4bd55f2..aa5ec95f7dad30 100644 --- a/benchmark/timers/set-immediate-depth-args.js +++ b/benchmark/timers/set-immediate-depth-args.js @@ -9,7 +9,7 @@ function main({ millions }) { const N = millions * 1e6; process.on('exit', function() { - bench.end(N / 1e6); + bench.end(millions); }); function cb3(n, arg2, arg3) { diff --git a/benchmark/timers/timers-cancel-pooled.js b/benchmark/timers/timers-cancel-pooled.js index 33897507c83937..3e262f820a3e08 100644 --- a/benchmark/timers/timers-cancel-pooled.js +++ b/benchmark/timers/timers-cancel-pooled.js @@ -28,5 +28,5 @@ function main({ millions }) { } function cb() { - assert(false, 'Timer should not call callback'); + assert.fail('Timer should not call callback'); } diff --git a/benchmark/timers/timers-cancel-unpooled.js b/benchmark/timers/timers-cancel-unpooled.js index 57e0139dfe1a4a..158667311330a4 100644 --- a/benchmark/timers/timers-cancel-unpooled.js +++ b/benchmark/timers/timers-cancel-unpooled.js @@ -22,5 +22,5 @@ function main({ millions }) { } function cb() { - assert(false, `Timer ${this._idleTimeout} should not call callback`); + assert.fail(`Timer ${this._idleTimeout} should not call callback`); } diff --git a/benchmark/timers/timers-insert-unpooled.js b/benchmark/timers/timers-insert-unpooled.js index 56526633358e42..fbbeebb759ff3a 100644 --- a/benchmark/timers/timers-insert-unpooled.js +++ b/benchmark/timers/timers-insert-unpooled.js @@ -23,5 +23,5 @@ function main({ millions }) { } function cb() { - assert(false, `Timer ${this._idleTimeout} should not call callback`); + assert.fail(`Timer ${this._idleTimeout} should not call callback`); } diff --git a/benchmark/tls/convertprotocols.js b/benchmark/tls/convertprotocols.js index 1ee2672bee7bd7..9f4969344d1bcd 100644 --- a/benchmark/tls/convertprotocols.js +++ b/benchmark/tls/convertprotocols.js @@ -8,14 +8,15 @@ const bench = common.createBenchmark(main, { }); function main({ n }) { - var i = 0; + const input = ['ABC', 'XYZ123', 'FOO']; var m = {}; // First call dominates results if (n > 1) { - tls.convertNPNProtocols(['ABC', 'XYZ123', 'FOO'], m); + tls.convertNPNProtocols(input, m); m = {}; } bench.start(); - for (; i < n; i++) tls.convertNPNProtocols(['ABC', 'XYZ123', 'FOO'], m); + for (var i = 0; i < n; i++) + tls.convertNPNProtocols(input, m); bench.end(n); } diff --git a/benchmark/tls/throughput.js b/benchmark/tls/throughput.js index f63257c49693d6..1ca52ad9496237 100644 --- a/benchmark/tls/throughput.js +++ b/benchmark/tls/throughput.js @@ -40,11 +40,11 @@ function main({ dur, type, size }) { }; server = tls.createServer(options, onConnection); - setTimeout(done, dur * 1000); var conn; server.listen(common.PORT, function() { const opt = { port: common.PORT, rejectUnauthorized: false }; conn = tls.connect(opt, function() { + setTimeout(done, dur * 1000); bench.start(); conn.on('drain', write); write(); diff --git a/benchmark/tls/tls-connect.js b/benchmark/tls/tls-connect.js index 67f2d5f8a932e0..da0f5e08d5e6db 100644 --- a/benchmark/tls/tls-connect.js +++ b/benchmark/tls/tls-connect.js @@ -11,12 +11,13 @@ const bench = common.createBenchmark(main, { var clientConn = 0; var serverConn = 0; -var server; var dur; var concurrency; var running = true; -function main({ dur, concurrency }) { +function main(conf) { + dur = conf.dur; + concurrency = conf.concurrency; const cert_dir = path.resolve(__dirname, '../../test/fixtures'); const options = { key: fs.readFileSync(`${cert_dir}/test_key.pem`), @@ -25,7 +26,7 @@ function main({ dur, concurrency }) { ciphers: 'AES256-GCM-SHA384' }; - server = tls.createServer(options, onConnection); + const server = tls.createServer(options, onConnection); server.listen(common.PORT, onListening); } diff --git a/benchmark/url/legacy-vs-whatwg-url-get-prop.js b/benchmark/url/legacy-vs-whatwg-url-get-prop.js index 93603c258cf1f2..2cc3ab8c75e65c 100644 --- a/benchmark/url/legacy-vs-whatwg-url-get-prop.js +++ b/benchmark/url/legacy-vs-whatwg-url-get-prop.js @@ -74,7 +74,7 @@ function useWHATWG(n, input) { function main({ type, n, method }) { const input = inputs[type]; if (!input) { - throw new Error('Unknown input type'); + throw new Error(`Unknown input type "${type}"`); } var noDead; // Avoid dead code elimination. @@ -86,7 +86,7 @@ function main({ type, n, method }) { noDead = useWHATWG(n, input); break; default: - throw new Error('Unknown method'); + throw new Error(`Unknown method "${method}"`); } assert.ok(noDead); diff --git a/benchmark/url/legacy-vs-whatwg-url-parse.js b/benchmark/url/legacy-vs-whatwg-url-parse.js index da42d5a189af47..2be55e17cc354b 100644 --- a/benchmark/url/legacy-vs-whatwg-url-parse.js +++ b/benchmark/url/legacy-vs-whatwg-url-parse.js @@ -34,7 +34,7 @@ function useWHATWG(n, input) { function main({ type, n, method }) { const input = inputs[type]; if (!input) { - throw new Error('Unknown input type'); + throw new Error(`Unknown input type "${type}"`); } var noDead; // Avoid dead code elimination. @@ -46,7 +46,7 @@ function main({ type, n, method }) { noDead = useWHATWG(n, input); break; default: - throw new Error('Unknown method'); + throw new Error(`Unknown method ${method}`); } assert.ok(noDead); diff --git a/benchmark/url/legacy-vs-whatwg-url-searchparams-parse.js b/benchmark/url/legacy-vs-whatwg-url-searchparams-parse.js index 51953ec8707374..e915ceb54f917f 100644 --- a/benchmark/url/legacy-vs-whatwg-url-searchparams-parse.js +++ b/benchmark/url/legacy-vs-whatwg-url-searchparams-parse.js @@ -31,7 +31,7 @@ function useWHATWG(n, input) { function main({ type, n, method }) { const input = inputs[type]; if (!input) { - throw new Error('Unknown input type'); + throw new Error(`Unknown input type "${type}"`); } switch (method) { @@ -42,6 +42,6 @@ function main({ type, n, method }) { useWHATWG(n, input); break; default: - throw new Error('Unknown method'); + throw new Error(`Unknown method ${method}`); } } diff --git a/benchmark/url/legacy-vs-whatwg-url-searchparams-serialize.js b/benchmark/url/legacy-vs-whatwg-url-searchparams-serialize.js index 3490782a1bf421..8fe3e546f0780d 100644 --- a/benchmark/url/legacy-vs-whatwg-url-searchparams-serialize.js +++ b/benchmark/url/legacy-vs-whatwg-url-searchparams-serialize.js @@ -33,7 +33,7 @@ function useWHATWG(n, input, prop) { function main({ type, n, method }) { const input = inputs[type]; if (!input) { - throw new Error('Unknown input type'); + throw new Error(`Unknown input type "${type}"`); } switch (method) { @@ -44,6 +44,6 @@ function main({ type, n, method }) { useWHATWG(n, input); break; default: - throw new Error('Unknown method'); + throw new Error(`Unknown method ${method}`); } } diff --git a/benchmark/url/legacy-vs-whatwg-url-serialize.js b/benchmark/url/legacy-vs-whatwg-url-serialize.js index e92b941b5d57e5..017ec4328c590b 100644 --- a/benchmark/url/legacy-vs-whatwg-url-serialize.js +++ b/benchmark/url/legacy-vs-whatwg-url-serialize.js @@ -36,7 +36,7 @@ function useWHATWG(n, input, prop) { function main({ type, n, method }) { const input = inputs[type]; if (!input) { - throw new Error('Unknown input type'); + throw new Error(`Unknown input type "${type}"`); } var noDead; // Avoid dead code elimination. @@ -48,7 +48,7 @@ function main({ type, n, method }) { noDead = useWHATWG(n, input); break; default: - throw new Error('Unknown method'); + throw new Error(`Unknown method ${method}`); } assert.ok(noDead); diff --git a/benchmark/url/url-searchparams-iteration.js b/benchmark/url/url-searchparams-iteration.js index 2b13992bdfcfc0..cae2ef5df61956 100644 --- a/benchmark/url/url-searchparams-iteration.js +++ b/benchmark/url/url-searchparams-iteration.js @@ -53,6 +53,6 @@ function main({ method, n }) { iterator(n); break; default: - throw new Error('Unknown method'); + throw new Error(`Unknown method ${method}`); } } diff --git a/benchmark/url/url-searchparams-read.js b/benchmark/url/url-searchparams-read.js index 29235ee81e0e14..0cf66dabbc36dc 100644 --- a/benchmark/url/url-searchparams-read.js +++ b/benchmark/url/url-searchparams-read.js @@ -10,45 +10,14 @@ const bench = common.createBenchmark(main, { const str = 'one=single&two=first&three=first&two=2nd&three=2nd&three=3rd'; -function get(n, param) { - const params = new URLSearchParams(str); - - bench.start(); - for (var i = 0; i < n; i += 1) - params.get(param); - bench.end(n); -} - -function getAll(n, param) { - const params = new URLSearchParams(str); - - bench.start(); - for (var i = 0; i < n; i += 1) - params.getAll(param); - bench.end(n); -} - -function has(n, param) { +function main({ method, param, n }) { const params = new URLSearchParams(str); + const fn = params[method]; + if (!fn) + throw new Error(`Unknown method ${method}`); bench.start(); for (var i = 0; i < n; i += 1) - params.has(param); + fn(param); bench.end(n); } - -function main({ method, param, n }) { - switch (method) { - case 'get': - get(n, param); - break; - case 'getAll': - getAll(n, param); - break; - case 'has': - has(n, param); - break; - default: - throw new Error('Unknown method'); - } -} diff --git a/benchmark/url/url-searchparams-sort.js b/benchmark/url/url-searchparams-sort.js index 524dacb6d52dc4..fe152bf823468f 100644 --- a/benchmark/url/url-searchparams-sort.js +++ b/benchmark/url/url-searchparams-sort.js @@ -37,9 +37,8 @@ function main({ type, n }) { const params = new URLSearchParams(); const array = getParams(input); - var i; bench.start(); - for (i = 0; i < n; i++) { + for (var i = 0; i < n; i++) { params[searchParams] = array.slice(); params.sort(); } diff --git a/benchmark/util/format.js b/benchmark/util/format.js index 5f9c4c3b594497..042b8a93ccfcf2 100644 --- a/benchmark/util/format.js +++ b/benchmark/util/format.js @@ -22,9 +22,7 @@ const bench = common.createBenchmark(main, { function main({ n, type }) { // For testing, if supplied with an empty type, default to string. - type = type || 'string'; - - const [first, second] = inputs[type]; + const [first, second] = inputs[type || 'string']; bench.start(); for (var i = 0; i < n; i++) { diff --git a/benchmark/util/inspect-array.js b/benchmark/util/inspect-array.js index 74332d18579865..8b3c54aeb942fe 100644 --- a/benchmark/util/inspect-array.js +++ b/benchmark/util/inspect-array.js @@ -18,14 +18,13 @@ function main({ n, len, type }) { var arr = Array(len); var i, opts; - // For testing, if supplied with an empty type, default to denseArray. - type = type || 'denseArray'; - switch (type) { case 'denseArray_showHidden': opts = { showHidden: true }; arr = arr.fill('denseArray'); break; + // For testing, if supplied with an empty type, default to denseArray. + case '': case 'denseArray': arr = arr.fill('denseArray'); break; diff --git a/benchmark/v8/get-stats.js b/benchmark/v8/get-stats.js index 6ee742858629c2..84a0655f5db4fa 100644 --- a/benchmark/v8/get-stats.js +++ b/benchmark/v8/get-stats.js @@ -12,9 +12,8 @@ const bench = common.createBenchmark(main, { }); function main({ method, n }) { - var i = 0; bench.start(); - for (; i < n; i++) + for (var i = 0; i < n; i++) v8[method](); bench.end(n); } diff --git a/benchmark/vm/run-in-context.js b/benchmark/vm/run-in-context.js index da8f56a6e0153b..9b57067a19c9ac 100644 --- a/benchmark/vm/run-in-context.js +++ b/benchmark/vm/run-in-context.js @@ -17,12 +17,10 @@ function main({ n, breakOnSigint, withSigintListener }) { if (withSigintListener) process.on('SIGINT', () => {}); - var i = 0; - const contextifiedSandbox = vm.createContext(); bench.start(); - for (; i < n; i++) + for (var i = 0; i < n; i++) vm.runInContext('0', contextifiedSandbox, options); bench.end(n); } diff --git a/benchmark/vm/run-in-this-context.js b/benchmark/vm/run-in-this-context.js index 33fd3a34d81f8f..0754287376d58c 100644 --- a/benchmark/vm/run-in-this-context.js +++ b/benchmark/vm/run-in-this-context.js @@ -17,10 +17,8 @@ function main({ n, breakOnSigint, withSigintListener }) { if (withSigintListener) process.on('SIGINT', () => {}); - var i = 0; - bench.start(); - for (; i < n; i++) + for (var i = 0; i < n; i++) vm.runInThisContext('0', options); bench.end(n); } diff --git a/common.gypi b/common.gypi index 0108301e3fb28c..08ef48ccedcccf 100644 --- a/common.gypi +++ b/common.gypi @@ -288,7 +288,7 @@ ], }], [ 'OS in "linux freebsd openbsd solaris aix"', { - 'cflags': [ '-pthread', ], + 'cflags': [ '-pthread' ], 'ldflags': [ '-pthread' ], }], [ 'OS in "linux freebsd openbsd solaris android aix cloudabi"', { @@ -301,6 +301,7 @@ 'standalone_static_library': 1, }], ['OS=="openbsd"', { + 'cflags': [ '-I/usr/local/include' ], 'ldflags': [ '-Wl,-z,wxneeded' ], }], ], diff --git a/configure b/configure index cd187bac81b8ef..d999cfc47d87fd 100755 --- a/configure +++ b/configure @@ -61,7 +61,7 @@ parser = optparse.OptionParser() valid_os = ('win', 'mac', 'solaris', 'freebsd', 'openbsd', 'linux', 'android', 'aix', 'cloudabi') valid_arch = ('arm', 'arm64', 'ia32', 'mips', 'mipsel', 'mips64el', 'ppc', - 'ppc64', 'x32','x64', 'x86', 's390', 's390x') + 'ppc64', 'x32','x64', 'x86', 'x86_64', 's390', 's390x') valid_arm_float_abi = ('soft', 'softfp', 'hard') valid_arm_fpu = ('vfp', 'vfpv3', 'vfpv3-d16', 'neon') valid_mips_arch = ('loongson', 'r1', 'r2', 'r6', 'rx') @@ -861,6 +861,9 @@ def configure_node(o): # the Makefile resets this to x86 afterward if target_arch == 'x86': target_arch = 'ia32' + # x86_64 is common across linuxes, allow it as an alias for x64 + if target_arch == 'x86_64': + target_arch = 'x64' o['variables']['host_arch'] = host_arch o['variables']['target_arch'] = target_arch o['variables']['node_byteorder'] = sys.byteorder diff --git a/deps/node-inspect/CHANGELOG.md b/deps/node-inspect/CHANGELOG.md index 41ed928e781ff6..0db3a7842eb15d 100644 --- a/deps/node-inspect/CHANGELOG.md +++ b/deps/node-inspect/CHANGELOG.md @@ -1,3 +1,12 @@ +### 1.11.3 + +* [`93caa0f`](https://github.com/nodejs/node-inspect/commit/93caa0f5267c7ab452b258d3b03329a0bb5ac7f7) **docs:** Add missing oc in protocol +* [`2d87cbe`](https://github.com/nodejs/node-inspect/commit/2d87cbe76aa968dfc1ac69d9571af1be81abd8e0) **fix:** Make --inspect-port=0 work +* [`ebfd02e`](https://github.com/nodejs/node-inspect/commit/ebfd02ece9b642586023f7791da71defeb13d746) **chore:** Bump tap to 10.7 +* [`c07adb1`](https://github.com/nodejs/node-inspect/commit/c07adb17b164c1cf3da8d38659ea9f5d7ff42e9c) **test:** Use useful break location +* [`94f0bf9`](https://github.com/nodejs/node-inspect/commit/94f0bf97d24c376baf3ecced2088d81715a73464) **fix:** Fix `takeHeapSnapshot()` truncation bug + + ### 1.11.2 * [`42e0cd1`](https://github.com/nodejs/node-inspect/commit/42e0cd111d89ed09faba1c0ec45089b0b44de011) **fix:** look for generic hint text diff --git a/deps/node-inspect/README.md b/deps/node-inspect/README.md index ecd939b3ea26a8..b52cc188a62f5b 100644 --- a/deps/node-inspect/README.md +++ b/deps/node-inspect/README.md @@ -10,7 +10,7 @@ node has two options: 1. `node --debug `: Start `file` with remote debugging enabled. 2. `node debug `: Start an interactive CLI debugger for ``. -But for the Chrome inspector protol, +But for the Chrome inspector protocol, there's only one: `node --inspect `. This project tries to provide the missing second option diff --git a/deps/node-inspect/lib/_inspect.js b/deps/node-inspect/lib/_inspect.js index 26912274cdaec4..d846efbe6a4a52 100644 --- a/deps/node-inspect/lib/_inspect.js +++ b/deps/node-inspect/lib/_inspect.js @@ -42,18 +42,9 @@ const [ InspectClient, createRepl ] = const debuglog = util.debuglog('inspect'); -const DEBUG_PORT_PATTERN = /^--(?:debug|inspect)(?:-port|-brk)?=(\d{1,5})$/; -function getDefaultPort() { - for (const arg of process.execArgv) { - const match = arg.match(DEBUG_PORT_PATTERN); - if (match) { - return +match[1]; - } - } - return 9229; -} - function portIsFree(host, port, timeout = 2000) { + if (port === 0) return Promise.resolve(); // Binding to a random port. + const retryDelay = 150; let didTimeOut = false; @@ -110,9 +101,11 @@ function runScript(script, scriptArgs, inspectHost, inspectPort, childPrint) { let output = ''; function waitForListenHint(text) { output += text; - if (/Debugger listening on/.test(output)) { + if (/Debugger listening on ws:\/\/\[?(.+?)\]?:(\d+)\//.test(output)) { + const host = RegExp.$1; + const port = Number.parseInt(RegExp.$2); child.stderr.removeListener('data', waitForListenHint); - resolve(child); + resolve([child, port, host]); } } @@ -160,10 +153,11 @@ class NodeInspector { options.port, this.childPrint.bind(this)); } else { - this._runScript = () => Promise.resolve(null); + this._runScript = + () => Promise.resolve([null, options.port, options.host]); } - this.client = new InspectClient(options.port, options.host); + this.client = new InspectClient(); this.domainNames = ['Debugger', 'HeapProfiler', 'Profiler', 'Runtime']; this.domainNames.forEach((domain) => { @@ -223,9 +217,8 @@ class NodeInspector { run() { this.killChild(); - const { host, port } = this.options; - return this._runScript().then((child) => { + return this._runScript().then(([child, port, host]) => { this.child = child; let connectionAttempts = 0; @@ -233,7 +226,7 @@ class NodeInspector { ++connectionAttempts; debuglog('connection attempt #%d', connectionAttempts); this.stdout.write('.'); - return this.client.connect() + return this.client.connect(port, host) .then(() => { debuglog('connection established'); this.stdout.write(' ok'); @@ -288,7 +281,7 @@ class NodeInspector { function parseArgv([target, ...args]) { let host = '127.0.0.1'; - let port = getDefaultPort(); + let port = 9229; let isRemote = false; let script = target; let scriptArgs = args; diff --git a/deps/node-inspect/lib/internal/inspect_client.js b/deps/node-inspect/lib/internal/inspect_client.js index c247e2add87706..9b8529de21aae2 100644 --- a/deps/node-inspect/lib/internal/inspect_client.js +++ b/deps/node-inspect/lib/internal/inspect_client.js @@ -164,12 +164,12 @@ function decodeFrameHybi17(data) { } class Client extends EventEmitter { - constructor(port, host) { + constructor() { super(); this.handleChunk = this._handleChunk.bind(this); - this._port = port; - this._host = host; + this._port = undefined; + this._host = undefined; this.reset(); } @@ -284,7 +284,9 @@ class Client extends EventEmitter { }); } - connect() { + connect(port, host) { + this._port = port; + this._host = host; return this._discoverWebsocketPath() .then((urlPath) => this._connectWebsocket(urlPath)); } diff --git a/deps/node-inspect/lib/internal/inspect_repl.js b/deps/node-inspect/lib/internal/inspect_repl.js index 937c1843d3a3ee..38fe4684cf6d71 100644 --- a/deps/node-inspect/lib/internal/inspect_repl.js +++ b/deps/node-inspect/lib/internal/inspect_repl.js @@ -900,10 +900,8 @@ function createRepl(inspector) { return new Promise((resolve, reject) => { const absoluteFile = Path.resolve(filename); const writer = FS.createWriteStream(absoluteFile); - let totalSize; let sizeWritten = 0; function onProgress({ done, total, finished }) { - totalSize = total; if (finished) { print('Heap snaphost prepared.'); } else { @@ -913,13 +911,18 @@ function createRepl(inspector) { function onChunk({ chunk }) { sizeWritten += chunk.length; writer.write(chunk); - print(`Writing snapshot: ${sizeWritten}/${totalSize}`, true); - if (sizeWritten >= totalSize) { - writer.end(); + print(`Writing snapshot: ${sizeWritten}`, true); + } + function onResolve() { + writer.end(() => { teardown(); print(`Wrote snapshot: ${absoluteFile}`); resolve(); - } + }); + } + function onReject(error) { + teardown(); + reject(error); } function teardown() { HeapProfiler.removeListener( @@ -932,10 +935,7 @@ function createRepl(inspector) { print('Heap snapshot: 0/0', true); HeapProfiler.takeHeapSnapshot({ reportProgress: true }) - .then(null, (error) => { - teardown(); - reject(error); - }); + .then(onResolve, onReject); }); }, diff --git a/deps/node-inspect/package.json b/deps/node-inspect/package.json index 070abfa8fe51be..d25376b5d4bb96 100644 --- a/deps/node-inspect/package.json +++ b/deps/node-inspect/package.json @@ -1,6 +1,6 @@ { "name": "node-inspect", - "version": "1.11.2", + "version": "1.11.3", "description": "Node Inspect", "license": "MIT", "main": "lib/_inspect.js", @@ -29,7 +29,7 @@ "devDependencies": { "eslint": "^3.10.2", "nlm": "^3.0.0", - "tap": "^7.1.2" + "tap": "^10.7.0" }, "author": { "name": "Jan Krems", diff --git a/deps/node-inspect/test/cli/break.test.js b/deps/node-inspect/test/cli/break.test.js index 59b12cde388c01..ce8c8d6d7d99bd 100644 --- a/deps/node-inspect/test/cli/break.test.js +++ b/deps/node-inspect/test/cli/break.test.js @@ -134,7 +134,7 @@ test('sb before loading file', (t) => { return cli.waitForInitialBreak() .then(() => cli.waitForPrompt()) - .then(() => cli.command('sb("other.js", 3)')) + .then(() => cli.command('sb("other.js", 2)')) .then(() => { t.match( cli.output, @@ -145,7 +145,7 @@ test('sb before loading file', (t) => { .then(() => { t.match( cli.output, - `break in ${otherScript}:3`, + `break in ${otherScript}:2`, 'found breakpoint in file that was not loaded yet'); }) .then(() => cli.quit()) diff --git a/deps/node-inspect/test/cli/heap-profiler.test.js b/deps/node-inspect/test/cli/heap-profiler.test.js new file mode 100644 index 00000000000000..ebd734e03cb06d --- /dev/null +++ b/deps/node-inspect/test/cli/heap-profiler.test.js @@ -0,0 +1,34 @@ +'use strict'; +const { test } = require('tap'); +const { readFileSync, unlinkSync } = require('fs'); + +const startCLI = require('./start-cli'); +const filename = 'node.heapsnapshot'; + +function cleanup() { + try { + unlinkSync(filename); + } catch (_) { + // Ignore. + } +} + +cleanup(); + +test('Heap profiler take snapshot', (t) => { + const cli = startCLI(['examples/empty.js']); + + function onFatal(error) { + cli.quit(); + throw error; + } + + // Check that the snapshot is valid JSON. + return cli.waitForInitialBreak() + .then(() => cli.waitForPrompt()) + .then(() => cli.command('takeHeapSnapshot()')) + .then(() => JSON.parse(readFileSync(filename, 'utf8'))) + .then(() => cleanup()) + .then(() => cli.quit()) + .then(null, onFatal); +}); diff --git a/deps/node-inspect/test/cli/launch.test.js b/deps/node-inspect/test/cli/launch.test.js index f7efc6eb3f2139..8808d47a08b900 100644 --- a/deps/node-inspect/test/cli/launch.test.js +++ b/deps/node-inspect/test/cli/launch.test.js @@ -26,6 +26,46 @@ test('custom port', (t) => { }); }); +test('random port', (t) => { + const script = Path.join('examples', 'three-lines.js'); + + const cli = startCLI(['--port=0', script]); + + return cli.waitForInitialBreak() + .then(() => cli.waitForPrompt()) + .then(() => { + t.match(cli.output, 'debug>', 'prints a prompt'); + t.match( + cli.output, + /< Debugger listening on /, + 'forwards child output'); + }) + .then(() => cli.quit()) + .then((code) => { + t.equal(code, 0, 'exits with success'); + }); +}); + +test('random port with --inspect-port=0', (t) => { + const script = Path.join('examples', 'three-lines.js'); + + const cli = startCLI([script], ['--inspect-port=0']); + + return cli.waitForInitialBreak() + .then(() => cli.waitForPrompt()) + .then(() => { + t.match(cli.output, 'debug>', 'prints a prompt'); + t.match( + cli.output, + /< Debugger listening on /, + 'forwards child output'); + }) + .then(() => cli.quit()) + .then((code) => { + t.equal(code, 0, 'exits with success'); + }); +}); + test('examples/three-lines.js', (t) => { const script = Path.join('examples', 'three-lines.js'); const cli = startCLI([script]); diff --git a/deps/node-inspect/test/cli/start-cli.js b/deps/node-inspect/test/cli/start-cli.js index ae904308e02270..b086dcd8ba218d 100644 --- a/deps/node-inspect/test/cli/start-cli.js +++ b/deps/node-inspect/test/cli/start-cli.js @@ -16,8 +16,8 @@ const BREAK_MESSAGE = new RegExp('(?:' + [ 'exception', 'other', 'promiseRejection', ].join('|') + ') in', 'i'); -function startCLI(args) { - const child = spawn(process.execPath, [CLI, ...args]); +function startCLI(args, flags = []) { + const child = spawn(process.execPath, [...flags, CLI, ...args]); let isFirstStdoutChunk = true; const outputBuffer = []; diff --git a/deps/v8/src/v8.gyp b/deps/v8/src/v8.gyp index bf7635ee339e2a..1c56842f81a548 100644 --- a/deps/v8/src/v8.gyp +++ b/deps/v8/src/v8.gyp @@ -2044,9 +2044,10 @@ '-L/usr/local/lib -lexecinfo', ]}, 'sources': [ + 'base/debug/stack_trace_posix.cc', 'base/platform/platform-openbsd.cc', 'base/platform/platform-posix.h', - 'base/platform/platform-posix.cc' + 'base/platform/platform-posix.cc', 'base/platform/platform-posix-time.h', 'base/platform/platform-posix-time.cc', ], diff --git a/doc/api/assert.md b/doc/api/assert.md index 280d10b8cd4a5b..1c4567eaa58aaa 100644 --- a/doc/api/assert.md +++ b/doc/api/assert.md @@ -113,7 +113,9 @@ changes: description: Enumerable symbol properties are now compared. - version: v9.0.0 pr-url: https://github.com/nodejs/node/pull/15036 - description: NaN is now compared using the [SameValueZero][] comparison. + description: NaN is now compared using the + [SameValueZero](https://tc39.github.io/ecma262/#sec-samevaluezero) + comparison. - version: v8.5.0 pr-url: https://github.com/nodejs/node/pull/15001 description: Error names and messages are now properly compared @@ -461,7 +463,9 @@ changes: description: -0 and +0 are not considered equal anymore. - version: v9.0.0 pr-url: https://github.com/nodejs/node/pull/15036 - description: NaN is now compared using the [SameValueZero][] comparison. + description: NaN is now compared using the + [SameValueZero](https://tc39.github.io/ecma262/#sec-samevaluezero) + comparison. - version: v9.0.0 pr-url: https://github.com/nodejs/node/pull/15001 description: Error names and messages are now properly compared @@ -719,11 +723,12 @@ For more information, see [MDN's guide on equality comparisons and sameness][mdn-equality-guide]. [`Error.captureStackTrace`]: errors.html#errors_error_capturestacktrace_targetobject_constructoropt -[`Map`]: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Map +[`Error`]: errors.html#errors_class_error +[`Map`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map [`Object.is()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is [`RegExp`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions -[`Set`]: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Set -[`Symbol`]: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Symbol +[`Set`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set +[`Symbol`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol [`TypeError`]: errors.html#errors_class_typeerror [`assert.deepEqual()`]: #assert_assert_deepequal_actual_expected_message [`assert.deepStrictEqual()`]: #assert_assert_deepstrictequal_actual_expected_message diff --git a/doc/api/async_hooks.md b/doc/api/async_hooks.md index 4fa23f28d116b0..2156477ae13c61 100644 --- a/doc/api/async_hooks.md +++ b/doc/api/async_hooks.md @@ -86,7 +86,7 @@ added: v8.1.0 * `before` {Function} The [`before` callback][]. * `after` {Function} The [`after` callback][]. * `destroy` {Function} The [`destroy` callback][]. -* Returns: `{AsyncHook}` Instance used for disabling and enabling hooks +* Returns: {AsyncHook} Instance used for disabling and enabling hooks Registers functions to be called for different lifetime events of each async operation. @@ -301,10 +301,10 @@ and document their own resource objects. For example, such a resource object could contain the SQL query being executed. In the case of Promises, the `resource` object will have `promise` property -that refers to the Promise that is being initialized, and a `parentId` property -set to the `asyncId` of a parent Promise, if there is one, and `undefined` +that refers to the Promise that is being initialized, and a `isChainedPromise` +property, set to `true` if the promise has a parent promise, and `false` otherwise. For example, in the case of `b = a.then(handler)`, `a` is considered -a parent Promise of `b`. +a parent Promise of `b`. Here, `b` is considered a chained promise. *Note*: In some cases the resource object is reused for performance reasons, it is thus not safe to use it as a key in a `WeakMap` or add properties to it. @@ -509,6 +509,9 @@ const server = net.createServer(function onConnection(conn) { }); ``` +Note that promise contexts may not get precise executionAsyncIds by default. +See the section on [promise execution tracking][]. + #### `async_hooks.triggerAsyncId()` * Returns: {number} The ID of the resource responsible for calling the callback @@ -531,6 +534,57 @@ const server = net.createServer((conn) => { }); ``` +Note that promise contexts may not get valid triggerAsyncIds by default. See +the section on [promise execution tracking][]. + +## Promise execution tracking + +By default, promise executions are not assigned asyncIds due to the relatively +expensive nature of the [promise introspection API][PromiseHooks] provided by +V8. This means that programs using promises or `async`/`await` will not get +correct execution and trigger ids for promise callback contexts by default. + +Here's an example: + +```js +const ah = require('async_hooks'); +Promise.resolve(1729).then(() => { + console.log(`eid ${ah.executionAsyncId()} tid ${ah.triggerAsyncId()}`); +}); +// produces: +// eid 1 tid 0 +``` + +Observe that the `then` callback claims to have executed in the context of the +outer scope even though there was an asynchronous hop involved. Also note that +the triggerAsyncId value is 0, which means that we are missing context about the +resource that caused (triggered) the `then` callback to be executed. + +Installing async hooks via `async_hooks.createHook` enables promise execution +tracking. Example: + +```js +const ah = require('async_hooks'); +ah.createHook({ init() {} }).enable(); // forces PromiseHooks to be enabled. +Promise.resolve(1729).then(() => { + console.log(`eid ${ah.executionAsyncId()} tid ${ah.triggerAsyncId()}`); +}); +// produces: +// eid 7 tid 6 +``` + +In this example, adding any actual hook function enabled the tracking of +promises. There are two promises in the example above; the promise created by +`Promise.resolve()` and the promise returned by the call to `then`. In the +example above, the first promise got the asyncId 6 and the latter got asyncId 7. +During the execution of the `then` callback, we are executing in the context of +promise with asyncId 7. This promise was triggered by async resource 6. + +Another subtlety with promises is that `before` and `after` callbacks are run +only on chained promises. That means promises not created by `then`/`catch` will +not have the `before` and `after` callbacks fired on them. For more details see +the details of the V8 [PromiseHooks][] API. + ## JavaScript Embedder API Library developers that handle their own asynchronous resources performing tasks @@ -655,3 +709,5 @@ constructor. [`destroy` callback]: #async_hooks_destroy_asyncid [`init` callback]: #async_hooks_init_asyncid_type_triggerasyncid_resource [Hook Callbacks]: #async_hooks_hook_callbacks +[PromiseHooks]: https://docs.google.com/document/d/1rda3yKGHimKIhg5YeoAmCOtyURgsbTH_qaYR79FELlk +[promise execution tracking]: #async_hooks_promise_execution_tracking diff --git a/doc/api/child_process.md b/doc/api/child_process.md index fcfd79150abf53..7ae5fd3d751e6a 100644 --- a/doc/api/child_process.md +++ b/doc/api/child_process.md @@ -44,7 +44,7 @@ implemented on top of [`child_process.spawn()`][] or [`child_process.spawnSync() * [`child_process.exec()`][]: spawns a shell and runs a command within that shell, passing the `stdout` and `stderr` to a callback function when complete. * [`child_process.execFile()`][]: similar to [`child_process.exec()`][] except that - it spawns the command directly without first spawning a shell. + it spawns the command directly without first spawning a shell by default. * [`child_process.fork()`][]: spawns a new Node.js process and invokes a specified module with an IPC communication channel established that allows sending messages between parent and child. @@ -78,7 +78,7 @@ when the child process terminates. The importance of the distinction between [`child_process.exec()`][] and [`child_process.execFile()`][] can vary based on platform. On Unix-type operating systems (Unix, Linux, macOS) [`child_process.execFile()`][] can be more efficient -because it does not spawn a shell. On Windows, however, `.bat` and `.cmd` +because it does not spawn a shell by default. On Windows, however, `.bat` and `.cmd` files are not executable on their own without a terminal, and therefore cannot be launched using [`child_process.execFile()`][]. When running on Windows, `.bat` and `.cmd` files can be invoked using [`child_process.spawn()`][] with the `shell` @@ -266,6 +266,10 @@ changes: normally be created on Windows systems. **Default:** `false`. * `windowsVerbatimArguments` {boolean} No quoting or escaping of arguments is done on Windows. Ignored on Unix. **Default:** `false`. + * `shell` {boolean|string} If `true`, runs `command` inside of a shell. Uses + `'/bin/sh'` on UNIX, and `process.env.ComSpec` on Windows. A different + shell can be specified as a string. See [Shell Requirements][] and + [Default Windows Shell][]. **Default:** `false` (no shell). * `callback` {Function} Called with the output when process terminates. * `error` {Error} * `stdout` {string|Buffer} @@ -273,7 +277,7 @@ changes: * Returns: {ChildProcess} The `child_process.execFile()` function is similar to [`child_process.exec()`][] -except that it does not spawn a shell. Rather, the specified executable `file` +except that it does not spawn a shell by default. Rather, the specified executable `file` is spawned directly as a new process making it slightly more efficient than [`child_process.exec()`][]. @@ -312,6 +316,10 @@ async function getVersion() { getVersion(); ``` +*Note*: If the `shell` option is enabled, do not pass unsanitized user input +to this function. Any input containing shell metacharacters may be used to +trigger arbitrary command execution. + ### child_process.fork(modulePath[, args][, options]) -* Returns: {Worker} A reference to `worker`. +* Returns: {cluster.Worker} A reference to `worker`. In a worker, this function will close all servers, wait for the `'close'` event on those servers, and then disconnect the IPC channel. diff --git a/doc/api/console.md b/doc/api/console.md index 84b7e2c11dac8e..0cc55b7fcbc53a 100644 --- a/doc/api/console.md +++ b/doc/api/console.md @@ -78,8 +78,8 @@ const { Console } = console; ``` ### new Console(stdout[, stderr]) -* `stdout` {Writable} -* `stderr` {Writable} +* `stdout` {stream.Writable} +* `stderr` {stream.Writable} Creates a new `Console` with one or two writable stream instances. `stdout` is a writable stream to print log or info output. `stderr` is used for warning or diff --git a/doc/api/crypto.md b/doc/api/crypto.md index f264f4ed20538e..c830a555dfed18 100644 --- a/doc/api/crypto.md +++ b/doc/api/crypto.md @@ -425,6 +425,14 @@ received _authentication tag_. If no tag is provided, or if the cipher text has been tampered with, [`decipher.final()`][] will throw, indicating that the cipher text should be discarded due to failed authentication. +Note that this Node.js version does not verify the length of GCM authentication +tags. Such a check *must* be implemented by applications and is crucial to the +authenticity of the encrypted data, otherwise, an attacker can use an +arbitrarily short authentication tag to increase the chances of successfully +passing authentication (up to 0.39%). It is highly recommended to associate one +of the values 16, 15, 14, 13, 12, 8 or 4 bytes with each key, and to only permit +authentication tags of that length, see [NIST SP 800-38D][]. + The `decipher.setAuthTag()` method must be called before [`decipher.final()`][]. @@ -1260,6 +1268,9 @@ vulnerabilities. For the case when IV is reused in GCM, see [Nonce-Disrespecting Adversaries][] for details. ### crypto.createCipheriv(algorithm, key, iv[, options]) + - `algorithm` {string} - `key` {string | Buffer | TypedArray | DataView} - `iv` {string | Buffer | TypedArray | DataView} @@ -1335,8 +1346,8 @@ recent OpenSSL releases, `openssl list-cipher-algorithms` will display the available cipher algorithms. The `key` is the raw key used by the `algorithm` and `iv` is an -[initialization vector][]. Both arguments must be `'utf8'` encoded strings or -[buffers][`Buffer`]. +[initialization vector][]. Both arguments must be `'utf8'` encoded strings, +[Buffers][`Buffer`], `TypedArray`, or `DataView`s. ### crypto.createDiffieHellman(prime[, primeEncoding][, generator][, generatorEncoding]) +changes: + - version: REPLACEME + pr-url: https://github.com/nodejs/node/pull/15752 + description: The `options` argument is supported now. +--> +- `options` {Object} + * `IncomingMessage` {http.IncomingMessage} Specifies the IncomingMessage class + to be used. Useful for extending the original `IncomingMessage`. Defaults + to: `IncomingMessage` + * `ServerResponse` {http.ServerResponse} Specifies the ServerResponse class to + be used. Useful for extending the original `ServerResponse`. Defaults to: + `ServerResponse` - `requestListener` {Function} * Returns: {http.Server} @@ -1880,6 +1893,49 @@ const req = http.request(options, (res) => { }); ``` +In a successful request, the following events will be emitted in the following +order: + +* `socket` +* `response` + * `data` any number of times, on the `res` object + (`data` will not be emitted at all if the response body is empty, for + instance, in most redirects) + * `end` on the `res` object +* `close` + +In the case of a connection error, the following events will be emitted: + +* `socket` +* `error` +* `close` + +If `req.abort()` is called before the connection succeeds, the following events +will be emitted in the following order: + +* `socket` +* (`req.abort()` called here) +* `abort` +* `close` +* `error` with an error with message `Error: socket hang up` and code + `ECONNRESET` + +If `req.abort()` is called after the response is received, the following events +will be emitted in the following order: + +* `socket` +* `response` + * `data` any number of times, on the `res` object +* (`req.abort()` called here) +* `abort` +* `close` + * `aborted` on the `res` object + * `end` on the `res` object + * `close` on the `res` object + +Note that setting the `timeout` option or using the `setTimeout` function will +not abort the request or do anything besides add a `timeout` event. + [`'checkContinue'`]: #http_event_checkcontinue [`'request'`]: #http_event_request [`'response'`]: #http_event_response diff --git a/doc/api/http2.md b/doc/api/http2.md index f4d20e2922c9b4..63700ae0051ce9 100644 --- a/doc/api/http2.md +++ b/doc/api/http2.md @@ -19,8 +19,8 @@ compatibility with the existing [HTTP/1][] module API. However, the [Compatibility API][] is. The `http2` Core API is much more symmetric between client and server than the -`http` API. For instance, most events, like `error` and `socketError`, can be -emitted either by client-side code or server-side code. +`http` API. For instance, most events, like `error`, `connect` and `stream`, can +be emitted either by client-side code or server-side code. ### Server-side example @@ -36,7 +36,6 @@ const server = http2.createSecureServer({ cert: fs.readFileSync('localhost-cert.pem') }); server.on('error', (err) => console.error(err)); -server.on('socketError', (err) => console.error(err)); server.on('stream', (stream, headers) => { // stream is a Duplex @@ -68,7 +67,6 @@ const client = http2.connect('https://localhost:8443', { ca: fs.readFileSync('localhost-cert.pem') }); client.on('error', (err) => console.error(err)); -client.on('socketError', (err) => console.error(err)); const req = client.request({ ':path': '/' }); @@ -479,44 +477,6 @@ Used to set a callback function that is called when there is no activity on the `Http2Session` after `msecs` milliseconds. The given `callback` is registered as a listener on the `'timeout'` event. -#### http2session.close(options[, callback]) - - -* `options` {Object} - * `errorCode` {number} The HTTP/2 [error code][] to return. Note that this is - *not* the same thing as an HTTP Response Status Code. **Default:** `0x00` - (No Error). - * `lastStreamID` {number} The Stream ID of the last successfully processed - `Http2Stream` on this `Http2Session`. If unspecified, will default to the - ID of the most recently received stream. - * `opaqueData` {Buffer|Uint8Array} A `Buffer` or `Uint8Array` instance - containing arbitrary additional data to send to the peer upon disconnection. - This is used, typically, to provide additional data for debugging failures, - if necessary. -* `callback` {Function} A callback that is invoked after the session shutdown - has been completed. -* Returns: {undefined} - -Attempts to shut down this `Http2Session` using HTTP/2 defined procedures. -If specified, the given `callback` function will be invoked once the shutdown -process has completed. - -If the `Http2Session` instance is a server-side session and the `errorCode` -option is `0x00` (No Error), a "graceful" shutdown will be initiated. During a -"graceful" shutdown, the session will first send a `GOAWAY` frame to -the connected peer identifying the last processed stream as 231-1. -Then, on the next tick of the event loop, a second `GOAWAY` frame identifying -the most recently processed stream identifier is sent. This process allows the -remote peer to begin preparing for the connection to be terminated. - -```js -session.close({ - opaqueData: Buffer.from('add some debugging data here') -}, () => session.destroy()); -``` - #### http2session.socket +* `alt`: {string} +* `origin`: {string} +* `streamId`: {number} + The `'altsvc'` event is emitted whenever an `ALTSVC` frame is received by the client. The event is emitted with the `ALTSVC` value, origin, and stream -ID, if any. If no `origin` is provided in the `ALTSVC` frame, `origin` will +ID. If no `origin` is provided in the `ALTSVC` frame, `origin` will be an empty string. ```js const http2 = require('http2'); const client = http2.connect('https://example.org'); -client.on('altsvc', (alt, origin, stream) => { +client.on('altsvc', (alt, origin, streamId) => { console.log(alt); console.log(origin); - console.log(stream); + console.log(streamId); }); ``` @@ -770,7 +734,7 @@ they respectively default to: added: v8.4.0 --> -* Extends: {Duplex} +* Extends: {stream.Duplex} Each instance of the `Http2Stream` class represents a bidirectional HTTP/2 communications stream over an `Http2Session` instance. Any single `Http2Session` @@ -1472,10 +1436,9 @@ added: v8.4.0 * Extends: {net.Server} -In `Http2Server`, there is no `'clientError'` event as there is in -HTTP1. However, there are `'socketError'`, `'sessionError'`, and -`'streamError'`, for errors emitted on the socket, `Http2Session`, or -`Http2Stream`. +In `Http2Server`, there are no `'clientError'` events as there are in +HTTP1. However, there are `'sessionError'`, and `'streamError'` events for +errors emitted on the socket, or from `Http2Session` or `Http2Stream` instances. #### Event: 'checkContinue' + +* `request` {http2.Http2ServerRequest} +* `response` {http2.Http2ServerResponse} + +If a [`'request'`][] listener is registered or [`http2.createSecureServer()`][] +is supplied a callback function, the `'checkContinue'` event is emitted each +time a request with an HTTP `Expect: 100-continue` is received. If this event +is not listened for, the server will automatically respond with a status +`100 Continue` as appropriate. + +Handling this event involves calling [`response.writeContinue()`][] if the client +should continue to send the request body, or generating an appropriate HTTP +response (e.g. 400 Bad Request) if the client should not continue to send the +request body. + +Note that when this event is emitted and handled, the [`'request'`][] event will +not be emitted. + +#### Event: 'request' -The `'sessionError'` event is emitted when an `'error'` event is emitted by -an `Http2Session` object associated with the `Http2SecureServer`. +* `request` {http2.Http2ServerRequest} +* `response` {http2.Http2ServerResponse} -#### Event: 'unknownProtocol' +Emitted each time there is a request. Note that there may be multiple requests +per session. See the [Compatibility API][]. + +#### Event: 'session' -The `'unknownProtocol'` event is emitted when a connecting client fails to -negotiate an allowed protocol (i.e. HTTP/2 or HTTP/1.1). The event handler -receives the socket for handling. If no listener is registered for this event, -the connection is terminated. See the [Compatibility API][]. +The `'session'` event is emitted when a new `Http2Session` is created by the +`Http2SecureServer`. + +#### Event: 'sessionError' + + +The `'sessionError'` event is emitted when an `'error'` event is emitted by +an `Http2Session` object associated with the `Http2SecureServer`. #### Event: 'stream' -* `request` {http2.Http2ServerRequest} -* `response` {http2.Http2ServerResponse} - -Emitted each time there is a request. Note that there may be multiple requests -per session. See the [Compatibility API][]. +The `'timeout'` event is emitted when there is no activity on the Server for +a given number of milliseconds set using `http2secureServer.setTimeout()`. -#### Event: 'timeout' +#### Event: 'unknownProtocol' -#### Event: 'checkContinue' - - -* `request` {http2.Http2ServerRequest} -* `response` {http2.Http2ServerResponse} - -If a [`'request'`][] listener is registered or [`http2.createSecureServer()`][] -is supplied a callback function, the `'checkContinue'` event is emitted each -time a request with an HTTP `Expect: 100-continue` is received. If this event -is not listened for, the server will automatically respond with a status -`100 Continue` as appropriate. - -Handling this event involves calling [`response.writeContinue()`][] if the client -should continue to send the request body, or generating an appropriate HTTP -response (e.g. 400 Bad Request) if the client should not continue to send the -request body. - -Note that when this event is emitted and handled, the [`'request'`][] event will -not be emitted. +The `'unknownProtocol'` event is emitted when a connecting client fails to +negotiate an allowed protocol (i.e. HTTP/2 or HTTP/1.1). The event handler +receives the socket for handling. If no listener is registered for this event, +the connection is terminated. See the [Compatibility API][]. ### http2.createServer(options[, onRequestHandler]) * `options` {Object} @@ -1723,13 +1701,27 @@ changes: and the total frame length will *not* necessarily be aligned at 8 bytes. * `peerMaxConcurrentStreams` {number} Sets the maximum number of concurrent streams for the remote peer as if a SETTINGS frame had been received. Will - be overridden if the remote peer sets its own value for. - `maxConcurrentStreams`. **Default** `100` + be overridden if the remote peer sets its own value for + `maxConcurrentStreams`. **Default:** `100` * `selectPadding` {Function} When `options.paddingStrategy` is equal to `http2.constants.PADDING_STRATEGY_CALLBACK`, provides the callback function used to determine the padding. See [Using options.selectPadding][]. * `settings` {HTTP2 Settings Object} The initial settings to send to the remote peer upon connection. + * `Http1IncomingMessage` {http.IncomingMessage} Specifies the IncomingMessage + class to used for HTTP/1 fallback. Useful for extending the original + `http.IncomingMessage`. **Default:** `http.IncomingMessage` + * `Http1ServerResponse` {http.ServerResponse} Specifies the ServerResponse + class to used for HTTP/1 fallback. Useful for extending the original + `http.ServerResponse`. **Default:** `http.ServerResponse` + * `Http2ServerRequest` {http2.Http2ServerRequest} Specifies the + Http2ServerRequest class to use. + Useful for extending the original `Http2ServerRequest`. + **Default:** `Http2ServerRequest` + * `Http2ServerResponse` {htt2.Http2ServerResponse} Specifies the + Http2ServerResponse class to use. + Useful for extending the original `Http2ServerResponse`. + **Default:** `Http2ServerResponse` * `onRequestHandler` {Function} See [Compatibility API][] * Returns: {Http2Server} diff --git a/doc/api/https.md b/doc/api/https.md index cb22873a01e1ba..4ac82220c85cef 100644 --- a/doc/api/https.md +++ b/doc/api/https.md @@ -12,7 +12,7 @@ separate module. added: v0.4.5 --> -An Agent object for HTTPS similar to [`http.Agent`][]. See [`https.request()`][] +An [`Agent`][] object for HTTPS similar to [`http.Agent`][]. See [`https.request()`][] for more information. ## Class: https.Server @@ -65,7 +65,8 @@ See [`http.Server#keepAliveTimeout`][]. -- `options` {Object} Accepts `options` from [`tls.createServer()`][] and [`tls.createSecureContext()`][]. +- `options` {Object} Accepts `options` from [`tls.createServer()`][], + [`tls.createSecureContext()`][] and [`http.createServer()`][]. - `requestListener` {Function} A listener to be added to the `request` event. Example: @@ -167,9 +168,10 @@ changes: Makes a request to a secure web server. -The following additional `options` from [`tls.connect()`][] are also accepted -when using a custom [`Agent`][]: `ca`, `cert`, `ciphers`, `clientCertEngine`, -`key`, `passphrase`, `pfx`, `rejectUnauthorized`, `secureProtocol`, `servername` +The following additional `options` from [`tls.connect()`][] are also accepted: +`ca`, `cert`, `ciphers`, `clientCertEngine`, `crl`, `dhparam`, `ecdhCurve`, +`honorCipherOrder`, `key`, `passphrase`, `pfx`, `rejectUnauthorized`, +`secureOptions`, `secureProtocol`, `servername`, `sessionIdContext` `options` can be an object, a string, or a [`URL`][] object. If `options` is a string, it is automatically parsed with [`url.parse()`][]. If it is a [`URL`][] @@ -219,7 +221,7 @@ const req = https.request(options, (res) => { }); ``` -Alternatively, opt out of connection pooling by not using an `Agent`. +Alternatively, opt out of connection pooling by not using an [`Agent`][]. Example: @@ -258,6 +260,7 @@ const req = https.request(options, (res) => { [`http.Server#setTimeout()`]: http.html#http_server_settimeout_msecs_callback [`http.Server#timeout`]: http.html#http_server_timeout [`http.Server`]: http.html#http_class_http_server +[`http.createServer()`]: http.html#http_http_createserver_options_requestlistener [`http.close()`]: http.html#http_server_close_callback [`http.get()`]: http.html#http_http_get_options_callback [`http.request()`]: http.html#http_http_request_options_callback diff --git a/doc/api/intl.md b/doc/api/intl.md index 224c00a62fe888..83a9947dc21238 100644 --- a/doc/api/intl.md +++ b/doc/api/intl.md @@ -190,17 +190,17 @@ to be helpful: ["ICU Data"]: http://userguide.icu-project.org/icudata [`--icu-data-dir`]: cli.html#cli_icu_data_dir_file -[`Date.prototype.toLocaleString()`]: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleString -[`Intl`]: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Intl +[`Date.prototype.toLocaleString()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleString +[`Intl`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl [`Intl.DateTimeFormat`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat [`NODE_ICU_DATA`]: cli.html#cli_node_icu_data_file -[`Number.prototype.toLocaleString()`]: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString +[`Number.prototype.toLocaleString()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString [`require('buffer').transcode()`]: buffer.html#buffer_buffer_transcode_source_fromenc_toenc [`require('util').TextDecoder`]: util.html#util_class_util_textdecoder -[`String.prototype.localeCompare()`]: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare -[`String.prototype.normalize()`]: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String/normalize -[`String.prototype.toLowerCase()`]: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String/toLowerCase -[`String.prototype.toUpperCase()`]: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String/toUpperCase +[`String.prototype.localeCompare()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare +[`String.prototype.normalize()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize +[`String.prototype.toLowerCase()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toLowerCase +[`String.prototype.toUpperCase()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toUpperCase [BUILDING.md]: https://github.com/nodejs/node/blob/master/BUILDING.md [BUILDING.md#full-icu]: https://github.com/nodejs/node/blob/master/BUILDING.md#build-with-full-icu-support-all-locales-supported-by-icu [ECMA-262]: https://tc39.github.io/ecma262/ diff --git a/doc/api/n-api.md b/doc/api/n-api.md index 05e799cc0e550b..1b94e71d1a1ade 100644 --- a/doc/api/n-api.md +++ b/doc/api/n-api.md @@ -554,10 +554,10 @@ NAPI_NO_RETURN void napi_fatal_error(const char* location, - `[in] location`: Optional location at which the error occurred. - `[in] location_len`: The length of the location in bytes, or -NAPI_AUTO_LENGTH if it is null-terminated. +`NAPI_AUTO_LENGTH` if it is null-terminated. - `[in] message`: The message associated with the error. - `[in] message_len`: The length of the message in bytes, or -NAPI_AUTO_LENGTH if it is +`NAPI_AUTO_LENGTH` if it is null-terminated. The function call does not return, the process will be terminated. @@ -918,7 +918,7 @@ For example, to set a function to be returned by the `require()` for the addon: napi_value Init(napi_env env, napi_value exports) { napi_value method; napi_status status; - status = napi_create_function(env, "exports", Method, NULL, &method)); + status = napi_create_function(env, "exports", NAPI_AUTO_LENGTH, Method, NULL, &method); if (status != napi_ok) return NULL; return method; } @@ -1255,7 +1255,7 @@ napi_status napi_create_function(napi_env env, - `[in] utf8name`: A string representing the name of the function encoded as UTF8. - `[in] length`: The length of the utf8name in bytes, or -NAPI_AUTO_LENGTH if it is null-terminated. +`NAPI_AUTO_LENGTH` if it is null-terminated. - `[in] cb`: A function pointer to the native function to be invoked when the created function is invoked from JavaScript. - `[in] data`: Optional arbitrary context data to be passed into the native @@ -1483,7 +1483,7 @@ napi_status napi_create_string_latin1(napi_env env, - `[in] env`: The environment that the API is invoked under. - `[in] str`: Character buffer representing a ISO-8859-1-encoded string. - `[in] length`: The length of the string in bytes, or -NAPI_AUTO_LENGTH if it is null-terminated. +`NAPI_AUTO_LENGTH` if it is null-terminated. - `[out] result`: A `napi_value` representing a JavaScript String. Returns `napi_ok` if the API succeeded. @@ -1507,7 +1507,7 @@ napi_status napi_create_string_utf16(napi_env env, - `[in] env`: The environment that the API is invoked under. - `[in] str`: Character buffer representing a UTF16-LE-encoded string. - `[in] length`: The length of the string in two-byte code units, or -NAPI_AUTO_LENGTH if it is null-terminated. +`NAPI_AUTO_LENGTH` if it is null-terminated. - `[out] result`: A `napi_value` representing a JavaScript String. Returns `napi_ok` if the API succeeded. @@ -1530,7 +1530,7 @@ napi_status napi_create_string_utf8(napi_env env, - `[in] env`: The environment that the API is invoked under. - `[in] str`: Character buffer representing a UTF8-encoded string. -- `[in] length`: The length of the string in bytes, or NAPI_AUTO_LENGTH +- `[in] length`: The length of the string in bytes, or `NAPI_AUTO_LENGTH` if it is null-terminated. - `[out] result`: A `napi_value` representing a JavaScript String. @@ -3053,7 +3053,7 @@ napi_status napi_define_class(napi_env env, - `[in] utf8name`: Name of the JavaScript constructor function; this is not required to be the same as the C++ class name, though it is recommended for clarity. - - `[in] length`: The length of the utf8name in bytes, or NAPI_AUTO_LENGTH + - `[in] length`: The length of the utf8name in bytes, or `NAPI_AUTO_LENGTH` if it is null-terminated. - `[in] constructor`: Callback function that handles constructing instances of the class. (This should be a static method on the class, not an actual @@ -3146,11 +3146,8 @@ required in order to enable correct proper of the reference. Afterward, additional manipulation of the wrapper's prototype chain may cause `napi_unwrap()` to fail. -*Note*: Calling `napi_wrap()` a second time on an object that already has a -native instance associated with it by virtue of a previous call to -`napi_wrap()` will cause an error to be returned. If you wish to associate -another native instance with the given object, call `napi_remove_wrap()` on it -first. +Calling napi_wrap() a second time on an object will return an error. To associate +another native instance with the object, use napi_remove_wrap() first. ### napi_unwrap +```C +NAPI_EXTERN napi_status napi_open_callback_scope(napi_env env, + napi_value resource_object, + napi_async_context context, + napi_callback_scope* result) +``` +- `[in] env`: The environment that the API is invoked under. +- `[in] resource_object`: An optional object associated with the async work + that will be passed to possible async_hooks [`init` hooks][]. +- `[in] context`: Context for the async operation that is +invoking the callback. This should be a value previously obtained +from [`napi_async_init`][]. +- `[out] result`: The newly created scope. + +There are cases (for example resolving promises) where it is +necessary to have the equivalent of the scope associated with a callback +in place when making certain N-API calls. If there is no other script on +the stack the [`napi_open_callback_scope`][] and +[`napi_close_callback_scope`][] functions can be used to open/close +the required scope. + +### *napi_close_callback_scope* + +```C +NAPI_EXTERN napi_status napi_close_callback_scope(napi_env env, + napi_callback_scope scope) +``` +- `[in] env`: The environment that the API is invoked under. +- `[in] scope`: The scope to be closed. + ## Version Management ### napi_get_node_version @@ -3719,6 +3752,7 @@ NAPI_EXTERN napi_status napi_get_uv_event_loop(napi_env env, [`napi_async_init`]: #n_api_napi_async_init [`napi_cancel_async_work`]: #n_api_napi_cancel_async_work [`napi_close_escapable_handle_scope`]: #n_api_napi_close_escapable_handle_scope +[`napi_close_callback_scope`]: #n_api_napi_close_callback_scope [`napi_close_handle_scope`]: #n_api_napi_close_handle_scope [`napi_create_async_work`]: #n_api_napi_create_async_work [`napi_create_error`]: #n_api_napi_create_error @@ -3744,6 +3778,7 @@ NAPI_EXTERN napi_status napi_get_uv_event_loop(napi_env env, [`napi_get_last_error_info`]: #n_api_napi_get_last_error_info [`napi_get_and_clear_last_exception`]: #n_api_napi_get_and_clear_last_exception [`napi_make_callback`]: #n_api_napi_make_callback +[`napi_open_callback_scope`]: #n_api_napi_open_callback_scope [`napi_open_escapable_handle_scope`]: #n_api_napi_open_escapable_handle_scope [`napi_open_handle_scope`]: #n_api_napi_open_handle_scope [`napi_property_descriptor`]: #n_api_napi_property_descriptor diff --git a/doc/api/perf_hooks.md b/doc/api/perf_hooks.md index 6d98d25af37cbc..608bee8d574680 100644 --- a/doc/api/perf_hooks.md +++ b/doc/api/perf_hooks.md @@ -125,6 +125,20 @@ Creates a new `PerformanceMark` entry in the Performance Timeline. A `performanceEntry.duration` is always `0`. Performance marks are used to mark specific significant moments in the Performance Timeline. +### performance.maxEntries + + +Value: {number} + +The maximum number of Performance Entry items that should be added to the +Performance Timeline. This limit is not strictly enforced, but a process +warning will be emitted if the number of entries in the timeline exceeds +this limit. + +Defaults to 150. + ### performance.measure(name, startMark, endMark) -* `stream` {Writable} +* `stream` {stream.Writable} * `dir` {number} * `-1` - to the left from cursor * `1` - to the right from cursor @@ -338,7 +338,7 @@ in a specified direction identified by `dir`. added: v0.7.7 --> -* `stream` {Writable} +* `stream` {stream.Writable} The `readline.clearScreenDown()` method clears the given [TTY][] stream from the current position of the cursor down. @@ -362,9 +362,9 @@ changes: --> * `options` {Object} - * `input` {Readable} The [Readable][] stream to listen to. This option is + * `input` {stream.Readable} The [Readable][] stream to listen to. This option is *required*. - * `output` {Writable} The [Writable][] stream to write readline data to. + * `output` {stream.Writable} The [Writable][] stream to write readline data to. * `completer` {Function} An optional function used for Tab autocompletion. * `terminal` {boolean} `true` if the `input` and `output` streams should be treated like a TTY, and have ANSI/VT100 escape codes written to it. @@ -444,7 +444,7 @@ function completer(linePartial, callback) { added: v0.7.7 --> -* `stream` {Writable} +* `stream` {stream.Writable} * `x` {number} * `y` {number} @@ -456,7 +456,7 @@ given [TTY][] `stream`. added: v0.7.7 --> -* `stream` {Readable} +* `stream` {stream.Readable} * `interface` {readline.Interface} The `readline.emitKeypressEvents()` method causes the given [Readable][] @@ -482,7 +482,7 @@ if (process.stdin.isTTY) added: v0.7.7 --> -* `stream` {Writable} +* `stream` {stream.Writable} * `dx` {number} * `dy` {number} diff --git a/doc/api/repl.md b/doc/api/repl.md index a1dfffa9cc0c0a..506f54a4b8a2a8 100644 --- a/doc/api/repl.md +++ b/doc/api/repl.md @@ -412,9 +412,9 @@ changes: * `options` {Object|string} * `prompt` {string} The input prompt to display. Defaults to `> ` (with a trailing space). - * `input` {Readable} The Readable stream from which REPL input will be read. + * `input` {stream.Readable} The Readable stream from which REPL input will be read. Defaults to `process.stdin`. - * `output` {Writable} The Writable stream to which REPL output will be + * `output` {stream.Writable} The Writable stream to which REPL output will be written. Defaults to `process.stdout`. * `terminal` {boolean} If `true`, specifies that the `output` should be treated as a TTY terminal, and have ANSI/VT100 escape codes written to it. diff --git a/doc/api/stream.md b/doc/api/stream.md index c0351a3679445e..529a6681e316b1 100644 --- a/doc/api/stream.md +++ b/doc/api/stream.md @@ -394,7 +394,7 @@ changes: --> * `encoding` {string} The new default encoding -* Returns: `this` +* Returns: {this} The `writable.setDefaultEncoding()` method sets the default `encoding` for a [Writable][] stream. @@ -533,7 +533,7 @@ A Writable stream in object mode will always ignore the `encoding` argument. added: v8.0.0 --> -* Returns: `this` +* Returns: {this} Destroy the stream, and emit the passed error. After this call, the writable stream has ended. Implementors should not override this method, @@ -580,8 +580,8 @@ The Readable can switch back to paused mode using one of the following: * If there are no pipe destinations, by calling the [`stream.pause()`][stream-pause] method. -* If there are pipe destinations, by removing any [`'data'`][] event - handlers, and removing all pipe destinations by calling the +* If there are pipe destinations, by removing all pipe destinations. + Multiple pipe destinations may be removed by calling the [`stream.unpipe()`][] method. The important concept to remember is that a Readable will not generate data @@ -818,7 +818,7 @@ readable.isPaused(); // === false added: v0.9.4 --> -* Returns: `this` +* Returns: {this} The `readable.pause()` method will cause a stream in flowing mode to stop emitting [`'data'`][] events, switching out of flowing mode. Any data that @@ -967,7 +967,7 @@ the status of the `highWaterMark`. added: v0.9.4 --> -* Returns: `this` +* Returns: {this} The `readable.resume()` method causes an explicitly paused Readable stream to resume emitting [`'data'`][] events, switching the stream into flowing mode. @@ -990,7 +990,7 @@ added: v0.9.4 --> * `encoding` {string} The encoding to use. -* Returns: `this` +* Returns: {this} The `readable.setEncoding()` method sets the character encoding for data read from the Readable stream. @@ -1428,7 +1428,7 @@ write succeeded. All calls to `writable.write()` that occur between the time `writable._write()` is called and the `callback` is called will cause the written data to be -buffered. Once the `callback` is invoked, the stream will emit a [`'drain'`][] +buffered. When the `callback` is invoked, the stream might emit a [`'drain'`][] event. If a stream implementation is capable of processing multiple chunks of data at once, the `writable._writev()` method should be implemented. diff --git a/doc/api/synopsis.md b/doc/api/synopsis.md index ada2437387b7e2..508dde1ff483f8 100644 --- a/doc/api/synopsis.md +++ b/doc/api/synopsis.md @@ -9,9 +9,58 @@ Please see the [Command Line Options][] document for information about different options and ways to run scripts with Node.js. ## Example - An example of a [web server][] written with Node.js which responds with -`'Hello World'`: +`'Hello World!'`: + +Commands displayed in this document are shown starting with `$` or `>` +to replicate how they would appear in a user's terminal. +Do not include the `$` and `>` character they are there to +indicate the start of each command. + +There are many tutorials and examples that follow this +convention: `$` or `>` for commands run as a regular user, and `#` +for commands that should be executed as an administrator. + +Lines that don’t start with `$` or `>` character are typically showing +the output of the previous command. + +Firstly, make sure to have downloaded and installed Node.js. +See [this guide][] for further install information. + +Now, create an empty project folder called `projects`, navigate into it: +Project folder can be named base on user's current project title but +this example will use `projects` as the project folder. + +Linux and Mac: + +```console +$ mkdir ~/projects +$ cd ~/projects +``` + +Windows CMD: + +```console +> mkdir %USERPROFILE%\projects +> cd %USERPROFILE%\projects +``` + +Windows PowerShell: + +```console +> mkdir $env:USERPROFILE\projects +> cd $env:USERPROFILE\projects +``` + +Next, create a new source file in the `projects` + folder and call it `hello-world.js`. + +In Node.js it is considered good style to use +hyphens (`-`) or underscores (`_`) to separate + multiple words in filenames. + +Open `hello-world.js` in any preferred text editor and +paste in the following content. ```js const http = require('http'); @@ -22,7 +71,7 @@ const port = 3000; const server = http.createServer((req, res) => { res.statusCode = 200; res.setHeader('Content-Type', 'text/plain'); - res.end('Hello World\n'); + res.end('Hello World!\n'); }); server.listen(port, hostname, () => { @@ -30,15 +79,26 @@ server.listen(port, hostname, () => { }); ``` -To run the server, put the code into a file called `example.js` and execute -it with Node.js: +Save the file, go back to the terminal window enter the following command: -```txt -$ node example.js -Server running at http://127.0.0.1:3000/ +```console +$ node hello-world.js ``` +An output like this should appear in the terminal to indicate Node.js +server is running: + + ```console + Server running at http://127.0.0.1:3000/ + ```` + +Now, open any preferred web browser and visit `http://127.0.0.1:3000`. + +If the browser displays the string `Hello, world!`, that indicates +the server is working. + Many of the examples in the documentation can be run similarly. [Command Line Options]: cli.html#cli_command_line_options [web server]: http.html +[this guide]: https://nodejs.org/en/download/package-manager/ diff --git a/doc/api/url.md b/doc/api/url.md index 5f504a5bc8937f..38cb95d6097ae9 100644 --- a/doc/api/url.md +++ b/doc/api/url.md @@ -1030,6 +1030,11 @@ The formatting process operates as follows: ### url.parse(urlString[, parseQueryString[, slashesDenoteHost]]) * `urlString` {string} The URL string to parse. @@ -1144,7 +1149,7 @@ console.log(myURL.origin); ``` [`Error`]: errors.html#errors_class_error -[`JSON.stringify()`]: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify +[`JSON.stringify()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify [`Map`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map [`TypeError`]: errors.html#errors_class_typeerror [`URLSearchParams`]: #url_class_urlsearchparams diff --git a/doc/api/util.md b/doc/api/util.md index 9fd7926cc1a627..00d04df8f850ee 100644 --- a/doc/api/util.md +++ b/doc/api/util.md @@ -1217,7 +1217,7 @@ Deprecated predecessor of `console.log`. [`Array.isArray`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray [`Buffer.isBuffer()`]: buffer.html#buffer_class_method_buffer_isbuffer_obj [`Error`]: errors.html#errors_class_error -[`Object.assign()`]: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign +[`Object.assign()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign [`assert.deepStrictEqual()`]: assert.html#assert_assert_deepstrictequal_actual_expected_message [`console.error()`]: console.html#console_console_error_data_args [`console.log()`]: console.html#console_console_log_data_args @@ -1228,5 +1228,5 @@ Deprecated predecessor of `console.log`. [Customizing `util.inspect` colors]: #util_customizing_util_inspect_colors [Internationalization]: intl.html [WHATWG Encoding Standard]: https://encoding.spec.whatwg.org/ -[constructor]: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/constructor +[constructor]: https://developer.mozilla.org/en-US/JavaScript/Reference/Global_Objects/Object/constructor [semantically incompatible]: https://github.com/nodejs/node/issues/4179 diff --git a/doc/api/vm.md b/doc/api/vm.md index a26ee4ed94d090..969f1a79aef661 100644 --- a/doc/api/vm.md +++ b/doc/api/vm.md @@ -43,6 +43,321 @@ console.log(x); // 1; y is not defined. *Note*: The vm module is not a security mechanism. **Do not use it to run untrusted code**. +## Class: vm.Module + + +> Stability: 1 - Experimental + +*This feature is only available with the `--experimental-vm-modules` command +flag enabled.* + +The `vm.Module` class provides a low-level interface for using ECMAScript +modules in VM contexts. It is the counterpart of the `vm.Script` class that +closely mirrors [Source Text Module Record][]s as defined in the ECMAScript +specification. + +Unlike `vm.Script` however, every `vm.Module` object is bound to a context from +its creation. Operations on `vm.Module` objects are intrinsically asynchronous, +in contrast with the synchronous nature of `vm.Script` objects. With the help +of async functions, however, manipulating `vm.Module` objects is fairly +straightforward. + +Using a `vm.Module` object requires four distinct steps: creation/parsing, +linking, instantiation, and evaluation. These four steps are illustrated in the +following example. + +*Note*: This implementation lies at a lower level than the [ECMAScript Module +loader][]. There is also currently no way to interact with the Loader, though +support is planned. + +```js +const vm = require('vm'); + +const contextifiedSandbox = vm.createContext({ secret: 42 }); + +(async () => { + // Step 1 + // + // Create a Module by constructing a new `vm.Module` object. This parses the + // provided source text, throwing a `SyntaxError` if anything goes wrong. By + // default, a Module is created in the top context. But here, we specify + // `contextifiedSandbox` as the context this Module belongs to. + // + // Here, we attempt to obtain the default export from the module "foo", and + // put it into local binding "secret". + + const bar = new vm.Module(` + import s from 'foo'; + s; + `, { context: contextifiedSandbox }); + + + // Step 2 + // + // "Link" the imported dependencies of this Module to it. + // + // The provided linking callback (the "linker") accepts two arguments: the + // parent module (`bar` in this case) and the string that is the specifier of + // the imported module. The callback is expected to return a Module that + // corresponds to the provided specifier, with certain requirements documented + // in `module.link()`. + // + // If linking has not started for the returned Module, the same linker + // callback will be called on the returned Module. + // + // Even top-level Modules without dependencies must be explicitly linked. The + // callback provided would never be called, however. + // + // The link() method returns a Promise that will be resolved when all the + // Promises returned by the linker resolve. + // + // Note: This is a contrived example in that the linker function creates a new + // "foo" module every time it is called. In a full-fledged module system, a + // cache would probably be used to avoid duplicated modules. + + async function linker(specifier, referencingModule) { + if (specifier === 'foo') { + return new vm.Module(` + // The "secret" variable refers to the global variable we added to + // "contextifiedSandbox" when creating the context. + export default secret; + `, { context: referencingModule.context }); + + // Using `contextifiedSandbox` instead of `referencingModule.context` + // here would work as well. + } + throw new Error(`Unable to resolve dependency: ${specifier}`); + } + await bar.link(linker); + + + // Step 3 + // + // Instantiate the top-level Module. + // + // Only the top-level Module needs to be explicitly instantiated; its + // dependencies will be recursively instantiated by instantiate(). + + bar.instantiate(); + + + // Step 4 + // + // Evaluate the Module. The evaluate() method returns a Promise with a single + // property "result" that contains the result of the very last statement + // executed in the Module. In the case of `bar`, it is `s;`, which refers to + // the default export of the `foo` module, the `secret` we set in the + // beginning to 42. + + const { result } = await bar.evaluate(); + + console.log(result); + // Prints 42. +})(); +``` + +### Constructor: new vm.Module(code[, options]) + +* `code` {string} JavaScript Module code to parse +* `options` + * `url` {string} URL used in module resolution and stack traces. **Default**: + `'vm:module(i)'` where `i` is a context-specific ascending index. + * `context` {Object} The [contextified][] object as returned by the + `vm.createContext()` method, to compile and evaluate this Module in. + * `lineOffset` {integer} Specifies the line number offset that is displayed + in stack traces produced by this Module. + * `columnOffset` {integer} Spcifies the column number offset that is displayed + in stack traces produced by this Module. + +Creates a new ES `Module` object. + +### module.dependencySpecifiers + +* {string[]} + +The specifiers of all dependencies of this module. The returned array is frozen +to disallow any changes to it. + +Corresponds to the [[RequestedModules]] field of [Source Text Module Record][]s +in the ECMAScript specification. + +### module.error + +* {any} + +If the `module.status` is `'errored'`, this property contains the exception thrown +by the module during evaluation. If the status is anything else, accessing this +property will result in a thrown exception. + +*Note*: `undefined` cannot be used for cases where there is not a thrown +exception due to possible ambiguity with `throw undefined;`. + +Corresponds to the [[EvaluationError]] field of [Source Text Module Record][]s +in the ECMAScript specification. + +### module.linkingStatus + +* {string} + +The current linking status of `module`. It will be one of the following values: + +- `'unlinked'`: `module.link()` has not yet been called. +- `'linking'`: `module.link()` has been called, but not all Promises returned by + the linker function have been resolved yet. +- `'linked'`: `module.link()` has been called, and all its dependencies have + been successfully linked. +- `'errored'`: `module.link()` has been called, but at least one of its + dependencies failed to link, either because the callback returned a Promise + that is rejected, or because the Module the callback returned is invalid. + +### module.namespace + +* {Object} + +The namespace object of the module. This is only available after instantiation +(`module.instantiate()`) has completed. + +Corresponds to the [GetModuleNamespace][] abstract operation in the ECMAScript +specification. + +### module.status + +* {string} + +The current status of the module. Will be one of: + +- `'uninstantiated'`: The module is not instantiated. It may because of any of + the following reasons: + + - The module was just created. + - `module.instantiate()` has been called on this module, but it failed for + some reason. + + This status does not convey any information regarding if `module.link()` has + been called. See `module.linkingStatus` for that. + +- `'instantiating'`: The module is currently being instantiated through a + `module.instantiate()` call on itself or a parent module. + +- `'instantiated'`: The module has been instantiated successfully, but + `module.evaluate()` has not yet been called. + +- `'evaluating'`: The module is being evaluated through a `module.evaluate()` on + itself or a parent module. + +- `'evaluated'`: The module has been successfully evaluated. + +- `'errored'`: The module has been evaluated, but an exception was thrown. + +Other than `'errored'`, this status string corresponds to the specification's +[Source Text Module Record][]'s [[Status]] field. `'errored'` corresponds to +`'evaluated'` in the specification, but with [[EvaluationError]] set to a value +that is not `undefined`. + +### module.url + +* {string} + +The URL of the current module, as set in the constructor. + +### module.evaluate([options]) + +* `options` {Object} + * `timeout` {number} Specifies the number of milliseconds to evaluate + before terminating execution. If execution is interrupted, an [`Error`][] + will be thrown. + * `breakOnSigint` {boolean} If `true`, the execution will be terminated when + `SIGINT` (Ctrl+C) is received. Existing handlers for the event that have + been attached via `process.on("SIGINT")` will be disabled during script + execution, but will continue to work after that. If execution is + interrupted, an [`Error`][] will be thrown. +* Returns: {Promise} + +Evaluate the module. + +This must be called after the module has been instantiated; otherwise it will +throw an error. It could be called also when the module has already been +evaluated, in which case it will do one of the following two things: + +- return `undefined` if the initial evaluation ended in success (`module.status` + is `'evaluated'`) +- rethrow the same exception the initial evaluation threw if the initial + evaluation ended in an error (`module.status` is `'errored'`) + +This method cannot be called while the module is being evaluated +(`module.status` is `'evaluating'`) to prevent infinite recursion. + +Corresponds to the [Evaluate() concrete method][] field of [Source Text Module +Record][]s in the ECMAScript specification. + +### module.instantiate() + +Instantiate the module. This must be called after linking has completed +(`linkingStatus` is `'linked'`); otherwise it will throw an error. It may also +throw an exception if one of the dependencies does not provide an export the +parent module requires. + +However, if this function succeeded, further calls to this function after the +initial instantiation will be no-ops, to be consistent with the ECMAScript +specification. + +Unlike other methods operating on `Module`, this function completes +synchronously and returns nothing. + +Corresponds to the [Instantiate() concrete method][] field of [Source Text +Module Record][]s in the ECMAScript specification. + +### module.link(linker) + +* `linker` {Function} +* Returns: {Promise} + +Link module dependencies. This method must be called before instantiation, and +can only be called once per module. + +Two parameters will be passed to the `linker` function: + +- `specifier` The specifier of the requested module: + + ```js + import foo from 'foo'; + // ^^^^^ the module specifier + ``` +- `referencingModule` The `Module` object `link()` is called on. + +The function is expected to return a `Module` object or a `Promise` that +eventually resolves to a `Module` object. The returned `Module` must satisfy the +following two invariants: + +- It must belong to the same context as the parent `Module`. +- Its `linkingStatus` must not be `'errored'`. + +If the returned `Module`'s `linkingStatus` is `'unlinked'`, this method will be +recursively called on the returned `Module` with the same provided `linker` +function. + +`link()` returns a `Promise` that will either get resolved when all linking +instances resolve to a valid `Module`, or rejected if the linker function either +throws an exception or returns an invalid `Module`. + +The linker function roughly corresponds to the implementation-defined +[HostResolveImportedModule][] abstract operation in the ECMAScript +specification, with a few key differences: + +- The linker function is allowed to be asynchronous while + [HostResolveImportedModule][] is synchronous. +- The linker function is executed during linking, a Node.js-specific stage + before instantiation, while [HostResolveImportedModule][] is called during + instantiation. + +The actual [HostResolveImportedModule][] implementation used during module +instantiation is one that returns the modules linked during linking. Since at +that point all modules would have been fully linked already, the +[HostResolveImportedModule][] implementation is fully synchronous per +specification. + ## Class: vm.Script +- `icu-system.gyp` is an alternate build file used when `--with-intl=system-icu` is invoked. It builds against the `pkg-config` located ICU. +- `iculslocs.cc` is source for the `iculslocs` utility, invoked by `icutrim.py` as part of repackaging. Not used separately. See source for more details. +- `no-op.cc` — empty function to convince gyp to use a C++ compiler. +- `README.md` — you are here +- `shrink-icu-src.py` — this is used during upgrade (see guide below) ## How to upgrade ICU @@ -12,13 +23,13 @@ make ``` -(The equivalent `vcbuild.bat` commands should work also. Note that we use the `.tgz` and not the `.zip` here, -that is because of line endings.) +> _Note_ in theory, the equivalent `vcbuild.bat` commands should work also, +> but the commands below are makefile-centric. -- (note- may need to make changes in `icu-generic.gyp` or `tools/icu/patches` for -version specific stuff) +- If there are ICU version-specific changes needed, you may need to make changes in `icu-generic.gyp` or add patch files to `tools/icu/patches`. + - Specifically, look for the lists in `sources!` in the `icu-generic.gyp` for files to exclude. -- Verify the node build works +- Verify the node build works: ```shell make test-ci @@ -27,13 +38,12 @@ make test-ci Also running + ```js new Intl.DateTimeFormat('es', {month: 'long'}).format(new Date(9E8)); ``` …Should return `January` not `enero`. -(TODO here: improve [testing](https://github.com/nodejs/Intl/issues/16)) - - Now, copy `deps/icu` over to `deps/icu-small` @@ -43,25 +53,25 @@ python tools/icu/shrink-icu-src.py - Now, do a clean rebuild of node to test: -(TODO: fix this when these options become default) - ```shell -./configure --with-intl=small-icu --with-icu-source=deps/icu-small +make -k distclean +./configure make ``` - Test this newly default-generated Node.js + ```js process.versions.icu; new Intl.DateTimeFormat('es', {month: 'long'}).format(new Date(9E8)); ``` -(should return your updated ICU version number, and also `January` again.) +(This should print your updated ICU version number, and also `January` again.) -- You are ready to check in the updated `deps/small-icu`. -This is a big commit, so make this a separate commit from other changes. +You are ready to check in the updated `deps/small-icu`. This is a big commit, +so make this a separate commit from the smaller changes. - Now, rebuild the Node license. @@ -85,22 +95,23 @@ make test-ci - commit the change to `configure` along with the updated `LICENSE` file. + - Note: To simplify review, I often will “pre-land” this patch, meaning that I run the patch through `curl -L https://github.com/nodejs/node/pull/xxx.patch | git am -3 --whitespace=fix` per the collaborator’s guide… and then push that patched branch into my PR's branch. This reduces the whitespace changes that show up in the PR, since the final land will eliminate those anyway. + ----- -## Notes about these tools +## Postscript about the tools -The files in this directory were written for the node.js effort. It's -the intent of their author (Steven R. Loomis / srl295) to merge them -upstream into ICU, pending much discussion within the ICU-PMC. +The files in this directory were written for the node.js effort. +It was the intent of their author (Steven R. Loomis / srl295) to +merge them upstream into ICU, pending much discussion within the +ICU-TC. `icu_small.json` is somewhat node-specific as it specifies a "small ICU" configuration file for the `icutrim.py` script. `icutrim.py` and `iculslocs.cpp` may themselves be superseded by components built into -ICU in the future. - -The following tickets were opened during this work, and their -resolution may inform the reader as to the current state of icu-trim -upstream: +ICU in the future. As of this writing, however, the tools are separate +entities within Node, although theyare being scrutinized by interested +members of the ICU-TC. The “upstream” ICU bugs are given below. * [#10919](http://bugs.icu-project.org/trac/ticket/10919) (experimental branch - may copy any source patches here) @@ -108,7 +119,3 @@ upstream: (data packaging improvements) * [#10923](http://bugs.icu-project.org/trac/ticket/10923) (rewrite data building in python) - -When/if components (not including the `.json` file) are merged into -ICU, this code and `configure` will be updated to detect and use those -variants rather than the ones in this directory. diff --git a/tools/icu/iculslocs.cc b/tools/icu/iculslocs.cc index ca312b783565c4..3ceb8d2a4d81d0 100644 --- a/tools/icu/iculslocs.cc +++ b/tools/icu/iculslocs.cc @@ -64,7 +64,7 @@ int VERBOSE = 0; #define RES_INDEX "res_index" #define INSTALLEDLOCALES "InstalledLocales" -CharString packageName; +icu::CharString packageName; const char* locale = RES_INDEX; // locale referring to our index void usage() { @@ -147,7 +147,7 @@ int localeExists(const char* loc, UBool* exists) { if (VERBOSE > 1) { printf("Trying to open %s:%s\n", packageName.data(), loc); } - LocalUResourceBundlePointer aResource( + icu::LocalUResourceBundlePointer aResource( ures_openDirect(packageName.data(), loc, &status)); *exists = FALSE; if (U_SUCCESS(status)) { @@ -189,11 +189,11 @@ void printIndent(FILE* bf, int indent) { * @return 0 for OK, 1 for err */ int dumpAllButInstalledLocales(int lev, - LocalUResourceBundlePointer* bund, + icu::LocalUResourceBundlePointer* bund, FILE* bf, UErrorCode* status) { ures_resetIterator(bund->getAlias()); - LocalUResourceBundlePointer t; + icu::LocalUResourceBundlePointer t; while (U_SUCCESS(*status) && ures_hasNext(bund->getAlias())) { t.adoptInstead(ures_getNextResource(bund->getAlias(), t.orphan(), status)); ASSERT_SUCCESS(status, "while processing table"); @@ -254,10 +254,10 @@ int list(const char* toBundle) { printf("\"locale\": %s\n", locale); } - LocalUResourceBundlePointer bund( + icu::LocalUResourceBundlePointer bund( ures_openDirect(packageName.data(), locale, &status)); ASSERT_SUCCESS(&status, "while opening the bundle"); - LocalUResourceBundlePointer installedLocales( + icu::LocalUResourceBundlePointer installedLocales( // NOLINTNEXTLINE (readability/null_usage) ures_getByKey(bund.getAlias(), INSTALLEDLOCALES, NULL, &status)); ASSERT_SUCCESS(&status, "while fetching installed locales"); @@ -295,7 +295,7 @@ int list(const char* toBundle) { } // OK, now list them. - LocalUResourceBundlePointer subkey; + icu::LocalUResourceBundlePointer subkey; int validCount = 0; for (int32_t i = 0; i < count; i++) { diff --git a/vcbuild.bat b/vcbuild.bat index 80941b3b91b142..6b631fb922d614 100644 --- a/vcbuild.bat +++ b/vcbuild.bat @@ -106,7 +106,7 @@ if /i "%1"=="build-release" set build_release=1&set sign=1&goto arg-ok if /i "%1"=="upload" set upload=1&goto arg-ok if /i "%1"=="small-icu" set i18n_arg=%1&goto arg-ok if /i "%1"=="full-icu" set i18n_arg=%1&goto arg-ok -if /i "%1"=="intl-none" set i18n_arg=%1&goto arg-ok +if /i "%1"=="intl-none" set i18n_arg=none&goto arg-ok if /i "%1"=="without-intl" set i18n_arg=none&goto arg-ok if /i "%1"=="download-all" set download_arg="--download=all"&goto arg-ok if /i "%1"=="ignore-flaky" set test_args=%test_args% --flaky-tests=dontcare&goto arg-ok @@ -540,7 +540,7 @@ if defined lint_js_ci goto lint-js-ci if not defined lint_js goto exit if not exist tools\node_modules\eslint goto no-lint echo running lint-js -%config%\node tools\node_modules\eslint\bin\eslint.js --cache --rule "linebreak-style: 0" --rulesdir=tools\eslint-rules --ext=.js,.md benchmark doc lib test tools +%config%\node tools\node_modules\eslint\bin\eslint.js --cache --rule "linebreak-style: 0" --rulesdir=tools\eslint-rules --ext=.js,.mjs,.md benchmark doc lib test tools goto exit :lint-js-ci