diff --git a/.eslintignore b/.eslintignore index 80959ce611ee58..bdfdfaeab2388d 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,9 +1,7 @@ node_modules -lib/internal/v8.js lib/internal/v8_prof_polyfill.js lib/punycode.js test/addons/??_* -test/es-module/test-esm-dynamic-import.js test/fixtures test/message/esm_display_syntax_error.mjs tools/icu diff --git a/.eslintrc.js b/.eslintrc.js index e504e085eb387f..ab0baf1c85dfca 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -17,7 +17,10 @@ Module._findPath = (request, paths, isMain) => { if (!r && hacks.includes(request)) { try { return require.resolve(`./tools/node_modules/${request}`); - } catch { + // Keep the variable in place to ensure that ESLint started by older Node.js + // versions work as expected. + // eslint-disable-next-line no-unused-vars + } catch (e) { return require.resolve( `./tools/node_modules/eslint/node_modules/${request}`); } @@ -220,6 +223,7 @@ module.exports = { }], 'no-useless-call': 'error', 'no-useless-concat': 'error', + 'no-useless-constructor': 'error', 'no-useless-escape': 'error', 'no-useless-return': 'error', 'no-void': 'error', diff --git a/CHANGELOG.md b/CHANGELOG.md index 845b38f657e45b..b1a68ab12dfbd7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,7 +26,8 @@ release. -10.15.2
+10.15.3
+10.15.2
10.15.1
10.15.0
10.14.2
diff --git a/COLLABORATOR_GUIDE.md b/COLLABORATOR_GUIDE.md index 0be47023ea7263..2d45f25c6ab219 100644 --- a/COLLABORATOR_GUIDE.md +++ b/COLLABORATOR_GUIDE.md @@ -72,61 +72,48 @@ issues and pull requests can always be re-opened if necessary. A pull request is _author ready_ when: * There is a CI run in progress or completed. -* There are at least two Collaborator approvals, or at least one approval if the - pull request is older than 7 days. +* There is at least one Collaborator approval. * There are no outstanding review comments. -Please always add the `author ready` label to the PR in that case. Please always -remove it again as soon as the conditions are not met anymore. +Please always add the `author ready` label to the pull request in that case. +Please always remove it again as soon as the conditions are not met anymore. ### Handling own pull requests -When you open a pull request, it is recommended to start a CI right away (see -[testing and CI](#testing-and-ci) for instructions) and to post the link to it -in a comment in the pull request. Starting a new CI after each update is also -recommended (for example, after an additional code change or after rebasing). +When you open a pull request, [start a CI](#testing-and-ci) right away and post +the link to it in a comment in the pull request. Later, after new code changes +or rebasing, start a new CI. -As soon as the PR is ready to land, please do so. Landing your own pull requests -allows other Collaborators to focus on other pull requests. If your pull request -is still awaiting the [minimum time to land](#waiting-for-approvals), add the -`author ready` label so other Collaborators know it can land as soon as the time -ends. If instead you wish to land the PR yourself, indicate this intent by using -the "assign yourself" button, to self-assign the PR. +As soon as the pull request is ready to land, please do so. This allows other +Collaborators to focus on other pull requests. If your pull request is not ready +to land but is [author ready](#author-ready-pull-requests), add the +`author ready` label. If you wish to land the pull request yourself, use the +"assign yourself" link to self-assign it. ## Accepting Modifications -All modifications to the Node.js code and documentation should be performed via -GitHub pull requests, including modifications by Collaborators and TSC members. -A pull request must be reviewed, and must also be tested with CI, before being -landed into the codebase. There may be exceptions to the latter (the changed -code cannot be tested with a CI or similar). If that is the case, please leave a -comment that explains why the PR does not require a CI run. +Contributors propose modifications to Node.js using GitHub pull requests. This +includes modifications proposed by TSC members and other Collaborators. A pull +request must pass code review and CI before landing into the codebase. ### Code Reviews At least two Collaborators must approve a pull request before the pull request -lands. (One Collaborator approval is enough if the pull request has been open -for more than 7 days.) Approving a pull request indicates that the Collaborator -accepts responsibility for the change. Approval must be from Collaborators who -are not authors of the change. +lands. One Collaborator approval is enough if the pull request has been open +for more than seven days. + +Approving a pull request indicates that the Collaborator accepts responsibility +for the change. + +Approval must be from Collaborators who are not authors of the change. In some cases, it may be necessary to summon a GitHub team to a pull request for review by @-mention. See [Who to CC in the issue tracker](#who-to-cc-in-the-issue-tracker). -If you are unsure about the modification and are not prepared to take -full responsibility for the change, defer to another Collaborator. - If you are the first Collaborator to approve a pull request that has no CI yet, -please start one (see [testing and CI](#testing-and-ci) for further information -on how to do that) and post the link to the CI in the PR. Please also start a -new CI in case the PR creator pushed new code since the last CI run (due to -e.g., an addressed review comment or a rebase). - -In case there are already enough approvals (`LGTM`), a CI run, and the PR is -open longer than the minimum waiting time without any open comments, please do -not (only) add another approval. Instead go ahead and land the PR after checking -the CI outcome. +please [start one](#testing-and-ci). Post the link to the CI in the PR. Please +also start a new CI if the PR creator pushed new code since the last CI run. ### Consensus Seeking @@ -153,61 +140,60 @@ the TSC meeting agenda. #### Helpful resources -* How to respectfully and usefully review code, part [one](https://mtlynch.io/human-code-reviews-1/) and [two](https://mtlynch.io/human-code-reviews-2/) -* [How to write a positive code review](https://css-tricks.com/code-review-etiquette/) +* [How to Do Code Reviews Like a Human (Part One)](https://mtlynch.io/human-code-reviews-1/) +* [How to Do Code Reviews Like a Human (Part Two)](https://mtlynch.io/human-code-reviews-2/) +* [Code Review Etiquette](https://css-tricks.com/code-review-etiquette/) ### Waiting for Approvals -Before landing pull requests, sufficient time should be left for input -from other Collaborators. In general, leave at least 48 hours to account for -international time differences and work schedules. However, certain types of -pull requests can be fast-tracked and may be landed after a shorter delay. For -example: +Before landing pull requests, allow 48 hours for input from other Collaborators. +Certain types of pull requests can be fast-tracked and may land after a shorter +delay. For example: * Focused changes that affect only documentation and/or the test suite: - * `code-and-learn` tasks typically fall into this category. + * `code-and-learn` tasks often fall into this category. * `good-first-issue` pull requests may also be suitable. * Changes that fix regressions: * Regressions that break the workflow (red CI or broken compilation). * Regressions that happen right before a release, or reported soon after. -When a pull request is deemed suitable to be fast-tracked, label it with -`fast-track` and add a comment that collaborators may upvote. Please mention any -Collaborators that previously approved the pull request. If someone disagrees -with the fast-tracking request, remove the label and leave a comment indicating -why the pull request should not be fast-tracked. The pull request can be landed -once two or more Collaborators approve both the pull request and the -fast-tracking request, and the necessary CI testing is done. A request to -fast-track a PR made by a different Collaborator than the pull-request author -counts as a fast-track approval. +To propose fast-tracking a pull request, apply the `fast-track` label. Then add +a comment that Collaborators may upvote. + +If someone disagrees with the fast-tracking request, remove the label. Do not +fast-track the pull request in that case. + +The pull request may be fast-tracked if two Collaborators approve the +fast-tracking request. To land, the pull request itself still needs two +Collaborator approvals and a passing CI. + +Collaborators may request fast-tracking of pull requests they did not author. +In that case only, the request itself is also one fast-track approval. Upvote +the comment anyway to avoid any doubt. ### Testing and CI -All bugfixes require a test case which demonstrates the defect. The -test should *fail* before the change, and *pass* after the change. +All fixes must have a test case which demonstrates the defect. The test should +fail before the change, and pass after the change. -All pull requests that modify executable code should also include a test case -and must be subjected to continuous integration tests on the -[project CI server](https://ci.nodejs.org/). The pull request should have a CI -status indicator. +All pull requests must pass continuous integration tests on the +[project CI server](https://ci.nodejs.org/). -Do not land any Pull Requests without passing (green or yellow) CI runs. If you -believe any failed (red or grey) CI sub-tasks are unrelated to the change in the -Pull Request, use "Resume Build" in the left navigation of the relevant -`node-test-pull-request` job. It will create a new `node-test-pull-request` run -that preserves all the green results from the current job but re-runs everything -else. +Do not land any pull requests without passing (green or yellow) CI runs. If +there are CI failures unrelated to the change in the pull request, try "Resume +Build". It is in the left navigation of the relevant `node-test-pull-request` +job. It will preserve all the green results from the current job but re-run +everything else. #### Useful CI Jobs * [`node-test-pull-request`](https://ci.nodejs.org/job/node-test-pull-request/) -is the standard CI run we do to check Pull Requests. It triggers -`node-test-commit`, which runs the `build-ci` and `test-ci` targets on all -supported platforms. +is the CI job to test pull requests. It runs the `build-ci` and `test-ci` +targets on all supported platforms. * [`node-test-pull-request-lite-pipeline`](https://ci.nodejs.org/job/node-test-pull-request-lite-pipeline/) -only runs the linter job, as well as the tests on LinuxONE, which is very fast. -This is useful for changes that only affect comments or documentation. +runs the linter job. It also runs the tests on a very fast host. This is useful +for changes that only affect comments or documentation. * [`citgm-smoker`](https://ci.nodejs.org/job/citgm-smoker/) uses [`CitGM`](https://github.com/nodejs/citgm) to allow you to run @@ -216,74 +202,48 @@ useful to check whether a change will cause breakage in the ecosystem. To test Node.js ABI changes you can run [`citgm-abi-smoker`](https://ci.nodejs.org/job/citgm-abi-smoker/). * [`node-stress-single-test`](https://ci.nodejs.org/job/node-stress-single-test/) -is designed to allow one to run a group of tests over and over on a specific -platform to confirm that the test is reliable. +can run a group of tests over and over on a specific platform. Use it to check +that the tests are reliable. * [`node-test-commit-v8-linux`](https://ci.nodejs.org/job/node-test-commit-v8-linux/) -is designed to allow validation of changes to the copy of V8 in the Node.js -tree by running the standard V8 tests. It should be run whenever the -level of V8 within Node.js is updated or new patches are floated on V8. +runs the standard V8 tests. Run it when updating V8 in Node.js or floating new +patches on V8. * [`node-test-commit-custom-suites`](https://ci.nodejs.org/job/node-test-commit-custom-suites/) -can be used to customize what tests are run and with what parameters. For -example, it can be used to execute tests which are not executed in a typical -`node-test-commit` run (such as tests in the `internet` or `pummel` -directories). It can also be used to make sure tests pass when provided with a -flag not typically used in other CI test runs (such as `--worker`). +enables customization of test suites and parameters. It can execute test suites +not used in other CI test runs (such as tests in the `internet` or `pummel` +directories). It can also make sure tests pass when provided with a flag not +used in other CI test runs (such as `--worker`). ### Internal vs. Public API -Due to the nature of the JavaScript language, it can often be difficult to -establish a clear distinction between which parts of the Node.js implementation -represent the public API Node.js users should assume to be stable and which -are part of the internal implementation details of Node.js itself. A rule of -thumb is to base the determination off what functionality is actually -documented in the official Node.js API documentation. However, it has been -repeatedly demonstrated that either the documentation does not completely cover -implemented behavior or that Node.js users have come to rely heavily on -undocumented aspects of the Node.js implementation. - -The following general rules should be followed to determine which aspects of the -Node.js API are internal: - -- All functionality exposed via `process.binding(...)` is internal. -- All functionality implemented in `lib/internal/**/*.js` is internal unless it - is re-exported by code in `lib/*.js` or documented as part of the Node.js - Public API. -- Any object property or method whose key is a non-exported `Symbol` is an - internal property. -- Any object property or method whose key begins with the underscore `_` prefix - is internal unless it is documented as part of the Node.js Public API. -- Any object, property, method, argument, behavior, or event not documented in - the Node.js documentation is internal. -- Any native C/C++ APIs/ABIs exported by the Node.js `*.h` header files that - are hidden behind the `NODE_WANT_INTERNALS` flag are internal. - -Exceptions can be made if use or behavior of a given internal API can be -demonstrated to be sufficiently relied upon by the Node.js ecosystem such that -any changes would cause too much breakage. The threshold for what qualifies as -too much breakage is to be decided on a case-by-case basis by the TSC. - -If it is determined that a currently undocumented object, property, method, -argument, or event *should* be documented, then a pull request adding the -documentation is required in order for it to be considered part of the public -API. - -Making a determination about whether something *should* be documented can be -difficult and will need to be handled on a case-by-case basis. For instance, if -one documented API cannot be used successfully without the use of a second -*currently undocumented* API, then the second API *should* be documented. If -using an API in a manner currently undocumented achieves a particular useful -result, a decision will need to be made whether or not that falls within the -supported scope of that API; and if it does, it should be documented. - -See [Breaking Changes to Internal Elements](#breaking-changes-to-internal-elements) -on how to handle those types of changes. +All functionality in the official Node.js documentation is part of the public +API. Any undocumented object, property, method, argument, behavior, or event is +internal. There are exceptions to this rule. Node.js users have come to rely on +some undocumented behaviors. Collaborators treat many of those undocumented +behaviors as public. + +All undocumented functionality exposed via `process.binding(...)` is internal. + +All undocumented functionality in `lib/internal/**/*.js` is internal. It is +public, though, if it is re-exported by code in `lib/*.js`. + +Non-exported `Symbol` properties and methods are internal. + +Any undocumented object property or method that begins with `_` is internal. + +Any native C/C++ APIs/ABIs requiring the `NODE_WANT_INTERNALS` flag are +internal. + +Sometimes, there is disagreement about whether functionality is internal or +public. In those cases, the TSC makes a determination. + +For undocumented APIs that are public, open a pull request documenting the API. ### Breaking Changes -Backwards-incompatible changes may land on the master branch at any time after -sufficient review by Collaborators and approval of at least two TSC members. +At least two TSC members must approve backward-incompatible changes to the +master branch. Examples of breaking changes include: @@ -294,11 +254,6 @@ Examples of breaking changes include: * altering expected timing of an event * changing the side effects of using a particular API -Purely additive changes (e.g. adding new events to `EventEmitter` -implementations, adding new arguments to a method in a way that allows -existing code to continue working without modification, or adding new -properties to an options argument) are semver-minor changes. - #### Breaking Changes and Deprecations With a few exceptions outlined below, when backward-incompatible changes to a diff --git a/CPP_STYLE_GUIDE.md b/CPP_STYLE_GUIDE.md index 5099f34ea866c9..b82ed7cc190ec8 100644 --- a/CPP_STYLE_GUIDE.md +++ b/CPP_STYLE_GUIDE.md @@ -21,6 +21,7 @@ * [Use explicit pointer comparisons](#use-explicit-pointer-comparisons) * [Ownership and Smart Pointers](#ownership-and-smart-pointers) * [Avoid non-const references](#avoid-non-const-references) + * [Use AliasedBuffers to manipulate TypedArrays](#use-aliasedbuffers-to-manipulate-typedarrays) * [Others](#others) * [Type casting](#type-casting) * [Using `auto`](#using-auto) @@ -257,6 +258,21 @@ class ExampleClass { }; ``` +### Use AliasedBuffers to manipulate TypedArrays + +When working with typed arrays that involve direct data modification +from C++, use an `AliasedBuffer` when possible. The API abstraction and +the usage scope of `AliasedBuffer` are documented in [aliased_buffer.h][]. + +```c++ +// Create an AliasedBuffer. +AliasedBuffer data; +... + +// Modify the data through natural operator semantics. +data[0] = 12345; +``` + ## Others ### Type casting @@ -382,3 +398,4 @@ even `try` and `catch` **will** break. [Run Time Type Information]: https://en.wikipedia.org/wiki/Run-time_type_information [cppref_auto_ptr]: https://en.cppreference.com/w/cpp/memory/auto_ptr [without C++ exception handling]: https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_exceptions.html#intro.using.exception.no +[aliased_buffer.h]: https://github.com/nodejs/node/blob/master/src/aliased_buffer.h#L12 diff --git a/Makefile b/Makefile index 3a343301d640bc..4e7263924cf19a 100644 --- a/Makefile +++ b/Makefile @@ -647,16 +647,16 @@ out/doc/api/assets/%: doc/api_assets/% out/doc/api/assets run-npm-ci = $(PWD)/$(NPM) ci +LINK_DATA = out/doc/apilinks.json gen-api = tools/doc/generate.js --node-version=$(FULLVERSION) \ - --apilinks=out/apilinks.json $< --output-directory=out/doc/api -gen-apilink = tools/doc/apilinks.js $(wildcard lib/*.js) > $@ + --apilinks=$(LINK_DATA) $< --output-directory=out/doc/api +gen-apilink = tools/doc/apilinks.js $(LINK_DATA) $(wildcard lib/*.js) -out/apilinks.json: $(wildcard lib/*.js) tools/doc/apilinks.js +$(LINK_DATA): $(wildcard lib/*.js) tools/doc/apilinks.js $(call available-node, $(gen-apilink)) out/doc/api/%.json out/doc/api/%.html: doc/api/%.md tools/doc/generate.js \ - tools/doc/html.js tools/doc/json.js tools/doc/apilinks.js | \ - out/apilinks.json + tools/doc/html.js tools/doc/json.js tools/doc/apilinks.js | $(LINK_DATA) $(call available-node, $(gen-api)) out/doc/api/all.html: $(apidocs_html) tools/doc/allhtml.js \ @@ -806,13 +806,29 @@ BINARYNAME=$(TARNAME)-$(PLATFORM)-$(ARCH) endif BINARYTAR=$(BINARYNAME).tar # OSX doesn't have xz installed by default, http://macpkg.sourceforge.net/ -XZ=$(shell which xz > /dev/null 2>&1; echo $$?) +HAS_XZ ?= $(shell which xz > /dev/null 2>&1; [ $$? -eq 0 ] && echo 1 || echo 0) +# Supply SKIP_XZ=1 to explicitly skip .tar.xz creation +SKIP_XZ ?= 0 +XZ = $(shell [ $(HAS_XZ) -eq 1 -a $(SKIP_XZ) -eq 0 ] && echo 1 || echo 0) XZ_COMPRESSION ?= 9e PKG=$(TARNAME).pkg MACOSOUTDIR=out/macos +ifeq ($(SKIP_XZ), 1) +check-xz: + @echo "SKIP_XZ=1 supplied, skipping .tar.xz creation" +else +ifeq ($(HAS_XZ), 1) +check-xz: +else +check-xz: + @echo "No xz command, cannot continue" + @exit 1 +endif +endif + .PHONY: release-only -release-only: +release-only: check-xz @if [ "$(DISTTYPE)" = "release" ] && `grep -q REPLACEME doc/api/*.md`; then \ echo 'Please update REPLACEME in Added: tags in doc/api/*.md (See doc/releases.md)' ; \ exit 1 ; \ @@ -938,7 +954,7 @@ $(TARBALL): release-only $(NODE_EXE) doc tar -cf $(TARNAME).tar $(TARNAME) $(RM) -r $(TARNAME) gzip -c -f -9 $(TARNAME).tar > $(TARNAME).tar.gz -ifeq ($(XZ), 0) +ifeq ($(XZ), 1) xz -c -f -$(XZ_COMPRESSION) $(TARNAME).tar > $(TARNAME).tar.xz endif $(RM) $(TARNAME).tar @@ -952,7 +968,7 @@ tar-upload: tar chmod 664 $(TARNAME).tar.gz scp -p $(TARNAME).tar.gz $(STAGINGSERVER):nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(TARNAME).tar.gz ssh $(STAGINGSERVER) "touch nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(TARNAME).tar.gz.done" -ifeq ($(XZ), 0) +ifeq ($(XZ), 1) chmod 664 $(TARNAME).tar.xz scp -p $(TARNAME).tar.xz $(STAGINGSERVER):nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(TARNAME).tar.xz ssh $(STAGINGSERVER) "touch nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(TARNAME).tar.xz.done" @@ -978,7 +994,7 @@ $(TARBALL)-headers: release-only tar -cf $(TARNAME)-headers.tar $(TARNAME) $(RM) -r $(TARNAME) gzip -c -f -9 $(TARNAME)-headers.tar > $(TARNAME)-headers.tar.gz -ifeq ($(XZ), 0) +ifeq ($(XZ), 1) xz -c -f -$(XZ_COMPRESSION) $(TARNAME)-headers.tar > $(TARNAME)-headers.tar.xz endif $(RM) $(TARNAME)-headers.tar @@ -990,7 +1006,7 @@ tar-headers-upload: tar-headers chmod 664 $(TARNAME)-headers.tar.gz scp -p $(TARNAME)-headers.tar.gz $(STAGINGSERVER):nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(TARNAME)-headers.tar.gz ssh $(STAGINGSERVER) "touch nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(TARNAME)-headers.tar.gz.done" -ifeq ($(XZ), 0) +ifeq ($(XZ), 1) chmod 664 $(TARNAME)-headers.tar.xz scp -p $(TARNAME)-headers.tar.xz $(STAGINGSERVER):nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(TARNAME)-headers.tar.xz ssh $(STAGINGSERVER) "touch nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(TARNAME)-headers.tar.xz.done" @@ -1015,7 +1031,7 @@ endif tar -cf $(BINARYNAME).tar $(BINARYNAME) $(RM) -r $(BINARYNAME) gzip -c -f -9 $(BINARYNAME).tar > $(BINARYNAME).tar.gz -ifeq ($(XZ), 0) +ifeq ($(XZ), 1) xz -c -f -$(XZ_COMPRESSION) $(BINARYNAME).tar > $(BINARYNAME).tar.xz endif $(RM) $(BINARYNAME).tar @@ -1030,7 +1046,7 @@ binary-upload: binary chmod 664 $(TARNAME)-$(OSTYPE)-$(ARCH).tar.gz scp -p $(TARNAME)-$(OSTYPE)-$(ARCH).tar.gz $(STAGINGSERVER):nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(TARNAME)-$(OSTYPE)-$(ARCH).tar.gz ssh $(STAGINGSERVER) "touch nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(TARNAME)-$(OSTYPE)-$(ARCH).tar.gz.done" -ifeq ($(XZ), 0) +ifeq ($(XZ), 1) chmod 664 $(TARNAME)-$(OSTYPE)-$(ARCH).tar.xz scp -p $(TARNAME)-$(OSTYPE)-$(ARCH).tar.xz $(STAGINGSERVER):nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(TARNAME)-$(OSTYPE)-$(ARCH).tar.xz ssh $(STAGINGSERVER) "touch nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(TARNAME)-$(OSTYPE)-$(ARCH).tar.xz.done" @@ -1079,7 +1095,7 @@ tools/.docmdlintstamp: $(LINT_MD_DOC_FILES) LINT_MD_TARGETS = src lib benchmark test tools/doc tools/icu LINT_MD_ROOT_DOCS := $(wildcard *.md) LINT_MD_MISC_FILES := $(shell find $(LINT_MD_TARGETS) -type f \ - -not -path '*node_modules*' -not -path 'test/fixtures/*' -name '*.md') \ + ! -path '*node_modules*' ! -path 'test/fixtures/*' -name '*.md') \ $(LINT_MD_ROOT_DOCS) run-lint-misc-md = tools/lint-md.js -q -f $(LINT_MD_MISC_FILES) # Lint other changed markdown files maintained by us @@ -1200,10 +1216,14 @@ tools/.cpplintstamp: $(LINT_CPP_FILES) @$(PYTHON) tools/check-imports.py @touch $@ -lint-addon-docs: test/addons/.docbuildstamp +.PHONY: lint-addon-docs +lint-addon-docs: tools/.doclintstamp + +tools/.doclintstamp: test/addons/.docbuildstamp @echo "Running C++ linter on addon docs..." @$(PYTHON) tools/cpplint.py $(CPPLINT_QUIET) --filter=$(ADDON_DOC_LINT_FLAGS) \ $(LINT_CPP_ADDON_DOC_FILES_GLOB) + @touch $@ cpplint: lint-cpp @echo "Please use lint-cpp instead of cpplint" @@ -1223,7 +1243,7 @@ ifneq ("","$(wildcard tools/pip/site-packages)") lint-py: PYTHONPATH=tools/pip $(PYTHON) -m flake8 . \ --count --show-source --statistics --select=E901,E999,F821,F822,F823 \ - --exclude=deps,lib,src,tools/*_macros.py,tools/gyp,tools/jinja2,tools/pip + --exclude=.git,deps,lib,src,tools/*_macros.py,tools/gyp,tools/inspector_protocol,tools/jinja2,tools/markupsafe,tools/pip else lint-py: @echo "Python linting with flake8 is not avalible" diff --git a/README.md b/README.md index 71da2e4b59ff80..3e2d61ecd882b5 100644 --- a/README.md +++ b/README.md @@ -50,11 +50,10 @@ If you didn't find an answer in the resources above, try these unofficial resources: * [Questions tagged 'node.js' on StackOverflow][] -* [#node.js channel on chat.freenode.net][]. See for more - information. +* [#node.js channel on chat.freenode.net][] * [Node.js Discord Community](https://discordapp.com/invite/v7rrPdE) -* [Node.js Slack Community](https://node-js.slack.com/): Visit - [nodeslackers.com](http://www.nodeslackers.com/) to register. +* [Node.js Slack Community](https://node-js.slack.com/) + * To register: [nodeslackers.com](http://www.nodeslackers.com/) GitHub issues are for tracking enhancements and bugs, not general support. @@ -83,7 +82,7 @@ your expectations. Current and LTS releases follow [Semantic Versioning](https://semver.org). A member of the Release Team [signs](#release-keys) each Current and LTS release. For more information, see the -[Release README](https://github.com/nodejs/Release). +[Release README](https://github.com/nodejs/Release#readme). ### Download @@ -249,6 +248,8 @@ For information about the governance of the Node.js project, see **Andreas Madsen** <amwebdk@gmail.com> (he/him) * [AnnaMag](https://github.com/AnnaMag) - **Anna M. Kedzierska** <anna.m.kedzierska@gmail.com> +* [antsmartian](https://github.com/antsmartian) - +**Anto Aravinth** <anto.aravinth.cse@gmail.com> (he/him) * [apapirovski](https://github.com/apapirovski) - **Anatoli Papirovski** <apapirovski@mac.com> (he/him) * [aqrln](https://github.com/aqrln) - @@ -550,11 +551,14 @@ GPG keys used to sign Node.js releases: `DD8F2338BAE7501E3DD5AC78C273792F7D83545D` * **Ruben Bridgewater** <ruben@bridgewater.de> `A48C2BEE680E841632CD4E44F07496B3EB3C1762` +* **Shelley Vohr** <shelley.vohr@gmail.com> +`B9E2F5981AA6E0CD28160D9FF13993A75599653C` To import the full set of trusted release keys: ```shell gpg --keyserver pool.sks-keyservers.net --recv-keys 4ED778F539E3634C779C87C6D7062848A1AB005C +gpg --keyserver pool.sks-keyservers.net --recv-keys B9E2F5981AA6E0CD28160D9FF13993A75599653C gpg --keyserver pool.sks-keyservers.net --recv-keys 94AE36675C464D64BAFA68DD7434390BDBE9B9C5 gpg --keyserver pool.sks-keyservers.net --recv-keys B9AE9905FFD7803F25714661B63B535A4C206CA9 gpg --keyserver pool.sks-keyservers.net --recv-keys 77984A986EBC2AA786BC0F66B01FBB92821C587A diff --git a/common.gypi b/common.gypi index 0a4ed881a5b925..4c643398ac222b 100644 --- a/common.gypi +++ b/common.gypi @@ -33,7 +33,7 @@ # Reset this number to 0 on major V8 upgrades. # Increment by one for each non-official patch applied to deps/v8. - 'v8_embedder_string': '-node.12', + 'v8_embedder_string': '-node.51', # Enable disassembler for `--print-code` v8 options 'v8_enable_disassembler': 1, @@ -117,6 +117,17 @@ 'cflags': [ '-gxcoff' ], 'ldflags': [ '-Wl,-bbigtoc' ], 'conditions': [ + ['target_arch=="ppc64"', { + 'ldflags': [ + '-Wl,-blibpath:/usr/lib:/lib:' + '/opt/freeware/lib/pthread/ppc64' + ], + }], + ['target_arch=="ppc"', { + 'ldflags': [ + '-Wl,-blibpath:/usr/lib:/lib:/opt/freeware/lib/pthread' + ], + }], ['"<(real_os_name)"=="OS400"', { 'ldflags': [ '-Wl,-blibpath:/QOpenSys/pkgs/lib:/QOpenSys/usr/lib', @@ -421,11 +432,18 @@ 'variables': {'real_os_name': ' debug::WeakMap::Get(v8::Local context, + v8::Local key) { + PREPARE_FOR_EXECUTION(context, WeakMap, Get, Value); + auto self = Utils::OpenHandle(this); + Local result; + i::Handle argv[] = {Utils::OpenHandle(*key)}; + has_pending_exception = + !ToLocal(i::Execution::Call(isolate, isolate->weakmap_get(), self, + arraysize(argv), argv), + &result); + RETURN_ON_FAILED_EXECUTION(Value); + RETURN_ESCAPED(result); +} + +v8::MaybeLocal debug::WeakMap::Set( + v8::Local context, v8::Local key, + v8::Local value) { + PREPARE_FOR_EXECUTION(context, WeakMap, Set, WeakMap); + auto self = Utils::OpenHandle(this); + i::Handle result; + i::Handle argv[] = {Utils::OpenHandle(*key), + Utils::OpenHandle(*value)}; + has_pending_exception = !i::Execution::Call(isolate, isolate->weakmap_set(), + self, arraysize(argv), argv) + .ToHandle(&result); + RETURN_ON_FAILED_EXECUTION(WeakMap); + RETURN_ESCAPED(Local::Cast(Utils::ToLocal(result))); +} + +Local debug::WeakMap::New(v8::Isolate* isolate) { + i::Isolate* i_isolate = reinterpret_cast(isolate); + LOG_API(i_isolate, WeakMap, New); + ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); + i::Handle obj = i_isolate->factory()->NewJSWeakMap(); + return ToApiHandle(obj); +} + +debug::WeakMap* debug::WeakMap::Cast(v8::Value* value) { + return static_cast(value); +} + const char* CpuProfileNode::GetFunctionNameStr() const { const i::ProfileNode* node = reinterpret_cast(this); return node->entry()->name(); diff --git a/deps/v8/src/api.h b/deps/v8/src/api.h index 342ab855ac011c..8df1a1539b8a44 100644 --- a/deps/v8/src/api.h +++ b/deps/v8/src/api.h @@ -124,6 +124,7 @@ class RegisteredExtension { V(Proxy, JSProxy) \ V(debug::GeneratorObject, JSGeneratorObject) \ V(debug::Script, Script) \ + V(debug::WeakMap, JSWeakMap) \ V(Promise, JSPromise) \ V(Primitive, Object) \ V(PrimitiveArray, FixedArray) \ diff --git a/deps/v8/src/bootstrapper.cc b/deps/v8/src/bootstrapper.cc index 548ef5109a9a68..f0cd00a62c2491 100644 --- a/deps/v8/src/bootstrapper.cc +++ b/deps/v8/src/bootstrapper.cc @@ -3250,7 +3250,9 @@ void Genesis::InitializeGlobal(Handle global_object, SimpleInstallFunction(prototype, "delete", Builtins::kWeakMapPrototypeDelete, 1, true); - SimpleInstallFunction(prototype, "get", Builtins::kWeakMapGet, 1, true); + Handle weakmap_get = SimpleInstallFunction(prototype, "get", + Builtins::kWeakMapGet, 1, true); + native_context()->set_weakmap_get(*weakmap_get); SimpleInstallFunction(prototype, "has", Builtins::kWeakMapHas, 1, true); Handle weakmap_set = SimpleInstallFunction( prototype, "set", Builtins::kWeakMapPrototypeSet, 2, true); diff --git a/deps/v8/src/contexts.h b/deps/v8/src/contexts.h index b66bb94a4b41ec..af75fa7243264e 100644 --- a/deps/v8/src/contexts.h +++ b/deps/v8/src/contexts.h @@ -108,6 +108,7 @@ enum ContextLookupFlags { V(WASM_RUNTIME_ERROR_FUNCTION_INDEX, JSFunction, \ wasm_runtime_error_function) \ V(WEAKMAP_SET_INDEX, JSFunction, weakmap_set) \ + V(WEAKMAP_GET_INDEX, JSFunction, weakmap_get) \ V(WEAKSET_ADD_INDEX, JSFunction, weakset_add) #define NATIVE_CONTEXT_FIELDS(V) \ diff --git a/deps/v8/src/counters.h b/deps/v8/src/counters.h index 255c8db7c6bb54..e873252fa1bcaa 100644 --- a/deps/v8/src/counters.h +++ b/deps/v8/src/counters.h @@ -730,6 +730,9 @@ class RuntimeCallTimer final { V(Map_Has) \ V(Map_New) \ V(Map_Set) \ + V(WeakMap_Get) \ + V(WeakMap_Set) \ + V(WeakMap_New) \ V(Message_GetEndColumn) \ V(Message_GetLineNumber) \ V(Message_GetSourceLine) \ diff --git a/deps/v8/src/debug/debug-interface.h b/deps/v8/src/debug/debug-interface.h index 2210b4e87f1bc6..169b73a9ea8116 100644 --- a/deps/v8/src/debug/debug-interface.h +++ b/deps/v8/src/debug/debug-interface.h @@ -515,6 +515,20 @@ bool SetFunctionBreakpoint(v8::Local function, v8::Platform* GetCurrentPlatform(); +class WeakMap : public v8::Object { + public: + V8_WARN_UNUSED_RESULT v8::MaybeLocal Get( + v8::Local context, v8::Local key); + V8_WARN_UNUSED_RESULT v8::MaybeLocal Set( + v8::Local context, v8::Local key, + v8::Local value); + + static Local New(v8::Isolate* isolate); + V8_INLINE static WeakMap* Cast(Value* obj); + + private: + WeakMap(); +}; } // namespace debug } // namespace v8 diff --git a/deps/v8/src/heap/store-buffer.cc b/deps/v8/src/heap/store-buffer.cc index d73e3235c158df..657aa9212a6153 100644 --- a/deps/v8/src/heap/store-buffer.cc +++ b/deps/v8/src/heap/store-buffer.cc @@ -30,22 +30,28 @@ StoreBuffer::StoreBuffer(Heap* heap) } void StoreBuffer::SetUp() { - // Allocate 3x the buffer size, so that we can start the new store buffer - // aligned to 2x the size. This lets us use a bit test to detect the end of - // the area. + const size_t requested_size = kStoreBufferSize * kStoreBuffers; + // Allocate buffer memory aligned at least to kStoreBufferSize. This lets us + // use a bit test to detect the ends of the buffers. + const size_t alignment = + std::max(kStoreBufferSize, AllocatePageSize()); + void* hint = AlignedAddress(heap_->GetRandomMmapAddr(), alignment); VirtualMemory reservation; - if (!AllocVirtualMemory(kStoreBufferSize * 3, heap_->GetRandomMmapAddr(), - &reservation)) { + if (!AlignedAllocVirtualMemory(requested_size, alignment, hint, + &reservation)) { heap_->FatalProcessOutOfMemory("StoreBuffer::SetUp"); } + Address start = reservation.address(); - start_[0] = reinterpret_cast(::RoundUp(start, kStoreBufferSize)); + const size_t allocated_size = reservation.size(); + + start_[0] = reinterpret_cast(start); limit_[0] = start_[0] + (kStoreBufferSize / kPointerSize); start_[1] = limit_[0]; limit_[1] = start_[1] + (kStoreBufferSize / kPointerSize); - Address* vm_limit = reinterpret_cast(start + reservation.size()); - + // Sanity check the buffers. + Address* vm_limit = reinterpret_cast(start + allocated_size); USE(vm_limit); for (int i = 0; i < kStoreBuffers; i++) { DCHECK(reinterpret_cast
(start_[i]) >= reservation.address()); @@ -55,8 +61,9 @@ void StoreBuffer::SetUp() { DCHECK_EQ(0, reinterpret_cast
(limit_[i]) & kStoreBufferMask); } - if (!reservation.SetPermissions(reinterpret_cast
(start_[0]), - kStoreBufferSize * kStoreBuffers, + // Set RW permissions only on the pages we use. + const size_t used_size = RoundUp(requested_size, CommitPageSize()); + if (!reservation.SetPermissions(start, used_size, PageAllocator::kReadWrite)) { heap_->FatalProcessOutOfMemory("StoreBuffer::SetUp"); } @@ -65,7 +72,6 @@ void StoreBuffer::SetUp() { virtual_memory_.TakeControl(&reservation); } - void StoreBuffer::TearDown() { if (virtual_memory_.IsReserved()) virtual_memory_.Free(); top_ = nullptr; diff --git a/deps/v8/src/inspector/v8-debugger.cc b/deps/v8/src/inspector/v8-debugger.cc index 6e4e6a1752e3ab..4fec951390c2f0 100644 --- a/deps/v8/src/inspector/v8-debugger.cc +++ b/deps/v8/src/inspector/v8-debugger.cc @@ -703,11 +703,37 @@ v8::MaybeLocal V8Debugger::generatorScopes( return getTargetScopes(context, generator, GENERATOR); } +v8::MaybeLocal V8Debugger::stableObjectId( + v8::Local context, v8::Local value) { + DCHECK(value->IsObject()); + if (m_stableObjectId.IsEmpty()) { + m_stableObjectId.Reset(m_isolate, v8::debug::WeakMap::New(m_isolate)); + } + v8::Local stableObjectId = + m_stableObjectId.Get(m_isolate); + v8::Local idValue; + if (!stableObjectId->Get(context, value).ToLocal(&idValue) || + !idValue->IsUint32()) { + idValue = v8::Integer::NewFromUnsigned(m_isolate, ++m_lastStableObjectId); + stableObjectId->Set(context, value, idValue).ToLocalChecked(); + } + return idValue.As(); +} + v8::MaybeLocal V8Debugger::internalProperties( v8::Local context, v8::Local value) { v8::Local properties; if (!v8::debug::GetInternalProperties(m_isolate, value).ToLocal(&properties)) return v8::MaybeLocal(); + if (value->IsObject()) { + v8::Local id; + if (stableObjectId(context, value).ToLocal(&id)) { + createDataProperty( + context, properties, properties->Length(), + toV8StringInternalized(m_isolate, "[[StableObjectId]]")); + createDataProperty(context, properties, properties->Length(), id); + } + } if (value->IsFunction()) { v8::Local function = value.As(); v8::Local location; diff --git a/deps/v8/src/inspector/v8-debugger.h b/deps/v8/src/inspector/v8-debugger.h index 351e5b66adbf8b..dd8c7f66192183 100644 --- a/deps/v8/src/inspector/v8-debugger.h +++ b/deps/v8/src/inspector/v8-debugger.h @@ -185,6 +185,9 @@ class V8Debugger : public v8::debug::DebugDelegate { int currentContextGroupId(); + v8::MaybeLocal stableObjectId(v8::Local, + v8::Local); + v8::Isolate* m_isolate; V8InspectorImpl* m_inspector; int m_enableCount; @@ -241,6 +244,9 @@ class V8Debugger : public v8::debug::DebugDelegate { std::unique_ptr m_terminateExecutionCallback; + uint32_t m_lastStableObjectId = 0; + v8::Global m_stableObjectId; + WasmTranslation m_wasmTranslation; DISALLOW_COPY_AND_ASSIGN(V8Debugger); diff --git a/deps/v8/src/regexp/ppc/regexp-macro-assembler-ppc.cc b/deps/v8/src/regexp/ppc/regexp-macro-assembler-ppc.cc index fdda46424eac98..aca0b269950963 100644 --- a/deps/v8/src/regexp/ppc/regexp-macro-assembler-ppc.cc +++ b/deps/v8/src/regexp/ppc/regexp-macro-assembler-ppc.cc @@ -142,8 +142,13 @@ int RegExpMacroAssemblerPPC::stack_limit_slack() { void RegExpMacroAssemblerPPC::AdvanceCurrentPosition(int by) { if (by != 0) { - __ addi(current_input_offset(), current_input_offset(), - Operand(by * char_size())); + if (is_int16(by * char_size())) { + __ addi(current_input_offset(), current_input_offset(), + Operand(by * char_size())); + } else { + __ mov(r0, Operand(by * char_size())); + __ add(current_input_offset(), r0, current_input_offset()); + } } } @@ -1272,7 +1277,12 @@ void RegExpMacroAssemblerPPC::LoadCurrentCharacterUnchecked(int cp_offset, Register offset = current_input_offset(); if (cp_offset != 0) { // r25 is not being used to store the capture start index at this point. - __ addi(r25, current_input_offset(), Operand(cp_offset * char_size())); + if (is_int16(cp_offset * char_size())) { + __ addi(r25, current_input_offset(), Operand(cp_offset * char_size())); + } else { + __ mov(r25, Operand(cp_offset * char_size())); + __ add(r25, r25, current_input_offset()); + } offset = r25; } // The lwz, stw, lhz, sth instructions can do unaligned accesses, if the CPU diff --git a/deps/v8/src/wasm/module-compiler.cc b/deps/v8/src/wasm/module-compiler.cc index 180c025a4965da..2b0eac818aa2fe 100644 --- a/deps/v8/src/wasm/module-compiler.cc +++ b/deps/v8/src/wasm/module-compiler.cc @@ -2653,20 +2653,20 @@ void InstanceBuilder::LoadTableSegments(Handle instance) { // Update the local dispatch table first. uint32_t sig_id = module_->signature_ids[function->sig_index]; - WasmInstanceObject* target_instance = *instance; + Handle target_instance = instance; Address call_target; const bool is_import = func_index < module_->num_imported_functions; if (is_import) { // For imported calls, take target instance and address from the // import table. ImportedFunctionEntry entry(instance, func_index); - target_instance = entry.instance(); + target_instance = handle(entry.instance(), isolate_); call_target = entry.target(); } else { call_target = native_module->GetCallTargetForFunction(func_index); } IndirectFunctionTableEntry(instance, table_index) - .set(sig_id, target_instance, call_target); + .set(sig_id, *target_instance, call_target); if (!table_instance.table_object.is_null()) { // Update the table object's other dispatch tables. @@ -2700,17 +2700,16 @@ void InstanceBuilder::LoadTableSegments(Handle instance) { } table_instance.js_wrappers->set(table_index, *js_wrappers_[func_index]); - // UpdateDispatchTables() should update this instance as well. + // UpdateDispatchTables() updates all other dispatch tables, since + // we have not yet added the dispatch table we are currently building. WasmTableObject::UpdateDispatchTables( isolate_, table_instance.table_object, table_index, function->sig, - instance, call_target); + target_instance, call_target); } } } - // TODO(titzer): we add the new dispatch table at the end to avoid - // redundant work and also because the new instance is not yet fully - // initialized. + // Add the new dispatch table at the end to avoid redundant lookups. if (!table_instance.table_object.is_null()) { // Add the new dispatch table to the WebAssembly.Table object. WasmTableObject::AddDispatchTable(isolate_, table_instance.table_object, diff --git a/deps/v8/test/inspector/debugger/eval-scopes-expected.txt b/deps/v8/test/inspector/debugger/eval-scopes-expected.txt index 71d6618c8e8387..4c93498c68f134 100644 --- a/deps/v8/test/inspector/debugger/eval-scopes-expected.txt +++ b/deps/v8/test/inspector/debugger/eval-scopes-expected.txt @@ -2,6 +2,12 @@ Tests that variables introduced in eval scopes are accessible { id : result : { + internalProperties : [ + [0] : { + name : [[StableObjectId]] + value : + } + ] result : [ [0] : { configurable : true diff --git a/deps/v8/test/inspector/debugger/scope-skip-variables-with-empty-name-expected.txt b/deps/v8/test/inspector/debugger/scope-skip-variables-with-empty-name-expected.txt index 626f9787c37993..6fbe355eff54c1 100644 --- a/deps/v8/test/inspector/debugger/scope-skip-variables-with-empty-name-expected.txt +++ b/deps/v8/test/inspector/debugger/scope-skip-variables-with-empty-name-expected.txt @@ -2,6 +2,12 @@ Tests that scopes do not report variables with empty names { id : result : { + internalProperties : [ + [0] : { + name : [[StableObjectId]] + value : + } + ] result : [ [0] : { configurable : true diff --git a/deps/v8/test/inspector/protocol-test.js b/deps/v8/test/inspector/protocol-test.js index 9b7ba0aafe6f37..7163dd68785a00 100644 --- a/deps/v8/test/inspector/protocol-test.js +++ b/deps/v8/test/inspector/protocol-test.js @@ -45,6 +45,8 @@ InspectorTest.logMessage = function(originalMessage) { var objects = [ message ]; while (objects.length) { var object = objects.shift(); + if (object && object.name === '[[StableObjectId]]') + object.value = ''; for (var key in object) { if (nonStableFields.has(key)) object[key] = `<${key}>`; diff --git a/deps/v8/test/inspector/runtime/es6-module-expected.txt b/deps/v8/test/inspector/runtime/es6-module-expected.txt index 25ba52e0341c2e..051ef6ceae183c 100644 --- a/deps/v8/test/inspector/runtime/es6-module-expected.txt +++ b/deps/v8/test/inspector/runtime/es6-module-expected.txt @@ -128,6 +128,12 @@ console.log(239) { id : result : { + internalProperties : [ + [0] : { + name : [[StableObjectId]] + value : + } + ] result : [ [0] : { configurable : true diff --git a/deps/v8/test/inspector/runtime/get-properties-expected.txt b/deps/v8/test/inspector/runtime/get-properties-expected.txt index 8b48e65c3b7060..5707ffc5afd2de 100644 --- a/deps/v8/test/inspector/runtime/get-properties-expected.txt +++ b/deps/v8/test/inspector/runtime/get-properties-expected.txt @@ -5,6 +5,7 @@ Running test: testObject5 foo own string cat Internal properties [[PrimitiveValue]] number 5 + [[StableObjectId]]: Running test: testNotOwn __defineGetter__ inherited function undefined @@ -23,6 +24,8 @@ Running test: testNotOwn toLocaleString inherited function undefined toString inherited function undefined valueOf inherited function undefined +Internal properties + [[StableObjectId]]: Running test: testAccessorsOnly b own no value, getter, setter @@ -34,6 +37,8 @@ Running test: testArray 2 own string blue __proto__ own object undefined length own number 3 +Internal properties + [[StableObjectId]]: Running test: testBound __proto__ own function undefined @@ -42,14 +47,19 @@ Running test: testBound Internal properties [[BoundArgs]] object undefined [[BoundThis]] object undefined + [[StableObjectId]]: [[TargetFunction]] function undefined Running test: testObjectThrowsLength __proto__ own object undefined length own no value, getter +Internal properties + [[StableObjectId]]: Running test: testTypedArrayWithoutLength __proto__ own object undefined +Internal properties + [[StableObjectId]]: Running test: testArrayBuffer [[Int8Array]] @@ -62,6 +72,8 @@ Running test: testArrayBuffer 6 own number 1 7 own number 1 __proto__ own object undefined +Internal properties + [[StableObjectId]]: [[Uint8Array]] 0 own number 1 1 own number 1 @@ -72,18 +84,26 @@ Running test: testArrayBuffer 6 own number 1 7 own number 1 __proto__ own object undefined +Internal properties + [[StableObjectId]]: [[Int16Array]] 0 own number 257 1 own number 257 2 own number 257 3 own number 257 __proto__ own object undefined +Internal properties + [[StableObjectId]]: [[Int32Array]] 0 own number 16843009 1 own number 16843009 __proto__ own object undefined +Internal properties + [[StableObjectId]]: Running test: testArrayBufferWithBrokenUintCtor [[Int8Array]] own object undefined [[Uint8Array]] own object undefined __proto__ own object undefined +Internal properties + [[StableObjectId]]: diff --git a/deps/v8/test/inspector/runtime/get-properties-on-proxy-expected.txt b/deps/v8/test/inspector/runtime/get-properties-on-proxy-expected.txt index a0437f4af6d644..efde782ae32b78 100644 --- a/deps/v8/test/inspector/runtime/get-properties-on-proxy-expected.txt +++ b/deps/v8/test/inspector/runtime/get-properties-on-proxy-expected.txt @@ -54,6 +54,10 @@ Testing regular Proxy value : false } } + [3] : { + name : [[StableObjectId]] + value : + } ] result : [ ] @@ -114,6 +118,10 @@ Testing revocable Proxy value : false } } + [3] : { + name : [[StableObjectId]] + value : + } ] result : [ ] @@ -166,6 +174,10 @@ Testing revocable Proxy value : true } } + [3] : { + name : [[StableObjectId]] + value : + } ] result : [ ] diff --git a/deps/v8/test/inspector/runtime/get-properties.js b/deps/v8/test/inspector/runtime/get-properties.js index d2b2c754a311e2..0386fdea6d87c5 100644 --- a/deps/v8/test/inspector/runtime/get-properties.js +++ b/deps/v8/test/inspector/runtime/get-properties.js @@ -94,7 +94,10 @@ async function logGetPropertiesResult(objectId, flags = { ownProperties: true }) for (var i = 0; i < internalPropertyArray.length; i++) { var p = internalPropertyArray[i]; var v = p.value; - InspectorTest.log(" " + p.name + " " + v.type + " " + v.value); + if (p.name !== '[[StableObjectId]]') + InspectorTest.log(" " + p.name + " " + v.type + " " + v.value); + else + InspectorTest.log(" [[StableObjectId]]: "); } } diff --git a/deps/v8/test/inspector/runtime/internal-properties-entries-expected.txt b/deps/v8/test/inspector/runtime/internal-properties-entries-expected.txt index d395067efe72b1..1d09e8dc1ebe77 100644 --- a/deps/v8/test/inspector/runtime/internal-properties-entries-expected.txt +++ b/deps/v8/test/inspector/runtime/internal-properties-entries-expected.txt @@ -15,6 +15,12 @@ expression: new Map([[1,2],[3,4]]) { id : result : { + internalProperties : [ + [0] : { + name : [[StableObjectId]] + value : + } + ] result : [ [0] : { configurable : true @@ -65,6 +71,12 @@ expression: new Map() { id : result : { + internalProperties : [ + [0] : { + name : [[StableObjectId]] + value : + } + ] result : [ [0] : { configurable : false @@ -97,6 +109,12 @@ expression: new Map([[1,2],[3,4]]).entries() { id : result : { + internalProperties : [ + [0] : { + name : [[StableObjectId]] + value : + } + ] result : [ [0] : { configurable : true @@ -151,6 +169,12 @@ expression: it = new Map([[1,2],[3,4]]).entries(); it.next(); it { id : result : { + internalProperties : [ + [0] : { + name : [[StableObjectId]] + value : + } + ] result : [ [0] : { configurable : true @@ -190,6 +214,12 @@ expression: it = new Map([[1,2],[3,4]]).keys(); it.next(); it { id : result : { + internalProperties : [ + [0] : { + name : [[StableObjectId]] + value : + } + ] result : [ [0] : { configurable : true @@ -229,6 +259,12 @@ expression: it = new Map([[1,2],[3,4]]).values(); it.next(); it { id : result : { + internalProperties : [ + [0] : { + name : [[StableObjectId]] + value : + } + ] result : [ [0] : { configurable : true @@ -265,6 +301,12 @@ expression: it = new Map([[1,2],[3,4]]).entries(); it.next(); it.next(); it { id : result : { + internalProperties : [ + [0] : { + name : [[StableObjectId]] + value : + } + ] result : [ [0] : { configurable : false @@ -295,6 +337,12 @@ expression: new Set([1,2]) { id : result : { + internalProperties : [ + [0] : { + name : [[StableObjectId]] + value : + } + ] result : [ [0] : { configurable : true @@ -345,6 +393,12 @@ expression: new Set() { id : result : { + internalProperties : [ + [0] : { + name : [[StableObjectId]] + value : + } + ] result : [ [0] : { configurable : false @@ -375,6 +429,12 @@ expression: new Set([1,2]).values() { id : result : { + internalProperties : [ + [0] : { + name : [[StableObjectId]] + value : + } + ] result : [ [0] : { configurable : true @@ -428,6 +488,12 @@ expression: it = new Set([1,2]).values(); it.next(); it { id : result : { + internalProperties : [ + [0] : { + name : [[StableObjectId]] + value : + } + ] result : [ [0] : { configurable : true @@ -467,6 +533,12 @@ expression: it = new Set([1,2]).keys(); it.next(); it { id : result : { + internalProperties : [ + [0] : { + name : [[StableObjectId]] + value : + } + ] result : [ [0] : { configurable : true @@ -506,6 +578,12 @@ expression: it = new Set([1,2]).entries(); it.next(); it { id : result : { + internalProperties : [ + [0] : { + name : [[StableObjectId]] + value : + } + ] result : [ [0] : { configurable : true @@ -542,6 +620,12 @@ expression: it = new Set([1,2]).values(); it.next(); it.next(); it { id : result : { + internalProperties : [ + [0] : { + name : [[StableObjectId]] + value : + } + ] result : [ [0] : { configurable : false @@ -566,6 +650,12 @@ expression: new WeakMap() { id : result : { + internalProperties : [ + [0] : { + name : [[StableObjectId]] + value : + } + ] result : [ [0] : { configurable : false @@ -594,6 +684,12 @@ expression: new WeakMap([[{ a: 2 }, 42]]) { id : result : { + internalProperties : [ + [0] : { + name : [[StableObjectId]] + value : + } + ] result : [ [0] : { configurable : true @@ -632,6 +728,12 @@ expression: new WeakSet() { id : result : { + internalProperties : [ + [0] : { + name : [[StableObjectId]] + value : + } + ] result : [ [0] : { configurable : false @@ -659,6 +761,12 @@ expression: new WeakSet([{a:2}]) { id : result : { + internalProperties : [ + [0] : { + name : [[StableObjectId]] + value : + } + ] result : [ [0] : { configurable : true diff --git a/deps/v8/test/inspector/runtime/internal-properties-expected.txt b/deps/v8/test/inspector/runtime/internal-properties-expected.txt index a2e38ab013f472..c114696eb81352 100644 --- a/deps/v8/test/inspector/runtime/internal-properties-expected.txt +++ b/deps/v8/test/inspector/runtime/internal-properties-expected.txt @@ -7,6 +7,10 @@ expression: (function* foo() { yield 1 }) result : { internalProperties : [ [0] : { + name : [[StableObjectId]] + value : + } + [1] : { name : [[FunctionLocation]] value : { description : Object @@ -19,14 +23,14 @@ expression: (function* foo() { yield 1 }) } } } - [1] : { + [2] : { name : [[IsGenerator]] value : { type : boolean value : true } } - [2] : { + [3] : { name : [[Scopes]] value : { className : Array @@ -47,6 +51,10 @@ expression: (function foo() {}) result : { internalProperties : [ [0] : { + name : [[StableObjectId]] + value : + } + [1] : { name : [[FunctionLocation]] value : { description : Object @@ -59,7 +67,7 @@ expression: (function foo() {}) } } } - [1] : { + [2] : { name : [[Scopes]] value : { className : Array @@ -87,6 +95,10 @@ expression: new Number(239) value : 239 } } + [1] : { + name : [[StableObjectId]] + value : + } ] } } @@ -102,6 +114,10 @@ expression: new Boolean(false) value : false } } + [1] : { + name : [[StableObjectId]] + value : + } ] } } @@ -117,6 +133,10 @@ expression: new String('abc') value : abc } } + [1] : { + name : [[StableObjectId]] + value : + } ] } } @@ -133,6 +153,10 @@ expression: Object(Symbol(42)) type : symbol } } + [1] : { + name : [[StableObjectId]] + value : + } ] } } @@ -149,6 +173,10 @@ expression: Object(BigInt(2)) unserializableValue : 2n } } + [1] : { + name : [[StableObjectId]] + value : + } ] } } @@ -174,6 +202,10 @@ expression: Promise.resolve(42) value : 42 } } + [2] : { + name : [[StableObjectId]] + value : + } ] } } @@ -195,6 +227,10 @@ expression: new Promise(() => undefined) type : undefined } } + [2] : { + name : [[StableObjectId]] + value : + } ] } } @@ -231,6 +267,10 @@ expression: gen1 } } [3] : { + name : [[StableObjectId]] + value : + } + [4] : { name : [[GeneratorLocation]] value : { description : Object @@ -243,7 +283,7 @@ expression: gen1 } } } - [4] : { + [5] : { name : [[Scopes]] value : { className : Array @@ -287,6 +327,10 @@ expression: gen1.next();gen1 } } [3] : { + name : [[StableObjectId]] + value : + } + [4] : { name : [[GeneratorLocation]] value : { description : Object @@ -299,7 +343,7 @@ expression: gen1.next();gen1 } } } - [4] : { + [5] : { name : [[Scopes]] value : { className : Array @@ -343,6 +387,10 @@ expression: gen1.next();gen1 } } [3] : { + name : [[StableObjectId]] + value : + } + [4] : { name : [[GeneratorLocation]] value : { description : Object @@ -391,6 +439,10 @@ expression: gen2 } } [3] : { + name : [[StableObjectId]] + value : + } + [4] : { name : [[GeneratorLocation]] value : { description : Object @@ -403,7 +455,7 @@ expression: gen2 } } } - [4] : { + [5] : { name : [[Scopes]] value : { className : Array @@ -447,6 +499,10 @@ expression: gen2.next();gen2 } } [3] : { + name : [[StableObjectId]] + value : + } + [4] : { name : [[GeneratorLocation]] value : { description : Object @@ -459,7 +515,7 @@ expression: gen2.next();gen2 } } } - [4] : { + [5] : { name : [[Scopes]] value : { className : Array @@ -503,6 +559,10 @@ expression: gen2.next();gen2 } } [3] : { + name : [[StableObjectId]] + value : + } + [4] : { name : [[GeneratorLocation]] value : { description : Object @@ -548,6 +608,10 @@ expression: (new Map([[1,2]])).entries() } } [3] : { + name : [[StableObjectId]] + value : + } + [4] : { name : [[Entries]] value : { className : Array @@ -588,6 +652,10 @@ expression: (new Set([[1,2]])).entries() } } [3] : { + name : [[StableObjectId]] + value : + } + [4] : { name : [[Entries]] value : { className : Array diff --git a/deps/v8/test/inspector/runtime/stable-object-id-expected.txt b/deps/v8/test/inspector/runtime/stable-object-id-expected.txt new file mode 100644 index 00000000000000..937727e1089f59 --- /dev/null +++ b/deps/v8/test/inspector/runtime/stable-object-id-expected.txt @@ -0,0 +1,14 @@ +Checks that protocol returns the same RemoteObjectId for the same object + +Running test: testGlobal +Compare global evaluated twice: true + +Running test: testObject +Compare object evaluated twice: true + +Running test: testObjectInArray +Compare first and second element: true + +Running test: testObjectOnPause +Compare global and this: true +Compare a and a on pause: true diff --git a/deps/v8/test/inspector/runtime/stable-object-id.js b/deps/v8/test/inspector/runtime/stable-object-id.js new file mode 100644 index 00000000000000..9a65e67d7f6855 --- /dev/null +++ b/deps/v8/test/inspector/runtime/stable-object-id.js @@ -0,0 +1,77 @@ +// Copyright 2018 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +let {session, contextGroup, Protocol} = InspectorTest.start( + 'Checks that protocol returns the same RemoteObjectId for the same object'); + +InspectorTest.runAsyncTestSuite([ + async function testGlobal() { + const {result:{result:{objectId:firstId}}} = + await Protocol.Runtime.evaluate({expression: 'this'}); + const firstStableId = await stableObjectId(firstId); + const {result:{result:{objectId:secondId}}} = + await Protocol.Runtime.evaluate({expression: 'this'}); + const secondStableId = await stableObjectId(secondId); + InspectorTest.log( + `Compare global evaluated twice: ${firstStableId === secondStableId}`); + }, + + async function testObject() { + const {result:{result:{objectId:firstId}}} = + await Protocol.Runtime.evaluate({expression: 'this.a = {}, this.a'}); + const firstStableId = await stableObjectId(firstId); + const {result:{result:{objectId:secondId}}} = + await Protocol.Runtime.evaluate({expression: 'this.a'}); + const secondStableId = await stableObjectId(secondId); + InspectorTest.log( + `Compare object evaluated twice: ${firstStableId === secondStableId}`); + }, + + async function testObjectInArray() { + await Protocol.Runtime.evaluate({expression: 'this.b = [this.a, this.a]'}); + const {result:{result:{objectId:firstId}}} = + await Protocol.Runtime.evaluate({expression: 'this.b[0]'}); + const firstStableId = await stableObjectId(firstId); + const {result:{result:{objectId:secondId}}} = + await Protocol.Runtime.evaluate({expression: 'this.b[1]'}); + const secondStableId = await stableObjectId(secondId); + InspectorTest.log( + `Compare first and second element: ${firstStableId === secondStableId}`); + }, + + async function testObjectOnPause() { + const {result:{result:{objectId:globalId}}} = + await Protocol.Runtime.evaluate({expression: 'this'}); + const globalStableId = await stableObjectId(globalId); + const {result:{result:{objectId:aId}}} = + await Protocol.Runtime.evaluate({expression: 'this.a'}); + const aStableId = await stableObjectId(aId); + await Protocol.Debugger.enable(); + Protocol.Runtime.evaluate({expression: 'debugger'}); + const {params:{callFrames:[topFrame]}} = + await Protocol.Debugger.oncePaused(); + const topFrameThisStableId = await stableObjectId(topFrame.this.objectId); + InspectorTest.log( + `Compare global and this: ${globalStableId === topFrameThisStableId}`); + + const {result:{result: props}} = await Protocol.Runtime.getProperties({ + objectId: topFrame.scopeChain[0].object.objectId + }); + const {value:{objectId: aIdOnPause}} = props.find(prop => prop.name === 'a'); + const aStableIdOnPause = await stableObjectId(aIdOnPause); + InspectorTest.log(`Compare a and a on pause: ${ + aStableId === aStableIdOnPause}`); + } +]); + +async function stableObjectId(objectId) { + const {result:{ + internalProperties: props + }} = await Protocol.Runtime.getProperties({ + objectId, + ownProperties: true, + generatePreview: false + }); + return props.find(prop => prop.name === '[[StableObjectId]]').value.value; +} diff --git a/deps/v8/test/inspector/sessions/runtime-remote-object-expected.txt b/deps/v8/test/inspector/sessions/runtime-remote-object-expected.txt index a8d0ec0c207895..7c6e69e05d69be 100644 --- a/deps/v8/test/inspector/sessions/runtime-remote-object-expected.txt +++ b/deps/v8/test/inspector/sessions/runtime-remote-object-expected.txt @@ -5,6 +5,12 @@ Retrieving properties in 2 { id : result : { + internalProperties : [ + [0] : { + name : [[StableObjectId]] + value : + } + ] result : [ [0] : { configurable : true @@ -38,6 +44,12 @@ Retrieving properties in 1 { id : result : { + internalProperties : [ + [0] : { + name : [[StableObjectId]] + value : + } + ] result : [ [0] : { configurable : true @@ -72,6 +84,12 @@ Retrieving properties in 1 { id : result : { + internalProperties : [ + [0] : { + name : [[StableObjectId]] + value : + } + ] result : [ [0] : { configurable : true diff --git a/deps/v8/test/mjsunit/wasm/import-table.js b/deps/v8/test/mjsunit/wasm/import-table.js new file mode 100644 index 00000000000000..bb8bf7807b5cf5 --- /dev/null +++ b/deps/v8/test/mjsunit/wasm/import-table.js @@ -0,0 +1,244 @@ +// Copyright 2018 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --expose-wasm + +load("test/mjsunit/wasm/wasm-constants.js"); +load("test/mjsunit/wasm/wasm-module-builder.js"); + +function addConstFunc(builder, val) { + return builder.addFunction("const" + val, kSig_i_v) + .addBody(wasmI32Const(val)).index; +} + +function addSigs(builder, pad) { + for (let i = 0; i < pad; i++) { + let params = []; + for (let j = 0; j < i; j++) params.push(kWasmF32); + builder.addType(makeSig(params, [])); + } + + return { i_v: builder.addType(kSig_i_v) }; +} + +let kTableSize = 50; + +(function TestAliasedImportedTable() { + print(arguments.callee.name); + + { + let builder = new WasmModuleBuilder(); + let signums = addSigs(builder, 1); + + builder.addImportedTable("m", "table", kTableSize, kTableSize); + let f15 = addConstFunc(builder, 15); + let call = builder.addFunction("call", kSig_i_i) + .addBody([ + kExprGetLocal, 0, + kExprCallIndirect, signums.i_v, kTableZero + ]) + .exportAs("call"); + let f17 = addConstFunc(builder, 17); + builder.addExport("f15", f15); + builder.addExport("f17", f17); + builder.addFunctionTableInit(15, false, [f15], true); + builder.addFunctionTableInit(1, false, [call.index], true); + + var mod1 = builder.toModule(); + } + + { + let builder = new WasmModuleBuilder(); + let signums = addSigs(builder, 5); // ensure different sigids + + builder.addImportedTable("m", "table", kTableSize, kTableSize); + let f15 = builder.addImport("m", "f15", kSig_i_v); + let f17 = builder.addImport("m", "f17", kSig_i_v); + let f21 = addConstFunc(builder, 21); + let call = builder.addFunction("call", kSig_i_i) + .addBody([ + kExprGetLocal, 0, + kExprCallIndirect, signums.i_v, kTableZero + ]) + .exportAs("call"); + let f26 = addConstFunc(builder, 26); + builder.addFunctionTableInit(17, false, [f17], true); + builder.addFunctionTableInit(21, false, [f21], true); + builder.addFunctionTableInit(26, false, [f26], true); + builder.addFunctionTableInit(5, false, [call.index], true); + + var mod2 = builder.toModule(); + } + + var table = new WebAssembly.Table({initial: kTableSize, + maximum: kTableSize, element: "anyfunc"}); + var i1 = new WebAssembly.Instance(mod1, {m: {table: table}}); + + var i2 = new WebAssembly.Instance(mod2, + {m: {table: table, f15: i1.exports.f15, f17: i1.exports.f17}}); + + for (i of [15, 17, 21, 26]) { + print(i); + assertEquals(i, i1.exports.call(i)); + assertEquals(i, i2.exports.call(i)); + } + for (i of [0, 1, 5, 16]) { + assertThrows(() => i1.exports.call(i)); + assertThrows(() => i2.exports.call(i)); + } +})(); + +function addConstFuncUsingGlobal(builder, val) { + let g = builder.addGlobal(kWasmI32, false); + g.init = val; + return builder.addFunction("global" + val, kSig_i_v) + .addBody([kExprGetGlobal, g.index]).index; +} + +(function TestAliasedImportedTableInstanceGlobals() { + print(arguments.callee.name); + + { + let builder = new WasmModuleBuilder(); + let signums = addSigs(builder, 1); + + builder.addImportedTable("m", "table", kTableSize, kTableSize); + let f14 = addConstFuncUsingGlobal(builder, 14); + let call = builder.addFunction("call", kSig_i_i) + .addBody([ + kExprGetLocal, 0, + kExprCallIndirect, signums.i_v, kTableZero + ]) + .exportAs("call"); + let f18 = addConstFuncUsingGlobal(builder, 18); + builder.addExport("f14", f14); + builder.addExport("f18", f18); + builder.addFunctionTableInit(14, false, [f14], true); + builder.addFunctionTableInit(1, false, [call.index], true); + + var mod1 = builder.toModule(); + } + + { + let builder = new WasmModuleBuilder(); + let signums = addSigs(builder, 3); // ensure different sigids + + builder.addImportedTable("m", "table", kTableSize, kTableSize); + let f14 = builder.addImport("m", "f14", kSig_i_v); + let f18 = builder.addImport("m", "f18", kSig_i_v); + let f22 = addConstFuncUsingGlobal(builder, 22); + let call = builder.addFunction("call", kSig_i_i) + .addBody([ + kExprGetLocal, 0, + kExprCallIndirect, signums.i_v, kTableZero + ]) + .exportAs("call"); + let f28 = addConstFuncUsingGlobal(builder, 28); + builder.addFunctionTableInit(18, false, [f18], true); + builder.addFunctionTableInit(22, false, [f22], true); + builder.addFunctionTableInit(28, false, [f28], true); + builder.addFunctionTableInit(5, false, [call.index], true); + + var mod2 = builder.toModule(); + } + + var table = new WebAssembly.Table({initial: kTableSize, + maximum: kTableSize, element: "anyfunc"}); + var i1 = new WebAssembly.Instance(mod1, {m: {table: table}}); + + var i2 = new WebAssembly.Instance(mod2, + {m: {table: table, f14: i1.exports.f14, f18: i1.exports.f18}}); + + for (i of [14, 18, 22, 28]) { + print(i); + assertEquals(i, i1.exports.call(i)); + assertEquals(i, i2.exports.call(i)); + } + for (i of [0, 1, 5, 16]) { + assertThrows(() => i1.exports.call(i)); + assertThrows(() => i2.exports.call(i)); + } +})(); + + +function addConstFuncUsingMemory(builder, val) { + var addr = builder.address; + builder.address += 8; + var bytes = [val & 0xff, (val>>8) & 0xff, (val>>16) & 0xff, (val>>24) & 0xff]; + builder.addDataSegment(addr, bytes); + return builder.addFunction("mem" + val, kSig_i_v) + .addBody([ + ...wasmI32Const(addr), + kExprI32LoadMem, 0, 0 + ]).index; +} + +(function TestAliasedImportedTableInstanceMemories() { + print(arguments.callee.name); + + { + let builder = new WasmModuleBuilder(); + builder.address = 8; + let signums = addSigs(builder, 1); + + builder.addMemory(1, 1, false); + builder.addImportedTable("m", "table", kTableSize, kTableSize); + let f13 = addConstFuncUsingMemory(builder, 13); + let call = builder.addFunction("call", kSig_i_i) + .addBody([ + kExprGetLocal, 0, + kExprCallIndirect, signums.i_v, kTableZero + ]) + .exportAs("call"); + let f19 = addConstFuncUsingMemory(builder, 19); + builder.addExport("f13", f13); + builder.addExport("f19", f19); + builder.addFunctionTableInit(13, false, [f13], true); + builder.addFunctionTableInit(1, false, [call.index], true); + + var mod1 = builder.toModule(); + } + + { + let builder = new WasmModuleBuilder(); + builder.address = 8; + let signums = addSigs(builder, 4); // ensure different sigids + + builder.addMemory(1, 1, false); + builder.addImportedTable("m", "table", kTableSize, kTableSize); + let f13 = builder.addImport("m", "f13", kSig_i_v); + let f19 = builder.addImport("m", "f19", kSig_i_v); + let f23 = addConstFuncUsingMemory(builder, 23); + let call = builder.addFunction("call", kSig_i_i) + .addBody([ + kExprGetLocal, 0, + kExprCallIndirect, signums.i_v, kTableZero + ]) + .exportAs("call"); + let f29 = addConstFuncUsingMemory(builder, 29); + builder.addFunctionTableInit(19, false, [f19], true); + builder.addFunctionTableInit(23, false, [f23], true); + builder.addFunctionTableInit(29, false, [f29], true); + builder.addFunctionTableInit(5, false, [call.index], true); + + var mod2 = builder.toModule(); + } + + var table = new WebAssembly.Table({initial: kTableSize, + maximum: kTableSize, element: "anyfunc"}); + var i1 = new WebAssembly.Instance(mod1, {m: {table: table}}); + + var i2 = new WebAssembly.Instance(mod2, + {m: {table: table, f13: i1.exports.f13, f19: i1.exports.f19}}); + + for (i of [13, 19, 23, 29]) { + print(i); + assertEquals(i, i1.exports.call(i)); + assertEquals(i, i2.exports.call(i)); + } + for (i of [0, 1, 5, 16]) { + assertThrows(() => i1.exports.call(i)); + assertThrows(() => i2.exports.call(i)); + } +})(); diff --git a/doc/api/async_hooks.md b/doc/api/async_hooks.md index 6a6cc781a79f1f..ac38f8093567b7 100644 --- a/doc/api/async_hooks.md +++ b/doc/api/async_hooks.md @@ -150,9 +150,9 @@ Because printing to the console is an asynchronous operation, `console.log()` will cause the AsyncHooks callbacks to be called. Using `console.log()` or similar asynchronous operations inside an AsyncHooks callback function will thus cause an infinite recursion. An easy solution to this when debugging is to use a -synchronous logging operation such as `fs.writeSync(process.stdout.fd, msg)`. -This will print to stdout and will not invoke AsyncHooks recursively because it -is synchronous. +synchronous logging operation such as `fs.writeFileSync(file, msg, flag)`. +This will print to the file and will not invoke AsyncHooks recursively because +it is synchronous. ```js const fs = require('fs'); @@ -160,7 +160,7 @@ const util = require('util'); function debug(...args) { // use a function like this one when debugging inside an AsyncHooks callback - fs.writeSync(process.stdout.fd, `${util.format(...args)}\n`); + fs.writeFileSync('log.out', `${util.format(...args)}\n`, { flag: 'a' }); } ``` @@ -330,17 +330,20 @@ async_hooks.createHook({ }, before(asyncId) { const indentStr = ' '.repeat(indent); - fs.writeSync(process.stdout.fd, `${indentStr}before: ${asyncId}\n`); + fs.writeFileSync('log.out', + `${indentStr}before: ${asyncId}\n`, { flag: 'a' }); indent += 2; }, after(asyncId) { indent -= 2; const indentStr = ' '.repeat(indent); - fs.writeSync(process.stdout.fd, `${indentStr}after: ${asyncId}\n`); + fs.writeFileSync('log.out', + `${indentStr}after: ${asyncId}\n`, { flag: 'a' }); }, destroy(asyncId) { const indentStr = ' '.repeat(indent); - fs.writeSync(process.stdout.fd, `${indentStr}destroy: ${asyncId}\n`); + fs.writeFileSync('log.out', + `${indentStr}destroy: ${asyncId}\n`, { flag: 'a' }); }, }).enable(); @@ -479,13 +482,12 @@ The ID returned from `executionAsyncId()` is related to execution timing, not causality (which is covered by `triggerAsyncId()`): ```js -const server = net.createServer(function onConnection(conn) { +const server = net.createServer((conn) => { // Returns the ID of the server, not of the new connection, because the - // onConnection callback runs in the execution scope of the server's - // MakeCallback(). + // callback runs in the execution scope of the server's MakeCallback(). async_hooks.executionAsyncId(); -}).listen(port, function onListening() { +}).listen(port, () => { // Returns the ID of a TickObject (i.e. process.nextTick()) because all // callbacks passed to .listen() are wrapped in a nextTick(). async_hooks.executionAsyncId(); diff --git a/doc/api/child_process.md b/doc/api/child_process.md index 04f8fa8a3d9bb6..0681b6bc47c2f3 100644 --- a/doc/api/child_process.md +++ b/doc/api/child_process.md @@ -325,6 +325,9 @@ changes: * `args` {string[]} List of string arguments. * `options` {Object} * `cwd` {string} Current working directory of the child process. + * `detached` {boolean} Prepare child to run independently of its parent + process. Specific behavior depends on the platform, see + [`options.detached`][]). * `env` {Object} Environment key-value pairs. * `execPath` {string} Executable used to create the child process. * `execArgv` {string[]} List of string arguments passed to the executable. diff --git a/doc/api/crypto.md b/doc/api/crypto.md index a23b1fe5d4fa0a..79d30b580d8cba 100644 --- a/doc/api/crypto.md +++ b/doc/api/crypto.md @@ -2220,7 +2220,9 @@ request. ### crypto.randomFillSync(buffer[, offset][, size]) + +* {string} + +The request authority pseudo header field. It can also be accessed via +`req.headers[':authority']`. + #### request.destroy([error]) + +* {string} + +The request scheme pseudo header field indicating the scheme +portion of the target URL. + #### request.setTimeout(msecs, callback) ```js const { Writable } = require('stream'); @@ -1531,6 +1532,7 @@ changes: * `final` {Function} Implementation for the [`stream._final()`][stream-_final] method. + ```js const { Writable } = require('stream'); @@ -1702,11 +1704,6 @@ required elements of a custom [`Writable`][] stream instance: const { Writable } = require('stream'); class MyWritable extends Writable { - constructor(options) { - super(options); - // ... - } - _write(chunk, encoding, callback) { if (chunk.toString().indexOf('a') >= 0) { callback(new Error('chunk is invalid')); @@ -1780,6 +1777,7 @@ constructor and implement the `readable._read()` method. * `destroy` {Function} Implementation for the [`stream._destroy()`][readable-_destroy] method. + ```js const { Readable } = require('stream'); @@ -2038,6 +2036,7 @@ changes: * `writableHighWaterMark` {number} Sets `highWaterMark` for the writable side of the stream. Has no effect if `highWaterMark` is provided. + ```js const { Duplex } = require('stream'); @@ -2192,6 +2191,7 @@ output on the `Readable` side is not consumed. * `flush` {Function} Implementation for the [`stream._flush()`][stream-_flush] method. + ```js const { Transform } = require('stream'); diff --git a/doc/api/url.md b/doc/api/url.md index 84f9b3684ff0b2..0789ecf70cbe3d 100644 --- a/doc/api/url.md +++ b/doc/api/url.md @@ -73,7 +73,9 @@ const myURL = ### Class: URL * `obj` {Object} An object representing a collection of key-value pairs @@ -627,7 +633,9 @@ console.log(params.toString()); #### Constructor: new URLSearchParams(iterable) * `iterable` {Iterable} An iterable object whose elements are key-value pairs @@ -785,7 +793,9 @@ console.log(params.toString()); #### urlSearchParams.sort() Sort all existing name-value pairs in-place by their names. Sorting is done @@ -836,7 +846,9 @@ for (const [name, value] of params) { ### url.domainToASCII(domain) * `domain` {string} @@ -859,7 +871,9 @@ console.log(url.domainToASCII('xn--iñvalid.com')); ### url.domainToUnicode(domain) * `domain` {string} @@ -881,6 +895,9 @@ console.log(url.domainToUnicode('xn--iñvalid.com')); ``` ### url.fileURLToPath(url) + * `url` {URL | string} The file URL string or URL object to convert to a path. * Returns: {string} The fully-resolved platform-specific Node.js file path. @@ -942,6 +959,9 @@ console.log(url.format(myURL, { fragment: false, unicode: true, auth: false })); ``` ### url.pathToFileURL(path) + * `path` {string} The path to convert to a File URL. * Returns: {URL} The file URL object. diff --git a/doc/api/v8.md b/doc/api/v8.md index e16e8645090713..2d76eb3a0f70f8 100644 --- a/doc/api/v8.md +++ b/doc/api/v8.md @@ -156,7 +156,7 @@ Usage: // Print GC events to stdout for one minute. const v8 = require('v8'); v8.setFlagsFromString('--trace_gc'); -setTimeout(function() { v8.setFlagsFromString('--notrace_gc'); }, 60e3); +setTimeout(() => { v8.setFlagsFromString('--notrace_gc'); }, 60e3); ``` ## Serialization API diff --git a/doc/api/vm.md b/doc/api/vm.md index d023d9c216903a..e8c4d1a6cbf2f2 100644 --- a/doc/api/vm.md +++ b/doc/api/vm.md @@ -167,10 +167,19 @@ const contextifiedSandbox = vm.createContext({ secret: 42 }); in stack traces produced by this `Module`. * `columnOffset` {integer} Specifies the column number offset that is displayed in stack traces produced by this `Module`. - * `initalizeImportMeta` {Function} Called during evaluation of this `Module` + * `initializeImportMeta` {Function} Called during evaluation of this `Module` to initialize the `import.meta`. This function has the signature `(meta, module)`, where `meta` is the `import.meta` object in the `Module`, and `module` is this `vm.SourceTextModule` object. + * `importModuleDynamically` {Function} Called during evaluation of this + module when `import()` is called. This function has the signature + `(specifier, module)` where `specifier` is the specifier passed to + `import()` and `module` is this `vm.SourceTextModule`. If this option is + not specified, calls to `import()` will reject with + [`ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING`][]. This method can return a + [Module Namespace Object][], but returning a `vm.SourceTextModule` is + recommended in order to take advantage of error tracking, and to avoid + issues with namespaces that contain `then` function exports. Creates a new ES `Module` object. @@ -436,6 +445,15 @@ changes: The `cachedDataProduced` value will be set to either `true` or `false` depending on whether code cache data is produced successfully. This option is deprecated in favor of `script.createCachedData()`. + * `importModuleDynamically` {Function} Called during evaluation of this + module when `import()` is called. This function has the signature + `(specifier, module)` where `specifier` is the specifier passed to + `import()` and `module` is this `vm.SourceTextModule`. If this option is + not specified, calls to `import()` will reject with + [`ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING`][]. This method can return a + [Module Namespace Object][], but returning a `vm.SourceTextModule` is + recommended in order to take advantage of error tracking, and to avoid + issues with namespaces that contain `then` function exports. Creating a new `vm.Script` object compiles `code` but does not run it. The compiled `vm.Script` can be run later multiple times. The `code` is not bound to @@ -977,6 +995,7 @@ This issue occurs because all contexts share the same microtask and nextTick queues. [`Error`]: errors.html#errors_class_error +[`ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING`]: errors.html#ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING [`URL`]: url.html#url_class_url [`eval()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval [`script.runInContext()`]: #vm_script_runincontext_contextifiedsandbox_options @@ -985,6 +1004,7 @@ queues. [`vm.createContext()`]: #vm_vm_createcontext_sandbox_options [`vm.runInContext()`]: #vm_vm_runincontext_code_contextifiedsandbox_options [`vm.runInThisContext()`]: #vm_vm_runinthiscontext_code_options +[Module Namespace Object]: https://tc39.github.io/ecma262/#sec-module-namespace-exotic-objects [ECMAScript Module Loader]: esm.html#esm_ecmascript_modules [Evaluate() concrete method]: https://tc39.github.io/ecma262/#sec-moduleevaluation [GetModuleNamespace]: https://tc39.github.io/ecma262/#sec-getmodulenamespace diff --git a/doc/api/worker_threads.md b/doc/api/worker_threads.md index 86b66fec90f9b4..ed4574ef441dd5 100644 --- a/doc/api/worker_threads.md +++ b/doc/api/worker_threads.md @@ -125,7 +125,7 @@ structured data, memory regions and other `MessagePort`s between different [`Worker`][]s. With the exception of `MessagePort`s being [`EventEmitter`][]s rather -than `EventTarget`s, this implementation matches [browser `MessagePort`][]s. +than [`EventTarget`][]s, this implementation matches [browser `MessagePort`][]s. ### Event: 'close' +* Extends: {EventEmitter} + The `Worker` class represents an independent JavaScript execution thread. Most Node.js APIs are available inside of it. @@ -305,10 +307,10 @@ if (isMainThread) { * `filename` {string} The path to the Worker’s main script. Must be either an absolute path or a relative path (i.e. relative to the current working directory) starting with `./` or `../`. - If `options.eval` is true, this is a string containing JavaScript code rather - than a path. + If `options.eval` is `true`, this is a string containing JavaScript code + rather than a path. * `options` {Object} - * `eval` {boolean} If true, interpret the first argument to the constructor + * `eval` {boolean} If `true`, interpret the first argument to the constructor as a script that is executed once the worker is online. * `workerData` {any} Any JavaScript value that will be cloned and made available as [`require('worker_threads').workerData`][]. The cloning will @@ -461,6 +463,7 @@ active handle in the event system. If the worker is already `unref()`ed calling [`Buffer`]: buffer.html [`EventEmitter`]: events.html +[`EventTarget`]: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget [`MessagePort`]: #worker_threads_class_messageport [`SharedArrayBuffer`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer [`Uint8Array`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array diff --git a/doc/changelogs/CHANGELOG_V10.md b/doc/changelogs/CHANGELOG_V10.md index 7f54626bd06c1a..43dafabeb5b30c 100644 --- a/doc/changelogs/CHANGELOG_V10.md +++ b/doc/changelogs/CHANGELOG_V10.md @@ -10,6 +10,7 @@ +10.15.3
10.15.2
10.15.1
10.15.0
@@ -50,6 +51,231 @@ * [io.js](CHANGELOG_IOJS.md) * [Archive](CHANGELOG_ARCHIVE.md) + + +## 2018-03-05, Version 10.15.3 'Dubnium' (LTS), @BethGriggs + +### Notable Changes + +* **doc** + * add antsmartian to collaborators (Anto Aravinth) [#24655](https://github.com/nodejs/node/pull/24655) +* **http** + * fix error check in Execute() (Brian White) [#25863](https://github.com/nodejs/node/pull/25863) +* **stream** + * fix end-of-stream for HTTP/2 (Anna Henningsen) [#24926](https://github.com/nodejs/node/pull/24926) + +### Commits + +* [[`732088dd44`](https://github.com/nodejs/node/commit/732088dd44)] - **assert**: fix loose deepEqual map comparison (Ruben Bridgewater) [#24749](https://github.com/nodejs/node/pull/24749) +* [[`5a81a4f6cd`](https://github.com/nodejs/node/commit/5a81a4f6cd)] - **assert,util**: fix sparse array comparison (Ruben Bridgewater) [#24749](https://github.com/nodejs/node/pull/24749) +* [[`bd08ede3ab`](https://github.com/nodejs/node/commit/bd08ede3ab)] - **buffer**: remove checkNumberType() (cjihrig) [#24815](https://github.com/nodejs/node/pull/24815) +* [[`15756e0acc`](https://github.com/nodejs/node/commit/15756e0acc)] - **build**: set `-blibpath:` for AIX (Richard Lau) [#25447](https://github.com/nodejs/node/pull/25447) +* [[`fde56fa748`](https://github.com/nodejs/node/commit/fde56fa748)] - **build**: make lint-addon-docs run only if needed (Daniel Bevenius) [#24993](https://github.com/nodejs/node/pull/24993) +* [[`8d4d3963e0`](https://github.com/nodejs/node/commit/8d4d3963e0)] - **build**: fix compiler version detection (Richard Lau) [#24879](https://github.com/nodejs/node/pull/24879) +* [[`552a5c080a`](https://github.com/nodejs/node/commit/552a5c080a)] - **build**: add '.git' to 'make lint-py' exclude list (cclauss) [#24802](https://github.com/nodejs/node/pull/24802) +* [[`02e9a93d2c`](https://github.com/nodejs/node/commit/02e9a93d2c)] - **build**: fix check-xz for platforms defaulting to sh (Rod Vagg) [#24841](https://github.com/nodejs/node/pull/24841) +* [[`920cab76cf`](https://github.com/nodejs/node/commit/920cab76cf)] - **build**: make tar.xz creation opt-out, fail if no xz (Rod Vagg) [#24551](https://github.com/nodejs/node/pull/24551) +* [[`b72bc11a93`](https://github.com/nodejs/node/commit/b72bc11a93)] - **build**: fix line length off by one error (Ruben Bridgewater) [#24748](https://github.com/nodejs/node/pull/24748) +* [[`18d81c94a6`](https://github.com/nodejs/node/commit/18d81c94a6)] - **build**: add line break as soon tests are done (Ruben Bridgewater) [#24748](https://github.com/nodejs/node/pull/24748) +* [[`c57008e549`](https://github.com/nodejs/node/commit/c57008e549)] - **build**: fix c++ code coverage on macOS (Refael Ackermann) [#24520](https://github.com/nodejs/node/pull/24520) +* [[`95a3b3e142`](https://github.com/nodejs/node/commit/95a3b3e142)] - **build**: replace `-not` with `!` in `find` (Rich Trott) [#24635](https://github.com/nodejs/node/pull/24635) +* [[`32d93cde01`](https://github.com/nodejs/node/commit/32d93cde01)] - **build, tools, win**: add .S files support to GYP (Bartosz Sosnowski) [#24553](https://github.com/nodejs/node/pull/24553) +* [[`a2155e1010`](https://github.com/nodejs/node/commit/a2155e1010)] - **crypto**: harden bignum-to-binary conversions (Ben Noordhuis) [#24719](https://github.com/nodejs/node/pull/24719) +* [[`6f4e30d029`](https://github.com/nodejs/node/commit/6f4e30d029)] - **crypto**: convert to arrow function (yosuke ota) [#24597](https://github.com/nodejs/node/pull/24597) +* [[`3b9fd0881a`](https://github.com/nodejs/node/commit/3b9fd0881a)] - **deps**: V8: cherry-pick 3cc6919 (milad) [#25872](https://github.com/nodejs/node/pull/25872) +* [[`70322ea2ca`](https://github.com/nodejs/node/commit/70322ea2ca)] - **deps**: V8: cherry-pick d0468de (Milad Farazmand) [#25827](https://github.com/nodejs/node/pull/25827) +* [[`c9a3e401da`](https://github.com/nodejs/node/commit/c9a3e401da)] - **deps**: cherry-pick d9fbfeb from upstream V8 (Alexey Kozyatinskiy) [#25330](https://github.com/nodejs/node/pull/25330) +* [[`e20e3472a4`](https://github.com/nodejs/node/commit/e20e3472a4)] - **deps**: V8: backport 442977e (Ali Ijaz Sheikh) [#25242](https://github.com/nodejs/node/pull/25242) +* [[`8af4f44130`](https://github.com/nodejs/node/commit/8af4f44130)] - **dns**: simplify dns.promises warning logic (cjihrig) [#24788](https://github.com/nodejs/node/pull/24788) +* [[`cfd5773f8d`](https://github.com/nodejs/node/commit/cfd5773f8d)] - **doc**: document fs.write limitation with TTY (Matteo Collina) [#24571](https://github.com/nodejs/node/pull/24571) +* [[`89ba5f41c8`](https://github.com/nodejs/node/commit/89ba5f41c8)] - **doc**: revise "Breaking Changes" section of Collaborator Guide (Rich Trott) [#25071](https://github.com/nodejs/node/pull/25071) +* [[`7382e8f648`](https://github.com/nodejs/node/commit/7382e8f648)] - **doc**: fix node.1 --http-parser sort order (cjihrig) [#25045](https://github.com/nodejs/node/pull/25045) +* [[`66e6c2a88b`](https://github.com/nodejs/node/commit/66e6c2a88b)] - **doc**: add EventTarget link to worker\_threads (Azard) [#25058](https://github.com/nodejs/node/pull/25058) +* [[`d1f19a033c`](https://github.com/nodejs/node/commit/d1f19a033c)] - **doc**: make README formatting more consistent (wenjun ye) [#25003](https://github.com/nodejs/node/pull/25003) +* [[`1880f23ed2`](https://github.com/nodejs/node/commit/1880f23ed2)] - **doc**: add codebytere's info to release team (Shelley Vohr) [#25022](https://github.com/nodejs/node/pull/25022) +* [[`8f434414a4`](https://github.com/nodejs/node/commit/8f434414a4)] - **doc**: revise internal vs. public API in Collaborator Guide (Rich Trott) [#24975](https://github.com/nodejs/node/pull/24975) +* [[`8ae649d105`](https://github.com/nodejs/node/commit/8ae649d105)] - **doc**: update a link of npm repository (Daijiro Wachi) [#24969](https://github.com/nodejs/node/pull/24969) +* [[`9ffa8270b1`](https://github.com/nodejs/node/commit/9ffa8270b1)] - **doc**: fix author-ready conflict (Ruben Bridgewater) [#25015](https://github.com/nodejs/node/pull/25015) +* [[`bdf21c1f10`](https://github.com/nodejs/node/commit/bdf21c1f10)] - **doc**: update Useful CI Jobs section of Collaborator Guide (Rich Trott) [#24916](https://github.com/nodejs/node/pull/24916) +* [[`f8ac170608`](https://github.com/nodejs/node/commit/f8ac170608)] - **doc**: add class worker documentation (yoshimoto koki) [#24849](https://github.com/nodejs/node/pull/24849) +* [[`f68ff0619c`](https://github.com/nodejs/node/commit/f68ff0619c)] - **doc**: remove bad link to irc info (Richard Lau) [#24967](https://github.com/nodejs/node/pull/24967) +* [[`0701559336`](https://github.com/nodejs/node/commit/0701559336)] - **doc**: simplify author ready (Ruben Bridgewater) [#24893](https://github.com/nodejs/node/pull/24893) +* [[`e7e8a25bb8`](https://github.com/nodejs/node/commit/e7e8a25bb8)] - **doc**: update "Testing and CI" in Collaborator Guide (Rich Trott) [#24884](https://github.com/nodejs/node/pull/24884) +* [[`a7f36dde00`](https://github.com/nodejs/node/commit/a7f36dde00)] - **doc**: update http doc for new Agent()/support options in socket.connect() (Beni von Cheni) [#24846](https://github.com/nodejs/node/pull/24846) +* [[`e9ad526297`](https://github.com/nodejs/node/commit/e9ad526297)] - **doc**: fix order of events when request is aborted (Luigi Pinca) [#24779](https://github.com/nodejs/node/pull/24779) +* [[`189d2e2ab2`](https://github.com/nodejs/node/commit/189d2e2ab2)] - **doc**: revise Waiting for Approvals documentation (Rich Trott) [#24845](https://github.com/nodejs/node/pull/24845) +* [[`f2df92cfc0`](https://github.com/nodejs/node/commit/f2df92cfc0)] - **doc**: list all versions WHATWG URL api was added (Thomas Watson) [#24847](https://github.com/nodejs/node/pull/24847) +* [[`2b03878de3`](https://github.com/nodejs/node/commit/2b03878de3)] - **doc**: add authority and scheme psuedo headers (Kenigbolo Meya Stephen) [#24777](https://github.com/nodejs/node/pull/24777) +* [[`23cd76e9ef`](https://github.com/nodejs/node/commit/23cd76e9ef)] - **doc**: add triaging section to releases.md (Beth Griggs) [#20165](https://github.com/nodejs/node/pull/20165) +* [[`f52ff588e2`](https://github.com/nodejs/node/commit/f52ff588e2)] - **doc**: use author's titles for linked resources (Rich Trott) [#24837](https://github.com/nodejs/node/pull/24837) +* [[`0a3c88551a`](https://github.com/nodejs/node/commit/0a3c88551a)] - **doc**: revise code review guidelines (Rich Trott) [#24790](https://github.com/nodejs/node/pull/24790) +* [[`7bd7328f0d`](https://github.com/nodejs/node/commit/7bd7328f0d)] - **doc**: add a note on usage scope of AliasedBuffer (Gireesh Punathil) [#24724](https://github.com/nodejs/node/pull/24724) +* [[`184425e7e8`](https://github.com/nodejs/node/commit/184425e7e8)] - **doc**: hide undocumented object artifacts in async\_hooks (Gireesh Punathil) [#24741](https://github.com/nodejs/node/pull/24741) +* [[`ad40e781af`](https://github.com/nodejs/node/commit/ad40e781af)] - **doc**: fix added version of randomFill+randomFillSync (Thomas Watson) [#24812](https://github.com/nodejs/node/pull/24812) +* [[`56916c8430`](https://github.com/nodejs/node/commit/56916c8430)] - **doc**: streamline Accepting Modifications in Collaborator Guide (Rich Trott) [#24807](https://github.com/nodejs/node/pull/24807) +* [[`7ae17573e6`](https://github.com/nodejs/node/commit/7ae17573e6)] - **doc**: make release README link be consistent with text (ZYSzys) [#24783](https://github.com/nodejs/node/pull/24783) +* [[`1c593c8192`](https://github.com/nodejs/node/commit/1c593c8192)] - **doc**: cookie is joined using '; ' (Gerhard Stoebich) [#24740](https://github.com/nodejs/node/pull/24740) +* [[`3e4b93ac8e`](https://github.com/nodejs/node/commit/3e4b93ac8e)] - **doc**: add antsmartian to collaborators (Anto Aravinth) [#24655](https://github.com/nodejs/node/pull/24655) +* [[`fe698d8ca0`](https://github.com/nodejs/node/commit/fe698d8ca0)] - **doc**: revise accepting-modifications in guide (Rich Trott) [#24650](https://github.com/nodejs/node/pull/24650) +* [[`546f9419d7`](https://github.com/nodejs/node/commit/546f9419d7)] - **doc**: clarify symlink resolution for \_\_filename (Rich Trott) [#24587](https://github.com/nodejs/node/pull/24587) +* [[`a1a393bfbf`](https://github.com/nodejs/node/commit/a1a393bfbf)] - **doc**: use arrow function for anonymous callbacks (koki-oshima) [#24606](https://github.com/nodejs/node/pull/24606) +* [[`6788d856d5`](https://github.com/nodejs/node/commit/6788d856d5)] - **doc**: revise handling-own-pull-requests text (Rich Trott) [#24583](https://github.com/nodejs/node/pull/24583) +* [[`bda73542be`](https://github.com/nodejs/node/commit/bda73542be)] - **doc**: fix duplicate "this" and "the" on http2.md (Yusuke Kawasaki) [#24611](https://github.com/nodejs/node/pull/24611) +* [[`73b99c7013`](https://github.com/nodejs/node/commit/73b99c7013)] - **doc**: replace anonymous function with arrow function (ka2jun8) [#24617](https://github.com/nodejs/node/pull/24617) +* [[`1eeb37c39c`](https://github.com/nodejs/node/commit/1eeb37c39c)] - **doc**: use arrow function (sadness_ojisan) [#24590](https://github.com/nodejs/node/pull/24590) +* [[`283172771e`](https://github.com/nodejs/node/commit/283172771e)] - **doc**: replace anonymous function with arrow function (yuriettys) [#24627](https://github.com/nodejs/node/pull/24627) +* [[`dd5bfd7f74`](https://github.com/nodejs/node/commit/dd5bfd7f74)] - **doc**: mark napi\_add\_finalizer experimental (Michael Dawson) [#24572](https://github.com/nodejs/node/pull/24572) +* [[`dacdd0113f`](https://github.com/nodejs/node/commit/dacdd0113f)] - **esm**: refactor dynamic modules (Myles Borins) [#24560](https://github.com/nodejs/node/pull/24560) +* [[`576d9c513a`](https://github.com/nodejs/node/commit/576d9c513a)] - **fs**: simplify fs.promises warning logic (cjihrig) [#24788](https://github.com/nodejs/node/pull/24788) +* [[`741c5ef6cd`](https://github.com/nodejs/node/commit/741c5ef6cd)] - **http**: fix error check in `Execute()` (Brian White) [#25863](https://github.com/nodejs/node/pull/25863) +* [[`f4aed8c3df`](https://github.com/nodejs/node/commit/f4aed8c3df)] - **http2**: make compat writeHead not crash if the stream is destroyed (Matteo Collina) [#24723](https://github.com/nodejs/node/pull/24723) +* [[`d12c5a7a75`](https://github.com/nodejs/node/commit/d12c5a7a75)] - **http2**: add compat support for nested array headers (Sebastiaan Deckers) [#24665](https://github.com/nodejs/node/pull/24665) +* [[`c7f876be38`](https://github.com/nodejs/node/commit/c7f876be38)] - **http2**: fix session\[kSession\] undefined issue (leeight) [#24547](https://github.com/nodejs/node/pull/24547) +* [[`e8dfdc063d`](https://github.com/nodejs/node/commit/e8dfdc063d)] - **lib**: ensure readable stream flows to end (Mikko Rantanen) [#24918](https://github.com/nodejs/node/pull/24918) +* [[`d5d8670783`](https://github.com/nodejs/node/commit/d5d8670783)] - **lib**: remove some useless assignments (Gus Caplan) [#23199](https://github.com/nodejs/node/pull/23199) +* [[`96036ef798`](https://github.com/nodejs/node/commit/96036ef798)] - **lib**: do not register DOMException in a module (Joyee Cheung) [#24708](https://github.com/nodejs/node/pull/24708) +* [[`ef68349617`](https://github.com/nodejs/node/commit/ef68349617)] - **lib**: move setupAllowedFlags() into per\_thread.js (Joyee Cheung) [#24704](https://github.com/nodejs/node/pull/24704) +* [[`1b48c9d9e3`](https://github.com/nodejs/node/commit/1b48c9d9e3)] - **lib**: convert to arrow function in fs.js (exoego) [#24604](https://github.com/nodejs/node/pull/24604) +* [[`eaa5e3efa4`](https://github.com/nodejs/node/commit/eaa5e3efa4)] - **lib**: change callbacks to arrow function (/Jesse) [#24625](https://github.com/nodejs/node/pull/24625) +* [[`4eec736a5e`](https://github.com/nodejs/node/commit/4eec736a5e)] - **lib**: chenged anonymous function to arrow function (nakashima) [#24605](https://github.com/nodejs/node/pull/24605) +* [[`8c93bd4d17`](https://github.com/nodejs/node/commit/8c93bd4d17)] - **lib**: rearm pre-existing signal event registrations (Gireesh Punathil) [#24651](https://github.com/nodejs/node/pull/24651) +* [[`8f427eb987`](https://github.com/nodejs/node/commit/8f427eb987)] - **lib**: convert to arrow function (horihiro) [#24623](https://github.com/nodejs/node/pull/24623) +* [[`e5abfe191e`](https://github.com/nodejs/node/commit/e5abfe191e)] - **lib**: convert to Arrow Function (Daiki Arai) [#24615](https://github.com/nodejs/node/pull/24615) +* [[`ccefef2d45`](https://github.com/nodejs/node/commit/ccefef2d45)] - **lib**: suppress crypto related env vars in help msg (Daniel Bevenius) [#24556](https://github.com/nodejs/node/pull/24556) +* [[`1c2ce239a1`](https://github.com/nodejs/node/commit/1c2ce239a1)] - **lib**: convert to arrow function (Naojirou Hisada) [#24596](https://github.com/nodejs/node/pull/24596) +* [[`c87af34886`](https://github.com/nodejs/node/commit/c87af34886)] - **lib**: change anonymous function to arrow function (takato) [#24589](https://github.com/nodejs/node/pull/24589) +* [[`ce2aa807f5`](https://github.com/nodejs/node/commit/ce2aa807f5)] - **lib**: simplify own keys retrieval (Vse Mozhet Byt) [#24582](https://github.com/nodejs/node/pull/24582) +* [[`9daf175483`](https://github.com/nodejs/node/commit/9daf175483)] - **lib**: fix nits in lib/internal/bootstrap/cache.js (Vse Mozhet Byt) [#24581](https://github.com/nodejs/node/pull/24581) +* [[`f2287c61e1`](https://github.com/nodejs/node/commit/f2287c61e1)] - **module**: use validateString in modules/esm (ZYSzys) [#24868](https://github.com/nodejs/node/pull/24868) +* [[`229f901a0f`](https://github.com/nodejs/node/commit/229f901a0f)] - **module**: use validateString in modules/cjs (ZYSzys) [#24863](https://github.com/nodejs/node/pull/24863) +* [[`fe0e119f55`](https://github.com/nodejs/node/commit/fe0e119f55)] - **n-api**: handle reference delete before finalize (Michael Dawson) [#24494](https://github.com/nodejs/node/pull/24494) +* [[`760277e490`](https://github.com/nodejs/node/commit/760277e490)] - **n-api,test**: remove last argument in assert.strictEqual() (susantruong) [#24584](https://github.com/nodejs/node/pull/24584) +* [[`f6e07fd809`](https://github.com/nodejs/node/commit/f6e07fd809)] - **net**: use strict comparisons for fd (cjihrig) [#25014](https://github.com/nodejs/node/pull/25014) +* [[`7eda47e5c9`](https://github.com/nodejs/node/commit/7eda47e5c9)] - **path**: replace assertPath() with validator (cjihrig) [#24840](https://github.com/nodejs/node/pull/24840) +* [[`33a907de20`](https://github.com/nodejs/node/commit/33a907de20)] - **perf_hooks**: make GC tracking state per-Environment (Anna Henningsen) [#25053](https://github.com/nodejs/node/pull/25053) +* [[`931a04e37e`](https://github.com/nodejs/node/commit/931a04e37e)] - **process**: fix omitting `--` from `process.execArgv` (Anna Henningsen) [#24654](https://github.com/nodejs/node/pull/24654) +* [[`a4068d9827`](https://github.com/nodejs/node/commit/a4068d9827)] - **process**: properly close file descriptor on exit (Ruben Bridgewater) [#24972](https://github.com/nodejs/node/pull/24972) +* [[`fd8a481a12`](https://github.com/nodejs/node/commit/fd8a481a12)] - **process**: simplify check in previousValueIsValid() (cjihrig) [#24836](https://github.com/nodejs/node/pull/24836) +* [[`5bca4c7cc0`](https://github.com/nodejs/node/commit/5bca4c7cc0)] - **process**: emit unhandled warning immediately (Anatoli Papirovski) [#24632](https://github.com/nodejs/node/pull/24632) +* [[`944e75d10b`](https://github.com/nodejs/node/commit/944e75d10b)] - **src**: emit 'params' instead of 'data' for NodeTracing.dataCollected (Kelvin Jin) [#24949](https://github.com/nodejs/node/pull/24949) +* [[`1cc5834180`](https://github.com/nodejs/node/commit/1cc5834180)] - **src**: add GetLoadedLibraries routine (Gireesh Punathil) [#24825](https://github.com/nodejs/node/pull/24825) +* [[`fa84e91813`](https://github.com/nodejs/node/commit/fa84e91813)] - **src**: create env-\>inspector\_console\_api\_object earlier (Joyee Cheung) [#24906](https://github.com/nodejs/node/pull/24906) +* [[`12f0485c8c`](https://github.com/nodejs/node/commit/12f0485c8c)] - **src**: remove use of CallOnForegroundThread() (cjihrig) [#24925](https://github.com/nodejs/node/pull/24925) +* [[`16a1f96d6e`](https://github.com/nodejs/node/commit/16a1f96d6e)] - **src**: do not alias new and old signal masks (Sam Roberts) [#24810](https://github.com/nodejs/node/pull/24810) +* [[`f0e7b2f509`](https://github.com/nodejs/node/commit/f0e7b2f509)] - **src**: fix warning for potential snprintf truncation (Sam Roberts) [#24810](https://github.com/nodejs/node/pull/24810) +* [[`7455597815`](https://github.com/nodejs/node/commit/7455597815)] - **src**: remove finalized\_ member from Hash class (Daniel Bevenius) [#24822](https://github.com/nodejs/node/pull/24822) +* [[`37047fc70a`](https://github.com/nodejs/node/commit/37047fc70a)] - **src**: use arraysize instead of hardcode number (leeight) [#24473](https://github.com/nodejs/node/pull/24473) +* [[`eb20e3d23e`](https://github.com/nodejs/node/commit/eb20e3d23e)] - **src**: set HAS\_USERNAME/PASSWORD more strictly (Timothy Gu) [#24495](https://github.com/nodejs/node/pull/24495) +* [[`4444cdb6cd`](https://github.com/nodejs/node/commit/4444cdb6cd)] - **src**: elevate v8 namespaces referenced (Juan José Arboleda) [#24657](https://github.com/nodejs/node/pull/24657) +* [[`28a1cc1377`](https://github.com/nodejs/node/commit/28a1cc1377)] - **src**: simplify uptime and ppid return values (cjihrig) [#24562](https://github.com/nodejs/node/pull/24562) +* [[`8c48302a50`](https://github.com/nodejs/node/commit/8c48302a50)] - **src**: elevate v8 namespaces for node\_url.cc (Jayasankar) [#24573](https://github.com/nodejs/node/pull/24573) +* [[`863d1987a3`](https://github.com/nodejs/node/commit/863d1987a3)] - **src**: elevate v8 namespaces of node\_trace\_events.cc (Jayasankar) [#24469](https://github.com/nodejs/node/pull/24469) +* [[`26f7edbf71`](https://github.com/nodejs/node/commit/26f7edbf71)] - **src**: re-sort the symbol macros (Sam Roberts) [#24382](https://github.com/nodejs/node/pull/24382) +* [[`450bcde462`](https://github.com/nodejs/node/commit/450bcde462)] - **src**: use v8:: for consistency in util (ZYSzys) [#23934](https://github.com/nodejs/node/pull/23934) +* [[`3f969d61ff`](https://github.com/nodejs/node/commit/3f969d61ff)] - **stream**: re-use existing `once()` implementation (Anna Henningsen) [#24991](https://github.com/nodejs/node/pull/24991) +* [[`bb8a65dd84`](https://github.com/nodejs/node/commit/bb8a65dd84)] - **stream**: fix end-of-stream for HTTP/2 (Anna Henningsen) [#24926](https://github.com/nodejs/node/pull/24926) +* [[`e356ce851f`](https://github.com/nodejs/node/commit/e356ce851f)] - **stream**: make async iterator .next() always resolve (Matteo Collina) [#24668](https://github.com/nodejs/node/pull/24668) +* [[`e338e50213`](https://github.com/nodejs/node/commit/e338e50213)] - **stream**: use arrow function for callback (DoiChris) [#24609](https://github.com/nodejs/node/pull/24609) +* [[`6be2d6187c`](https://github.com/nodejs/node/commit/6be2d6187c)] - **test**: improve comparison coverage to 100% (Ruben Bridgewater) [#24749](https://github.com/nodejs/node/pull/24749) +* [[`1d083e29e5`](https://github.com/nodejs/node/commit/1d083e29e5)] - **test**: test internal/util/types in vm (ZYSzys) [#25056](https://github.com/nodejs/node/pull/25056) +* [[`56c6686fe5`](https://github.com/nodejs/node/commit/56c6686fe5)] - **test**: merge test with unnecessary child process (Sam Roberts) [#25025](https://github.com/nodejs/node/pull/25025) +* [[`ee054110b5`](https://github.com/nodejs/node/commit/ee054110b5)] - **test**: remove unnecessary linter comment (cjihrig) [#25013](https://github.com/nodejs/node/pull/25013) +* [[`c9b0a36989`](https://github.com/nodejs/node/commit/c9b0a36989)] - **test**: use global.gc() instead of gc() (cjihrig) [#25012](https://github.com/nodejs/node/pull/25012) +* [[`bcfc1d1a7d`](https://github.com/nodejs/node/commit/bcfc1d1a7d)] - **test**: run eslint on test file and fix errors (Ruben Bridgewater) [#25009](https://github.com/nodejs/node/pull/25009) +* [[`17527981d0`](https://github.com/nodejs/node/commit/17527981d0)] - **test**: remove dead code (Ruben Bridgewater) [#25009](https://github.com/nodejs/node/pull/25009) +* [[`48c54137d4`](https://github.com/nodejs/node/commit/48c54137d4)] - **test**: use blocks instead of async IIFE (Anna Henningsen) [#24989](https://github.com/nodejs/node/pull/24989) +* [[`54d7e82530`](https://github.com/nodejs/node/commit/54d7e82530)] - **test**: adding history regression test case (Anto Aravinth) [#24843](https://github.com/nodejs/node/pull/24843) +* [[`dd2b553874`](https://github.com/nodejs/node/commit/dd2b553874)] - **test**: mark test-child-process-execfile flaky (Rich Trott) [#25051](https://github.com/nodejs/node/pull/25051) +* [[`bfa396a81e`](https://github.com/nodejs/node/commit/bfa396a81e)] - **test**: mark test-child-process-exit-code flaky (Rich Trott) [#25050](https://github.com/nodejs/node/pull/25050) +* [[`55680e3ecb`](https://github.com/nodejs/node/commit/55680e3ecb)] - **test**: mark test-worker-memory flaky on Windows CI (Rich Trott) [#25042](https://github.com/nodejs/node/pull/25042) +* [[`89b6d1b1fa`](https://github.com/nodejs/node/commit/89b6d1b1fa)] - **test**: mark test-child-process-execsync flaky on AIX (Rich Trott) [#25031](https://github.com/nodejs/node/pull/25031) +* [[`11d5c07c7d`](https://github.com/nodejs/node/commit/11d5c07c7d)] - **test**: refactor test-enable-in-init (Mitch Hankins) [#24976](https://github.com/nodejs/node/pull/24976) +* [[`0658424227`](https://github.com/nodejs/node/commit/0658424227)] - **test**: from functools import reduce in test/testpy/\_\_init\_\_.py (cclauss) [#24954](https://github.com/nodejs/node/pull/24954) +* [[`3bdff05cdb`](https://github.com/nodejs/node/commit/3bdff05cdb)] - **test**: improve internet/test-dns (Ilarion Halushka) [#24927](https://github.com/nodejs/node/pull/24927) +* [[`3f2c6ce9aa`](https://github.com/nodejs/node/commit/3f2c6ce9aa)] - **test**: replace callback with arrows (Shubham Urkade) [#24866](https://github.com/nodejs/node/pull/24866) +* [[`2869b7810d`](https://github.com/nodejs/node/commit/2869b7810d)] - **test**: mark test-cli-syntax as flaky/unreliable (Rich Trott) [#24957](https://github.com/nodejs/node/pull/24957) +* [[`83c6f0a86e`](https://github.com/nodejs/node/commit/83c6f0a86e)] - **test**: do not lint macros files (again) (cclauss) [#24886](https://github.com/nodejs/node/pull/24886) +* [[`a67d37d226`](https://github.com/nodejs/node/commit/a67d37d226)] - **test**: prepare test/pseudo-tty/testcfg.py Python 3 (cclauss) [#24887](https://github.com/nodejs/node/pull/24887) +* [[`4e51e3d550`](https://github.com/nodejs/node/commit/4e51e3d550)] - **test**: move test-cli-syntax to sequential (Rich Trott) [#24907](https://github.com/nodejs/node/pull/24907) +* [[`e20ad2e446`](https://github.com/nodejs/node/commit/e20ad2e446)] - **test**: move http2 test to parallel (Rich Trott) [#24877](https://github.com/nodejs/node/pull/24877) +* [[`1a1811d1e0`](https://github.com/nodejs/node/commit/1a1811d1e0)] - **test**: make http2 timeout test robust (Rich Trott) [#24877](https://github.com/nodejs/node/pull/24877) +* [[`a2dd3a62a7`](https://github.com/nodejs/node/commit/a2dd3a62a7)] - **test**: fix wrong parameter (zhmushan) [#24844](https://github.com/nodejs/node/pull/24844) +* [[`1dff257280`](https://github.com/nodejs/node/commit/1dff257280)] - **test**: improve test-net-socket-timeout (Rich Trott) [#24859](https://github.com/nodejs/node/pull/24859) +* [[`5e29865375`](https://github.com/nodejs/node/commit/5e29865375)] - **test**: prepare test/pseudo-tty/testcfg.py for Python 3 (cclauss) [#24791](https://github.com/nodejs/node/pull/24791) +* [[`520d041afb`](https://github.com/nodejs/node/commit/520d041afb)] - **test**: refactor test-fs-write-file-sync.js (cjihrig) [#24834](https://github.com/nodejs/node/pull/24834) +* [[`b1bbac726e`](https://github.com/nodejs/node/commit/b1bbac726e)] - **test**: prepare test/message/testcfg.py for Python 3 (cclauss) [#24793](https://github.com/nodejs/node/pull/24793) +* [[`ff90d17eb3`](https://github.com/nodejs/node/commit/ff90d17eb3)] - **test**: remove unused addons-napi directory (Rich Trott) [#24839](https://github.com/nodejs/node/pull/24839) +* [[`d08b5e94f5`](https://github.com/nodejs/node/commit/d08b5e94f5)] - **test**: add .gitignore file for node-api (Rich Trott) [#24839](https://github.com/nodejs/node/pull/24839) +* [[`546fc68ae4`](https://github.com/nodejs/node/commit/546fc68ae4)] - **test**: fix `common.mustNotCall()` usage in HTTP test (Anna Henningsen) [#24750](https://github.com/nodejs/node/pull/24750) +* [[`1c746c7524`](https://github.com/nodejs/node/commit/1c746c7524)] - **test**: use ES2017 syntax in test-fs-open-\* (jy95) [#23031](https://github.com/nodejs/node/pull/23031) +* [[`e17dbd22c3`](https://github.com/nodejs/node/commit/e17dbd22c3)] - **test**: add flag scenario in test-fs-write-file-sync (Gireesh Punathil) [#24766](https://github.com/nodejs/node/pull/24766) +* [[`fd5af6bfa9`](https://github.com/nodejs/node/commit/fd5af6bfa9)] - **test**: check invalid argument error for option (timothy searcy) [#24736](https://github.com/nodejs/node/pull/24736) +* [[`46e37adf59`](https://github.com/nodejs/node/commit/46e37adf59)] - **test**: show stdout and stderr in test-cli-syntax when it fails (Joyee Cheung) [#24720](https://github.com/nodejs/node/pull/24720) +* [[`31c1ee405e`](https://github.com/nodejs/node/commit/31c1ee405e)] - **test**: minor refactoring of onticketkeycallback (Daniel Bevenius) [#24718](https://github.com/nodejs/node/pull/24718) +* [[`a7c72d7d5e`](https://github.com/nodejs/node/commit/a7c72d7d5e)] - **test**: mark test\_threadsafe\_function/test as flaky (Gireesh Punathil) [#24714](https://github.com/nodejs/node/pull/24714) +* [[`e74345b2f5`](https://github.com/nodejs/node/commit/e74345b2f5)] - **test**: verify order of error in h2 server stream (Myles Borins) [#24685](https://github.com/nodejs/node/pull/24685) +* [[`288a421dcc`](https://github.com/nodejs/node/commit/288a421dcc)] - **test**: cover path empty string case (lakatostamas) [#24569](https://github.com/nodejs/node/pull/24569) +* [[`d4b1666686`](https://github.com/nodejs/node/commit/d4b1666686)] - **test**: use arrow syntax for anonymous callbacks (Shubham Urkade) [#24691](https://github.com/nodejs/node/pull/24691) +* [[`af582096ad`](https://github.com/nodejs/node/commit/af582096ad)] - **test**: fix the arguments order in assert.strictEqual (pastak) [#24620](https://github.com/nodejs/node/pull/24620) +* [[`e89f5e59ea`](https://github.com/nodejs/node/commit/e89f5e59ea)] - **test**: mark test-vm-timeout-escape-nexttick flaky (Gireesh Punathil) [#24712](https://github.com/nodejs/node/pull/24712) +* [[`288d60c2f6`](https://github.com/nodejs/node/commit/288d60c2f6)] - **test**: fix the arguments order in assert.strictEqual (sigwyg) [#24624](https://github.com/nodejs/node/pull/24624) +* [[`9f66105e29`](https://github.com/nodejs/node/commit/9f66105e29)] - **test**: fix the arguments order in `assert.strictEqual` (rt33) [#24626](https://github.com/nodejs/node/pull/24626) +* [[`06208c8313`](https://github.com/nodejs/node/commit/06208c8313)] - **test**: reach res.\_dump after abort ClientRequest (Tadhg Creedon) [#24191](https://github.com/nodejs/node/pull/24191) +* [[`85e948753b`](https://github.com/nodejs/node/commit/85e948753b)] - **test**: validate fs.rename() when NODE\_TEST\_DIR on separate mount (Drew Folta) [#24707](https://github.com/nodejs/node/pull/24707) +* [[`5966dbed05`](https://github.com/nodejs/node/commit/5966dbed05)] - **test**: test and docs for detached fork process (timothy searcy) [#24524](https://github.com/nodejs/node/pull/24524) +* [[`1c609bf6e2`](https://github.com/nodejs/node/commit/1c609bf6e2)] - **test**: fix arguments order in `assert.strictEqual` (sota1235) [#24607](https://github.com/nodejs/node/pull/24607) +* [[`dc7ed30437`](https://github.com/nodejs/node/commit/dc7ed30437)] - **test**: fix arguments order in assert.strictEqual (grimrose) [#24608](https://github.com/nodejs/node/pull/24608) +* [[`be17cc59c7`](https://github.com/nodejs/node/commit/be17cc59c7)] - **test**: make test-uv-binding-constant JS engine neutral (Rich Trott) [#24666](https://github.com/nodejs/node/pull/24666) +* [[`2318c7fea3`](https://github.com/nodejs/node/commit/2318c7fea3)] - **test**: use arrow function (sagirk) [#24482](https://github.com/nodejs/node/pull/24482) +* [[`43bfb136f9`](https://github.com/nodejs/node/commit/43bfb136f9)] - **test**: fix arguments order in `assert.strictEqual` (Takahiro Nakamura) [#24621](https://github.com/nodejs/node/pull/24621) +* [[`3811817290`](https://github.com/nodejs/node/commit/3811817290)] - **test**: update strictEqual argument order (VeysonD) [#24622](https://github.com/nodejs/node/pull/24622) +* [[`ec7bd18146`](https://github.com/nodejs/node/commit/ec7bd18146)] - **test**: fix argument order in assert.strictEqual (feng jianmei) [#24594](https://github.com/nodejs/node/pull/24594) +* [[`4cc91ff2b5`](https://github.com/nodejs/node/commit/4cc91ff2b5)] - **test**: use arrow functions in callbacks (apoorvanand) [#24441](https://github.com/nodejs/node/pull/24441) +* [[`4093572c4d`](https://github.com/nodejs/node/commit/4093572c4d)] - **test**: add test for socket.end callback (ajido) [#24087](https://github.com/nodejs/node/pull/24087) +* [[`7dee5e5d16`](https://github.com/nodejs/node/commit/7dee5e5d16)] - **test**: replace anonymous closure functions with arrow functions (tpanthera) [#24443](https://github.com/nodejs/node/pull/24443) +* [[`82d9ffc6a6`](https://github.com/nodejs/node/commit/82d9ffc6a6)] - **test**: fix arguments order in `assert.strictEqual` (tottokotkd) [#24612](https://github.com/nodejs/node/pull/24612) +* [[`372073e8da`](https://github.com/nodejs/node/commit/372073e8da)] - **test**: convert callback to arrow function (jamesgeorge007) [#24513](https://github.com/nodejs/node/pull/24513) +* [[`82376015ab`](https://github.com/nodejs/node/commit/82376015ab)] - **test**: change anonymous function to arrow function (Gagandeep Singh) [#24528](https://github.com/nodejs/node/pull/24528) +* [[`5e3b34fbfd`](https://github.com/nodejs/node/commit/5e3b34fbfd)] - **test**: split out http2 from test-stream-pipeline (Rich Trott) [#24631](https://github.com/nodejs/node/pull/24631) +* [[`b6cceae96f`](https://github.com/nodejs/node/commit/b6cceae96f)] - **test**: cover path.basename when path and ext are the same (Laszlo.Moczo) [#24570](https://github.com/nodejs/node/pull/24570) +* [[`7f0fb163a0`](https://github.com/nodejs/node/commit/7f0fb163a0)] - **test**: fix assert.strictEqual (mki-skt) [#24619](https://github.com/nodejs/node/pull/24619) +* [[`e464a1dca5`](https://github.com/nodejs/node/commit/e464a1dca5)] - **test**: fix arguments order in assert.strictEqual (teppeis) [#24591](https://github.com/nodejs/node/pull/24591) +* [[`ec70330dab`](https://github.com/nodejs/node/commit/ec70330dab)] - **test**: fix http2-binding strictEqual order (dominikeinkemmer) [#24616](https://github.com/nodejs/node/pull/24616) +* [[`7b096026d8`](https://github.com/nodejs/node/commit/7b096026d8)] - **test**: fix the arguments order in `assert.strictEqual` (sota1235) [#24595](https://github.com/nodejs/node/pull/24595) +* [[`1658924d90`](https://github.com/nodejs/node/commit/1658924d90)] - **test**: replace callback with arrow functions (prodroy1) [#24434](https://github.com/nodejs/node/pull/24434) +* [[`0e63d0abd5`](https://github.com/nodejs/node/commit/0e63d0abd5)] - **test**: confirm tls server suite default is its own (Sam Roberts) [#24374](https://github.com/nodejs/node/pull/24374) +* [[`3c2b40ba04`](https://github.com/nodejs/node/commit/3c2b40ba04)] - **test**: rename agent1-pfx.pem to agent1.pfx (Sam Roberts) [#24374](https://github.com/nodejs/node/pull/24374) +* [[`43dcbbedb9`](https://github.com/nodejs/node/commit/43dcbbedb9)] - **test**: add independent multi-alg crypto identities (Sam Roberts) [#24374](https://github.com/nodejs/node/pull/24374) +* [[`83145ec3a6`](https://github.com/nodejs/node/commit/83145ec3a6)] - **test**: cover tls multi-identity option mixtures (Sam Roberts) [#24374](https://github.com/nodejs/node/pull/24374) +* [[`77cf877ea2`](https://github.com/nodejs/node/commit/77cf877ea2)] - **tls**: re-define max supported version as 1.2 (Sam Roberts) [#25024](https://github.com/nodejs/node/pull/25024) +* [[`027ca95b46`](https://github.com/nodejs/node/commit/027ca95b46)] - **tools**: make apilinks building more robust (Joyee Cheung) [#25019](https://github.com/nodejs/node/pull/25019) +* [[`694ea008d1`](https://github.com/nodejs/node/commit/694ea008d1)] - **tools**: enable no-useless-constructor lint rule (cjihrig) [#25055](https://github.com/nodejs/node/pull/25055) +* [[`5cbc0dbeaf`](https://github.com/nodejs/node/commit/5cbc0dbeaf)] - **tools**: prepare ./tools/compress\_json.py for Python 3 (cclauss) [#24889](https://github.com/nodejs/node/pull/24889) +* [[`87f20822c1`](https://github.com/nodejs/node/commit/87f20822c1)] - **tools**: prepare tools/testp.py for Python 3 (cclauss) [#24890](https://github.com/nodejs/node/pull/24890) +* [[`91a96e446a`](https://github.com/nodejs/node/commit/91a96e446a)] - **tools**: prepare tools/icu/icutrim.py for Python 3 (cclauss) [#24888](https://github.com/nodejs/node/pull/24888) +* [[`34212b531f`](https://github.com/nodejs/node/commit/34212b531f)] - **tools**: update ESLint to 5.10.0 (cjihrig) [#24903](https://github.com/nodejs/node/pull/24903) +* [[`229c0e0cc9`](https://github.com/nodejs/node/commit/229c0e0cc9)] - **tools**: do not lint tools/inspector\_protocol or tools/markupsafe (cclauss) [#24882](https://github.com/nodejs/node/pull/24882) +* [[`bece371639`](https://github.com/nodejs/node/commit/bece371639)] - **tools**: prepare tools/js2c.py for Python 3 (cclauss) [#24798](https://github.com/nodejs/node/pull/24798) +* [[`e6afaa350b`](https://github.com/nodejs/node/commit/e6afaa350b)] - **tools**: prepare tools/specialize\_node\_d.py for Python 3 (cclauss) [#24797](https://github.com/nodejs/node/pull/24797) +* [[`544a20f37c`](https://github.com/nodejs/node/commit/544a20f37c)] - **tools**: prepare tools/test.py for Python 3 (cclauss) [#24799](https://github.com/nodejs/node/pull/24799) +* [[`388ec8d77c`](https://github.com/nodejs/node/commit/388ec8d77c)] - **tools**: prepare tools/genv8constants.py for Python 3 (cclauss) [#24801](https://github.com/nodejs/node/pull/24801) +* [[`039097e276`](https://github.com/nodejs/node/commit/039097e276)] - **tools**: prepare tools/install.py for Python 3 (cclauss) [#24800](https://github.com/nodejs/node/pull/24800) +* [[`f21137976e`](https://github.com/nodejs/node/commit/f21137976e)] - **tools**: fix eslint usage for Node.js 8 and before (Ruben Bridgewater) [#24753](https://github.com/nodejs/node/pull/24753) +* [[`691e1a69ff`](https://github.com/nodejs/node/commit/691e1a69ff)] - **tools**: don't use GH API for commit message checks (Rod Vagg) [#24574](https://github.com/nodejs/node/pull/24574) +* [[`f5f1266326`](https://github.com/nodejs/node/commit/f5f1266326)] - **tools**: only sign release if promotion successful (Rod Vagg) [#24669](https://github.com/nodejs/node/pull/24669) +* [[`cc880fbeeb`](https://github.com/nodejs/node/commit/cc880fbeeb)] - **tools**: check for git tag before promoting release (Rod Vagg) [#24670](https://github.com/nodejs/node/pull/24670) +* [[`8a5b5e1fd0`](https://github.com/nodejs/node/commit/8a5b5e1fd0)] - **tools**: use print() function on both Python 2 and 3 (cclauss) [#24486](https://github.com/nodejs/node/pull/24486) +* [[`f9933ff2c8`](https://github.com/nodejs/node/commit/f9933ff2c8)] - **tools,doc**: fix version picker bug in html.js (Rich Trott) [#24638](https://github.com/nodejs/node/pull/24638) +* [[`b3932ef8e3`](https://github.com/nodejs/node/commit/b3932ef8e3)] - **url**: remove an eslint-disable comment (cjihrig) [#24995](https://github.com/nodejs/node/pull/24995) +* [[`c0423cf34c`](https://github.com/nodejs/node/commit/c0423cf34c)] - **url**: simplify native URL object construction (Timothy Gu) [#24495](https://github.com/nodejs/node/pull/24495) +* [[`d06ea3e505`](https://github.com/nodejs/node/commit/d06ea3e505)] - **url**: reuse existing context in href setter (Timothy Gu) [#24495](https://github.com/nodejs/node/pull/24495) +* [[`4e111ce050`](https://github.com/nodejs/node/commit/4e111ce050)] - ***Revert*** "**url**: make the context non-enumerable" (Timothy Gu) [#24495](https://github.com/nodejs/node/pull/24495) +* [[`7048cba388`](https://github.com/nodejs/node/commit/7048cba388)] - **url**: use SafeSet to filter known special protocols (Mike Samuel) [#24703](https://github.com/nodejs/node/pull/24703) +* [[`8d953b7d26`](https://github.com/nodejs/node/commit/8d953b7d26)] - **vm**: simplify Script constructor options validation (cjihrig) [#25054](https://github.com/nodejs/node/pull/25054) +* [[`134d1e9526`](https://github.com/nodejs/node/commit/134d1e9526)] - **vm**: add dynamic import support (Gus Caplan) [#22381](https://github.com/nodejs/node/pull/22381) +* [[`595bdc7603`](https://github.com/nodejs/node/commit/595bdc7603)] - **win, build**: skip building cctest by default (Bartosz Sosnowski) [#21408](https://github.com/nodejs/node/pull/21408) +* [[`483ff7bcc7`](https://github.com/nodejs/node/commit/483ff7bcc7)] - **worker**: drain messages from internal message port (Yael Hermon) [#24932](https://github.com/nodejs/node/pull/24932) + ## 2019-02-28, Version 10.15.2 'Dubnium' (LTS), @rvagg diff --git a/doc/guides/maintaining-npm.md b/doc/guides/maintaining-npm.md index 6017e78fded70a..67a4a9fcff6fd3 100644 --- a/doc/guides/maintaining-npm.md +++ b/doc/guides/maintaining-npm.md @@ -17,7 +17,7 @@ changes can be reviewed and landed via the normal consensus seeking process. ## Step 1: Clone npm ```console -$ git clone https://github.com/npm/npm.git +$ git clone https://github.com/npm/cli.git npm $ cd npm ``` diff --git a/doc/guides/writing-and-running-benchmarks.md b/doc/guides/writing-and-running-benchmarks.md index b6f8984afff029..693107f4c22668 100644 --- a/doc/guides/writing-and-running-benchmarks.md +++ b/doc/guides/writing-and-running-benchmarks.md @@ -444,14 +444,14 @@ function main(conf) { const http = require('http'); const len = conf.kb * 1024; const chunk = Buffer.alloc(len, 'x'); - const server = http.createServer(function(req, res) { + const server = http.createServer((req, res) => { res.end(chunk); }); - server.listen(common.PORT, function() { + server.listen(common.PORT, () => { bench.http({ connections: conf.connections, - }, function() { + }, () => { server.close(); }); }); diff --git a/doc/guides/writing-tests.md b/doc/guides/writing-tests.md index 4d0c0307bbd765..36cbe3b917db97 100644 --- a/doc/guides/writing-tests.md +++ b/doc/guides/writing-tests.md @@ -168,7 +168,7 @@ process.on('exit', function() { assert.equal(response, 1, 'http request "response" callback was not called'); }); -const server = http.createServer(function(req, res) { +const server = http.createServer((req, res) => { request++; res.end(); }).listen(0, function() { @@ -176,7 +176,7 @@ const server = http.createServer(function(req, res) { agent: null, port: this.address().port }; - http.get(options, function(res) { + http.get(options, (res) => { response++; res.resume(); server.close(); @@ -191,14 +191,14 @@ This test could be greatly simplified by using `common.mustCall` like this: const common = require('../common'); const http = require('http'); -const server = http.createServer(common.mustCall(function(req, res) { +const server = http.createServer(common.mustCall((req, res) => { res.end(); })).listen(0, function() { const options = { agent: null, port: this.address().port }; - http.get(options, common.mustCall(function(res) { + http.get(options, common.mustCall((res) => { res.resume(); server.close(); })); diff --git a/doc/node.1 b/doc/node.1 index 0c351032174476..61bd4925d54502 100644 --- a/doc/node.1 +++ b/doc/node.1 @@ -103,6 +103,12 @@ Force FIPS-compliant crypto on startup Same requirements as .Fl -enable-fips . . +.It Fl -http-parser Ns = Ns Ar library +Chooses an HTTP parser library. Available values are +.Sy llhttp +or +.Sy legacy . +. .It Fl -icu-data-dir Ns = Ns Ar file Specify ICU data load path. Overrides diff --git a/doc/onboarding.md b/doc/onboarding.md index 133680a8cfb93a..5938803e531c95 100644 --- a/doc/onboarding.md +++ b/doc/onboarding.md @@ -96,11 +96,7 @@ onboarding session. `semver-major` label * When adding a `semver-*` label, add a comment explaining why you're adding it. Do it right away so you don't forget! - * Please add the `author-ready` label for PRs where: - * the CI has been started (not necessarily finished), - * no outstanding review comments exist and - * at least two Collaborators approved the PR (one Collaborator approval is - enough if the pull request has been open for more than 7 days). + * Please add the [`author-ready`][] label for PRs, if applicable. * See [Who to CC in the issue tracker][who-to-cc]. * This will come more naturally over time @@ -245,6 +241,7 @@ needs to be pointed out separately during the onboarding. the [summit](https://github.com/nodejs/summit) repository for details. [Code of Conduct]: https://github.com/nodejs/admin/blob/master/CODE_OF_CONDUCT.md +[`author-ready`]: https://github.com/nodejs/node/blob/master/COLLABORATOR_GUIDE.md#author-ready-pull-requests [`core-validate-commit`]: https://github.com/nodejs/core-validate-commit [`git-node`]: https://github.com/nodejs/node-core-utils/blob/master/docs/git-node.md [`node-core-utils`]: https://github.com/nodejs/node-core-utils diff --git a/doc/releases.md b/doc/releases.md index ab871c0b2067ff..117edc4a780b92 100644 --- a/doc/releases.md +++ b/doc/releases.md @@ -138,7 +138,22 @@ $ git reset --hard upstream/v1.x-staging ``` If the staging branch is not up to date relative to `master`, bring the -appropriate commits into it. To determine the relevant commits, use +appropriate PRs and commits into it. + +Go through PRs with the label `vN.x`. e.g. [PRs with the `v8.x` label](https://github.com/nodejs/node/pulls?q=is%3Apr+is%3Aopen+sort%3Aupdated-desc+label%3Av8.x). + +For each PR: +- Run or check that there is a passing CI. +- Check approvals (you can approve yourself). +- Check that the commit metadata was not changed from the `master` commit. +- If there are merge conflicts, ask the PR author to rebase. +Simple conflicts can be resolved when landing. + +When landing the PR add the `Backport-PR-URL:` line to each commit. Close the +backport PR with `Landed in ...`. Update the label on the original PR from +`backport-requested-vN.x` to `backported-to-vN.x`. + +To determine the relevant commits, use [`branch-diff`](https://github.com/nodejs/branch-diff). The tool is available on npm and should be installed globally or run with `npx`. It depends on our commit metadata, as well as the GitHub labels such as `semver-minor` and @@ -152,14 +167,24 @@ For a list of commits that could be landed in a patch release on v1.x: $ branch-diff v1.x-staging master --exclude-label=semver-major,semver-minor,dont-land-on-v1.x,backport-requested-v1.x --filter-release --format=simple ``` -Carefully review the list of commits looking for errors (incorrect `PR-URL`, -incorrect semver, etc.). Commits labeled as `semver-minor` or `semver-major` -should only be cherry-picked when appropriate for the type of release being -made. Previous release commits and version bumps do not need to be +Previous release commits and version bumps do not need to be cherry-picked. -If commits were cherry-picked in this step, push to the staging branch to keep -it up-to-date. +Carefully review the list of commits: +- Checking for errors (incorrect `PR-URL`) +- Checking semver status - Commits labeled as `semver-minor` or `semver-major` +should only be cherry-picked when appropriate for the type of release being +made. +- If you think it's risky so should wait for a while, add the `baking-for-lts` + tag. + +When cherry-picking commits, if there are simple conflicts you can resolve +them. Otherwise, add the `backport-requested-vN.x` label to the original PR +and post a comment stating that it does not land cleanly and will require a +backport PR. + +If commits were cherry-picked in this step, check that the test still pass and +push to the staging branch to keep it up-to-date. ```console $ git push upstream v1.x-staging diff --git a/lib/_http_client.js b/lib/_http_client.js index 075787ba9f8f33..a70f4de918b08e 100644 --- a/lib/_http_client.js +++ b/lib/_http_client.js @@ -299,7 +299,7 @@ ClientRequest.prototype.abort = function abort() { if (this.res) { this.res._dump(); } else { - this.once('response', function(res) { + this.once('response', (res) => { res._dump(); }); } diff --git a/lib/_stream_readable.js b/lib/_stream_readable.js index 3534557ab4644a..1e041f2c2c0df9 100644 --- a/lib/_stream_readable.js +++ b/lib/_stream_readable.js @@ -563,16 +563,38 @@ function maybeReadMore(stream, state) { } function maybeReadMore_(stream, state) { - var len = state.length; + // Attempt to read more data if we should. + // + // The conditions for reading more data are (one of): + // - Not enough data buffered (state.length < state.highWaterMark). The loop + // is responsible for filling the buffer with enough data if such data + // is available. If highWaterMark is 0 and we are not in the flowing mode + // we should _not_ attempt to buffer any extra data. We'll get more data + // when the stream consumer calls read() instead. + // - No data in the buffer, and the stream is in flowing mode. In this mode + // the loop below is responsible for ensuring read() is called. Failing to + // call read here would abort the flow and there's no other mechanism for + // continuing the flow if the stream consumer has just subscribed to the + // 'data' event. + // + // In addition to the above conditions to keep reading data, the following + // conditions prevent the data from being read: + // - The stream has ended (state.ended). + // - There is already a pending 'read' operation (state.reading). This is a + // case where the the stream has called the implementation defined _read() + // method, but they are processing the call asynchronously and have _not_ + // called push() with new data. In this case we skip performing more + // read()s. The execution ends in this method again after the _read() ends + // up calling push() with more data. while (!state.reading && !state.ended && - state.length < state.highWaterMark) { + (state.length < state.highWaterMark || + (state.flowing && state.length === 0))) { + const len = state.length; debug('maybeReadMore read 0'); stream.read(0); if (len === state.length) // didn't get any data, stop spinning. break; - else - len = state.length; } state.readingMore = false; } diff --git a/lib/dns.js b/lib/dns.js index b2ae92a9d6999c..f90d7c1a57b541 100644 --- a/lib/dns.js +++ b/lib/dns.js @@ -49,8 +49,7 @@ const { const dnsException = errors.dnsException; -let promisesWarn = true; -let promises; // Lazy loaded +let promises = null; // Lazy loaded function onlookup(err, addresses) { if (err) { @@ -267,7 +266,7 @@ function defaultResolverSetServers(servers) { setDefaultResolver(resolver); bindDefaultResolver(module.exports, Resolver.prototype); - if (promises !== undefined) + if (promises !== null) bindDefaultResolver(promises, promises.Resolver.prototype); } @@ -316,10 +315,9 @@ Object.defineProperties(module.exports, { configurable: true, enumerable: false, get() { - if (promisesWarn) { + if (promises === null) { promises = require('internal/dns/promises'); promises.setServers = defaultResolverSetServers; - promisesWarn = false; process.emitWarning('The dns.promises API is experimental', 'ExperimentalWarning'); } diff --git a/lib/events.js b/lib/events.js index 5dfa34469b09af..3fce38f881b9fb 100644 --- a/lib/events.js +++ b/lib/events.js @@ -224,7 +224,7 @@ function _addListener(target, type, listener, prepend) { if (existing === undefined) { // Optimize the case of one listener. Don't need the extra array object. - existing = events[type] = listener; + events[type] = listener; ++target._eventsCount; } else { if (typeof existing === 'function') { diff --git a/lib/fs.js b/lib/fs.js index a832b8df56d89b..1eed27109465e0 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -86,12 +86,11 @@ const { validateUint32 } = require('internal/validators'); -let promisesWarn = true; let truncateWarn = true; let fs; // Lazy loaded -let promises; +let promises = null; let watchers; let ReadFileContext; @@ -137,7 +136,7 @@ function makeCallback(cb) { throw new ERR_INVALID_CALLBACK(); } - return function(...args) { + return (...args) => { return Reflect.apply(cb, undefined, args); }; } @@ -150,7 +149,7 @@ function makeStatsCallback(cb) { throw new ERR_INVALID_CALLBACK(); } - return function(err, stats) { + return (err, stats) => { if (err) return cb(err); cb(err, getStatsFromBinding(stats)); }; @@ -608,11 +607,11 @@ function truncate(path, len, callback) { validateInteger(len, 'len'); callback = maybeCallback(callback); - fs.open(path, 'r+', function(er, fd) { + fs.open(path, 'r+', (er, fd) => { if (er) return callback(er); const req = new FSReqWrap(); req.oncomplete = function oncomplete(er) { - fs.close(fd, function(er2) { + fs.close(fd, (er2) => { callback(er || er2); }); }; @@ -972,15 +971,15 @@ function fchmodSync(fd, mode) { function lchmod(path, mode, callback) { callback = maybeCallback(callback); - fs.open(path, O_WRONLY | O_SYMLINK, function(err, fd) { + fs.open(path, O_WRONLY | O_SYMLINK, (err, fd) => { if (err) { callback(err); return; } // Prefer to return the chmod error, if one occurs, // but still try to close, and report closing errors if they occur. - fs.fchmod(fd, mode, function(err) { - fs.close(fd, function(err2) { + fs.fchmod(fd, mode, (err) => { + fs.close(fd, (err2) => { callback(err || err2); }); }); @@ -1129,7 +1128,7 @@ function futimesSync(fd, atime, mtime) { function writeAll(fd, isUserFd, buffer, offset, length, position, callback) { // write(fd, buffer, offset, length, position, callback) - fs.write(fd, buffer, offset, length, position, function(writeErr, written) { + fs.write(fd, buffer, offset, length, position, (writeErr, written) => { if (writeErr) { if (isUserFd) { callback(writeErr); @@ -1165,7 +1164,7 @@ function writeFile(path, data, options, callback) { return; } - fs.open(path, flag, options.mode, function(openErr, fd) { + fs.open(path, flag, options.mode, (openErr, fd) => { if (openErr) { callback(openErr); } else { @@ -1508,7 +1507,7 @@ function realpathSync(p, options) { } -realpathSync.native = function(path, options) { +realpathSync.native = (path, options) => { options = getOptions(options, {}); path = toPathIfFileURL(path); validatePath(path); @@ -1549,7 +1548,7 @@ function realpath(p, options, callback) { // On windows, check that the root exists. On unix there is no need. if (isWindows && !knownHard[base]) { - fs.lstat(base, function(err, stats) { + fs.lstat(base, (err, stats) => { if (err) return callback(err); knownHard[base] = true; LOOP(); @@ -1613,10 +1612,10 @@ function realpath(p, options, callback) { return gotTarget(null, seenLinks[id], base); } } - fs.stat(base, function(err) { + fs.stat(base, (err) => { if (err) return callback(err); - fs.readlink(base, function(err, target) { + fs.readlink(base, (err, target) => { if (!isWindows) seenLinks[id] = target; gotTarget(err, target); }); @@ -1637,7 +1636,7 @@ function realpath(p, options, callback) { // On windows, check that the root exists. On unix there is no need. if (isWindows && !knownHard[base]) { - fs.lstat(base, function(err) { + fs.lstat(base, (err) => { if (err) return callback(err); knownHard[base] = true; LOOP(); @@ -1649,7 +1648,7 @@ function realpath(p, options, callback) { } -realpath.native = function(path, options, callback) { +realpath.native = (path, options, callback) => { callback = makeCallback(callback || options); options = getOptions(options, {}); path = toPathIfFileURL(path); @@ -1837,9 +1836,8 @@ Object.defineProperties(fs, { configurable: true, enumerable: false, get() { - if (promisesWarn) { + if (promises === null) { promises = require('internal/fs/promises'); - promisesWarn = false; process.emitWarning('The fs.promises API is experimental', 'ExperimentalWarning'); } diff --git a/lib/internal/bootstrap/cache.js b/lib/internal/bootstrap/cache.js index 41159d650bc375..03e2800c79128c 100644 --- a/lib/internal/bootstrap/cache.js +++ b/lib/internal/bootstrap/cache.js @@ -3,11 +3,9 @@ // This is only exposed for internal build steps and testing purposes. // We create new copies of the source and the code cache // so the resources eventually used to compile builtin modules -// cannot be tampered with even with --expose-internals +// cannot be tampered with even with --expose-internals. -const { - NativeModule -} = require('internal/bootstrap/loaders'); +const { NativeModule } = require('internal/bootstrap/loaders'); const { hasTracing } = process.binding('config'); function getCodeCache(id) { @@ -26,10 +24,10 @@ const depsModule = Object.keys(NativeModule._source).filter( ); // Modules with source code compiled in js2c that -// cannot be compiled with the code cache +// cannot be compiled with the code cache. const cannotUseCache = [ 'config', - 'sys', // deprecated + 'sys', // Deprecated. 'internal/v8_prof_polyfill', 'internal/v8_prof_processor', @@ -37,8 +35,7 @@ const cannotUseCache = [ 'internal/test/binding', // TODO(joyeecheung): update the C++ side so that - // the code cache is also used when compiling these - // two files. + // the code cache is also used when compiling these two files. 'internal/bootstrap/loaders', 'internal/bootstrap/node' ].concat(depsModule); @@ -46,32 +43,36 @@ const cannotUseCache = [ // Skip modules that cannot be required when they are not // built into the binary. if (process.config.variables.v8_enable_inspector !== 1) { - cannotUseCache.push('inspector'); - cannotUseCache.push('internal/util/inspector'); + cannotUseCache.push( + 'inspector', + 'internal/util/inspector', + ); } if (!hasTracing) { cannotUseCache.push('trace_events'); } if (!process.versions.openssl) { - cannotUseCache.push('crypto'); - cannotUseCache.push('https'); - cannotUseCache.push('http2'); - cannotUseCache.push('tls'); - cannotUseCache.push('_tls_common'); - cannotUseCache.push('_tls_wrap'); - cannotUseCache.push('internal/crypto/certificate'); - cannotUseCache.push('internal/crypto/cipher'); - cannotUseCache.push('internal/crypto/diffiehellman'); - cannotUseCache.push('internal/crypto/hash'); - cannotUseCache.push('internal/crypto/keygen'); - cannotUseCache.push('internal/crypto/pbkdf2'); - cannotUseCache.push('internal/crypto/random'); - cannotUseCache.push('internal/crypto/scrypt'); - cannotUseCache.push('internal/crypto/sig'); - cannotUseCache.push('internal/crypto/util'); - cannotUseCache.push('internal/http2/core'); - cannotUseCache.push('internal/http2/compat'); - cannotUseCache.push('internal/streams/lazy_transform'); + cannotUseCache.push( + 'crypto', + 'https', + 'http2', + 'tls', + '_tls_common', + '_tls_wrap', + 'internal/crypto/certificate', + 'internal/crypto/cipher', + 'internal/crypto/diffiehellman', + 'internal/crypto/hash', + 'internal/crypto/keygen', + 'internal/crypto/pbkdf2', + 'internal/crypto/random', + 'internal/crypto/scrypt', + 'internal/crypto/sig', + 'internal/crypto/util', + 'internal/http2/core', + 'internal/http2/compat', + 'internal/streams/lazy_transform', + ); } module.exports = { diff --git a/lib/internal/bootstrap/loaders.js b/lib/internal/bootstrap/loaders.js index e2cfdbf83d38ef..06aee591496440 100644 --- a/lib/internal/bootstrap/loaders.js +++ b/lib/internal/bootstrap/loaders.js @@ -115,6 +115,8 @@ }; } + // Create this WeakMap in js-land because V8 has no C++ API for WeakMap + internalBinding('module_wrap').callbackMap = new WeakMap(); const { ContextifyScript } = process.binding('contextify'); // Set up NativeModule diff --git a/lib/internal/bootstrap/node.js b/lib/internal/bootstrap/node.js index 885546c5d6f1ca..b168eb08acb7f0 100644 --- a/lib/internal/bootstrap/node.js +++ b/lib/internal/bootstrap/node.js @@ -209,7 +209,7 @@ perf.markMilestone(NODE_PERFORMANCE_MILESTONE_BOOTSTRAP_COMPLETE); - setupAllowedFlags(); + perThreadSetup.setupAllowedFlags(); // There are various modes that Node can run in. The most common two // are running from a script and running the REPL - but there are a few @@ -223,7 +223,7 @@ // To allow people to extend Node in different ways, this hook allows // one to drop a file lib/_third_party_main.js into the build // directory which will be executed instead of Node's normal loading. - process.nextTick(function() { + process.nextTick(() => { NativeModule.require('_third_party_main'); }); } else if (process.argv[1] === 'inspect' || process.argv[1] === 'debug') { @@ -234,7 +234,7 @@ } // Start the debugger agent. - process.nextTick(function() { + process.nextTick(() => { NativeModule.require('internal/deps/node-inspect/lib/_inspect').start(); }); @@ -287,14 +287,14 @@ if (process._forceRepl || NativeModule.require('tty').isatty(0)) { // REPL const cliRepl = NativeModule.require('internal/repl'); - cliRepl.createInternalRepl(process.env, function(err, repl) { + cliRepl.createInternalRepl(process.env, (err, repl) => { if (err) { throw err; } - repl.on('exit', function() { + repl.on('exit', () => { if (repl._flushing) { repl.pause(); - return repl.once('flushHistory', function() { + return repl.once('flushHistory', () => { process.exit(); }); } @@ -311,7 +311,7 @@ process.stdin.setEncoding('utf8'); let code = ''; - process.stdin.on('data', function(d) { + process.stdin.on('data', (d) => { code += d; }); @@ -434,7 +434,9 @@ function setupDOMException() { // Registers the constructor with C++. - NativeModule.require('internal/domexception'); + const DOMException = NativeModule.require('internal/domexception'); + const { registerDOMException } = internalBinding('messaging'); + registerDOMException(DOMException); } function setupInspector(originalConsole, wrappedConsole) { @@ -484,7 +486,7 @@ emitAfter } = NativeModule.require('internal/async_hooks'); - process._fatalException = function(er) { + process._fatalException = (er) => { // It's possible that defaultTriggerAsyncId was set for a constructor // call that threw and was never cleared. So clear it now. clearDefaultTriggerAsyncId(); @@ -617,128 +619,5 @@ new vm.Script(source, { displayErrors: true, filename }); } - function setupAllowedFlags() { - // This builds process.allowedNodeEnvironmentFlags - // from data in the config binding - - const replaceUnderscoresRegex = /_/g; - const leadingDashesRegex = /^--?/; - const trailingValuesRegex = /=.*$/; - - // Save references so user code does not interfere - const replace = Function.call.bind(String.prototype.replace); - const has = Function.call.bind(Set.prototype.has); - const test = Function.call.bind(RegExp.prototype.test); - - const get = () => { - const { - envSettings: { kAllowedInEnvironment } - } = internalBinding('options'); - const { options, aliases } = NativeModule.require('internal/options'); - - const allowedNodeEnvironmentFlags = []; - for (const [name, info] of options) { - if (info.envVarSettings === kAllowedInEnvironment) { - allowedNodeEnvironmentFlags.push(name); - } - } - - for (const [ from, expansion ] of aliases) { - let isAccepted = true; - for (const to of expansion) { - if (!to.startsWith('-') || to === '--') continue; - const recursiveExpansion = aliases.get(to); - if (recursiveExpansion) { - if (recursiveExpansion[0] === to) - recursiveExpansion.splice(0, 1); - expansion.push(...recursiveExpansion); - continue; - } - isAccepted = options.get(to).envVarSettings === kAllowedInEnvironment; - if (!isAccepted) break; - } - if (isAccepted) { - let canonical = from; - if (canonical.endsWith('=')) - canonical = canonical.substr(0, canonical.length - 1); - if (canonical.endsWith(' ')) - canonical = canonical.substr(0, canonical.length - 4); - allowedNodeEnvironmentFlags.push(canonical); - } - } - - const trimLeadingDashes = (flag) => replace(flag, leadingDashesRegex, ''); - - // Save these for comparison against flags provided to - // process.allowedNodeEnvironmentFlags.has() which lack leading dashes. - // Avoid interference w/ user code by flattening `Set.prototype` into - // each object. - const nodeFlags = Object.defineProperties( - new Set(allowedNodeEnvironmentFlags.map(trimLeadingDashes)), - Object.getOwnPropertyDescriptors(Set.prototype) - ); - - class NodeEnvironmentFlagsSet extends Set { - constructor(...args) { - super(...args); - - // the super constructor consumes `add`, but - // disallow any future adds. - this.add = () => this; - } - - delete() { - // noop, `Set` API compatible - return false; - } - - clear() { - // noop - } - - has(key) { - // This will return `true` based on various possible - // permutations of a flag, including present/missing leading - // dash(es) and/or underscores-for-dashes. - // Strips any values after `=`, inclusive. - // TODO(addaleax): It might be more flexible to run the option parser - // on a dummy option set and see whether it rejects the argument or - // not. - if (typeof key === 'string') { - key = replace(key, replaceUnderscoresRegex, '-'); - if (test(leadingDashesRegex, key)) { - key = replace(key, trailingValuesRegex, ''); - return has(this, key); - } - return has(nodeFlags, key); - } - return false; - } - } - - Object.freeze(NodeEnvironmentFlagsSet.prototype.constructor); - Object.freeze(NodeEnvironmentFlagsSet.prototype); - - return process.allowedNodeEnvironmentFlags = Object.freeze( - new NodeEnvironmentFlagsSet( - allowedNodeEnvironmentFlags - )); - }; - - Object.defineProperty(process, 'allowedNodeEnvironmentFlags', { - get, - set(value) { - Object.defineProperty(this, 'allowedNodeEnvironmentFlags', { - value, - configurable: true, - enumerable: true, - writable: true - }); - }, - enumerable: true, - configurable: true - }); - } - startup(); }); diff --git a/lib/internal/buffer.js b/lib/internal/buffer.js index 42f4dc3fdc07a4..9bd158b58e9340 100644 --- a/lib/internal/buffer.js +++ b/lib/internal/buffer.js @@ -25,7 +25,7 @@ float32Array[0] = -1; // 0xBF800000 const bigEndian = uInt8Float32Array[3] === 0; function checkBounds(buf, offset, byteLength) { - checkNumberType(offset); + validateNumber(offset, 'offset'); if (buf[offset] === undefined || buf[offset + byteLength] === undefined) boundsError(offset, buf.length - (byteLength + 1)); } @@ -37,13 +37,9 @@ function checkInt(value, min, max, buf, offset, byteLength) { checkBounds(buf, offset, byteLength); } -function checkNumberType(value, type) { - validateNumber(value, type || 'offset'); -} - function boundsError(value, length, type) { if (Math.floor(value) !== value) { - checkNumberType(value, type); + validateNumber(value, type); throw new ERR_OUT_OF_RANGE(type || 'offset', 'an integer', value); } @@ -74,7 +70,7 @@ function readUIntLE(offset, byteLength) { } function readUInt48LE(buf, offset = 0) { - checkNumberType(offset); + validateNumber(offset, 'offset'); const first = buf[offset]; const last = buf[offset + 5]; if (first === undefined || last === undefined) @@ -88,7 +84,7 @@ function readUInt48LE(buf, offset = 0) { } function readUInt40LE(buf, offset = 0) { - checkNumberType(offset); + validateNumber(offset, 'offset'); const first = buf[offset]; const last = buf[offset + 4]; if (first === undefined || last === undefined) @@ -102,7 +98,7 @@ function readUInt40LE(buf, offset = 0) { } function readUInt32LE(offset = 0) { - checkNumberType(offset); + validateNumber(offset, 'offset'); const first = this[offset]; const last = this[offset + 3]; if (first === undefined || last === undefined) @@ -115,7 +111,7 @@ function readUInt32LE(offset = 0) { } function readUInt24LE(buf, offset = 0) { - checkNumberType(offset); + validateNumber(offset, 'offset'); const first = buf[offset]; const last = buf[offset + 2]; if (first === undefined || last === undefined) @@ -125,7 +121,7 @@ function readUInt24LE(buf, offset = 0) { } function readUInt16LE(offset = 0) { - checkNumberType(offset); + validateNumber(offset, 'offset'); const first = this[offset]; const last = this[offset + 1]; if (first === undefined || last === undefined) @@ -135,7 +131,7 @@ function readUInt16LE(offset = 0) { } function readUInt8(offset = 0) { - checkNumberType(offset); + validateNumber(offset, 'offset'); const val = this[offset]; if (val === undefined) boundsError(offset, this.length - 1); @@ -161,7 +157,7 @@ function readUIntBE(offset, byteLength) { } function readUInt48BE(buf, offset = 0) { - checkNumberType(offset); + validateNumber(offset, 'offset'); const first = buf[offset]; const last = buf[offset + 5]; if (first === undefined || last === undefined) @@ -175,7 +171,7 @@ function readUInt48BE(buf, offset = 0) { } function readUInt40BE(buf, offset = 0) { - checkNumberType(offset); + validateNumber(offset, 'offset'); const first = buf[offset]; const last = buf[offset + 4]; if (first === undefined || last === undefined) @@ -189,7 +185,7 @@ function readUInt40BE(buf, offset = 0) { } function readUInt32BE(offset = 0) { - checkNumberType(offset); + validateNumber(offset, 'offset'); const first = this[offset]; const last = this[offset + 3]; if (first === undefined || last === undefined) @@ -202,7 +198,7 @@ function readUInt32BE(offset = 0) { } function readUInt24BE(buf, offset = 0) { - checkNumberType(offset); + validateNumber(offset, 'offset'); const first = buf[offset]; const last = buf[offset + 2]; if (first === undefined || last === undefined) @@ -212,7 +208,7 @@ function readUInt24BE(buf, offset = 0) { } function readUInt16BE(offset = 0) { - checkNumberType(offset); + validateNumber(offset, 'offset'); const first = this[offset]; const last = this[offset + 1]; if (first === undefined || last === undefined) @@ -239,7 +235,7 @@ function readIntLE(offset, byteLength) { } function readInt48LE(buf, offset = 0) { - checkNumberType(offset); + validateNumber(offset, 'offset'); const first = buf[offset]; const last = buf[offset + 5]; if (first === undefined || last === undefined) @@ -254,7 +250,7 @@ function readInt48LE(buf, offset = 0) { } function readInt40LE(buf, offset = 0) { - checkNumberType(offset); + validateNumber(offset, 'offset'); const first = buf[offset]; const last = buf[offset + 4]; if (first === undefined || last === undefined) @@ -268,7 +264,7 @@ function readInt40LE(buf, offset = 0) { } function readInt32LE(offset = 0) { - checkNumberType(offset); + validateNumber(offset, 'offset'); const first = this[offset]; const last = this[offset + 3]; if (first === undefined || last === undefined) @@ -281,7 +277,7 @@ function readInt32LE(offset = 0) { } function readInt24LE(buf, offset = 0) { - checkNumberType(offset); + validateNumber(offset, 'offset'); const first = buf[offset]; const last = buf[offset + 2]; if (first === undefined || last === undefined) @@ -292,7 +288,7 @@ function readInt24LE(buf, offset = 0) { } function readInt16LE(offset = 0) { - checkNumberType(offset); + validateNumber(offset, 'offset'); const first = this[offset]; const last = this[offset + 1]; if (first === undefined || last === undefined) @@ -303,7 +299,7 @@ function readInt16LE(offset = 0) { } function readInt8(offset = 0) { - checkNumberType(offset); + validateNumber(offset, 'offset'); const val = this[offset]; if (val === undefined) boundsError(offset, this.length - 1); @@ -329,7 +325,7 @@ function readIntBE(offset, byteLength) { } function readInt48BE(buf, offset = 0) { - checkNumberType(offset); + validateNumber(offset, 'offset'); const first = buf[offset]; const last = buf[offset + 5]; if (first === undefined || last === undefined) @@ -344,7 +340,7 @@ function readInt48BE(buf, offset = 0) { } function readInt40BE(buf, offset = 0) { - checkNumberType(offset); + validateNumber(offset, 'offset'); const first = buf[offset]; const last = buf[offset + 4]; if (first === undefined || last === undefined) @@ -358,7 +354,7 @@ function readInt40BE(buf, offset = 0) { } function readInt32BE(offset = 0) { - checkNumberType(offset); + validateNumber(offset, 'offset'); const first = this[offset]; const last = this[offset + 3]; if (first === undefined || last === undefined) @@ -371,7 +367,7 @@ function readInt32BE(offset = 0) { } function readInt24BE(buf, offset = 0) { - checkNumberType(offset); + validateNumber(offset, 'offset'); const first = buf[offset]; const last = buf[offset + 2]; if (first === undefined || last === undefined) @@ -382,7 +378,7 @@ function readInt24BE(buf, offset = 0) { } function readInt16BE(offset = 0) { - checkNumberType(offset); + validateNumber(offset, 'offset'); const first = this[offset]; const last = this[offset + 1]; if (first === undefined || last === undefined) @@ -394,7 +390,7 @@ function readInt16BE(offset = 0) { // Read floats function readFloatBackwards(offset = 0) { - checkNumberType(offset); + validateNumber(offset, 'offset'); const first = this[offset]; const last = this[offset + 3]; if (first === undefined || last === undefined) @@ -408,7 +404,7 @@ function readFloatBackwards(offset = 0) { } function readFloatForwards(offset = 0) { - checkNumberType(offset); + validateNumber(offset, 'offset'); const first = this[offset]; const last = this[offset + 3]; if (first === undefined || last === undefined) @@ -422,7 +418,7 @@ function readFloatForwards(offset = 0) { } function readDoubleBackwards(offset = 0) { - checkNumberType(offset); + validateNumber(offset, 'offset'); const first = this[offset]; const last = this[offset + 7]; if (first === undefined || last === undefined) @@ -440,7 +436,7 @@ function readDoubleBackwards(offset = 0) { } function readDoubleForwards(offset = 0) { - checkNumberType(offset); + validateNumber(offset, 'offset'); const first = this[offset]; const last = this[offset + 7]; if (first === undefined || last === undefined) @@ -554,7 +550,7 @@ function writeUInt16LE(value, offset = 0) { function writeU_Int8(buf, value, offset, min, max) { value = +value; // `checkInt()` can not be used here because it checks two entries. - checkNumberType(offset); + validateNumber(offset, 'offset'); if (value > max || value < min) { throw new ERR_OUT_OF_RANGE('value', `>= ${min} and <= ${max}`, value); } diff --git a/lib/internal/child_process.js b/lib/internal/child_process.js index 63038bcc54750f..b142237937eeff 100644 --- a/lib/internal/child_process.js +++ b/lib/internal/child_process.js @@ -62,11 +62,11 @@ const handleConversion = { 'net.Native': { simultaneousAccepts: true, - send: function(message, handle, options) { + send(message, handle, options) { return handle; }, - got: function(message, handle, emit) { + got(message, handle, emit) { emit(handle); } }, @@ -74,20 +74,20 @@ const handleConversion = { 'net.Server': { simultaneousAccepts: true, - send: function(message, server, options) { + send(message, server, options) { return server._handle; }, - got: function(message, handle, emit) { + got(message, handle, emit) { var server = new net.Server(); - server.listen(handle, function() { + server.listen(handle, () => { emit(server); }); } }, 'net.Socket': { - send: function(message, socket, options) { + send(message, socket, options) { if (!socket._handle) return; @@ -135,7 +135,7 @@ const handleConversion = { return handle; }, - postSend: function(message, handle, options, callback, target) { + postSend(message, handle, options, callback, target) { // Store the handle after successfully sending it, so it can be closed // when the NODE_HANDLE_ACK is received. If the handle could not be sent, // just close it. @@ -153,7 +153,7 @@ const handleConversion = { } }, - got: function(message, handle, emit) { + got(message, handle, emit) { var socket = new net.Socket({ handle: handle, readable: true, @@ -177,11 +177,11 @@ const handleConversion = { 'dgram.Native': { simultaneousAccepts: false, - send: function(message, handle, options) { + send(message, handle, options) { return handle; }, - got: function(message, handle, emit) { + got(message, handle, emit) { emit(handle); } }, @@ -189,16 +189,16 @@ const handleConversion = { 'dgram.Socket': { simultaneousAccepts: false, - send: function(message, socket, options) { + send(message, socket, options) { message.dgramType = socket.type; return socket[kStateSymbol].handle; }, - got: function(message, handle, emit) { + got(message, handle, emit) { var socket = new dgram.Socket(message.dgramType); - socket.bind(handle, function() { + socket.bind(handle, () => { emit(socket); }); } @@ -610,7 +610,7 @@ function setupChannel(target, channel) { } // Convert handle object - obj.got.call(this, message, handle, function(handle) { + obj.got.call(this, message, handle, (handle) => { handleMessage(message.msg, handle, isInternal(message.msg)); }); }); @@ -732,7 +732,7 @@ function setupChannel(target, channel) { } if (req.async) { - req.oncomplete = function() { + req.oncomplete = () => { control.unref(); if (typeof callback === 'function') callback(null); @@ -869,7 +869,7 @@ function _validateStdio(stdio, sync) { // Translate stdio into C++-readable form // (i.e. PipeWraps or fds) - stdio = stdio.reduce(function(acc, stdio, i) { + stdio = stdio.reduce((acc, stdio, i) => { function cleanup() { for (var i = 0; i < acc.length; i++) { if ((acc[i].type === 'pipe' || acc[i].type === 'ipc') && acc[i].handle) diff --git a/lib/internal/crypto/cipher.js b/lib/internal/crypto/cipher.js index d5f6700fa270c1..8f5549feb14ec7 100644 --- a/lib/internal/crypto/cipher.js +++ b/lib/internal/crypto/cipher.js @@ -37,7 +37,7 @@ const { deprecate, normalizeEncoding } = require('internal/util'); let StringDecoder; function rsaFunctionFor(method, defaultPadding) { - return function(options, buffer) { + return (options, buffer) => { const key = options.key || options; const padding = options.padding || defaultPadding; const passphrase = options.passphrase || null; diff --git a/lib/internal/domexception.js b/lib/internal/domexception.js index 3f9d3f36018264..9845919e498dae 100644 --- a/lib/internal/domexception.js +++ b/lib/internal/domexception.js @@ -1,6 +1,5 @@ 'use strict'; -const { registerDOMException } = internalBinding('messaging'); const { ERR_INVALID_THIS } = require('internal/errors').codes; const internalsMap = new WeakMap(); @@ -85,5 +84,3 @@ for (const [name, codeName, value] of [ } module.exports = DOMException; - -registerDOMException(DOMException); diff --git a/lib/internal/errors.js b/lib/internal/errors.js index b418fa295d2dcc..71b4a87ca0d86f 100644 --- a/lib/internal/errors.js +++ b/lib/internal/errors.js @@ -920,6 +920,8 @@ E('ERR_V8BREAKITERATOR', // This should probably be a `TypeError`. E('ERR_VALID_PERFORMANCE_ENTRY_TYPE', 'At least one valid performance entry type is required', Error); +E('ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING', + 'A dynamic import callback was not specified.', TypeError); E('ERR_VM_MODULE_ALREADY_LINKED', 'Module has already been linked', Error); E('ERR_VM_MODULE_DIFFERENT_CONTEXT', 'Linked modules must use the same context', Error); diff --git a/lib/internal/http2/compat.js b/lib/internal/http2/compat.js index 2fb96ea113eed4..188e3788345f22 100644 --- a/lib/internal/http2/compat.js +++ b/lib/internal/http2/compat.js @@ -568,16 +568,27 @@ class Http2ServerResponse extends Stream { if (this[kStream].headersSent) throw new ERR_HTTP2_HEADERS_SENT(); + // If the stream is destroyed, we return false, + // like require('http'). + if (this.stream.destroyed) + return false; + if (typeof statusMessage === 'string') statusMessageWarn(); if (headers === undefined && typeof statusMessage === 'object') headers = statusMessage; - if (typeof headers === 'object') { + var i; + if (Array.isArray(headers)) { + for (i = 0; i < headers.length; i++) { + const header = headers[i]; + this[kSetHeader](header[0], header[1]); + } + } else if (typeof headers === 'object') { const keys = Object.keys(headers); let key = ''; - for (var i = 0; i < keys.length; i++) { + for (i = 0; i < keys.length; i++) { key = keys[i]; this[kSetHeader](key, headers[key]); } diff --git a/lib/internal/http2/core.js b/lib/internal/http2/core.js index d92b956f81a6e2..de89197b4f834f 100644 --- a/lib/internal/http2/core.js +++ b/lib/internal/http2/core.js @@ -1996,6 +1996,7 @@ class Http2Stream extends Duplex { // attempt to gracefully close the session. const state = this[kState]; if (this.headersSent && + this[kSession] && this[kSession][kType] === NGHTTP2_SESSION_SERVER && !(state.flags & STREAM_FLAGS_HAS_TRAILERS) && !state.didRead && diff --git a/lib/internal/modules/cjs/helpers.js b/lib/internal/modules/cjs/helpers.js index b08e97b29c5c8d..2c856a99c6b8fd 100644 --- a/lib/internal/modules/cjs/helpers.js +++ b/lib/internal/modules/cjs/helpers.js @@ -1,6 +1,6 @@ 'use strict'; -const { ERR_INVALID_ARG_TYPE } = require('internal/errors').codes; +const { validateString } = require('internal/validators'); const { CHAR_LINE_FEED, @@ -26,18 +26,14 @@ function makeRequireFunction(mod) { } function resolve(request, options) { - if (typeof request !== 'string') { - throw new ERR_INVALID_ARG_TYPE('request', 'string', request); - } + validateString(request, 'request'); return Module._resolveFilename(request, mod, false, options); } require.resolve = resolve; function paths(request) { - if (typeof request !== 'string') { - throw new ERR_INVALID_ARG_TYPE('request', 'string', request); - } + validateString(request, 'request'); return Module._resolveLookupPaths(request, mod, true); } diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js index fb3770b7299d4e..4c3c05bcfb25c3 100644 --- a/lib/internal/modules/cjs/loader.js +++ b/lib/internal/modules/cjs/loader.js @@ -29,6 +29,7 @@ const assert = require('assert').ok; const fs = require('fs'); const internalFS = require('internal/fs/utils'); const path = require('path'); +const { URL } = require('url'); const { internalModuleReadJSON, internalModuleStat @@ -46,10 +47,10 @@ const preserveSymlinksMain = getOptionValue('--preserve-symlinks-main'); const experimentalModules = getOptionValue('--experimental-modules'); const { - ERR_INVALID_ARG_TYPE, ERR_INVALID_ARG_VALUE, ERR_REQUIRE_ESM } = require('internal/errors').codes; +const { validateString } = require('internal/validators'); module.exports = Module; @@ -602,23 +603,24 @@ Module.prototype.load = function(filename) { if (experimentalModules) { if (asyncESM === undefined) lazyLoadESM(); const ESMLoader = asyncESM.ESMLoader; - const url = pathToFileURL(filename); - const urlString = `${url}`; + const url = `${pathToFileURL(filename)}`; + const module = ESMLoader.moduleMap.get(url); + // create module entry at load time to snapshot exports correctly const exports = this.exports; - if (ESMLoader.moduleMap.has(urlString) !== true) { + if (module !== undefined) { // called from cjs translator + module.reflect.onReady((reflect) => { + reflect.exports.default.set(exports); + }); + } else { // preemptively cache ESMLoader.moduleMap.set( - urlString, + url, new ModuleJob(ESMLoader, url, async () => { - const ctx = createDynamicModule( - ['default'], url); - ctx.reflect.exports.default.set(exports); - return ctx; + return createDynamicModule( + ['default'], url, (reflect) => { + reflect.exports.default.set(exports); + }); }) ); - } else { - const job = ESMLoader.moduleMap.get(urlString); - if (job.reflect) - job.reflect.exports.default.set(exports); } } }; @@ -627,9 +629,7 @@ Module.prototype.load = function(filename) { // Loads a module at the given file path. Returns that module's // `exports` property. Module.prototype.require = function(id) { - if (typeof id !== 'string') { - throw new ERR_INVALID_ARG_TYPE('id', 'string', id); - } + validateString(id, 'id'); if (id === '') { throw new ERR_INVALID_ARG_VALUE('id', id, 'must be a non-empty string'); @@ -642,6 +642,13 @@ Module.prototype.require = function(id) { // (needed for setting breakpoint when called with --inspect-brk) var resolvedArgv; +function normalizeReferrerURL(referrer) { + if (typeof referrer === 'string' && path.isAbsolute(referrer)) { + return pathToFileURL(referrer).href; + } + return new URL(referrer).href; +} + // Run the file contents in the correct scope or sandbox. Expose // the correct helper variables (require, module, exports) to @@ -657,7 +664,12 @@ Module.prototype._compile = function(content, filename) { var compiledWrapper = vm.runInThisContext(wrapper, { filename: filename, lineOffset: 0, - displayErrors: true + displayErrors: true, + importModuleDynamically: experimentalModules ? async (specifier) => { + if (asyncESM === undefined) lazyLoadESM(); + const loader = await asyncESM.loaderPromise; + return loader.import(specifier, normalizeReferrerURL(filename)); + } : undefined, }); var inspectorWrapper = null; diff --git a/lib/internal/modules/esm/create_dynamic_module.js b/lib/internal/modules/esm/create_dynamic_module.js index 8e93a08502c3cf..8358016195f11d 100644 --- a/lib/internal/modules/esm/create_dynamic_module.js +++ b/lib/internal/modules/esm/create_dynamic_module.js @@ -1,6 +1,6 @@ 'use strict'; -const { ModuleWrap } = internalBinding('module_wrap'); +const { ModuleWrap, callbackMap } = internalBinding('module_wrap'); const debug = require('util').debuglog('esm'); const ArrayJoin = Function.call.bind(Array.prototype.join); const ArrayMap = Function.call.bind(Array.prototype.map); @@ -10,50 +10,47 @@ const createDynamicModule = (exports, url = '', evaluate) => { `creating ESM facade for ${url} with exports: ${ArrayJoin(exports, ', ')}` ); const names = ArrayMap(exports, (name) => `${name}`); - // Create two modules: One whose exports are get- and set-able ('reflective'), - // and one which re-exports all of these but additionally may - // run an executor function once everything is set up. - const src = ` - export let executor; - ${ArrayJoin(ArrayMap(names, (name) => `export let $${name};`), '\n')} - /* This function is implicitly returned as the module's completion value */ - (() => ({ - setExecutor: fn => executor = fn, - reflect: { - exports: { ${ - ArrayJoin(ArrayMap(names, (name) => ` - ${name}: { - get: () => $${name}, - set: v => $${name} = v - }`), ', \n')} - } - } - }));`; - const reflectiveModule = new ModuleWrap(src, `cjs-facade:${url}`); - reflectiveModule.instantiate(); - const { setExecutor, reflect } = reflectiveModule.evaluate(-1, false)(); - // public exposed ESM - const reexports = ` - import { - executor, - ${ArrayMap(names, (name) => `$${name}`)} - } from ""; - export { - ${ArrayJoin(ArrayMap(names, (name) => `$${name} as ${name}`), ', ')} - } - if (typeof executor === "function") { - // add await to this later if top level await comes along - executor() - }`; - if (typeof evaluate === 'function') { - setExecutor(() => evaluate(reflect)); - } - const module = new ModuleWrap(reexports, `${url}`); - module.link(async () => reflectiveModule); - module.instantiate(); - reflect.namespace = module.namespace(); + + const source = ` +${ArrayJoin(ArrayMap(names, (name) => + `let $${name}; +export { $${name} as ${name} }; +import.meta.exports.${name} = { + get: () => $${name}, + set: (v) => $${name} = v, +};`), '\n') +} + +import.meta.done(); +`; + + const m = new ModuleWrap(source, `${url}`); + m.link(() => 0); + m.instantiate(); + + const readyfns = new Set(); + const reflect = { + namespace: m.namespace(), + exports: {}, + onReady: (cb) => { readyfns.add(cb); }, + }; + + callbackMap.set(m, { + initializeImportMeta: (meta, wrap) => { + meta.exports = reflect.exports; + meta.done = () => { + evaluate(reflect); + reflect.onReady = (cb) => cb(reflect); + for (const fn of readyfns) { + readyfns.delete(fn); + fn(reflect); + } + }; + }, + }); + return { - module, + module: m, reflect, }; }; diff --git a/lib/internal/modules/esm/loader.js b/lib/internal/modules/esm/loader.js index 60f1e31f94e86e..820b593446ca79 100644 --- a/lib/internal/modules/esm/loader.js +++ b/lib/internal/modules/esm/loader.js @@ -1,7 +1,6 @@ 'use strict'; const { - ERR_INVALID_ARG_TYPE, ERR_INVALID_RETURN_PROPERTY, ERR_INVALID_RETURN_PROPERTY_VALUE, ERR_INVALID_RETURN_VALUE, @@ -9,6 +8,7 @@ const { ERR_UNKNOWN_MODULE_FORMAT } = require('internal/errors').codes; const { URL } = require('url'); +const { validateString } = require('internal/validators'); const ModuleMap = require('internal/modules/esm/module_map'); const ModuleJob = require('internal/modules/esm/module_job'); const defaultResolve = require('internal/modules/esm/default_resolve'); @@ -52,8 +52,8 @@ class Loader { async resolve(specifier, parentURL) { const isMain = parentURL === undefined; - if (!isMain && typeof parentURL !== 'string') - throw new ERR_INVALID_ARG_TYPE('parentURL', 'string', parentURL); + if (!isMain) + validateString(parentURL, 'parentURL'); const resolved = await this._resolve(specifier, parentURL, defaultResolve); diff --git a/lib/internal/modules/esm/module_map.js b/lib/internal/modules/esm/module_map.js index f4786f8e9ef0be..a9d0c23c0e5ee9 100644 --- a/lib/internal/modules/esm/module_map.js +++ b/lib/internal/modules/esm/module_map.js @@ -4,19 +4,16 @@ const ModuleJob = require('internal/modules/esm/module_job'); const { SafeMap } = require('internal/safe_globals'); const debug = require('util').debuglog('esm'); const { ERR_INVALID_ARG_TYPE } = require('internal/errors').codes; +const { validateString } = require('internal/validators'); // Tracks the state of the loader-level module cache class ModuleMap extends SafeMap { get(url) { - if (typeof url !== 'string') { - throw new ERR_INVALID_ARG_TYPE('url', 'string', url); - } + validateString(url, 'url'); return super.get(url); } set(url, job) { - if (typeof url !== 'string') { - throw new ERR_INVALID_ARG_TYPE('url', 'string', url); - } + validateString(url, 'url'); if (job instanceof ModuleJob !== true) { throw new ERR_INVALID_ARG_TYPE('job', 'ModuleJob', job); } @@ -24,9 +21,7 @@ class ModuleMap extends SafeMap { return super.set(url, job); } has(url) { - if (typeof url !== 'string') { - throw new ERR_INVALID_ARG_TYPE('url', 'string', url); - } + validateString(url, 'url'); return super.has(url); } } diff --git a/lib/internal/modules/esm/translators.js b/lib/internal/modules/esm/translators.js index df3c446cab7ce7..0d19a728aa788b 100644 --- a/lib/internal/modules/esm/translators.js +++ b/lib/internal/modules/esm/translators.js @@ -1,7 +1,7 @@ 'use strict'; const { NativeModule } = require('internal/bootstrap/loaders'); -const { ModuleWrap } = internalBinding('module_wrap'); +const { ModuleWrap, callbackMap } = internalBinding('module_wrap'); const { stripShebang, stripBOM @@ -15,6 +15,8 @@ const { _makeLong } = require('path'); const { SafeMap } = require('internal/safe_globals'); const { URL } = require('url'); const { debuglog, promisify } = require('util'); +const esmLoader = require('internal/process/esm_loader'); + const readFileAsync = promisify(fs.readFile); const readFileSync = fs.readFileSync; const StringReplace = Function.call.bind(String.prototype.replace); @@ -25,13 +27,27 @@ const debug = debuglog('esm'); const translators = new SafeMap(); module.exports = translators; +function initializeImportMeta(meta, { url }) { + meta.url = url; +} + +async function importModuleDynamically(specifier, { url }) { + const loader = await esmLoader.loaderPromise; + return loader.import(specifier, url); +} + // Strategy for loading a standard JavaScript module translators.set('esm', async (url) => { const source = `${await readFileAsync(new URL(url))}`; debug(`Translating StandardModule ${url}`); + const module = new ModuleWrap(stripShebang(source), url); + callbackMap.set(module, { + initializeImportMeta, + importModuleDynamically, + }); return { - module: new ModuleWrap(stripShebang(source), url), - reflect: undefined + module, + reflect: undefined, }; }); @@ -44,9 +60,10 @@ translators.set('cjs', async (url, isMain) => { const module = CJSModule._cache[ isWindows ? StringReplace(pathname, winSepRegEx, '\\') : pathname]; if (module && module.loaded) { - const ctx = createDynamicModule(['default'], url); - ctx.reflect.exports.default.set(module.exports); - return ctx; + const exports = module.exports; + return createDynamicModule(['default'], url, (reflect) => { + reflect.exports.default.set(exports); + }); } return createDynamicModule(['default'], url, () => { debug(`Loading CJSModule ${url}`); diff --git a/lib/internal/print_help.js b/lib/internal/print_help.js index c1baa643e70db2..6e904a6b18633d 100644 --- a/lib/internal/print_help.js +++ b/lib/internal/print_help.js @@ -1,6 +1,7 @@ 'use strict'; const { types } = internalBinding('options'); +const hasCrypto = Boolean(process.versions.openssl); const typeLookup = []; for (const key of Object.keys(types)) @@ -33,11 +34,6 @@ const envVars = new Map([ 'certificate validation' }], ['NODE_V8_COVERAGE', { helpText: 'directory to output v8 coverage JSON ' + 'to' }], - ['OPENSSL_CONF', { helpText: 'load OpenSSL configuration from file' }], - ['SSL_CERT_DIR', { helpText: 'sets OpenSSL\'s directory of trusted ' + - 'certificates when used in conjunction with --use-openssl-ca' }], - ['SSL_CERT_FILE', { helpText: 'sets OpenSSL\'s trusted certificate file ' + - 'when used in conjunction with --use-openssl-ca' }], ['UV_THREADPOOL_SIZE', { helpText: 'sets the number of threads used in ' + 'libuv\'s threadpool' }] ].concat(hasIntl ? [ @@ -46,6 +42,12 @@ const envVars = new Map([ ] : []).concat(hasNodeOptions ? [ ['NODE_OPTIONS', { helpText: 'set CLI options in the environment via a ' + 'space-separated list' }] +] : []).concat(hasCrypto ? [ + ['OPENSSL_CONF', { helpText: 'load OpenSSL configuration from file' }], + ['SSL_CERT_DIR', { helpText: 'sets OpenSSL\'s directory of trusted ' + + 'certificates when used in conjunction with --use-openssl-ca' }], + ['SSL_CERT_FILE', { helpText: 'sets OpenSSL\'s trusted certificate file ' + + 'when used in conjunction with --use-openssl-ca' }], ] : [])); diff --git a/lib/internal/process/esm_loader.js b/lib/internal/process/esm_loader.js index be08a6364781ed..f81053a1c3c3ad 100644 --- a/lib/internal/process/esm_loader.js +++ b/lib/internal/process/esm_loader.js @@ -2,40 +2,42 @@ const { setImportModuleDynamicallyCallback, - setInitializeImportMetaObjectCallback + setInitializeImportMetaObjectCallback, + callbackMap, } = internalBinding('module_wrap'); const { pathToFileURL } = require('internal/url'); const Loader = require('internal/modules/esm/loader'); -const path = require('path'); -const { URL } = require('url'); const { - initImportMetaMap, - wrapToModuleMap + wrapToModuleMap, } = require('internal/vm/source_text_module'); +const { + ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING, +} = require('internal/errors').codes; -function normalizeReferrerURL(referrer) { - if (typeof referrer === 'string' && path.isAbsolute(referrer)) { - return pathToFileURL(referrer).href; +function initializeImportMetaObject(wrap, meta) { + if (callbackMap.has(wrap)) { + const { initializeImportMeta } = callbackMap.get(wrap); + if (initializeImportMeta !== undefined) { + initializeImportMeta(meta, wrapToModuleMap.get(wrap) || wrap); + } } - return new URL(referrer).href; } -function initializeImportMetaObject(wrap, meta) { - const vmModule = wrapToModuleMap.get(wrap); - if (vmModule === undefined) { - // This ModuleWrap belongs to the Loader. - meta.url = wrap.url; - } else { - const initializeImportMeta = initImportMetaMap.get(vmModule); - if (initializeImportMeta !== undefined) { - // This ModuleWrap belongs to vm.SourceTextModule, - // initializer callback was provided. - initializeImportMeta(meta, vmModule); +async function importModuleDynamicallyCallback(wrap, specifier) { + if (callbackMap.has(wrap)) { + const { importModuleDynamically } = callbackMap.get(wrap); + if (importModuleDynamically !== undefined) { + return importModuleDynamically( + specifier, wrapToModuleMap.get(wrap) || wrap); } } + throw new ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING(); } +setInitializeImportMetaObjectCallback(initializeImportMetaObject); +setImportModuleDynamicallyCallback(importModuleDynamicallyCallback); + let loaderResolve; exports.loaderPromise = new Promise((resolve, reject) => { loaderResolve = resolve; @@ -44,8 +46,6 @@ exports.loaderPromise = new Promise((resolve, reject) => { exports.ESMLoader = undefined; exports.setup = function() { - setInitializeImportMetaObjectCallback(initializeImportMetaObject); - let ESMLoader = new Loader(); const loaderPromise = (async () => { const userLoader = require('internal/options').getOptionValue('--loader'); @@ -60,10 +60,5 @@ exports.setup = function() { })(); loaderResolve(loaderPromise); - setImportModuleDynamicallyCallback(async (referrer, specifier) => { - const loader = await loaderPromise; - return loader.import(specifier, normalizeReferrerURL(referrer)); - }); - exports.ESMLoader = ESMLoader; }; diff --git a/lib/internal/process/main_thread_only.js b/lib/internal/process/main_thread_only.js index 814cca266d6675..6fb238df72e5c1 100644 --- a/lib/internal/process/main_thread_only.js +++ b/lib/internal/process/main_thread_only.js @@ -102,6 +102,13 @@ function setupSignalHandlers() { delete signalWraps[type]; } }); + + // re-arm pre-existing signal event registrations + // with this signal wrap capabilities. + process.eventNames().forEach((ev) => { + if (isSignal(ev)) + process.emit('newListener', ev); + }); } function setupChildProcessIpcChannel() { diff --git a/lib/internal/process/per_thread.js b/lib/internal/process/per_thread.js index 3842582da6c8d0..b196e4270f69b7 100644 --- a/lib/internal/process/per_thread.js +++ b/lib/internal/process/per_thread.js @@ -85,7 +85,7 @@ function setupCpuUsage(_cpuUsage) { // Ensure that a previously passed in value is valid. Currently, the native // implementation always returns numbers <= Number.MAX_SAFE_INTEGER. function previousValueIsValid(num) { - return Number.isFinite(num) && + return typeof num === 'number' && num <= Number.MAX_SAFE_INTEGER && num >= 0; } @@ -234,7 +234,132 @@ function setupUncaughtExceptionCapture(exceptionHandlerState, }; } +const replaceUnderscoresRegex = /_/g; +const leadingDashesRegex = /^--?/; +const trailingValuesRegex = /=.*$/; + +// Save references so user code does not interfere +const replace = Function.call.bind(String.prototype.replace); +const has = Function.call.bind(Set.prototype.has); +const test = Function.call.bind(RegExp.prototype.test); + +// This builds the initial process.allowedNodeEnvironmentFlags +// from data in the config binding. +function buildAllowedFlags() { + const { + envSettings: { kAllowedInEnvironment } + } = internalBinding('options'); + const { options, aliases } = require('internal/options'); + + const allowedNodeEnvironmentFlags = []; + for (const [name, info] of options) { + if (info.envVarSettings === kAllowedInEnvironment) { + allowedNodeEnvironmentFlags.push(name); + } + } + + for (const [ from, expansion ] of aliases) { + let isAccepted = true; + for (const to of expansion) { + if (!to.startsWith('-') || to === '--') continue; + const recursiveExpansion = aliases.get(to); + if (recursiveExpansion) { + if (recursiveExpansion[0] === to) + recursiveExpansion.splice(0, 1); + expansion.push(...recursiveExpansion); + continue; + } + isAccepted = options.get(to).envVarSettings === kAllowedInEnvironment; + if (!isAccepted) break; + } + if (isAccepted) { + let canonical = from; + if (canonical.endsWith('=')) + canonical = canonical.substr(0, canonical.length - 1); + if (canonical.endsWith(' ')) + canonical = canonical.substr(0, canonical.length - 4); + allowedNodeEnvironmentFlags.push(canonical); + } + } + + const trimLeadingDashes = (flag) => replace(flag, leadingDashesRegex, ''); + + // Save these for comparison against flags provided to + // process.allowedNodeEnvironmentFlags.has() which lack leading dashes. + // Avoid interference w/ user code by flattening `Set.prototype` into + // each object. + const nodeFlags = Object.defineProperties( + new Set(allowedNodeEnvironmentFlags.map(trimLeadingDashes)), + Object.getOwnPropertyDescriptors(Set.prototype) + ); + + class NodeEnvironmentFlagsSet extends Set { + constructor(...args) { + super(...args); + + // the super constructor consumes `add`, but + // disallow any future adds. + this.add = () => this; + } + + delete() { + // noop, `Set` API compatible + return false; + } + + clear() { + // noop + } + + has(key) { + // This will return `true` based on various possible + // permutations of a flag, including present/missing leading + // dash(es) and/or underscores-for-dashes. + // Strips any values after `=`, inclusive. + // TODO(addaleax): It might be more flexible to run the option parser + // on a dummy option set and see whether it rejects the argument or + // not. + if (typeof key === 'string') { + key = replace(key, replaceUnderscoresRegex, '-'); + if (test(leadingDashesRegex, key)) { + key = replace(key, trailingValuesRegex, ''); + return has(this, key); + } + return has(nodeFlags, key); + } + return false; + } + } + + Object.freeze(NodeEnvironmentFlagsSet.prototype.constructor); + Object.freeze(NodeEnvironmentFlagsSet.prototype); + + return process.allowedNodeEnvironmentFlags = Object.freeze( + new NodeEnvironmentFlagsSet( + allowedNodeEnvironmentFlags + )); +} + +function setupAllowedFlags() { + Object.defineProperty(process, 'allowedNodeEnvironmentFlags', { + get: buildAllowedFlags, + set(value) { + // If the user tries to set this to another value, override + // this completely to that value. + Object.defineProperty(this, 'allowedNodeEnvironmentFlags', { + value, + configurable: true, + enumerable: true, + writable: true + }); + }, + enumerable: true, + configurable: true + }); +} + module.exports = { + setupAllowedFlags, setupAssert, setupCpuUsage, setupHrtime, diff --git a/lib/internal/process/promises.js b/lib/internal/process/promises.js index d70deb516025fe..31c96293b341b9 100644 --- a/lib/internal/process/promises.js +++ b/lib/internal/process/promises.js @@ -108,7 +108,7 @@ function emitPromiseRejectionWarnings() { } } - let hadListeners = false; + let maybeScheduledTicks = false; let len = pendingUnhandledRejections.length; while (len--) { const promise = pendingUnhandledRejections.shift(); @@ -118,10 +118,9 @@ function emitPromiseRejectionWarnings() { const { reason, uid } = promiseInfo; if (!process.emit('unhandledRejection', reason, promise)) { emitWarning(uid, reason); - } else { - hadListeners = true; } + maybeScheduledTicks = true; } } - return hadListeners || pendingUnhandledRejections.length !== 0; + return maybeScheduledTicks || pendingUnhandledRejections.length !== 0; } diff --git a/lib/internal/process/warning.js b/lib/internal/process/warning.js index e367cf1f58bd9d..9fabd0687a1a07 100644 --- a/lib/internal/process/warning.js +++ b/lib/internal/process/warning.js @@ -20,14 +20,16 @@ function writeOut(message) { } function onClose(fd) { - return function() { + return () => { if (fs === null) fs = require('fs'); - fs.close(fd, nop); + try { + fs.closeSync(fd); + } catch {} }; } function onOpen(cb) { - return function(err, fd) { + return (err, fd) => { acquiringFd = false; if (fd !== undefined) { cachedFd = fd; @@ -41,7 +43,7 @@ function onOpen(cb) { function onAcquired(message) { // make a best effort attempt at writing the message // to the fd. Errors are ignored at this point. - return function(err, fd) { + return (err, fd) => { if (err) return writeOut(message); if (fs === null) fs = require('fs'); @@ -70,7 +72,7 @@ function output(message) { } function doEmitWarning(warning) { - return function() { + return () => { process.emit('warning', warning); }; } @@ -104,7 +106,7 @@ function setupProcessWarnings() { // process.emitWarning(error) // process.emitWarning(str[, type[, code]][, ctor]) // process.emitWarning(str[, options]) - process.emitWarning = function(warning, type, code, ctor, now) { + process.emitWarning = (warning, type, code, ctor, now) => { var detail; if (type !== null && typeof type === 'object' && !Array.isArray(type)) { ctor = type.ctor; diff --git a/lib/internal/readline.js b/lib/internal/readline.js index 45125db0c223ef..3974ff4468bf54 100644 --- a/lib/internal/readline.js +++ b/lib/internal/readline.js @@ -258,7 +258,7 @@ function* emitKeys(stream) { s += (ch = yield); if (ch >= '0' && ch <= '9') { - s += (ch = yield); + s += yield; } } diff --git a/lib/internal/safe_globals.js b/lib/internal/safe_globals.js index ad58fa662b53ef..31de4137f0ad53 100644 --- a/lib/internal/safe_globals.js +++ b/lib/internal/safe_globals.js @@ -1,9 +1,7 @@ 'use strict'; const copyProps = (unsafe, safe) => { - for (const key of [...Object.getOwnPropertyNames(unsafe), - ...Object.getOwnPropertySymbols(unsafe) - ]) { + for (const key of Reflect.ownKeys(unsafe)) { if (!Object.getOwnPropertyDescriptor(safe, key)) { Object.defineProperty( safe, diff --git a/lib/internal/socket_list.js b/lib/internal/socket_list.js index d12686e1de107d..8cd7b1e0ed9057 100644 --- a/lib/internal/socket_list.js +++ b/lib/internal/socket_list.js @@ -47,7 +47,7 @@ class SocketListSend extends EventEmitter { this._request({ cmd: 'NODE_SOCKET_GET_COUNT', key: this.key - }, 'NODE_SOCKET_COUNT', false, function(err, msg) { + }, 'NODE_SOCKET_COUNT', false, (err, msg) => { if (err) return callback(err); callback(null, msg.count); }); diff --git a/lib/internal/streams/async_iterator.js b/lib/internal/streams/async_iterator.js index 90960f5a3842e3..cc8e218498f995 100644 --- a/lib/internal/streams/async_iterator.js +++ b/lib/internal/streams/async_iterator.js @@ -37,8 +37,13 @@ function onReadable(iter) { } function wrapForNext(lastPromise, iter) { - return function(resolve, reject) { - lastPromise.then(function() { + return (resolve, reject) => { + lastPromise.then(() => { + if (iter[kEnded]) { + resolve(createIterResult(undefined, true)); + return; + } + iter[kHandlePromise](resolve, reject); }, reject); }; @@ -61,7 +66,7 @@ const ReadableStreamAsyncIteratorPrototype = Object.setPrototypeOf({ } if (this[kEnded]) { - return Promise.resolve(createIterResult(null, true)); + return Promise.resolve(createIterResult(undefined, true)); } if (this[kStream].destroyed) { @@ -74,7 +79,7 @@ const ReadableStreamAsyncIteratorPrototype = Object.setPrototypeOf({ if (this[kError]) { reject(this[kError]); } else { - resolve(createIterResult(null, true)); + resolve(createIterResult(undefined, true)); } }); }); @@ -115,7 +120,7 @@ const ReadableStreamAsyncIteratorPrototype = Object.setPrototypeOf({ reject(err); return; } - resolve(createIterResult(null, true)); + resolve(createIterResult(undefined, true)); }); }); }, @@ -131,7 +136,6 @@ const createReadableStreamAsyncIterator = (stream) => { value: stream._readableState.endEmitted, writable: true }, - [kLastPromise]: { value: null, writable: true }, // the function passed to new Promise // is cached so we avoid allocating a new // closure at every run @@ -151,6 +155,7 @@ const createReadableStreamAsyncIterator = (stream) => { writable: true, }, }); + iterator[kLastPromise] = null; finished(stream, (err) => { if (err && err.code !== 'ERR_STREAM_PREMATURE_CLOSE') { @@ -172,7 +177,7 @@ const createReadableStreamAsyncIterator = (stream) => { iterator[kLastPromise] = null; iterator[kLastResolve] = null; iterator[kLastReject] = null; - resolve(createIterResult(null, true)); + resolve(createIterResult(undefined, true)); } iterator[kEnded] = true; }); diff --git a/lib/internal/streams/end-of-stream.js b/lib/internal/streams/end-of-stream.js index eeb8a61456a730..47c20bf363eecd 100644 --- a/lib/internal/streams/end-of-stream.js +++ b/lib/internal/streams/end-of-stream.js @@ -6,6 +6,7 @@ const { ERR_STREAM_PREMATURE_CLOSE } = require('internal/errors').codes; +const { once } = require('internal/util'); function noop() {} @@ -13,23 +14,12 @@ function isRequest(stream) { return stream.setHeader && typeof stream.abort === 'function'; } -function once(callback) { - let called = false; - return function(err) { - if (called) return; - called = true; - callback.call(this, err); - }; -} - function eos(stream, opts, callback) { if (typeof opts === 'function') return eos(stream, null, opts); if (!opts) opts = {}; callback = once(callback || noop); - const ws = stream._writableState; - const rs = stream._readableState; let readable = opts.readable || (opts.readable !== false && stream.readable); let writable = opts.writable || (opts.writable !== false && stream.writable); @@ -37,13 +27,17 @@ function eos(stream, opts, callback) { if (!stream.writable) onfinish(); }; + var writableEnded = stream._writableState && stream._writableState.finished; const onfinish = () => { writable = false; + writableEnded = true; if (!readable) callback.call(stream); }; + var readableEnded = stream._readableState && stream._readableState.endEmitted; const onend = () => { readable = false; + readableEnded = true; if (!writable) callback.call(stream); }; @@ -52,11 +46,16 @@ function eos(stream, opts, callback) { }; const onclose = () => { - if (readable && !(rs && rs.ended)) { - return callback.call(stream, new ERR_STREAM_PREMATURE_CLOSE()); + let err; + if (readable && !readableEnded) { + if (!stream._readableState || !stream._readableState.ended) + err = new ERR_STREAM_PREMATURE_CLOSE(); + return callback.call(stream, err); } - if (writable && !(ws && ws.ended)) { - return callback.call(stream, new ERR_STREAM_PREMATURE_CLOSE()); + if (writable && !writableEnded) { + if (!stream._writableState || !stream._writableState.ended) + err = new ERR_STREAM_PREMATURE_CLOSE(); + return callback.call(stream, err); } }; @@ -69,7 +68,7 @@ function eos(stream, opts, callback) { stream.on('abort', onclose); if (stream.req) onrequest(); else stream.on('request', onrequest); - } else if (writable && !ws) { // legacy streams + } else if (writable && !stream._writableState) { // legacy streams stream.on('end', onlegacyfinish); stream.on('close', onlegacyfinish); } diff --git a/lib/internal/url.js b/lib/internal/url.js index 8d14a26ecb3617..d61901979c89c9 100644 --- a/lib/internal/url.js +++ b/lib/internal/url.js @@ -43,7 +43,7 @@ const { domainToUnicode: _domainToUnicode, encodeAuth, toUSVString: _toUSVString, - parse: _parse, + parse, setURLConstructor, URL_FLAGS_CANNOT_BE_BASE, URL_FLAGS_HAS_FRAGMENT, @@ -243,21 +243,6 @@ function onParseError(flags, input) { throw error; } -// Reused by URL constructor and URL#href setter. -function parse(url, input, base) { - const base_context = base ? base[context] : undefined; - // In the URL#href setter - if (!url[context]) { - Object.defineProperty(url, context, { - enumerable: false, - configurable: false, - value: new URLContext() - }); - } - _parse(input.trim(), -1, base_context, undefined, - onParseComplete.bind(url), onParseError); -} - function onParseProtocolComplete(flags, protocol, username, password, host, port, path, query, fragment) { const ctx = this[context]; @@ -326,10 +311,13 @@ class URL { constructor(input, base) { // toUSVString is not needed. input = `${input}`; + let base_context; if (base !== undefined) { - base = new URL(base); + base_context = new URL(base)[context]; } - parse(this, input, base); + this[context] = new URLContext(); + parse(input, -1, base_context, undefined, onParseComplete.bind(this), + onParseError); } get [special]() { @@ -452,7 +440,8 @@ Object.defineProperties(URL.prototype, { set(input) { // toUSVString is not needed. input = `${input}`; - parse(this, input); + parse(input, -1, undefined, undefined, onParseComplete.bind(this), + onParseError); } }, origin: { // readonly @@ -498,8 +487,8 @@ Object.defineProperties(URL.prototype, { (ctx.host === '' || ctx.host === null)) { return; } - _parse(scheme, kSchemeStart, null, ctx, - onParseProtocolComplete.bind(this)); + parse(scheme, kSchemeStart, null, ctx, + onParseProtocolComplete.bind(this)); } }, username: { @@ -562,7 +551,7 @@ Object.defineProperties(URL.prototype, { // Cannot set the host if cannot-be-base is set return; } - _parse(host, kHost, null, ctx, onParseHostComplete.bind(this)); + parse(host, kHost, null, ctx, onParseHostComplete.bind(this)); } }, hostname: { @@ -579,7 +568,7 @@ Object.defineProperties(URL.prototype, { // Cannot set the host if cannot-be-base is set return; } - _parse(host, kHostname, null, ctx, onParseHostnameComplete.bind(this)); + parse(host, kHostname, null, ctx, onParseHostnameComplete.bind(this)); } }, port: { @@ -599,7 +588,7 @@ Object.defineProperties(URL.prototype, { ctx.port = null; return; } - _parse(port, kPort, null, ctx, onParsePortComplete.bind(this)); + parse(port, kPort, null, ctx, onParsePortComplete.bind(this)); } }, pathname: { @@ -618,8 +607,8 @@ Object.defineProperties(URL.prototype, { path = `${path}`; if (this[cannotBeBase]) return; - _parse(path, kPathStart, null, this[context], - onParsePathComplete.bind(this)); + parse(path, kPathStart, null, this[context], + onParsePathComplete.bind(this)); } }, search: { @@ -642,7 +631,7 @@ Object.defineProperties(URL.prototype, { ctx.query = ''; ctx.flags |= URL_FLAGS_HAS_QUERY; if (search) { - _parse(search, kQuery, null, ctx, onParseSearchComplete.bind(this)); + parse(search, kQuery, null, ctx, onParseSearchComplete.bind(this)); } } initSearchParams(this[searchParams], search); @@ -676,7 +665,7 @@ Object.defineProperties(URL.prototype, { if (hash[0] === '#') hash = hash.slice(1); ctx.fragment = ''; ctx.flags |= URL_FLAGS_HAS_FRAGMENT; - _parse(hash, kFragment, null, ctx, onParseHashComplete.bind(this)); + parse(hash, kFragment, null, ctx, onParseHashComplete.bind(this)); } }, toJSON: { @@ -782,8 +771,7 @@ function parseParams(qs) { if (code === CHAR_PERCENT) { encodeCheck = 1; } else if (encodeCheck > 0) { - // eslint-disable-next-line no-extra-boolean-cast - if (!!isHexTable[code]) { + if (isHexTable[code] === 1) { if (++encodeCheck === 3) { querystring = require('querystring'); encoded = true; @@ -1380,15 +1368,6 @@ function toPathIfFileURL(fileURLOrPath) { return fileURLToPath(fileURLOrPath); } -function NativeURL(ctx) { - Object.defineProperty(this, context, { - enumerable: false, - configurable: false, - value: ctx - }); -} -NativeURL.prototype = URL.prototype; - function constructUrl(flags, protocol, username, password, host, port, path, query, fragment) { var ctx = new URLContext(); @@ -1401,10 +1380,13 @@ function constructUrl(flags, protocol, username, password, ctx.query = query; ctx.fragment = fragment; ctx.host = host; - const url = new NativeURL(ctx); - url[searchParams] = new URLSearchParams(); - url[searchParams][context] = url; - initSearchParams(url[searchParams], query); + + const url = Object.create(URL.prototype); + url[context] = ctx; + const params = new URLSearchParams(); + url[searchParams] = params; + params[context] = url; + initSearchParams(params, query); return url; } setURLConstructor(constructUrl); diff --git a/lib/internal/util.js b/lib/internal/util.js index 76c4b93eb854f6..b5e3bc7d74c70c 100644 --- a/lib/internal/util.js +++ b/lib/internal/util.js @@ -368,7 +368,7 @@ function once(callback) { return function(...args) { if (called) return; called = true; - callback(...args); + callback.apply(this, args); }; } diff --git a/lib/internal/util/comparisons.js b/lib/internal/util/comparisons.js index 205d84f4840886..fc92579cebf3d4 100644 --- a/lib/internal/util/comparisons.js +++ b/lib/internal/util/comparisons.js @@ -401,9 +401,7 @@ function mapMightHaveLoosePrim(a, b, prim, item, memo) { !innerDeepEqual(item, curB, false, memo)) { return false; } - const curA = a.get(altValue); - return curA === undefined && a.has(altValue) || - innerDeepEqual(item, curA, false, memo); + return !a.has(altValue) && innerDeepEqual(item, curB, false, memo); } function setEquiv(a, b, strict, memo) { @@ -545,11 +543,10 @@ function objEquiv(a, b, strict, keys, memos, iterationType) { } else { // Array is sparse. const keysA = objectKeys(a); - i++; for (; i < keysA.length; i++) { const key = keysA[i]; if (!hasOwnProperty(b, key) || - !innerDeepEqual(a[key], b[i], strict, memos)) { + !innerDeepEqual(a[key], b[key], strict, memos)) { return false; } } diff --git a/lib/internal/v8_prof_processor.js b/lib/internal/v8_prof_processor.js index 6c7a4db6641935..e252b683e30157 100644 --- a/lib/internal/v8_prof_processor.js +++ b/lib/internal/v8_prof_processor.js @@ -18,7 +18,8 @@ const scriptFiles = [ ]; var script = ''; -scriptFiles.forEach(function(s) { + +scriptFiles.forEach((s) => { script += process.binding('natives')[s] + '\n'; }); diff --git a/lib/internal/vm/source_text_module.js b/lib/internal/vm/source_text_module.js index 915289a0591373..1898831bf6f238 100644 --- a/lib/internal/vm/source_text_module.js +++ b/lib/internal/vm/source_text_module.js @@ -1,5 +1,6 @@ 'use strict'; +const { isModuleNamespaceObject } = require('util').types; const { URL } = require('internal/url'); const { isContext } = process.binding('contextify'); const { @@ -10,7 +11,7 @@ const { ERR_VM_MODULE_LINKING_ERRORED, ERR_VM_MODULE_NOT_LINKED, ERR_VM_MODULE_NOT_MODULE, - ERR_VM_MODULE_STATUS + ERR_VM_MODULE_STATUS, } = require('internal/errors').codes; const { getConstructorOf, @@ -21,6 +22,7 @@ const { SafePromise } = require('internal/safe_globals'); const { ModuleWrap, + callbackMap, kUninstantiated, kInstantiating, kInstantiated, @@ -43,8 +45,6 @@ const perContextModuleId = new WeakMap(); const wrapMap = new WeakMap(); const dependencyCacheMap = new WeakMap(); const linkingStatusMap = new WeakMap(); -// vm.SourceTextModule -> function -const initImportMetaMap = new WeakMap(); // ModuleWrap -> vm.SourceTextModule const wrapToModuleMap = new WeakMap(); const defaultModuleName = 'vm:module'; @@ -63,7 +63,8 @@ class SourceTextModule { context, lineOffset = 0, columnOffset = 0, - initializeImportMeta + initializeImportMeta, + importModuleDynamically, } = options; if (context !== undefined) { @@ -96,13 +97,16 @@ class SourceTextModule { validateInteger(lineOffset, 'options.lineOffset'); validateInteger(columnOffset, 'options.columnOffset'); - if (initializeImportMeta !== undefined) { - if (typeof initializeImportMeta === 'function') { - initImportMetaMap.set(this, initializeImportMeta); - } else { - throw new ERR_INVALID_ARG_TYPE( - 'options.initializeImportMeta', 'function', initializeImportMeta); - } + if (initializeImportMeta !== undefined && + typeof initializeImportMeta !== 'function') { + throw new ERR_INVALID_ARG_TYPE( + 'options.initializeImportMeta', 'function', initializeImportMeta); + } + + if (importModuleDynamically !== undefined && + typeof importModuleDynamically !== 'function') { + throw new ERR_INVALID_ARG_TYPE( + 'options.importModuleDynamically', 'function', importModuleDynamically); } const wrap = new ModuleWrap(src, url, context, lineOffset, columnOffset); @@ -110,6 +114,22 @@ class SourceTextModule { linkingStatusMap.set(this, 'unlinked'); wrapToModuleMap.set(wrap, this); + callbackMap.set(wrap, { + initializeImportMeta, + importModuleDynamically: importModuleDynamically ? async (...args) => { + const m = await importModuleDynamically(...args); + if (isModuleNamespaceObject(m)) { + return m; + } + if (!m || !wrapMap.has(m)) + throw new ERR_VM_MODULE_NOT_MODULE(); + const childLinkingStatus = linkingStatusMap.get(m); + if (childLinkingStatus === 'errored') + throw m.error; + return m.namespace; + } : undefined, + }); + Object.defineProperties(this, { url: { value: url, enumerable: true }, context: { value: context, enumerable: true }, @@ -255,6 +275,7 @@ function validateInteger(prop, propName) { module.exports = { SourceTextModule, - initImportMetaMap, - wrapToModuleMap + wrapToModuleMap, + wrapMap, + linkingStatusMap, }; diff --git a/lib/internal/worker.js b/lib/internal/worker.js index 88580893cdc015..669a86bb23faef 100644 --- a/lib/internal/worker.js +++ b/lib/internal/worker.js @@ -317,6 +317,7 @@ class Worker extends EventEmitter { [kOnExit](code) { debug(`[${threadId}] hears end event for Worker ${this.threadId}`); MessagePortPrototype.drain.call(this[kPublicPort]); + MessagePortPrototype.drain.call(this[kPort]); this[kDispose](); this.emit('exit', code); this.removeAllListeners(); diff --git a/lib/net.js b/lib/net.js index d21040198de631..e40aaa870289e8 100644 --- a/lib/net.js +++ b/lib/net.js @@ -275,11 +275,8 @@ function Socket(options) { throw errnoException(err, 'open'); this[async_id_symbol] = this._handle.getAsyncId(); - // options.fd can be string (since it is user-defined), - // so changing this to === would be semver-major - // See: https://github.com/nodejs/node/pull/11513 - // eslint-disable-next-line eqeqeq - if ((fd == 1 || fd == 2) && + + if ((fd === 1 || fd === 2) && (this._handle instanceof Pipe) && process.platform === 'win32') { // Make stdout and stderr blocking on Windows @@ -1071,10 +1068,6 @@ function afterConnect(status, handle, req, readable, writable) { return; } - // Update handle if it was wrapped - // TODO(indutny): assert that the handle is actually an ancestor of old one - handle = self._handle; - debug('afterConnect'); assert(self.connecting); diff --git a/lib/path.js b/lib/path.js index 798682ca0f1a6b..7ea431d1d00bb4 100644 --- a/lib/path.js +++ b/lib/path.js @@ -33,12 +33,7 @@ const { CHAR_COLON, CHAR_QUESTION_MARK, } = require('internal/constants'); - -function assertPath(path) { - if (typeof path !== 'string') { - throw new ERR_INVALID_ARG_TYPE('path', 'string', path); - } -} +const { validateString } = require('internal/validators'); function isPathSeparator(code) { return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH; @@ -163,7 +158,7 @@ const win32 = { } } - assertPath(path); + validateString(path, 'path'); // Skip empty entries if (path.length === 0) { @@ -282,7 +277,7 @@ const win32 = { }, normalize: function normalize(path) { - assertPath(path); + validateString(path, 'path'); const len = path.length; if (len === 0) return '.'; @@ -401,7 +396,7 @@ const win32 = { isAbsolute: function isAbsolute(path) { - assertPath(path); + validateString(path, 'path'); const len = path.length; if (len === 0) return false; @@ -429,7 +424,7 @@ const win32 = { var firstPart; for (var i = 0; i < arguments.length; ++i) { var arg = arguments[i]; - assertPath(arg); + validateString(arg, 'path'); if (arg.length > 0) { if (joined === undefined) joined = firstPart = arg; @@ -494,8 +489,8 @@ const win32 = { // to = 'C:\\orandea\\impl\\bbb' // The output of the function should be: '..\\..\\impl\\bbb' relative: function relative(from, to) { - assertPath(from); - assertPath(to); + validateString(from, 'from'); + validateString(to, 'to'); if (from === to) return ''; @@ -648,7 +643,7 @@ const win32 = { }, dirname: function dirname(path) { - assertPath(path); + validateString(path, 'path'); const len = path.length; if (len === 0) return '.'; @@ -744,9 +739,9 @@ const win32 = { basename: function basename(path, ext) { - if (ext !== undefined && typeof ext !== 'string') - throw new ERR_INVALID_ARG_TYPE('ext', 'string', ext); - assertPath(path); + if (ext !== undefined) + validateString(ext, 'ext'); + validateString(path, 'path'); var start = 0; var end = -1; var matchedSlash = true; @@ -832,7 +827,7 @@ const win32 = { extname: function extname(path) { - assertPath(path); + validateString(path, 'path'); var start = 0; var startDot = -1; var startPart = 0; @@ -905,7 +900,7 @@ const win32 = { parse: function parse(path) { - assertPath(path); + validateString(path, 'path'); var ret = { root: '', dir: '', base: '', ext: '', name: '' }; if (path.length === 0) @@ -1082,7 +1077,7 @@ const posix = { path = process.cwd(); } - assertPath(path); + validateString(path, 'path'); // Skip empty entries if (path.length === 0) { @@ -1114,7 +1109,7 @@ const posix = { normalize: function normalize(path) { - assertPath(path); + validateString(path, 'path'); if (path.length === 0) return '.'; @@ -1138,7 +1133,7 @@ const posix = { isAbsolute: function isAbsolute(path) { - assertPath(path); + validateString(path, 'path'); return path.length > 0 && path.charCodeAt(0) === CHAR_FORWARD_SLASH; }, @@ -1149,7 +1144,7 @@ const posix = { var joined; for (var i = 0; i < arguments.length; ++i) { var arg = arguments[i]; - assertPath(arg); + validateString(arg, 'path'); if (arg.length > 0) { if (joined === undefined) joined = arg; @@ -1164,8 +1159,8 @@ const posix = { relative: function relative(from, to) { - assertPath(from); - assertPath(to); + validateString(from, 'from'); + validateString(to, 'to'); if (from === to) return ''; @@ -1262,7 +1257,7 @@ const posix = { }, dirname: function dirname(path) { - assertPath(path); + validateString(path, 'path'); if (path.length === 0) return '.'; const hasRoot = path.charCodeAt(0) === CHAR_FORWARD_SLASH; @@ -1289,9 +1284,9 @@ const posix = { basename: function basename(path, ext) { - if (ext !== undefined && typeof ext !== 'string') - throw new ERR_INVALID_ARG_TYPE('ext', 'string', ext); - assertPath(path); + if (ext !== undefined) + validateString(ext, 'ext'); + validateString(path, 'path'); var start = 0; var end = -1; @@ -1367,7 +1362,7 @@ const posix = { extname: function extname(path) { - assertPath(path); + validateString(path, 'path'); var startDot = -1; var startPart = 0; var end = -1; @@ -1428,7 +1423,7 @@ const posix = { parse: function parse(path) { - assertPath(path); + validateString(path, 'path'); var ret = { root: '', dir: '', base: '', ext: '', name: '' }; if (path.length === 0) diff --git a/lib/perf_hooks.js b/lib/perf_hooks.js index f7b18816e6ceb0..7d4f1ef43073fe 100644 --- a/lib/perf_hooks.js +++ b/lib/perf_hooks.js @@ -142,8 +142,6 @@ function getMilestoneTimestamp(milestoneIdx) { } class PerformanceNodeTiming { - constructor() {} - get name() { return 'node'; } diff --git a/lib/url.js b/lib/url.js index 676722de622e2b..7870ce50d86545 100644 --- a/lib/url.js +++ b/lib/url.js @@ -26,6 +26,8 @@ const { toASCII } = process.binding('config').hasIntl ? const { hexTable } = require('internal/querystring'); +const { SafeSet } = require('internal/safe_globals'); + const { ERR_INVALID_ARG_TYPE } = require('internal/errors').codes; @@ -76,28 +78,28 @@ const simplePathPattern = /^(\/\/?(?!\/)[^?\s]*)(\?[^\s]*)?$/; const hostnameMaxLen = 255; // protocols that can allow "unsafe" and "unwise" chars. -const unsafeProtocol = { - 'javascript': true, - 'javascript:': true -}; +const unsafeProtocol = new SafeSet([ + 'javascript', + 'javascript:' +]); // protocols that never have a hostname. -const hostlessProtocol = { - 'javascript': true, - 'javascript:': true -}; +const hostlessProtocol = new SafeSet([ + 'javascript', + 'javascript:' +]); // protocols that always contain a // bit. -const slashedProtocol = { - 'http': true, - 'http:': true, - 'https': true, - 'https:': true, - 'ftp': true, - 'ftp:': true, - 'gopher': true, - 'gopher:': true, - 'file': true, - 'file:': true -}; +const slashedProtocol = new SafeSet([ + 'http', + 'http:', + 'https', + 'https:', + 'ftp', + 'ftp:', + 'gopher', + 'gopher:', + 'file', + 'file:' +]); const { CHAR_SPACE, CHAR_TAB, @@ -267,14 +269,14 @@ Url.prototype.parse = function parse(url, parseQueryString, slashesDenoteHost) { if (slashesDenoteHost || proto || hostPattern.test(rest)) { var slashes = rest.charCodeAt(0) === CHAR_FORWARD_SLASH && rest.charCodeAt(1) === CHAR_FORWARD_SLASH; - if (slashes && !(proto && hostlessProtocol[lowerProto])) { + if (slashes && !(proto && hostlessProtocol.has(lowerProto))) { rest = rest.slice(2); this.slashes = true; } } - if (!hostlessProtocol[lowerProto] && - (slashes || (proto && !slashedProtocol[proto]))) { + if (!hostlessProtocol.has(lowerProto) && + (slashes || (proto && !slashedProtocol.has(proto)))) { // there's a hostname. // the first instance of /, ?, ;, or # ends the host. @@ -400,7 +402,7 @@ Url.prototype.parse = function parse(url, parseQueryString, slashesDenoteHost) { // now rest is set to the post-host stuff. // chop off any delim chars. - if (!unsafeProtocol[lowerProto]) { + if (!unsafeProtocol.has(lowerProto)) { // First, make 100% sure that any "autoEscape" chars get // escaped, even if encodeURIComponent doesn't think they // need to be. @@ -447,7 +449,7 @@ Url.prototype.parse = function parse(url, parseQueryString, slashesDenoteHost) { } else if (firstIdx > 0) { this.pathname = rest.slice(0, firstIdx); } - if (slashedProtocol[lowerProto] && + if (slashedProtocol.has(lowerProto) && this.hostname && !this.pathname) { this.pathname = '/'; } @@ -629,7 +631,7 @@ Url.prototype.format = function format() { // only the slashedProtocols get the //. Not mailto:, xmpp:, etc. // unless they had them to begin with. - if (this.slashes || slashedProtocol[protocol]) { + if (this.slashes || slashedProtocol.has(protocol)) { if (this.slashes || host) { if (pathname && pathname.charCodeAt(0) !== CHAR_FORWARD_SLASH) pathname = '/' + pathname; @@ -701,7 +703,7 @@ Url.prototype.resolveObject = function resolveObject(relative) { } // urlParse appends trailing / to urls like http://www.example.com - if (slashedProtocol[result.protocol] && + if (slashedProtocol.has(result.protocol) && result.hostname && !result.pathname) { result.path = result.pathname = '/'; } @@ -719,7 +721,7 @@ Url.prototype.resolveObject = function resolveObject(relative) { // if it is file:, then the host is dropped, // because that's known to be hostless. // anything else is assumed to be absolute. - if (!slashedProtocol[relative.protocol]) { + if (!slashedProtocol.has(relative.protocol)) { var keys = Object.keys(relative); for (var v = 0; v < keys.length; v++) { var k = keys[v]; @@ -732,7 +734,7 @@ Url.prototype.resolveObject = function resolveObject(relative) { result.protocol = relative.protocol; if (!relative.host && !/^file:?$/.test(relative.protocol) && - !hostlessProtocol[relative.protocol]) { + !hostlessProtocol.has(relative.protocol)) { const relPath = (relative.pathname || '').split('/'); while (relPath.length && !(relative.host = relPath.shift())); if (!relative.host) relative.host = ''; @@ -769,7 +771,8 @@ Url.prototype.resolveObject = function resolveObject(relative) { var removeAllDots = mustEndAbs; var srcPath = result.pathname && result.pathname.split('/') || []; var relPath = relative.pathname && relative.pathname.split('/') || []; - var noLeadingSlashes = result.protocol && !slashedProtocol[result.protocol]; + var noLeadingSlashes = result.protocol && + !slashedProtocol.has(result.protocol); // if the url is a non-slashed url, then relative // links like ../.. should be able diff --git a/lib/v8.js b/lib/v8.js index 0d9ffc6033ced2..5b9632fcb096bd 100644 --- a/lib/v8.js +++ b/lib/v8.js @@ -173,10 +173,6 @@ class DefaultSerializer extends Serializer { } class DefaultDeserializer extends Deserializer { - constructor(buffer) { - super(buffer); - } - _readHostObject() { const typeIndex = this.readUint32(); const ctor = arrayBufferViewTypes[typeIndex]; diff --git a/lib/vm.js b/lib/vm.js index dbe48b7b15c194..02b3f0bce423bc 100644 --- a/lib/vm.js +++ b/lib/vm.js @@ -27,12 +27,13 @@ const { isContext: _isContext, compileFunction: _compileFunction } = process.binding('contextify'); - +const { callbackMap } = internalBinding('module_wrap'); const { ERR_INVALID_ARG_TYPE, - ERR_OUT_OF_RANGE + ERR_OUT_OF_RANGE, + ERR_VM_MODULE_NOT_MODULE, } = require('internal/errors').codes; -const { isUint8Array } = require('internal/util/types'); +const { isModuleNamespaceObject, isUint8Array } = require('util').types; const { validateUint32 } = require('internal/validators'); const kParsingContext = Symbol('script parsing context'); @@ -44,8 +45,7 @@ class Script extends ContextifyScript { code = `${code}`; if (typeof options === 'string') { options = { filename: options }; - } - if (typeof options !== 'object' || options === null) { + } else if (typeof options !== 'object' || options === null) { throw new ERR_INVALID_ARG_TYPE('options', 'Object', options); } @@ -55,7 +55,8 @@ class Script extends ContextifyScript { columnOffset = 0, cachedData, produceCachedData = false, - [kParsingContext]: parsingContext + importModuleDynamically, + [kParsingContext]: parsingContext, } = options; if (typeof filename !== 'string') { @@ -86,6 +87,28 @@ class Script extends ContextifyScript { } catch (e) { throw e; /* node-do-not-add-exception-line */ } + + if (importModuleDynamically !== undefined) { + if (typeof importModuleDynamically !== 'function') { + throw new ERR_INVALID_ARG_TYPE('options.importModuleDynamically', + 'function', + importModuleDynamically); + } + const { wrapMap, linkingStatusMap } = + require('internal/vm/source_text_module'); + callbackMap.set(this, { importModuleDynamically: async (...args) => { + const m = await importModuleDynamically(...args); + if (isModuleNamespaceObject(m)) { + return m; + } + if (!m || !wrapMap.has(m)) + throw new ERR_VM_MODULE_NOT_MODULE(); + const childLinkingStatus = linkingStatusMap.get(m); + if (childLinkingStatus === 'errored') + throw m.error; + return m.namespace; + } }); + } } runInThisContext(options) { diff --git a/node.gypi b/node.gypi index 7836561a84117d..6a948b48170b92 100644 --- a/node.gypi +++ b/node.gypi @@ -269,25 +269,28 @@ '-Wl,--whole-archive <(v8_base)', '-Wl,--no-whole-archive' ] }], - [ 'OS in "mac freebsd linux" and node_shared=="false"' - ' and coverage=="true"', { + [ 'coverage=="true" and node_shared=="false" and OS in "mac freebsd linux"', { + 'cflags!': [ '-O3' ], 'ldflags': [ '--coverage', '-g', '-O0' ], 'cflags': [ '--coverage', '-g', '-O0' ], - 'cflags!': [ '-O3' ], 'xcode_settings': { - 'OTHER_LDFLAGS': [ - '--coverage', - ], - 'OTHER_CFLAGS+': [ + 'OTHER_CFLAGS': [ '--coverage', '-g', '-O0' ], - } + }, + 'conditions': [ + [ '_type=="executable"', { + 'xcode_settings': { + 'OTHER_LDFLAGS': [ '--coverage', ], + }, + }], + ], }], [ 'OS=="sunos"', { 'ldflags': [ '-Wl,-M,/usr/lib/ld/map.noexstk' ], diff --git a/src/async_wrap.cc b/src/async_wrap.cc index b7d59671908564..42fd723e4776c0 100644 --- a/src/async_wrap.cc +++ b/src/async_wrap.cc @@ -28,6 +28,8 @@ #include "v8-profiler.h" using v8::Context; +using v8::DontDelete; +using v8::EscapableHandleScope; using v8::Function; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; @@ -36,16 +38,22 @@ using v8::Integer; using v8::Isolate; using v8::Local; using v8::MaybeLocal; +using v8::NewStringType; using v8::Number; using v8::Object; using v8::ObjectTemplate; using v8::Promise; using v8::PromiseHookType; +using v8::PropertyAttribute; using v8::PropertyCallbackInfo; +using v8::ReadOnly; using v8::String; +using v8::TryCatch; using v8::Uint32; using v8::Undefined; using v8::Value; +using v8::WeakCallbackInfo; +using v8::WeakCallbackType; using AsyncHooks = node::Environment::AsyncHooks; @@ -115,7 +123,7 @@ void Emit(Environment* env, double async_id, AsyncHooks::Fields type, if (async_hooks->fields()[type] == 0 || !env->can_call_into_js()) return; - v8::HandleScope handle_scope(env->isolate()); + HandleScope handle_scope(env->isolate()); Local async_id_value = Number::New(env->isolate(), async_id); FatalTryCatch try_catch(env); USE(fn->Call(env->context(), Undefined(env->isolate()), 1, &async_id_value)); @@ -351,8 +359,7 @@ class DestroyParam { Persistent propBag; }; - -void AsyncWrap::WeakCallback(const v8::WeakCallbackInfo& info) { +void AsyncWrap::WeakCallback(const WeakCallbackInfo& info) { HandleScope scope(info.GetIsolate()); std::unique_ptr p{info.GetParameter()}; @@ -377,8 +384,7 @@ static void RegisterDestroyHook(const FunctionCallbackInfo& args) { p->env = Environment::GetCurrent(args); p->target.Reset(isolate, args[0].As()); p->propBag.Reset(isolate, args[2].As()); - p->target.SetWeak( - p, AsyncWrap::WeakCallback, v8::WeakCallbackType::kParameter); + p->target.SetWeak(p, AsyncWrap::WeakCallback, WeakCallbackType::kParameter); } @@ -452,8 +458,8 @@ void AsyncWrap::Initialize(Local target, env->SetMethod(target, "disablePromiseHook", DisablePromiseHook); env->SetMethod(target, "registerDestroyHook", RegisterDestroyHook); - v8::PropertyAttribute ReadOnlyDontDelete = - static_cast(v8::ReadOnly | v8::DontDelete); + PropertyAttribute ReadOnlyDontDelete = + static_cast(ReadOnly | DontDelete); #define FORCE_SET_TARGET_FIELD(obj, str, field) \ (obj)->DefineOwnProperty(context, \ @@ -695,7 +701,7 @@ MaybeLocal AsyncWrap::MakeCallback(const Local cb, async_id AsyncHooksGetExecutionAsyncId(Isolate* isolate) { // Environment::GetCurrent() allocates a Local<> handle. - v8::HandleScope handle_scope(isolate); + HandleScope handle_scope(isolate); Environment* env = Environment::GetCurrent(isolate); if (env == nullptr) return -1; return env->execution_async_id(); @@ -704,7 +710,7 @@ async_id AsyncHooksGetExecutionAsyncId(Isolate* isolate) { async_id AsyncHooksGetTriggerAsyncId(Isolate* isolate) { // Environment::GetCurrent() allocates a Local<> handle. - v8::HandleScope handle_scope(isolate); + HandleScope handle_scope(isolate); Environment* env = Environment::GetCurrent(isolate); if (env == nullptr) return -1; return env->trigger_async_id(); @@ -715,18 +721,18 @@ async_context EmitAsyncInit(Isolate* isolate, Local resource, const char* name, async_id trigger_async_id) { - v8::HandleScope handle_scope(isolate); + HandleScope handle_scope(isolate); Local type = - String::NewFromUtf8(isolate, name, v8::NewStringType::kInternalized) + String::NewFromUtf8(isolate, name, NewStringType::kInternalized) .ToLocalChecked(); return EmitAsyncInit(isolate, resource, type, trigger_async_id); } async_context EmitAsyncInit(Isolate* isolate, Local resource, - v8::Local name, + Local name, async_id trigger_async_id) { - v8::HandleScope handle_scope(isolate); + HandleScope handle_scope(isolate); Environment* env = Environment::GetCurrent(isolate); CHECK_NOT_NULL(env); @@ -748,7 +754,7 @@ async_context EmitAsyncInit(Isolate* isolate, void EmitAsyncDestroy(Isolate* isolate, async_context asyncContext) { // Environment::GetCurrent() allocates a Local<> handle. - v8::HandleScope handle_scope(isolate); + HandleScope handle_scope(isolate); AsyncWrap::EmitDestroy( Environment::GetCurrent(isolate), asyncContext.async_id); } @@ -767,10 +773,10 @@ Local AsyncWrap::GetOwner() { } Local AsyncWrap::GetOwner(Environment* env, Local obj) { - v8::EscapableHandleScope handle_scope(env->isolate()); + EscapableHandleScope handle_scope(env->isolate()); CHECK(!obj.IsEmpty()); - v8::TryCatch ignore_exceptions(env->isolate()); + TryCatch ignore_exceptions(env->isolate()); while (true) { Local owner; if (!obj->Get(env->context(), diff --git a/src/debug_utils.cc b/src/debug_utils.cc index 77ea219bfc880a..4f086106b66ca7 100644 --- a/src/debug_utils.cc +++ b/src/debug_utils.cc @@ -30,6 +30,27 @@ #endif // __POSIX__ +#if defined(__linux__) || defined(__sun) +#include +#endif // (__linux__) || defined(__sun) + +#ifdef __APPLE__ +#include // _dyld_get_image_name() +#endif // __APPLE__ + +#ifdef _AIX +#include // ld_info structure +#endif // _AIX + +#ifdef _WIN32 +#include +#include +#include +#include +#include +#include +#endif // _WIN32 + namespace node { #ifdef __POSIX__ @@ -299,6 +320,108 @@ void CheckedUvLoopClose(uv_loop_t* loop) { CHECK(0 && "uv_loop_close() while having open handles"); } +std::vector NativeSymbolDebuggingContext::GetLoadedLibraries() { + std::vector list; +#ifdef __linux__ + dl_iterate_phdr( + [](struct dl_phdr_info* info, size_t size, void* data) { + auto list = static_cast*>(data); + if (*info->dlpi_name != '\0') { + list->push_back(info->dlpi_name); + } + return 0; + }, + &list); +#elif __APPLE__ + uint32_t i = 0; + for (const char* name = _dyld_get_image_name(i); name != nullptr; + name = _dyld_get_image_name(++i)) { + list.push_back(name); + } + +#elif _AIX + // We can't tell in advance how large the buffer needs to be. + // Retry until we reach too large a size (1Mb). + const unsigned int kBufferGrowStep = 4096; + MallocedBuffer buffer(kBufferGrowStep); + int rc = -1; + do { + rc = loadquery(L_GETINFO, buffer.data, buffer.size); + if (rc == 0) break; + buffer = MallocedBuffer(buffer.size + kBufferGrowStep); + } while (buffer.size < 1024 * 1024); + + if (rc == 0) { + char* buf = buffer.data; + ld_info* cur_info = nullptr; + do { + std::ostringstream str; + cur_info = reinterpret_cast(buf); + char* member_name = cur_info->ldinfo_filename + + strlen(cur_info->ldinfo_filename) + 1; + if (*member_name != '\0') { + str << cur_info->ldinfo_filename << "(" << member_name << ")"; + list.push_back(str.str()); + str.str(""); + } else { + list.push_back(cur_info->ldinfo_filename); + } + buf += cur_info->ldinfo_next; + } while (cur_info->ldinfo_next != 0); + } +#elif __sun + Link_map* p; + + if (dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &p) != -1) { + for (Link_map* l = p; l != nullptr; l = l->l_next) { + list.push_back(l->l_name); + } + } + +#elif _WIN32 + // Windows implementation - get a handle to the process. + HANDLE process_handle = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, + FALSE, GetCurrentProcessId()); + if (process_handle == nullptr) { + // Cannot proceed, return an empty list. + return list; + } + // Get a list of all the modules in this process + DWORD size_1 = 0; + DWORD size_2 = 0; + // First call to get the size of module array needed + if (EnumProcessModules(process_handle, nullptr, 0, &size_1)) { + MallocedBuffer modules(size_1); + + // Second call to populate the module array + if (EnumProcessModules(process_handle, modules.data, size_1, &size_2)) { + for (DWORD i = 0; + i < (size_1 / sizeof(HMODULE)) && i < (size_2 / sizeof(HMODULE)); + i++) { + WCHAR module_name[MAX_PATH]; + // Obtain and report the full pathname for each module + if (GetModuleFileNameExW(process_handle, + modules.data[i], + module_name, + arraysize(module_name) / sizeof(WCHAR))) { + DWORD size = WideCharToMultiByte( + CP_UTF8, 0, module_name, -1, nullptr, 0, nullptr, nullptr); + char* str = new char[size]; + WideCharToMultiByte( + CP_UTF8, 0, module_name, -1, str, size, nullptr, nullptr); + list.push_back(str); + } + } + } + } + + // Release the handle to the process. + CloseHandle(process_handle); +#endif + return list; +} + + } // namespace node extern "C" void __DumpBacktrace(FILE* fp) { diff --git a/src/debug_utils.h b/src/debug_utils.h index c6c8e03b51fd64..034d8a9ab331dc 100644 --- a/src/debug_utils.h +++ b/src/debug_utils.h @@ -113,6 +113,7 @@ class NativeSymbolDebuggingContext { = delete; NativeSymbolDebuggingContext operator=(NativeSymbolDebuggingContext&&) = delete; + static std::vector GetLoadedLibraries(); }; // Variant of `uv_loop_close` that tries to be as helpful as possible diff --git a/src/env-inl.h b/src/env-inl.h index b512412c0ff4f0..4af5add4c8f52c 100644 --- a/src/env-inl.h +++ b/src/env-inl.h @@ -441,6 +441,13 @@ Environment::should_abort_on_uncaught_toggle() { return should_abort_on_uncaught_toggle_; } +inline uint32_t Environment::get_next_module_id() { + return module_id_counter_++; +} +inline uint32_t Environment::get_next_script_id() { + return script_id_counter_++; +} + Environment::ShouldNotAbortOnUncaughtScope::ShouldNotAbortOnUncaughtScope( Environment* env) : env_(env) { diff --git a/src/env.cc b/src/env.cc index 57c0be960f7784..8f061f9f83f288 100644 --- a/src/env.cc +++ b/src/env.cc @@ -241,6 +241,13 @@ void Environment::Start(const std::vector& args, static uv_once_t init_once = UV_ONCE_INIT; uv_once(&init_once, InitThreadLocalOnce); uv_key_set(&thread_local_env, this); + +#if HAVE_INSPECTOR + // This needs to be set before we start the inspector + Local obj = Object::New(isolate()); + CHECK(obj->SetPrototype(context(), Null(isolate())).FromJust()); + set_inspector_console_api_object(obj); +#endif // HAVE_INSPECTOR } void Environment::RegisterHandleCleanups() { diff --git a/src/env.h b/src/env.h index 1d2baf58b007ea..66c69e8d00b9da 100644 --- a/src/env.h +++ b/src/env.h @@ -47,6 +47,10 @@ struct nghttp2_rcbuf; namespace node { +namespace contextify { +class ContextifyScript; +} + namespace fs { class FileHandleReadWrap; } @@ -112,8 +116,8 @@ struct PackageConfig { // for the sake of convenience. #define PER_ISOLATE_SYMBOL_PROPERTIES(V) \ V(handle_onclose_symbol, "handle_onclose") \ - V(owner_symbol, "owner") \ V(oninit_symbol, "oninit") \ + V(owner_symbol, "owner") \ // Strings are per-isolate primitives but Environment proxies them // for the sake of convenience. Strings should be ASCII-only. @@ -124,19 +128,18 @@ struct PackageConfig { V(async, "async") \ V(async_ids_stack_string, "async_ids_stack") \ V(buffer_string, "buffer") \ - V(bytes_string, "bytes") \ V(bytes_parsed_string, "bytesParsed") \ V(bytes_read_string, "bytesRead") \ + V(bytes_string, "bytes") \ V(bytes_written_string, "bytesWritten") \ - V(cached_data_string, "cachedData") \ V(cached_data_produced_string, "cachedDataProduced") \ V(cached_data_rejected_string, "cachedDataRejected") \ + V(cached_data_string, "cachedData") \ V(change_string, "change") \ V(channel_string, "channel") \ V(chunks_sent_since_last_write_string, "chunksSentSinceLastWrite") \ - V(constants_string, "constants") \ - V(oncertcb_string, "oncertcb") \ V(code_string, "code") \ + V(constants_string, "constants") \ V(cwd_string, "cwd") \ V(dest_string, "dest") \ V(destroyed_string, "destroyed") \ @@ -153,7 +156,6 @@ struct PackageConfig { V(dns_txt_string, "TXT") \ V(duration_string, "duration") \ V(emit_warning_string, "emitWarning") \ - V(exchange_string, "exchange") \ V(encoding_string, "encoding") \ V(entries_string, "entries") \ V(entry_type_string, "entryType") \ @@ -161,6 +163,7 @@ struct PackageConfig { V(env_var_settings_string, "envVarSettings") \ V(errno_string, "errno") \ V(error_string, "error") \ + V(exchange_string, "exchange") \ V(exit_code_string, "exitCode") \ V(expire_string, "expire") \ V(exponent_string, "exponent") \ @@ -171,8 +174,8 @@ struct PackageConfig { V(fatal_exception_string, "_fatalException") \ V(fd_string, "fd") \ V(file_string, "file") \ - V(fingerprint_string, "fingerprint") \ V(fingerprint256_string, "fingerprint256") \ + V(fingerprint_string, "fingerprint") \ V(flags_string, "flags") \ V(fragment_string, "fragment") \ V(get_data_clone_error_string, "_getDataCloneError") \ @@ -198,9 +201,9 @@ struct PackageConfig { V(mac_string, "mac") \ V(main_string, "main") \ V(max_buffer_string, "maxBuffer") \ - V(message_string, "message") \ - V(message_port_string, "messagePort") \ V(message_port_constructor_string, "MessagePort") \ + V(message_port_string, "messagePort") \ + V(message_string, "message") \ V(minttl_string, "minttl") \ V(modulus_string, "modulus") \ V(name_string, "name") \ @@ -208,6 +211,7 @@ struct PackageConfig { V(nsname_string, "nsname") \ V(ocsp_request_string, "OCSPRequest") \ V(onaltsvc_string, "onaltsvc") \ + V(oncertcb_string, "oncertcb") \ V(onchange_string, "onchange") \ V(onclienthello_string, "onclienthello") \ V(oncomplete_string, "oncomplete") \ @@ -217,19 +221,19 @@ struct PackageConfig { V(onexit_string, "onexit") \ V(onframeerror_string, "onframeerror") \ V(ongetpadding_string, "ongetpadding") \ + V(ongoawaydata_string, "ongoawaydata") \ V(onhandshakedone_string, "onhandshakedone") \ V(onhandshakestart_string, "onhandshakestart") \ V(onheaders_string, "onheaders") \ V(onmessage_string, "onmessage") \ V(onnewsession_string, "onnewsession") \ V(onocspresponse_string, "onocspresponse") \ - V(ongoawaydata_string, "ongoawaydata") \ V(onorigin_string, "onorigin") \ + V(onping_string, "onping") \ V(onpriority_string, "onpriority") \ V(onread_string, "onread") \ V(onreadstart_string, "onreadstart") \ V(onreadstop_string, "onreadstop") \ - V(onping_string, "onping") \ V(onsettings_string, "onsettings") \ V(onshutdown_string, "onshutdown") \ V(onsignal_string, "onsignal") \ @@ -239,19 +243,19 @@ struct PackageConfig { V(onwrite_string, "onwrite") \ V(openssl_error_stack, "opensslErrorStack") \ V(options_string, "options") \ - V(output_string, "output") \ V(order_string, "order") \ + V(output_string, "output") \ V(parse_error_string, "Parse Error") \ V(password_string, "password") \ V(path_string, "path") \ V(pending_handle_string, "pendingHandle") \ V(pid_string, "pid") \ + V(pipe_source_string, "pipeSource") \ V(pipe_string, "pipe") \ V(pipe_target_string, "pipeTarget") \ - V(pipe_source_string, "pipeSource") \ - V(port_string, "port") \ V(port1_string, "port1") \ V(port2_string, "port2") \ + V(port_string, "port") \ V(preference_string, "preference") \ V(priority_string, "priority") \ V(promise_string, "promise") \ @@ -266,11 +270,11 @@ struct PackageConfig { V(replacement_string, "replacement") \ V(retry_string, "retry") \ V(scheme_string, "scheme") \ - V(serial_string, "serial") \ V(scopeid_string, "scopeid") \ V(serial_number_string, "serialNumber") \ - V(service_string, "service") \ + V(serial_string, "serial") \ V(servername_string, "servername") \ + V(service_string, "service") \ V(session_id_string, "sessionId") \ V(shell_string, "shell") \ V(signal_string, "signal") \ @@ -309,7 +313,7 @@ struct PackageConfig { V(write_host_object_string, "_writeHostObject") \ V(write_queue_size_string, "writeQueueSize") \ V(x_forwarded_string, "x-forwarded-for") \ - V(zero_return_string, "ZERO_RETURN") + V(zero_return_string, "ZERO_RETURN") \ #define ENVIRONMENT_STRONG_PERSISTENT_PROPERTIES(V) \ V(as_external, v8::External) \ @@ -319,17 +323,17 @@ struct PackageConfig { V(async_hooks_destroy_function, v8::Function) \ V(async_hooks_init_function, v8::Function) \ V(async_hooks_promise_resolve_function, v8::Function) \ - V(async_wrap_object_ctor_template, v8::FunctionTemplate) \ V(async_wrap_ctor_template, v8::FunctionTemplate) \ + V(async_wrap_object_ctor_template, v8::FunctionTemplate) \ V(buffer_prototype_object, v8::Object) \ V(context, v8::Context) \ V(domain_callback, v8::Function) \ V(domexception_function, v8::Function) \ - V(fdclose_constructor_template, v8::ObjectTemplate) \ V(fd_constructor_template, v8::ObjectTemplate) \ + V(fdclose_constructor_template, v8::ObjectTemplate) \ V(filehandlereadwrap_template, v8::ObjectTemplate) \ - V(fsreqpromise_constructor_template, v8::ObjectTemplate) \ V(fs_use_promises_symbol, v8::Symbol) \ + V(fsreqpromise_constructor_template, v8::ObjectTemplate) \ V(handle_wrap_ctor_template, v8::FunctionTemplate) \ V(host_import_module_dynamically_callback, v8::Function) \ V(host_initialize_import_meta_object_callback, v8::Function) \ @@ -341,9 +345,9 @@ struct PackageConfig { V(libuv_stream_wrap_ctor_template, v8::FunctionTemplate) \ V(message_port, v8::Object) \ V(message_port_constructor_template, v8::FunctionTemplate) \ - V(pipe_constructor_template, v8::FunctionTemplate) \ V(performance_entry_callback, v8::Function) \ V(performance_entry_template, v8::Function) \ + V(pipe_constructor_template, v8::FunctionTemplate) \ V(process_object, v8::Object) \ V(promise_handler_function, v8::Function) \ V(promise_wrap_template, v8::ObjectTemplate) \ @@ -360,7 +364,7 @@ struct PackageConfig { V(tty_constructor_template, v8::FunctionTemplate) \ V(udp_constructor_function, v8::Function) \ V(url_constructor_function, v8::Function) \ - V(write_wrap_template, v8::ObjectTemplate) + V(write_wrap_template, v8::ObjectTemplate) \ class Environment; @@ -671,7 +675,13 @@ class Environment { // List of id's that have been destroyed and need the destroy() cb called. inline std::vector* destroy_async_id_list(); - std::unordered_multimap module_map; + std::unordered_multimap hash_to_module_map; + std::unordered_map id_to_module_map; + std::unordered_map + id_to_script_map; + + inline uint32_t get_next_module_id(); + inline uint32_t get_next_script_id(); std::unordered_map package_json_cache; @@ -899,6 +909,9 @@ class Environment { std::shared_ptr options_; + uint32_t module_id_counter_ = 0; + uint32_t script_id_counter_ = 0; + AliasedBuffer should_abort_on_uncaught_toggle_; int should_not_abort_scope_counter_ = 0; diff --git a/src/inspector/main_thread_interface.cc b/src/inspector/main_thread_interface.cc index d3f553caac8f9f..e374c0fd701b3c 100644 --- a/src/inspector/main_thread_interface.cc +++ b/src/inspector/main_thread_interface.cc @@ -254,8 +254,9 @@ void MainThreadInterface::Post(std::unique_ptr request) { if (needs_notify) { CHECK_EQ(0, uv_async_send(&main_thread_request_->first)); if (isolate_ != nullptr && platform_ != nullptr) { - platform_->CallOnForegroundThread(isolate_, - new DispatchMessagesTask(this)); + std::shared_ptr taskrunner = + platform_->GetForegroundTaskRunner(isolate_); + taskrunner->PostTask(std::make_unique(this)); isolate_->RequestInterrupt([](v8::Isolate* isolate, void* thread) { static_cast(thread)->DispatchMessages(); }, this); diff --git a/src/inspector/tracing_agent.cc b/src/inspector/tracing_agent.cc index fe69e6f863e2a6..2f815eb2fbbc7f 100644 --- a/src/inspector/tracing_agent.cc +++ b/src/inspector/tracing_agent.cc @@ -30,7 +30,7 @@ class InspectorTraceWriter : public node::tracing::AsyncTraceWriter { return; json_writer_.reset(); std::ostringstream result( - "{\"method\":\"NodeTracing.dataCollected\",\"data\":", + "{\"method\":\"NodeTracing.dataCollected\",\"params\":", std::ostringstream::ate); result << stream_.str(); result << "}"; diff --git a/src/inspector_agent.cc b/src/inspector_agent.cc index dde6bda4b5f0e7..47bcf8cbfb1b89 100644 --- a/src/inspector_agent.cc +++ b/src/inspector_agent.cc @@ -39,6 +39,8 @@ using v8::Local; using v8::Message; using v8::Object; using v8::String; +using v8::Task; +using v8::TaskRunner; using v8::Value; using v8_inspector::StringBuffer; @@ -49,7 +51,7 @@ using v8_inspector::V8InspectorClient; static uv_sem_t start_io_thread_semaphore; static uv_async_t start_io_thread_async; -class StartIoTask : public v8::Task { +class StartIoTask : public Task { public: explicit StartIoTask(Agent* agent) : agent(agent) {} @@ -109,7 +111,9 @@ static int StartDebugSignalHandler() { sigset_t sigmask; // Mask all signals. sigfillset(&sigmask); - CHECK_EQ(0, pthread_sigmask(SIG_SETMASK, &sigmask, &sigmask)); + sigset_t savemask; + CHECK_EQ(0, pthread_sigmask(SIG_SETMASK, &sigmask, &savemask)); + sigmask = savemask; pthread_t thread; const int err = pthread_create(&thread, &attr, StartIoThreadMain, nullptr); @@ -501,6 +505,7 @@ class NodeInspectorClient : public V8InspectorClient { void installAdditionalCommandLineAPI(Local context, Local target) override { Local console_api = env_->inspector_console_api_object(); + CHECK(!console_api.IsEmpty()); Local properties = console_api->GetOwnPropertyNames(context).ToLocalChecked(); @@ -852,7 +857,9 @@ void Agent::RequestIoThreadStart() { uv_async_send(&start_io_thread_async); Isolate* isolate = parent_env_->isolate(); v8::Platform* platform = parent_env_->isolate_data()->platform(); - platform->CallOnForegroundThread(isolate, new StartIoTask(this)); + std::shared_ptr taskrunner = + platform->GetForegroundTaskRunner(isolate); + taskrunner->PostTask(std::make_unique(this)); isolate->RequestInterrupt(StartIoInterrupt, this); uv_async_send(&start_io_thread_async); } diff --git a/src/inspector_js_api.cc b/src/inspector_js_api.cc index 52f14639a430d3..2e69665e09cd87 100644 --- a/src/inspector_js_api.cc +++ b/src/inspector_js_api.cc @@ -277,12 +277,6 @@ void Url(const FunctionCallbackInfo& args) { void Initialize(Local target, Local unused, Local context, void* priv) { Environment* env = Environment::GetCurrent(context); - { - auto obj = Object::New(env->isolate()); - auto null = Null(env->isolate()); - CHECK(obj->SetPrototype(context, null).FromJust()); - env->set_inspector_console_api_object(obj); - } Agent* agent = env->inspector_agent(); env->SetMethod(target, "consoleCall", InspectorConsoleCall); diff --git a/src/module_wrap.cc b/src/module_wrap.cc index 816c68d55d16ce..fe6a8e2639c7a7 100644 --- a/src/module_wrap.cc +++ b/src/module_wrap.cc @@ -33,7 +33,9 @@ using v8::Maybe; using v8::MaybeLocal; using v8::Module; using v8::Nothing; +using v8::Number; using v8::Object; +using v8::PrimitiveArray; using v8::Promise; using v8::ScriptCompiler; using v8::ScriptOrigin; @@ -47,18 +49,22 @@ static const char* const EXTENSIONS[] = {".mjs", ".js", ".json", ".node"}; ModuleWrap::ModuleWrap(Environment* env, Local object, Local module, - Local url) : BaseObject(env, object) { + Local url) : + BaseObject(env, object), + id_(env->get_next_module_id()) { module_.Reset(env->isolate(), module); url_.Reset(env->isolate(), url); + env->id_to_module_map.emplace(id_, this); } ModuleWrap::~ModuleWrap() { HandleScope scope(env()->isolate()); Local module = module_.Get(env()->isolate()); - auto range = env()->module_map.equal_range(module->GetIdentityHash()); + env()->id_to_module_map.erase(id_); + auto range = env()->hash_to_module_map.equal_range(module->GetIdentityHash()); for (auto it = range.first; it != range.second; ++it) { if (it->second == this) { - env()->module_map.erase(it); + env()->hash_to_module_map.erase(it); break; } } @@ -66,15 +72,21 @@ ModuleWrap::~ModuleWrap() { ModuleWrap* ModuleWrap::GetFromModule(Environment* env, Local module) { - ModuleWrap* ret = nullptr; - auto range = env->module_map.equal_range(module->GetIdentityHash()); + auto range = env->hash_to_module_map.equal_range(module->GetIdentityHash()); for (auto it = range.first; it != range.second; ++it) { if (it->second->module_ == module) { - ret = it->second; - break; + return it->second; } } - return ret; + return nullptr; +} + +ModuleWrap* ModuleWrap::GetFromID(Environment* env, uint32_t id) { + auto module_wrap_it = env->id_to_module_map.find(id); + if (module_wrap_it == env->id_to_module_map.end()) { + return nullptr; + } + return module_wrap_it->second; } void ModuleWrap::New(const FunctionCallbackInfo& args) { @@ -126,6 +138,11 @@ void ModuleWrap::New(const FunctionCallbackInfo& args) { TryCatch try_catch(isolate); Local module; + Local host_defined_options = + PrimitiveArray::New(isolate, HostDefinedOptions::kLength); + host_defined_options->Set(isolate, HostDefinedOptions::kType, + Number::New(isolate, ScriptType::kModule)); + // compile { ScriptOrigin origin(url, @@ -136,7 +153,8 @@ void ModuleWrap::New(const FunctionCallbackInfo& args) { Local(), // source map URL False(isolate), // is opaque (?) False(isolate), // is WASM - True(isolate)); // is ES6 module + True(isolate), // is ES Module + host_defined_options); Context::Scope context_scope(context); ScriptCompiler::Source source(source_text, origin); if (!ScriptCompiler::CompileModule(isolate, &source).ToLocal(&module)) { @@ -157,7 +175,10 @@ void ModuleWrap::New(const FunctionCallbackInfo& args) { ModuleWrap* obj = new ModuleWrap(env, that, module, url); obj->context_.Reset(isolate, context); - env->module_map.emplace(module->GetIdentityHash(), obj); + env->hash_to_module_map.emplace(module->GetIdentityHash(), obj); + + host_defined_options->Set(isolate, HostDefinedOptions::kID, + Number::New(isolate, obj->id())); that->SetIntegrityLevel(context, IntegrityLevel::kFrozen); args.GetReturnValue().Set(that); @@ -364,19 +385,14 @@ MaybeLocal ModuleWrap::ResolveCallback(Local context, Environment* env = Environment::GetCurrent(context); CHECK_NOT_NULL(env); // TODO(addaleax): Handle nullptr here. Isolate* isolate = env->isolate(); - if (env->module_map.count(referrer->GetIdentityHash()) == 0) { - env->ThrowError("linking error, unknown module"); - return MaybeLocal(); - } ModuleWrap* dependent = GetFromModule(env, referrer); - if (dependent == nullptr) { env->ThrowError("linking error, null dep"); return MaybeLocal(); } - Utf8Value specifier_utf8(env->isolate(), specifier); + Utf8Value specifier_utf8(isolate, specifier); std::string specifier_std(*specifier_utf8, specifier_utf8.length()); if (dependent->resolve_cache_.count(specifier_std) != 1) { @@ -402,7 +418,7 @@ MaybeLocal ModuleWrap::ResolveCallback(Local context, ModuleWrap* module; ASSIGN_OR_RETURN_UNWRAP(&module, module_object, MaybeLocal()); - return module->module_.Get(env->isolate()); + return module->module_.Get(isolate); } namespace { @@ -703,35 +719,56 @@ static MaybeLocal ImportModuleDynamically( CHECK_NOT_NULL(env); // TODO(addaleax): Handle nullptr here. v8::EscapableHandleScope handle_scope(iso); - if (env->context() != context) { - auto maybe_resolver = Promise::Resolver::New(context); - Local resolver; - if (maybe_resolver.ToLocal(&resolver)) { - // TODO(jkrems): Turn into proper error object w/ code - Local error = v8::Exception::Error( - OneByteString(iso, "import() called outside of main context")); - if (resolver->Reject(context, error).IsJust()) { - return handle_scope.Escape(resolver.As()); - } - } - return MaybeLocal(); - } - Local import_callback = env->host_import_module_dynamically_callback(); + + Local options = referrer->GetHostDefinedOptions(); + if (options->Length() != HostDefinedOptions::kLength) { + Local resolver = + Promise::Resolver::New(context).ToLocalChecked(); + resolver + ->Reject(context, + v8::Exception::TypeError(FIXED_ONE_BYTE_STRING( + context->GetIsolate(), "Invalid host defined options"))) + .ToChecked(); + return handle_scope.Escape(resolver->GetPromise()); + } + + Local object; + + int type = options->Get(iso, HostDefinedOptions::kType) + .As() + ->Int32Value(context) + .ToChecked(); + uint32_t id = options->Get(iso, HostDefinedOptions::kID) + .As() + ->Uint32Value(context) + .ToChecked(); + if (type == ScriptType::kScript) { + contextify::ContextifyScript* wrap = env->id_to_script_map.find(id)->second; + object = wrap->object(); + } else if (type == ScriptType::kModule) { + ModuleWrap* wrap = ModuleWrap::GetFromID(env, id); + object = wrap->object(); + } else { + UNREACHABLE(); + } + Local import_args[] = { - referrer->GetResourceName(), - Local(specifier) + object, + Local(specifier), }; - MaybeLocal maybe_result = import_callback->Call(context, - v8::Undefined(iso), - 2, - import_args); Local result; - if (maybe_result.ToLocal(&result)) { + if (import_callback->Call( + context, + v8::Undefined(iso), + arraysize(import_args), + import_args).ToLocal(&result)) { + CHECK(result->IsPromise()); return handle_scope.Escape(result.As()); } + return MaybeLocal(); } diff --git a/src/module_wrap.h b/src/module_wrap.h index d6593c48135d18..0e352c657580e4 100644 --- a/src/module_wrap.h +++ b/src/module_wrap.h @@ -17,6 +17,17 @@ enum PackageMainCheck : bool { IgnoreMain = false }; +enum ScriptType : int { + kScript, + kModule, +}; + +enum HostDefinedOptions : int { + kType = 8, + kID = 9, + kLength = 10, +}; + v8::Maybe Resolve(Environment* env, const std::string& specifier, const url::URL& base, @@ -38,6 +49,9 @@ class ModuleWrap : public BaseObject { tracker->TrackField("resolve_cache", resolve_cache_); } + inline uint32_t id() { return id_; } + static ModuleWrap* GetFromID(node::Environment*, uint32_t id); + SET_MEMORY_INFO_NAME(ModuleWrap) SET_SELF_SIZE(ModuleWrap) @@ -69,12 +83,12 @@ class ModuleWrap : public BaseObject { v8::Local referrer); static ModuleWrap* GetFromModule(node::Environment*, v8::Local); - Persistent module_; Persistent url_; bool linked_ = false; std::unordered_map> resolve_cache_; Persistent context_; + uint32_t id_; }; } // namespace loader diff --git a/src/node_api.cc b/src/node_api.cc index 1f7b1405539e7b..98d13ff6008abf 100644 --- a/src/node_api.cc +++ b/src/node_api.cc @@ -369,6 +369,7 @@ class Finalizer { napi_finalize _finalize_callback; void* _finalize_data; void* _finalize_hint; + bool _finalize_ran = false; }; // Wrapper around node::Persistent that implements reference counting. @@ -412,8 +413,29 @@ class Reference : private Finalizer { finalize_hint); } + // Delete is called in 2 ways. Either from the finalizer or + // from one of Unwrap or napi_delete_reference. + // + // When it is called from Unwrap or napi_delete_reference we only + // want to do the delete if the finalizer has already run, + // otherwise we may crash when the finalizer does run. + // If the finalizer has not already run delay the delete until + // the finalizer runs by not doing the delete + // and setting _delete_self to true so that the finalizer will + // delete it when it runs. + // + // The second way this is called is from + // the finalizer and _delete_self is set. In this case we + // know we need to do the deletion so just do it. static void Delete(Reference* reference) { - delete reference; + if ((reference->_delete_self) || (reference->_finalize_ran)) { + delete reference; + } else { + // reduce the reference count to 0 and defer until + // finalizer runs + reference->_delete_self = true; + while (reference->Unref() != 0) {} + } } uint32_t Ref() { @@ -453,9 +475,6 @@ class Reference : private Finalizer { Reference* reference = data.GetParameter(); reference->_persistent.Reset(); - // Check before calling the finalize callback, because the callback might - // delete it. - bool delete_self = reference->_delete_self; napi_env env = reference->_env; if (reference->_finalize_callback != nullptr) { @@ -466,8 +485,13 @@ class Reference : private Finalizer { reference->_finalize_hint)); } - if (delete_self) { + // this is safe because if a request to delete the reference + // is made in the finalize_callback it will defer deletion + // to this block and set _delete_self to true + if (reference->_delete_self) { Delete(reference); + } else { + reference->_finalize_ran = true; } } diff --git a/src/node_contextify.cc b/src/node_contextify.cc index c99f6c7ea5aef5..a1903d9bd9b7e0 100644 --- a/src/node_contextify.cc +++ b/src/node_contextify.cc @@ -25,6 +25,7 @@ #include "node_contextify.h" #include "node_context_data.h" #include "node_errors.h" +#include "module_wrap.h" namespace node { namespace contextify { @@ -48,8 +49,10 @@ using v8::Maybe; using v8::MaybeLocal; using v8::Name; using v8::NamedPropertyHandlerConfiguration; +using v8::Number; using v8::Object; using v8::ObjectTemplate; +using v8::PrimitiveArray; using v8::PropertyAttribute; using v8::PropertyCallbackInfo; using v8::PropertyDescriptor; @@ -590,368 +593,381 @@ void ContextifyContext::IndexedPropertyDeleterCallback( args.GetReturnValue().Set(false); } -class ContextifyScript : public BaseObject { - private: - Persistent script_; - - public: - SET_NO_MEMORY_INFO() - SET_MEMORY_INFO_NAME(ContextifyScript) - SET_SELF_SIZE(ContextifyScript) - - static void Init(Environment* env, Local target) { - HandleScope scope(env->isolate()); - Local class_name = - FIXED_ONE_BYTE_STRING(env->isolate(), "ContextifyScript"); - - Local script_tmpl = env->NewFunctionTemplate(New); - script_tmpl->InstanceTemplate()->SetInternalFieldCount(1); - script_tmpl->SetClassName(class_name); - env->SetProtoMethod(script_tmpl, "createCachedData", CreateCachedData); - env->SetProtoMethod(script_tmpl, "runInContext", RunInContext); - env->SetProtoMethod(script_tmpl, "runInThisContext", RunInThisContext); - - target->Set(class_name, - script_tmpl->GetFunction(env->context()).ToLocalChecked()); - env->set_script_context_constructor_template(script_tmpl); - } - - - static void New(const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); - Isolate* isolate = env->isolate(); - Local context = env->context(); - - CHECK(args.IsConstructCall()); - - const int argc = args.Length(); - CHECK_GE(argc, 2); - - CHECK(args[0]->IsString()); - Local code = args[0].As(); - - CHECK(args[1]->IsString()); - Local filename = args[1].As(); - - Local line_offset; - Local column_offset; - Local cached_data_buf; - bool produce_cached_data = false; - Local parsing_context = context; - - if (argc > 2) { - // new ContextifyScript(code, filename, lineOffset, columnOffset, - // cachedData, produceCachedData, parsingContext) - CHECK_EQ(argc, 7); - CHECK(args[2]->IsNumber()); - line_offset = args[2].As(); - CHECK(args[3]->IsNumber()); - column_offset = args[3].As(); - if (!args[4]->IsUndefined()) { - CHECK(args[4]->IsUint8Array()); - cached_data_buf = args[4].As(); - } - CHECK(args[5]->IsBoolean()); - produce_cached_data = args[5]->IsTrue(); - if (!args[6]->IsUndefined()) { - CHECK(args[6]->IsObject()); - ContextifyContext* sandbox = - ContextifyContext::ContextFromContextifiedSandbox( - env, args[6].As()); - CHECK_NOT_NULL(sandbox); - parsing_context = sandbox->context(); - } - } else { - line_offset = Integer::New(isolate, 0); - column_offset = Integer::New(isolate, 0); - } - - ContextifyScript* contextify_script = - new ContextifyScript(env, args.This()); - - if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( - TRACING_CATEGORY_NODE2(vm, script)) != 0) { - Utf8Value fn(isolate, filename); - TRACE_EVENT_NESTABLE_ASYNC_BEGIN1( - TRACING_CATEGORY_NODE2(vm, script), - "ContextifyScript::New", - contextify_script, - "filename", TRACE_STR_COPY(*fn)); - } +void ContextifyScript::Init(Environment* env, Local target) { + HandleScope scope(env->isolate()); + Local class_name = + FIXED_ONE_BYTE_STRING(env->isolate(), "ContextifyScript"); + + Local script_tmpl = env->NewFunctionTemplate(New); + script_tmpl->InstanceTemplate()->SetInternalFieldCount(1); + script_tmpl->SetClassName(class_name); + env->SetProtoMethod(script_tmpl, "createCachedData", CreateCachedData); + env->SetProtoMethod(script_tmpl, "runInContext", RunInContext); + env->SetProtoMethod(script_tmpl, "runInThisContext", RunInThisContext); + + target->Set(class_name, + script_tmpl->GetFunction(env->context()).ToLocalChecked()); + env->set_script_context_constructor_template(script_tmpl); +} - ScriptCompiler::CachedData* cached_data = nullptr; - if (!cached_data_buf.IsEmpty()) { - ArrayBuffer::Contents contents = cached_data_buf->Buffer()->GetContents(); - uint8_t* data = static_cast(contents.Data()); - cached_data = new ScriptCompiler::CachedData( - data + cached_data_buf->ByteOffset(), cached_data_buf->ByteLength()); - } +void ContextifyScript::New(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + Isolate* isolate = env->isolate(); + Local context = env->context(); - ScriptOrigin origin(filename, line_offset, column_offset); - ScriptCompiler::Source source(code, origin, cached_data); - ScriptCompiler::CompileOptions compile_options = - ScriptCompiler::kNoCompileOptions; + CHECK(args.IsConstructCall()); - if (source.GetCachedData() != nullptr) - compile_options = ScriptCompiler::kConsumeCodeCache; + const int argc = args.Length(); + CHECK_GE(argc, 2); - TryCatch try_catch(isolate); - Environment::ShouldNotAbortOnUncaughtScope no_abort_scope(env); - Context::Scope scope(parsing_context); + CHECK(args[0]->IsString()); + Local code = args[0].As(); - MaybeLocal v8_script = ScriptCompiler::CompileUnboundScript( - isolate, - &source, - compile_options); + CHECK(args[1]->IsString()); + Local filename = args[1].As(); - if (v8_script.IsEmpty()) { - DecorateErrorStack(env, try_catch); - no_abort_scope.Close(); - try_catch.ReThrow(); - TRACE_EVENT_NESTABLE_ASYNC_END0( - TRACING_CATEGORY_NODE2(vm, script), - "ContextifyScript::New", - contextify_script); - return; + Local line_offset; + Local column_offset; + Local cached_data_buf; + bool produce_cached_data = false; + Local parsing_context = context; + + if (argc > 2) { + // new ContextifyScript(code, filename, lineOffset, columnOffset, + // cachedData, produceCachedData, parsingContext) + CHECK_EQ(argc, 7); + CHECK(args[2]->IsNumber()); + line_offset = args[2].As(); + CHECK(args[3]->IsNumber()); + column_offset = args[3].As(); + if (!args[4]->IsUndefined()) { + CHECK(args[4]->IsUint8Array()); + cached_data_buf = args[4].As(); } - contextify_script->script_.Reset(isolate, v8_script.ToLocalChecked()); - - if (compile_options == ScriptCompiler::kConsumeCodeCache) { - args.This()->Set( - env->cached_data_rejected_string(), - Boolean::New(isolate, source.GetCachedData()->rejected)); - } else if (produce_cached_data) { - const ScriptCompiler::CachedData* cached_data = - ScriptCompiler::CreateCodeCache(v8_script.ToLocalChecked()); - bool cached_data_produced = cached_data != nullptr; - if (cached_data_produced) { - MaybeLocal buf = Buffer::Copy( - env, - reinterpret_cast(cached_data->data), - cached_data->length); - args.This()->Set(env->cached_data_string(), buf.ToLocalChecked()); - } - args.This()->Set( - env->cached_data_produced_string(), - Boolean::New(isolate, cached_data_produced)); + CHECK(args[5]->IsBoolean()); + produce_cached_data = args[5]->IsTrue(); + if (!args[6]->IsUndefined()) { + CHECK(args[6]->IsObject()); + ContextifyContext* sandbox = + ContextifyContext::ContextFromContextifiedSandbox( + env, args[6].As()); + CHECK_NOT_NULL(sandbox); + parsing_context = sandbox->context(); } - TRACE_EVENT_NESTABLE_ASYNC_END0( + } else { + line_offset = Integer::New(isolate, 0); + column_offset = Integer::New(isolate, 0); + } + + ContextifyScript* contextify_script = + new ContextifyScript(env, args.This()); + + if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( + TRACING_CATEGORY_NODE2(vm, script)) != 0) { + Utf8Value fn(isolate, filename); + TRACE_EVENT_NESTABLE_ASYNC_BEGIN1( TRACING_CATEGORY_NODE2(vm, script), "ContextifyScript::New", - contextify_script); + contextify_script, + "filename", TRACE_STR_COPY(*fn)); } - - static bool InstanceOf(Environment* env, const Local& value) { - return !value.IsEmpty() && - env->script_context_constructor_template()->HasInstance(value); + ScriptCompiler::CachedData* cached_data = nullptr; + if (!cached_data_buf.IsEmpty()) { + ArrayBuffer::Contents contents = cached_data_buf->Buffer()->GetContents(); + uint8_t* data = static_cast(contents.Data()); + cached_data = new ScriptCompiler::CachedData( + data + cached_data_buf->ByteOffset(), cached_data_buf->ByteLength()); } + Local host_defined_options = + PrimitiveArray::New(isolate, loader::HostDefinedOptions::kLength); + host_defined_options->Set(isolate, loader::HostDefinedOptions::kType, + Number::New(isolate, loader::ScriptType::kScript)); + host_defined_options->Set(isolate, loader::HostDefinedOptions::kID, + Number::New(isolate, contextify_script->id())); + + ScriptOrigin origin(filename, + line_offset, // line offset + column_offset, // column offset + False(isolate), // is cross origin + Local(), // script id + Local(), // source map URL + False(isolate), // is opaque (?) + False(isolate), // is WASM + False(isolate), // is ES Module + host_defined_options); + ScriptCompiler::Source source(code, origin, cached_data); + ScriptCompiler::CompileOptions compile_options = + ScriptCompiler::kNoCompileOptions; - static void CreateCachedData(const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); - ContextifyScript* wrapped_script; - ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder()); - Local unbound_script = - PersistentToLocal(env->isolate(), wrapped_script->script_); - std::unique_ptr cached_data( - ScriptCompiler::CreateCodeCache(unbound_script)); - if (!cached_data) { - args.GetReturnValue().Set(Buffer::New(env, 0).ToLocalChecked()); - } else { + if (source.GetCachedData() != nullptr) + compile_options = ScriptCompiler::kConsumeCodeCache; + + TryCatch try_catch(isolate); + Environment::ShouldNotAbortOnUncaughtScope no_abort_scope(env); + Context::Scope scope(parsing_context); + + MaybeLocal v8_script = ScriptCompiler::CompileUnboundScript( + isolate, + &source, + compile_options); + + if (v8_script.IsEmpty()) { + DecorateErrorStack(env, try_catch); + no_abort_scope.Close(); + try_catch.ReThrow(); + TRACE_EVENT_NESTABLE_ASYNC_END0( + TRACING_CATEGORY_NODE2(vm, script), + "ContextifyScript::New", + contextify_script); + return; + } + contextify_script->script_.Reset(isolate, v8_script.ToLocalChecked()); + + if (compile_options == ScriptCompiler::kConsumeCodeCache) { + args.This()->Set( + env->cached_data_rejected_string(), + Boolean::New(isolate, source.GetCachedData()->rejected)); + } else if (produce_cached_data) { + const ScriptCompiler::CachedData* cached_data = + ScriptCompiler::CreateCodeCache(v8_script.ToLocalChecked()); + bool cached_data_produced = cached_data != nullptr; + if (cached_data_produced) { MaybeLocal buf = Buffer::Copy( env, reinterpret_cast(cached_data->data), cached_data->length); - args.GetReturnValue().Set(buf.ToLocalChecked()); + args.This()->Set(env->cached_data_string(), buf.ToLocalChecked()); } + args.This()->Set( + env->cached_data_produced_string(), + Boolean::New(isolate, cached_data_produced)); } + TRACE_EVENT_NESTABLE_ASYNC_END0( + TRACING_CATEGORY_NODE2(vm, script), + "ContextifyScript::New", + contextify_script); +} +bool ContextifyScript::InstanceOf(Environment* env, + const Local& value) { + return !value.IsEmpty() && + env->script_context_constructor_template()->HasInstance(value); +} - static void RunInThisContext(const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); +void ContextifyScript::CreateCachedData( + const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + ContextifyScript* wrapped_script; + ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder()); + Local unbound_script = + PersistentToLocal(env->isolate(), wrapped_script->script_); + std::unique_ptr cached_data( + ScriptCompiler::CreateCodeCache(unbound_script)); + if (!cached_data) { + args.GetReturnValue().Set(Buffer::New(env, 0).ToLocalChecked()); + } else { + MaybeLocal buf = Buffer::Copy( + env, + reinterpret_cast(cached_data->data), + cached_data->length); + args.GetReturnValue().Set(buf.ToLocalChecked()); + } +} - ContextifyScript* wrapped_script; - ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder()); +void ContextifyScript::RunInThisContext( + const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); - TRACE_EVENT_NESTABLE_ASYNC_BEGIN0( - TRACING_CATEGORY_NODE2(vm, script), "RunInThisContext", wrapped_script); + ContextifyScript* wrapped_script; + ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder()); - CHECK_EQ(args.Length(), 3); + TRACE_EVENT_NESTABLE_ASYNC_BEGIN0( + TRACING_CATEGORY_NODE2(vm, script), "RunInThisContext", wrapped_script); - CHECK(args[0]->IsNumber()); - int64_t timeout = args[0]->IntegerValue(env->context()).FromJust(); + CHECK_EQ(args.Length(), 3); - CHECK(args[1]->IsBoolean()); - bool display_errors = args[1]->IsTrue(); + CHECK(args[0]->IsNumber()); + int64_t timeout = args[0]->IntegerValue(env->context()).FromJust(); - CHECK(args[2]->IsBoolean()); - bool break_on_sigint = args[2]->IsTrue(); + CHECK(args[1]->IsBoolean()); + bool display_errors = args[1]->IsTrue(); - // Do the eval within this context - EvalMachine(env, timeout, display_errors, break_on_sigint, args); + CHECK(args[2]->IsBoolean()); + bool break_on_sigint = args[2]->IsTrue(); - TRACE_EVENT_NESTABLE_ASYNC_END0( - TRACING_CATEGORY_NODE2(vm, script), "RunInThisContext", wrapped_script); - } + // Do the eval within this context + EvalMachine(env, timeout, display_errors, break_on_sigint, args); - static void RunInContext(const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); + TRACE_EVENT_NESTABLE_ASYNC_END0( + TRACING_CATEGORY_NODE2(vm, script), "RunInThisContext", wrapped_script); +} - ContextifyScript* wrapped_script; - ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder()); +void ContextifyScript::RunInContext(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); - CHECK_EQ(args.Length(), 4); + ContextifyScript* wrapped_script; + ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder()); - CHECK(args[0]->IsObject()); - Local sandbox = args[0].As(); - // Get the context from the sandbox - ContextifyContext* contextify_context = - ContextifyContext::ContextFromContextifiedSandbox(env, sandbox); - CHECK_NOT_NULL(contextify_context); + CHECK_EQ(args.Length(), 4); - if (contextify_context->context().IsEmpty()) - return; + CHECK(args[0]->IsObject()); + Local sandbox = args[0].As(); + // Get the context from the sandbox + ContextifyContext* contextify_context = + ContextifyContext::ContextFromContextifiedSandbox(env, sandbox); + CHECK_NOT_NULL(contextify_context); - TRACE_EVENT_NESTABLE_ASYNC_BEGIN0( - TRACING_CATEGORY_NODE2(vm, script), "RunInContext", wrapped_script); + if (contextify_context->context().IsEmpty()) + return; - CHECK(args[1]->IsNumber()); - int64_t timeout = args[1]->IntegerValue(env->context()).FromJust(); + TRACE_EVENT_NESTABLE_ASYNC_BEGIN0( + TRACING_CATEGORY_NODE2(vm, script), "RunInContext", wrapped_script); - CHECK(args[2]->IsBoolean()); - bool display_errors = args[2]->IsTrue(); + CHECK(args[1]->IsNumber()); + int64_t timeout = args[1]->IntegerValue(env->context()).FromJust(); - CHECK(args[3]->IsBoolean()); - bool break_on_sigint = args[3]->IsTrue(); + CHECK(args[2]->IsBoolean()); + bool display_errors = args[2]->IsTrue(); - // Do the eval within the context - Context::Scope context_scope(contextify_context->context()); - EvalMachine(contextify_context->env(), - timeout, - display_errors, - break_on_sigint, - args); + CHECK(args[3]->IsBoolean()); + bool break_on_sigint = args[3]->IsTrue(); + + // Do the eval within the context + Context::Scope context_scope(contextify_context->context()); + EvalMachine(contextify_context->env(), + timeout, + display_errors, + break_on_sigint, + args); + + TRACE_EVENT_NESTABLE_ASYNC_END0( + TRACING_CATEGORY_NODE2(vm, script), "RunInContext", wrapped_script); +} - TRACE_EVENT_NESTABLE_ASYNC_END0( - TRACING_CATEGORY_NODE2(vm, script), "RunInContext", wrapped_script); - } +void ContextifyScript::DecorateErrorStack( + Environment* env, const TryCatch& try_catch) { + Local exception = try_catch.Exception(); - static void DecorateErrorStack(Environment* env, const TryCatch& try_catch) { - Local exception = try_catch.Exception(); + if (!exception->IsObject()) + return; - if (!exception->IsObject()) - return; + Local err_obj = exception.As(); - Local err_obj = exception.As(); + if (IsExceptionDecorated(env, err_obj)) + return; - if (IsExceptionDecorated(env, err_obj)) - return; + AppendExceptionLine(env, exception, try_catch.Message(), CONTEXTIFY_ERROR); + Local stack = err_obj->Get(env->stack_string()); + MaybeLocal maybe_value = + err_obj->GetPrivate( + env->context(), + env->arrow_message_private_symbol()); - AppendExceptionLine(env, exception, try_catch.Message(), CONTEXTIFY_ERROR); - Local stack = err_obj->Get(env->stack_string()); - MaybeLocal maybe_value = - err_obj->GetPrivate( - env->context(), - env->arrow_message_private_symbol()); + Local arrow; + if (!(maybe_value.ToLocal(&arrow) && arrow->IsString())) { + return; + } - Local arrow; - if (!(maybe_value.ToLocal(&arrow) && arrow->IsString())) { - return; - } + if (stack.IsEmpty() || !stack->IsString()) { + return; + } - if (stack.IsEmpty() || !stack->IsString()) { - return; - } + Local decorated_stack = String::Concat( + env->isolate(), + String::Concat(env->isolate(), + arrow.As(), + FIXED_ONE_BYTE_STRING(env->isolate(), "\n")), + stack.As()); + err_obj->Set(env->stack_string(), decorated_stack); + err_obj->SetPrivate( + env->context(), + env->decorated_private_symbol(), + True(env->isolate())); +} - Local decorated_stack = String::Concat( - env->isolate(), - String::Concat(env->isolate(), - arrow.As(), - FIXED_ONE_BYTE_STRING(env->isolate(), "\n")), - stack.As()); - err_obj->Set(env->stack_string(), decorated_stack); - err_obj->SetPrivate( - env->context(), - env->decorated_private_symbol(), - True(env->isolate())); +bool ContextifyScript::EvalMachine(Environment* env, + const int64_t timeout, + const bool display_errors, + const bool break_on_sigint, + const FunctionCallbackInfo& args) { + if (!env->can_call_into_js()) + return false; + if (!ContextifyScript::InstanceOf(env, args.Holder())) { + env->ThrowTypeError( + "Script methods can only be called on script instances."); + return false; + } + TryCatch try_catch(env->isolate()); + ContextifyScript* wrapped_script; + ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder(), false); + Local unbound_script = + PersistentToLocal(env->isolate(), wrapped_script->script_); + Local