diff --git a/.mailmap b/.mailmap index 4a42b718f44a8e..4a2bdf086fb8dd 100644 --- a/.mailmap +++ b/.mailmap @@ -547,6 +547,7 @@ Viero Fernando <60427892+vierofernando@users.noreply. Viktor Karpov Vincent Voyer Vladimir de Turckheim +Vladimir de Turckheim vsemozhetbyt Vyacheslav Egorov Wang Xinyong diff --git a/AUTHORS b/AUTHORS index 9d96d37984ca38..fd7efde7278c32 100644 --- a/AUTHORS +++ b/AUTHORS @@ -3552,5 +3552,8 @@ Anjana Krishnakumar Vellore <54228505+anjanakvellore@users.noreply.github.com> mmeenapriya <42589859+mmeenapriya@users.noreply.github.com> Chandana <100327450+chanduMe@users.noreply.github.com> pete3249 <63552971+pete3249@users.noreply.github.com> +Bruno Pitrus +Manuel Spigolon +Lorand Horvath <72015221+lorand-horvath@users.noreply.github.com> # Generated by tools/update-authors.mjs diff --git a/BUILDING.md b/BUILDING.md index 526df5b519df86..0dd95488013174 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -660,7 +660,7 @@ Be sure you have downloaded and extracted a folder. Then run: ```console -$ source ./android-configure /path/to/your/android-ndk target_arch android_sdk_version +$ ./android-configure $ make -j4 ``` @@ -1053,6 +1053,44 @@ To make `./myModule.js` available via `require('myModule')` and > .\vcbuild link-module './myModule.js' link-module './myModule2.js' ``` +## Building to use shared dependencies at runtime + +By default Node.js is built so that all dependencies are bundled into +the Node.js binary itself. This provides a single binary that includes +the correct versions of all dependencies on which it depends. + +Some Node.js distributions, however, prefer to manage dependencies. +A number of `configure` options are provided to support this use case. + +* For dependencies with native code, the first set of options allow + Node.js to be built so that it uses a shared library + at runtime instead of building and including the dependency + in the Node.js binary itself. These options are in the + `Shared libraries` section of the `configure` help + (run `./configure --help` to get the complete list). + They provide the ability to enable the use of a shared library, + to set the name of the shared library, and to set the paths that + contain the include and shared library files. + +* For dependencies with JavaScript code (including WASM), the second + set of options allow the Node.js binary to be built so that it loads + the JavaScript for dependencies at runtime instead of being built into + the Node.js binary itself. These options are in the `Shared builtins` + section of the `configure` help + (run `./configure --help` to get the complete list). They + provide the ability to set the path to an external JavaScript file + for the dependency to be used at runtime. + +It is the responsibility of any distribution +shipping with these options to: + +* ensure that the shared dependencies available at runtime + match what is expected by the Node.js binary. A + mismatch may result in crashes or unexpected behavior. +* fully test that Node.js operates as expected with the + external dependencies. There may be little or no test coverage + within the Node.js project CI for these non-default options. + ## Note for downstream distributors of Node.js The Node.js ecosystem is reliant on ABI compatibility within a major release. diff --git a/README.md b/README.md index cea0ff25e0d68c..abe2f6d8102132 100644 --- a/README.md +++ b/README.md @@ -110,7 +110,7 @@ For Current and LTS, the GPG detached signature of `SHASUMS256.txt` is in import the keys: ```console -$ gpg --keyserver hkps://keys.openpgp.org --recv-keys DD8F2338BAE7501E3DD5AC78C273792F7D83545D +$ gpg --keyserver hkps://keys.openpgp.org --recv-keys 4ED778F539E3634C779C87C6D7062848A1AB005C ``` See [Release keys](#release-keys) for a script to import active release keys. @@ -695,12 +695,8 @@ Primary GPG keys for Node.js Releasers (some Releasers sign with subkeys): `4ED778F539E3634C779C87C6D7062848A1AB005C` * **Bryan English** <> `141F07595B7B3FFE74309A937405533BE57C7D57` -* **Colin Ihrig** <> - `94AE36675C464D64BAFA68DD7434390BDBE9B9C5` * **Danielle Adams** <> `74F12602B6F1C4E913FAA37AD3A89613643B6201` -* **James M Snell** <> - `71DCFD284A79C3B38668286BC97EC7A07EDE3FC1` * **Juan José Arboleda** <> `61FC681DFB92A079F1685E77973F295594EC4689` * **Michaël Zasso** <> @@ -711,14 +707,8 @@ Primary GPG keys for Node.js Releasers (some Releasers sign with subkeys): `890C08DB8579162FEE0DF9DB8BEAB4DFCF555EF4` * **Richard Lau** <> `C82FA3AE1CBEDC6BE46B9360C43CEC45C17AB93C` -* **Rod Vagg** <> - `DD8F2338BAE7501E3DD5AC78C273792F7D83545D` -* **Ruben Bridgewater** <> - `A48C2BEE680E841632CD4E44F07496B3EB3C1762` * **Ruy Adorno** <> `108F52B48DB57BB0CC439B2997B01419BD92F80A` -* **Shelley Vohr** <> - `B9E2F5981AA6E0CD28160D9FF13993A75599653C` To import the full set of trusted release keys (including subkeys possibly used to sign releases): @@ -726,18 +716,13 @@ to sign releases): ```bash gpg --keyserver hkps://keys.openpgp.org --recv-keys 4ED778F539E3634C779C87C6D7062848A1AB005C gpg --keyserver hkps://keys.openpgp.org --recv-keys 141F07595B7B3FFE74309A937405533BE57C7D57 -gpg --keyserver hkps://keys.openpgp.org --recv-keys 94AE36675C464D64BAFA68DD7434390BDBE9B9C5 gpg --keyserver hkps://keys.openpgp.org --recv-keys 74F12602B6F1C4E913FAA37AD3A89613643B6201 -gpg --keyserver hkps://keys.openpgp.org --recv-keys 71DCFD284A79C3B38668286BC97EC7A07EDE3FC1 gpg --keyserver hkps://keys.openpgp.org --recv-keys 61FC681DFB92A079F1685E77973F295594EC4689 gpg --keyserver hkps://keys.openpgp.org --recv-keys 8FCCA13FEF1D0C2E91008E09770F7A9A5AE15600 gpg --keyserver hkps://keys.openpgp.org --recv-keys C4F0DFFF4E8C1A8236409D08E73BC641CC11F4C8 gpg --keyserver hkps://keys.openpgp.org --recv-keys 890C08DB8579162FEE0DF9DB8BEAB4DFCF555EF4 gpg --keyserver hkps://keys.openpgp.org --recv-keys C82FA3AE1CBEDC6BE46B9360C43CEC45C17AB93C -gpg --keyserver hkps://keys.openpgp.org --recv-keys DD8F2338BAE7501E3DD5AC78C273792F7D83545D -gpg --keyserver hkps://keys.openpgp.org --recv-keys A48C2BEE680E841632CD4E44F07496B3EB3C1762 gpg --keyserver hkps://keys.openpgp.org --recv-keys 108F52B48DB57BB0CC439B2997B01419BD92F80A -gpg --keyserver hkps://keys.openpgp.org --recv-keys B9E2F5981AA6E0CD28160D9FF13993A75599653C ``` See [Verifying binaries](#verifying-binaries) for how to use these keys to @@ -749,6 +734,8 @@ verify a downloaded file. * **Chris Dickinson** <> `9554F04D7259F04124DE6B476D5A82AC7E37093B` +* **Colin Ihrig** <> + `94AE36675C464D64BAFA68DD7434390BDBE9B9C5` * **Danielle Adams** <> `1C050899334244A8AF75E53792EF661D867B9DFA` * **Evan Lucas** <> @@ -759,10 +746,18 @@ verify a downloaded file. `93C7E9E91B49E432C2F75674B0A78B0A6C481CF6` * **Italo A. Casas** <> `56730D5401028683275BD23C23EFEFE93C4CFFFE` +* **James M Snell** <> + `71DCFD284A79C3B38668286BC97EC7A07EDE3FC1` * **Jeremiah Senkpiel** <> `FD3A5288F042B6850C66B31F09FE44734EB7990E` * **Julien Gilli** <> `114F43EE0176B71C7BC219DD50A3051F888C628D` +* **Rod Vagg** <> + `DD8F2338BAE7501E3DD5AC78C273792F7D83545D` +* **Ruben Bridgewater** <> + `A48C2BEE680E841632CD4E44F07496B3EB3C1762` +* **Shelley Vohr** <> + `B9E2F5981AA6E0CD28160D9FF13993A75599653C` * **Timothy J Fontaine** <> `7937DFD2AB06298B2293C3187D33FF9D0246406D` diff --git a/benchmark/fs/readfile-promises.js b/benchmark/fs/readfile-promises.js index 0fa92fdffad78d..af14509e710f7a 100644 --- a/benchmark/fs/readfile-promises.js +++ b/benchmark/fs/readfile-promises.js @@ -16,7 +16,14 @@ const filename = path.resolve(tmpdir.path, const bench = common.createBenchmark(main, { duration: [5], encoding: ['', 'utf-8'], - len: [1024, 16 * 1024 * 1024], + len: [ + 1024, + 512 * 1024, + 4 * 1024 ** 2, + 8 * 1024 ** 2, + 16 * 1024 ** 2, + 32 * 1024 ** 2, + ], concurrent: [1, 10] }); diff --git a/benchmark/vm/context-global-proxy.js b/benchmark/vm/context-global-proxy.js new file mode 100644 index 00000000000000..3f461671b195e1 --- /dev/null +++ b/benchmark/vm/context-global-proxy.js @@ -0,0 +1,21 @@ +'use strict'; + +const common = require('../common.js'); + +const bench = common.createBenchmark(main, { + n: [100000], +}); + +const vm = require('vm'); +const script = new vm.Script(` + globalThis.foo++; +`); +const context = vm.createContext({ foo: 1 }); + +function main({ n }) { + bench.start(); + for (let i = 0; i < n; i++) { + script.runInContext(context); + } + bench.end(n); +} diff --git a/common.gypi b/common.gypi index 3f708d89b1ef38..5f629c49634b2c 100644 --- a/common.gypi +++ b/common.gypi @@ -36,7 +36,7 @@ # Reset this number to 0 on major V8 upgrades. # Increment by one for each non-official patch applied to deps/v8. - 'v8_embedder_string': '-node.12', + 'v8_embedder_string': '-node.11', ##### V8 defaults for Node.js ##### diff --git a/configure.py b/configure.py index a2fc6d5c5a27e0..b6415c38c808ab 100755 --- a/configure.py +++ b/configure.py @@ -57,6 +57,11 @@ with open ('tools/icu/icu_versions.json') as f: icu_versions = json.load(f) +shareable_builtins = {'cjs_module_lexer/lexer': 'deps/cjs-module-lexer/lexer.js', + 'cjs_module_lexer/dist/lexer': 'deps/cjs-module-lexer/dist/lexer.js', + 'undici/undici': 'deps/undici/undici.js' +} + # create option groups shared_optgroup = parser.add_argument_group("Shared libraries", "Flags that allows you to control whether you want to build against " @@ -70,6 +75,9 @@ "library you want to build against.") http2_optgroup = parser.add_argument_group("HTTP2", "Flags that allows you to control HTTP2 features in Node.js") +shared_builtin_optgroup = parser.add_argument_group("Shared builtins", + "Flags that allows you to control whether you want to build against " + "internal builtins or shared files.") # Options should be in alphabetical order but keep --prefix at the top, # that's arguably the one people will be looking for most. @@ -422,6 +430,16 @@ parser.add_argument_group(shared_optgroup) +for builtin in shareable_builtins: + builtin_id = 'shared_builtin_' + builtin + '_path' + shared_builtin_optgroup.add_argument('--shared-builtin-' + builtin + '-path', + action='store', + dest='node_shared_builtin_' + builtin.replace('/', '_') + '_path', + help='Path to shared file for ' + builtin + ' builtin. ' + 'Will be used instead of bundled version at runtime') + +parser.add_argument_group(shared_builtin_optgroup) + static_optgroup.add_argument('--static-zoslib-gyp', action='store', dest='static_zoslib_gyp', @@ -1960,6 +1978,19 @@ def make_bin_override(): configure_inspector(output) configure_section_file(output) +# configure shareable builtins +output['variables']['node_builtin_shareable_builtins'] = [] +for builtin in shareable_builtins: + builtin_id = 'node_shared_builtin_' + builtin.replace('/', '_') + '_path' + if getattr(options, builtin_id): + if options.with_intl == 'none': + option_name = '--shared-builtin-' + builtin + '-path' + error(option_name + ' is incompatible with --with-intl=none' ) + else: + output['defines'] += [builtin_id.upper() + '=' + getattr(options, builtin_id)] + else: + output['variables']['node_builtin_shareable_builtins'] += [shareable_builtins[builtin]] + # Forward OSS-Fuzz settings output['variables']['ossfuzz'] = b(options.ossfuzz) diff --git a/deps/corepack/CHANGELOG.md b/deps/corepack/CHANGELOG.md index 8bfc7c0f5142d6..8b66751f0f4b7a 100644 --- a/deps/corepack/CHANGELOG.md +++ b/deps/corepack/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [0.14.2](https://github.com/nodejs/corepack/compare/v0.14.1...v0.14.2) (2022-09-24) + +### Features + +* update package manager versions ([#184](https://github.com/nodejs/corepack/issues/184)) ([84ae313](https://github.com/nodejs/corepack/commit/84ae3139e4b9a86d97465e36b50beb9201fda732)) + ## [0.14.1](https://github.com/nodejs/corepack/compare/v0.14.0...v0.14.1) (2022-09-16) diff --git a/deps/corepack/dist/corepack.js b/deps/corepack/dist/corepack.js index 923b26744f498c..aff9562e4e4187 100755 --- a/deps/corepack/dist/corepack.js +++ b/deps/corepack/dist/corepack.js @@ -17027,7 +17027,7 @@ const supportsColor = { /***/ ((module) => { "use strict"; -module.exports = JSON.parse('{"definitions":{"npm":{"default":"8.19.2+sha1.db90e88584d065f51b069ab46b4f02f5cf4898b7","fetchLatestFrom":{"type":"npm","package":"npm"},"transparent":{"commands":[["npm","init"],["npx"]]},"ranges":{"*":{"url":"https://registry.npmjs.org/npm/-/npm-{}.tgz","bin":{"npm":"./bin/npm-cli.js","npx":"./bin/npx-cli.js"},"registry":{"type":"npm","package":"npm"}}}},"pnpm":{"default":"7.11.0+sha1.ae48bcb805080989f94fe5dca372013c9ae517e7","fetchLatestFrom":{"type":"npm","package":"pnpm"},"transparent":{"commands":[["pnpm","init"],["pnpx"],["pnpm","dlx"]]},"ranges":{"<6.0.0":{"url":"https://registry.npmjs.org/pnpm/-/pnpm-{}.tgz","bin":{"pnpm":"./bin/pnpm.js","pnpx":"./bin/pnpx.js"},"registry":{"type":"npm","package":"pnpm"}},">=6.0.0":{"url":"https://registry.npmjs.org/pnpm/-/pnpm-{}.tgz","bin":{"pnpm":"./bin/pnpm.cjs","pnpx":"./bin/pnpx.cjs"},"registry":{"type":"npm","package":"pnpm"}}}},"yarn":{"default":"1.22.19+sha1.4ba7fc5c6e704fce2066ecbfb0b0d8976fe62447","fetchLatestFrom":{"type":"npm","package":"yarn"},"transparent":{"default":"3.2.3+sha224.953c8233f7a92884eee2de69a1b92d1f2ec1655e66d08071ba9a02fa","commands":[["yarn","dlx"]]},"ranges":{"<2.0.0":{"url":"https://registry.yarnpkg.com/yarn/-/yarn-{}.tgz","bin":{"yarn":"./bin/yarn.js","yarnpkg":"./bin/yarn.js"},"registry":{"type":"npm","package":"yarn"}},">=2.0.0":{"name":"yarn","url":"https://repo.yarnpkg.com/{}/packages/yarnpkg-cli/bin/yarn.js","bin":["yarn","yarnpkg"],"registry":{"type":"url","url":"https://repo.yarnpkg.com/tags","fields":{"tags":"latest","versions":"tags"}}}}}}}'); +module.exports = JSON.parse('{"definitions":{"npm":{"default":"8.19.2+sha1.db90e88584d065f51b069ab46b4f02f5cf4898b7","fetchLatestFrom":{"type":"npm","package":"npm"},"transparent":{"commands":[["npm","init"],["npx"]]},"ranges":{"*":{"url":"https://registry.npmjs.org/npm/-/npm-{}.tgz","bin":{"npm":"./bin/npm-cli.js","npx":"./bin/npx-cli.js"},"registry":{"type":"npm","package":"npm"}}}},"pnpm":{"default":"7.12.2+sha1.9908aafac1fa95c4d09f6f4916e98440804dd203","fetchLatestFrom":{"type":"npm","package":"pnpm"},"transparent":{"commands":[["pnpm","init"],["pnpx"],["pnpm","dlx"]]},"ranges":{"<6.0.0":{"url":"https://registry.npmjs.org/pnpm/-/pnpm-{}.tgz","bin":{"pnpm":"./bin/pnpm.js","pnpx":"./bin/pnpx.js"},"registry":{"type":"npm","package":"pnpm"}},">=6.0.0":{"url":"https://registry.npmjs.org/pnpm/-/pnpm-{}.tgz","bin":{"pnpm":"./bin/pnpm.cjs","pnpx":"./bin/pnpx.cjs"},"registry":{"type":"npm","package":"pnpm"}}}},"yarn":{"default":"1.22.19+sha1.4ba7fc5c6e704fce2066ecbfb0b0d8976fe62447","fetchLatestFrom":{"type":"npm","package":"yarn"},"transparent":{"default":"3.2.3+sha224.953c8233f7a92884eee2de69a1b92d1f2ec1655e66d08071ba9a02fa","commands":[["yarn","dlx"]]},"ranges":{"<2.0.0":{"url":"https://registry.yarnpkg.com/yarn/-/yarn-{}.tgz","bin":{"yarn":"./bin/yarn.js","yarnpkg":"./bin/yarn.js"},"registry":{"type":"npm","package":"yarn"}},">=2.0.0":{"name":"yarn","url":"https://repo.yarnpkg.com/{}/packages/yarnpkg-cli/bin/yarn.js","bin":["yarn","yarnpkg"],"registry":{"type":"url","url":"https://repo.yarnpkg.com/tags","fields":{"tags":"latest","versions":"tags"}}}}}}}'); /***/ }), @@ -17038,7 +17038,7 @@ module.exports = JSON.parse('{"definitions":{"npm":{"default":"8.19.2+sha1.db90e /***/ ((module) => { "use strict"; -module.exports = JSON.parse('{"name":"corepack","version":"0.14.1","homepage":"https://github.com/nodejs/corepack#readme","bugs":{"url":"https://github.com/nodejs/corepack/issues"},"repository":{"type":"git","url":"https://github.com/nodejs/corepack.git"},"license":"MIT","packageManager":"yarn@4.0.0-rc.15+sha224.7fa5c1d1875b041cea8fcbf9a364667e398825364bf5c5c8cd5f6601","devDependencies":{"@babel/core":"^7.14.3","@babel/plugin-transform-modules-commonjs":"^7.14.0","@babel/preset-typescript":"^7.13.0","@types/debug":"^4.1.5","@types/jest":"^29.0.0","@types/node":"^18.0.0","@types/semver":"^7.1.0","@types/tar":"^6.0.0","@types/which":"^2.0.0","@typescript-eslint/eslint-plugin":"^5.0.0","@typescript-eslint/parser":"^5.0.0","@yarnpkg/eslint-config":"^1.0.0-rc.5","@yarnpkg/fslib":"^2.1.0","@zkochan/cmd-shim":"^5.0.0","babel-plugin-dynamic-import-node":"^2.3.3","clipanion":"^3.0.1","debug":"^4.1.1","eslint":"^8.0.0","eslint-plugin-arca":"^0.15.0","jest":"^29.0.0","nock":"^13.0.4","proxy-agent":"^5.0.0","semver":"^7.1.3","supports-color":"^9.0.0","tar":"^6.0.1","terser-webpack-plugin":"^5.1.2","ts-loader":"^9.0.0","ts-node":"^10.0.0","typescript":"^4.3.2","v8-compile-cache":"^2.3.0","webpack":"^5.38.1","webpack-cli":"^4.0.0","which":"^2.0.2"},"scripts":{"build":"rm -rf dist shims && webpack && ts-node ./mkshims.ts","corepack":"ts-node ./sources/_entryPoint.ts","lint":"yarn eslint","prepack":"yarn build","postpack":"rm -rf dist shims","typecheck":"tsc --noEmit","test":"yarn jest"},"files":["dist","shims","LICENSE.md"],"publishConfig":{"bin":{"corepack":"./dist/corepack.js","pnpm":"./dist/pnpm.js","pnpx":"./dist/pnpx.js","yarn":"./dist/yarn.js","yarnpkg":"./dist/yarnpkg.js"},"executableFiles":["./dist/npm.js","./dist/npx.js","./dist/pnpm.js","./dist/pnpx.js","./dist/yarn.js","./dist/yarnpkg.js","./dist/corepack.js","./shims/npm","./shims/npm.ps1","./shims/npx","./shims/npx.ps1","./shims/pnpm","./shims/pnpm.ps1","./shims/pnpx","./shims/pnpx.ps1","./shims/yarn","./shims/yarn.ps1","./shims/yarnpkg","./shims/yarnpkg.ps1"]},"resolutions":{"vm2":"patch:vm2@npm:3.9.9#.yarn/patches/vm2-npm-3.9.9-03fd1f4dc5.patch"}}'); +module.exports = JSON.parse('{"name":"corepack","version":"0.14.2","homepage":"https://github.com/nodejs/corepack#readme","bugs":{"url":"https://github.com/nodejs/corepack/issues"},"repository":{"type":"git","url":"https://github.com/nodejs/corepack.git"},"license":"MIT","packageManager":"yarn@4.0.0-rc.15+sha224.7fa5c1d1875b041cea8fcbf9a364667e398825364bf5c5c8cd5f6601","devDependencies":{"@babel/core":"^7.14.3","@babel/plugin-transform-modules-commonjs":"^7.14.0","@babel/preset-typescript":"^7.13.0","@types/debug":"^4.1.5","@types/jest":"^29.0.0","@types/node":"^18.0.0","@types/semver":"^7.1.0","@types/tar":"^6.0.0","@types/which":"^2.0.0","@typescript-eslint/eslint-plugin":"^5.0.0","@typescript-eslint/parser":"^5.0.0","@yarnpkg/eslint-config":"^1.0.0-rc.5","@yarnpkg/fslib":"^2.1.0","@zkochan/cmd-shim":"^5.0.0","babel-plugin-dynamic-import-node":"^2.3.3","clipanion":"^3.0.1","debug":"^4.1.1","eslint":"^8.0.0","eslint-plugin-arca":"^0.15.0","jest":"^29.0.0","nock":"^13.0.4","proxy-agent":"^5.0.0","semver":"^7.1.3","supports-color":"^9.0.0","tar":"^6.0.1","terser-webpack-plugin":"^5.1.2","ts-loader":"^9.0.0","ts-node":"^10.0.0","typescript":"^4.3.2","v8-compile-cache":"^2.3.0","webpack":"^5.38.1","webpack-cli":"^4.0.0","which":"^2.0.2"},"scripts":{"build":"rm -rf dist shims && webpack && ts-node ./mkshims.ts","corepack":"ts-node ./sources/_entryPoint.ts","lint":"yarn eslint","prepack":"yarn build","postpack":"rm -rf dist shims","typecheck":"tsc --noEmit","test":"yarn jest"},"files":["dist","shims","LICENSE.md"],"publishConfig":{"bin":{"corepack":"./dist/corepack.js","pnpm":"./dist/pnpm.js","pnpx":"./dist/pnpx.js","yarn":"./dist/yarn.js","yarnpkg":"./dist/yarnpkg.js"},"executableFiles":["./dist/npm.js","./dist/npx.js","./dist/pnpm.js","./dist/pnpx.js","./dist/yarn.js","./dist/yarnpkg.js","./dist/corepack.js","./shims/npm","./shims/npm.ps1","./shims/npx","./shims/npx.ps1","./shims/pnpm","./shims/pnpm.ps1","./shims/pnpx","./shims/pnpx.ps1","./shims/yarn","./shims/yarn.ps1","./shims/yarnpkg","./shims/yarnpkg.ps1"]},"resolutions":{"vm2":"patch:vm2@npm:3.9.9#.yarn/patches/vm2-npm-3.9.9-03fd1f4dc5.patch"}}'); /***/ }) diff --git a/deps/corepack/package.json b/deps/corepack/package.json index 323996f93b7de8..b7edd6bfeed749 100644 --- a/deps/corepack/package.json +++ b/deps/corepack/package.json @@ -1,6 +1,6 @@ { "name": "corepack", - "version": "0.14.1", + "version": "0.14.2", "homepage": "https://github.com/nodejs/corepack#readme", "bugs": { "url": "https://github.com/nodejs/corepack/issues" diff --git a/deps/undici/src/README.md b/deps/undici/src/README.md index 323b2ca38bb58d..475a9c1ba45397 100644 --- a/deps/undici/src/README.md +++ b/deps/undici/src/README.md @@ -185,12 +185,12 @@ Help us improve the test coverage by following instructions at [nodejs/undici/#9 Basic usage example: ```js -import { fetch } from 'undici'; +import { fetch } from 'undici' const res = await fetch('https://example.com') const json = await res.json() -console.log(json); +console.log(json) ``` You can pass an optional dispatcher to `fetch` as: @@ -225,16 +225,16 @@ A body can be of the following types: In this implementation of fetch, ```request.body``` now accepts ```Async Iterables```. It is not present in the [Fetch Standard.](https://fetch.spec.whatwg.org) ```js -import { fetch } from "undici"; +import { fetch } from 'undici' const data = { async *[Symbol.asyncIterator]() { - yield "hello"; - yield "world"; + yield 'hello' + yield 'world' }, -}; +} -await fetch("https://example.com", { body: data, method: 'POST' }); +await fetch('https://example.com', { body: data, method: 'POST' }) ``` #### `response.body` @@ -242,12 +242,12 @@ await fetch("https://example.com", { body: data, method: 'POST' }); Nodejs has two kinds of streams: [web streams](https://nodejs.org/dist/latest-v16.x/docs/api/webstreams.html), which follow the API of the WHATWG web standard found in browsers, and an older Node-specific [streams API](https://nodejs.org/api/stream.html). `response.body` returns a readable web stream. If you would prefer to work with a Node stream you can convert a web stream using `.fromWeb()`. ```js -import { fetch } from 'undici'; -import { Readable } from 'node:stream'; +import { fetch } from 'undici' +import { Readable } from 'node:stream' const response = await fetch('https://example.com') -const readableWebStream = response.body; -const readableNodeStream = Readable.fromWeb(readableWebStream); +const readableWebStream = response.body +const readableNodeStream = Readable.fromWeb(readableWebStream) ``` #### Specification Compliance @@ -329,6 +329,28 @@ Gets the global dispatcher used by Common API Methods. Returns: `Dispatcher` +### `undici.setGlobalOrigin(origin)` + +* origin `string | URL | undefined` + +Sets the global origin used in `fetch`. + +If `undefined` is passed, the global origin will be reset. This will cause `Response.redirect`, `new Request()`, and `fetch` to throw an error when a relative path is passed. + +```js +setGlobalOrigin('http://localhost:3000') + +const response = await fetch('/api/ping') + +console.log(response.url) // http://localhost:3000/api/ping +``` + +### `undici.getGlobalOrigin()` + +Gets the global origin used in `fetch`. + +Returns: `URL` + ### `UrlObject` * **port** `string | number` (optional) diff --git a/deps/undici/src/docs/api/Agent.md b/deps/undici/src/docs/api/Agent.md index 854dc6aedfc0ae..dd5d99bc1e1287 100644 --- a/deps/undici/src/docs/api/Agent.md +++ b/deps/undici/src/docs/api/Agent.md @@ -16,10 +16,11 @@ Returns: `Agent` ### Parameter: `AgentOptions` -Extends: [`ClientOptions`](Pool.md#parameter-pooloptions) +Extends: [`PoolOptions`](Pool.md#parameter-pooloptions) * **factory** `(origin: URL, opts: Object) => Dispatcher` - Default: `(origin, opts) => new Pool(origin, opts)` * **maxRedirections** `Integer` - Default: `0`. The number of HTTP redirection to follow unless otherwise specified in `DispatchOptions`. +* **interceptors** `{ Agent: DispatchInterceptor[] }` - Default: `[RedirectInterceptor]` - A list of interceptors that are applied to the dispatch method. Additional logic can be applied (such as, but not limited to: 302 status code handling, authentication, cookies, compression and caching). Note that the behavior of interceptors is Experimental and might change at any given time. ## Instance Properties diff --git a/deps/undici/src/docs/api/Client.md b/deps/undici/src/docs/api/Client.md index 76a22253ffccf8..555262359d4183 100644 --- a/deps/undici/src/docs/api/Client.md +++ b/deps/undici/src/docs/api/Client.md @@ -26,6 +26,7 @@ Returns: `Client` * **pipelining** `number | null` (optional) - Default: `1` - The amount of concurrent requests to be sent over the single TCP/TLS connection according to [RFC7230](https://tools.ietf.org/html/rfc7230#section-6.3.2). Carefully consider your workload and environment before enabling concurrent requests as pipelining may reduce performance if used incorrectly. Pipelining is sensitive to network stack settings as well as head of line blocking caused by e.g. long running requests. Set to `0` to disable keep-alive connections. * **connect** `ConnectOptions | Function | null` (optional) - Default: `null`. * **strictContentLength** `Boolean` (optional) - Default: `true` - Whether to treat request content length mismatches as errors. If true, an error is thrown when the request content-length header doesn't match the length of the request body. +* **interceptors** `{ Client: DispatchInterceptor[] }` - Default: `[RedirectInterceptor]` - A list of interceptors that are applied to the dispatch method. Additional logic can be applied (such as, but not limited to: 302 status code handling, authentication, cookies, compression and caching). Note that the behavior of interceptors is Experimental and might change at any given time. #### Parameter: `ConnectOptions` diff --git a/deps/undici/src/docs/api/DispatchInterceptor.md b/deps/undici/src/docs/api/DispatchInterceptor.md new file mode 100644 index 00000000000000..652b2e86bf9920 --- /dev/null +++ b/deps/undici/src/docs/api/DispatchInterceptor.md @@ -0,0 +1,60 @@ +#Interface: DispatchInterceptor + +Extends: `Function` + +A function that can be applied to the `Dispatcher.Dispatch` function before it is invoked with a dispatch request. + +This allows one to write logic to intercept both the outgoing request, and the incoming response. + +### Parameter: `Dispatcher.Dispatch` + +The base dispatch function you are decorating. + +### ReturnType: `Dispatcher.Dispatch` + +A dispatch function that has been altered to provide additional logic + +### Basic Example + +Here is an example of an interceptor being used to provide a JWT bearer token + +```js +'use strict' + +const insertHeaderInterceptor = dispatch => { + return function InterceptedDispatch(opts, handler){ + opts.headers.push('Authorization', 'Bearer [Some token]') + return dispatch(opts, handler) + } +} + +const client = new Client('https://localhost:3000', { + interceptors: { Client: [insertHeaderInterceptor] } +}) + +``` + +### Basic Example 2 + +Here is a contrived example of an interceptor stripping the headers from a response. + +```js +'use strict' + +const clearHeadersInterceptor = dispatch => { + const { DecoratorHandler } = require('undici') + class ResultInterceptor extends DecoratorHandler { + onHeaders (statusCode, headers, resume) { + return super.onHeaders(statusCode, [], resume) + } + } + return function InterceptedDispatch(opts, handler){ + return dispatch(opts, new ResultInterceptor(handler)) + } +} + +const client = new Client('https://localhost:3000', { + interceptors: { Client: [clearHeadersInterceptor] } +}) + +``` diff --git a/deps/undici/src/docs/api/MockPool.md b/deps/undici/src/docs/api/MockPool.md index 87fde1ddd995e5..c86f9a30adb8e0 100644 --- a/deps/undici/src/docs/api/MockPool.md +++ b/deps/undici/src/docs/api/MockPool.md @@ -54,7 +54,7 @@ Returns: `MockInterceptor` corresponding to the input options. ### Parameter: `MockPoolInterceptOptions` * **path** `string | RegExp | (path: string) => boolean` - a matcher for the HTTP request path. -* **method** `string | RegExp | (method: string) => boolean` - a matcher for the HTTP request method. +* **method** `string | RegExp | (method: string) => boolean` - (optional) - a matcher for the HTTP request method. Defaults to `GET`. * **body** `string | RegExp | (body: string) => boolean` - (optional) - a matcher for the HTTP request body. * **headers** `Record boolean`> - (optional) - a matcher for the HTTP request headers. To be intercepted, a request must match all defined headers. Extra headers not defined here may (or may not) be included in the request and do not affect the interception in any way. * **query** `Record | null` - (optional) - a matcher for the HTTP request query string params. diff --git a/deps/undici/src/docs/api/Pool.md b/deps/undici/src/docs/api/Pool.md index 6b08294b61c4c1..8fcabac31541d9 100644 --- a/deps/undici/src/docs/api/Pool.md +++ b/deps/undici/src/docs/api/Pool.md @@ -19,6 +19,7 @@ Extends: [`ClientOptions`](Client.md#parameter-clientoptions) * **factory** `(origin: URL, opts: Object) => Dispatcher` - Default: `(origin, opts) => new Client(origin, opts)` * **connections** `number | null` (optional) - Default: `null` - The number of `Client` instances to create. When set to `null`, the `Pool` instance will create an unlimited amount of `Client` instances. +* **interceptors** `{ Pool: DispatchInterceptor[] } }` - Default: `{ Pool: [] }` - A list of interceptors that are applied to the dispatch method. Additional logic can be applied (such as, but not limited to: 302 status code handling, authentication, cookies, compression and caching). ## Instance Properties diff --git a/deps/undici/src/index-fetch.js b/deps/undici/src/index-fetch.js index 2ee12fc1ef77e6..27a44732f44d80 100644 --- a/deps/undici/src/index-fetch.js +++ b/deps/undici/src/index-fetch.js @@ -1,11 +1,16 @@ 'use strict' const { getGlobalDispatcher } = require('./lib/global') -const fetchImpl = require('./lib/fetch') +const fetchImpl = require('./lib/fetch').fetch module.exports.fetch = async function fetch (resource) { const dispatcher = (arguments[1] && arguments[1].dispatcher) || getGlobalDispatcher() - return fetchImpl.apply(dispatcher, arguments) + try { + return await fetchImpl.apply(dispatcher, arguments) + } catch (err) { + Error.captureStackTrace(err, this) + throw err + } } module.exports.FormData = require('./lib/fetch/formdata').FormData module.exports.Headers = require('./lib/fetch/headers').Headers diff --git a/deps/undici/src/index.d.ts b/deps/undici/src/index.d.ts index e4aa8f62cdbc42..1c8c6e2d03ac43 100644 --- a/deps/undici/src/index.d.ts +++ b/deps/undici/src/index.d.ts @@ -1,6 +1,9 @@ import Dispatcher = require('./types/dispatcher') import { setGlobalDispatcher, getGlobalDispatcher } from './types/global-dispatcher' +import { setGlobalOrigin, getGlobalOrigin } from './types/global-origin' import Pool = require('./types/pool') +import { RedirectHandler, DecoratorHandler } from './types/handlers' + import BalancedPool = require('./types/balanced-pool') import Client = require('./types/client') import buildConnector = require('./types/connector') @@ -19,14 +22,15 @@ export * from './types/formdata' export * from './types/diagnostics-channel' export { Interceptable } from './types/mock-interceptor' -export { Dispatcher, BalancedPool, Pool, Client, buildConnector, errors, Agent, request, stream, pipeline, connect, upgrade, setGlobalDispatcher, getGlobalDispatcher, MockClient, MockPool, MockAgent, mockErrors, ProxyAgent } +export { Dispatcher, BalancedPool, Pool, Client, buildConnector, errors, Agent, request, stream, pipeline, connect, upgrade, setGlobalDispatcher, getGlobalDispatcher, setGlobalOrigin, getGlobalOrigin, MockClient, MockPool, MockAgent, mockErrors, ProxyAgent, RedirectHandler, DecoratorHandler } export default Undici -declare function Undici(url: string, opts: Pool.Options): Pool - declare namespace Undici { var Dispatcher: typeof import('./types/dispatcher') var Pool: typeof import('./types/pool'); + var RedirectHandler: typeof import ('./types/handlers').RedirectHandler + var DecoratorHandler: typeof import ('./types/handlers').DecoratorHandler + var createRedirectInterceptor: typeof import ('./types/interceptors').createRedirectInterceptor var BalancedPool: typeof import('./types/balanced-pool'); var Client: typeof import('./types/client'); var buildConnector: typeof import('./types/connector'); diff --git a/deps/undici/src/index.js b/deps/undici/src/index.js index 8099f5a692f64b..9cde34aed6fc9f 100644 --- a/deps/undici/src/index.js +++ b/deps/undici/src/index.js @@ -16,6 +16,9 @@ const MockPool = require('./lib/mock/mock-pool') const mockErrors = require('./lib/mock/mock-errors') const ProxyAgent = require('./lib/proxy-agent') const { getGlobalDispatcher, setGlobalDispatcher } = require('./lib/global') +const DecoratorHandler = require('./lib/handler/DecoratorHandler') +const RedirectHandler = require('./lib/handler/RedirectHandler') +const createRedirectInterceptor = require('./lib/interceptor/redirectInterceptor') const nodeVersion = process.versions.node.split('.') const nodeMajor = Number(nodeVersion[0]) @@ -30,6 +33,10 @@ module.exports.BalancedPool = BalancedPool module.exports.Agent = Agent module.exports.ProxyAgent = ProxyAgent +module.exports.DecoratorHandler = DecoratorHandler +module.exports.RedirectHandler = RedirectHandler +module.exports.createRedirectInterceptor = createRedirectInterceptor + module.exports.buildConnector = buildConnector module.exports.errors = errors @@ -89,16 +96,26 @@ if (nodeMajor > 16 || (nodeMajor === 16 && nodeMinor >= 8)) { let fetchImpl = null module.exports.fetch = async function fetch (resource) { if (!fetchImpl) { - fetchImpl = require('./lib/fetch') + fetchImpl = require('./lib/fetch').fetch } const dispatcher = (arguments[1] && arguments[1].dispatcher) || getGlobalDispatcher() - return fetchImpl.apply(dispatcher, arguments) + try { + return await fetchImpl.apply(dispatcher, arguments) + } catch (err) { + Error.captureStackTrace(err, this) + throw err + } } module.exports.Headers = require('./lib/fetch/headers').Headers module.exports.Response = require('./lib/fetch/response').Response module.exports.Request = require('./lib/fetch/request').Request module.exports.FormData = require('./lib/fetch/formdata').FormData module.exports.File = require('./lib/fetch/file').File + + const { setGlobalOrigin, getGlobalOrigin } = require('./lib/fetch/global') + + module.exports.setGlobalOrigin = setGlobalOrigin + module.exports.getGlobalOrigin = getGlobalOrigin } module.exports.request = makeDispatcher(api.request) diff --git a/deps/undici/src/lib/agent.js b/deps/undici/src/lib/agent.js index 47aa2365e61a34..0b18f2a91bd2fe 100644 --- a/deps/undici/src/lib/agent.js +++ b/deps/undici/src/lib/agent.js @@ -1,12 +1,12 @@ 'use strict' const { InvalidArgumentError } = require('./core/errors') -const { kClients, kRunning, kClose, kDestroy, kDispatch } = require('./core/symbols') +const { kClients, kRunning, kClose, kDestroy, kDispatch, kInterceptors } = require('./core/symbols') const DispatcherBase = require('./dispatcher-base') const Pool = require('./pool') const Client = require('./client') const util = require('./core/util') -const RedirectHandler = require('./handler/redirect') +const createRedirectInterceptor = require('./interceptor/redirectInterceptor') const { WeakRef, FinalizationRegistry } = require('./compat/dispatcher-weakref')() const kOnConnect = Symbol('onConnect') @@ -44,7 +44,14 @@ class Agent extends DispatcherBase { connect = { ...connect } } + this[kInterceptors] = options.interceptors && options.interceptors.Agent && Array.isArray(options.interceptors.Agent) + ? options.interceptors.Agent + : [createRedirectInterceptor({ maxRedirections })] + this[kOptions] = { ...util.deepClone(options), connect } + this[kOptions].interceptors = options.interceptors + ? { ...options.interceptors } + : undefined this[kMaxRedirections] = maxRedirections this[kFactory] = factory this[kClients] = new Map() @@ -108,12 +115,6 @@ class Agent extends DispatcherBase { this[kFinalizer].register(dispatcher, key) } - const { maxRedirections = this[kMaxRedirections] } = opts - if (maxRedirections != null && maxRedirections !== 0) { - opts = { ...opts, maxRedirections: 0 } // Stop sub dispatcher from also redirecting. - handler = new RedirectHandler(this, maxRedirections, opts, handler) - } - return dispatcher.dispatch(opts, handler) } diff --git a/deps/undici/src/lib/balanced-pool.js b/deps/undici/src/lib/balanced-pool.js index 47468ec0460689..10bc6a47bafd5c 100644 --- a/deps/undici/src/lib/balanced-pool.js +++ b/deps/undici/src/lib/balanced-pool.js @@ -13,7 +13,7 @@ const { kGetDispatcher } = require('./pool-base') const Pool = require('./pool') -const { kUrl } = require('./core/symbols') +const { kUrl, kInterceptors } = require('./core/symbols') const { parseOrigin } = require('./core/util') const kFactory = Symbol('factory') @@ -53,6 +53,9 @@ class BalancedPool extends PoolBase { throw new InvalidArgumentError('factory must be a function.') } + this[kInterceptors] = opts.interceptors && opts.interceptors.BalancedPool && Array.isArray(opts.interceptors.BalancedPool) + ? opts.interceptors.BalancedPool + : [] this[kFactory] = factory for (const upstream of upstreams) { diff --git a/deps/undici/src/lib/client.js b/deps/undici/src/lib/client.js index 14fcaee2e3cc63..46ec0b993309d0 100644 --- a/deps/undici/src/lib/client.js +++ b/deps/undici/src/lib/client.js @@ -7,7 +7,6 @@ const net = require('net') const util = require('./core/util') const Request = require('./core/request') const DispatcherBase = require('./dispatcher-base') -const RedirectHandler = require('./handler/redirect') const { RequestContentLengthMismatchError, ResponseContentLengthMismatchError, @@ -60,7 +59,8 @@ const { kCounter, kClose, kDestroy, - kDispatch + kDispatch, + kInterceptors } = require('./core/symbols') const kClosedResolve = Symbol('kClosedResolve') @@ -82,6 +82,7 @@ try { class Client extends DispatcherBase { constructor (url, { + interceptors, maxHeaderSize, headersTimeout, socketTimeout, @@ -179,6 +180,9 @@ class Client extends DispatcherBase { }) } + this[kInterceptors] = interceptors && interceptors.Client && Array.isArray(interceptors.Client) + ? interceptors.Client + : [createRedirectInterceptor({ maxRedirections })] this[kUrl] = util.parseOrigin(url) this[kConnector] = connect this[kSocket] = null @@ -254,11 +258,6 @@ class Client extends DispatcherBase { } [kDispatch] (opts, handler) { - const { maxRedirections = this[kMaxRedirections] } = opts - if (maxRedirections) { - handler = new RedirectHandler(this, maxRedirections, opts, handler) - } - const origin = opts.origin || this[kUrl].origin const request = new Request(origin, opts, handler) @@ -319,6 +318,7 @@ class Client extends DispatcherBase { } const constants = require('./llhttp/constants') +const createRedirectInterceptor = require('./interceptor/redirectInterceptor') const EMPTY_BUF = Buffer.alloc(0) async function lazyllhttp () { diff --git a/deps/undici/src/lib/core/symbols.js b/deps/undici/src/lib/core/symbols.js index 30108827a846d0..34e4b9fd2aa803 100644 --- a/deps/undici/src/lib/core/symbols.js +++ b/deps/undici/src/lib/core/symbols.js @@ -48,5 +48,6 @@ module.exports = { kMaxRedirections: Symbol('maxRedirections'), kMaxRequests: Symbol('maxRequestsPerClient'), kProxy: Symbol('proxy agent options'), - kCounter: Symbol('socket request counter') + kCounter: Symbol('socket request counter'), + kInterceptors: Symbol('dispatch interceptors') } diff --git a/deps/undici/src/lib/core/util.js b/deps/undici/src/lib/core/util.js index e9a8384ced802c..c2dcf79fb800c9 100644 --- a/deps/undici/src/lib/core/util.js +++ b/deps/undici/src/lib/core/util.js @@ -8,6 +8,7 @@ const net = require('net') const { InvalidArgumentError } = require('./errors') const { Blob } = require('buffer') const nodeUtil = require('util') +const { stringify } = require('querystring') function nop () {} @@ -26,46 +27,15 @@ function isBlobLike (object) { ) } -function isObject (val) { - return val !== null && typeof val === 'object' -} - -// this escapes all non-uri friendly characters -function encode (val) { - return encodeURIComponent(val) -} - -// based on https://github.com/axios/axios/blob/63e559fa609c40a0a460ae5d5a18c3470ffc6c9e/lib/helpers/buildURL.js (MIT license) function buildURL (url, queryParams) { if (url.includes('?') || url.includes('#')) { throw new Error('Query params cannot be passed when url already contains "?" or "#".') } - if (!isObject(queryParams)) { - throw new Error('Query params must be an object') - } - - const parts = [] - for (let [key, val] of Object.entries(queryParams)) { - if (val === null || typeof val === 'undefined') { - continue - } - - if (!Array.isArray(val)) { - val = [val] - } - - for (const v of val) { - if (isObject(v)) { - throw new Error('Passing object as a query param is not supported, please serialize to string up-front') - } - parts.push(encode(key) + '=' + encode(v)) - } - } - const serializedParams = parts.join('&') + const stringified = stringify(queryParams) - if (serializedParams) { - url += '?' + serializedParams + if (stringified) { + url += '?' + stringified } return url diff --git a/deps/undici/src/lib/dispatcher-base.js b/deps/undici/src/lib/dispatcher-base.js index 2c12ba80f351cf..14a5c0acd70043 100644 --- a/deps/undici/src/lib/dispatcher-base.js +++ b/deps/undici/src/lib/dispatcher-base.js @@ -6,12 +6,13 @@ const { ClientClosedError, InvalidArgumentError } = require('./core/errors') -const { kDestroy, kClose, kDispatch } = require('./core/symbols') +const { kDestroy, kClose, kDispatch, kInterceptors } = require('./core/symbols') const kDestroyed = Symbol('destroyed') const kClosed = Symbol('closed') const kOnDestroyed = Symbol('onDestroyed') const kOnClosed = Symbol('onClosed') +const kInterceptedDispatch = Symbol('Intercepted Dispatch') class DispatcherBase extends Dispatcher { constructor () { @@ -31,6 +32,23 @@ class DispatcherBase extends Dispatcher { return this[kClosed] } + get interceptors () { + return this[kInterceptors] + } + + set interceptors (newInterceptors) { + if (newInterceptors) { + for (let i = newInterceptors.length - 1; i >= 0; i--) { + const interceptor = this[kInterceptors][i] + if (typeof interceptor !== 'function') { + throw new InvalidArgumentError('interceptor must be an function') + } + } + } + + this[kInterceptors] = newInterceptors + } + close (callback) { if (callback === undefined) { return new Promise((resolve, reject) => { @@ -125,6 +143,20 @@ class DispatcherBase extends Dispatcher { }) } + [kInterceptedDispatch] (opts, handler) { + if (!this[kInterceptors] || this[kInterceptors].length === 0) { + this[kInterceptedDispatch] = this[kDispatch] + return this[kDispatch](opts, handler) + } + + let dispatch = this[kDispatch].bind(this) + for (let i = this[kInterceptors].length - 1; i >= 0; i--) { + dispatch = this[kInterceptors][i](dispatch) + } + this[kInterceptedDispatch] = dispatch + return dispatch(opts, handler) + } + dispatch (opts, handler) { if (!handler || typeof handler !== 'object') { throw new InvalidArgumentError('handler must be an object') @@ -143,7 +175,7 @@ class DispatcherBase extends Dispatcher { throw new ClientClosedError() } - return this[kDispatch](opts, handler) + return this[kInterceptedDispatch](opts, handler) } catch (err) { if (typeof handler.onError !== 'function') { throw new InvalidArgumentError('invalid onError method') diff --git a/deps/undici/src/lib/fetch/body.js b/deps/undici/src/lib/fetch/body.js index f70fbb7d27dc35..b6dadce055c095 100644 --- a/deps/undici/src/lib/fetch/body.js +++ b/deps/undici/src/lib/fetch/body.js @@ -1,16 +1,18 @@ 'use strict' +const Busboy = require('busboy') const util = require('../core/util') const { ReadableStreamFrom, toUSVString, isBlobLike } = require('./util') const { FormData } = require('./formdata') const { kState } = require('./symbols') const { webidl } = require('./webidl') +const { DOMException } = require('./constants') const { Blob } = require('buffer') const { kBodyUsed } = require('../core/symbols') const assert = require('assert') -const { NotSupportedError } = require('../core/errors') const { isErrored } = require('../core/util') const { isUint8Array, isArrayBuffer } = require('util/types') +const { File } = require('./file') let ReadableStream @@ -230,9 +232,9 @@ function safelyExtractBody (object, keepalive = false) { if (object instanceof ReadableStream) { // Assert: object is neither disturbed nor locked. // istanbul ignore next - assert(!util.isDisturbed(object), 'disturbed') + assert(!util.isDisturbed(object), 'The body has already been consumed.') // istanbul ignore next - assert(!object.locked, 'locked') + assert(!object.locked, 'The stream is locked.') } // 2. Return the results of extracting object. @@ -266,11 +268,11 @@ async function * consumeBody (body) { const stream = body.stream if (util.isDisturbed(stream)) { - throw new TypeError('disturbed') + throw new TypeError('The body has already been consumed.') } if (stream.locked) { - throw new TypeError('locked') + throw new TypeError('The stream is locked.') } // Compat. @@ -281,6 +283,12 @@ async function * consumeBody (body) { } } +function throwIfAborted (state) { + if (state.aborted) { + throw new DOMException('The operation was aborted.', 'AbortError') + } +} + function bodyMixinMethods (instance) { const methods = { async blob () { @@ -288,6 +296,8 @@ function bodyMixinMethods (instance) { throw new TypeError('Illegal invocation') } + throwIfAborted(this[kState]) + const chunks = [] for await (const chunk of consumeBody(this[kState].body)) { @@ -308,6 +318,8 @@ function bodyMixinMethods (instance) { throw new TypeError('Illegal invocation') } + throwIfAborted(this[kState]) + const contentLength = this.headers.get('content-length') const encoded = this.headers.has('content-encoding') @@ -363,6 +375,8 @@ function bodyMixinMethods (instance) { throw new TypeError('Illegal invocation') } + throwIfAborted(this[kState]) + let result = '' const textDecoder = new TextDecoder() @@ -385,6 +399,8 @@ function bodyMixinMethods (instance) { throw new TypeError('Illegal invocation') } + throwIfAborted(this[kState]) + return JSON.parse(await this.text()) }, @@ -393,11 +409,68 @@ function bodyMixinMethods (instance) { throw new TypeError('Illegal invocation') } + throwIfAborted(this[kState]) + const contentType = this.headers.get('Content-Type') // If mimeType’s essence is "multipart/form-data", then: if (/multipart\/form-data/.test(contentType)) { - throw new NotSupportedError('multipart/form-data not supported') + const headers = {} + for (const [key, value] of this.headers) headers[key.toLowerCase()] = value + + const responseFormData = new FormData() + + let busboy + + try { + busboy = Busboy({ headers }) + } catch (err) { + // Error due to headers: + throw Object.assign(new TypeError(), { cause: err }) + } + + busboy.on('field', (name, value) => { + responseFormData.append(name, value) + }) + busboy.on('file', (name, value, info) => { + const { filename, encoding, mimeType } = info + const chunks = [] + + if (encoding.toLowerCase() === 'base64') { + let base64chunk = '' + + value.on('data', (chunk) => { + base64chunk += chunk.toString().replace(/[\r\n]/gm, '') + + const end = base64chunk.length - base64chunk.length % 4 + chunks.push(Buffer.from(base64chunk.slice(0, end), 'base64')) + + base64chunk = base64chunk.slice(end) + }) + value.on('end', () => { + chunks.push(Buffer.from(base64chunk, 'base64')) + responseFormData.append(name, new File(chunks, filename, { type: mimeType })) + }) + } else { + value.on('data', (chunk) => { + chunks.push(chunk) + }) + value.on('end', () => { + responseFormData.append(name, new File(chunks, filename, { type: mimeType })) + }) + } + }) + + const busboyResolve = new Promise((resolve, reject) => { + busboy.on('finish', resolve) + busboy.on('error', (err) => reject(err)) + }) + + if (this.body !== null) for await (const chunk of consumeBody(this[kState].body)) busboy.write(chunk) + busboy.end() + await busboyResolve + + return responseFormData } else if (/application\/x-www-form-urlencoded/.test(contentType)) { // Otherwise, if mimeType’s essence is "application/x-www-form-urlencoded", then: @@ -429,10 +502,16 @@ function bodyMixinMethods (instance) { } return formData } else { + // Wait a tick before checking if the request has been aborted. + // Otherwise, a TypeError can be thrown when an AbortError should. + await Promise.resolve() + + throwIfAborted(this[kState]) + // Otherwise, throw a TypeError. webidl.errors.exception({ header: `${instance.name}.formData`, - value: 'Could not parse content as FormData.' + message: 'Could not parse content as FormData.' }) } } diff --git a/deps/undici/src/lib/fetch/dataURL.js b/deps/undici/src/lib/fetch/dataURL.js index cad44853e1657e..71e5b35ba3a029 100644 --- a/deps/undici/src/lib/fetch/dataURL.js +++ b/deps/undici/src/lib/fetch/dataURL.js @@ -1,5 +1,6 @@ const assert = require('assert') const { atob } = require('buffer') +const { isValidHTTPToken } = require('./util') const encoder = new TextEncoder() @@ -376,9 +377,7 @@ function parseMIMEType (input) { // 1. Set parameterValue to the result of collecting // an HTTP quoted string from input, given position // and the extract-value flag. - // Undici implementation note: extract-value is never - // defined or mentioned anywhere. - parameterValue = collectAnHTTPQuotedString(input, position/*, extractValue */) + parameterValue = collectAnHTTPQuotedString(input, position, true) // 2. Collect a sequence of code points that are not // U+003B (;) from input, given position. @@ -400,7 +399,8 @@ function parseMIMEType (input) { ) // 2. Remove any trailing HTTP whitespace from parameterValue. - parameterValue = parameterValue.trim() + // Note: it says "trailing" whitespace; leading is fine. + parameterValue = parameterValue.trimEnd() // 3. If parameterValue is the empty string, then continue. if (parameterValue.length === 0) { @@ -547,11 +547,56 @@ function collectAnHTTPQuotedString (input, position, extractValue) { return input.slice(positionStart, position.position) } +/** + * @see https://mimesniff.spec.whatwg.org/#serialize-a-mime-type + */ +function serializeAMimeType (mimeType) { + assert(mimeType !== 'failure') + const { type, subtype, parameters } = mimeType + + // 1. Let serialization be the concatenation of mimeType’s + // type, U+002F (/), and mimeType’s subtype. + let serialization = `${type}/${subtype}` + + // 2. For each name → value of mimeType’s parameters: + for (let [name, value] of parameters.entries()) { + // 1. Append U+003B (;) to serialization. + serialization += ';' + + // 2. Append name to serialization. + serialization += name + + // 3. Append U+003D (=) to serialization. + serialization += '=' + + // 4. If value does not solely contain HTTP token code + // points or value is the empty string, then: + if (!isValidHTTPToken(value)) { + // 1. Precede each occurence of U+0022 (") or + // U+005C (\) in value with U+005C (\). + value = value.replace(/(\\|")/g, '\\$1') + + // 2. Prepend U+0022 (") to value. + value = '"' + value + + // 3. Append U+0022 (") to value. + value += '"' + } + + // 5. Append value to serialization. + serialization += value + } + + // 3. Return serialization. + return serialization +} + module.exports = { dataURLProcessor, URLSerializer, collectASequenceOfCodePoints, stringPercentDecode, parseMIMEType, - collectAnHTTPQuotedString + collectAnHTTPQuotedString, + serializeAMimeType } diff --git a/deps/undici/src/lib/fetch/file.js b/deps/undici/src/lib/fetch/file.js index be12fb2b58445c..2720831c180cb4 100644 --- a/deps/undici/src/lib/fetch/file.js +++ b/deps/undici/src/lib/fetch/file.js @@ -312,4 +312,16 @@ function convertLineEndingsNative (s) { return s.replace(/\r?\n/g, nativeLineEnding) } -module.exports = { File, FileLike } +// If this function is moved to ./util.js, some tools (such as +// rollup) will warn about circular dependencies. See: +// https://github.com/nodejs/undici/issues/1629 +function isFileLike (object) { + return object instanceof File || ( + object && + (typeof object.stream === 'function' || + typeof object.arrayBuffer === 'function') && + object[Symbol.toStringTag] === 'File' + ) +} + +module.exports = { File, FileLike, isFileLike } diff --git a/deps/undici/src/lib/fetch/formdata.js b/deps/undici/src/lib/fetch/formdata.js index e4b9841bbfa309..a2c9453333526f 100644 --- a/deps/undici/src/lib/fetch/formdata.js +++ b/deps/undici/src/lib/fetch/formdata.js @@ -1,8 +1,8 @@ 'use strict' -const { isBlobLike, isFileLike, toUSVString, makeIterator } = require('./util') +const { isBlobLike, toUSVString, makeIterator } = require('./util') const { kState } = require('./symbols') -const { File, FileLike } = require('./file') +const { File, FileLike, isFileLike } = require('./file') const { webidl } = require('./webidl') const { Blob } = require('buffer') diff --git a/deps/undici/src/lib/fetch/global.js b/deps/undici/src/lib/fetch/global.js new file mode 100644 index 00000000000000..42282acdfe2572 --- /dev/null +++ b/deps/undici/src/lib/fetch/global.js @@ -0,0 +1,48 @@ +'use strict' + +// In case of breaking changes, increase the version +// number to avoid conflicts. +const globalOrigin = Symbol.for('undici.globalOrigin.1') + +function getGlobalOrigin () { + return globalThis[globalOrigin] +} + +function setGlobalOrigin (newOrigin) { + if ( + newOrigin !== undefined && + typeof newOrigin !== 'string' && + !(newOrigin instanceof URL) + ) { + throw new Error('Invalid base url') + } + + if (newOrigin === undefined) { + Object.defineProperty(globalThis, globalOrigin, { + value: undefined, + writable: true, + enumerable: false, + configurable: false + }) + + return + } + + const parsedURL = new URL(newOrigin) + + if (parsedURL.protocol !== 'http:' && parsedURL.protocol !== 'https:') { + throw new TypeError(`Only http & https urls are allowed, received ${parsedURL.protocol}`) + } + + Object.defineProperty(globalThis, globalOrigin, { + value: parsedURL, + writable: true, + enumerable: false, + configurable: false + }) +} + +module.exports = { + getGlobalOrigin, + setGlobalOrigin +} diff --git a/deps/undici/src/lib/fetch/headers.js b/deps/undici/src/lib/fetch/headers.js index 69a3ec57576890..78f2990774fc52 100644 --- a/deps/undici/src/lib/fetch/headers.js +++ b/deps/undici/src/lib/fetch/headers.js @@ -402,7 +402,9 @@ class Headers { } get [kHeadersSortedMap] () { - this[kHeadersList][kHeadersSortedMap] ??= new Map([...this[kHeadersList]].sort((a, b) => a[0] < b[0] ? -1 : 1)) + if (!this[kHeadersList][kHeadersSortedMap]) { + this[kHeadersList][kHeadersSortedMap] = new Map([...this[kHeadersList]].sort((a, b) => a[0] < b[0] ? -1 : 1)) + } return this[kHeadersList][kHeadersSortedMap] } diff --git a/deps/undici/src/lib/fetch/index.js b/deps/undici/src/lib/fetch/index.js index c7c88ec40b3b73..663d274f0e867f 100644 --- a/deps/undici/src/lib/fetch/index.js +++ b/deps/undici/src/lib/fetch/index.js @@ -52,7 +52,7 @@ const { kHeadersList } = require('../core/symbols') const EE = require('events') const { Readable, pipeline } = require('stream') const { isErrored, isReadable } = require('../core/util') -const { dataURLProcessor } = require('./dataURL') +const { dataURLProcessor, serializeAMimeType } = require('./dataURL') const { TransformStream } = require('stream/web') /** @type {import('buffer').resolveObjectURL} */ @@ -832,25 +832,7 @@ async function schemeFetch (fetchParams) { } // 3. Let mimeType be dataURLStruct’s MIME type, serialized. - const { mimeType } = dataURLStruct - - /** @type {string} */ - let contentType = `${mimeType.type}/${mimeType.subtype}` - const contentTypeParams = [] - - if (mimeType.parameters.size > 0) { - contentType += ';' - } - - for (const [key, value] of mimeType.parameters) { - if (value.length > 0) { - contentTypeParams.push(`${key}=${value}`) - } else { - contentTypeParams.push(key) - } - } - - contentType += contentTypeParams.join(',') + const mimeType = serializeAMimeType(dataURLStruct.mimeType) // 4. Return a response whose status message is `OK`, // header list is « (`Content-Type`, mimeType) », @@ -858,7 +840,7 @@ async function schemeFetch (fetchParams) { return makeResponse({ statusText: 'OK', headersList: [ - ['content-type', contentType] + ['content-type', mimeType] ], body: extractBody(dataURLStruct.body)[0] }) @@ -1048,7 +1030,9 @@ async function httpFetch (fetchParams) { // and the connection uses HTTP/2, then user agents may, and are even // encouraged to, transmit an RST_STREAM frame. // See, https://github.com/whatwg/fetch/issues/1288 - fetchParams.controller.connection.destroy() + if (request.redirect !== 'manual') { + fetchParams.controller.connection.destroy() + } // 2. Switch on request’s redirect mode: if (request.redirect === 'error') { @@ -1956,8 +1940,12 @@ async function httpNetworkFetch ( const decoders = [] + const willFollow = request.redirect === 'follow' && + location && + redirectStatus.includes(status) + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding - if (request.method !== 'HEAD' && request.method !== 'CONNECT' && !nullBodyStatus.includes(status) && !(request.redirect === 'follow' && location)) { + if (request.method !== 'HEAD' && request.method !== 'CONNECT' && !nullBodyStatus.includes(status) && !willFollow) { for (const coding of codings) { if (/(x-)?gzip/.test(coding)) { decoders.push(zlib.createGunzip()) @@ -2033,4 +2021,9 @@ async function httpNetworkFetch ( } } -module.exports = fetch +module.exports = { + fetch, + Fetch, + fetching, + finalizeAndReportTiming +} diff --git a/deps/undici/src/lib/fetch/request.js b/deps/undici/src/lib/fetch/request.js index 5f0c3330139626..bc0ad3c24ccd30 100644 --- a/deps/undici/src/lib/fetch/request.js +++ b/deps/undici/src/lib/fetch/request.js @@ -23,6 +23,7 @@ const { const { kEnumerableProperty } = util const { kHeaders, kSignal, kState, kGuard, kRealm } = require('./symbols') const { webidl } = require('./webidl') +const { getGlobalOrigin } = require('./global') const { kHeadersList } = require('../core/symbols') const assert = require('assert') @@ -52,7 +53,11 @@ class Request { init = webidl.converters.RequestInit(init) // TODO - this[kRealm] = { settingsObject: {} } + this[kRealm] = { + settingsObject: { + baseUrl: getGlobalOrigin() + } + } // 1. Let request be null. let request = null diff --git a/deps/undici/src/lib/fetch/response.js b/deps/undici/src/lib/fetch/response.js index 526259478d4099..198beb9c226bb5 100644 --- a/deps/undici/src/lib/fetch/response.js +++ b/deps/undici/src/lib/fetch/response.js @@ -21,6 +21,7 @@ const { const { kState, kHeaders, kGuard, kRealm } = require('./symbols') const { webidl } = require('./webidl') const { FormData } = require('./formdata') +const { getGlobalOrigin } = require('./global') const { kHeadersList } = require('../core/symbols') const assert = require('assert') const { types } = require('util') @@ -100,7 +101,7 @@ class Response { // TODO: base-URL? let parsedURL try { - parsedURL = new URL(url) + parsedURL = new URL(url, getGlobalOrigin()) } catch (err) { throw Object.assign(new TypeError('Failed to parse URL from ' + url), { cause: err @@ -518,7 +519,7 @@ webidl.converters.XMLHttpRequestBodyInit = function (V) { } if (isBlobLike(V)) { - return webidl.converters.Blob(V) + return webidl.converters.Blob(V, { strict: false }) } if ( @@ -529,8 +530,8 @@ webidl.converters.XMLHttpRequestBodyInit = function (V) { return webidl.converters.BufferSource(V) } - if (V instanceof FormData) { - return webidl.converters.FormData(V) + if (util.isFormDataLike(V)) { + return webidl.converters.FormData(V, { strict: false }) } if (V instanceof URLSearchParams) { diff --git a/deps/undici/src/lib/fetch/util.js b/deps/undici/src/lib/fetch/util.js index 01bf254d53f2db..6cf628ccfb9a92 100644 --- a/deps/undici/src/lib/fetch/util.js +++ b/deps/undici/src/lib/fetch/util.js @@ -6,8 +6,6 @@ const { isBlobLike, toUSVString, ReadableStreamFrom } = require('../core/util') const assert = require('assert') const { isUint8Array } = require('util/types') -let File - // https://nodejs.org/api/crypto.html#determining-if-crypto-support-is-unavailable /** @type {import('crypto')|undefined} */ let crypto @@ -81,18 +79,6 @@ function requestBadPort (request) { return 'allowed' } -function isFileLike (object) { - if (!File) { - File = require('./file').File - } - return object instanceof File || ( - object && - (typeof object.stream === 'function' || - typeof object.arrayBuffer === 'function') && - /^(File)$/.test(object[Symbol.toStringTag]) - ) -} - function isErrorLike (object) { return object instanceof Error || ( object?.constructor?.name === 'Error' || @@ -346,8 +332,175 @@ function clonePolicyContainer () { // https://w3c.github.io/webappsec-referrer-policy/#determine-requests-referrer function determineRequestsReferrer (request) { - // TODO - return 'no-referrer' + // 1. Let policy be request's referrer policy. + const policy = request.referrerPolicy + + // Return no-referrer when empty or policy says so + if (policy == null || policy === '' || policy === 'no-referrer') { + return 'no-referrer' + } + + // 2. Let environment be the request client + const environment = request.client + let referrerSource = null + + /** + * 3, Switch on request’s referrer: + "client" + If environment’s global object is a Window object, then + Let document be the associated Document of environment’s global object. + If document’s origin is an opaque origin, return no referrer. + While document is an iframe srcdoc document, + let document be document’s browsing context’s browsing context container’s node document. + Let referrerSource be document’s URL. + + Otherwise, let referrerSource be environment’s creation URL. + + a URL + Let referrerSource be request’s referrer. + */ + if (request.referrer === 'client') { + // Not defined in Node but part of the spec + if (request.client?.globalObject?.constructor?.name === 'Window' ) { // eslint-disable-line + const origin = environment.globalObject.self?.origin ?? environment.globalObject.location?.origin + + // If document’s origin is an opaque origin, return no referrer. + if (origin == null || origin === 'null') return 'no-referrer' + + // Let referrerSource be document’s URL. + referrerSource = new URL(environment.globalObject.location.href) + } else { + // 3(a)(II) If environment's global object is not Window, + // Let referrerSource be environments creationURL + if (environment?.globalObject?.location == null) { + return 'no-referrer' + } + + referrerSource = new URL(environment.globalObject.location.href) + } + } else if (request.referrer instanceof URL) { + // 3(b) If requests's referrer is a URL instance, then make + // referrerSource be requests's referrer. + referrerSource = request.referrer + } else { + // If referrerSource neither client nor instance of URL + // then return "no-referrer". + return 'no-referrer' + } + + const urlProtocol = referrerSource.protocol + + // If url's scheme is a local scheme (i.e. one of "about", "data", "javascript", "file") + // then return "no-referrer". + if ( + urlProtocol === 'about:' || urlProtocol === 'data:' || + urlProtocol === 'blob:' + ) { + return 'no-referrer' + } + + let temp + let referrerOrigin + // 4. Let requests's referrerURL be the result of stripping referrer + // source for use as referrer (using util function, without origin only) + const referrerUrl = (temp = stripURLForReferrer(referrerSource)).length > 4096 + // 5. Let referrerOrigin be the result of stripping referrer + // source for use as referrer (using util function, with originOnly true) + ? (referrerOrigin = stripURLForReferrer(referrerSource, true)) + // 6. If result of seralizing referrerUrl is a string whose length is greater than + // 4096, then set referrerURL to referrerOrigin + : temp + const areSameOrigin = sameOrigin(request, referrerUrl) + const isNonPotentiallyTrustWorthy = isURLPotentiallyTrustworthy(referrerUrl) && + !isURLPotentiallyTrustworthy(request.url) + + // NOTE: How to treat step 7? + // 8. Execute the switch statements corresponding to the value of policy: + switch (policy) { + case 'origin': return referrerOrigin != null ? referrerOrigin : stripURLForReferrer(referrerSource, true) + case 'unsafe-url': return referrerUrl + case 'same-origin': + return areSameOrigin ? referrerOrigin : 'no-referrer' + case 'origin-when-cross-origin': + return areSameOrigin ? referrerUrl : referrerOrigin + case 'strict-origin-when-cross-origin': + /** + * 1. If the origin of referrerURL and the origin of request’s current URL are the same, + * then return referrerURL. + * 2. If referrerURL is a potentially trustworthy URL and request’s current URL is not a + * potentially trustworthy URL, then return no referrer. + * 3. Return referrerOrigin + */ + if (areSameOrigin) return referrerOrigin + // else return isNonPotentiallyTrustWorthy ? 'no-referrer' : referrerOrigin + case 'strict-origin': // eslint-disable-line + /** + * 1. If referrerURL is a potentially trustworthy URL and + * request’s current URL is not a potentially trustworthy URL, + * then return no referrer. + * 2. Return referrerOrigin + */ + case 'no-referrer-when-downgrade': // eslint-disable-line + /** + * 1. If referrerURL is a potentially trustworthy URL and + * request’s current URL is not a potentially trustworthy URL, + * then return no referrer. + * 2. Return referrerOrigin + */ + + default: // eslint-disable-line + return isNonPotentiallyTrustWorthy ? 'no-referrer' : referrerOrigin + } + + function stripURLForReferrer (url, originOnly = false) { + const urlObject = new URL(url.href) + urlObject.username = '' + urlObject.password = '' + urlObject.hash = '' + + return originOnly ? urlObject.origin : urlObject.href + } +} + +function isURLPotentiallyTrustworthy (url) { + if (!(url instanceof URL)) { + return false + } + + // If child of about, return true + if (url.href === 'about:blank' || url.href === 'about:srcdoc') { + return true + } + + // If scheme is data, return true + if (url.protocol === 'data:') return true + + // If file, return true + if (url.protocol === 'file:') return true + + return isOriginPotentiallyTrustworthy(url.origin) + + function isOriginPotentiallyTrustworthy (origin) { + // If origin is explicitly null, return false + if (origin == null || origin === 'null') return false + + const originAsURL = new URL(origin) + + // If secure, return true + if (originAsURL.protocol === 'https:' || originAsURL.protocol === 'wss:') { + return true + } + + // If localhost or variants, return true + if (/^127(?:\.[0-9]+){0,2}\.[0-9]+$|^\[(?:0*:)*?:?0*1\]$/.test(originAsURL.hostname) || + (originAsURL.hostname === 'localhost' || originAsURL.hostname.includes('localhost.')) || + (originAsURL.hostname.endsWith('.localhost'))) { + return true + } + + // If any other, return false + return false + } } /** @@ -631,7 +784,7 @@ module.exports = { responseURL, responseLocationURL, isBlobLike, - isFileLike, + isURLPotentiallyTrustworthy, isValidReasonPhrase, sameOrigin, normalizeMethod, diff --git a/deps/undici/src/lib/handler/DecoratorHandler.js b/deps/undici/src/lib/handler/DecoratorHandler.js new file mode 100644 index 00000000000000..9d70a767f1e9e8 --- /dev/null +++ b/deps/undici/src/lib/handler/DecoratorHandler.js @@ -0,0 +1,35 @@ +'use strict' + +module.exports = class DecoratorHandler { + constructor (handler) { + this.handler = handler + } + + onConnect (...args) { + return this.handler.onConnect(...args) + } + + onError (...args) { + return this.handler.onError(...args) + } + + onUpgrade (...args) { + return this.handler.onUpgrade(...args) + } + + onHeaders (...args) { + return this.handler.onHeaders(...args) + } + + onData (...args) { + return this.handler.onData(...args) + } + + onComplete (...args) { + return this.handler.onComplete(...args) + } + + onBodySent (...args) { + return this.handler.onBodySent(...args) + } +} diff --git a/deps/undici/src/lib/handler/RedirectHandler.js b/deps/undici/src/lib/handler/RedirectHandler.js new file mode 100644 index 00000000000000..2f726e79f2fa66 --- /dev/null +++ b/deps/undici/src/lib/handler/RedirectHandler.js @@ -0,0 +1,215 @@ +'use strict' + +const util = require('../core/util') +const { kBodyUsed } = require('../core/symbols') +const assert = require('assert') +const { InvalidArgumentError } = require('../core/errors') +const EE = require('events') + +const redirectableStatusCodes = [300, 301, 302, 303, 307, 308] + +const kBody = Symbol('body') + +class BodyAsyncIterable { + constructor (body) { + this[kBody] = body + this[kBodyUsed] = false + } + + async * [Symbol.asyncIterator] () { + assert(!this[kBodyUsed], 'disturbed') + this[kBodyUsed] = true + yield * this[kBody] + } +} + +class RedirectHandler { + constructor (dispatch, maxRedirections, opts, handler) { + if (maxRedirections != null && (!Number.isInteger(maxRedirections) || maxRedirections < 0)) { + throw new InvalidArgumentError('maxRedirections must be a positive number') + } + + util.validateHandler(handler, opts.method, opts.upgrade) + + this.dispatch = dispatch + this.location = null + this.abort = null + this.opts = { ...opts, maxRedirections: 0 } // opts must be a copy + this.maxRedirections = maxRedirections + this.handler = handler + this.history = [] + + if (util.isStream(this.opts.body)) { + // TODO (fix): Provide some way for the user to cache the file to e.g. /tmp + // so that it can be dispatched again? + // TODO (fix): Do we need 100-expect support to provide a way to do this properly? + if (util.bodyLength(this.opts.body) === 0) { + this.opts.body + .on('data', function () { + assert(false) + }) + } + + if (typeof this.opts.body.readableDidRead !== 'boolean') { + this.opts.body[kBodyUsed] = false + EE.prototype.on.call(this.opts.body, 'data', function () { + this[kBodyUsed] = true + }) + } + } else if (this.opts.body && typeof this.opts.body.pipeTo === 'function') { + // TODO (fix): We can't access ReadableStream internal state + // to determine whether or not it has been disturbed. This is just + // a workaround. + this.opts.body = new BodyAsyncIterable(this.opts.body) + } else if ( + this.opts.body && + typeof this.opts.body !== 'string' && + !ArrayBuffer.isView(this.opts.body) && + util.isIterable(this.opts.body) + ) { + // TODO: Should we allow re-using iterable if !this.opts.idempotent + // or through some other flag? + this.opts.body = new BodyAsyncIterable(this.opts.body) + } + } + + onConnect (abort) { + this.abort = abort + this.handler.onConnect(abort, { history: this.history }) + } + + onUpgrade (statusCode, headers, socket) { + this.handler.onUpgrade(statusCode, headers, socket) + } + + onError (error) { + this.handler.onError(error) + } + + onHeaders (statusCode, headers, resume, statusText) { + this.location = this.history.length >= this.maxRedirections || util.isDisturbed(this.opts.body) + ? null + : parseLocation(statusCode, headers) + + if (this.opts.origin) { + this.history.push(new URL(this.opts.path, this.opts.origin)) + } + + if (!this.location) { + return this.handler.onHeaders(statusCode, headers, resume, statusText) + } + + const { origin, pathname, search } = util.parseURL(new URL(this.location, this.opts.origin && new URL(this.opts.path, this.opts.origin))) + const path = search ? `${pathname}${search}` : pathname + + // Remove headers referring to the original URL. + // By default it is Host only, unless it's a 303 (see below), which removes also all Content-* headers. + // https://tools.ietf.org/html/rfc7231#section-6.4 + this.opts.headers = cleanRequestHeaders(this.opts.headers, statusCode === 303, this.opts.origin !== origin) + this.opts.path = path + this.opts.origin = origin + this.opts.maxRedirections = 0 + + // https://tools.ietf.org/html/rfc7231#section-6.4.4 + // In case of HTTP 303, always replace method to be either HEAD or GET + if (statusCode === 303 && this.opts.method !== 'HEAD') { + this.opts.method = 'GET' + this.opts.body = null + } + } + + onData (chunk) { + if (this.location) { + /* + https://tools.ietf.org/html/rfc7231#section-6.4 + + TLDR: undici always ignores 3xx response bodies. + + Redirection is used to serve the requested resource from another URL, so it is assumes that + no body is generated (and thus can be ignored). Even though generating a body is not prohibited. + + For status 301, 302, 303, 307 and 308 (the latter from RFC 7238), the specs mention that the body usually + (which means it's optional and not mandated) contain just an hyperlink to the value of + the Location response header, so the body can be ignored safely. + + For status 300, which is "Multiple Choices", the spec mentions both generating a Location + response header AND a response body with the other possible location to follow. + Since the spec explicitily chooses not to specify a format for such body and leave it to + servers and browsers implementors, we ignore the body as there is no specified way to eventually parse it. + */ + } else { + return this.handler.onData(chunk) + } + } + + onComplete (trailers) { + if (this.location) { + /* + https://tools.ietf.org/html/rfc7231#section-6.4 + + TLDR: undici always ignores 3xx response trailers as they are not expected in case of redirections + and neither are useful if present. + + See comment on onData method above for more detailed informations. + */ + + this.location = null + this.abort = null + + this.dispatch(this.opts, this) + } else { + this.handler.onComplete(trailers) + } + } + + onBodySent (chunk) { + if (this.handler.onBodySent) { + this.handler.onBodySent(chunk) + } + } +} + +function parseLocation (statusCode, headers) { + if (redirectableStatusCodes.indexOf(statusCode) === -1) { + return null + } + + for (let i = 0; i < headers.length; i += 2) { + if (headers[i].toString().toLowerCase() === 'location') { + return headers[i + 1] + } + } +} + +// https://tools.ietf.org/html/rfc7231#section-6.4.4 +function shouldRemoveHeader (header, removeContent, unknownOrigin) { + return ( + (header.length === 4 && header.toString().toLowerCase() === 'host') || + (removeContent && header.toString().toLowerCase().indexOf('content-') === 0) || + (unknownOrigin && header.length === 13 && header.toString().toLowerCase() === 'authorization') || + (unknownOrigin && header.length === 6 && header.toString().toLowerCase() === 'cookie') + ) +} + +// https://tools.ietf.org/html/rfc7231#section-6.4 +function cleanRequestHeaders (headers, removeContent, unknownOrigin) { + const ret = [] + if (Array.isArray(headers)) { + for (let i = 0; i < headers.length; i += 2) { + if (!shouldRemoveHeader(headers[i], removeContent, unknownOrigin)) { + ret.push(headers[i], headers[i + 1]) + } + } + } else if (headers && typeof headers === 'object') { + for (const key of Object.keys(headers)) { + if (!shouldRemoveHeader(key, removeContent, unknownOrigin)) { + ret.push(key, headers[key]) + } + } + } else { + assert(headers == null, 'headers must be an object or an array') + } + return ret +} + +module.exports = RedirectHandler diff --git a/deps/undici/src/lib/handler/redirect.js b/deps/undici/src/lib/handler/redirect.js deleted file mode 100644 index a464e052dc7038..00000000000000 --- a/deps/undici/src/lib/handler/redirect.js +++ /dev/null @@ -1,215 +0,0 @@ -'use strict' - -const util = require('../core/util') -const { kBodyUsed } = require('../core/symbols') -const assert = require('assert') -const { InvalidArgumentError } = require('../core/errors') -const EE = require('events') - -const redirectableStatusCodes = [300, 301, 302, 303, 307, 308] - -const kBody = Symbol('body') - -class BodyAsyncIterable { - constructor (body) { - this[kBody] = body - this[kBodyUsed] = false - } - - async * [Symbol.asyncIterator] () { - assert(!this[kBodyUsed], 'disturbed') - this[kBodyUsed] = true - yield * this[kBody] - } -} - -class RedirectHandler { - constructor (dispatcher, maxRedirections, opts, handler) { - if (maxRedirections != null && (!Number.isInteger(maxRedirections) || maxRedirections < 0)) { - throw new InvalidArgumentError('maxRedirections must be a positive number') - } - - util.validateHandler(handler, opts.method, opts.upgrade) - - this.dispatcher = dispatcher - this.location = null - this.abort = null - this.opts = { ...opts, maxRedirections: 0 } // opts must be a copy - this.maxRedirections = maxRedirections - this.handler = handler - this.history = [] - - if (util.isStream(this.opts.body)) { - // TODO (fix): Provide some way for the user to cache the file to e.g. /tmp - // so that it can be dispatched again? - // TODO (fix): Do we need 100-expect support to provide a way to do this properly? - if (util.bodyLength(this.opts.body) === 0) { - this.opts.body - .on('data', function () { - assert(false) - }) - } - - if (typeof this.opts.body.readableDidRead !== 'boolean') { - this.opts.body[kBodyUsed] = false - EE.prototype.on.call(this.opts.body, 'data', function () { - this[kBodyUsed] = true - }) - } - } else if (this.opts.body && typeof this.opts.body.pipeTo === 'function') { - // TODO (fix): We can't access ReadableStream internal state - // to determine whether or not it has been disturbed. This is just - // a workaround. - this.opts.body = new BodyAsyncIterable(this.opts.body) - } else if ( - this.opts.body && - typeof this.opts.body !== 'string' && - !ArrayBuffer.isView(this.opts.body) && - util.isIterable(this.opts.body) - ) { - // TODO: Should we allow re-using iterable if !this.opts.idempotent - // or through some other flag? - this.opts.body = new BodyAsyncIterable(this.opts.body) - } - } - - onConnect (abort) { - this.abort = abort - this.handler.onConnect(abort, { history: this.history }) - } - - onUpgrade (statusCode, headers, socket) { - this.handler.onUpgrade(statusCode, headers, socket) - } - - onError (error) { - this.handler.onError(error) - } - - onHeaders (statusCode, headers, resume, statusText) { - this.location = this.history.length >= this.maxRedirections || util.isDisturbed(this.opts.body) - ? null - : parseLocation(statusCode, headers) - - if (this.opts.origin) { - this.history.push(new URL(this.opts.path, this.opts.origin)) - } - - if (!this.location) { - return this.handler.onHeaders(statusCode, headers, resume, statusText) - } - - const { origin, pathname, search } = util.parseURL(new URL(this.location, this.opts.origin && new URL(this.opts.path, this.opts.origin))) - const path = search ? `${pathname}${search}` : pathname - - // Remove headers referring to the original URL. - // By default it is Host only, unless it's a 303 (see below), which removes also all Content-* headers. - // https://tools.ietf.org/html/rfc7231#section-6.4 - this.opts.headers = cleanRequestHeaders(this.opts.headers, statusCode === 303, this.opts.origin !== origin) - this.opts.path = path - this.opts.origin = origin - this.opts.maxRedirections = 0 - - // https://tools.ietf.org/html/rfc7231#section-6.4.4 - // In case of HTTP 303, always replace method to be either HEAD or GET - if (statusCode === 303 && this.opts.method !== 'HEAD') { - this.opts.method = 'GET' - this.opts.body = null - } - } - - onData (chunk) { - if (this.location) { - /* - https://tools.ietf.org/html/rfc7231#section-6.4 - - TLDR: undici always ignores 3xx response bodies. - - Redirection is used to serve the requested resource from another URL, so it is assumes that - no body is generated (and thus can be ignored). Even though generating a body is not prohibited. - - For status 301, 302, 303, 307 and 308 (the latter from RFC 7238), the specs mention that the body usually - (which means it's optional and not mandated) contain just an hyperlink to the value of - the Location response header, so the body can be ignored safely. - - For status 300, which is "Multiple Choices", the spec mentions both generating a Location - response header AND a response body with the other possible location to follow. - Since the spec explicitily chooses not to specify a format for such body and leave it to - servers and browsers implementors, we ignore the body as there is no specified way to eventually parse it. - */ - } else { - return this.handler.onData(chunk) - } - } - - onComplete (trailers) { - if (this.location) { - /* - https://tools.ietf.org/html/rfc7231#section-6.4 - - TLDR: undici always ignores 3xx response trailers as they are not expected in case of redirections - and neither are useful if present. - - See comment on onData method above for more detailed informations. - */ - - this.location = null - this.abort = null - - this.dispatcher.dispatch(this.opts, this) - } else { - this.handler.onComplete(trailers) - } - } - - onBodySent (chunk) { - if (this.handler.onBodySent) { - this.handler.onBodySent(chunk) - } - } -} - -function parseLocation (statusCode, headers) { - if (redirectableStatusCodes.indexOf(statusCode) === -1) { - return null - } - - for (let i = 0; i < headers.length; i += 2) { - if (headers[i].toString().toLowerCase() === 'location') { - return headers[i + 1] - } - } -} - -// https://tools.ietf.org/html/rfc7231#section-6.4.4 -function shouldRemoveHeader (header, removeContent, unknownOrigin) { - return ( - (header.length === 4 && header.toString().toLowerCase() === 'host') || - (removeContent && header.toString().toLowerCase().indexOf('content-') === 0) || - (unknownOrigin && header.length === 13 && header.toString().toLowerCase() === 'authorization') || - (unknownOrigin && header.length === 6 && header.toString().toLowerCase() === 'cookie') - ) -} - -// https://tools.ietf.org/html/rfc7231#section-6.4 -function cleanRequestHeaders (headers, removeContent, unknownOrigin) { - const ret = [] - if (Array.isArray(headers)) { - for (let i = 0; i < headers.length; i += 2) { - if (!shouldRemoveHeader(headers[i], removeContent, unknownOrigin)) { - ret.push(headers[i], headers[i + 1]) - } - } - } else if (headers && typeof headers === 'object') { - for (const key of Object.keys(headers)) { - if (!shouldRemoveHeader(key, removeContent, unknownOrigin)) { - ret.push(key, headers[key]) - } - } - } else { - assert(headers == null, 'headers must be an object or an array') - } - return ret -} - -module.exports = RedirectHandler diff --git a/deps/undici/src/lib/interceptor/redirectInterceptor.js b/deps/undici/src/lib/interceptor/redirectInterceptor.js new file mode 100644 index 00000000000000..7cc035e096c84e --- /dev/null +++ b/deps/undici/src/lib/interceptor/redirectInterceptor.js @@ -0,0 +1,21 @@ +'use strict' + +const RedirectHandler = require('../handler/RedirectHandler') + +function createRedirectInterceptor ({ maxRedirections: defaultMaxRedirections }) { + return (dispatch) => { + return function Intercept (opts, handler) { + const { maxRedirections = defaultMaxRedirections } = opts + + if (!maxRedirections) { + return dispatch(opts, handler) + } + + const redirectHandler = new RedirectHandler(dispatch, maxRedirections, opts, handler) + opts = { ...opts, maxRedirections: 0 } // Stop sub dispatcher from also redirecting. + return dispatch(opts, redirectHandler) + } + } +} + +module.exports = createRedirectInterceptor diff --git a/deps/undici/src/lib/mock/mock-utils.js b/deps/undici/src/lib/mock/mock-utils.js index c00ee08e07de1b..7d5ca5071d9470 100644 --- a/deps/undici/src/lib/mock/mock-utils.js +++ b/deps/undici/src/lib/mock/mock-utils.js @@ -9,6 +9,7 @@ const { kGetNetConnect } = require('./mock-symbols') const { buildURL, nop } = require('../core/util') +const { STATUS_CODES } = require('http') function matchValue (match, value) { if (typeof match === 'string') { @@ -190,72 +191,7 @@ function generateKeyValues (data) { * @param {number} statusCode */ function getStatusText (statusCode) { - switch (statusCode) { - case 100: return 'Continue' - case 101: return 'Switching Protocols' - case 102: return 'Processing' - case 103: return 'Early Hints' - case 200: return 'OK' - case 201: return 'Created' - case 202: return 'Accepted' - case 203: return 'Non-Authoritative Information' - case 204: return 'No Content' - case 205: return 'Reset Content' - case 206: return 'Partial Content' - case 207: return 'Multi-Status' - case 208: return 'Already Reported' - case 226: return 'IM Used' - case 300: return 'Multiple Choice' - case 301: return 'Moved Permanently' - case 302: return 'Found' - case 303: return 'See Other' - case 304: return 'Not Modified' - case 305: return 'Use Proxy' - case 306: return 'unused' - case 307: return 'Temporary Redirect' - case 308: return 'Permanent Redirect' - case 400: return 'Bad Request' - case 401: return 'Unauthorized' - case 402: return 'Payment Required' - case 403: return 'Forbidden' - case 404: return 'Not Found' - case 405: return 'Method Not Allowed' - case 406: return 'Not Acceptable' - case 407: return 'Proxy Authentication Required' - case 408: return 'Request Timeout' - case 409: return 'Conflict' - case 410: return 'Gone' - case 411: return 'Length Required' - case 412: return 'Precondition Failed' - case 413: return 'Payload Too Large' - case 414: return 'URI Too Large' - case 415: return 'Unsupported Media Type' - case 416: return 'Range Not Satisfiable' - case 417: return 'Expectation Failed' - case 418: return 'I\'m a teapot' - case 421: return 'Misdirected Request' - case 422: return 'Unprocessable Entity' - case 423: return 'Locked' - case 424: return 'Failed Dependency' - case 425: return 'Too Early' - case 426: return 'Upgrade Required' - case 428: return 'Precondition Required' - case 429: return 'Too Many Requests' - case 431: return 'Request Header Fields Too Large' - case 451: return 'Unavailable For Legal Reasons' - case 500: return 'Internal Server Error' - case 501: return 'Not Implemented' - case 502: return 'Bad Gateway' - case 503: return 'Service Unavailable' - case 504: return 'Gateway Timeout' - case 505: return 'HTTP Version Not Supported' - case 506: return 'Variant Also Negotiates' - case 507: return 'Insufficient Storage' - case 508: return 'Loop Detected' - case 510: return 'Not Extended' - case 511: return 'Network Authentication Required' - default: return 'unknown' - } + return STATUS_CODES[statusCode] || 'unknown' } async function getResponse (body) { diff --git a/deps/undici/src/lib/pool.js b/deps/undici/src/lib/pool.js index 155dd3604b2eab..c1c20dd6b876c3 100644 --- a/deps/undici/src/lib/pool.js +++ b/deps/undici/src/lib/pool.js @@ -12,7 +12,7 @@ const { InvalidArgumentError } = require('./core/errors') const util = require('./core/util') -const { kUrl } = require('./core/symbols') +const { kUrl, kInterceptors } = require('./core/symbols') const buildConnector = require('./core/connect') const kOptions = Symbol('options') @@ -58,9 +58,15 @@ class Pool extends PoolBase { }) } + this[kInterceptors] = options.interceptors && options.interceptors.Pool && Array.isArray(options.interceptors.Pool) + ? options.interceptors.Pool + : [] this[kConnections] = connections || null this[kUrl] = util.parseOrigin(origin) this[kOptions] = { ...util.deepClone(options), connect } + this[kOptions].interceptors = options.interceptors + ? { ...options.interceptors } + : undefined this[kFactory] = factory } diff --git a/deps/undici/src/lib/proxy-agent.js b/deps/undici/src/lib/proxy-agent.js index bfc75d796ed677..716a950f8b553b 100644 --- a/deps/undici/src/lib/proxy-agent.js +++ b/deps/undici/src/lib/proxy-agent.js @@ -1,8 +1,9 @@ 'use strict' -const { kClose, kDestroy } = require('./core/symbols') -const Client = require('./agent') +const { kProxy, kClose, kDestroy, kInterceptors } = require('./core/symbols') +const { URL } = require('url') const Agent = require('./agent') +const Client = require('./client') const DispatcherBase = require('./dispatcher-base') const { InvalidArgumentError, RequestAbortedError } = require('./core/errors') const buildConnector = require('./core/connect') @@ -18,9 +19,29 @@ function defaultProtocolPort (protocol) { return protocol === 'https:' ? 443 : 80 } +function buildProxyOptions (opts) { + if (typeof opts === 'string') { + opts = { uri: opts } + } + + if (!opts || !opts.uri) { + throw new InvalidArgumentError('Proxy opts.uri is mandatory') + } + + return { + uri: opts.uri, + protocol: opts.protocol || 'https' + } +} + class ProxyAgent extends DispatcherBase { constructor (opts) { super(opts) + this[kProxy] = buildProxyOptions(opts) + this[kAgent] = new Agent(opts) + this[kInterceptors] = opts.interceptors && opts.interceptors.ProxyAgent && Array.isArray(opts.interceptors.ProxyAgent) + ? opts.interceptors.ProxyAgent + : [] if (typeof opts === 'string') { opts = { uri: opts } @@ -38,11 +59,12 @@ class ProxyAgent extends DispatcherBase { this[kProxyHeaders]['proxy-authorization'] = `Basic ${opts.auth}` } - const { origin, port } = new URL(opts.uri) + const resolvedUrl = new URL(opts.uri) + const { origin, port, host } = resolvedUrl const connect = buildConnector({ ...opts.proxyTls }) this[kConnectEndpoint] = buildConnector({ ...opts.requestTls }) - this[kClient] = new Client({ origin: opts.origin, connect }) + this[kClient] = new Client(resolvedUrl, { connect }) this[kAgent] = new Agent({ ...opts, connect: async (opts, callback) => { @@ -58,7 +80,7 @@ class ProxyAgent extends DispatcherBase { signal: opts.signal, headers: { ...this[kProxyHeaders], - host: opts.host + host } }) if (statusCode !== 200) { diff --git a/deps/undici/src/node_modules/busboy/.eslintrc.js b/deps/undici/src/node_modules/busboy/.eslintrc.js new file mode 100644 index 00000000000000..be9311d02655a2 --- /dev/null +++ b/deps/undici/src/node_modules/busboy/.eslintrc.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = { + extends: '@mscdex/eslint-config', +}; diff --git a/deps/undici/src/node_modules/busboy/.github/workflows/ci.yml b/deps/undici/src/node_modules/busboy/.github/workflows/ci.yml new file mode 100644 index 00000000000000..799bae04adb62a --- /dev/null +++ b/deps/undici/src/node_modules/busboy/.github/workflows/ci.yml @@ -0,0 +1,24 @@ +name: CI + +on: + pull_request: + push: + branches: [ master ] + +jobs: + tests-linux: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + node-version: [10.16.0, 10.x, 12.x, 14.x, 16.x] + steps: + - uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - name: Install module + run: npm install + - name: Run tests + run: npm test diff --git a/deps/undici/src/node_modules/busboy/.github/workflows/lint.yml b/deps/undici/src/node_modules/busboy/.github/workflows/lint.yml new file mode 100644 index 00000000000000..9f9e1f589a30be --- /dev/null +++ b/deps/undici/src/node_modules/busboy/.github/workflows/lint.yml @@ -0,0 +1,23 @@ +name: lint + +on: + pull_request: + push: + branches: [ master ] + +env: + NODE_VERSION: 16.x + +jobs: + lint-js: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Use Node.js ${{ env.NODE_VERSION }} + uses: actions/setup-node@v1 + with: + node-version: ${{ env.NODE_VERSION }} + - name: Install ESLint + ESLint configs/plugins + run: npm install --only=dev + - name: Lint files + run: npm run lint diff --git a/deps/undici/src/node_modules/busboy/LICENSE b/deps/undici/src/node_modules/busboy/LICENSE new file mode 100644 index 00000000000000..290762e94f4e2f --- /dev/null +++ b/deps/undici/src/node_modules/busboy/LICENSE @@ -0,0 +1,19 @@ +Copyright Brian White. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. \ No newline at end of file diff --git a/deps/undici/src/node_modules/busboy/README.md b/deps/undici/src/node_modules/busboy/README.md new file mode 100644 index 00000000000000..654af30455614e --- /dev/null +++ b/deps/undici/src/node_modules/busboy/README.md @@ -0,0 +1,191 @@ +# Description + +A node.js module for parsing incoming HTML form data. + +Changes (breaking or otherwise) in v1.0.0 can be found [here](https://github.com/mscdex/busboy/issues/266). + +# Requirements + +* [node.js](http://nodejs.org/) -- v10.16.0 or newer + + +# Install + + npm install busboy + + +# Examples + +* Parsing (multipart) with default options: + +```js +const http = require('http'); + +const busboy = require('busboy'); + +http.createServer((req, res) => { + if (req.method === 'POST') { + console.log('POST request'); + const bb = busboy({ headers: req.headers }); + bb.on('file', (name, file, info) => { + const { filename, encoding, mimeType } = info; + console.log( + `File [${name}]: filename: %j, encoding: %j, mimeType: %j`, + filename, + encoding, + mimeType + ); + file.on('data', (data) => { + console.log(`File [${name}] got ${data.length} bytes`); + }).on('close', () => { + console.log(`File [${name}] done`); + }); + }); + bb.on('field', (name, val, info) => { + console.log(`Field [${name}]: value: %j`, val); + }); + bb.on('close', () => { + console.log('Done parsing form!'); + res.writeHead(303, { Connection: 'close', Location: '/' }); + res.end(); + }); + req.pipe(bb); + } else if (req.method === 'GET') { + res.writeHead(200, { Connection: 'close' }); + res.end(` + + + +
+
+
+ +
+ + + `); + } +}).listen(8000, () => { + console.log('Listening for requests'); +}); + +// Example output: +// +// Listening for requests +// < ... form submitted ... > +// POST request +// File [filefield]: filename: "logo.jpg", encoding: "binary", mime: "image/jpeg" +// File [filefield] got 11912 bytes +// Field [textfield]: value: "testing! :-)" +// File [filefield] done +// Done parsing form! +``` + +* Save all incoming files to disk: + +```js +const { randomFillSync } = require('crypto'); +const fs = require('fs'); +const http = require('http'); +const os = require('os'); +const path = require('path'); + +const busboy = require('busboy'); + +const random = (() => { + const buf = Buffer.alloc(16); + return () => randomFillSync(buf).toString('hex'); +})(); + +http.createServer((req, res) => { + if (req.method === 'POST') { + const bb = busboy({ headers: req.headers }); + bb.on('file', (name, file, info) => { + const saveTo = path.join(os.tmpdir(), `busboy-upload-${random()}`); + file.pipe(fs.createWriteStream(saveTo)); + }); + bb.on('close', () => { + res.writeHead(200, { 'Connection': 'close' }); + res.end(`That's all folks!`); + }); + req.pipe(bb); + return; + } + res.writeHead(404); + res.end(); +}).listen(8000, () => { + console.log('Listening for requests'); +}); +``` + + +# API + +## Exports + +`busboy` exports a single function: + +**( _function_ )**(< _object_ >config) - Creates and returns a new _Writable_ form parser stream. + +* Valid `config` properties: + + * **headers** - _object_ - These are the HTTP headers of the incoming request, which are used by individual parsers. + + * **highWaterMark** - _integer_ - highWaterMark to use for the parser stream. **Default:** node's _stream.Writable_ default. + + * **fileHwm** - _integer_ - highWaterMark to use for individual file streams. **Default:** node's _stream.Readable_ default. + + * **defCharset** - _string_ - Default character set to use when one isn't defined. **Default:** `'utf8'`. + + * **defParamCharset** - _string_ - For multipart forms, the default character set to use for values of part header parameters (e.g. filename) that are not extended parameters (that contain an explicit charset). **Default:** `'latin1'`. + + * **preservePath** - _boolean_ - If paths in filenames from file parts in a `'multipart/form-data'` request shall be preserved. **Default:** `false`. + + * **limits** - _object_ - Various limits on incoming data. Valid properties are: + + * **fieldNameSize** - _integer_ - Max field name size (in bytes). **Default:** `100`. + + * **fieldSize** - _integer_ - Max field value size (in bytes). **Default:** `1048576` (1MB). + + * **fields** - _integer_ - Max number of non-file fields. **Default:** `Infinity`. + + * **fileSize** - _integer_ - For multipart forms, the max file size (in bytes). **Default:** `Infinity`. + + * **files** - _integer_ - For multipart forms, the max number of file fields. **Default:** `Infinity`. + + * **parts** - _integer_ - For multipart forms, the max number of parts (fields + files). **Default:** `Infinity`. + + * **headerPairs** - _integer_ - For multipart forms, the max number of header key-value pairs to parse. **Default:** `2000` (same as node's http module). + +This function can throw exceptions if there is something wrong with the values in `config`. For example, if the Content-Type in `headers` is missing entirely, is not a supported type, or is missing the boundary for `'multipart/form-data'` requests. + +## (Special) Parser stream events + +* **file**(< _string_ >name, < _Readable_ >stream, < _object_ >info) - Emitted for each new file found. `name` contains the form field name. `stream` is a _Readable_ stream containing the file's data. No transformations/conversions (e.g. base64 to raw binary) are done on the file's data. `info` contains the following properties: + + * `filename` - _string_ - If supplied, this contains the file's filename. **WARNING:** You should almost _never_ use this value as-is (especially if you are using `preservePath: true` in your `config`) as it could contain malicious input. You are better off generating your own (safe) filenames, or at the very least using a hash of the filename. + + * `encoding` - _string_ - The file's `'Content-Transfer-Encoding'` value. + + * `mimeType` - _string_ - The file's `'Content-Type'` value. + + **Note:** If you listen for this event, you should always consume the `stream` whether you care about its contents or not (you can simply do `stream.resume();` if you want to discard/skip the contents), otherwise the `'finish'`/`'close'` event will never fire on the busboy parser stream. + However, if you aren't accepting files, you can either simply not listen for the `'file'` event at all or set `limits.files` to `0`, and any/all files will be automatically skipped (these skipped files will still count towards any configured `limits.files` and `limits.parts` limits though). + + **Note:** If a configured `limits.fileSize` limit was reached for a file, `stream` will both have a boolean property `truncated` set to `true` (best checked at the end of the stream) and emit a `'limit'` event to notify you when this happens. + +* **field**(< _string_ >name, < _string_ >value, < _object_ >info) - Emitted for each new non-file field found. `name` contains the form field name. `value` contains the string value of the field. `info` contains the following properties: + + * `nameTruncated` - _boolean_ - Whether `name` was truncated or not (due to a configured `limits.fieldNameSize` limit) + + * `valueTruncated` - _boolean_ - Whether `value` was truncated or not (due to a configured `limits.fieldSize` limit) + + * `encoding` - _string_ - The field's `'Content-Transfer-Encoding'` value. + + * `mimeType` - _string_ - The field's `'Content-Type'` value. + +* **partsLimit**() - Emitted when the configured `limits.parts` limit has been reached. No more `'file'` or `'field'` events will be emitted. + +* **filesLimit**() - Emitted when the configured `limits.files` limit has been reached. No more `'file'` events will be emitted. + +* **fieldsLimit**() - Emitted when the configured `limits.fields` limit has been reached. No more `'field'` events will be emitted. diff --git a/deps/undici/src/node_modules/busboy/bench/bench-multipart-fields-100mb-big.js b/deps/undici/src/node_modules/busboy/bench/bench-multipart-fields-100mb-big.js new file mode 100644 index 00000000000000..ef15729ea65c38 --- /dev/null +++ b/deps/undici/src/node_modules/busboy/bench/bench-multipart-fields-100mb-big.js @@ -0,0 +1,149 @@ +'use strict'; + +function createMultipartBuffers(boundary, sizes) { + const bufs = []; + for (let i = 0; i < sizes.length; ++i) { + const mb = sizes[i] * 1024 * 1024; + bufs.push(Buffer.from([ + `--${boundary}`, + `content-disposition: form-data; name="field${i + 1}"`, + '', + '0'.repeat(mb), + '', + ].join('\r\n'))); + } + bufs.push(Buffer.from([ + `--${boundary}--`, + '', + ].join('\r\n'))); + return bufs; +} + +const boundary = '-----------------------------168072824752491622650073'; +const buffers = createMultipartBuffers(boundary, [ + 10, + 10, + 10, + 20, + 50, +]); +const calls = { + partBegin: 0, + headerField: 0, + headerValue: 0, + headerEnd: 0, + headersEnd: 0, + partData: 0, + partEnd: 0, + end: 0, +}; + +const moduleName = process.argv[2]; +switch (moduleName) { + case 'busboy': { + const busboy = require('busboy'); + + const parser = busboy({ + limits: { + fieldSizeLimit: Infinity, + }, + headers: { + 'content-type': `multipart/form-data; boundary=${boundary}`, + }, + }); + parser.on('field', (name, val, info) => { + ++calls.partBegin; + ++calls.partData; + ++calls.partEnd; + }).on('close', () => { + ++calls.end; + console.timeEnd(moduleName); + }); + + console.time(moduleName); + for (const buf of buffers) + parser.write(buf); + break; + } + + case 'formidable': { + const { MultipartParser } = require('formidable'); + + const parser = new MultipartParser(); + parser.initWithBoundary(boundary); + parser.on('data', ({ name }) => { + ++calls[name]; + if (name === 'end') + console.timeEnd(moduleName); + }); + + console.time(moduleName); + for (const buf of buffers) + parser.write(buf); + + break; + } + + case 'multiparty': { + const { Readable } = require('stream'); + + const { Form } = require('multiparty'); + + const form = new Form({ + maxFieldsSize: Infinity, + maxFields: Infinity, + maxFilesSize: Infinity, + autoFields: false, + autoFiles: false, + }); + + const req = new Readable({ read: () => {} }); + req.headers = { + 'content-type': `multipart/form-data; boundary=${boundary}`, + }; + + function hijack(name, fn) { + const oldFn = form[name]; + form[name] = function() { + fn(); + return oldFn.apply(this, arguments); + }; + } + + hijack('onParseHeaderField', () => { + ++calls.headerField; + }); + hijack('onParseHeaderValue', () => { + ++calls.headerValue; + }); + hijack('onParsePartBegin', () => { + ++calls.partBegin; + }); + hijack('onParsePartData', () => { + ++calls.partData; + }); + hijack('onParsePartEnd', () => { + ++calls.partEnd; + }); + + form.on('close', () => { + ++calls.end; + console.timeEnd(moduleName); + }).on('part', (p) => p.resume()); + + console.time(moduleName); + form.parse(req); + for (const buf of buffers) + req.push(buf); + req.push(null); + + break; + } + + default: + if (moduleName === undefined) + console.error('Missing parser module name'); + else + console.error(`Invalid parser module name: ${moduleName}`); + process.exit(1); +} diff --git a/deps/undici/src/node_modules/busboy/bench/bench-multipart-fields-100mb-small.js b/deps/undici/src/node_modules/busboy/bench/bench-multipart-fields-100mb-small.js new file mode 100644 index 00000000000000..f32d421c735d32 --- /dev/null +++ b/deps/undici/src/node_modules/busboy/bench/bench-multipart-fields-100mb-small.js @@ -0,0 +1,143 @@ +'use strict'; + +function createMultipartBuffers(boundary, sizes) { + const bufs = []; + for (let i = 0; i < sizes.length; ++i) { + const mb = sizes[i] * 1024 * 1024; + bufs.push(Buffer.from([ + `--${boundary}`, + `content-disposition: form-data; name="field${i + 1}"`, + '', + '0'.repeat(mb), + '', + ].join('\r\n'))); + } + bufs.push(Buffer.from([ + `--${boundary}--`, + '', + ].join('\r\n'))); + return bufs; +} + +const boundary = '-----------------------------168072824752491622650073'; +const buffers = createMultipartBuffers(boundary, (new Array(100)).fill(1)); +const calls = { + partBegin: 0, + headerField: 0, + headerValue: 0, + headerEnd: 0, + headersEnd: 0, + partData: 0, + partEnd: 0, + end: 0, +}; + +const moduleName = process.argv[2]; +switch (moduleName) { + case 'busboy': { + const busboy = require('busboy'); + + const parser = busboy({ + limits: { + fieldSizeLimit: Infinity, + }, + headers: { + 'content-type': `multipart/form-data; boundary=${boundary}`, + }, + }); + parser.on('field', (name, val, info) => { + ++calls.partBegin; + ++calls.partData; + ++calls.partEnd; + }).on('close', () => { + ++calls.end; + console.timeEnd(moduleName); + }); + + console.time(moduleName); + for (const buf of buffers) + parser.write(buf); + break; + } + + case 'formidable': { + const { MultipartParser } = require('formidable'); + + const parser = new MultipartParser(); + parser.initWithBoundary(boundary); + parser.on('data', ({ name }) => { + ++calls[name]; + if (name === 'end') + console.timeEnd(moduleName); + }); + + console.time(moduleName); + for (const buf of buffers) + parser.write(buf); + + break; + } + + case 'multiparty': { + const { Readable } = require('stream'); + + const { Form } = require('multiparty'); + + const form = new Form({ + maxFieldsSize: Infinity, + maxFields: Infinity, + maxFilesSize: Infinity, + autoFields: false, + autoFiles: false, + }); + + const req = new Readable({ read: () => {} }); + req.headers = { + 'content-type': `multipart/form-data; boundary=${boundary}`, + }; + + function hijack(name, fn) { + const oldFn = form[name]; + form[name] = function() { + fn(); + return oldFn.apply(this, arguments); + }; + } + + hijack('onParseHeaderField', () => { + ++calls.headerField; + }); + hijack('onParseHeaderValue', () => { + ++calls.headerValue; + }); + hijack('onParsePartBegin', () => { + ++calls.partBegin; + }); + hijack('onParsePartData', () => { + ++calls.partData; + }); + hijack('onParsePartEnd', () => { + ++calls.partEnd; + }); + + form.on('close', () => { + ++calls.end; + console.timeEnd(moduleName); + }).on('part', (p) => p.resume()); + + console.time(moduleName); + form.parse(req); + for (const buf of buffers) + req.push(buf); + req.push(null); + + break; + } + + default: + if (moduleName === undefined) + console.error('Missing parser module name'); + else + console.error(`Invalid parser module name: ${moduleName}`); + process.exit(1); +} diff --git a/deps/undici/src/node_modules/busboy/bench/bench-multipart-files-100mb-big.js b/deps/undici/src/node_modules/busboy/bench/bench-multipart-files-100mb-big.js new file mode 100644 index 00000000000000..b46bdee02cdded --- /dev/null +++ b/deps/undici/src/node_modules/busboy/bench/bench-multipart-files-100mb-big.js @@ -0,0 +1,154 @@ +'use strict'; + +function createMultipartBuffers(boundary, sizes) { + const bufs = []; + for (let i = 0; i < sizes.length; ++i) { + const mb = sizes[i] * 1024 * 1024; + bufs.push(Buffer.from([ + `--${boundary}`, + `content-disposition: form-data; name="file${i + 1}"; ` + + `filename="random${i + 1}.bin"`, + 'content-type: application/octet-stream', + '', + '0'.repeat(mb), + '', + ].join('\r\n'))); + } + bufs.push(Buffer.from([ + `--${boundary}--`, + '', + ].join('\r\n'))); + return bufs; +} + +const boundary = '-----------------------------168072824752491622650073'; +const buffers = createMultipartBuffers(boundary, [ + 10, + 10, + 10, + 20, + 50, +]); +const calls = { + partBegin: 0, + headerField: 0, + headerValue: 0, + headerEnd: 0, + headersEnd: 0, + partData: 0, + partEnd: 0, + end: 0, +}; + +const moduleName = process.argv[2]; +switch (moduleName) { + case 'busboy': { + const busboy = require('busboy'); + + const parser = busboy({ + limits: { + fieldSizeLimit: Infinity, + }, + headers: { + 'content-type': `multipart/form-data; boundary=${boundary}`, + }, + }); + parser.on('file', (name, stream, info) => { + ++calls.partBegin; + stream.on('data', (chunk) => { + ++calls.partData; + }).on('end', () => { + ++calls.partEnd; + }); + }).on('close', () => { + ++calls.end; + console.timeEnd(moduleName); + }); + + console.time(moduleName); + for (const buf of buffers) + parser.write(buf); + break; + } + + case 'formidable': { + const { MultipartParser } = require('formidable'); + + const parser = new MultipartParser(); + parser.initWithBoundary(boundary); + parser.on('data', ({ name }) => { + ++calls[name]; + if (name === 'end') + console.timeEnd(moduleName); + }); + + console.time(moduleName); + for (const buf of buffers) + parser.write(buf); + + break; + } + + case 'multiparty': { + const { Readable } = require('stream'); + + const { Form } = require('multiparty'); + + const form = new Form({ + maxFieldsSize: Infinity, + maxFields: Infinity, + maxFilesSize: Infinity, + autoFields: false, + autoFiles: false, + }); + + const req = new Readable({ read: () => {} }); + req.headers = { + 'content-type': `multipart/form-data; boundary=${boundary}`, + }; + + function hijack(name, fn) { + const oldFn = form[name]; + form[name] = function() { + fn(); + return oldFn.apply(this, arguments); + }; + } + + hijack('onParseHeaderField', () => { + ++calls.headerField; + }); + hijack('onParseHeaderValue', () => { + ++calls.headerValue; + }); + hijack('onParsePartBegin', () => { + ++calls.partBegin; + }); + hijack('onParsePartData', () => { + ++calls.partData; + }); + hijack('onParsePartEnd', () => { + ++calls.partEnd; + }); + + form.on('close', () => { + ++calls.end; + console.timeEnd(moduleName); + }).on('part', (p) => p.resume()); + + console.time(moduleName); + form.parse(req); + for (const buf of buffers) + req.push(buf); + req.push(null); + + break; + } + + default: + if (moduleName === undefined) + console.error('Missing parser module name'); + else + console.error(`Invalid parser module name: ${moduleName}`); + process.exit(1); +} diff --git a/deps/undici/src/node_modules/busboy/bench/bench-multipart-files-100mb-small.js b/deps/undici/src/node_modules/busboy/bench/bench-multipart-files-100mb-small.js new file mode 100644 index 00000000000000..46b5dffb0c74d8 --- /dev/null +++ b/deps/undici/src/node_modules/busboy/bench/bench-multipart-files-100mb-small.js @@ -0,0 +1,148 @@ +'use strict'; + +function createMultipartBuffers(boundary, sizes) { + const bufs = []; + for (let i = 0; i < sizes.length; ++i) { + const mb = sizes[i] * 1024 * 1024; + bufs.push(Buffer.from([ + `--${boundary}`, + `content-disposition: form-data; name="file${i + 1}"; ` + + `filename="random${i + 1}.bin"`, + 'content-type: application/octet-stream', + '', + '0'.repeat(mb), + '', + ].join('\r\n'))); + } + bufs.push(Buffer.from([ + `--${boundary}--`, + '', + ].join('\r\n'))); + return bufs; +} + +const boundary = '-----------------------------168072824752491622650073'; +const buffers = createMultipartBuffers(boundary, (new Array(100)).fill(1)); +const calls = { + partBegin: 0, + headerField: 0, + headerValue: 0, + headerEnd: 0, + headersEnd: 0, + partData: 0, + partEnd: 0, + end: 0, +}; + +const moduleName = process.argv[2]; +switch (moduleName) { + case 'busboy': { + const busboy = require('busboy'); + + const parser = busboy({ + limits: { + fieldSizeLimit: Infinity, + }, + headers: { + 'content-type': `multipart/form-data; boundary=${boundary}`, + }, + }); + parser.on('file', (name, stream, info) => { + ++calls.partBegin; + stream.on('data', (chunk) => { + ++calls.partData; + }).on('end', () => { + ++calls.partEnd; + }); + }).on('close', () => { + ++calls.end; + console.timeEnd(moduleName); + }); + + console.time(moduleName); + for (const buf of buffers) + parser.write(buf); + break; + } + + case 'formidable': { + const { MultipartParser } = require('formidable'); + + const parser = new MultipartParser(); + parser.initWithBoundary(boundary); + parser.on('data', ({ name }) => { + ++calls[name]; + if (name === 'end') + console.timeEnd(moduleName); + }); + + console.time(moduleName); + for (const buf of buffers) + parser.write(buf); + + break; + } + + case 'multiparty': { + const { Readable } = require('stream'); + + const { Form } = require('multiparty'); + + const form = new Form({ + maxFieldsSize: Infinity, + maxFields: Infinity, + maxFilesSize: Infinity, + autoFields: false, + autoFiles: false, + }); + + const req = new Readable({ read: () => {} }); + req.headers = { + 'content-type': `multipart/form-data; boundary=${boundary}`, + }; + + function hijack(name, fn) { + const oldFn = form[name]; + form[name] = function() { + fn(); + return oldFn.apply(this, arguments); + }; + } + + hijack('onParseHeaderField', () => { + ++calls.headerField; + }); + hijack('onParseHeaderValue', () => { + ++calls.headerValue; + }); + hijack('onParsePartBegin', () => { + ++calls.partBegin; + }); + hijack('onParsePartData', () => { + ++calls.partData; + }); + hijack('onParsePartEnd', () => { + ++calls.partEnd; + }); + + form.on('close', () => { + ++calls.end; + console.timeEnd(moduleName); + }).on('part', (p) => p.resume()); + + console.time(moduleName); + form.parse(req); + for (const buf of buffers) + req.push(buf); + req.push(null); + + break; + } + + default: + if (moduleName === undefined) + console.error('Missing parser module name'); + else + console.error(`Invalid parser module name: ${moduleName}`); + process.exit(1); +} diff --git a/deps/undici/src/node_modules/busboy/bench/bench-urlencoded-fields-100pairs-small.js b/deps/undici/src/node_modules/busboy/bench/bench-urlencoded-fields-100pairs-small.js new file mode 100644 index 00000000000000..5c337df2ef951f --- /dev/null +++ b/deps/undici/src/node_modules/busboy/bench/bench-urlencoded-fields-100pairs-small.js @@ -0,0 +1,101 @@ +'use strict'; + +const buffers = [ + Buffer.from( + (new Array(100)).fill('').map((_, i) => `key${i}=value${i}`).join('&') + ), +]; +const calls = { + field: 0, + end: 0, +}; + +let n = 3e3; + +const moduleName = process.argv[2]; +switch (moduleName) { + case 'busboy': { + const busboy = require('busboy'); + + console.time(moduleName); + (function next() { + const parser = busboy({ + limits: { + fieldSizeLimit: Infinity, + }, + headers: { + 'content-type': 'application/x-www-form-urlencoded; charset=utf-8', + }, + }); + parser.on('field', (name, val, info) => { + ++calls.field; + }).on('close', () => { + ++calls.end; + if (--n === 0) + console.timeEnd(moduleName); + else + process.nextTick(next); + }); + + for (const buf of buffers) + parser.write(buf); + parser.end(); + })(); + break; + } + + case 'formidable': { + const QuerystringParser = + require('formidable/src/parsers/Querystring.js'); + + console.time(moduleName); + (function next() { + const parser = new QuerystringParser(); + parser.on('data', (obj) => { + ++calls.field; + }).on('end', () => { + ++calls.end; + if (--n === 0) + console.timeEnd(moduleName); + else + process.nextTick(next); + }); + + for (const buf of buffers) + parser.write(buf); + parser.end(); + })(); + break; + } + + case 'formidable-streaming': { + const QuerystringParser = + require('formidable/src/parsers/StreamingQuerystring.js'); + + console.time(moduleName); + (function next() { + const parser = new QuerystringParser(); + parser.on('data', (obj) => { + ++calls.field; + }).on('end', () => { + ++calls.end; + if (--n === 0) + console.timeEnd(moduleName); + else + process.nextTick(next); + }); + + for (const buf of buffers) + parser.write(buf); + parser.end(); + })(); + break; + } + + default: + if (moduleName === undefined) + console.error('Missing parser module name'); + else + console.error(`Invalid parser module name: ${moduleName}`); + process.exit(1); +} diff --git a/deps/undici/src/node_modules/busboy/bench/bench-urlencoded-fields-900pairs-small-alt.js b/deps/undici/src/node_modules/busboy/bench/bench-urlencoded-fields-900pairs-small-alt.js new file mode 100644 index 00000000000000..1f5645cb8cc43f --- /dev/null +++ b/deps/undici/src/node_modules/busboy/bench/bench-urlencoded-fields-900pairs-small-alt.js @@ -0,0 +1,84 @@ +'use strict'; + +const buffers = [ + Buffer.from( + (new Array(900)).fill('').map((_, i) => `key${i}=value${i}`).join('&') + ), +]; +const calls = { + field: 0, + end: 0, +}; + +const moduleName = process.argv[2]; +switch (moduleName) { + case 'busboy': { + const busboy = require('busboy'); + + console.time(moduleName); + const parser = busboy({ + limits: { + fieldSizeLimit: Infinity, + }, + headers: { + 'content-type': 'application/x-www-form-urlencoded; charset=utf-8', + }, + }); + parser.on('field', (name, val, info) => { + ++calls.field; + }).on('close', () => { + ++calls.end; + console.timeEnd(moduleName); + }); + + for (const buf of buffers) + parser.write(buf); + parser.end(); + break; + } + + case 'formidable': { + const QuerystringParser = + require('formidable/src/parsers/Querystring.js'); + + console.time(moduleName); + const parser = new QuerystringParser(); + parser.on('data', (obj) => { + ++calls.field; + }).on('end', () => { + ++calls.end; + console.timeEnd(moduleName); + }); + + for (const buf of buffers) + parser.write(buf); + parser.end(); + break; + } + + case 'formidable-streaming': { + const QuerystringParser = + require('formidable/src/parsers/StreamingQuerystring.js'); + + console.time(moduleName); + const parser = new QuerystringParser(); + parser.on('data', (obj) => { + ++calls.field; + }).on('end', () => { + ++calls.end; + console.timeEnd(moduleName); + }); + + for (const buf of buffers) + parser.write(buf); + parser.end(); + break; + } + + default: + if (moduleName === undefined) + console.error('Missing parser module name'); + else + console.error(`Invalid parser module name: ${moduleName}`); + process.exit(1); +} diff --git a/deps/undici/src/node_modules/busboy/lib/index.js b/deps/undici/src/node_modules/busboy/lib/index.js new file mode 100644 index 00000000000000..873272d93cf34c --- /dev/null +++ b/deps/undici/src/node_modules/busboy/lib/index.js @@ -0,0 +1,57 @@ +'use strict'; + +const { parseContentType } = require('./utils.js'); + +function getInstance(cfg) { + const headers = cfg.headers; + const conType = parseContentType(headers['content-type']); + if (!conType) + throw new Error('Malformed content type'); + + for (const type of TYPES) { + const matched = type.detect(conType); + if (!matched) + continue; + + const instanceCfg = { + limits: cfg.limits, + headers, + conType, + highWaterMark: undefined, + fileHwm: undefined, + defCharset: undefined, + defParamCharset: undefined, + preservePath: false, + }; + if (cfg.highWaterMark) + instanceCfg.highWaterMark = cfg.highWaterMark; + if (cfg.fileHwm) + instanceCfg.fileHwm = cfg.fileHwm; + instanceCfg.defCharset = cfg.defCharset; + instanceCfg.defParamCharset = cfg.defParamCharset; + instanceCfg.preservePath = cfg.preservePath; + return new type(instanceCfg); + } + + throw new Error(`Unsupported content type: ${headers['content-type']}`); +} + +// Note: types are explicitly listed here for easier bundling +// See: https://github.com/mscdex/busboy/issues/121 +const TYPES = [ + require('./types/multipart'), + require('./types/urlencoded'), +].filter(function(typemod) { return typeof typemod.detect === 'function'; }); + +module.exports = (cfg) => { + if (typeof cfg !== 'object' || cfg === null) + cfg = {}; + + if (typeof cfg.headers !== 'object' + || cfg.headers === null + || typeof cfg.headers['content-type'] !== 'string') { + throw new Error('Missing Content-Type'); + } + + return getInstance(cfg); +}; diff --git a/deps/undici/src/node_modules/busboy/lib/types/multipart.js b/deps/undici/src/node_modules/busboy/lib/types/multipart.js new file mode 100644 index 00000000000000..cc0d7bb6638a12 --- /dev/null +++ b/deps/undici/src/node_modules/busboy/lib/types/multipart.js @@ -0,0 +1,653 @@ +'use strict'; + +const { Readable, Writable } = require('stream'); + +const StreamSearch = require('streamsearch'); + +const { + basename, + convertToUTF8, + getDecoder, + parseContentType, + parseDisposition, +} = require('../utils.js'); + +const BUF_CRLF = Buffer.from('\r\n'); +const BUF_CR = Buffer.from('\r'); +const BUF_DASH = Buffer.from('-'); + +function noop() {} + +const MAX_HEADER_PAIRS = 2000; // From node +const MAX_HEADER_SIZE = 16 * 1024; // From node (its default value) + +const HPARSER_NAME = 0; +const HPARSER_PRE_OWS = 1; +const HPARSER_VALUE = 2; +class HeaderParser { + constructor(cb) { + this.header = Object.create(null); + this.pairCount = 0; + this.byteCount = 0; + this.state = HPARSER_NAME; + this.name = ''; + this.value = ''; + this.crlf = 0; + this.cb = cb; + } + + reset() { + this.header = Object.create(null); + this.pairCount = 0; + this.byteCount = 0; + this.state = HPARSER_NAME; + this.name = ''; + this.value = ''; + this.crlf = 0; + } + + push(chunk, pos, end) { + let start = pos; + while (pos < end) { + switch (this.state) { + case HPARSER_NAME: { + let done = false; + for (; pos < end; ++pos) { + if (this.byteCount === MAX_HEADER_SIZE) + return -1; + ++this.byteCount; + const code = chunk[pos]; + if (TOKEN[code] !== 1) { + if (code !== 58/* ':' */) + return -1; + this.name += chunk.latin1Slice(start, pos); + if (this.name.length === 0) + return -1; + ++pos; + done = true; + this.state = HPARSER_PRE_OWS; + break; + } + } + if (!done) { + this.name += chunk.latin1Slice(start, pos); + break; + } + // FALLTHROUGH + } + case HPARSER_PRE_OWS: { + // Skip optional whitespace + let done = false; + for (; pos < end; ++pos) { + if (this.byteCount === MAX_HEADER_SIZE) + return -1; + ++this.byteCount; + const code = chunk[pos]; + if (code !== 32/* ' ' */ && code !== 9/* '\t' */) { + start = pos; + done = true; + this.state = HPARSER_VALUE; + break; + } + } + if (!done) + break; + // FALLTHROUGH + } + case HPARSER_VALUE: + switch (this.crlf) { + case 0: // Nothing yet + for (; pos < end; ++pos) { + if (this.byteCount === MAX_HEADER_SIZE) + return -1; + ++this.byteCount; + const code = chunk[pos]; + if (FIELD_VCHAR[code] !== 1) { + if (code !== 13/* '\r' */) + return -1; + ++this.crlf; + break; + } + } + this.value += chunk.latin1Slice(start, pos++); + break; + case 1: // Received CR + if (this.byteCount === MAX_HEADER_SIZE) + return -1; + ++this.byteCount; + if (chunk[pos++] !== 10/* '\n' */) + return -1; + ++this.crlf; + break; + case 2: { // Received CR LF + if (this.byteCount === MAX_HEADER_SIZE) + return -1; + ++this.byteCount; + const code = chunk[pos]; + if (code === 32/* ' ' */ || code === 9/* '\t' */) { + // Folded value + start = pos; + this.crlf = 0; + } else { + if (++this.pairCount < MAX_HEADER_PAIRS) { + this.name = this.name.toLowerCase(); + if (this.header[this.name] === undefined) + this.header[this.name] = [this.value]; + else + this.header[this.name].push(this.value); + } + if (code === 13/* '\r' */) { + ++this.crlf; + ++pos; + } else { + // Assume start of next header field name + start = pos; + this.crlf = 0; + this.state = HPARSER_NAME; + this.name = ''; + this.value = ''; + } + } + break; + } + case 3: { // Received CR LF CR + if (this.byteCount === MAX_HEADER_SIZE) + return -1; + ++this.byteCount; + if (chunk[pos++] !== 10/* '\n' */) + return -1; + // End of header + const header = this.header; + this.reset(); + this.cb(header); + return pos; + } + } + break; + } + } + + return pos; + } +} + +class FileStream extends Readable { + constructor(opts, owner) { + super(opts); + this.truncated = false; + this._readcb = null; + this.once('end', () => { + // We need to make sure that we call any outstanding _writecb() that is + // associated with this file so that processing of the rest of the form + // can continue. This may not happen if the file stream ends right after + // backpressure kicks in, so we force it here. + this._read(); + if (--owner._fileEndsLeft === 0 && owner._finalcb) { + const cb = owner._finalcb; + owner._finalcb = null; + // Make sure other 'end' event handlers get a chance to be executed + // before busboy's 'finish' event is emitted + process.nextTick(cb); + } + }); + } + _read(n) { + const cb = this._readcb; + if (cb) { + this._readcb = null; + cb(); + } + } +} + +const ignoreData = { + push: (chunk, pos) => {}, + destroy: () => {}, +}; + +function callAndUnsetCb(self, err) { + const cb = self._writecb; + self._writecb = null; + if (err) + self.destroy(err); + else if (cb) + cb(); +} + +function nullDecoder(val, hint) { + return val; +} + +class Multipart extends Writable { + constructor(cfg) { + const streamOpts = { + autoDestroy: true, + emitClose: true, + highWaterMark: (typeof cfg.highWaterMark === 'number' + ? cfg.highWaterMark + : undefined), + }; + super(streamOpts); + + if (!cfg.conType.params || typeof cfg.conType.params.boundary !== 'string') + throw new Error('Multipart: Boundary not found'); + + const boundary = cfg.conType.params.boundary; + const paramDecoder = (typeof cfg.defParamCharset === 'string' + && cfg.defParamCharset + ? getDecoder(cfg.defParamCharset) + : nullDecoder); + const defCharset = (cfg.defCharset || 'utf8'); + const preservePath = cfg.preservePath; + const fileOpts = { + autoDestroy: true, + emitClose: true, + highWaterMark: (typeof cfg.fileHwm === 'number' + ? cfg.fileHwm + : undefined), + }; + + const limits = cfg.limits; + const fieldSizeLimit = (limits && typeof limits.fieldSize === 'number' + ? limits.fieldSize + : 1 * 1024 * 1024); + const fileSizeLimit = (limits && typeof limits.fileSize === 'number' + ? limits.fileSize + : Infinity); + const filesLimit = (limits && typeof limits.files === 'number' + ? limits.files + : Infinity); + const fieldsLimit = (limits && typeof limits.fields === 'number' + ? limits.fields + : Infinity); + const partsLimit = (limits && typeof limits.parts === 'number' + ? limits.parts + : Infinity); + + let parts = -1; // Account for initial boundary + let fields = 0; + let files = 0; + let skipPart = false; + + this._fileEndsLeft = 0; + this._fileStream = undefined; + this._complete = false; + let fileSize = 0; + + let field; + let fieldSize = 0; + let partCharset; + let partEncoding; + let partType; + let partName; + let partTruncated = false; + + let hitFilesLimit = false; + let hitFieldsLimit = false; + + this._hparser = null; + const hparser = new HeaderParser((header) => { + this._hparser = null; + skipPart = false; + + partType = 'text/plain'; + partCharset = defCharset; + partEncoding = '7bit'; + partName = undefined; + partTruncated = false; + + let filename; + if (!header['content-disposition']) { + skipPart = true; + return; + } + + const disp = parseDisposition(header['content-disposition'][0], + paramDecoder); + if (!disp || disp.type !== 'form-data') { + skipPart = true; + return; + } + + if (disp.params) { + if (disp.params.name) + partName = disp.params.name; + + if (disp.params['filename*']) + filename = disp.params['filename*']; + else if (disp.params.filename) + filename = disp.params.filename; + + if (filename !== undefined && !preservePath) + filename = basename(filename); + } + + if (header['content-type']) { + const conType = parseContentType(header['content-type'][0]); + if (conType) { + partType = `${conType.type}/${conType.subtype}`; + if (conType.params && typeof conType.params.charset === 'string') + partCharset = conType.params.charset.toLowerCase(); + } + } + + if (header['content-transfer-encoding']) + partEncoding = header['content-transfer-encoding'][0].toLowerCase(); + + if (partType === 'application/octet-stream' || filename !== undefined) { + // File + + if (files === filesLimit) { + if (!hitFilesLimit) { + hitFilesLimit = true; + this.emit('filesLimit'); + } + skipPart = true; + return; + } + ++files; + + if (this.listenerCount('file') === 0) { + skipPart = true; + return; + } + + fileSize = 0; + this._fileStream = new FileStream(fileOpts, this); + ++this._fileEndsLeft; + this.emit( + 'file', + partName, + this._fileStream, + { filename, + encoding: partEncoding, + mimeType: partType } + ); + } else { + // Non-file + + if (fields === fieldsLimit) { + if (!hitFieldsLimit) { + hitFieldsLimit = true; + this.emit('fieldsLimit'); + } + skipPart = true; + return; + } + ++fields; + + if (this.listenerCount('field') === 0) { + skipPart = true; + return; + } + + field = []; + fieldSize = 0; + } + }); + + let matchPostBoundary = 0; + const ssCb = (isMatch, data, start, end, isDataSafe) => { +retrydata: + while (data) { + if (this._hparser !== null) { + const ret = this._hparser.push(data, start, end); + if (ret === -1) { + this._hparser = null; + hparser.reset(); + this.emit('error', new Error('Malformed part header')); + break; + } + start = ret; + } + + if (start === end) + break; + + if (matchPostBoundary !== 0) { + if (matchPostBoundary === 1) { + switch (data[start]) { + case 45: // '-' + // Try matching '--' after boundary + matchPostBoundary = 2; + ++start; + break; + case 13: // '\r' + // Try matching CR LF before header + matchPostBoundary = 3; + ++start; + break; + default: + matchPostBoundary = 0; + } + if (start === end) + return; + } + + if (matchPostBoundary === 2) { + matchPostBoundary = 0; + if (data[start] === 45/* '-' */) { + // End of multipart data + this._complete = true; + this._bparser = ignoreData; + return; + } + // We saw something other than '-', so put the dash we consumed + // "back" + const writecb = this._writecb; + this._writecb = noop; + ssCb(false, BUF_DASH, 0, 1, false); + this._writecb = writecb; + } else if (matchPostBoundary === 3) { + matchPostBoundary = 0; + if (data[start] === 10/* '\n' */) { + ++start; + if (parts >= partsLimit) + break; + // Prepare the header parser + this._hparser = hparser; + if (start === end) + break; + // Process the remaining data as a header + continue retrydata; + } else { + // We saw something other than LF, so put the CR we consumed + // "back" + const writecb = this._writecb; + this._writecb = noop; + ssCb(false, BUF_CR, 0, 1, false); + this._writecb = writecb; + } + } + } + + if (!skipPart) { + if (this._fileStream) { + let chunk; + const actualLen = Math.min(end - start, fileSizeLimit - fileSize); + if (!isDataSafe) { + chunk = Buffer.allocUnsafe(actualLen); + data.copy(chunk, 0, start, start + actualLen); + } else { + chunk = data.slice(start, start + actualLen); + } + + fileSize += chunk.length; + if (fileSize === fileSizeLimit) { + if (chunk.length > 0) + this._fileStream.push(chunk); + this._fileStream.emit('limit'); + this._fileStream.truncated = true; + skipPart = true; + } else if (!this._fileStream.push(chunk)) { + if (this._writecb) + this._fileStream._readcb = this._writecb; + this._writecb = null; + } + } else if (field !== undefined) { + let chunk; + const actualLen = Math.min( + end - start, + fieldSizeLimit - fieldSize + ); + if (!isDataSafe) { + chunk = Buffer.allocUnsafe(actualLen); + data.copy(chunk, 0, start, start + actualLen); + } else { + chunk = data.slice(start, start + actualLen); + } + + fieldSize += actualLen; + field.push(chunk); + if (fieldSize === fieldSizeLimit) { + skipPart = true; + partTruncated = true; + } + } + } + + break; + } + + if (isMatch) { + matchPostBoundary = 1; + + if (this._fileStream) { + // End the active file stream if the previous part was a file + this._fileStream.push(null); + this._fileStream = null; + } else if (field !== undefined) { + let data; + switch (field.length) { + case 0: + data = ''; + break; + case 1: + data = convertToUTF8(field[0], partCharset, 0); + break; + default: + data = convertToUTF8( + Buffer.concat(field, fieldSize), + partCharset, + 0 + ); + } + field = undefined; + fieldSize = 0; + this.emit( + 'field', + partName, + data, + { nameTruncated: false, + valueTruncated: partTruncated, + encoding: partEncoding, + mimeType: partType } + ); + } + + if (++parts === partsLimit) + this.emit('partsLimit'); + } + }; + this._bparser = new StreamSearch(`\r\n--${boundary}`, ssCb); + + this._writecb = null; + this._finalcb = null; + + // Just in case there is no preamble + this.write(BUF_CRLF); + } + + static detect(conType) { + return (conType.type === 'multipart' && conType.subtype === 'form-data'); + } + + _write(chunk, enc, cb) { + this._writecb = cb; + this._bparser.push(chunk, 0); + if (this._writecb) + callAndUnsetCb(this); + } + + _destroy(err, cb) { + this._hparser = null; + this._bparser = ignoreData; + if (!err) + err = checkEndState(this); + const fileStream = this._fileStream; + if (fileStream) { + this._fileStream = null; + fileStream.destroy(err); + } + cb(err); + } + + _final(cb) { + this._bparser.destroy(); + if (!this._complete) + return cb(new Error('Unexpected end of form')); + if (this._fileEndsLeft) + this._finalcb = finalcb.bind(null, this, cb); + else + finalcb(this, cb); + } +} + +function finalcb(self, cb, err) { + if (err) + return cb(err); + err = checkEndState(self); + cb(err); +} + +function checkEndState(self) { + if (self._hparser) + return new Error('Malformed part header'); + const fileStream = self._fileStream; + if (fileStream) { + self._fileStream = null; + fileStream.destroy(new Error('Unexpected end of file')); + } + if (!self._complete) + return new Error('Unexpected end of form'); +} + +const TOKEN = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +]; + +const FIELD_VCHAR = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +]; + +module.exports = Multipart; diff --git a/deps/undici/src/node_modules/busboy/lib/types/urlencoded.js b/deps/undici/src/node_modules/busboy/lib/types/urlencoded.js new file mode 100644 index 00000000000000..5c463a25899a72 --- /dev/null +++ b/deps/undici/src/node_modules/busboy/lib/types/urlencoded.js @@ -0,0 +1,350 @@ +'use strict'; + +const { Writable } = require('stream'); + +const { getDecoder } = require('../utils.js'); + +class URLEncoded extends Writable { + constructor(cfg) { + const streamOpts = { + autoDestroy: true, + emitClose: true, + highWaterMark: (typeof cfg.highWaterMark === 'number' + ? cfg.highWaterMark + : undefined), + }; + super(streamOpts); + + let charset = (cfg.defCharset || 'utf8'); + if (cfg.conType.params && typeof cfg.conType.params.charset === 'string') + charset = cfg.conType.params.charset; + + this.charset = charset; + + const limits = cfg.limits; + this.fieldSizeLimit = (limits && typeof limits.fieldSize === 'number' + ? limits.fieldSize + : 1 * 1024 * 1024); + this.fieldsLimit = (limits && typeof limits.fields === 'number' + ? limits.fields + : Infinity); + this.fieldNameSizeLimit = ( + limits && typeof limits.fieldNameSize === 'number' + ? limits.fieldNameSize + : 100 + ); + + this._inKey = true; + this._keyTrunc = false; + this._valTrunc = false; + this._bytesKey = 0; + this._bytesVal = 0; + this._fields = 0; + this._key = ''; + this._val = ''; + this._byte = -2; + this._lastPos = 0; + this._encode = 0; + this._decoder = getDecoder(charset); + } + + static detect(conType) { + return (conType.type === 'application' + && conType.subtype === 'x-www-form-urlencoded'); + } + + _write(chunk, enc, cb) { + if (this._fields >= this.fieldsLimit) + return cb(); + + let i = 0; + const len = chunk.length; + this._lastPos = 0; + + // Check if we last ended mid-percent-encoded byte + if (this._byte !== -2) { + i = readPctEnc(this, chunk, i, len); + if (i === -1) + return cb(new Error('Malformed urlencoded form')); + if (i >= len) + return cb(); + if (this._inKey) + ++this._bytesKey; + else + ++this._bytesVal; + } + +main: + while (i < len) { + if (this._inKey) { + // Parsing key + + i = skipKeyBytes(this, chunk, i, len); + + while (i < len) { + switch (chunk[i]) { + case 61: // '=' + if (this._lastPos < i) + this._key += chunk.latin1Slice(this._lastPos, i); + this._lastPos = ++i; + this._key = this._decoder(this._key, this._encode); + this._encode = 0; + this._inKey = false; + continue main; + case 38: // '&' + if (this._lastPos < i) + this._key += chunk.latin1Slice(this._lastPos, i); + this._lastPos = ++i; + this._key = this._decoder(this._key, this._encode); + this._encode = 0; + if (this._bytesKey > 0) { + this.emit( + 'field', + this._key, + '', + { nameTruncated: this._keyTrunc, + valueTruncated: false, + encoding: this.charset, + mimeType: 'text/plain' } + ); + } + this._key = ''; + this._val = ''; + this._keyTrunc = false; + this._valTrunc = false; + this._bytesKey = 0; + this._bytesVal = 0; + if (++this._fields >= this.fieldsLimit) { + this.emit('fieldsLimit'); + return cb(); + } + continue; + case 43: // '+' + if (this._lastPos < i) + this._key += chunk.latin1Slice(this._lastPos, i); + this._key += ' '; + this._lastPos = i + 1; + break; + case 37: // '%' + if (this._encode === 0) + this._encode = 1; + if (this._lastPos < i) + this._key += chunk.latin1Slice(this._lastPos, i); + this._lastPos = i + 1; + this._byte = -1; + i = readPctEnc(this, chunk, i + 1, len); + if (i === -1) + return cb(new Error('Malformed urlencoded form')); + if (i >= len) + return cb(); + ++this._bytesKey; + i = skipKeyBytes(this, chunk, i, len); + continue; + } + ++i; + ++this._bytesKey; + i = skipKeyBytes(this, chunk, i, len); + } + if (this._lastPos < i) + this._key += chunk.latin1Slice(this._lastPos, i); + } else { + // Parsing value + + i = skipValBytes(this, chunk, i, len); + + while (i < len) { + switch (chunk[i]) { + case 38: // '&' + if (this._lastPos < i) + this._val += chunk.latin1Slice(this._lastPos, i); + this._lastPos = ++i; + this._inKey = true; + this._val = this._decoder(this._val, this._encode); + this._encode = 0; + if (this._bytesKey > 0 || this._bytesVal > 0) { + this.emit( + 'field', + this._key, + this._val, + { nameTruncated: this._keyTrunc, + valueTruncated: this._valTrunc, + encoding: this.charset, + mimeType: 'text/plain' } + ); + } + this._key = ''; + this._val = ''; + this._keyTrunc = false; + this._valTrunc = false; + this._bytesKey = 0; + this._bytesVal = 0; + if (++this._fields >= this.fieldsLimit) { + this.emit('fieldsLimit'); + return cb(); + } + continue main; + case 43: // '+' + if (this._lastPos < i) + this._val += chunk.latin1Slice(this._lastPos, i); + this._val += ' '; + this._lastPos = i + 1; + break; + case 37: // '%' + if (this._encode === 0) + this._encode = 1; + if (this._lastPos < i) + this._val += chunk.latin1Slice(this._lastPos, i); + this._lastPos = i + 1; + this._byte = -1; + i = readPctEnc(this, chunk, i + 1, len); + if (i === -1) + return cb(new Error('Malformed urlencoded form')); + if (i >= len) + return cb(); + ++this._bytesVal; + i = skipValBytes(this, chunk, i, len); + continue; + } + ++i; + ++this._bytesVal; + i = skipValBytes(this, chunk, i, len); + } + if (this._lastPos < i) + this._val += chunk.latin1Slice(this._lastPos, i); + } + } + + cb(); + } + + _final(cb) { + if (this._byte !== -2) + return cb(new Error('Malformed urlencoded form')); + if (!this._inKey || this._bytesKey > 0 || this._bytesVal > 0) { + if (this._inKey) + this._key = this._decoder(this._key, this._encode); + else + this._val = this._decoder(this._val, this._encode); + this.emit( + 'field', + this._key, + this._val, + { nameTruncated: this._keyTrunc, + valueTruncated: this._valTrunc, + encoding: this.charset, + mimeType: 'text/plain' } + ); + } + cb(); + } +} + +function readPctEnc(self, chunk, pos, len) { + if (pos >= len) + return len; + + if (self._byte === -1) { + // We saw a '%' but no hex characters yet + const hexUpper = HEX_VALUES[chunk[pos++]]; + if (hexUpper === -1) + return -1; + + if (hexUpper >= 8) + self._encode = 2; // Indicate high bits detected + + if (pos < len) { + // Both hex characters are in this chunk + const hexLower = HEX_VALUES[chunk[pos++]]; + if (hexLower === -1) + return -1; + + if (self._inKey) + self._key += String.fromCharCode((hexUpper << 4) + hexLower); + else + self._val += String.fromCharCode((hexUpper << 4) + hexLower); + + self._byte = -2; + self._lastPos = pos; + } else { + // Only one hex character was available in this chunk + self._byte = hexUpper; + } + } else { + // We saw only one hex character so far + const hexLower = HEX_VALUES[chunk[pos++]]; + if (hexLower === -1) + return -1; + + if (self._inKey) + self._key += String.fromCharCode((self._byte << 4) + hexLower); + else + self._val += String.fromCharCode((self._byte << 4) + hexLower); + + self._byte = -2; + self._lastPos = pos; + } + + return pos; +} + +function skipKeyBytes(self, chunk, pos, len) { + // Skip bytes if we've truncated + if (self._bytesKey > self.fieldNameSizeLimit) { + if (!self._keyTrunc) { + if (self._lastPos < pos) + self._key += chunk.latin1Slice(self._lastPos, pos - 1); + } + self._keyTrunc = true; + for (; pos < len; ++pos) { + const code = chunk[pos]; + if (code === 61/* '=' */ || code === 38/* '&' */) + break; + ++self._bytesKey; + } + self._lastPos = pos; + } + + return pos; +} + +function skipValBytes(self, chunk, pos, len) { + // Skip bytes if we've truncated + if (self._bytesVal > self.fieldSizeLimit) { + if (!self._valTrunc) { + if (self._lastPos < pos) + self._val += chunk.latin1Slice(self._lastPos, pos - 1); + } + self._valTrunc = true; + for (; pos < len; ++pos) { + if (chunk[pos] === 38/* '&' */) + break; + ++self._bytesVal; + } + self._lastPos = pos; + } + + return pos; +} + +/* eslint-disable no-multi-spaces */ +const HEX_VALUES = [ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +]; +/* eslint-enable no-multi-spaces */ + +module.exports = URLEncoded; diff --git a/deps/undici/src/node_modules/busboy/lib/utils.js b/deps/undici/src/node_modules/busboy/lib/utils.js new file mode 100644 index 00000000000000..8274f6c3aef47a --- /dev/null +++ b/deps/undici/src/node_modules/busboy/lib/utils.js @@ -0,0 +1,596 @@ +'use strict'; + +function parseContentType(str) { + if (str.length === 0) + return; + + const params = Object.create(null); + let i = 0; + + // Parse type + for (; i < str.length; ++i) { + const code = str.charCodeAt(i); + if (TOKEN[code] !== 1) { + if (code !== 47/* '/' */ || i === 0) + return; + break; + } + } + // Check for type without subtype + if (i === str.length) + return; + + const type = str.slice(0, i).toLowerCase(); + + // Parse subtype + const subtypeStart = ++i; + for (; i < str.length; ++i) { + const code = str.charCodeAt(i); + if (TOKEN[code] !== 1) { + // Make sure we have a subtype + if (i === subtypeStart) + return; + + if (parseContentTypeParams(str, i, params) === undefined) + return; + break; + } + } + // Make sure we have a subtype + if (i === subtypeStart) + return; + + const subtype = str.slice(subtypeStart, i).toLowerCase(); + + return { type, subtype, params }; +} + +function parseContentTypeParams(str, i, params) { + while (i < str.length) { + // Consume whitespace + for (; i < str.length; ++i) { + const code = str.charCodeAt(i); + if (code !== 32/* ' ' */ && code !== 9/* '\t' */) + break; + } + + // Ended on whitespace + if (i === str.length) + break; + + // Check for malformed parameter + if (str.charCodeAt(i++) !== 59/* ';' */) + return; + + // Consume whitespace + for (; i < str.length; ++i) { + const code = str.charCodeAt(i); + if (code !== 32/* ' ' */ && code !== 9/* '\t' */) + break; + } + + // Ended on whitespace (malformed) + if (i === str.length) + return; + + let name; + const nameStart = i; + // Parse parameter name + for (; i < str.length; ++i) { + const code = str.charCodeAt(i); + if (TOKEN[code] !== 1) { + if (code !== 61/* '=' */) + return; + break; + } + } + + // No value (malformed) + if (i === str.length) + return; + + name = str.slice(nameStart, i); + ++i; // Skip over '=' + + // No value (malformed) + if (i === str.length) + return; + + let value = ''; + let valueStart; + if (str.charCodeAt(i) === 34/* '"' */) { + valueStart = ++i; + let escaping = false; + // Parse quoted value + for (; i < str.length; ++i) { + const code = str.charCodeAt(i); + if (code === 92/* '\\' */) { + if (escaping) { + valueStart = i; + escaping = false; + } else { + value += str.slice(valueStart, i); + escaping = true; + } + continue; + } + if (code === 34/* '"' */) { + if (escaping) { + valueStart = i; + escaping = false; + continue; + } + value += str.slice(valueStart, i); + break; + } + if (escaping) { + valueStart = i - 1; + escaping = false; + } + // Invalid unescaped quoted character (malformed) + if (QDTEXT[code] !== 1) + return; + } + + // No end quote (malformed) + if (i === str.length) + return; + + ++i; // Skip over double quote + } else { + valueStart = i; + // Parse unquoted value + for (; i < str.length; ++i) { + const code = str.charCodeAt(i); + if (TOKEN[code] !== 1) { + // No value (malformed) + if (i === valueStart) + return; + break; + } + } + value = str.slice(valueStart, i); + } + + name = name.toLowerCase(); + if (params[name] === undefined) + params[name] = value; + } + + return params; +} + +function parseDisposition(str, defDecoder) { + if (str.length === 0) + return; + + const params = Object.create(null); + let i = 0; + + for (; i < str.length; ++i) { + const code = str.charCodeAt(i); + if (TOKEN[code] !== 1) { + if (parseDispositionParams(str, i, params, defDecoder) === undefined) + return; + break; + } + } + + const type = str.slice(0, i).toLowerCase(); + + return { type, params }; +} + +function parseDispositionParams(str, i, params, defDecoder) { + while (i < str.length) { + // Consume whitespace + for (; i < str.length; ++i) { + const code = str.charCodeAt(i); + if (code !== 32/* ' ' */ && code !== 9/* '\t' */) + break; + } + + // Ended on whitespace + if (i === str.length) + break; + + // Check for malformed parameter + if (str.charCodeAt(i++) !== 59/* ';' */) + return; + + // Consume whitespace + for (; i < str.length; ++i) { + const code = str.charCodeAt(i); + if (code !== 32/* ' ' */ && code !== 9/* '\t' */) + break; + } + + // Ended on whitespace (malformed) + if (i === str.length) + return; + + let name; + const nameStart = i; + // Parse parameter name + for (; i < str.length; ++i) { + const code = str.charCodeAt(i); + if (TOKEN[code] !== 1) { + if (code === 61/* '=' */) + break; + return; + } + } + + // No value (malformed) + if (i === str.length) + return; + + let value = ''; + let valueStart; + let charset; + //~ let lang; + name = str.slice(nameStart, i); + if (name.charCodeAt(name.length - 1) === 42/* '*' */) { + // Extended value + + const charsetStart = ++i; + // Parse charset name + for (; i < str.length; ++i) { + const code = str.charCodeAt(i); + if (CHARSET[code] !== 1) { + if (code !== 39/* '\'' */) + return; + break; + } + } + + // Incomplete charset (malformed) + if (i === str.length) + return; + + charset = str.slice(charsetStart, i); + ++i; // Skip over the '\'' + + //~ const langStart = ++i; + // Parse language name + for (; i < str.length; ++i) { + const code = str.charCodeAt(i); + if (code === 39/* '\'' */) + break; + } + + // Incomplete language (malformed) + if (i === str.length) + return; + + //~ lang = str.slice(langStart, i); + ++i; // Skip over the '\'' + + // No value (malformed) + if (i === str.length) + return; + + valueStart = i; + + let encode = 0; + // Parse value + for (; i < str.length; ++i) { + const code = str.charCodeAt(i); + if (EXTENDED_VALUE[code] !== 1) { + if (code === 37/* '%' */) { + let hexUpper; + let hexLower; + if (i + 2 < str.length + && (hexUpper = HEX_VALUES[str.charCodeAt(i + 1)]) !== -1 + && (hexLower = HEX_VALUES[str.charCodeAt(i + 2)]) !== -1) { + const byteVal = (hexUpper << 4) + hexLower; + value += str.slice(valueStart, i); + value += String.fromCharCode(byteVal); + i += 2; + valueStart = i + 1; + if (byteVal >= 128) + encode = 2; + else if (encode === 0) + encode = 1; + continue; + } + // '%' disallowed in non-percent encoded contexts (malformed) + return; + } + break; + } + } + + value += str.slice(valueStart, i); + value = convertToUTF8(value, charset, encode); + if (value === undefined) + return; + } else { + // Non-extended value + + ++i; // Skip over '=' + + // No value (malformed) + if (i === str.length) + return; + + if (str.charCodeAt(i) === 34/* '"' */) { + valueStart = ++i; + let escaping = false; + // Parse quoted value + for (; i < str.length; ++i) { + const code = str.charCodeAt(i); + if (code === 92/* '\\' */) { + if (escaping) { + valueStart = i; + escaping = false; + } else { + value += str.slice(valueStart, i); + escaping = true; + } + continue; + } + if (code === 34/* '"' */) { + if (escaping) { + valueStart = i; + escaping = false; + continue; + } + value += str.slice(valueStart, i); + break; + } + if (escaping) { + valueStart = i - 1; + escaping = false; + } + // Invalid unescaped quoted character (malformed) + if (QDTEXT[code] !== 1) + return; + } + + // No end quote (malformed) + if (i === str.length) + return; + + ++i; // Skip over double quote + } else { + valueStart = i; + // Parse unquoted value + for (; i < str.length; ++i) { + const code = str.charCodeAt(i); + if (TOKEN[code] !== 1) { + // No value (malformed) + if (i === valueStart) + return; + break; + } + } + value = str.slice(valueStart, i); + } + + value = defDecoder(value, 2); + if (value === undefined) + return; + } + + name = name.toLowerCase(); + if (params[name] === undefined) + params[name] = value; + } + + return params; +} + +function getDecoder(charset) { + let lc; + while (true) { + switch (charset) { + case 'utf-8': + case 'utf8': + return decoders.utf8; + case 'latin1': + case 'ascii': // TODO: Make these a separate, strict decoder? + case 'us-ascii': + case 'iso-8859-1': + case 'iso8859-1': + case 'iso88591': + case 'iso_8859-1': + case 'windows-1252': + case 'iso_8859-1:1987': + case 'cp1252': + case 'x-cp1252': + return decoders.latin1; + case 'utf16le': + case 'utf-16le': + case 'ucs2': + case 'ucs-2': + return decoders.utf16le; + case 'base64': + return decoders.base64; + default: + if (lc === undefined) { + lc = true; + charset = charset.toLowerCase(); + continue; + } + return decoders.other.bind(charset); + } + } +} + +const decoders = { + utf8: (data, hint) => { + if (data.length === 0) + return ''; + if (typeof data === 'string') { + // If `data` never had any percent-encoded bytes or never had any that + // were outside of the ASCII range, then we can safely just return the + // input since UTF-8 is ASCII compatible + if (hint < 2) + return data; + + data = Buffer.from(data, 'latin1'); + } + return data.utf8Slice(0, data.length); + }, + + latin1: (data, hint) => { + if (data.length === 0) + return ''; + if (typeof data === 'string') + return data; + return data.latin1Slice(0, data.length); + }, + + utf16le: (data, hint) => { + if (data.length === 0) + return ''; + if (typeof data === 'string') + data = Buffer.from(data, 'latin1'); + return data.ucs2Slice(0, data.length); + }, + + base64: (data, hint) => { + if (data.length === 0) + return ''; + if (typeof data === 'string') + data = Buffer.from(data, 'latin1'); + return data.base64Slice(0, data.length); + }, + + other: (data, hint) => { + if (data.length === 0) + return ''; + if (typeof data === 'string') + data = Buffer.from(data, 'latin1'); + try { + const decoder = new TextDecoder(this); + return decoder.decode(data); + } catch {} + }, +}; + +function convertToUTF8(data, charset, hint) { + const decode = getDecoder(charset); + if (decode) + return decode(data, hint); +} + +function basename(path) { + if (typeof path !== 'string') + return ''; + for (let i = path.length - 1; i >= 0; --i) { + switch (path.charCodeAt(i)) { + case 0x2F: // '/' + case 0x5C: // '\' + path = path.slice(i + 1); + return (path === '..' || path === '.' ? '' : path); + } + } + return (path === '..' || path === '.' ? '' : path); +} + +const TOKEN = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +]; + +const QDTEXT = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +]; + +const CHARSET = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +]; + +const EXTENDED_VALUE = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +]; + +/* eslint-disable no-multi-spaces */ +const HEX_VALUES = [ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +]; +/* eslint-enable no-multi-spaces */ + +module.exports = { + basename, + convertToUTF8, + getDecoder, + parseContentType, + parseDisposition, +}; diff --git a/deps/undici/src/node_modules/busboy/package.json b/deps/undici/src/node_modules/busboy/package.json new file mode 100644 index 00000000000000..ac2577fe2c5873 --- /dev/null +++ b/deps/undici/src/node_modules/busboy/package.json @@ -0,0 +1,22 @@ +{ "name": "busboy", + "version": "1.6.0", + "author": "Brian White ", + "description": "A streaming parser for HTML form data for node.js", + "main": "./lib/index.js", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "devDependencies": { + "@mscdex/eslint-config": "^1.1.0", + "eslint": "^7.32.0" + }, + "scripts": { + "test": "node test/test.js", + "lint": "eslint --cache --report-unused-disable-directives --ext=.js .eslintrc.js lib test bench", + "lint:fix": "npm run lint -- --fix" + }, + "engines": { "node": ">=10.16.0" }, + "keywords": [ "uploads", "forms", "multipart", "form-data" ], + "licenses": [ { "type": "MIT", "url": "http://github.com/mscdex/busboy/raw/master/LICENSE" } ], + "repository": { "type": "git", "url": "http://github.com/mscdex/busboy.git" } +} diff --git a/deps/undici/src/node_modules/busboy/test/common.js b/deps/undici/src/node_modules/busboy/test/common.js new file mode 100644 index 00000000000000..fb82ad81b1b9ef --- /dev/null +++ b/deps/undici/src/node_modules/busboy/test/common.js @@ -0,0 +1,109 @@ +'use strict'; + +const assert = require('assert'); +const { inspect } = require('util'); + +const mustCallChecks = []; + +function noop() {} + +function runCallChecks(exitCode) { + if (exitCode !== 0) return; + + const failed = mustCallChecks.filter((context) => { + if ('minimum' in context) { + context.messageSegment = `at least ${context.minimum}`; + return context.actual < context.minimum; + } + context.messageSegment = `exactly ${context.exact}`; + return context.actual !== context.exact; + }); + + failed.forEach((context) => { + console.error('Mismatched %s function calls. Expected %s, actual %d.', + context.name, + context.messageSegment, + context.actual); + console.error(context.stack.split('\n').slice(2).join('\n')); + }); + + if (failed.length) + process.exit(1); +} + +function mustCall(fn, exact) { + return _mustCallInner(fn, exact, 'exact'); +} + +function mustCallAtLeast(fn, minimum) { + return _mustCallInner(fn, minimum, 'minimum'); +} + +function _mustCallInner(fn, criteria = 1, field) { + if (process._exiting) + throw new Error('Cannot use common.mustCall*() in process exit handler'); + + if (typeof fn === 'number') { + criteria = fn; + fn = noop; + } else if (fn === undefined) { + fn = noop; + } + + if (typeof criteria !== 'number') + throw new TypeError(`Invalid ${field} value: ${criteria}`); + + const context = { + [field]: criteria, + actual: 0, + stack: inspect(new Error()), + name: fn.name || '' + }; + + // Add the exit listener only once to avoid listener leak warnings + if (mustCallChecks.length === 0) + process.on('exit', runCallChecks); + + mustCallChecks.push(context); + + function wrapped(...args) { + ++context.actual; + return fn.call(this, ...args); + } + // TODO: remove origFn? + wrapped.origFn = fn; + + return wrapped; +} + +function getCallSite(top) { + const originalStackFormatter = Error.prepareStackTrace; + Error.prepareStackTrace = (err, stack) => + `${stack[0].getFileName()}:${stack[0].getLineNumber()}`; + const err = new Error(); + Error.captureStackTrace(err, top); + // With the V8 Error API, the stack is not formatted until it is accessed + // eslint-disable-next-line no-unused-expressions + err.stack; + Error.prepareStackTrace = originalStackFormatter; + return err.stack; +} + +function mustNotCall(msg) { + const callSite = getCallSite(mustNotCall); + return function mustNotCall(...args) { + args = args.map(inspect).join(', '); + const argsInfo = (args.length > 0 + ? `\ncalled with arguments: ${args}` + : ''); + assert.fail( + `${msg || 'function should not have been called'} at ${callSite}` + + argsInfo); + }; +} + +module.exports = { + mustCall, + mustCallAtLeast, + mustNotCall, +}; diff --git a/deps/undici/src/node_modules/busboy/test/test-types-multipart-charsets.js b/deps/undici/src/node_modules/busboy/test/test-types-multipart-charsets.js new file mode 100644 index 00000000000000..ed9c38aeb6c1f3 --- /dev/null +++ b/deps/undici/src/node_modules/busboy/test/test-types-multipart-charsets.js @@ -0,0 +1,94 @@ +'use strict'; + +const assert = require('assert'); +const { inspect } = require('util'); + +const { mustCall } = require(`${__dirname}/common.js`); + +const busboy = require('..'); + +const input = Buffer.from([ + '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + 'Content-Disposition: form-data; ' + + 'name="upload_file_0"; filename="テスト.dat"', + 'Content-Type: application/octet-stream', + '', + 'A'.repeat(1023), + '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--' +].join('\r\n')); +const boundary = '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k'; +const expected = [ + { type: 'file', + name: 'upload_file_0', + data: Buffer.from('A'.repeat(1023)), + info: { + filename: 'テスト.dat', + encoding: '7bit', + mimeType: 'application/octet-stream', + }, + limited: false, + }, +]; +const bb = busboy({ + defParamCharset: 'utf8', + headers: { + 'content-type': `multipart/form-data; boundary=${boundary}`, + } +}); +const results = []; + +bb.on('field', (name, val, info) => { + results.push({ type: 'field', name, val, info }); +}); + +bb.on('file', (name, stream, info) => { + const data = []; + let nb = 0; + const file = { + type: 'file', + name, + data: null, + info, + limited: false, + }; + results.push(file); + stream.on('data', (d) => { + data.push(d); + nb += d.length; + }).on('limit', () => { + file.limited = true; + }).on('close', () => { + file.data = Buffer.concat(data, nb); + assert.strictEqual(stream.truncated, file.limited); + }).once('error', (err) => { + file.err = err.message; + }); +}); + +bb.on('error', (err) => { + results.push({ error: err.message }); +}); + +bb.on('partsLimit', () => { + results.push('partsLimit'); +}); + +bb.on('filesLimit', () => { + results.push('filesLimit'); +}); + +bb.on('fieldsLimit', () => { + results.push('fieldsLimit'); +}); + +bb.on('close', mustCall(() => { + assert.deepStrictEqual( + results, + expected, + 'Results mismatch.\n' + + `Parsed: ${inspect(results)}\n` + + `Expected: ${inspect(expected)}` + ); +})); + +bb.end(input); diff --git a/deps/undici/src/node_modules/busboy/test/test-types-multipart-stream-pause.js b/deps/undici/src/node_modules/busboy/test/test-types-multipart-stream-pause.js new file mode 100644 index 00000000000000..df7268a4b17f73 --- /dev/null +++ b/deps/undici/src/node_modules/busboy/test/test-types-multipart-stream-pause.js @@ -0,0 +1,102 @@ +'use strict'; + +const assert = require('assert'); +const { randomFillSync } = require('crypto'); +const { inspect } = require('util'); + +const busboy = require('..'); + +const { mustCall } = require('./common.js'); + +const BOUNDARY = 'u2KxIV5yF1y+xUspOQCCZopaVgeV6Jxihv35XQJmuTx8X3sh'; + +function formDataSection(key, value) { + return Buffer.from( + `\r\n--${BOUNDARY}` + + `\r\nContent-Disposition: form-data; name="${key}"` + + `\r\n\r\n${value}` + ); +} + +function formDataFile(key, filename, contentType) { + const buf = Buffer.allocUnsafe(100000); + return Buffer.concat([ + Buffer.from(`\r\n--${BOUNDARY}\r\n`), + Buffer.from(`Content-Disposition: form-data; name="${key}"` + + `; filename="${filename}"\r\n`), + Buffer.from(`Content-Type: ${contentType}\r\n\r\n`), + randomFillSync(buf) + ]); +} + +const reqChunks = [ + Buffer.concat([ + formDataFile('file', 'file.bin', 'application/octet-stream'), + formDataSection('foo', 'foo value'), + ]), + formDataSection('bar', 'bar value'), + Buffer.from(`\r\n--${BOUNDARY}--\r\n`) +]; +const bb = busboy({ + headers: { + 'content-type': `multipart/form-data; boundary=${BOUNDARY}` + } +}); +const expected = [ + { type: 'file', + name: 'file', + info: { + filename: 'file.bin', + encoding: '7bit', + mimeType: 'application/octet-stream', + }, + }, + { type: 'field', + name: 'foo', + val: 'foo value', + info: { + nameTruncated: false, + valueTruncated: false, + encoding: '7bit', + mimeType: 'text/plain', + }, + }, + { type: 'field', + name: 'bar', + val: 'bar value', + info: { + nameTruncated: false, + valueTruncated: false, + encoding: '7bit', + mimeType: 'text/plain', + }, + }, +]; +const results = []; + +bb.on('field', (name, val, info) => { + results.push({ type: 'field', name, val, info }); +}); + +bb.on('file', (name, stream, info) => { + results.push({ type: 'file', name, info }); + // Simulate a pipe where the destination is pausing (perhaps due to waiting + // for file system write to finish) + setTimeout(() => { + stream.resume(); + }, 10); +}); + +bb.on('close', mustCall(() => { + assert.deepStrictEqual( + results, + expected, + 'Results mismatch.\n' + + `Parsed: ${inspect(results)}\n` + + `Expected: ${inspect(expected)}` + ); +})); + +for (const chunk of reqChunks) + bb.write(chunk); +bb.end(); diff --git a/deps/undici/src/node_modules/busboy/test/test-types-multipart.js b/deps/undici/src/node_modules/busboy/test/test-types-multipart.js new file mode 100644 index 00000000000000..9755642ad9060c --- /dev/null +++ b/deps/undici/src/node_modules/busboy/test/test-types-multipart.js @@ -0,0 +1,1053 @@ +'use strict'; + +const assert = require('assert'); +const { inspect } = require('util'); + +const busboy = require('..'); + +const active = new Map(); + +const tests = [ + { source: [ + ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + 'Content-Disposition: form-data; name="file_name_0"', + '', + 'super alpha file', + '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + 'Content-Disposition: form-data; name="file_name_1"', + '', + 'super beta file', + '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + 'Content-Disposition: form-data; ' + + 'name="upload_file_0"; filename="1k_a.dat"', + 'Content-Type: application/octet-stream', + '', + 'A'.repeat(1023), + '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + 'Content-Disposition: form-data; ' + + 'name="upload_file_1"; filename="1k_b.dat"', + 'Content-Type: application/octet-stream', + '', + 'B'.repeat(1023), + '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--' + ].join('\r\n') + ], + boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + expected: [ + { type: 'field', + name: 'file_name_0', + val: 'super alpha file', + info: { + nameTruncated: false, + valueTruncated: false, + encoding: '7bit', + mimeType: 'text/plain', + }, + }, + { type: 'field', + name: 'file_name_1', + val: 'super beta file', + info: { + nameTruncated: false, + valueTruncated: false, + encoding: '7bit', + mimeType: 'text/plain', + }, + }, + { type: 'file', + name: 'upload_file_0', + data: Buffer.from('A'.repeat(1023)), + info: { + filename: '1k_a.dat', + encoding: '7bit', + mimeType: 'application/octet-stream', + }, + limited: false, + }, + { type: 'file', + name: 'upload_file_1', + data: Buffer.from('B'.repeat(1023)), + info: { + filename: '1k_b.dat', + encoding: '7bit', + mimeType: 'application/octet-stream', + }, + limited: false, + }, + ], + what: 'Fields and files' + }, + { source: [ + ['------WebKitFormBoundaryTB2MiQ36fnSJlrhY', + 'Content-Disposition: form-data; name="cont"', + '', + 'some random content', + '------WebKitFormBoundaryTB2MiQ36fnSJlrhY', + 'Content-Disposition: form-data; name="pass"', + '', + 'some random pass', + '------WebKitFormBoundaryTB2MiQ36fnSJlrhY', + 'Content-Disposition: form-data; name=bit', + '', + '2', + '------WebKitFormBoundaryTB2MiQ36fnSJlrhY--' + ].join('\r\n') + ], + boundary: '----WebKitFormBoundaryTB2MiQ36fnSJlrhY', + expected: [ + { type: 'field', + name: 'cont', + val: 'some random content', + info: { + nameTruncated: false, + valueTruncated: false, + encoding: '7bit', + mimeType: 'text/plain', + }, + }, + { type: 'field', + name: 'pass', + val: 'some random pass', + info: { + nameTruncated: false, + valueTruncated: false, + encoding: '7bit', + mimeType: 'text/plain', + }, + }, + { type: 'field', + name: 'bit', + val: '2', + info: { + nameTruncated: false, + valueTruncated: false, + encoding: '7bit', + mimeType: 'text/plain', + }, + }, + ], + what: 'Fields only' + }, + { source: [ + '' + ], + boundary: '----WebKitFormBoundaryTB2MiQ36fnSJlrhY', + expected: [ + { error: 'Unexpected end of form' }, + ], + what: 'No fields and no files' + }, + { source: [ + ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + 'Content-Disposition: form-data; name="file_name_0"', + '', + 'super alpha file', + '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + 'Content-Disposition: form-data; ' + + 'name="upload_file_0"; filename="1k_a.dat"', + 'Content-Type: application/octet-stream', + '', + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', + '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--' + ].join('\r\n') + ], + boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + limits: { + fileSize: 13, + fieldSize: 5 + }, + expected: [ + { type: 'field', + name: 'file_name_0', + val: 'super', + info: { + nameTruncated: false, + valueTruncated: true, + encoding: '7bit', + mimeType: 'text/plain', + }, + }, + { type: 'file', + name: 'upload_file_0', + data: Buffer.from('ABCDEFGHIJKLM'), + info: { + filename: '1k_a.dat', + encoding: '7bit', + mimeType: 'application/octet-stream', + }, + limited: true, + }, + ], + what: 'Fields and files (limits)' + }, + { source: [ + ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + 'Content-Disposition: form-data; name="file_name_0"', + '', + 'super alpha file', + '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + 'Content-Disposition: form-data; ' + + 'name="upload_file_0"; filename="1k_a.dat"', + 'Content-Type: application/octet-stream', + '', + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', + '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--' + ].join('\r\n') + ], + boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + limits: { + files: 0 + }, + expected: [ + { type: 'field', + name: 'file_name_0', + val: 'super alpha file', + info: { + nameTruncated: false, + valueTruncated: false, + encoding: '7bit', + mimeType: 'text/plain', + }, + }, + 'filesLimit', + ], + what: 'Fields and files (limits: 0 files)' + }, + { source: [ + ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + 'Content-Disposition: form-data; name="file_name_0"', + '', + 'super alpha file', + '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + 'Content-Disposition: form-data; name="file_name_1"', + '', + 'super beta file', + '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + 'Content-Disposition: form-data; ' + + 'name="upload_file_0"; filename="1k_a.dat"', + 'Content-Type: application/octet-stream', + '', + 'A'.repeat(1023), + '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + 'Content-Disposition: form-data; ' + + 'name="upload_file_1"; filename="1k_b.dat"', + 'Content-Type: application/octet-stream', + '', + 'B'.repeat(1023), + '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--' + ].join('\r\n') + ], + boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + expected: [ + { type: 'field', + name: 'file_name_0', + val: 'super alpha file', + info: { + nameTruncated: false, + valueTruncated: false, + encoding: '7bit', + mimeType: 'text/plain', + }, + }, + { type: 'field', + name: 'file_name_1', + val: 'super beta file', + info: { + nameTruncated: false, + valueTruncated: false, + encoding: '7bit', + mimeType: 'text/plain', + }, + }, + ], + events: ['field'], + what: 'Fields and (ignored) files' + }, + { source: [ + ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + 'Content-Disposition: form-data; ' + + 'name="upload_file_0"; filename="/tmp/1k_a.dat"', + 'Content-Type: application/octet-stream', + '', + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', + '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + 'Content-Disposition: form-data; ' + + 'name="upload_file_1"; filename="C:\\files\\1k_b.dat"', + 'Content-Type: application/octet-stream', + '', + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', + '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + 'Content-Disposition: form-data; ' + + 'name="upload_file_2"; filename="relative/1k_c.dat"', + 'Content-Type: application/octet-stream', + '', + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', + '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--' + ].join('\r\n') + ], + boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + expected: [ + { type: 'file', + name: 'upload_file_0', + data: Buffer.from('ABCDEFGHIJKLMNOPQRSTUVWXYZ'), + info: { + filename: '1k_a.dat', + encoding: '7bit', + mimeType: 'application/octet-stream', + }, + limited: false, + }, + { type: 'file', + name: 'upload_file_1', + data: Buffer.from('ABCDEFGHIJKLMNOPQRSTUVWXYZ'), + info: { + filename: '1k_b.dat', + encoding: '7bit', + mimeType: 'application/octet-stream', + }, + limited: false, + }, + { type: 'file', + name: 'upload_file_2', + data: Buffer.from('ABCDEFGHIJKLMNOPQRSTUVWXYZ'), + info: { + filename: '1k_c.dat', + encoding: '7bit', + mimeType: 'application/octet-stream', + }, + limited: false, + }, + ], + what: 'Files with filenames containing paths' + }, + { source: [ + ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + 'Content-Disposition: form-data; ' + + 'name="upload_file_0"; filename="/absolute/1k_a.dat"', + 'Content-Type: application/octet-stream', + '', + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', + '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + 'Content-Disposition: form-data; ' + + 'name="upload_file_1"; filename="C:\\absolute\\1k_b.dat"', + 'Content-Type: application/octet-stream', + '', + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', + '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + 'Content-Disposition: form-data; ' + + 'name="upload_file_2"; filename="relative/1k_c.dat"', + 'Content-Type: application/octet-stream', + '', + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', + '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--' + ].join('\r\n') + ], + boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + preservePath: true, + expected: [ + { type: 'file', + name: 'upload_file_0', + data: Buffer.from('ABCDEFGHIJKLMNOPQRSTUVWXYZ'), + info: { + filename: '/absolute/1k_a.dat', + encoding: '7bit', + mimeType: 'application/octet-stream', + }, + limited: false, + }, + { type: 'file', + name: 'upload_file_1', + data: Buffer.from('ABCDEFGHIJKLMNOPQRSTUVWXYZ'), + info: { + filename: 'C:\\absolute\\1k_b.dat', + encoding: '7bit', + mimeType: 'application/octet-stream', + }, + limited: false, + }, + { type: 'file', + name: 'upload_file_2', + data: Buffer.from('ABCDEFGHIJKLMNOPQRSTUVWXYZ'), + info: { + filename: 'relative/1k_c.dat', + encoding: '7bit', + mimeType: 'application/octet-stream', + }, + limited: false, + }, + ], + what: 'Paths to be preserved through the preservePath option' + }, + { source: [ + ['------WebKitFormBoundaryTB2MiQ36fnSJlrhY', + 'Content-Disposition: form-data; name="cont"', + 'Content-Type: ', + '', + 'some random content', + '------WebKitFormBoundaryTB2MiQ36fnSJlrhY', + 'Content-Disposition: ', + '', + 'some random pass', + '------WebKitFormBoundaryTB2MiQ36fnSJlrhY--' + ].join('\r\n') + ], + boundary: '----WebKitFormBoundaryTB2MiQ36fnSJlrhY', + expected: [ + { type: 'field', + name: 'cont', + val: 'some random content', + info: { + nameTruncated: false, + valueTruncated: false, + encoding: '7bit', + mimeType: 'text/plain', + }, + }, + ], + what: 'Empty content-type and empty content-disposition' + }, + { source: [ + ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + 'Content-Disposition: form-data; ' + + 'name="file"; filename*=utf-8\'\'n%C3%A4me.txt', + 'Content-Type: application/octet-stream', + '', + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', + '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--' + ].join('\r\n') + ], + boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + expected: [ + { type: 'file', + name: 'file', + data: Buffer.from('ABCDEFGHIJKLMNOPQRSTUVWXYZ'), + info: { + filename: 'näme.txt', + encoding: '7bit', + mimeType: 'application/octet-stream', + }, + limited: false, + }, + ], + what: 'Unicode filenames' + }, + { source: [ + ['--asdasdasdasd\r\n', + 'Content-Type: text/plain\r\n', + 'Content-Disposition: form-data; name="foo"\r\n', + '\r\n', + 'asd\r\n', + '--asdasdasdasd--' + ].join(':)') + ], + boundary: 'asdasdasdasd', + expected: [ + { error: 'Malformed part header' }, + { error: 'Unexpected end of form' }, + ], + what: 'Stopped mid-header' + }, + { source: [ + ['------WebKitFormBoundaryTB2MiQ36fnSJlrhY', + 'Content-Disposition: form-data; name="cont"', + 'Content-Type: application/json', + '', + '{}', + '------WebKitFormBoundaryTB2MiQ36fnSJlrhY--', + ].join('\r\n') + ], + boundary: '----WebKitFormBoundaryTB2MiQ36fnSJlrhY', + expected: [ + { type: 'field', + name: 'cont', + val: '{}', + info: { + nameTruncated: false, + valueTruncated: false, + encoding: '7bit', + mimeType: 'application/json', + }, + }, + ], + what: 'content-type for fields' + }, + { source: [ + '------WebKitFormBoundaryTB2MiQ36fnSJlrhY--', + ], + boundary: '----WebKitFormBoundaryTB2MiQ36fnSJlrhY', + expected: [], + what: 'empty form' + }, + { source: [ + ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + 'Content-Disposition: form-data; ' + + 'name=upload_file_0; filename="1k_a.dat"', + 'Content-Type: application/octet-stream', + 'Content-Transfer-Encoding: binary', + '', + '', + ].join('\r\n') + ], + boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + expected: [ + { type: 'file', + name: 'upload_file_0', + data: Buffer.alloc(0), + info: { + filename: '1k_a.dat', + encoding: 'binary', + mimeType: 'application/octet-stream', + }, + limited: false, + err: 'Unexpected end of form', + }, + { error: 'Unexpected end of form' }, + ], + what: 'Stopped mid-file #1' + }, + { source: [ + ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + 'Content-Disposition: form-data; ' + + 'name=upload_file_0; filename="1k_a.dat"', + 'Content-Type: application/octet-stream', + '', + 'a', + ].join('\r\n') + ], + boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + expected: [ + { type: 'file', + name: 'upload_file_0', + data: Buffer.from('a'), + info: { + filename: '1k_a.dat', + encoding: '7bit', + mimeType: 'application/octet-stream', + }, + limited: false, + err: 'Unexpected end of form', + }, + { error: 'Unexpected end of form' }, + ], + what: 'Stopped mid-file #2' + }, + { source: [ + ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + 'Content-Disposition: form-data; ' + + 'name="upload_file_0"; filename="notes.txt"', + 'Content-Type: text/plain; charset=utf8', + '', + 'a', + '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--', + ].join('\r\n') + ], + boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + expected: [ + { type: 'file', + name: 'upload_file_0', + data: Buffer.from('a'), + info: { + filename: 'notes.txt', + encoding: '7bit', + mimeType: 'text/plain', + }, + limited: false, + }, + ], + what: 'Text file with charset' + }, + { source: [ + ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + 'Content-Disposition: form-data; ' + + 'name="upload_file_0"; filename="notes.txt"', + 'Content-Type: ', + ' text/plain; charset=utf8', + '', + 'a', + '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--', + ].join('\r\n') + ], + boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + expected: [ + { type: 'file', + name: 'upload_file_0', + data: Buffer.from('a'), + info: { + filename: 'notes.txt', + encoding: '7bit', + mimeType: 'text/plain', + }, + limited: false, + }, + ], + what: 'Folded header value' + }, + { source: [ + ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + 'Content-Type: text/plain; charset=utf8', + '', + 'a', + '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--', + ].join('\r\n') + ], + boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + expected: [], + what: 'No Content-Disposition' + }, + { source: [ + ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + 'Content-Disposition: form-data; name="file_name_0"', + '', + 'a'.repeat(64 * 1024), + '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + 'Content-Disposition: form-data; ' + + 'name="upload_file_0"; filename="notes.txt"', + 'Content-Type: ', + ' text/plain; charset=utf8', + '', + 'bc', + '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--', + ].join('\r\n') + ], + boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + limits: { + fieldSize: Infinity, + }, + expected: [ + { type: 'file', + name: 'upload_file_0', + data: Buffer.from('bc'), + info: { + filename: 'notes.txt', + encoding: '7bit', + mimeType: 'text/plain', + }, + limited: false, + }, + ], + events: [ 'file' ], + what: 'Skip field parts if no listener' + }, + { source: [ + ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + 'Content-Disposition: form-data; name="file_name_0"', + '', + 'a', + '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + 'Content-Disposition: form-data; ' + + 'name="upload_file_0"; filename="notes.txt"', + 'Content-Type: ', + ' text/plain; charset=utf8', + '', + 'bc', + '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--', + ].join('\r\n') + ], + boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + limits: { + parts: 1, + }, + expected: [ + { type: 'field', + name: 'file_name_0', + val: 'a', + info: { + nameTruncated: false, + valueTruncated: false, + encoding: '7bit', + mimeType: 'text/plain', + }, + }, + 'partsLimit', + ], + what: 'Parts limit' + }, + { source: [ + ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + 'Content-Disposition: form-data; name="file_name_0"', + '', + 'a', + '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + 'Content-Disposition: form-data; name="file_name_1"', + '', + 'b', + '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--', + ].join('\r\n') + ], + boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + limits: { + fields: 1, + }, + expected: [ + { type: 'field', + name: 'file_name_0', + val: 'a', + info: { + nameTruncated: false, + valueTruncated: false, + encoding: '7bit', + mimeType: 'text/plain', + }, + }, + 'fieldsLimit', + ], + what: 'Fields limit' + }, + { source: [ + ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + 'Content-Disposition: form-data; ' + + 'name="upload_file_0"; filename="notes.txt"', + 'Content-Type: text/plain; charset=utf8', + '', + 'ab', + '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + 'Content-Disposition: form-data; ' + + 'name="upload_file_1"; filename="notes2.txt"', + 'Content-Type: text/plain; charset=utf8', + '', + 'cd', + '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--', + ].join('\r\n') + ], + boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + limits: { + files: 1, + }, + expected: [ + { type: 'file', + name: 'upload_file_0', + data: Buffer.from('ab'), + info: { + filename: 'notes.txt', + encoding: '7bit', + mimeType: 'text/plain', + }, + limited: false, + }, + 'filesLimit', + ], + what: 'Files limit' + }, + { source: [ + ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + 'Content-Disposition: form-data; ' + + `name="upload_file_0"; filename="${'a'.repeat(64 * 1024)}.txt"`, + 'Content-Type: text/plain; charset=utf8', + '', + 'ab', + '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + 'Content-Disposition: form-data; ' + + 'name="upload_file_1"; filename="notes2.txt"', + 'Content-Type: text/plain; charset=utf8', + '', + 'cd', + '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--', + ].join('\r\n') + ], + boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + expected: [ + { error: 'Malformed part header' }, + { type: 'file', + name: 'upload_file_1', + data: Buffer.from('cd'), + info: { + filename: 'notes2.txt', + encoding: '7bit', + mimeType: 'text/plain', + }, + limited: false, + }, + ], + what: 'Oversized part header' + }, + { source: [ + ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + 'Content-Disposition: form-data; ' + + 'name="upload_file_0"; filename="notes.txt"', + 'Content-Type: text/plain; charset=utf8', + '', + 'a'.repeat(31) + '\r', + ].join('\r\n'), + 'b'.repeat(40), + '\r\n-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--', + ], + boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + fileHwm: 32, + expected: [ + { type: 'file', + name: 'upload_file_0', + data: Buffer.from('a'.repeat(31) + '\r' + 'b'.repeat(40)), + info: { + filename: 'notes.txt', + encoding: '7bit', + mimeType: 'text/plain', + }, + limited: false, + }, + ], + what: 'Lookbehind data should not stall file streams' + }, + { source: [ + ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + 'Content-Disposition: form-data; ' + + `name="upload_file_0"; filename="${'a'.repeat(8 * 1024)}.txt"`, + 'Content-Type: text/plain; charset=utf8', + '', + 'ab', + '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + 'Content-Disposition: form-data; ' + + `name="upload_file_1"; filename="${'b'.repeat(8 * 1024)}.txt"`, + 'Content-Type: text/plain; charset=utf8', + '', + 'cd', + '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + 'Content-Disposition: form-data; ' + + `name="upload_file_2"; filename="${'c'.repeat(8 * 1024)}.txt"`, + 'Content-Type: text/plain; charset=utf8', + '', + 'ef', + '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--', + ].join('\r\n') + ], + boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k', + expected: [ + { type: 'file', + name: 'upload_file_0', + data: Buffer.from('ab'), + info: { + filename: `${'a'.repeat(8 * 1024)}.txt`, + encoding: '7bit', + mimeType: 'text/plain', + }, + limited: false, + }, + { type: 'file', + name: 'upload_file_1', + data: Buffer.from('cd'), + info: { + filename: `${'b'.repeat(8 * 1024)}.txt`, + encoding: '7bit', + mimeType: 'text/plain', + }, + limited: false, + }, + { type: 'file', + name: 'upload_file_2', + data: Buffer.from('ef'), + info: { + filename: `${'c'.repeat(8 * 1024)}.txt`, + encoding: '7bit', + mimeType: 'text/plain', + }, + limited: false, + }, + ], + what: 'Header size limit should be per part' + }, + { source: [ + '\r\n--d1bf46b3-aa33-4061-b28d-6c5ced8b08ee\r\n', + 'Content-Type: application/gzip\r\n' + + 'Content-Encoding: gzip\r\n' + + 'Content-Disposition: form-data; name=batch-1; filename=batch-1' + + '\r\n\r\n', + '\r\n--d1bf46b3-aa33-4061-b28d-6c5ced8b08ee--', + ], + boundary: 'd1bf46b3-aa33-4061-b28d-6c5ced8b08ee', + expected: [ + { type: 'file', + name: 'batch-1', + data: Buffer.alloc(0), + info: { + filename: 'batch-1', + encoding: '7bit', + mimeType: 'application/gzip', + }, + limited: false, + }, + ], + what: 'Empty part' + }, +]; + +for (const test of tests) { + active.set(test, 1); + + const { what, boundary, events, limits, preservePath, fileHwm } = test; + const bb = busboy({ + fileHwm, + limits, + preservePath, + headers: { + 'content-type': `multipart/form-data; boundary=${boundary}`, + } + }); + const results = []; + + if (events === undefined || events.includes('field')) { + bb.on('field', (name, val, info) => { + results.push({ type: 'field', name, val, info }); + }); + } + + if (events === undefined || events.includes('file')) { + bb.on('file', (name, stream, info) => { + const data = []; + let nb = 0; + const file = { + type: 'file', + name, + data: null, + info, + limited: false, + }; + results.push(file); + stream.on('data', (d) => { + data.push(d); + nb += d.length; + }).on('limit', () => { + file.limited = true; + }).on('close', () => { + file.data = Buffer.concat(data, nb); + assert.strictEqual(stream.truncated, file.limited); + }).once('error', (err) => { + file.err = err.message; + }); + }); + } + + bb.on('error', (err) => { + results.push({ error: err.message }); + }); + + bb.on('partsLimit', () => { + results.push('partsLimit'); + }); + + bb.on('filesLimit', () => { + results.push('filesLimit'); + }); + + bb.on('fieldsLimit', () => { + results.push('fieldsLimit'); + }); + + bb.on('close', () => { + active.delete(test); + + assert.deepStrictEqual( + results, + test.expected, + `[${what}] Results mismatch.\n` + + `Parsed: ${inspect(results)}\n` + + `Expected: ${inspect(test.expected)}` + ); + }); + + for (const src of test.source) { + const buf = (typeof src === 'string' ? Buffer.from(src, 'utf8') : src); + bb.write(buf); + } + bb.end(); +} + +// Byte-by-byte versions +for (let test of tests) { + test = { ...test }; + test.what += ' (byte-by-byte)'; + active.set(test, 1); + + const { what, boundary, events, limits, preservePath, fileHwm } = test; + const bb = busboy({ + fileHwm, + limits, + preservePath, + headers: { + 'content-type': `multipart/form-data; boundary=${boundary}`, + } + }); + const results = []; + + if (events === undefined || events.includes('field')) { + bb.on('field', (name, val, info) => { + results.push({ type: 'field', name, val, info }); + }); + } + + if (events === undefined || events.includes('file')) { + bb.on('file', (name, stream, info) => { + const data = []; + let nb = 0; + const file = { + type: 'file', + name, + data: null, + info, + limited: false, + }; + results.push(file); + stream.on('data', (d) => { + data.push(d); + nb += d.length; + }).on('limit', () => { + file.limited = true; + }).on('close', () => { + file.data = Buffer.concat(data, nb); + assert.strictEqual(stream.truncated, file.limited); + }).once('error', (err) => { + file.err = err.message; + }); + }); + } + + bb.on('error', (err) => { + results.push({ error: err.message }); + }); + + bb.on('partsLimit', () => { + results.push('partsLimit'); + }); + + bb.on('filesLimit', () => { + results.push('filesLimit'); + }); + + bb.on('fieldsLimit', () => { + results.push('fieldsLimit'); + }); + + bb.on('close', () => { + active.delete(test); + + assert.deepStrictEqual( + results, + test.expected, + `[${what}] Results mismatch.\n` + + `Parsed: ${inspect(results)}\n` + + `Expected: ${inspect(test.expected)}` + ); + }); + + for (const src of test.source) { + const buf = (typeof src === 'string' ? Buffer.from(src, 'utf8') : src); + for (let i = 0; i < buf.length; ++i) + bb.write(buf.slice(i, i + 1)); + } + bb.end(); +} + +{ + let exception = false; + process.once('uncaughtException', (ex) => { + exception = true; + throw ex; + }); + process.on('exit', () => { + if (exception || active.size === 0) + return; + process.exitCode = 1; + console.error('=========================='); + console.error(`${active.size} test(s) did not finish:`); + console.error('=========================='); + console.error(Array.from(active.keys()).map((v) => v.what).join('\n')); + }); +} diff --git a/deps/undici/src/node_modules/busboy/test/test-types-urlencoded.js b/deps/undici/src/node_modules/busboy/test/test-types-urlencoded.js new file mode 100644 index 00000000000000..c35962b973f29a --- /dev/null +++ b/deps/undici/src/node_modules/busboy/test/test-types-urlencoded.js @@ -0,0 +1,488 @@ +'use strict'; + +const assert = require('assert'); +const { transcode } = require('buffer'); +const { inspect } = require('util'); + +const busboy = require('..'); + +const active = new Map(); + +const tests = [ + { source: ['foo'], + expected: [ + ['foo', + '', + { nameTruncated: false, + valueTruncated: false, + encoding: 'utf-8', + mimeType: 'text/plain' }, + ], + ], + what: 'Unassigned value' + }, + { source: ['foo=bar'], + expected: [ + ['foo', + 'bar', + { nameTruncated: false, + valueTruncated: false, + encoding: 'utf-8', + mimeType: 'text/plain' }, + ], + ], + what: 'Assigned value' + }, + { source: ['foo&bar=baz'], + expected: [ + ['foo', + '', + { nameTruncated: false, + valueTruncated: false, + encoding: 'utf-8', + mimeType: 'text/plain' }, + ], + ['bar', + 'baz', + { nameTruncated: false, + valueTruncated: false, + encoding: 'utf-8', + mimeType: 'text/plain' }, + ], + ], + what: 'Unassigned and assigned value' + }, + { source: ['foo=bar&baz'], + expected: [ + ['foo', + 'bar', + { nameTruncated: false, + valueTruncated: false, + encoding: 'utf-8', + mimeType: 'text/plain' }, + ], + ['baz', + '', + { nameTruncated: false, + valueTruncated: false, + encoding: 'utf-8', + mimeType: 'text/plain' }, + ], + ], + what: 'Assigned and unassigned value' + }, + { source: ['foo=bar&baz=bla'], + expected: [ + ['foo', + 'bar', + { nameTruncated: false, + valueTruncated: false, + encoding: 'utf-8', + mimeType: 'text/plain' }, + ], + ['baz', + 'bla', + { nameTruncated: false, + valueTruncated: false, + encoding: 'utf-8', + mimeType: 'text/plain' }, + ], + ], + what: 'Two assigned values' + }, + { source: ['foo&bar'], + expected: [ + ['foo', + '', + { nameTruncated: false, + valueTruncated: false, + encoding: 'utf-8', + mimeType: 'text/plain' }, + ], + ['bar', + '', + { nameTruncated: false, + valueTruncated: false, + encoding: 'utf-8', + mimeType: 'text/plain' }, + ], + ], + what: 'Two unassigned values' + }, + { source: ['foo&bar&'], + expected: [ + ['foo', + '', + { nameTruncated: false, + valueTruncated: false, + encoding: 'utf-8', + mimeType: 'text/plain' }, + ], + ['bar', + '', + { nameTruncated: false, + valueTruncated: false, + encoding: 'utf-8', + mimeType: 'text/plain' }, + ], + ], + what: 'Two unassigned values and ampersand' + }, + { source: ['foo+1=bar+baz%2Bquux'], + expected: [ + ['foo 1', + 'bar baz+quux', + { nameTruncated: false, + valueTruncated: false, + encoding: 'utf-8', + mimeType: 'text/plain' }, + ], + ], + what: 'Assigned key and value with (plus) space' + }, + { source: ['foo=bar%20baz%21'], + expected: [ + ['foo', + 'bar baz!', + { nameTruncated: false, + valueTruncated: false, + encoding: 'utf-8', + mimeType: 'text/plain' }, + ], + ], + what: 'Assigned value with encoded bytes' + }, + { source: ['foo%20bar=baz%20bla%21'], + expected: [ + ['foo bar', + 'baz bla!', + { nameTruncated: false, + valueTruncated: false, + encoding: 'utf-8', + mimeType: 'text/plain' }, + ], + ], + what: 'Assigned value with encoded bytes #2' + }, + { source: ['foo=bar%20baz%21&num=1000'], + expected: [ + ['foo', + 'bar baz!', + { nameTruncated: false, + valueTruncated: false, + encoding: 'utf-8', + mimeType: 'text/plain' }, + ], + ['num', + '1000', + { nameTruncated: false, + valueTruncated: false, + encoding: 'utf-8', + mimeType: 'text/plain' }, + ], + ], + what: 'Two assigned values, one with encoded bytes' + }, + { source: [ + Array.from(transcode(Buffer.from('foo'), 'utf8', 'utf16le')).map( + (n) => `%${n.toString(16).padStart(2, '0')}` + ).join(''), + '=', + Array.from(transcode(Buffer.from('😀!'), 'utf8', 'utf16le')).map( + (n) => `%${n.toString(16).padStart(2, '0')}` + ).join(''), + ], + expected: [ + ['foo', + '😀!', + { nameTruncated: false, + valueTruncated: false, + encoding: 'UTF-16LE', + mimeType: 'text/plain' }, + ], + ], + charset: 'UTF-16LE', + what: 'Encoded value with multi-byte charset' + }, + { source: [ + 'foo=<', + Array.from(transcode(Buffer.from('©:^þ'), 'utf8', 'latin1')).map( + (n) => `%${n.toString(16).padStart(2, '0')}` + ).join(''), + ], + expected: [ + ['foo', + '<©:^þ', + { nameTruncated: false, + valueTruncated: false, + encoding: 'ISO-8859-1', + mimeType: 'text/plain' }, + ], + ], + charset: 'ISO-8859-1', + what: 'Encoded value with single-byte, ASCII-compatible, non-UTF8 charset' + }, + { source: ['foo=bar&baz=bla'], + expected: [], + what: 'Limits: zero fields', + limits: { fields: 0 } + }, + { source: ['foo=bar&baz=bla'], + expected: [ + ['foo', + 'bar', + { nameTruncated: false, + valueTruncated: false, + encoding: 'utf-8', + mimeType: 'text/plain' }, + ], + ], + what: 'Limits: one field', + limits: { fields: 1 } + }, + { source: ['foo=bar&baz=bla'], + expected: [ + ['foo', + 'bar', + { nameTruncated: false, + valueTruncated: false, + encoding: 'utf-8', + mimeType: 'text/plain' }, + ], + ['baz', + 'bla', + { nameTruncated: false, + valueTruncated: false, + encoding: 'utf-8', + mimeType: 'text/plain' }, + ], + ], + what: 'Limits: field part lengths match limits', + limits: { fieldNameSize: 3, fieldSize: 3 } + }, + { source: ['foo=bar&baz=bla'], + expected: [ + ['fo', + 'bar', + { nameTruncated: true, + valueTruncated: false, + encoding: 'utf-8', + mimeType: 'text/plain' }, + ], + ['ba', + 'bla', + { nameTruncated: true, + valueTruncated: false, + encoding: 'utf-8', + mimeType: 'text/plain' }, + ], + ], + what: 'Limits: truncated field name', + limits: { fieldNameSize: 2 } + }, + { source: ['foo=bar&baz=bla'], + expected: [ + ['foo', + 'ba', + { nameTruncated: false, + valueTruncated: true, + encoding: 'utf-8', + mimeType: 'text/plain' }, + ], + ['baz', + 'bl', + { nameTruncated: false, + valueTruncated: true, + encoding: 'utf-8', + mimeType: 'text/plain' }, + ], + ], + what: 'Limits: truncated field value', + limits: { fieldSize: 2 } + }, + { source: ['foo=bar&baz=bla'], + expected: [ + ['fo', + 'ba', + { nameTruncated: true, + valueTruncated: true, + encoding: 'utf-8', + mimeType: 'text/plain' }, + ], + ['ba', + 'bl', + { nameTruncated: true, + valueTruncated: true, + encoding: 'utf-8', + mimeType: 'text/plain' }, + ], + ], + what: 'Limits: truncated field name and value', + limits: { fieldNameSize: 2, fieldSize: 2 } + }, + { source: ['foo=bar&baz=bla'], + expected: [ + ['fo', + '', + { nameTruncated: true, + valueTruncated: true, + encoding: 'utf-8', + mimeType: 'text/plain' }, + ], + ['ba', + '', + { nameTruncated: true, + valueTruncated: true, + encoding: 'utf-8', + mimeType: 'text/plain' }, + ], + ], + what: 'Limits: truncated field name and zero value limit', + limits: { fieldNameSize: 2, fieldSize: 0 } + }, + { source: ['foo=bar&baz=bla'], + expected: [ + ['', + '', + { nameTruncated: true, + valueTruncated: true, + encoding: 'utf-8', + mimeType: 'text/plain' }, + ], + ['', + '', + { nameTruncated: true, + valueTruncated: true, + encoding: 'utf-8', + mimeType: 'text/plain' }, + ], + ], + what: 'Limits: truncated zero field name and zero value limit', + limits: { fieldNameSize: 0, fieldSize: 0 } + }, + { source: ['&'], + expected: [], + what: 'Ampersand' + }, + { source: ['&&&&&'], + expected: [], + what: 'Many ampersands' + }, + { source: ['='], + expected: [ + ['', + '', + { nameTruncated: false, + valueTruncated: false, + encoding: 'utf-8', + mimeType: 'text/plain' }, + ], + ], + what: 'Assigned value, empty name and value' + }, + { source: [''], + expected: [], + what: 'Nothing' + }, +]; + +for (const test of tests) { + active.set(test, 1); + + const { what } = test; + const charset = test.charset || 'utf-8'; + const bb = busboy({ + limits: test.limits, + headers: { + 'content-type': `application/x-www-form-urlencoded; charset=${charset}`, + }, + }); + const results = []; + + bb.on('field', (key, val, info) => { + results.push([key, val, info]); + }); + + bb.on('file', () => { + throw new Error(`[${what}] Unexpected file`); + }); + + bb.on('close', () => { + active.delete(test); + + assert.deepStrictEqual( + results, + test.expected, + `[${what}] Results mismatch.\n` + + `Parsed: ${inspect(results)}\n` + + `Expected: ${inspect(test.expected)}` + ); + }); + + for (const src of test.source) { + const buf = (typeof src === 'string' ? Buffer.from(src, 'utf8') : src); + bb.write(buf); + } + bb.end(); +} + +// Byte-by-byte versions +for (let test of tests) { + test = { ...test }; + test.what += ' (byte-by-byte)'; + active.set(test, 1); + + const { what } = test; + const charset = test.charset || 'utf-8'; + const bb = busboy({ + limits: test.limits, + headers: { + 'content-type': `application/x-www-form-urlencoded; charset="${charset}"`, + }, + }); + const results = []; + + bb.on('field', (key, val, info) => { + results.push([key, val, info]); + }); + + bb.on('file', () => { + throw new Error(`[${what}] Unexpected file`); + }); + + bb.on('close', () => { + active.delete(test); + + assert.deepStrictEqual( + results, + test.expected, + `[${what}] Results mismatch.\n` + + `Parsed: ${inspect(results)}\n` + + `Expected: ${inspect(test.expected)}` + ); + }); + + for (const src of test.source) { + const buf = (typeof src === 'string' ? Buffer.from(src, 'utf8') : src); + for (let i = 0; i < buf.length; ++i) + bb.write(buf.slice(i, i + 1)); + } + bb.end(); +} + +{ + let exception = false; + process.once('uncaughtException', (ex) => { + exception = true; + throw ex; + }); + process.on('exit', () => { + if (exception || active.size === 0) + return; + process.exitCode = 1; + console.error('=========================='); + console.error(`${active.size} test(s) did not finish:`); + console.error('=========================='); + console.error(Array.from(active.keys()).map((v) => v.what).join('\n')); + }); +} diff --git a/deps/undici/src/node_modules/busboy/test/test.js b/deps/undici/src/node_modules/busboy/test/test.js new file mode 100644 index 00000000000000..d0380f29de7842 --- /dev/null +++ b/deps/undici/src/node_modules/busboy/test/test.js @@ -0,0 +1,20 @@ +'use strict'; + +const { spawnSync } = require('child_process'); +const { readdirSync } = require('fs'); +const { join } = require('path'); + +const files = readdirSync(__dirname).sort(); +for (const filename of files) { + if (filename.startsWith('test-')) { + const path = join(__dirname, filename); + console.log(`> Running ${filename} ...`); + const result = spawnSync(`${process.argv0} ${path}`, { + shell: true, + stdio: 'inherit', + windowsHide: true + }); + if (result.status !== 0) + process.exitCode = 1; + } +} diff --git a/deps/undici/src/node_modules/streamsearch/.eslintrc.js b/deps/undici/src/node_modules/streamsearch/.eslintrc.js new file mode 100644 index 00000000000000..be9311d02655a2 --- /dev/null +++ b/deps/undici/src/node_modules/streamsearch/.eslintrc.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = { + extends: '@mscdex/eslint-config', +}; diff --git a/deps/undici/src/node_modules/streamsearch/.github/workflows/ci.yml b/deps/undici/src/node_modules/streamsearch/.github/workflows/ci.yml new file mode 100644 index 00000000000000..29d51782c77a93 --- /dev/null +++ b/deps/undici/src/node_modules/streamsearch/.github/workflows/ci.yml @@ -0,0 +1,24 @@ +name: CI + +on: + pull_request: + push: + branches: [ master ] + +jobs: + tests-linux: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + node-version: [10.x, 12.x, 14.x, 16.x] + steps: + - uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - name: Install module + run: npm install + - name: Run tests + run: npm test diff --git a/deps/undici/src/node_modules/streamsearch/.github/workflows/lint.yml b/deps/undici/src/node_modules/streamsearch/.github/workflows/lint.yml new file mode 100644 index 00000000000000..9f9e1f589a30be --- /dev/null +++ b/deps/undici/src/node_modules/streamsearch/.github/workflows/lint.yml @@ -0,0 +1,23 @@ +name: lint + +on: + pull_request: + push: + branches: [ master ] + +env: + NODE_VERSION: 16.x + +jobs: + lint-js: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Use Node.js ${{ env.NODE_VERSION }} + uses: actions/setup-node@v1 + with: + node-version: ${{ env.NODE_VERSION }} + - name: Install ESLint + ESLint configs/plugins + run: npm install --only=dev + - name: Lint files + run: npm run lint diff --git a/deps/undici/src/node_modules/streamsearch/LICENSE b/deps/undici/src/node_modules/streamsearch/LICENSE new file mode 100644 index 00000000000000..9ea90e03922d5e --- /dev/null +++ b/deps/undici/src/node_modules/streamsearch/LICENSE @@ -0,0 +1,19 @@ +Copyright Brian White. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. \ No newline at end of file diff --git a/deps/undici/src/node_modules/streamsearch/README.md b/deps/undici/src/node_modules/streamsearch/README.md new file mode 100644 index 00000000000000..c3934d1c7d5711 --- /dev/null +++ b/deps/undici/src/node_modules/streamsearch/README.md @@ -0,0 +1,95 @@ +Description +=========== + +streamsearch is a module for [node.js](http://nodejs.org/) that allows searching a stream using the Boyer-Moore-Horspool algorithm. + +This module is based heavily on the Streaming Boyer-Moore-Horspool C++ implementation by Hongli Lai [here](https://github.com/FooBarWidget/boyer-moore-horspool). + + +Requirements +============ + +* [node.js](http://nodejs.org/) -- v10.0.0 or newer + + +Installation +============ + + npm install streamsearch + +Example +======= + +```js + const { inspect } = require('util'); + + const StreamSearch = require('streamsearch'); + + const needle = Buffer.from('\r\n'); + const ss = new StreamSearch(needle, (isMatch, data, start, end) => { + if (data) + console.log('data: ' + inspect(data.toString('latin1', start, end))); + if (isMatch) + console.log('match!'); + }); + + const chunks = [ + 'foo', + ' bar', + '\r', + '\n', + 'baz, hello\r', + '\n world.', + '\r\n Node.JS rules!!\r\n\r\n', + ]; + for (const chunk of chunks) + ss.push(Buffer.from(chunk)); + + // output: + // + // data: 'foo' + // data: ' bar' + // match! + // data: 'baz, hello' + // match! + // data: ' world.' + // match! + // data: ' Node.JS rules!!' + // match! + // data: '' + // match! +``` + + +API +=== + +Properties +---------- + +* **maxMatches** - < _integer_ > - The maximum number of matches. Defaults to `Infinity`. + +* **matches** - < _integer_ > - The current match count. + + +Functions +--------- + +* **(constructor)**(< _mixed_ >needle, < _function_ >callback) - Creates and returns a new instance for searching for a _Buffer_ or _string_ `needle`. `callback` is called any time there is non-matching data and/or there is a needle match. `callback` will be called with the following arguments: + + 1. `isMatch` - _boolean_ - Indicates whether a match has been found + + 2. `data` - _mixed_ - If set, this contains data that did not match the needle. + + 3. `start` - _integer_ - The index in `data` where the non-matching data begins (inclusive). + + 4. `end` - _integer_ - The index in `data` where the non-matching data ends (exclusive). + + 5. `isSafeData` - _boolean_ - Indicates if it is safe to store a reference to `data` (e.g. as-is or via `data.slice()`) or not, as in some cases `data` may point to a Buffer whose contents change over time. + +* **destroy**() - _(void)_ - Emits any last remaining unmatched data that may still be buffered and then resets internal state. + +* **push**(< _Buffer_ >chunk) - _integer_ - Processes `chunk`, searching for a match. The return value is the last processed index in `chunk` + 1. + +* **reset**() - _(void)_ - Resets internal state. Useful for when you wish to start searching a new/different stream for example. + diff --git a/deps/undici/src/node_modules/streamsearch/lib/sbmh.js b/deps/undici/src/node_modules/streamsearch/lib/sbmh.js new file mode 100644 index 00000000000000..510cae26e67a58 --- /dev/null +++ b/deps/undici/src/node_modules/streamsearch/lib/sbmh.js @@ -0,0 +1,267 @@ +'use strict'; +/* + Based heavily on the Streaming Boyer-Moore-Horspool C++ implementation + by Hongli Lai at: https://github.com/FooBarWidget/boyer-moore-horspool +*/ +function memcmp(buf1, pos1, buf2, pos2, num) { + for (let i = 0; i < num; ++i) { + if (buf1[pos1 + i] !== buf2[pos2 + i]) + return false; + } + return true; +} + +class SBMH { + constructor(needle, cb) { + if (typeof cb !== 'function') + throw new Error('Missing match callback'); + + if (typeof needle === 'string') + needle = Buffer.from(needle); + else if (!Buffer.isBuffer(needle)) + throw new Error(`Expected Buffer for needle, got ${typeof needle}`); + + const needleLen = needle.length; + + this.maxMatches = Infinity; + this.matches = 0; + + this._cb = cb; + this._lookbehindSize = 0; + this._needle = needle; + this._bufPos = 0; + + this._lookbehind = Buffer.allocUnsafe(needleLen); + + // Initialize occurrence table. + this._occ = [ + needleLen, needleLen, needleLen, needleLen, needleLen, needleLen, + needleLen, needleLen, needleLen, needleLen, needleLen, needleLen, + needleLen, needleLen, needleLen, needleLen, needleLen, needleLen, + needleLen, needleLen, needleLen, needleLen, needleLen, needleLen, + needleLen, needleLen, needleLen, needleLen, needleLen, needleLen, + needleLen, needleLen, needleLen, needleLen, needleLen, needleLen, + needleLen, needleLen, needleLen, needleLen, needleLen, needleLen, + needleLen, needleLen, needleLen, needleLen, needleLen, needleLen, + needleLen, needleLen, needleLen, needleLen, needleLen, needleLen, + needleLen, needleLen, needleLen, needleLen, needleLen, needleLen, + needleLen, needleLen, needleLen, needleLen, needleLen, needleLen, + needleLen, needleLen, needleLen, needleLen, needleLen, needleLen, + needleLen, needleLen, needleLen, needleLen, needleLen, needleLen, + needleLen, needleLen, needleLen, needleLen, needleLen, needleLen, + needleLen, needleLen, needleLen, needleLen, needleLen, needleLen, + needleLen, needleLen, needleLen, needleLen, needleLen, needleLen, + needleLen, needleLen, needleLen, needleLen, needleLen, needleLen, + needleLen, needleLen, needleLen, needleLen, needleLen, needleLen, + needleLen, needleLen, needleLen, needleLen, needleLen, needleLen, + needleLen, needleLen, needleLen, needleLen, needleLen, needleLen, + needleLen, needleLen, needleLen, needleLen, needleLen, needleLen, + needleLen, needleLen, needleLen, needleLen, needleLen, needleLen, + needleLen, needleLen, needleLen, needleLen, needleLen, needleLen, + needleLen, needleLen, needleLen, needleLen, needleLen, needleLen, + needleLen, needleLen, needleLen, needleLen, needleLen, needleLen, + needleLen, needleLen, needleLen, needleLen, needleLen, needleLen, + needleLen, needleLen, needleLen, needleLen, needleLen, needleLen, + needleLen, needleLen, needleLen, needleLen, needleLen, needleLen, + needleLen, needleLen, needleLen, needleLen, needleLen, needleLen, + needleLen, needleLen, needleLen, needleLen, needleLen, needleLen, + needleLen, needleLen, needleLen, needleLen, needleLen, needleLen, + needleLen, needleLen, needleLen, needleLen, needleLen, needleLen, + needleLen, needleLen, needleLen, needleLen, needleLen, needleLen, + needleLen, needleLen, needleLen, needleLen, needleLen, needleLen, + needleLen, needleLen, needleLen, needleLen, needleLen, needleLen, + needleLen, needleLen, needleLen, needleLen, needleLen, needleLen, + needleLen, needleLen, needleLen, needleLen, needleLen, needleLen, + needleLen, needleLen, needleLen, needleLen, needleLen, needleLen, + needleLen, needleLen, needleLen, needleLen, needleLen, needleLen, + needleLen, needleLen, needleLen, needleLen, needleLen, needleLen, + needleLen, needleLen, needleLen, needleLen, needleLen, needleLen, + needleLen, needleLen, needleLen, needleLen, needleLen, needleLen, + needleLen, needleLen, needleLen, needleLen + ]; + + // Populate occurrence table with analysis of the needle, ignoring the last + // letter. + if (needleLen > 1) { + for (let i = 0; i < needleLen - 1; ++i) + this._occ[needle[i]] = needleLen - 1 - i; + } + } + + reset() { + this.matches = 0; + this._lookbehindSize = 0; + this._bufPos = 0; + } + + push(chunk, pos) { + let result; + if (!Buffer.isBuffer(chunk)) + chunk = Buffer.from(chunk, 'latin1'); + const chunkLen = chunk.length; + this._bufPos = pos || 0; + while (result !== chunkLen && this.matches < this.maxMatches) + result = feed(this, chunk); + return result; + } + + destroy() { + const lbSize = this._lookbehindSize; + if (lbSize) + this._cb(false, this._lookbehind, 0, lbSize, false); + this.reset(); + } +} + +function feed(self, data) { + const len = data.length; + const needle = self._needle; + const needleLen = needle.length; + + // Positive: points to a position in `data` + // pos == 3 points to data[3] + // Negative: points to a position in the lookbehind buffer + // pos == -2 points to lookbehind[lookbehindSize - 2] + let pos = -self._lookbehindSize; + const lastNeedleCharPos = needleLen - 1; + const lastNeedleChar = needle[lastNeedleCharPos]; + const end = len - needleLen; + const occ = self._occ; + const lookbehind = self._lookbehind; + + if (pos < 0) { + // Lookbehind buffer is not empty. Perform Boyer-Moore-Horspool + // search with character lookup code that considers both the + // lookbehind buffer and the current round's haystack data. + // + // Loop until + // there is a match. + // or until + // we've moved past the position that requires the + // lookbehind buffer. In this case we switch to the + // optimized loop. + // or until + // the character to look at lies outside the haystack. + while (pos < 0 && pos <= end) { + const nextPos = pos + lastNeedleCharPos; + const ch = (nextPos < 0 + ? lookbehind[self._lookbehindSize + nextPos] + : data[nextPos]); + + if (ch === lastNeedleChar + && matchNeedle(self, data, pos, lastNeedleCharPos)) { + self._lookbehindSize = 0; + ++self.matches; + if (pos > -self._lookbehindSize) + self._cb(true, lookbehind, 0, self._lookbehindSize + pos, false); + else + self._cb(true, undefined, 0, 0, true); + + return (self._bufPos = pos + needleLen); + } + + pos += occ[ch]; + } + + // No match. + + // There's too few data for Boyer-Moore-Horspool to run, + // so let's use a different algorithm to skip as much as + // we can. + // Forward pos until + // the trailing part of lookbehind + data + // looks like the beginning of the needle + // or until + // pos == 0 + while (pos < 0 && !matchNeedle(self, data, pos, len - pos)) + ++pos; + + if (pos < 0) { + // Cut off part of the lookbehind buffer that has + // been processed and append the entire haystack + // into it. + const bytesToCutOff = self._lookbehindSize + pos; + + if (bytesToCutOff > 0) { + // The cut off data is guaranteed not to contain the needle. + self._cb(false, lookbehind, 0, bytesToCutOff, false); + } + + self._lookbehindSize -= bytesToCutOff; + lookbehind.copy(lookbehind, 0, bytesToCutOff, self._lookbehindSize); + lookbehind.set(data, self._lookbehindSize); + self._lookbehindSize += len; + + self._bufPos = len; + return len; + } + + // Discard lookbehind buffer. + self._cb(false, lookbehind, 0, self._lookbehindSize, false); + self._lookbehindSize = 0; + } + + pos += self._bufPos; + + const firstNeedleChar = needle[0]; + + // Lookbehind buffer is now empty. Perform Boyer-Moore-Horspool + // search with optimized character lookup code that only considers + // the current round's haystack data. + while (pos <= end) { + const ch = data[pos + lastNeedleCharPos]; + + if (ch === lastNeedleChar + && data[pos] === firstNeedleChar + && memcmp(needle, 0, data, pos, lastNeedleCharPos)) { + ++self.matches; + if (pos > 0) + self._cb(true, data, self._bufPos, pos, true); + else + self._cb(true, undefined, 0, 0, true); + + return (self._bufPos = pos + needleLen); + } + + pos += occ[ch]; + } + + // There was no match. If there's trailing haystack data that we cannot + // match yet using the Boyer-Moore-Horspool algorithm (because the trailing + // data is less than the needle size) then match using a modified + // algorithm that starts matching from the beginning instead of the end. + // Whatever trailing data is left after running this algorithm is added to + // the lookbehind buffer. + while (pos < len) { + if (data[pos] !== firstNeedleChar + || !memcmp(data, pos, needle, 0, len - pos)) { + ++pos; + continue; + } + data.copy(lookbehind, 0, pos, len); + self._lookbehindSize = len - pos; + break; + } + + // Everything until `pos` is guaranteed not to contain needle data. + if (pos > 0) + self._cb(false, data, self._bufPos, pos < len ? pos : len, true); + + self._bufPos = len; + return len; +} + +function matchNeedle(self, data, pos, len) { + const lb = self._lookbehind; + const lbSize = self._lookbehindSize; + const needle = self._needle; + + for (let i = 0; i < len; ++i, ++pos) { + const ch = (pos < 0 ? lb[lbSize + pos] : data[pos]); + if (ch !== needle[i]) + return false; + } + return true; +} + +module.exports = SBMH; diff --git a/deps/undici/src/node_modules/streamsearch/package.json b/deps/undici/src/node_modules/streamsearch/package.json new file mode 100644 index 00000000000000..51df8f9707cebd --- /dev/null +++ b/deps/undici/src/node_modules/streamsearch/package.json @@ -0,0 +1,34 @@ +{ + "name": "streamsearch", + "version": "1.1.0", + "author": "Brian White ", + "description": "Streaming Boyer-Moore-Horspool searching for node.js", + "main": "./lib/sbmh.js", + "engines": { + "node": ">=10.0.0" + }, + "devDependencies": { + "@mscdex/eslint-config": "^1.1.0", + "eslint": "^7.32.0" + }, + "scripts": { + "test": "node test/test.js", + "lint": "eslint --cache --report-unused-disable-directives --ext=.js .eslintrc.js lib test", + "lint:fix": "npm run lint -- --fix" + }, + "keywords": [ + "stream", + "horspool", + "boyer-moore-horspool", + "boyer-moore", + "search" + ], + "licenses": [{ + "type": "MIT", + "url": "http://github.com/mscdex/streamsearch/raw/master/LICENSE" + }], + "repository": { + "type": "git", + "url": "http://github.com/mscdex/streamsearch.git" + } +} diff --git a/deps/undici/src/node_modules/streamsearch/test/test.js b/deps/undici/src/node_modules/streamsearch/test/test.js new file mode 100644 index 00000000000000..39a04d7f834bea --- /dev/null +++ b/deps/undici/src/node_modules/streamsearch/test/test.js @@ -0,0 +1,70 @@ +'use strict'; + +const assert = require('assert'); + +const StreamSearch = require('../lib/sbmh.js'); + +[ + { + needle: '\r\n', + chunks: [ + 'foo', + ' bar', + '\r', + '\n', + 'baz, hello\r', + '\n world.', + '\r\n Node.JS rules!!\r\n\r\n', + ], + expect: [ + [false, 'foo'], + [false, ' bar'], + [ true, null], + [false, 'baz, hello'], + [ true, null], + [false, ' world.'], + [ true, null], + [ true, ' Node.JS rules!!'], + [ true, ''], + ], + }, + { + needle: '---foobarbaz', + chunks: [ + '---foobarbaz', + 'asdf', + '\r\n', + '---foobarba', + '---foobar', + 'ba', + '\r\n---foobarbaz--\r\n', + ], + expect: [ + [ true, null], + [false, 'asdf'], + [false, '\r\n'], + [false, '---foobarba'], + [false, '---foobarba'], + [ true, '\r\n'], + [false, '--\r\n'], + ], + }, +].forEach((test, i) => { + console.log(`Running test #${i + 1}`); + const { needle, chunks, expect } = test; + + const results = []; + const ss = new StreamSearch(Buffer.from(needle), + (isMatch, data, start, end) => { + if (data) + data = data.toString('latin1', start, end); + else + data = null; + results.push([isMatch, data]); + }); + + for (const chunk of chunks) + ss.push(Buffer.from(chunk)); + + assert.deepStrictEqual(results, expect); +}); diff --git a/deps/undici/src/package.json b/deps/undici/src/package.json index 0a3d9e5226cc7e..823c48b8d3e4f6 100644 --- a/deps/undici/src/package.json +++ b/deps/undici/src/package.json @@ -1,6 +1,6 @@ { "name": "undici", - "version": "5.10.0", + "version": "5.11.0", "description": "An HTTP/1.1 client, written from scratch for Node.js", "homepage": "https://undici.nodejs.org", "bugs": { @@ -46,13 +46,14 @@ "build:wasm": "node build/wasm.js --docker", "lint": "standard | snazzy", "lint:fix": "standard --fix | snazzy", - "test": "npm run test:tap && npm run test:node-fetch && npm run test:fetch && npm run test:jest && tsd", + "test": "npm run test:tap && npm run test:node-fetch && npm run test:fetch && npm run test:wpt && npm run test:jest && tsd", "test:node-fetch": "node scripts/verifyVersion.js 16 || mocha test/node-fetch", "test:fetch": "node scripts/verifyVersion.js 16 || (npm run build:node && tap test/fetch/*.js && tap test/webidl/*.js)", - "test:jest": "jest", + "test:jest": "node scripts/verifyVersion.js 14 || jest", "test:tap": "tap test/*.js test/diagnostics-channel/*.js", "test:tdd": "tap test/*.js test/diagnostics-channel/*.js -w", "test:typescript": "tsd", + "test:wpt": "node scripts/verifyVersion 18 || node test/wpt/runner/start.mjs", "coverage": "nyc --reporter=text --reporter=html npm run test", "coverage:ci": "nyc --reporter=lcov npm run test", "bench": "PORT=3042 concurrently -k -s first npm:bench:server npm:bench:run", @@ -65,10 +66,9 @@ }, "devDependencies": { "@sinonjs/fake-timers": "^9.1.2", - "@types/node": "^17.0.29", + "@types/node": "^17.0.45", "abort-controller": "^3.0.0", "atomic-sleep": "^1.0.0", - "busboy": "^1.6.0", "chai": "^4.3.4", "chai-as-promised": "^7.1.1", "chai-iterator": "^3.0.2", @@ -81,7 +81,7 @@ "https-pem": "^3.0.0", "husky": "^8.0.1", "import-fresh": "^3.3.0", - "jest": "^28.0.1", + "jest": "^29.0.2", "jsfuzz": "^1.0.15", "mocha": "^10.0.0", "p-timeout": "^3.2.0", @@ -94,7 +94,7 @@ "standard": "^17.0.0", "table": "^6.8.0", "tap": "^16.1.0", - "tsd": "^0.22.0", + "tsd": "^0.24.1", "wait-on": "^6.0.0" }, "engines": { @@ -106,7 +106,9 @@ ], "ignore": [ "lib/llhttp/constants.js", - "lib/llhttp/utils.js" + "lib/llhttp/utils.js", + "test/wpt/tests", + "test/wpt/runner/resources" ] }, "tsd": { @@ -122,5 +124,8 @@ "testMatch": [ "/test/jest/**" ] + }, + "dependencies": { + "busboy": "^1.6.0" } } diff --git a/deps/undici/src/types/agent.d.ts b/deps/undici/src/types/agent.d.ts index ebadc194daf00a..c09260b29130f0 100644 --- a/deps/undici/src/types/agent.d.ts +++ b/deps/undici/src/types/agent.d.ts @@ -1,6 +1,7 @@ import { URL } from 'url' import Dispatcher = require('./dispatcher') import Pool = require('./pool') +import {DispatchInterceptor} from "./dispatcher"; export = Agent @@ -20,6 +21,8 @@ declare namespace Agent { factory?(origin: URL, opts: Object): Dispatcher; /** Integer. Default: `0` */ maxRedirections?: number; + + interceptors?: { Agent?: readonly DispatchInterceptor[] } & Pool.Options["interceptors"] } export interface DispatchOptions extends Dispatcher.DispatchOptions { diff --git a/deps/undici/src/types/client.d.ts b/deps/undici/src/types/client.d.ts index 22fcb42cfe8201..4932ece3ffefb5 100644 --- a/deps/undici/src/types/client.d.ts +++ b/deps/undici/src/types/client.d.ts @@ -1,8 +1,8 @@ import { URL } from 'url' import { TlsOptions } from 'tls' import Dispatcher = require('./dispatcher') -import { DispatchOptions, RequestOptions } from './dispatcher' -import buildConnector = require('./connector') +import {DispatchInterceptor} from './dispatcher' +import buildConnector, {connector} from "./connector"; export = Client @@ -28,7 +28,7 @@ declare namespace Client { /** The amount of concurrent requests to be sent over the single TCP/TLS connection according to [RFC7230](https://tools.ietf.org/html/rfc7230#section-6.3.2). Default: `1`. */ pipelining?: number | null; /** **/ - connect?: buildConnector.BuildOptions | Function | null; + connect?: buildConnector.BuildOptions | connector | null; /** The maximum length of request headers in bytes. Default: `16384` (16KiB). */ maxHeaderSize?: number | null; /** The timeout after which a request will time out, in milliseconds. Monitors time between receiving body data. Use `0` to disable it entirely. Default: `30e3` milliseconds (30s). */ @@ -41,6 +41,8 @@ declare namespace Client { tls?: TlsOptions | null; /** */ maxRequestsPerClient?: number; + + interceptors?: {Client: readonly DispatchInterceptor[] | undefined} } export interface SocketInfo { @@ -53,4 +55,6 @@ declare namespace Client { bytesWritten?: number bytesRead?: number } + + } diff --git a/deps/undici/src/types/connector.d.ts b/deps/undici/src/types/connector.d.ts index 38016b00008091..9a47f87e59919f 100644 --- a/deps/undici/src/types/connector.d.ts +++ b/deps/undici/src/types/connector.d.ts @@ -2,7 +2,7 @@ import {TLSSocket, ConnectionOptions} from 'tls' import {IpcNetConnectOpts, Socket, TcpNetConnectOpts} from 'net' export = buildConnector -declare function buildConnector (options?: buildConnector.BuildOptions): typeof buildConnector.connector +declare function buildConnector (options?: buildConnector.BuildOptions): buildConnector.connector declare namespace buildConnector { export type BuildOptions = (ConnectionOptions | TcpNetConnectOpts | IpcNetConnectOpts) & { @@ -20,7 +20,16 @@ declare namespace buildConnector { servername?: string } - export type Callback = (err: Error | null, socket: Socket | TLSSocket | null) => void + export type Callback = (...args: CallbackArgs) => void + type CallbackArgs = [null, Socket | TLSSocket] | [Error, null] - export function connector (options: buildConnector.Options, callback: buildConnector.Callback): Socket | TLSSocket; + export type connector = connectorAsync | connectorSync + + interface connectorSync { + (options: buildConnector.Options): Socket | TLSSocket + } + + interface connectorAsync { + (options: buildConnector.Options, callback: buildConnector.Callback): void + } } diff --git a/deps/undici/src/types/diagnostics-channel.d.ts b/deps/undici/src/types/diagnostics-channel.d.ts index c6131482280dc6..6c754491b89f3f 100644 --- a/deps/undici/src/types/diagnostics-channel.d.ts +++ b/deps/undici/src/types/diagnostics-channel.d.ts @@ -25,7 +25,7 @@ declare namespace DiagnosticsChannel { port: URL["port"]; servername: string | null; } - type Connector = typeof connector; + type Connector = connector; export interface RequestCreateMessage { request: Request; } diff --git a/deps/undici/src/types/dispatcher.d.ts b/deps/undici/src/types/dispatcher.d.ts index 8744f04e2d7083..cbd558a932f848 100644 --- a/deps/undici/src/types/dispatcher.d.ts +++ b/deps/undici/src/types/dispatcher.d.ts @@ -3,8 +3,9 @@ import { Duplex, Readable, Writable } from 'stream' import { EventEmitter } from 'events' import { IncomingHttpHeaders } from 'http' import { Blob } from 'buffer' -import BodyReadable = require('./readable') +import type BodyReadable from './readable' import { FormData } from './formdata' +import { UndiciError } from './errors' type AbortSignal = unknown; @@ -36,6 +37,59 @@ declare class Dispatcher extends EventEmitter { destroy(err: Error | null): Promise; destroy(callback: () => void): void; destroy(err: Error | null, callback: () => void): void; + + on(eventName: 'connect', callback: (origin: URL, targets: readonly Dispatcher[]) => void): this; + on(eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void): this; + on(eventName: 'connectionError', callback: (origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void): this; + on(eventName: 'drain', callback: (origin: URL) => void): this; + + + once(eventName: 'connect', callback: (origin: URL, targets: readonly Dispatcher[]) => void): this; + once(eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void): this; + once(eventName: 'connectionError', callback: (origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void): this; + once(eventName: 'drain', callback: (origin: URL) => void): this; + + + off(eventName: 'connect', callback: (origin: URL, targets: readonly Dispatcher[]) => void): this; + off(eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void): this; + off(eventName: 'connectionError', callback: (origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void): this; + off(eventName: 'drain', callback: (origin: URL) => void): this; + + + addListener(eventName: 'connect', callback: (origin: URL, targets: readonly Dispatcher[]) => void): this; + addListener(eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void): this; + addListener(eventName: 'connectionError', callback: (origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void): this; + addListener(eventName: 'drain', callback: (origin: URL) => void): this; + + removeListener(eventName: 'connect', callback: (origin: URL, targets: readonly Dispatcher[]) => void): this; + removeListener(eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void): this; + removeListener(eventName: 'connectionError', callback: (origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void): this; + removeListener(eventName: 'drain', callback: (origin: URL) => void): this; + + prependListener(eventName: 'connect', callback: (origin: URL, targets: readonly Dispatcher[]) => void): this; + prependListener(eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void): this; + prependListener(eventName: 'connectionError', callback: (origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void): this; + prependListener(eventName: 'drain', callback: (origin: URL) => void): this; + + prependOnceListener(eventName: 'connect', callback: (origin: URL, targets: readonly Dispatcher[]) => void): this; + prependOnceListener(eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void): this; + prependOnceListener(eventName: 'connectionError', callback: (origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void): this; + prependOnceListener(eventName: 'drain', callback: (origin: URL) => void): this; + + listeners(eventName: 'connect'): ((origin: URL, targets: readonly Dispatcher[]) => void)[] + listeners(eventName: 'disconnect'): ((origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void)[]; + listeners(eventName: 'connectionError'): ((origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void)[]; + listeners(eventName: 'drain'): ((origin: URL) => void)[]; + + rawListeners(eventName: 'connect'): ((origin: URL, targets: readonly Dispatcher[]) => void)[] + rawListeners(eventName: 'disconnect'): ((origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void)[]; + rawListeners(eventName: 'connectionError'): ((origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void)[]; + rawListeners(eventName: 'drain'): ((origin: URL) => void)[]; + + emit(eventName: 'connect', origin: URL, targets: readonly Dispatcher[]): boolean; + emit(eventName: 'disconnect', origin: URL, targets: readonly Dispatcher[], error: UndiciError): boolean; + emit(eventName: 'connectionError', origin: URL, targets: readonly Dispatcher[], error: UndiciError): boolean; + emit(eventName: 'drain', origin: URL): boolean; } declare namespace Dispatcher { @@ -147,9 +201,9 @@ declare namespace Dispatcher { /** Invoked when an error has occurred. */ onError?(err: Error): void; /** Invoked when request is upgraded either due to a `Upgrade` header or `CONNECT` method. */ - onUpgrade?(statusCode: number, headers: string[] | null, socket: Duplex): void; + onUpgrade?(statusCode: number, headers: Buffer[] | string[] | null, socket: Duplex): void; /** Invoked when statusCode and headers have been received. May be invoked multiple times due to 1xx informational headers. */ - onHeaders?(statusCode: number, headers: string[] | null, resume: () => void): boolean; + onHeaders?(statusCode: number, headers: Buffer[] | string[] | null, resume: () => void): boolean; /** Invoked when response payload data is received. */ onData?(chunk: Buffer): boolean; /** Invoked when response payload and trailers have been received and the request has completed. */ @@ -172,4 +226,8 @@ declare namespace Dispatcher { json(): Promise; text(): Promise; } + + export interface DispatchInterceptor { + (dispatch: Dispatcher['dispatch']): Dispatcher['dispatch'] + } } diff --git a/deps/undici/src/types/global-origin.d.ts b/deps/undici/src/types/global-origin.d.ts new file mode 100644 index 00000000000000..322542d66756a7 --- /dev/null +++ b/deps/undici/src/types/global-origin.d.ts @@ -0,0 +1,7 @@ +export { + setGlobalOrigin, + getGlobalOrigin +} + +declare function setGlobalOrigin(origin: string | URL | undefined): void; +declare function getGlobalOrigin(): URL | undefined; \ No newline at end of file diff --git a/deps/undici/src/types/handlers.d.ts b/deps/undici/src/types/handlers.d.ts new file mode 100644 index 00000000000000..eb4f5a9e8dd209 --- /dev/null +++ b/deps/undici/src/types/handlers.d.ts @@ -0,0 +1,9 @@ +import Dispatcher from "./dispatcher"; + +export declare class RedirectHandler implements Dispatcher.DispatchHandlers{ + constructor (dispatch: Dispatcher, maxRedirections: number, opts: Dispatcher.DispatchOptions, handler: Dispatcher.DispatchHandlers) +} + +export declare class DecoratorHandler implements Dispatcher.DispatchHandlers{ + constructor (handler: Dispatcher.DispatchHandlers) +} diff --git a/deps/undici/src/types/interceptors.d.ts b/deps/undici/src/types/interceptors.d.ts new file mode 100644 index 00000000000000..a920ea982e8ab1 --- /dev/null +++ b/deps/undici/src/types/interceptors.d.ts @@ -0,0 +1,5 @@ +import {DispatchInterceptor} from "./dispatcher"; + +type RedirectInterceptorOpts = { maxRedirections?: number } + +export declare function createRedirectInterceptor (opts: RedirectInterceptorOpts): DispatchInterceptor diff --git a/deps/undici/src/types/pool.d.ts b/deps/undici/src/types/pool.d.ts index af7fb94a9a68d8..0ef0bc39884db9 100644 --- a/deps/undici/src/types/pool.d.ts +++ b/deps/undici/src/types/pool.d.ts @@ -2,6 +2,7 @@ import Client = require('./client') import Dispatcher = require('./dispatcher') import TPoolStats = require('./pool-stats') import { URL } from 'url' +import {DispatchInterceptor} from "./dispatcher"; export = Pool @@ -22,5 +23,7 @@ declare namespace Pool { factory?(origin: URL, opts: object): Dispatcher; /** The max number of clients to create. `null` if no limit. Default `null`. */ connections?: number | null; + + interceptors?: { Pool?: readonly DispatchInterceptor[] } & Client.Options["interceptors"] } } diff --git a/deps/undici/undici.js b/deps/undici/undici.js index 6578fb40bd7f4d..45b30da4fa04b0 100644 --- a/deps/undici/undici.js +++ b/deps/undici/undici.js @@ -255,7 +255,8 @@ var require_symbols = __commonJS({ kMaxRedirections: Symbol("maxRedirections"), kMaxRequests: Symbol("maxRequestsPerClient"), kProxy: Symbol("proxy agent options"), - kCounter: Symbol("socket request counter") + kCounter: Symbol("socket request counter"), + kInterceptors: Symbol("dispatch interceptors") }; } }); @@ -290,11 +291,12 @@ var require_dispatcher_base = __commonJS({ ClientClosedError, InvalidArgumentError } = require_errors(); - var { kDestroy, kClose, kDispatch } = require_symbols(); + var { kDestroy, kClose, kDispatch, kInterceptors } = require_symbols(); var kDestroyed = Symbol("destroyed"); var kClosed = Symbol("closed"); var kOnDestroyed = Symbol("onDestroyed"); var kOnClosed = Symbol("onClosed"); + var kInterceptedDispatch = Symbol("Intercepted Dispatch"); var DispatcherBase = class extends Dispatcher { constructor() { super(); @@ -309,6 +311,20 @@ var require_dispatcher_base = __commonJS({ get closed() { return this[kClosed]; } + get interceptors() { + return this[kInterceptors]; + } + set interceptors(newInterceptors) { + if (newInterceptors) { + for (let i = newInterceptors.length - 1; i >= 0; i--) { + const interceptor = this[kInterceptors][i]; + if (typeof interceptor !== "function") { + throw new InvalidArgumentError("interceptor must be an function"); + } + } + } + this[kInterceptors] = newInterceptors; + } close(callback) { if (callback === void 0) { return new Promise((resolve, reject) => { @@ -384,6 +400,18 @@ var require_dispatcher_base = __commonJS({ queueMicrotask(onDestroyed); }); } + [kInterceptedDispatch](opts, handler) { + if (!this[kInterceptors] || this[kInterceptors].length === 0) { + this[kInterceptedDispatch] = this[kDispatch]; + return this[kDispatch](opts, handler); + } + let dispatch = this[kDispatch].bind(this); + for (let i = this[kInterceptors].length - 1; i >= 0; i--) { + dispatch = this[kInterceptors][i](dispatch); + } + this[kInterceptedDispatch] = dispatch; + return dispatch(opts, handler); + } dispatch(opts, handler) { if (!handler || typeof handler !== "object") { throw new InvalidArgumentError("handler must be an object"); @@ -398,7 +426,7 @@ var require_dispatcher_base = __commonJS({ if (this[kClosed]) { throw new ClientClosedError(); } - return this[kDispatch](opts, handler); + return this[kInterceptedDispatch](opts, handler); } catch (err) { if (typeof handler.onError !== "function") { throw new InvalidArgumentError("invalid onError method"); @@ -668,6 +696,7 @@ var require_util = __commonJS({ var { InvalidArgumentError } = require_errors(); var { Blob } = require("buffer"); var nodeUtil = require("util"); + var { stringify } = require("querystring"); function nop() { } function isStream(obj) { @@ -676,37 +705,13 @@ var require_util = __commonJS({ function isBlobLike(object) { return Blob && object instanceof Blob || object && typeof object === "object" && (typeof object.stream === "function" || typeof object.arrayBuffer === "function") && /^(Blob|File)$/.test(object[Symbol.toStringTag]); } - function isObject(val) { - return val !== null && typeof val === "object"; - } - function encode(val) { - return encodeURIComponent(val); - } function buildURL(url, queryParams) { if (url.includes("?") || url.includes("#")) { throw new Error('Query params cannot be passed when url already contains "?" or "#".'); } - if (!isObject(queryParams)) { - throw new Error("Query params must be an object"); - } - const parts = []; - for (let [key, val] of Object.entries(queryParams)) { - if (val === null || typeof val === "undefined") { - continue; - } - if (!Array.isArray(val)) { - val = [val]; - } - for (const v of val) { - if (isObject(v)) { - throw new Error("Passing object as a query param is not supported, please serialize to string up-front"); - } - parts.push(encode(key) + "=" + encode(v)); - } - } - const serializedParams = parts.join("&"); - if (serializedParams) { - url += "?" + serializedParams; + const stringified = stringify(queryParams); + if (stringified) { + url += "?" + stringified; } return url; } @@ -973,335 +978,4508 @@ var require_util = __commonJS({ } }); -// lib/fetch/constants.js -var require_constants = __commonJS({ - "lib/fetch/constants.js"(exports2, module2) { +// node_modules/busboy/lib/utils.js +var require_utils = __commonJS({ + "node_modules/busboy/lib/utils.js"(exports2, module2) { "use strict"; - var corsSafeListedMethods = ["GET", "HEAD", "POST"]; - var nullBodyStatus = [101, 204, 205, 304]; - var redirectStatus = [301, 302, 303, 307, 308]; - var referrerPolicy = [ - "", - "no-referrer", - "no-referrer-when-downgrade", - "same-origin", - "origin", - "strict-origin", - "origin-when-cross-origin", - "strict-origin-when-cross-origin", - "unsafe-url" + function parseContentType(str) { + if (str.length === 0) + return; + const params = /* @__PURE__ */ Object.create(null); + let i = 0; + for (; i < str.length; ++i) { + const code = str.charCodeAt(i); + if (TOKEN[code] !== 1) { + if (code !== 47 || i === 0) + return; + break; + } + } + if (i === str.length) + return; + const type = str.slice(0, i).toLowerCase(); + const subtypeStart = ++i; + for (; i < str.length; ++i) { + const code = str.charCodeAt(i); + if (TOKEN[code] !== 1) { + if (i === subtypeStart) + return; + if (parseContentTypeParams(str, i, params) === void 0) + return; + break; + } + } + if (i === subtypeStart) + return; + const subtype = str.slice(subtypeStart, i).toLowerCase(); + return { type, subtype, params }; + } + function parseContentTypeParams(str, i, params) { + while (i < str.length) { + for (; i < str.length; ++i) { + const code = str.charCodeAt(i); + if (code !== 32 && code !== 9) + break; + } + if (i === str.length) + break; + if (str.charCodeAt(i++) !== 59) + return; + for (; i < str.length; ++i) { + const code = str.charCodeAt(i); + if (code !== 32 && code !== 9) + break; + } + if (i === str.length) + return; + let name; + const nameStart = i; + for (; i < str.length; ++i) { + const code = str.charCodeAt(i); + if (TOKEN[code] !== 1) { + if (code !== 61) + return; + break; + } + } + if (i === str.length) + return; + name = str.slice(nameStart, i); + ++i; + if (i === str.length) + return; + let value = ""; + let valueStart; + if (str.charCodeAt(i) === 34) { + valueStart = ++i; + let escaping = false; + for (; i < str.length; ++i) { + const code = str.charCodeAt(i); + if (code === 92) { + if (escaping) { + valueStart = i; + escaping = false; + } else { + value += str.slice(valueStart, i); + escaping = true; + } + continue; + } + if (code === 34) { + if (escaping) { + valueStart = i; + escaping = false; + continue; + } + value += str.slice(valueStart, i); + break; + } + if (escaping) { + valueStart = i - 1; + escaping = false; + } + if (QDTEXT[code] !== 1) + return; + } + if (i === str.length) + return; + ++i; + } else { + valueStart = i; + for (; i < str.length; ++i) { + const code = str.charCodeAt(i); + if (TOKEN[code] !== 1) { + if (i === valueStart) + return; + break; + } + } + value = str.slice(valueStart, i); + } + name = name.toLowerCase(); + if (params[name] === void 0) + params[name] = value; + } + return params; + } + function parseDisposition(str, defDecoder) { + if (str.length === 0) + return; + const params = /* @__PURE__ */ Object.create(null); + let i = 0; + for (; i < str.length; ++i) { + const code = str.charCodeAt(i); + if (TOKEN[code] !== 1) { + if (parseDispositionParams(str, i, params, defDecoder) === void 0) + return; + break; + } + } + const type = str.slice(0, i).toLowerCase(); + return { type, params }; + } + function parseDispositionParams(str, i, params, defDecoder) { + while (i < str.length) { + for (; i < str.length; ++i) { + const code = str.charCodeAt(i); + if (code !== 32 && code !== 9) + break; + } + if (i === str.length) + break; + if (str.charCodeAt(i++) !== 59) + return; + for (; i < str.length; ++i) { + const code = str.charCodeAt(i); + if (code !== 32 && code !== 9) + break; + } + if (i === str.length) + return; + let name; + const nameStart = i; + for (; i < str.length; ++i) { + const code = str.charCodeAt(i); + if (TOKEN[code] !== 1) { + if (code === 61) + break; + return; + } + } + if (i === str.length) + return; + let value = ""; + let valueStart; + let charset; + name = str.slice(nameStart, i); + if (name.charCodeAt(name.length - 1) === 42) { + const charsetStart = ++i; + for (; i < str.length; ++i) { + const code = str.charCodeAt(i); + if (CHARSET[code] !== 1) { + if (code !== 39) + return; + break; + } + } + if (i === str.length) + return; + charset = str.slice(charsetStart, i); + ++i; + for (; i < str.length; ++i) { + const code = str.charCodeAt(i); + if (code === 39) + break; + } + if (i === str.length) + return; + ++i; + if (i === str.length) + return; + valueStart = i; + let encode = 0; + for (; i < str.length; ++i) { + const code = str.charCodeAt(i); + if (EXTENDED_VALUE[code] !== 1) { + if (code === 37) { + let hexUpper; + let hexLower; + if (i + 2 < str.length && (hexUpper = HEX_VALUES[str.charCodeAt(i + 1)]) !== -1 && (hexLower = HEX_VALUES[str.charCodeAt(i + 2)]) !== -1) { + const byteVal = (hexUpper << 4) + hexLower; + value += str.slice(valueStart, i); + value += String.fromCharCode(byteVal); + i += 2; + valueStart = i + 1; + if (byteVal >= 128) + encode = 2; + else if (encode === 0) + encode = 1; + continue; + } + return; + } + break; + } + } + value += str.slice(valueStart, i); + value = convertToUTF8(value, charset, encode); + if (value === void 0) + return; + } else { + ++i; + if (i === str.length) + return; + if (str.charCodeAt(i) === 34) { + valueStart = ++i; + let escaping = false; + for (; i < str.length; ++i) { + const code = str.charCodeAt(i); + if (code === 92) { + if (escaping) { + valueStart = i; + escaping = false; + } else { + value += str.slice(valueStart, i); + escaping = true; + } + continue; + } + if (code === 34) { + if (escaping) { + valueStart = i; + escaping = false; + continue; + } + value += str.slice(valueStart, i); + break; + } + if (escaping) { + valueStart = i - 1; + escaping = false; + } + if (QDTEXT[code] !== 1) + return; + } + if (i === str.length) + return; + ++i; + } else { + valueStart = i; + for (; i < str.length; ++i) { + const code = str.charCodeAt(i); + if (TOKEN[code] !== 1) { + if (i === valueStart) + return; + break; + } + } + value = str.slice(valueStart, i); + } + value = defDecoder(value, 2); + if (value === void 0) + return; + } + name = name.toLowerCase(); + if (params[name] === void 0) + params[name] = value; + } + return params; + } + function getDecoder(charset) { + let lc; + while (true) { + switch (charset) { + case "utf-8": + case "utf8": + return decoders.utf8; + case "latin1": + case "ascii": + case "us-ascii": + case "iso-8859-1": + case "iso8859-1": + case "iso88591": + case "iso_8859-1": + case "windows-1252": + case "iso_8859-1:1987": + case "cp1252": + case "x-cp1252": + return decoders.latin1; + case "utf16le": + case "utf-16le": + case "ucs2": + case "ucs-2": + return decoders.utf16le; + case "base64": + return decoders.base64; + default: + if (lc === void 0) { + lc = true; + charset = charset.toLowerCase(); + continue; + } + return decoders.other.bind(charset); + } + } + } + var decoders = { + utf8: (data, hint) => { + if (data.length === 0) + return ""; + if (typeof data === "string") { + if (hint < 2) + return data; + data = Buffer.from(data, "latin1"); + } + return data.utf8Slice(0, data.length); + }, + latin1: (data, hint) => { + if (data.length === 0) + return ""; + if (typeof data === "string") + return data; + return data.latin1Slice(0, data.length); + }, + utf16le: (data, hint) => { + if (data.length === 0) + return ""; + if (typeof data === "string") + data = Buffer.from(data, "latin1"); + return data.ucs2Slice(0, data.length); + }, + base64: (data, hint) => { + if (data.length === 0) + return ""; + if (typeof data === "string") + data = Buffer.from(data, "latin1"); + return data.base64Slice(0, data.length); + }, + other: (data, hint) => { + if (data.length === 0) + return ""; + if (typeof data === "string") + data = Buffer.from(data, "latin1"); + try { + const decoder = new TextDecoder(exports2); + return decoder.decode(data); + } catch { + } + } + }; + function convertToUTF8(data, charset, hint) { + const decode = getDecoder(charset); + if (decode) + return decode(data, hint); + } + function basename(path) { + if (typeof path !== "string") + return ""; + for (let i = path.length - 1; i >= 0; --i) { + switch (path.charCodeAt(i)) { + case 47: + case 92: + path = path.slice(i + 1); + return path === ".." || path === "." ? "" : path; + } + } + return path === ".." || path === "." ? "" : path; + } + var TOKEN = [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 ]; - var requestRedirect = ["follow", "manual", "error"]; - var safeMethods = ["GET", "HEAD", "OPTIONS", "TRACE"]; - var requestMode = ["navigate", "same-origin", "no-cors", "cors"]; - var requestCredentials = ["omit", "same-origin", "include"]; - var requestCache = [ - "default", - "no-store", - "reload", - "no-cache", - "force-cache", - "only-if-cached" + var QDTEXT = [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 ]; - var requestBodyHeader = [ - "content-encoding", - "content-language", - "content-location", - "content-type" + var CHARSET = [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 ]; - var forbiddenMethods = ["CONNECT", "TRACE", "TRACK"]; - var subresource = [ - "audio", - "audioworklet", - "font", - "image", - "manifest", - "paintworklet", - "script", - "style", - "track", - "video", - "xslt", - "" + var EXTENDED_VALUE = [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ]; + var HEX_VALUES = [ + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + 10, + 11, + 12, + 13, + 14, + 15, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + 10, + 11, + 12, + 13, + 14, + 15, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1 ]; - var DOMException = globalThis.DOMException ?? (() => { - try { - atob("~"); - } catch (err) { - return Object.getPrototypeOf(err).constructor; - } - })(); module2.exports = { - DOMException, - subresource, - forbiddenMethods, - requestBodyHeader, - referrerPolicy, - requestRedirect, - requestMode, - requestCredentials, - requestCache, - redirectStatus, - corsSafeListedMethods, - nullBodyStatus, - safeMethods + basename, + convertToUTF8, + getDecoder, + parseContentType, + parseDisposition }; } }); -// lib/fetch/symbols.js -var require_symbols2 = __commonJS({ - "lib/fetch/symbols.js"(exports2, module2) { +// node_modules/streamsearch/lib/sbmh.js +var require_sbmh = __commonJS({ + "node_modules/streamsearch/lib/sbmh.js"(exports2, module2) { "use strict"; - module2.exports = { - kUrl: Symbol("url"), - kHeaders: Symbol("headers"), - kSignal: Symbol("signal"), - kState: Symbol("state"), - kGuard: Symbol("guard"), - kRealm: Symbol("realm") + function memcmp(buf1, pos1, buf2, pos2, num) { + for (let i = 0; i < num; ++i) { + if (buf1[pos1 + i] !== buf2[pos2 + i]) + return false; + } + return true; + } + var SBMH = class { + constructor(needle, cb) { + if (typeof cb !== "function") + throw new Error("Missing match callback"); + if (typeof needle === "string") + needle = Buffer.from(needle); + else if (!Buffer.isBuffer(needle)) + throw new Error(`Expected Buffer for needle, got ${typeof needle}`); + const needleLen = needle.length; + this.maxMatches = Infinity; + this.matches = 0; + this._cb = cb; + this._lookbehindSize = 0; + this._needle = needle; + this._bufPos = 0; + this._lookbehind = Buffer.allocUnsafe(needleLen); + this._occ = [ + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen, + needleLen + ]; + if (needleLen > 1) { + for (let i = 0; i < needleLen - 1; ++i) + this._occ[needle[i]] = needleLen - 1 - i; + } + } + reset() { + this.matches = 0; + this._lookbehindSize = 0; + this._bufPos = 0; + } + push(chunk, pos) { + let result; + if (!Buffer.isBuffer(chunk)) + chunk = Buffer.from(chunk, "latin1"); + const chunkLen = chunk.length; + this._bufPos = pos || 0; + while (result !== chunkLen && this.matches < this.maxMatches) + result = feed(this, chunk); + return result; + } + destroy() { + const lbSize = this._lookbehindSize; + if (lbSize) + this._cb(false, this._lookbehind, 0, lbSize, false); + this.reset(); + } }; + function feed(self, data) { + const len = data.length; + const needle = self._needle; + const needleLen = needle.length; + let pos = -self._lookbehindSize; + const lastNeedleCharPos = needleLen - 1; + const lastNeedleChar = needle[lastNeedleCharPos]; + const end = len - needleLen; + const occ = self._occ; + const lookbehind = self._lookbehind; + if (pos < 0) { + while (pos < 0 && pos <= end) { + const nextPos = pos + lastNeedleCharPos; + const ch = nextPos < 0 ? lookbehind[self._lookbehindSize + nextPos] : data[nextPos]; + if (ch === lastNeedleChar && matchNeedle(self, data, pos, lastNeedleCharPos)) { + self._lookbehindSize = 0; + ++self.matches; + if (pos > -self._lookbehindSize) + self._cb(true, lookbehind, 0, self._lookbehindSize + pos, false); + else + self._cb(true, void 0, 0, 0, true); + return self._bufPos = pos + needleLen; + } + pos += occ[ch]; + } + while (pos < 0 && !matchNeedle(self, data, pos, len - pos)) + ++pos; + if (pos < 0) { + const bytesToCutOff = self._lookbehindSize + pos; + if (bytesToCutOff > 0) { + self._cb(false, lookbehind, 0, bytesToCutOff, false); + } + self._lookbehindSize -= bytesToCutOff; + lookbehind.copy(lookbehind, 0, bytesToCutOff, self._lookbehindSize); + lookbehind.set(data, self._lookbehindSize); + self._lookbehindSize += len; + self._bufPos = len; + return len; + } + self._cb(false, lookbehind, 0, self._lookbehindSize, false); + self._lookbehindSize = 0; + } + pos += self._bufPos; + const firstNeedleChar = needle[0]; + while (pos <= end) { + const ch = data[pos + lastNeedleCharPos]; + if (ch === lastNeedleChar && data[pos] === firstNeedleChar && memcmp(needle, 0, data, pos, lastNeedleCharPos)) { + ++self.matches; + if (pos > 0) + self._cb(true, data, self._bufPos, pos, true); + else + self._cb(true, void 0, 0, 0, true); + return self._bufPos = pos + needleLen; + } + pos += occ[ch]; + } + while (pos < len) { + if (data[pos] !== firstNeedleChar || !memcmp(data, pos, needle, 0, len - pos)) { + ++pos; + continue; + } + data.copy(lookbehind, 0, pos, len); + self._lookbehindSize = len - pos; + break; + } + if (pos > 0) + self._cb(false, data, self._bufPos, pos < len ? pos : len, true); + self._bufPos = len; + return len; + } + function matchNeedle(self, data, pos, len) { + const lb = self._lookbehind; + const lbSize = self._lookbehindSize; + const needle = self._needle; + for (let i = 0; i < len; ++i, ++pos) { + const ch = pos < 0 ? lb[lbSize + pos] : data[pos]; + if (ch !== needle[i]) + return false; + } + return true; + } + module2.exports = SBMH; } }); -// lib/fetch/webidl.js -var require_webidl = __commonJS({ - "lib/fetch/webidl.js"(exports2, module2) { +// node_modules/busboy/lib/types/multipart.js +var require_multipart = __commonJS({ + "node_modules/busboy/lib/types/multipart.js"(exports2, module2) { "use strict"; - var { types } = require("util"); - var { hasOwn, toUSVString } = require_util2(); - var webidl = {}; - webidl.converters = {}; - webidl.util = {}; - webidl.errors = {}; - webidl.errors.exception = function(message) { - throw new TypeError(`${message.header}: ${message.message}`); + var { Readable, Writable } = require("stream"); + var StreamSearch = require_sbmh(); + var { + basename, + convertToUTF8, + getDecoder, + parseContentType, + parseDisposition + } = require_utils(); + var BUF_CRLF = Buffer.from("\r\n"); + var BUF_CR = Buffer.from("\r"); + var BUF_DASH = Buffer.from("-"); + function noop() { + } + var MAX_HEADER_PAIRS = 2e3; + var MAX_HEADER_SIZE = 16 * 1024; + var HPARSER_NAME = 0; + var HPARSER_PRE_OWS = 1; + var HPARSER_VALUE = 2; + var HeaderParser = class { + constructor(cb) { + this.header = /* @__PURE__ */ Object.create(null); + this.pairCount = 0; + this.byteCount = 0; + this.state = HPARSER_NAME; + this.name = ""; + this.value = ""; + this.crlf = 0; + this.cb = cb; + } + reset() { + this.header = /* @__PURE__ */ Object.create(null); + this.pairCount = 0; + this.byteCount = 0; + this.state = HPARSER_NAME; + this.name = ""; + this.value = ""; + this.crlf = 0; + } + push(chunk, pos, end) { + let start = pos; + while (pos < end) { + switch (this.state) { + case HPARSER_NAME: { + let done = false; + for (; pos < end; ++pos) { + if (this.byteCount === MAX_HEADER_SIZE) + return -1; + ++this.byteCount; + const code = chunk[pos]; + if (TOKEN[code] !== 1) { + if (code !== 58) + return -1; + this.name += chunk.latin1Slice(start, pos); + if (this.name.length === 0) + return -1; + ++pos; + done = true; + this.state = HPARSER_PRE_OWS; + break; + } + } + if (!done) { + this.name += chunk.latin1Slice(start, pos); + break; + } + } + case HPARSER_PRE_OWS: { + let done = false; + for (; pos < end; ++pos) { + if (this.byteCount === MAX_HEADER_SIZE) + return -1; + ++this.byteCount; + const code = chunk[pos]; + if (code !== 32 && code !== 9) { + start = pos; + done = true; + this.state = HPARSER_VALUE; + break; + } + } + if (!done) + break; + } + case HPARSER_VALUE: + switch (this.crlf) { + case 0: + for (; pos < end; ++pos) { + if (this.byteCount === MAX_HEADER_SIZE) + return -1; + ++this.byteCount; + const code = chunk[pos]; + if (FIELD_VCHAR[code] !== 1) { + if (code !== 13) + return -1; + ++this.crlf; + break; + } + } + this.value += chunk.latin1Slice(start, pos++); + break; + case 1: + if (this.byteCount === MAX_HEADER_SIZE) + return -1; + ++this.byteCount; + if (chunk[pos++] !== 10) + return -1; + ++this.crlf; + break; + case 2: { + if (this.byteCount === MAX_HEADER_SIZE) + return -1; + ++this.byteCount; + const code = chunk[pos]; + if (code === 32 || code === 9) { + start = pos; + this.crlf = 0; + } else { + if (++this.pairCount < MAX_HEADER_PAIRS) { + this.name = this.name.toLowerCase(); + if (this.header[this.name] === void 0) + this.header[this.name] = [this.value]; + else + this.header[this.name].push(this.value); + } + if (code === 13) { + ++this.crlf; + ++pos; + } else { + start = pos; + this.crlf = 0; + this.state = HPARSER_NAME; + this.name = ""; + this.value = ""; + } + } + break; + } + case 3: { + if (this.byteCount === MAX_HEADER_SIZE) + return -1; + ++this.byteCount; + if (chunk[pos++] !== 10) + return -1; + const header = this.header; + this.reset(); + this.cb(header); + return pos; + } + } + break; + } + } + return pos; + } }; - webidl.errors.conversionFailed = function(context) { - const plural = context.types.length === 1 ? "" : " one of"; - const message = `${context.argument} could not be converted to${plural}: ${context.types.join(", ")}.`; - return webidl.errors.exception({ - header: context.prefix, - message - }); - }; - webidl.errors.invalidArgument = function(context) { - return webidl.errors.exception({ - header: context.prefix, - message: `"${context.value}" is an invalid ${context.type}.` - }); - }; - webidl.util.Type = function(V) { - switch (typeof V) { - case "undefined": - return "Undefined"; - case "boolean": - return "Boolean"; - case "string": - return "String"; - case "symbol": - return "Symbol"; - case "number": - return "Number"; - case "bigint": - return "BigInt"; - case "function": - case "object": { - if (V === null) { - return "Null"; + var FileStream = class extends Readable { + constructor(opts, owner) { + super(opts); + this.truncated = false; + this._readcb = null; + this.once("end", () => { + this._read(); + if (--owner._fileEndsLeft === 0 && owner._finalcb) { + const cb = owner._finalcb; + owner._finalcb = null; + process.nextTick(cb); } - return "Object"; - } - } - }; - webidl.util.ConvertToInt = function(V, bitLength, signedness, opts = {}) { - let upperBound; - let lowerBound; - if (bitLength === 64) { - upperBound = Math.pow(2, 53) - 1; - if (signedness === "unsigned") { - lowerBound = 0; - } else { - lowerBound = Math.pow(-2, 53) + 1; - } - } else if (signedness === "unsigned") { - lowerBound = 0; - upperBound = Math.pow(2, bitLength) - 1; - } else { - lowerBound = Math.pow(-2, bitLength) - 1; - upperBound = Math.pow(2, bitLength - 1) - 1; - } - let x = Number(V); - if (Object.is(-0, x)) { - x = 0; - } - if (opts.enforceRange === true) { - if (Number.isNaN(x) || x === Number.POSITIVE_INFINITY || x === Number.NEGATIVE_INFINITY) { - webidl.errors.exception({ - header: "Integer conversion", - message: `Could not convert ${V} to an integer.` - }); - } - x = webidl.util.IntegerPart(x); - if (x < lowerBound || x > upperBound) { - webidl.errors.exception({ - header: "Integer conversion", - message: `Value must be between ${lowerBound}-${upperBound}, got ${x}.` - }); - } - return x; + }); } - if (!Number.isNaN(x) && opts.clamp === true) { - x = Math.min(Math.max(x, lowerBound), upperBound); - if (Math.floor(x) % 2 === 0) { - x = Math.floor(x); - } else { - x = Math.ceil(x); + _read(n) { + const cb = this._readcb; + if (cb) { + this._readcb = null; + cb(); } - return x; - } - if (Number.isNaN(x) || Object.is(0, x) || x === Number.POSITIVE_INFINITY || x === Number.NEGATIVE_INFINITY) { - return 0; - } - x = webidl.util.IntegerPart(x); - x = x % Math.pow(2, bitLength); - if (signedness === "signed" && x >= Math.pow(2, bitLength) - 1) { - return x - Math.pow(2, bitLength); } - return x; }; - webidl.util.IntegerPart = function(n) { - const r = Math.floor(Math.abs(n)); - if (n < 0) { - return -1 * r; + var ignoreData = { + push: (chunk, pos) => { + }, + destroy: () => { } - return r; }; - webidl.sequenceConverter = function(converter) { - return (V) => { - if (webidl.util.Type(V) !== "Object") { - webidl.errors.exception({ - header: "Sequence", - message: `Value of type ${webidl.util.Type(V)} is not an Object.` - }); - } - const method = V?.[Symbol.iterator]?.(); - const seq = []; - if (method === void 0 || typeof method.next !== "function") { - webidl.errors.exception({ - header: "Sequence", - message: "Object is not an iterator." - }); - } - while (true) { - const { done, value } = method.next(); - if (done) { - break; + function callAndUnsetCb(self, err) { + const cb = self._writecb; + self._writecb = null; + if (err) + self.destroy(err); + else if (cb) + cb(); + } + function nullDecoder(val, hint) { + return val; + } + var Multipart = class extends Writable { + constructor(cfg) { + const streamOpts = { + autoDestroy: true, + emitClose: true, + highWaterMark: typeof cfg.highWaterMark === "number" ? cfg.highWaterMark : void 0 + }; + super(streamOpts); + if (!cfg.conType.params || typeof cfg.conType.params.boundary !== "string") + throw new Error("Multipart: Boundary not found"); + const boundary = cfg.conType.params.boundary; + const paramDecoder = typeof cfg.defParamCharset === "string" && cfg.defParamCharset ? getDecoder(cfg.defParamCharset) : nullDecoder; + const defCharset = cfg.defCharset || "utf8"; + const preservePath = cfg.preservePath; + const fileOpts = { + autoDestroy: true, + emitClose: true, + highWaterMark: typeof cfg.fileHwm === "number" ? cfg.fileHwm : void 0 + }; + const limits = cfg.limits; + const fieldSizeLimit = limits && typeof limits.fieldSize === "number" ? limits.fieldSize : 1 * 1024 * 1024; + const fileSizeLimit = limits && typeof limits.fileSize === "number" ? limits.fileSize : Infinity; + const filesLimit = limits && typeof limits.files === "number" ? limits.files : Infinity; + const fieldsLimit = limits && typeof limits.fields === "number" ? limits.fields : Infinity; + const partsLimit = limits && typeof limits.parts === "number" ? limits.parts : Infinity; + let parts = -1; + let fields = 0; + let files = 0; + let skipPart = false; + this._fileEndsLeft = 0; + this._fileStream = void 0; + this._complete = false; + let fileSize = 0; + let field; + let fieldSize = 0; + let partCharset; + let partEncoding; + let partType; + let partName; + let partTruncated = false; + let hitFilesLimit = false; + let hitFieldsLimit = false; + this._hparser = null; + const hparser = new HeaderParser((header) => { + this._hparser = null; + skipPart = false; + partType = "text/plain"; + partCharset = defCharset; + partEncoding = "7bit"; + partName = void 0; + partTruncated = false; + let filename; + if (!header["content-disposition"]) { + skipPart = true; + return; } - seq.push(converter(value)); - } - return seq; - }; - }; - webidl.recordConverter = function(keyConverter, valueConverter) { - return (V) => { - const record = {}; - const type = webidl.util.Type(V); - if (type === "Undefined" || type === "Null") { - return record; - } - if (type !== "Object") { - webidl.errors.exception({ - header: "Record", - message: `Expected ${V} to be an Object type.` - }); - } - for (let [key, value] of Object.entries(V)) { - key = keyConverter(key); - value = valueConverter(value); - record[key] = value; - } - return record; - }; - }; - webidl.interfaceConverter = function(i) { - return (V, opts = {}) => { - if (opts.strict !== false && !(V instanceof i)) { - webidl.errors.exception({ - header: i.name, - message: `Expected ${V} to be an instance of ${i.name}.` - }); - } - return V; - }; - }; - webidl.dictionaryConverter = function(converters) { - return (dictionary) => { - const type = webidl.util.Type(dictionary); - const dict = {}; - if (type !== "Null" && type !== "Undefined" && type !== "Object") { - webidl.errors.exception({ - header: "Dictionary", - message: `Expected ${dictionary} to be one of: Null, Undefined, Object.` - }); - } - for (const options of converters) { - const { key, defaultValue, required, converter } = options; - if (required === true) { - if (!hasOwn(dictionary, key)) { - webidl.errors.exception({ - header: "Dictionary", - message: `Missing required key "${key}".` - }); + const disp = parseDisposition(header["content-disposition"][0], paramDecoder); + if (!disp || disp.type !== "form-data") { + skipPart = true; + return; + } + if (disp.params) { + if (disp.params.name) + partName = disp.params.name; + if (disp.params["filename*"]) + filename = disp.params["filename*"]; + else if (disp.params.filename) + filename = disp.params.filename; + if (filename !== void 0 && !preservePath) + filename = basename(filename); + } + if (header["content-type"]) { + const conType = parseContentType(header["content-type"][0]); + if (conType) { + partType = `${conType.type}/${conType.subtype}`; + if (conType.params && typeof conType.params.charset === "string") + partCharset = conType.params.charset.toLowerCase(); } } - let value = dictionary[key]; - const hasDefault = hasOwn(options, "defaultValue"); - if (hasDefault && value !== null) { - value = value ?? defaultValue; + if (header["content-transfer-encoding"]) + partEncoding = header["content-transfer-encoding"][0].toLowerCase(); + if (partType === "application/octet-stream" || filename !== void 0) { + if (files === filesLimit) { + if (!hitFilesLimit) { + hitFilesLimit = true; + this.emit("filesLimit"); + } + skipPart = true; + return; + } + ++files; + if (this.listenerCount("file") === 0) { + skipPart = true; + return; + } + fileSize = 0; + this._fileStream = new FileStream(fileOpts, this); + ++this._fileEndsLeft; + this.emit("file", partName, this._fileStream, { + filename, + encoding: partEncoding, + mimeType: partType + }); + } else { + if (fields === fieldsLimit) { + if (!hitFieldsLimit) { + hitFieldsLimit = true; + this.emit("fieldsLimit"); + } + skipPart = true; + return; + } + ++fields; + if (this.listenerCount("field") === 0) { + skipPart = true; + return; + } + field = []; + fieldSize = 0; } - if (required || hasDefault || value !== void 0) { - value = converter(value); - if (options.allowedValues && !options.allowedValues.includes(value)) { - webidl.errors.exception({ - header: "Dictionary", - message: `${value} is not an accepted type. Expected one of ${options.allowedValues.join(", ")}.` + }); + let matchPostBoundary = 0; + const ssCb = (isMatch, data, start, end, isDataSafe) => { + retrydata: + while (data) { + if (this._hparser !== null) { + const ret = this._hparser.push(data, start, end); + if (ret === -1) { + this._hparser = null; + hparser.reset(); + this.emit("error", new Error("Malformed part header")); + break; + } + start = ret; + } + if (start === end) + break; + if (matchPostBoundary !== 0) { + if (matchPostBoundary === 1) { + switch (data[start]) { + case 45: + matchPostBoundary = 2; + ++start; + break; + case 13: + matchPostBoundary = 3; + ++start; + break; + default: + matchPostBoundary = 0; + } + if (start === end) + return; + } + if (matchPostBoundary === 2) { + matchPostBoundary = 0; + if (data[start] === 45) { + this._complete = true; + this._bparser = ignoreData; + return; + } + const writecb = this._writecb; + this._writecb = noop; + ssCb(false, BUF_DASH, 0, 1, false); + this._writecb = writecb; + } else if (matchPostBoundary === 3) { + matchPostBoundary = 0; + if (data[start] === 10) { + ++start; + if (parts >= partsLimit) + break; + this._hparser = hparser; + if (start === end) + break; + continue retrydata; + } else { + const writecb = this._writecb; + this._writecb = noop; + ssCb(false, BUF_CR, 0, 1, false); + this._writecb = writecb; + } + } + } + if (!skipPart) { + if (this._fileStream) { + let chunk; + const actualLen = Math.min(end - start, fileSizeLimit - fileSize); + if (!isDataSafe) { + chunk = Buffer.allocUnsafe(actualLen); + data.copy(chunk, 0, start, start + actualLen); + } else { + chunk = data.slice(start, start + actualLen); + } + fileSize += chunk.length; + if (fileSize === fileSizeLimit) { + if (chunk.length > 0) + this._fileStream.push(chunk); + this._fileStream.emit("limit"); + this._fileStream.truncated = true; + skipPart = true; + } else if (!this._fileStream.push(chunk)) { + if (this._writecb) + this._fileStream._readcb = this._writecb; + this._writecb = null; + } + } else if (field !== void 0) { + let chunk; + const actualLen = Math.min(end - start, fieldSizeLimit - fieldSize); + if (!isDataSafe) { + chunk = Buffer.allocUnsafe(actualLen); + data.copy(chunk, 0, start, start + actualLen); + } else { + chunk = data.slice(start, start + actualLen); + } + fieldSize += actualLen; + field.push(chunk); + if (fieldSize === fieldSizeLimit) { + skipPart = true; + partTruncated = true; + } + } + } + break; + } + if (isMatch) { + matchPostBoundary = 1; + if (this._fileStream) { + this._fileStream.push(null); + this._fileStream = null; + } else if (field !== void 0) { + let data2; + switch (field.length) { + case 0: + data2 = ""; + break; + case 1: + data2 = convertToUTF8(field[0], partCharset, 0); + break; + default: + data2 = convertToUTF8(Buffer.concat(field, fieldSize), partCharset, 0); + } + field = void 0; + fieldSize = 0; + this.emit("field", partName, data2, { + nameTruncated: false, + valueTruncated: partTruncated, + encoding: partEncoding, + mimeType: partType }); } - dict[key] = value; + if (++parts === partsLimit) + this.emit("partsLimit"); } - } - return dict; - }; - }; - webidl.nullableConverter = function(converter) { - return (V) => { - if (V === null) { - return V; - } - return converter(V); - }; - }; - webidl.converters.DOMString = function(V, opts = {}) { - if (V === null && opts.legacyNullToEmptyString) { - return ""; - } - if (typeof V === "symbol") { - throw new TypeError("Could not convert argument of type symbol to string."); + }; + this._bparser = new StreamSearch(`\r +--${boundary}`, ssCb); + this._writecb = null; + this._finalcb = null; + this.write(BUF_CRLF); + } + static detect(conType) { + return conType.type === "multipart" && conType.subtype === "form-data"; + } + _write(chunk, enc, cb) { + this._writecb = cb; + this._bparser.push(chunk, 0); + if (this._writecb) + callAndUnsetCb(this); + } + _destroy(err, cb) { + this._hparser = null; + this._bparser = ignoreData; + if (!err) + err = checkEndState(this); + const fileStream = this._fileStream; + if (fileStream) { + this._fileStream = null; + fileStream.destroy(err); + } + cb(err); + } + _final(cb) { + this._bparser.destroy(); + if (!this._complete) + return cb(new Error("Unexpected end of form")); + if (this._fileEndsLeft) + this._finalcb = finalcb.bind(null, this, cb); + else + finalcb(this, cb); } - return String(V); }; - webidl.converters.ByteString = function(V) { - const x = webidl.converters.DOMString(V); - for (let index = 0; index < x.length; index++) { - const charCode = x.charCodeAt(index); - if (charCode > 255) { - throw new TypeError(`Cannot convert argument to a ByteString because the character atindex ${index} has a value of ${charCode} which is greater than 255.`); + function finalcb(self, cb, err) { + if (err) + return cb(err); + err = checkEndState(self); + cb(err); + } + function checkEndState(self) { + if (self._hparser) + return new Error("Malformed part header"); + const fileStream = self._fileStream; + if (fileStream) { + self._fileStream = null; + fileStream.destroy(new Error("Unexpected end of file")); + } + if (!self._complete) + return new Error("Unexpected end of form"); + } + var TOKEN = [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ]; + var FIELD_VCHAR = [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ]; + module2.exports = Multipart; + } +}); + +// node_modules/busboy/lib/types/urlencoded.js +var require_urlencoded = __commonJS({ + "node_modules/busboy/lib/types/urlencoded.js"(exports2, module2) { + "use strict"; + var { Writable } = require("stream"); + var { getDecoder } = require_utils(); + var URLEncoded = class extends Writable { + constructor(cfg) { + const streamOpts = { + autoDestroy: true, + emitClose: true, + highWaterMark: typeof cfg.highWaterMark === "number" ? cfg.highWaterMark : void 0 + }; + super(streamOpts); + let charset = cfg.defCharset || "utf8"; + if (cfg.conType.params && typeof cfg.conType.params.charset === "string") + charset = cfg.conType.params.charset; + this.charset = charset; + const limits = cfg.limits; + this.fieldSizeLimit = limits && typeof limits.fieldSize === "number" ? limits.fieldSize : 1 * 1024 * 1024; + this.fieldsLimit = limits && typeof limits.fields === "number" ? limits.fields : Infinity; + this.fieldNameSizeLimit = limits && typeof limits.fieldNameSize === "number" ? limits.fieldNameSize : 100; + this._inKey = true; + this._keyTrunc = false; + this._valTrunc = false; + this._bytesKey = 0; + this._bytesVal = 0; + this._fields = 0; + this._key = ""; + this._val = ""; + this._byte = -2; + this._lastPos = 0; + this._encode = 0; + this._decoder = getDecoder(charset); + } + static detect(conType) { + return conType.type === "application" && conType.subtype === "x-www-form-urlencoded"; + } + _write(chunk, enc, cb) { + if (this._fields >= this.fieldsLimit) + return cb(); + let i = 0; + const len = chunk.length; + this._lastPos = 0; + if (this._byte !== -2) { + i = readPctEnc(this, chunk, i, len); + if (i === -1) + return cb(new Error("Malformed urlencoded form")); + if (i >= len) + return cb(); + if (this._inKey) + ++this._bytesKey; + else + ++this._bytesVal; + } + main: + while (i < len) { + if (this._inKey) { + i = skipKeyBytes(this, chunk, i, len); + while (i < len) { + switch (chunk[i]) { + case 61: + if (this._lastPos < i) + this._key += chunk.latin1Slice(this._lastPos, i); + this._lastPos = ++i; + this._key = this._decoder(this._key, this._encode); + this._encode = 0; + this._inKey = false; + continue main; + case 38: + if (this._lastPos < i) + this._key += chunk.latin1Slice(this._lastPos, i); + this._lastPos = ++i; + this._key = this._decoder(this._key, this._encode); + this._encode = 0; + if (this._bytesKey > 0) { + this.emit("field", this._key, "", { + nameTruncated: this._keyTrunc, + valueTruncated: false, + encoding: this.charset, + mimeType: "text/plain" + }); + } + this._key = ""; + this._val = ""; + this._keyTrunc = false; + this._valTrunc = false; + this._bytesKey = 0; + this._bytesVal = 0; + if (++this._fields >= this.fieldsLimit) { + this.emit("fieldsLimit"); + return cb(); + } + continue; + case 43: + if (this._lastPos < i) + this._key += chunk.latin1Slice(this._lastPos, i); + this._key += " "; + this._lastPos = i + 1; + break; + case 37: + if (this._encode === 0) + this._encode = 1; + if (this._lastPos < i) + this._key += chunk.latin1Slice(this._lastPos, i); + this._lastPos = i + 1; + this._byte = -1; + i = readPctEnc(this, chunk, i + 1, len); + if (i === -1) + return cb(new Error("Malformed urlencoded form")); + if (i >= len) + return cb(); + ++this._bytesKey; + i = skipKeyBytes(this, chunk, i, len); + continue; + } + ++i; + ++this._bytesKey; + i = skipKeyBytes(this, chunk, i, len); + } + if (this._lastPos < i) + this._key += chunk.latin1Slice(this._lastPos, i); + } else { + i = skipValBytes(this, chunk, i, len); + while (i < len) { + switch (chunk[i]) { + case 38: + if (this._lastPos < i) + this._val += chunk.latin1Slice(this._lastPos, i); + this._lastPos = ++i; + this._inKey = true; + this._val = this._decoder(this._val, this._encode); + this._encode = 0; + if (this._bytesKey > 0 || this._bytesVal > 0) { + this.emit("field", this._key, this._val, { + nameTruncated: this._keyTrunc, + valueTruncated: this._valTrunc, + encoding: this.charset, + mimeType: "text/plain" + }); + } + this._key = ""; + this._val = ""; + this._keyTrunc = false; + this._valTrunc = false; + this._bytesKey = 0; + this._bytesVal = 0; + if (++this._fields >= this.fieldsLimit) { + this.emit("fieldsLimit"); + return cb(); + } + continue main; + case 43: + if (this._lastPos < i) + this._val += chunk.latin1Slice(this._lastPos, i); + this._val += " "; + this._lastPos = i + 1; + break; + case 37: + if (this._encode === 0) + this._encode = 1; + if (this._lastPos < i) + this._val += chunk.latin1Slice(this._lastPos, i); + this._lastPos = i + 1; + this._byte = -1; + i = readPctEnc(this, chunk, i + 1, len); + if (i === -1) + return cb(new Error("Malformed urlencoded form")); + if (i >= len) + return cb(); + ++this._bytesVal; + i = skipValBytes(this, chunk, i, len); + continue; + } + ++i; + ++this._bytesVal; + i = skipValBytes(this, chunk, i, len); + } + if (this._lastPos < i) + this._val += chunk.latin1Slice(this._lastPos, i); + } + } + cb(); + } + _final(cb) { + if (this._byte !== -2) + return cb(new Error("Malformed urlencoded form")); + if (!this._inKey || this._bytesKey > 0 || this._bytesVal > 0) { + if (this._inKey) + this._key = this._decoder(this._key, this._encode); + else + this._val = this._decoder(this._val, this._encode); + this.emit("field", this._key, this._val, { + nameTruncated: this._keyTrunc, + valueTruncated: this._valTrunc, + encoding: this.charset, + mimeType: "text/plain" + }); } + cb(); } - return x; }; - webidl.converters.USVString = toUSVString; + function readPctEnc(self, chunk, pos, len) { + if (pos >= len) + return len; + if (self._byte === -1) { + const hexUpper = HEX_VALUES[chunk[pos++]]; + if (hexUpper === -1) + return -1; + if (hexUpper >= 8) + self._encode = 2; + if (pos < len) { + const hexLower = HEX_VALUES[chunk[pos++]]; + if (hexLower === -1) + return -1; + if (self._inKey) + self._key += String.fromCharCode((hexUpper << 4) + hexLower); + else + self._val += String.fromCharCode((hexUpper << 4) + hexLower); + self._byte = -2; + self._lastPos = pos; + } else { + self._byte = hexUpper; + } + } else { + const hexLower = HEX_VALUES[chunk[pos++]]; + if (hexLower === -1) + return -1; + if (self._inKey) + self._key += String.fromCharCode((self._byte << 4) + hexLower); + else + self._val += String.fromCharCode((self._byte << 4) + hexLower); + self._byte = -2; + self._lastPos = pos; + } + return pos; + } + function skipKeyBytes(self, chunk, pos, len) { + if (self._bytesKey > self.fieldNameSizeLimit) { + if (!self._keyTrunc) { + if (self._lastPos < pos) + self._key += chunk.latin1Slice(self._lastPos, pos - 1); + } + self._keyTrunc = true; + for (; pos < len; ++pos) { + const code = chunk[pos]; + if (code === 61 || code === 38) + break; + ++self._bytesKey; + } + self._lastPos = pos; + } + return pos; + } + function skipValBytes(self, chunk, pos, len) { + if (self._bytesVal > self.fieldSizeLimit) { + if (!self._valTrunc) { + if (self._lastPos < pos) + self._val += chunk.latin1Slice(self._lastPos, pos - 1); + } + self._valTrunc = true; + for (; pos < len; ++pos) { + if (chunk[pos] === 38) + break; + ++self._bytesVal; + } + self._lastPos = pos; + } + return pos; + } + var HEX_VALUES = [ + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + 10, + 11, + 12, + 13, + 14, + 15, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + 10, + 11, + 12, + 13, + 14, + 15, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1 + ]; + module2.exports = URLEncoded; + } +}); + +// node_modules/busboy/lib/index.js +var require_lib = __commonJS({ + "node_modules/busboy/lib/index.js"(exports2, module2) { + "use strict"; + var { parseContentType } = require_utils(); + function getInstance(cfg) { + const headers = cfg.headers; + const conType = parseContentType(headers["content-type"]); + if (!conType) + throw new Error("Malformed content type"); + for (const type of TYPES) { + const matched = type.detect(conType); + if (!matched) + continue; + const instanceCfg = { + limits: cfg.limits, + headers, + conType, + highWaterMark: void 0, + fileHwm: void 0, + defCharset: void 0, + defParamCharset: void 0, + preservePath: false + }; + if (cfg.highWaterMark) + instanceCfg.highWaterMark = cfg.highWaterMark; + if (cfg.fileHwm) + instanceCfg.fileHwm = cfg.fileHwm; + instanceCfg.defCharset = cfg.defCharset; + instanceCfg.defParamCharset = cfg.defParamCharset; + instanceCfg.preservePath = cfg.preservePath; + return new type(instanceCfg); + } + throw new Error(`Unsupported content type: ${headers["content-type"]}`); + } + var TYPES = [ + require_multipart(), + require_urlencoded() + ].filter(function(typemod) { + return typeof typemod.detect === "function"; + }); + module2.exports = (cfg) => { + if (typeof cfg !== "object" || cfg === null) + cfg = {}; + if (typeof cfg.headers !== "object" || cfg.headers === null || typeof cfg.headers["content-type"] !== "string") { + throw new Error("Missing Content-Type"); + } + return getInstance(cfg); + }; + } +}); + +// lib/fetch/constants.js +var require_constants = __commonJS({ + "lib/fetch/constants.js"(exports2, module2) { + "use strict"; + var corsSafeListedMethods = ["GET", "HEAD", "POST"]; + var nullBodyStatus = [101, 204, 205, 304]; + var redirectStatus = [301, 302, 303, 307, 308]; + var referrerPolicy = [ + "", + "no-referrer", + "no-referrer-when-downgrade", + "same-origin", + "origin", + "strict-origin", + "origin-when-cross-origin", + "strict-origin-when-cross-origin", + "unsafe-url" + ]; + var requestRedirect = ["follow", "manual", "error"]; + var safeMethods = ["GET", "HEAD", "OPTIONS", "TRACE"]; + var requestMode = ["navigate", "same-origin", "no-cors", "cors"]; + var requestCredentials = ["omit", "same-origin", "include"]; + var requestCache = [ + "default", + "no-store", + "reload", + "no-cache", + "force-cache", + "only-if-cached" + ]; + var requestBodyHeader = [ + "content-encoding", + "content-language", + "content-location", + "content-type" + ]; + var forbiddenMethods = ["CONNECT", "TRACE", "TRACK"]; + var subresource = [ + "audio", + "audioworklet", + "font", + "image", + "manifest", + "paintworklet", + "script", + "style", + "track", + "video", + "xslt", + "" + ]; + var DOMException = globalThis.DOMException ?? (() => { + try { + atob("~"); + } catch (err) { + return Object.getPrototypeOf(err).constructor; + } + })(); + module2.exports = { + DOMException, + subresource, + forbiddenMethods, + requestBodyHeader, + referrerPolicy, + requestRedirect, + requestMode, + requestCredentials, + requestCache, + redirectStatus, + corsSafeListedMethods, + nullBodyStatus, + safeMethods + }; + } +}); + +// lib/fetch/util.js +var require_util2 = __commonJS({ + "lib/fetch/util.js"(exports2, module2) { + "use strict"; + var { redirectStatus } = require_constants(); + var { performance: performance2 } = require("perf_hooks"); + var { isBlobLike, toUSVString, ReadableStreamFrom } = require_util(); + var assert = require("assert"); + var { isUint8Array } = require("util/types"); + var crypto; + try { + crypto = require("crypto"); + } catch { + } + var badPorts = [ + "1", + "7", + "9", + "11", + "13", + "15", + "17", + "19", + "20", + "21", + "22", + "23", + "25", + "37", + "42", + "43", + "53", + "69", + "77", + "79", + "87", + "95", + "101", + "102", + "103", + "104", + "109", + "110", + "111", + "113", + "115", + "117", + "119", + "123", + "135", + "137", + "139", + "143", + "161", + "179", + "389", + "427", + "465", + "512", + "513", + "514", + "515", + "526", + "530", + "531", + "532", + "540", + "548", + "554", + "556", + "563", + "587", + "601", + "636", + "989", + "990", + "993", + "995", + "1719", + "1720", + "1723", + "2049", + "3659", + "4045", + "5060", + "5061", + "6000", + "6566", + "6665", + "6666", + "6667", + "6668", + "6669", + "6697", + "10080" + ]; + function responseURL(response) { + const urlList = response.urlList; + const length = urlList.length; + return length === 0 ? null : urlList[length - 1].toString(); + } + function responseLocationURL(response, requestFragment) { + if (!redirectStatus.includes(response.status)) { + return null; + } + let location = response.headersList.get("location"); + location = location ? new URL(location, responseURL(response)) : null; + if (location && !location.hash) { + location.hash = requestFragment; + } + return location; + } + function requestCurrentURL(request) { + return request.urlList[request.urlList.length - 1]; + } + function requestBadPort(request) { + const url = requestCurrentURL(request); + if (/^https?:/.test(url.protocol) && badPorts.includes(url.port)) { + return "blocked"; + } + return "allowed"; + } + function isErrorLike(object) { + return object instanceof Error || (object?.constructor?.name === "Error" || object?.constructor?.name === "DOMException"); + } + function isValidReasonPhrase(statusText) { + for (let i = 0; i < statusText.length; ++i) { + const c = statusText.charCodeAt(i); + if (!(c === 9 || c >= 32 && c <= 126 || c >= 128 && c <= 255)) { + return false; + } + } + return true; + } + function isTokenChar(c) { + return !(c >= 127 || c <= 32 || c === "(" || c === ")" || c === "<" || c === ">" || c === "@" || c === "," || c === ";" || c === ":" || c === "\\" || c === '"' || c === "/" || c === "[" || c === "]" || c === "?" || c === "=" || c === "{" || c === "}"); + } + function isValidHTTPToken(characters) { + if (!characters || typeof characters !== "string") { + return false; + } + for (let i = 0; i < characters.length; ++i) { + const c = characters.charCodeAt(i); + if (c > 127 || !isTokenChar(c)) { + return false; + } + } + return true; + } + function isValidHeaderName(potentialValue) { + if (potentialValue.length === 0) { + return false; + } + for (const char of potentialValue) { + if (!isValidHTTPToken(char)) { + return false; + } + } + return true; + } + function isValidHeaderValue(potentialValue) { + if (potentialValue.startsWith(" ") || potentialValue.startsWith(" ") || potentialValue.endsWith(" ") || potentialValue.endsWith(" ")) { + return false; + } + if (potentialValue.includes("\0") || potentialValue.includes("\r") || potentialValue.includes("\n")) { + return false; + } + return true; + } + function setRequestReferrerPolicyOnRedirect(request, actualResponse) { + const policy = ""; + if (policy !== "") { + request.referrerPolicy = policy; + } + } + function crossOriginResourcePolicyCheck() { + return "allowed"; + } + function corsCheck() { + return "success"; + } + function TAOCheck() { + return "success"; + } + function appendFetchMetadata(httpRequest) { + let header = null; + header = httpRequest.mode; + httpRequest.headersList.set("sec-fetch-mode", header); + } + function appendRequestOriginHeader(request) { + let serializedOrigin = request.origin; + if (request.responseTainting === "cors" || request.mode === "websocket") { + if (serializedOrigin) { + request.headersList.append("Origin", serializedOrigin); + } + } else if (request.method !== "GET" && request.method !== "HEAD") { + switch (request.referrerPolicy) { + case "no-referrer": + serializedOrigin = null; + break; + case "no-referrer-when-downgrade": + case "strict-origin": + case "strict-origin-when-cross-origin": + if (/^https:/.test(request.origin) && !/^https:/.test(requestCurrentURL(request))) { + serializedOrigin = null; + } + break; + case "same-origin": + if (!sameOrigin(request, requestCurrentURL(request))) { + serializedOrigin = null; + } + break; + default: + } + if (serializedOrigin) { + request.headersList.append("Origin", serializedOrigin); + } + } + } + function coarsenedSharedCurrentTime(crossOriginIsolatedCapability) { + return performance2.now(); + } + function createOpaqueTimingInfo(timingInfo) { + return { + startTime: timingInfo.startTime ?? 0, + redirectStartTime: 0, + redirectEndTime: 0, + postRedirectStartTime: timingInfo.startTime ?? 0, + finalServiceWorkerStartTime: 0, + finalNetworkResponseStartTime: 0, + finalNetworkRequestStartTime: 0, + endTime: 0, + encodedBodySize: 0, + decodedBodySize: 0, + finalConnectionTimingInfo: null + }; + } + function makePolicyContainer() { + return {}; + } + function clonePolicyContainer() { + return {}; + } + function determineRequestsReferrer(request) { + const policy = request.referrerPolicy; + if (policy == null || policy === "" || policy === "no-referrer") { + return "no-referrer"; + } + const environment = request.client; + let referrerSource = null; + if (request.referrer === "client") { + if (request.client?.globalObject?.constructor?.name === "Window") { + const origin = environment.globalObject.self?.origin ?? environment.globalObject.location?.origin; + if (origin == null || origin === "null") + return "no-referrer"; + referrerSource = new URL(environment.globalObject.location.href); + } else { + if (environment?.globalObject?.location == null) { + return "no-referrer"; + } + referrerSource = new URL(environment.globalObject.location.href); + } + } else if (request.referrer instanceof URL) { + referrerSource = request.referrer; + } else { + return "no-referrer"; + } + const urlProtocol = referrerSource.protocol; + if (urlProtocol === "about:" || urlProtocol === "data:" || urlProtocol === "blob:") { + return "no-referrer"; + } + let temp; + let referrerOrigin; + const referrerUrl = (temp = stripURLForReferrer(referrerSource)).length > 4096 ? referrerOrigin = stripURLForReferrer(referrerSource, true) : temp; + const areSameOrigin = sameOrigin(request, referrerUrl); + const isNonPotentiallyTrustWorthy = isURLPotentiallyTrustworthy(referrerUrl) && !isURLPotentiallyTrustworthy(request.url); + switch (policy) { + case "origin": + return referrerOrigin != null ? referrerOrigin : stripURLForReferrer(referrerSource, true); + case "unsafe-url": + return referrerUrl; + case "same-origin": + return areSameOrigin ? referrerOrigin : "no-referrer"; + case "origin-when-cross-origin": + return areSameOrigin ? referrerUrl : referrerOrigin; + case "strict-origin-when-cross-origin": + if (areSameOrigin) + return referrerOrigin; + case "strict-origin": + case "no-referrer-when-downgrade": + default: + return isNonPotentiallyTrustWorthy ? "no-referrer" : referrerOrigin; + } + function stripURLForReferrer(url, originOnly = false) { + const urlObject = new URL(url.href); + urlObject.username = ""; + urlObject.password = ""; + urlObject.hash = ""; + return originOnly ? urlObject.origin : urlObject.href; + } + } + function isURLPotentiallyTrustworthy(url) { + if (!(url instanceof URL)) { + return false; + } + if (url.href === "about:blank" || url.href === "about:srcdoc") { + return true; + } + if (url.protocol === "data:") + return true; + if (url.protocol === "file:") + return true; + return isOriginPotentiallyTrustworthy(url.origin); + function isOriginPotentiallyTrustworthy(origin) { + if (origin == null || origin === "null") + return false; + const originAsURL = new URL(origin); + if (originAsURL.protocol === "https:" || originAsURL.protocol === "wss:") { + return true; + } + if (/^127(?:\.[0-9]+){0,2}\.[0-9]+$|^\[(?:0*:)*?:?0*1\]$/.test(originAsURL.hostname) || (originAsURL.hostname === "localhost" || originAsURL.hostname.includes("localhost.")) || originAsURL.hostname.endsWith(".localhost")) { + return true; + } + return false; + } + } + function bytesMatch(bytes, metadataList) { + if (crypto === void 0) { + return true; + } + const parsedMetadata = parseMetadata(metadataList); + if (parsedMetadata === "no metadata") { + return true; + } + if (parsedMetadata.length === 0) { + return true; + } + const metadata = parsedMetadata.sort((c, d) => d.algo.localeCompare(c.algo)); + for (const item of metadata) { + const algorithm = item.algo; + const expectedValue = item.hash; + const actualValue = crypto.createHash(algorithm).update(bytes).digest("base64"); + if (actualValue === expectedValue) { + return true; + } + } + return false; + } + var parseHashWithOptions = /((?sha256|sha384|sha512)-(?[A-z0-9+/]{1}.*={1,2}))( +[\x21-\x7e]?)?/i; + function parseMetadata(metadata) { + const result = []; + let empty = true; + const supportedHashes = crypto.getHashes(); + for (const token of metadata.split(" ")) { + empty = false; + const parsedToken = parseHashWithOptions.exec(token); + if (parsedToken === null || parsedToken.groups === void 0) { + continue; + } + const algorithm = parsedToken.groups.algo; + if (supportedHashes.includes(algorithm.toLowerCase())) { + result.push(parsedToken.groups); + } + } + if (empty === true) { + return "no metadata"; + } + return result; + } + function tryUpgradeRequestToAPotentiallyTrustworthyURL(request) { + } + function sameOrigin(A, B) { + if (A.protocol === B.protocol && A.hostname === B.hostname && A.port === B.port) { + return true; + } + return false; + } + function createDeferredPromise() { + let res; + let rej; + const promise = new Promise((resolve, reject) => { + res = resolve; + rej = reject; + }); + return { promise, resolve: res, reject: rej }; + } + function isAborted(fetchParams) { + return fetchParams.controller.state === "aborted"; + } + function isCancelled(fetchParams) { + return fetchParams.controller.state === "aborted" || fetchParams.controller.state === "terminated"; + } + function normalizeMethod(method) { + return /^(DELETE|GET|HEAD|OPTIONS|POST|PUT)$/i.test(method) ? method.toUpperCase() : method; + } + function serializeJavascriptValueToJSONString(value) { + const result = JSON.stringify(value); + if (result === void 0) { + throw new TypeError("Value is not JSON serializable"); + } + assert(typeof result === "string"); + return result; + } + var esIteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]())); + function makeIterator(iterator, name) { + const i = { + next() { + if (Object.getPrototypeOf(this) !== i) { + throw new TypeError(`'next' called on an object that does not implement interface ${name} Iterator.`); + } + return iterator.next(); + }, + [Symbol.toStringTag]: `${name} Iterator` + }; + Object.setPrototypeOf(i, esIteratorPrototype); + return Object.setPrototypeOf({}, i); + } + async function fullyReadBody(body, processBody, processBodyError) { + try { + const chunks = []; + let length = 0; + const reader = body.stream.getReader(); + while (true) { + const { done, value } = await reader.read(); + if (done === true) { + break; + } + assert(isUint8Array(value)); + chunks.push(value); + length += value.byteLength; + } + const fulfilledSteps = (bytes) => queueMicrotask(() => { + processBody(bytes); + }); + fulfilledSteps(Buffer.concat(chunks, length)); + } catch (err) { + queueMicrotask(() => processBodyError(err)); + } + } + var hasOwn = Object.hasOwn || ((dict, key) => Object.prototype.hasOwnProperty.call(dict, key)); + module2.exports = { + isAborted, + isCancelled, + createDeferredPromise, + ReadableStreamFrom, + toUSVString, + tryUpgradeRequestToAPotentiallyTrustworthyURL, + coarsenedSharedCurrentTime, + determineRequestsReferrer, + makePolicyContainer, + clonePolicyContainer, + appendFetchMetadata, + appendRequestOriginHeader, + TAOCheck, + corsCheck, + crossOriginResourcePolicyCheck, + createOpaqueTimingInfo, + setRequestReferrerPolicyOnRedirect, + isValidHTTPToken, + requestBadPort, + requestCurrentURL, + responseURL, + responseLocationURL, + isBlobLike, + isURLPotentiallyTrustworthy, + isValidReasonPhrase, + sameOrigin, + normalizeMethod, + serializeJavascriptValueToJSONString, + makeIterator, + isValidHeaderName, + isValidHeaderValue, + hasOwn, + isErrorLike, + fullyReadBody, + bytesMatch + }; + } +}); + +// lib/fetch/symbols.js +var require_symbols2 = __commonJS({ + "lib/fetch/symbols.js"(exports2, module2) { + "use strict"; + module2.exports = { + kUrl: Symbol("url"), + kHeaders: Symbol("headers"), + kSignal: Symbol("signal"), + kState: Symbol("state"), + kGuard: Symbol("guard"), + kRealm: Symbol("realm") + }; + } +}); + +// lib/fetch/webidl.js +var require_webidl = __commonJS({ + "lib/fetch/webidl.js"(exports2, module2) { + "use strict"; + var { types } = require("util"); + var { hasOwn, toUSVString } = require_util2(); + var webidl = {}; + webidl.converters = {}; + webidl.util = {}; + webidl.errors = {}; + webidl.errors.exception = function(message) { + throw new TypeError(`${message.header}: ${message.message}`); + }; + webidl.errors.conversionFailed = function(context) { + const plural = context.types.length === 1 ? "" : " one of"; + const message = `${context.argument} could not be converted to${plural}: ${context.types.join(", ")}.`; + return webidl.errors.exception({ + header: context.prefix, + message + }); + }; + webidl.errors.invalidArgument = function(context) { + return webidl.errors.exception({ + header: context.prefix, + message: `"${context.value}" is an invalid ${context.type}.` + }); + }; + webidl.util.Type = function(V) { + switch (typeof V) { + case "undefined": + return "Undefined"; + case "boolean": + return "Boolean"; + case "string": + return "String"; + case "symbol": + return "Symbol"; + case "number": + return "Number"; + case "bigint": + return "BigInt"; + case "function": + case "object": { + if (V === null) { + return "Null"; + } + return "Object"; + } + } + }; + webidl.util.ConvertToInt = function(V, bitLength, signedness, opts = {}) { + let upperBound; + let lowerBound; + if (bitLength === 64) { + upperBound = Math.pow(2, 53) - 1; + if (signedness === "unsigned") { + lowerBound = 0; + } else { + lowerBound = Math.pow(-2, 53) + 1; + } + } else if (signedness === "unsigned") { + lowerBound = 0; + upperBound = Math.pow(2, bitLength) - 1; + } else { + lowerBound = Math.pow(-2, bitLength) - 1; + upperBound = Math.pow(2, bitLength - 1) - 1; + } + let x = Number(V); + if (Object.is(-0, x)) { + x = 0; + } + if (opts.enforceRange === true) { + if (Number.isNaN(x) || x === Number.POSITIVE_INFINITY || x === Number.NEGATIVE_INFINITY) { + webidl.errors.exception({ + header: "Integer conversion", + message: `Could not convert ${V} to an integer.` + }); + } + x = webidl.util.IntegerPart(x); + if (x < lowerBound || x > upperBound) { + webidl.errors.exception({ + header: "Integer conversion", + message: `Value must be between ${lowerBound}-${upperBound}, got ${x}.` + }); + } + return x; + } + if (!Number.isNaN(x) && opts.clamp === true) { + x = Math.min(Math.max(x, lowerBound), upperBound); + if (Math.floor(x) % 2 === 0) { + x = Math.floor(x); + } else { + x = Math.ceil(x); + } + return x; + } + if (Number.isNaN(x) || Object.is(0, x) || x === Number.POSITIVE_INFINITY || x === Number.NEGATIVE_INFINITY) { + return 0; + } + x = webidl.util.IntegerPart(x); + x = x % Math.pow(2, bitLength); + if (signedness === "signed" && x >= Math.pow(2, bitLength) - 1) { + return x - Math.pow(2, bitLength); + } + return x; + }; + webidl.util.IntegerPart = function(n) { + const r = Math.floor(Math.abs(n)); + if (n < 0) { + return -1 * r; + } + return r; + }; + webidl.sequenceConverter = function(converter) { + return (V) => { + if (webidl.util.Type(V) !== "Object") { + webidl.errors.exception({ + header: "Sequence", + message: `Value of type ${webidl.util.Type(V)} is not an Object.` + }); + } + const method = V?.[Symbol.iterator]?.(); + const seq = []; + if (method === void 0 || typeof method.next !== "function") { + webidl.errors.exception({ + header: "Sequence", + message: "Object is not an iterator." + }); + } + while (true) { + const { done, value } = method.next(); + if (done) { + break; + } + seq.push(converter(value)); + } + return seq; + }; + }; + webidl.recordConverter = function(keyConverter, valueConverter) { + return (V) => { + const record = {}; + const type = webidl.util.Type(V); + if (type === "Undefined" || type === "Null") { + return record; + } + if (type !== "Object") { + webidl.errors.exception({ + header: "Record", + message: `Expected ${V} to be an Object type.` + }); + } + for (let [key, value] of Object.entries(V)) { + key = keyConverter(key); + value = valueConverter(value); + record[key] = value; + } + return record; + }; + }; + webidl.interfaceConverter = function(i) { + return (V, opts = {}) => { + if (opts.strict !== false && !(V instanceof i)) { + webidl.errors.exception({ + header: i.name, + message: `Expected ${V} to be an instance of ${i.name}.` + }); + } + return V; + }; + }; + webidl.dictionaryConverter = function(converters) { + return (dictionary) => { + const type = webidl.util.Type(dictionary); + const dict = {}; + if (type !== "Null" && type !== "Undefined" && type !== "Object") { + webidl.errors.exception({ + header: "Dictionary", + message: `Expected ${dictionary} to be one of: Null, Undefined, Object.` + }); + } + for (const options of converters) { + const { key, defaultValue, required, converter } = options; + if (required === true) { + if (!hasOwn(dictionary, key)) { + webidl.errors.exception({ + header: "Dictionary", + message: `Missing required key "${key}".` + }); + } + } + let value = dictionary[key]; + const hasDefault = hasOwn(options, "defaultValue"); + if (hasDefault && value !== null) { + value = value ?? defaultValue; + } + if (required || hasDefault || value !== void 0) { + value = converter(value); + if (options.allowedValues && !options.allowedValues.includes(value)) { + webidl.errors.exception({ + header: "Dictionary", + message: `${value} is not an accepted type. Expected one of ${options.allowedValues.join(", ")}.` + }); + } + dict[key] = value; + } + } + return dict; + }; + }; + webidl.nullableConverter = function(converter) { + return (V) => { + if (V === null) { + return V; + } + return converter(V); + }; + }; + webidl.converters.DOMString = function(V, opts = {}) { + if (V === null && opts.legacyNullToEmptyString) { + return ""; + } + if (typeof V === "symbol") { + throw new TypeError("Could not convert argument of type symbol to string."); + } + return String(V); + }; + webidl.converters.ByteString = function(V) { + const x = webidl.converters.DOMString(V); + for (let index = 0; index < x.length; index++) { + const charCode = x.charCodeAt(index); + if (charCode > 255) { + throw new TypeError(`Cannot convert argument to a ByteString because the character atindex ${index} has a value of ${charCode} which is greater than 255.`); + } + } + return x; + }; + webidl.converters.USVString = toUSVString; webidl.converters.boolean = function(V) { const x = Boolean(V); return x; @@ -1347,623 +5525,219 @@ var require_webidl = __commonJS({ message: "SharedArrayBuffer is not allowed." }); } - return V; - }; - webidl.converters.DataView = function(V, opts = {}) { - if (webidl.util.Type(V) !== "Object" || !types.isDataView(V)) { - webidl.errors.exception({ - header: "DataView", - message: "Object is not a DataView." - }); - } - if (opts.allowShared === false && types.isSharedArrayBuffer(V.buffer)) { - webidl.errors.exception({ - header: "ArrayBuffer", - message: "SharedArrayBuffer is not allowed." - }); - } - return V; - }; - webidl.converters.BufferSource = function(V, opts = {}) { - if (types.isAnyArrayBuffer(V)) { - return webidl.converters.ArrayBuffer(V, opts); - } - if (types.isTypedArray(V)) { - return webidl.converters.TypedArray(V, V.constructor); - } - if (types.isDataView(V)) { - return webidl.converters.DataView(V, opts); - } - throw new TypeError(`Could not convert ${V} to a BufferSource.`); - }; - webidl.converters["sequence"] = webidl.sequenceConverter(webidl.converters.ByteString); - webidl.converters["sequence>"] = webidl.sequenceConverter(webidl.converters["sequence"]); - webidl.converters["record"] = webidl.recordConverter(webidl.converters.ByteString, webidl.converters.ByteString); - module2.exports = { - webidl - }; - } -}); - -// lib/fetch/file.js -var require_file = __commonJS({ - "lib/fetch/file.js"(exports2, module2) { - "use strict"; - var { Blob } = require("buffer"); - var { types } = require("util"); - var { kState } = require_symbols2(); - var { isBlobLike } = require_util2(); - var { webidl } = require_webidl(); - var File = class extends Blob { - constructor(fileBits, fileName, options = {}) { - if (arguments.length < 2) { - throw new TypeError("2 arguments required"); - } - fileBits = webidl.converters["sequence"](fileBits); - fileName = webidl.converters.USVString(fileName); - options = webidl.converters.FilePropertyBag(options); - const n = fileName; - const d = options.lastModified; - super(processBlobParts(fileBits, options), { type: options.type }); - this[kState] = { - name: n, - lastModified: d - }; - } - get name() { - if (!(this instanceof File)) { - throw new TypeError("Illegal invocation"); - } - return this[kState].name; - } - get lastModified() { - if (!(this instanceof File)) { - throw new TypeError("Illegal invocation"); - } - return this[kState].lastModified; - } - get [Symbol.toStringTag]() { - return this.constructor.name; - } - }; - var FileLike = class { - constructor(blobLike, fileName, options = {}) { - const n = fileName; - const t = options.type; - const d = options.lastModified ?? Date.now(); - this[kState] = { - blobLike, - name: n, - type: t, - lastModified: d - }; - } - stream(...args) { - if (!(this instanceof FileLike)) { - throw new TypeError("Illegal invocation"); - } - return this[kState].blobLike.stream(...args); - } - arrayBuffer(...args) { - if (!(this instanceof FileLike)) { - throw new TypeError("Illegal invocation"); - } - return this[kState].blobLike.arrayBuffer(...args); - } - slice(...args) { - if (!(this instanceof FileLike)) { - throw new TypeError("Illegal invocation"); - } - return this[kState].blobLike.slice(...args); - } - text(...args) { - if (!(this instanceof FileLike)) { - throw new TypeError("Illegal invocation"); - } - return this[kState].blobLike.text(...args); - } - get size() { - if (!(this instanceof FileLike)) { - throw new TypeError("Illegal invocation"); - } - return this[kState].blobLike.size; - } - get type() { - if (!(this instanceof FileLike)) { - throw new TypeError("Illegal invocation"); - } - return this[kState].blobLike.type; - } - get name() { - if (!(this instanceof FileLike)) { - throw new TypeError("Illegal invocation"); - } - return this[kState].name; - } - get lastModified() { - if (!(this instanceof FileLike)) { - throw new TypeError("Illegal invocation"); - } - return this[kState].lastModified; - } - get [Symbol.toStringTag]() { - return "File"; - } + return V; }; - webidl.converters.Blob = webidl.interfaceConverter(Blob); - webidl.converters.BlobPart = function(V, opts) { - if (webidl.util.Type(V) === "Object") { - if (isBlobLike(V)) { - return webidl.converters.Blob(V, { strict: false }); - } - return webidl.converters.BufferSource(V, opts); - } else { - return webidl.converters.USVString(V, opts); + webidl.converters.DataView = function(V, opts = {}) { + if (webidl.util.Type(V) !== "Object" || !types.isDataView(V)) { + webidl.errors.exception({ + header: "DataView", + message: "Object is not a DataView." + }); } + if (opts.allowShared === false && types.isSharedArrayBuffer(V.buffer)) { + webidl.errors.exception({ + header: "ArrayBuffer", + message: "SharedArrayBuffer is not allowed." + }); + } + return V; }; - webidl.converters["sequence"] = webidl.sequenceConverter(webidl.converters.BlobPart); - webidl.converters.FilePropertyBag = webidl.dictionaryConverter([ - { - key: "lastModified", - converter: webidl.converters["long long"], - get defaultValue() { - return Date.now(); - } - }, - { - key: "type", - converter: webidl.converters.DOMString, - defaultValue: "" - }, - { - key: "endings", - converter: (value) => { - value = webidl.converters.DOMString(value); - value = value.toLowerCase(); - if (value !== "native") { - value = "transparent"; - } - return value; - }, - defaultValue: "transparent" + webidl.converters.BufferSource = function(V, opts = {}) { + if (types.isAnyArrayBuffer(V)) { + return webidl.converters.ArrayBuffer(V, opts); } - ]); - function processBlobParts(parts, options) { - const bytes = []; - for (const element of parts) { - if (typeof element === "string") { - let s = element; - if (options.endings === "native") { - s = convertLineEndingsNative(s); - } - bytes.push(new TextEncoder().encode(s)); - } else if (types.isAnyArrayBuffer(element) || types.isTypedArray(element)) { - if (!element.buffer) { - bytes.push(new Uint8Array(element)); - } else { - bytes.push(new Uint8Array(element.buffer, element.byteOffset, element.byteLength)); - } - } else if (isBlobLike(element)) { - bytes.push(element); - } + if (types.isTypedArray(V)) { + return webidl.converters.TypedArray(V, V.constructor); } - return bytes; - } - function convertLineEndingsNative(s) { - let nativeLineEnding = "\n"; - if (process.platform === "win32") { - nativeLineEnding = "\r\n"; + if (types.isDataView(V)) { + return webidl.converters.DataView(V, opts); } - return s.replace(/\r?\n/g, nativeLineEnding); - } - module2.exports = { File, FileLike }; + throw new TypeError(`Could not convert ${V} to a BufferSource.`); + }; + webidl.converters["sequence"] = webidl.sequenceConverter(webidl.converters.ByteString); + webidl.converters["sequence>"] = webidl.sequenceConverter(webidl.converters["sequence"]); + webidl.converters["record"] = webidl.recordConverter(webidl.converters.ByteString, webidl.converters.ByteString); + module2.exports = { + webidl + }; } }); -// lib/fetch/util.js -var require_util2 = __commonJS({ - "lib/fetch/util.js"(exports2, module2) { +// lib/fetch/file.js +var require_file = __commonJS({ + "lib/fetch/file.js"(exports2, module2) { "use strict"; - var { redirectStatus } = require_constants(); - var { performance: performance2 } = require("perf_hooks"); - var { isBlobLike, toUSVString, ReadableStreamFrom } = require_util(); - var assert = require("assert"); - var { isUint8Array } = require("util/types"); - var File; - var crypto; - try { - crypto = require("crypto"); - } catch { - } - var badPorts = [ - "1", - "7", - "9", - "11", - "13", - "15", - "17", - "19", - "20", - "21", - "22", - "23", - "25", - "37", - "42", - "43", - "53", - "69", - "77", - "79", - "87", - "95", - "101", - "102", - "103", - "104", - "109", - "110", - "111", - "113", - "115", - "117", - "119", - "123", - "135", - "137", - "139", - "143", - "161", - "179", - "389", - "427", - "465", - "512", - "513", - "514", - "515", - "526", - "530", - "531", - "532", - "540", - "548", - "554", - "556", - "563", - "587", - "601", - "636", - "989", - "990", - "993", - "995", - "1719", - "1720", - "1723", - "2049", - "3659", - "4045", - "5060", - "5061", - "6000", - "6566", - "6665", - "6666", - "6667", - "6668", - "6669", - "6697", - "10080" - ]; - function responseURL(response) { - const urlList = response.urlList; - const length = urlList.length; - return length === 0 ? null : urlList[length - 1].toString(); - } - function responseLocationURL(response, requestFragment) { - if (!redirectStatus.includes(response.status)) { - return null; - } - let location = response.headersList.get("location"); - location = location ? new URL(location, responseURL(response)) : null; - if (location && !location.hash) { - location.hash = requestFragment; - } - return location; - } - function requestCurrentURL(request) { - return request.urlList[request.urlList.length - 1]; - } - function requestBadPort(request) { - const url = requestCurrentURL(request); - if (/^https?:/.test(url.protocol) && badPorts.includes(url.port)) { - return "blocked"; - } - return "allowed"; - } - function isFileLike(object) { - if (!File) { - File = require_file().File; - } - return object instanceof File || object && (typeof object.stream === "function" || typeof object.arrayBuffer === "function") && /^(File)$/.test(object[Symbol.toStringTag]); - } - function isErrorLike(object) { - return object instanceof Error || (object?.constructor?.name === "Error" || object?.constructor?.name === "DOMException"); - } - function isValidReasonPhrase(statusText) { - for (let i = 0; i < statusText.length; ++i) { - const c = statusText.charCodeAt(i); - if (!(c === 9 || c >= 32 && c <= 126 || c >= 128 && c <= 255)) { - return false; - } - } - return true; - } - function isTokenChar(c) { - return !(c >= 127 || c <= 32 || c === "(" || c === ")" || c === "<" || c === ">" || c === "@" || c === "," || c === ";" || c === ":" || c === "\\" || c === '"' || c === "/" || c === "[" || c === "]" || c === "?" || c === "=" || c === "{" || c === "}"); - } - function isValidHTTPToken(characters) { - if (!characters || typeof characters !== "string") { - return false; - } - for (let i = 0; i < characters.length; ++i) { - const c = characters.charCodeAt(i); - if (c > 127 || !isTokenChar(c)) { - return false; + var { Blob } = require("buffer"); + var { types } = require("util"); + var { kState } = require_symbols2(); + var { isBlobLike } = require_util2(); + var { webidl } = require_webidl(); + var File = class extends Blob { + constructor(fileBits, fileName, options = {}) { + if (arguments.length < 2) { + throw new TypeError("2 arguments required"); } + fileBits = webidl.converters["sequence"](fileBits); + fileName = webidl.converters.USVString(fileName); + options = webidl.converters.FilePropertyBag(options); + const n = fileName; + const d = options.lastModified; + super(processBlobParts(fileBits, options), { type: options.type }); + this[kState] = { + name: n, + lastModified: d + }; } - return true; - } - function isValidHeaderName(potentialValue) { - if (potentialValue.length === 0) { - return false; - } - for (const char of potentialValue) { - if (!isValidHTTPToken(char)) { - return false; + get name() { + if (!(this instanceof File)) { + throw new TypeError("Illegal invocation"); } + return this[kState].name; } - return true; - } - function isValidHeaderValue(potentialValue) { - if (potentialValue.startsWith(" ") || potentialValue.startsWith(" ") || potentialValue.endsWith(" ") || potentialValue.endsWith(" ")) { - return false; + get lastModified() { + if (!(this instanceof File)) { + throw new TypeError("Illegal invocation"); + } + return this[kState].lastModified; } - if (potentialValue.includes("\0") || potentialValue.includes("\r") || potentialValue.includes("\n")) { - return false; + get [Symbol.toStringTag]() { + return this.constructor.name; } - return true; - } - function setRequestReferrerPolicyOnRedirect(request, actualResponse) { - const policy = ""; - if (policy !== "") { - request.referrerPolicy = policy; + }; + var FileLike = class { + constructor(blobLike, fileName, options = {}) { + const n = fileName; + const t = options.type; + const d = options.lastModified ?? Date.now(); + this[kState] = { + blobLike, + name: n, + type: t, + lastModified: d + }; } - } - function crossOriginResourcePolicyCheck() { - return "allowed"; - } - function corsCheck() { - return "success"; - } - function TAOCheck() { - return "success"; - } - function appendFetchMetadata(httpRequest) { - let header = null; - header = httpRequest.mode; - httpRequest.headersList.set("sec-fetch-mode", header); - } - function appendRequestOriginHeader(request) { - let serializedOrigin = request.origin; - if (request.responseTainting === "cors" || request.mode === "websocket") { - if (serializedOrigin) { - request.headersList.append("Origin", serializedOrigin); - } - } else if (request.method !== "GET" && request.method !== "HEAD") { - switch (request.referrerPolicy) { - case "no-referrer": - serializedOrigin = null; - break; - case "no-referrer-when-downgrade": - case "strict-origin": - case "strict-origin-when-cross-origin": - if (/^https:/.test(request.origin) && !/^https:/.test(requestCurrentURL(request))) { - serializedOrigin = null; - } - break; - case "same-origin": - if (!sameOrigin(request, requestCurrentURL(request))) { - serializedOrigin = null; - } - break; - default: - } - if (serializedOrigin) { - request.headersList.append("Origin", serializedOrigin); + stream(...args) { + if (!(this instanceof FileLike)) { + throw new TypeError("Illegal invocation"); } + return this[kState].blobLike.stream(...args); } - } - function coarsenedSharedCurrentTime(crossOriginIsolatedCapability) { - return performance2.now(); - } - function createOpaqueTimingInfo(timingInfo) { - return { - startTime: timingInfo.startTime ?? 0, - redirectStartTime: 0, - redirectEndTime: 0, - postRedirectStartTime: timingInfo.startTime ?? 0, - finalServiceWorkerStartTime: 0, - finalNetworkResponseStartTime: 0, - finalNetworkRequestStartTime: 0, - endTime: 0, - encodedBodySize: 0, - decodedBodySize: 0, - finalConnectionTimingInfo: null - }; - } - function makePolicyContainer() { - return {}; - } - function clonePolicyContainer() { - return {}; - } - function determineRequestsReferrer(request) { - return "no-referrer"; - } - function bytesMatch(bytes, metadataList) { - if (crypto === void 0) { - return true; + arrayBuffer(...args) { + if (!(this instanceof FileLike)) { + throw new TypeError("Illegal invocation"); + } + return this[kState].blobLike.arrayBuffer(...args); } - const parsedMetadata = parseMetadata(metadataList); - if (parsedMetadata === "no metadata") { - return true; + slice(...args) { + if (!(this instanceof FileLike)) { + throw new TypeError("Illegal invocation"); + } + return this[kState].blobLike.slice(...args); } - if (parsedMetadata.length === 0) { - return true; + text(...args) { + if (!(this instanceof FileLike)) { + throw new TypeError("Illegal invocation"); + } + return this[kState].blobLike.text(...args); } - const metadata = parsedMetadata.sort((c, d) => d.algo.localeCompare(c.algo)); - for (const item of metadata) { - const algorithm = item.algo; - const expectedValue = item.hash; - const actualValue = crypto.createHash(algorithm).update(bytes).digest("base64"); - if (actualValue === expectedValue) { - return true; + get size() { + if (!(this instanceof FileLike)) { + throw new TypeError("Illegal invocation"); } + return this[kState].blobLike.size; } - return false; - } - var parseHashWithOptions = /((?sha256|sha384|sha512)-(?[A-z0-9+/]{1}.*={1,2}))( +[\x21-\x7e]?)?/i; - function parseMetadata(metadata) { - const result = []; - let empty = true; - const supportedHashes = crypto.getHashes(); - for (const token of metadata.split(" ")) { - empty = false; - const parsedToken = parseHashWithOptions.exec(token); - if (parsedToken === null || parsedToken.groups === void 0) { - continue; + get type() { + if (!(this instanceof FileLike)) { + throw new TypeError("Illegal invocation"); } - const algorithm = parsedToken.groups.algo; - if (supportedHashes.includes(algorithm.toLowerCase())) { - result.push(parsedToken.groups); + return this[kState].blobLike.type; + } + get name() { + if (!(this instanceof FileLike)) { + throw new TypeError("Illegal invocation"); } + return this[kState].name; } - if (empty === true) { - return "no metadata"; + get lastModified() { + if (!(this instanceof FileLike)) { + throw new TypeError("Illegal invocation"); + } + return this[kState].lastModified; } - return result; - } - function tryUpgradeRequestToAPotentiallyTrustworthyURL(request) { - } - function sameOrigin(A, B) { - if (A.protocol === B.protocol && A.hostname === B.hostname && A.port === B.port) { - return true; + get [Symbol.toStringTag]() { + return "File"; } - return false; - } - function createDeferredPromise() { - let res; - let rej; - const promise = new Promise((resolve, reject) => { - res = resolve; - rej = reject; - }); - return { promise, resolve: res, reject: rej }; - } - function isAborted(fetchParams) { - return fetchParams.controller.state === "aborted"; - } - function isCancelled(fetchParams) { - return fetchParams.controller.state === "aborted" || fetchParams.controller.state === "terminated"; - } - function normalizeMethod(method) { - return /^(DELETE|GET|HEAD|OPTIONS|POST|PUT)$/i.test(method) ? method.toUpperCase() : method; - } - function serializeJavascriptValueToJSONString(value) { - const result = JSON.stringify(value); - if (result === void 0) { - throw new TypeError("Value is not JSON serializable"); + }; + webidl.converters.Blob = webidl.interfaceConverter(Blob); + webidl.converters.BlobPart = function(V, opts) { + if (webidl.util.Type(V) === "Object") { + if (isBlobLike(V)) { + return webidl.converters.Blob(V, { strict: false }); + } + return webidl.converters.BufferSource(V, opts); + } else { + return webidl.converters.USVString(V, opts); } - assert(typeof result === "string"); - return result; - } - var esIteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]())); - function makeIterator(iterator, name) { - const i = { - next() { - if (Object.getPrototypeOf(this) !== i) { - throw new TypeError(`'next' called on an object that does not implement interface ${name} Iterator.`); + }; + webidl.converters["sequence"] = webidl.sequenceConverter(webidl.converters.BlobPart); + webidl.converters.FilePropertyBag = webidl.dictionaryConverter([ + { + key: "lastModified", + converter: webidl.converters["long long"], + get defaultValue() { + return Date.now(); + } + }, + { + key: "type", + converter: webidl.converters.DOMString, + defaultValue: "" + }, + { + key: "endings", + converter: (value) => { + value = webidl.converters.DOMString(value); + value = value.toLowerCase(); + if (value !== "native") { + value = "transparent"; } - return iterator.next(); + return value; }, - [Symbol.toStringTag]: `${name} Iterator` - }; - Object.setPrototypeOf(i, esIteratorPrototype); - return Object.setPrototypeOf({}, i); - } - async function fullyReadBody(body, processBody, processBodyError) { - try { - const chunks = []; - let length = 0; - const reader = body.stream.getReader(); - while (true) { - const { done, value } = await reader.read(); - if (done === true) { - break; + defaultValue: "transparent" + } + ]); + function processBlobParts(parts, options) { + const bytes = []; + for (const element of parts) { + if (typeof element === "string") { + let s = element; + if (options.endings === "native") { + s = convertLineEndingsNative(s); } - assert(isUint8Array(value)); - chunks.push(value); - length += value.byteLength; + bytes.push(new TextEncoder().encode(s)); + } else if (types.isAnyArrayBuffer(element) || types.isTypedArray(element)) { + if (!element.buffer) { + bytes.push(new Uint8Array(element)); + } else { + bytes.push(new Uint8Array(element.buffer, element.byteOffset, element.byteLength)); + } + } else if (isBlobLike(element)) { + bytes.push(element); } - const fulfilledSteps = (bytes) => queueMicrotask(() => { - processBody(bytes); - }); - fulfilledSteps(Buffer.concat(chunks, length)); - } catch (err) { - queueMicrotask(() => processBodyError(err)); } + return bytes; } - var hasOwn = Object.hasOwn || ((dict, key) => Object.prototype.hasOwnProperty.call(dict, key)); - module2.exports = { - isAborted, - isCancelled, - createDeferredPromise, - ReadableStreamFrom, - toUSVString, - tryUpgradeRequestToAPotentiallyTrustworthyURL, - coarsenedSharedCurrentTime, - determineRequestsReferrer, - makePolicyContainer, - clonePolicyContainer, - appendFetchMetadata, - appendRequestOriginHeader, - TAOCheck, - corsCheck, - crossOriginResourcePolicyCheck, - createOpaqueTimingInfo, - setRequestReferrerPolicyOnRedirect, - isValidHTTPToken, - requestBadPort, - requestCurrentURL, - responseURL, - responseLocationURL, - isBlobLike, - isFileLike, - isValidReasonPhrase, - sameOrigin, - normalizeMethod, - serializeJavascriptValueToJSONString, - makeIterator, - isValidHeaderName, - isValidHeaderValue, - hasOwn, - isErrorLike, - fullyReadBody, - bytesMatch - }; + function convertLineEndingsNative(s) { + let nativeLineEnding = "\n"; + if (process.platform === "win32") { + nativeLineEnding = "\r\n"; + } + return s.replace(/\r?\n/g, nativeLineEnding); + } + function isFileLike(object) { + return object instanceof File || object && (typeof object.stream === "function" || typeof object.arrayBuffer === "function") && object[Symbol.toStringTag] === "File"; + } + module2.exports = { File, FileLike, isFileLike }; } }); @@ -1971,9 +5745,9 @@ var require_util2 = __commonJS({ var require_formdata = __commonJS({ "lib/fetch/formdata.js"(exports2, module2) { "use strict"; - var { isBlobLike, isFileLike, toUSVString, makeIterator } = require_util2(); + var { isBlobLike, toUSVString, makeIterator } = require_util2(); var { kState } = require_symbols2(); - var { File, FileLike } = require_file(); + var { File, FileLike, isFileLike } = require_file(); var { webidl } = require_webidl(); var { Blob } = require("buffer"); var _FormData = class { @@ -2150,17 +5924,19 @@ var require_formdata = __commonJS({ var require_body = __commonJS({ "lib/fetch/body.js"(exports2, module2) { "use strict"; + var Busboy = require_lib(); var util = require_util(); var { ReadableStreamFrom, toUSVString, isBlobLike } = require_util2(); var { FormData } = require_formdata(); var { kState } = require_symbols2(); var { webidl } = require_webidl(); + var { DOMException } = require_constants(); var { Blob } = require("buffer"); var { kBodyUsed } = require_symbols(); var assert = require("assert"); - var { NotSupportedError } = require_errors(); var { isErrored } = require_util(); var { isUint8Array, isArrayBuffer } = require("util/types"); + var { File } = require_file(); var ReadableStream; async function* blobGen(blob) { yield* blob.stream(); @@ -2272,8 +6048,8 @@ Content-Type: ${value.type || "application/octet-stream"}\r ReadableStream = require("stream/web").ReadableStream; } if (object instanceof ReadableStream) { - assert(!util.isDisturbed(object), "disturbed"); - assert(!object.locked, "locked"); + assert(!util.isDisturbed(object), "The body has already been consumed."); + assert(!object.locked, "The stream is locked."); } return extractBody(object, keepalive); } @@ -2293,22 +6069,28 @@ Content-Type: ${value.type || "application/octet-stream"}\r } else { const stream = body.stream; if (util.isDisturbed(stream)) { - throw new TypeError("disturbed"); + throw new TypeError("The body has already been consumed."); } if (stream.locked) { - throw new TypeError("locked"); + throw new TypeError("The stream is locked."); } stream[kBodyUsed] = true; yield* stream; } } } + function throwIfAborted(state) { + if (state.aborted) { + throw new DOMException("The operation was aborted.", "AbortError"); + } + } function bodyMixinMethods(instance) { const methods = { async blob() { if (!(this instanceof instance)) { throw new TypeError("Illegal invocation"); } + throwIfAborted(this[kState]); const chunks = []; for await (const chunk of consumeBody(this[kState].body)) { if (!isUint8Array(chunk)) { @@ -2322,6 +6104,7 @@ Content-Type: ${value.type || "application/octet-stream"}\r if (!(this instanceof instance)) { throw new TypeError("Illegal invocation"); } + throwIfAborted(this[kState]); const contentLength = this.headers.get("content-length"); const encoded = this.headers.has("content-encoding"); if (!encoded && contentLength) { @@ -2357,6 +6140,7 @@ Content-Type: ${value.type || "application/octet-stream"}\r if (!(this instanceof instance)) { throw new TypeError("Illegal invocation"); } + throwIfAborted(this[kState]); let result = ""; const textDecoder = new TextDecoder(); for await (const chunk of consumeBody(this[kState].body)) { @@ -2372,15 +6156,63 @@ Content-Type: ${value.type || "application/octet-stream"}\r if (!(this instanceof instance)) { throw new TypeError("Illegal invocation"); } + throwIfAborted(this[kState]); return JSON.parse(await this.text()); }, async formData() { if (!(this instanceof instance)) { throw new TypeError("Illegal invocation"); } + throwIfAborted(this[kState]); const contentType = this.headers.get("Content-Type"); if (/multipart\/form-data/.test(contentType)) { - throw new NotSupportedError("multipart/form-data not supported"); + const headers = {}; + for (const [key, value] of this.headers) + headers[key.toLowerCase()] = value; + const responseFormData = new FormData(); + let busboy; + try { + busboy = Busboy({ headers }); + } catch (err) { + throw Object.assign(new TypeError(), { cause: err }); + } + busboy.on("field", (name, value) => { + responseFormData.append(name, value); + }); + busboy.on("file", (name, value, info) => { + const { filename, encoding, mimeType } = info; + const chunks = []; + if (encoding.toLowerCase() === "base64") { + let base64chunk = ""; + value.on("data", (chunk) => { + base64chunk += chunk.toString().replace(/[\r\n]/gm, ""); + const end = base64chunk.length - base64chunk.length % 4; + chunks.push(Buffer.from(base64chunk.slice(0, end), "base64")); + base64chunk = base64chunk.slice(end); + }); + value.on("end", () => { + chunks.push(Buffer.from(base64chunk, "base64")); + responseFormData.append(name, new File(chunks, filename, { type: mimeType })); + }); + } else { + value.on("data", (chunk) => { + chunks.push(chunk); + }); + value.on("end", () => { + responseFormData.append(name, new File(chunks, filename, { type: mimeType })); + }); + } + }); + const busboyResolve = new Promise((resolve, reject) => { + busboy.on("finish", resolve); + busboy.on("error", (err) => reject(err)); + }); + if (this.body !== null) + for await (const chunk of consumeBody(this[kState].body)) + busboy.write(chunk); + busboy.end(); + await busboyResolve; + return responseFormData; } else if (/application\/x-www-form-urlencoded/.test(contentType)) { let entries; try { @@ -2403,9 +6235,11 @@ Content-Type: ${value.type || "application/octet-stream"}\r } return formData; } else { + await Promise.resolve(); + throwIfAborted(this[kState]); webidl.errors.exception({ header: `${instance.name}.formData`, - value: "Could not parse content as FormData." + message: "Could not parse content as FormData." }); } } @@ -2626,203 +6460,64 @@ var require_request = __commonJS({ } onComplete(trailers) { assert(!this.aborted); - this.completed = true; - if (channels.trailers.hasSubscribers) { - channels.trailers.publish({ request: this, trailers }); - } - return this[kHandler].onComplete(trailers); - } - onError(error) { - if (channels.error.hasSubscribers) { - channels.error.publish({ request: this, error }); - } - if (this.aborted) { - return; - } - this.aborted = true; - return this[kHandler].onError(error); - } - addHeader(key, value) { - processHeader(this, key, value); - return this; - } - }; - function processHeader(request, key, val) { - if (val && typeof val === "object") { - throw new InvalidArgumentError(`invalid ${key} header`); - } else if (val === void 0) { - return; - } - if (request.host === null && key.length === 4 && key.toLowerCase() === "host") { - request.host = val; - } else if (request.contentLength === null && key.length === 14 && key.toLowerCase() === "content-length") { - request.contentLength = parseInt(val, 10); - if (!Number.isFinite(request.contentLength)) { - throw new InvalidArgumentError("invalid content-length header"); - } - } else if (request.contentType === null && key.length === 12 && key.toLowerCase() === "content-type" && headerCharRegex.exec(val) === null) { - request.contentType = val; - request.headers += `${key}: ${val}\r -`; - } else if (key.length === 17 && key.toLowerCase() === "transfer-encoding") { - throw new InvalidArgumentError("invalid transfer-encoding header"); - } else if (key.length === 10 && key.toLowerCase() === "connection") { - throw new InvalidArgumentError("invalid connection header"); - } else if (key.length === 10 && key.toLowerCase() === "keep-alive") { - throw new InvalidArgumentError("invalid keep-alive header"); - } else if (key.length === 7 && key.toLowerCase() === "upgrade") { - throw new InvalidArgumentError("invalid upgrade header"); - } else if (key.length === 6 && key.toLowerCase() === "expect") { - throw new NotSupportedError("expect header not supported"); - } else if (tokenRegExp.exec(key) === null) { - throw new InvalidArgumentError("invalid header key"); - } else if (headerCharRegex.exec(val) !== null) { - throw new InvalidArgumentError(`invalid ${key} header`); - } else { - request.headers += `${key}: ${val}\r -`; - } - } - module2.exports = Request; - } -}); - -// lib/handler/redirect.js -var require_redirect = __commonJS({ - "lib/handler/redirect.js"(exports2, module2) { - "use strict"; - var util = require_util(); - var { kBodyUsed } = require_symbols(); - var assert = require("assert"); - var { InvalidArgumentError } = require_errors(); - var EE = require("events"); - var redirectableStatusCodes = [300, 301, 302, 303, 307, 308]; - var kBody = Symbol("body"); - var BodyAsyncIterable = class { - constructor(body) { - this[kBody] = body; - this[kBodyUsed] = false; - } - async *[Symbol.asyncIterator]() { - assert(!this[kBodyUsed], "disturbed"); - this[kBodyUsed] = true; - yield* this[kBody]; - } - }; - var RedirectHandler = class { - constructor(dispatcher, maxRedirections, opts, handler) { - if (maxRedirections != null && (!Number.isInteger(maxRedirections) || maxRedirections < 0)) { - throw new InvalidArgumentError("maxRedirections must be a positive number"); - } - util.validateHandler(handler, opts.method, opts.upgrade); - this.dispatcher = dispatcher; - this.location = null; - this.abort = null; - this.opts = { ...opts, maxRedirections: 0 }; - this.maxRedirections = maxRedirections; - this.handler = handler; - this.history = []; - if (util.isStream(this.opts.body)) { - if (util.bodyLength(this.opts.body) === 0) { - this.opts.body.on("data", function() { - assert(false); - }); - } - if (typeof this.opts.body.readableDidRead !== "boolean") { - this.opts.body[kBodyUsed] = false; - EE.prototype.on.call(this.opts.body, "data", function() { - this[kBodyUsed] = true; - }); - } - } else if (this.opts.body && typeof this.opts.body.pipeTo === "function") { - this.opts.body = new BodyAsyncIterable(this.opts.body); - } else if (this.opts.body && typeof this.opts.body !== "string" && !ArrayBuffer.isView(this.opts.body) && util.isIterable(this.opts.body)) { - this.opts.body = new BodyAsyncIterable(this.opts.body); - } - } - onConnect(abort) { - this.abort = abort; - this.handler.onConnect(abort, { history: this.history }); - } - onUpgrade(statusCode, headers, socket) { - this.handler.onUpgrade(statusCode, headers, socket); - } - onError(error) { - this.handler.onError(error); - } - onHeaders(statusCode, headers, resume, statusText) { - this.location = this.history.length >= this.maxRedirections || util.isDisturbed(this.opts.body) ? null : parseLocation(statusCode, headers); - if (this.opts.origin) { - this.history.push(new URL(this.opts.path, this.opts.origin)); - } - if (!this.location) { - return this.handler.onHeaders(statusCode, headers, resume, statusText); - } - const { origin, pathname, search } = util.parseURL(new URL(this.location, this.opts.origin && new URL(this.opts.path, this.opts.origin))); - const path = search ? `${pathname}${search}` : pathname; - this.opts.headers = cleanRequestHeaders(this.opts.headers, statusCode === 303, this.opts.origin !== origin); - this.opts.path = path; - this.opts.origin = origin; - this.opts.maxRedirections = 0; - if (statusCode === 303 && this.opts.method !== "HEAD") { - this.opts.method = "GET"; - this.opts.body = null; - } - } - onData(chunk) { - if (this.location) { - } else { - return this.handler.onData(chunk); - } - } - onComplete(trailers) { - if (this.location) { - this.location = null; - this.abort = null; - this.dispatcher.dispatch(this.opts, this); - } else { - this.handler.onComplete(trailers); + this.completed = true; + if (channels.trailers.hasSubscribers) { + channels.trailers.publish({ request: this, trailers }); } + return this[kHandler].onComplete(trailers); } - onBodySent(chunk) { - if (this.handler.onBodySent) { - this.handler.onBodySent(chunk); + onError(error) { + if (channels.error.hasSubscribers) { + channels.error.publish({ request: this, error }); + } + if (this.aborted) { + return; } + this.aborted = true; + return this[kHandler].onError(error); } - }; - function parseLocation(statusCode, headers) { - if (redirectableStatusCodes.indexOf(statusCode) === -1) { - return null; + addHeader(key, value) { + processHeader(this, key, value); + return this; } - for (let i = 0; i < headers.length; i += 2) { - if (headers[i].toString().toLowerCase() === "location") { - return headers[i + 1]; - } + }; + function processHeader(request, key, val) { + if (val && typeof val === "object") { + throw new InvalidArgumentError(`invalid ${key} header`); + } else if (val === void 0) { + return; } - } - function shouldRemoveHeader(header, removeContent, unknownOrigin) { - return header.length === 4 && header.toString().toLowerCase() === "host" || removeContent && header.toString().toLowerCase().indexOf("content-") === 0 || unknownOrigin && header.length === 13 && header.toString().toLowerCase() === "authorization" || unknownOrigin && header.length === 6 && header.toString().toLowerCase() === "cookie"; - } - function cleanRequestHeaders(headers, removeContent, unknownOrigin) { - const ret = []; - if (Array.isArray(headers)) { - for (let i = 0; i < headers.length; i += 2) { - if (!shouldRemoveHeader(headers[i], removeContent, unknownOrigin)) { - ret.push(headers[i], headers[i + 1]); - } - } - } else if (headers && typeof headers === "object") { - for (const key of Object.keys(headers)) { - if (!shouldRemoveHeader(key, removeContent, unknownOrigin)) { - ret.push(key, headers[key]); - } + if (request.host === null && key.length === 4 && key.toLowerCase() === "host") { + request.host = val; + } else if (request.contentLength === null && key.length === 14 && key.toLowerCase() === "content-length") { + request.contentLength = parseInt(val, 10); + if (!Number.isFinite(request.contentLength)) { + throw new InvalidArgumentError("invalid content-length header"); } + } else if (request.contentType === null && key.length === 12 && key.toLowerCase() === "content-type" && headerCharRegex.exec(val) === null) { + request.contentType = val; + request.headers += `${key}: ${val}\r +`; + } else if (key.length === 17 && key.toLowerCase() === "transfer-encoding") { + throw new InvalidArgumentError("invalid transfer-encoding header"); + } else if (key.length === 10 && key.toLowerCase() === "connection") { + throw new InvalidArgumentError("invalid connection header"); + } else if (key.length === 10 && key.toLowerCase() === "keep-alive") { + throw new InvalidArgumentError("invalid keep-alive header"); + } else if (key.length === 7 && key.toLowerCase() === "upgrade") { + throw new InvalidArgumentError("invalid upgrade header"); + } else if (key.length === 6 && key.toLowerCase() === "expect") { + throw new NotSupportedError("expect header not supported"); + } else if (tokenRegExp.exec(key) === null) { + throw new InvalidArgumentError("invalid header key"); + } else if (headerCharRegex.exec(val) !== null) { + throw new InvalidArgumentError(`invalid ${key} header`); } else { - assert(headers == null, "headers must be an object or an array"); + request.headers += `${key}: ${val}\r +`; } - return ret; } - module2.exports = RedirectHandler; + module2.exports = Request; } }); @@ -2934,7 +6629,7 @@ var require_connect = __commonJS({ }); // lib/llhttp/utils.js -var require_utils = __commonJS({ +var require_utils2 = __commonJS({ "lib/llhttp/utils.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); @@ -2959,7 +6654,7 @@ var require_constants2 = __commonJS({ "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); exports2.SPECIAL_HEADERS = exports2.HEADER_STATE = exports2.MINOR = exports2.MAJOR = exports2.CONNECTION_TOKEN_CHARS = exports2.HEADER_CHARS = exports2.TOKEN = exports2.STRICT_TOKEN = exports2.HEX = exports2.URL_CHAR = exports2.STRICT_URL_CHAR = exports2.USERINFO_CHARS = exports2.MARK = exports2.ALPHANUM = exports2.NUM = exports2.HEX_MAP = exports2.NUM_MAP = exports2.ALPHA = exports2.FINISH = exports2.H_METHOD_MAP = exports2.METHOD_MAP = exports2.METHODS_RTSP = exports2.METHODS_ICE = exports2.METHODS_HTTP = exports2.METHODS = exports2.LENIENT_FLAGS = exports2.FLAGS = exports2.TYPE = exports2.ERROR = void 0; - var utils_1 = require_utils(); + var utils_1 = require_utils2(); var ERROR; (function(ERROR2) { ERROR2[ERROR2["OK"] = 0] = "OK"; @@ -3272,6 +6967,167 @@ var require_constants2 = __commonJS({ } }); +// lib/handler/RedirectHandler.js +var require_RedirectHandler = __commonJS({ + "lib/handler/RedirectHandler.js"(exports2, module2) { + "use strict"; + var util = require_util(); + var { kBodyUsed } = require_symbols(); + var assert = require("assert"); + var { InvalidArgumentError } = require_errors(); + var EE = require("events"); + var redirectableStatusCodes = [300, 301, 302, 303, 307, 308]; + var kBody = Symbol("body"); + var BodyAsyncIterable = class { + constructor(body) { + this[kBody] = body; + this[kBodyUsed] = false; + } + async *[Symbol.asyncIterator]() { + assert(!this[kBodyUsed], "disturbed"); + this[kBodyUsed] = true; + yield* this[kBody]; + } + }; + var RedirectHandler = class { + constructor(dispatch, maxRedirections, opts, handler) { + if (maxRedirections != null && (!Number.isInteger(maxRedirections) || maxRedirections < 0)) { + throw new InvalidArgumentError("maxRedirections must be a positive number"); + } + util.validateHandler(handler, opts.method, opts.upgrade); + this.dispatch = dispatch; + this.location = null; + this.abort = null; + this.opts = { ...opts, maxRedirections: 0 }; + this.maxRedirections = maxRedirections; + this.handler = handler; + this.history = []; + if (util.isStream(this.opts.body)) { + if (util.bodyLength(this.opts.body) === 0) { + this.opts.body.on("data", function() { + assert(false); + }); + } + if (typeof this.opts.body.readableDidRead !== "boolean") { + this.opts.body[kBodyUsed] = false; + EE.prototype.on.call(this.opts.body, "data", function() { + this[kBodyUsed] = true; + }); + } + } else if (this.opts.body && typeof this.opts.body.pipeTo === "function") { + this.opts.body = new BodyAsyncIterable(this.opts.body); + } else if (this.opts.body && typeof this.opts.body !== "string" && !ArrayBuffer.isView(this.opts.body) && util.isIterable(this.opts.body)) { + this.opts.body = new BodyAsyncIterable(this.opts.body); + } + } + onConnect(abort) { + this.abort = abort; + this.handler.onConnect(abort, { history: this.history }); + } + onUpgrade(statusCode, headers, socket) { + this.handler.onUpgrade(statusCode, headers, socket); + } + onError(error) { + this.handler.onError(error); + } + onHeaders(statusCode, headers, resume, statusText) { + this.location = this.history.length >= this.maxRedirections || util.isDisturbed(this.opts.body) ? null : parseLocation(statusCode, headers); + if (this.opts.origin) { + this.history.push(new URL(this.opts.path, this.opts.origin)); + } + if (!this.location) { + return this.handler.onHeaders(statusCode, headers, resume, statusText); + } + const { origin, pathname, search } = util.parseURL(new URL(this.location, this.opts.origin && new URL(this.opts.path, this.opts.origin))); + const path = search ? `${pathname}${search}` : pathname; + this.opts.headers = cleanRequestHeaders(this.opts.headers, statusCode === 303, this.opts.origin !== origin); + this.opts.path = path; + this.opts.origin = origin; + this.opts.maxRedirections = 0; + if (statusCode === 303 && this.opts.method !== "HEAD") { + this.opts.method = "GET"; + this.opts.body = null; + } + } + onData(chunk) { + if (this.location) { + } else { + return this.handler.onData(chunk); + } + } + onComplete(trailers) { + if (this.location) { + this.location = null; + this.abort = null; + this.dispatch(this.opts, this); + } else { + this.handler.onComplete(trailers); + } + } + onBodySent(chunk) { + if (this.handler.onBodySent) { + this.handler.onBodySent(chunk); + } + } + }; + function parseLocation(statusCode, headers) { + if (redirectableStatusCodes.indexOf(statusCode) === -1) { + return null; + } + for (let i = 0; i < headers.length; i += 2) { + if (headers[i].toString().toLowerCase() === "location") { + return headers[i + 1]; + } + } + } + function shouldRemoveHeader(header, removeContent, unknownOrigin) { + return header.length === 4 && header.toString().toLowerCase() === "host" || removeContent && header.toString().toLowerCase().indexOf("content-") === 0 || unknownOrigin && header.length === 13 && header.toString().toLowerCase() === "authorization" || unknownOrigin && header.length === 6 && header.toString().toLowerCase() === "cookie"; + } + function cleanRequestHeaders(headers, removeContent, unknownOrigin) { + const ret = []; + if (Array.isArray(headers)) { + for (let i = 0; i < headers.length; i += 2) { + if (!shouldRemoveHeader(headers[i], removeContent, unknownOrigin)) { + ret.push(headers[i], headers[i + 1]); + } + } + } else if (headers && typeof headers === "object") { + for (const key of Object.keys(headers)) { + if (!shouldRemoveHeader(key, removeContent, unknownOrigin)) { + ret.push(key, headers[key]); + } + } + } else { + assert(headers == null, "headers must be an object or an array"); + } + return ret; + } + module2.exports = RedirectHandler; + } +}); + +// lib/interceptor/redirectInterceptor.js +var require_redirectInterceptor = __commonJS({ + "lib/interceptor/redirectInterceptor.js"(exports2, module2) { + "use strict"; + var RedirectHandler = require_RedirectHandler(); + function createRedirectInterceptor({ maxRedirections: defaultMaxRedirections }) { + return (dispatch) => { + return function Intercept(opts, handler) { + const { maxRedirections = defaultMaxRedirections } = opts; + if (!maxRedirections) { + return dispatch(opts, handler); + } + const redirectHandler = new RedirectHandler(dispatch, maxRedirections, opts, handler); + opts = { ...opts, maxRedirections: 0 }; + return dispatch(opts, redirectHandler); + }; + }; + } + module2.exports = createRedirectInterceptor; + } +}); + // lib/llhttp/llhttp.wasm.js var require_llhttp_wasm = __commonJS({ "lib/llhttp/llhttp.wasm.js"(exports2, module2) { @@ -3295,7 +7151,6 @@ var require_client = __commonJS({ var util = require_util(); var Request = require_request(); var DispatcherBase = require_dispatcher_base(); - var RedirectHandler = require_redirect(); var { RequestContentLengthMismatchError, ResponseContentLengthMismatchError, @@ -3348,7 +7203,8 @@ var require_client = __commonJS({ kCounter, kClose, kDestroy, - kDispatch + kDispatch, + kInterceptors } = require_symbols(); var kClosedResolve = Symbol("kClosedResolve"); var channels = {}; @@ -3366,6 +7222,7 @@ var require_client = __commonJS({ } var Client = class extends DispatcherBase { constructor(url, { + interceptors, maxHeaderSize, headersTimeout, socketTimeout, @@ -3445,6 +7302,7 @@ var require_client = __commonJS({ ...connect2 }); } + this[kInterceptors] = interceptors && interceptors.Client && Array.isArray(interceptors.Client) ? interceptors.Client : [createRedirectInterceptor({ maxRedirections })]; this[kUrl] = util.parseOrigin(url); this[kConnector] = connect2; this[kSocket] = null; @@ -3497,10 +7355,6 @@ var require_client = __commonJS({ this.once("connect", cb); } [kDispatch](opts, handler) { - const { maxRedirections = this[kMaxRedirections] } = opts; - if (maxRedirections) { - handler = new RedirectHandler(this, maxRedirections, opts, handler); - } const origin = opts.origin || this[kUrl].origin; const request = new Request(origin, opts, handler); this[kQueue].push(request); @@ -3549,6 +7403,7 @@ var require_client = __commonJS({ } }; var constants = require_constants2(); + var createRedirectInterceptor = require_redirectInterceptor(); var EMPTY_BUF = Buffer.alloc(0); async function lazyllhttp() { const llhttpWasmData = process.env.JEST_WORKER_ID ? require_llhttp_wasm() : void 0; @@ -4608,7 +8463,7 @@ var require_pool = __commonJS({ InvalidArgumentError } = require_errors(); var util = require_util(); - var { kUrl } = require_symbols(); + var { kUrl, kInterceptors } = require_symbols(); var buildConnector = require_connect(); var kOptions = Symbol("options"); var kConnections = Symbol("connections"); @@ -4646,9 +8501,11 @@ var require_pool = __commonJS({ ...connect }); } + this[kInterceptors] = options.interceptors && options.interceptors.Pool && Array.isArray(options.interceptors.Pool) ? options.interceptors.Pool : []; this[kConnections] = connections || null; this[kUrl] = util.parseOrigin(origin); this[kOptions] = { ...util.deepClone(options), connect }; + this[kOptions].interceptors = options.interceptors ? { ...options.interceptors } : void 0; this[kFactory] = factory; } [kGetDispatcher]() { @@ -4706,12 +8563,12 @@ var require_agent = __commonJS({ "lib/agent.js"(exports2, module2) { "use strict"; var { InvalidArgumentError } = require_errors(); - var { kClients, kRunning, kClose, kDestroy, kDispatch } = require_symbols(); + var { kClients, kRunning, kClose, kDestroy, kDispatch, kInterceptors } = require_symbols(); var DispatcherBase = require_dispatcher_base(); var Pool = require_pool(); var Client = require_client(); var util = require_util(); - var RedirectHandler = require_redirect(); + var createRedirectInterceptor = require_redirectInterceptor(); var { WeakRef, FinalizationRegistry } = require_dispatcher_weakref()(); var kOnConnect = Symbol("onConnect"); var kOnDisconnect = Symbol("onDisconnect"); @@ -4739,7 +8596,9 @@ var require_agent = __commonJS({ if (connect && typeof connect !== "function") { connect = { ...connect }; } + this[kInterceptors] = options.interceptors && options.interceptors.Agent && Array.isArray(options.interceptors.Agent) ? options.interceptors.Agent : [createRedirectInterceptor({ maxRedirections })]; this[kOptions] = { ...util.deepClone(options), connect }; + this[kOptions].interceptors = options.interceptors ? { ...options.interceptors } : void 0; this[kMaxRedirections] = maxRedirections; this[kFactory] = factory; this[kClients] = /* @__PURE__ */ new Map(); @@ -4787,11 +8646,6 @@ var require_agent = __commonJS({ this[kClients].set(key, new WeakRef(dispatcher)); this[kFinalizer].register(dispatcher, key); } - const { maxRedirections = this[kMaxRedirections] } = opts; - if (maxRedirections != null && maxRedirections !== 0) { - opts = { ...opts, maxRedirections: 0 }; - handler = new RedirectHandler(this, maxRedirections, opts, handler); - } return dispatcher.dispatch(opts, handler); } async [kClose]() { @@ -5082,7 +8936,9 @@ var require_headers = __commonJS({ return this[kHeadersList].set(name, value); } get [kHeadersSortedMap]() { - this[kHeadersList][kHeadersSortedMap] ??= new Map([...this[kHeadersList]].sort((a, b) => a[0] < b[0] ? -1 : 1)); + if (!this[kHeadersList][kHeadersSortedMap]) { + this[kHeadersList][kHeadersSortedMap] = new Map([...this[kHeadersList]].sort((a, b) => a[0] < b[0] ? -1 : 1)); + } return this[kHeadersList][kHeadersSortedMap]; } keys() { @@ -5157,6 +9013,45 @@ var require_headers = __commonJS({ } }); +// lib/fetch/global.js +var require_global2 = __commonJS({ + "lib/fetch/global.js"(exports2, module2) { + "use strict"; + var globalOrigin = Symbol.for("undici.globalOrigin.1"); + function getGlobalOrigin() { + return globalThis[globalOrigin]; + } + function setGlobalOrigin(newOrigin) { + if (newOrigin !== void 0 && typeof newOrigin !== "string" && !(newOrigin instanceof URL)) { + throw new Error("Invalid base url"); + } + if (newOrigin === void 0) { + Object.defineProperty(globalThis, globalOrigin, { + value: void 0, + writable: true, + enumerable: false, + configurable: false + }); + return; + } + const parsedURL = new URL(newOrigin); + if (parsedURL.protocol !== "http:" && parsedURL.protocol !== "https:") { + throw new TypeError(`Only http & https urls are allowed, received ${parsedURL.protocol}`); + } + Object.defineProperty(globalThis, globalOrigin, { + value: parsedURL, + writable: true, + enumerable: false, + configurable: false + }); + } + module2.exports = { + getGlobalOrigin, + setGlobalOrigin + }; + } +}); + // lib/fetch/response.js var require_response = __commonJS({ "lib/fetch/response.js"(exports2, module2) { @@ -5182,6 +9077,7 @@ var require_response = __commonJS({ var { kState, kHeaders, kGuard, kRealm } = require_symbols2(); var { webidl } = require_webidl(); var { FormData } = require_formdata(); + var { getGlobalOrigin } = require_global2(); var { kHeadersList } = require_symbols(); var assert = require("assert"); var { types } = require("util"); @@ -5223,7 +9119,7 @@ var require_response = __commonJS({ status = webidl.converters["unsigned short"](status); let parsedURL; try { - parsedURL = new URL(url); + parsedURL = new URL(url, getGlobalOrigin()); } catch (err) { throw Object.assign(new TypeError("Failed to parse URL from " + url), { cause: err @@ -5470,13 +9366,13 @@ var require_response = __commonJS({ return webidl.converters.USVString(V); } if (isBlobLike(V)) { - return webidl.converters.Blob(V); + return webidl.converters.Blob(V, { strict: false }); } if (types.isAnyArrayBuffer(V) || types.isTypedArray(V) || types.isDataView(V)) { return webidl.converters.BufferSource(V); } - if (V instanceof FormData) { - return webidl.converters.FormData(V); + if (util.isFormDataLike(V)) { + return webidl.converters.FormData(V, { strict: false }); } if (V instanceof URLSearchParams) { return webidl.converters.URLSearchParams(V); @@ -5543,6 +9439,7 @@ var require_request2 = __commonJS({ var { kEnumerableProperty } = util; var { kHeaders, kSignal, kState, kGuard, kRealm } = require_symbols2(); var { webidl } = require_webidl(); + var { getGlobalOrigin } = require_global2(); var { kHeadersList } = require_symbols(); var assert = require("assert"); var TransformStream; @@ -5560,7 +9457,11 @@ var require_request2 = __commonJS({ } input = webidl.converters.RequestInfo(input); init = webidl.converters.RequestInit(init); - this[kRealm] = { settingsObject: {} }; + this[kRealm] = { + settingsObject: { + baseUrl: getGlobalOrigin() + } + }; let request = null; let fallbackMode = null; const baseUrl = this[kRealm].settingsObject.baseUrl; @@ -6073,6 +9974,7 @@ var require_dataURL = __commonJS({ "lib/fetch/dataURL.js"(exports2, module2) { var assert = require("assert"); var { atob: atob2 } = require("buffer"); + var { isValidHTTPToken } = require_util2(); var encoder = new TextEncoder(); function dataURLProcessor(dataURL) { assert(dataURL.protocol === "data:"); @@ -6201,11 +10103,11 @@ var require_dataURL = __commonJS({ } let parameterValue = null; if (input[position.position] === '"') { - parameterValue = collectAnHTTPQuotedString(input, position); + parameterValue = collectAnHTTPQuotedString(input, position, true); collectASequenceOfCodePoints((char) => char !== ";", input, position); } else { parameterValue = collectASequenceOfCodePoints((char) => char !== ";", input, position); - parameterValue = parameterValue.trim(); + parameterValue = parameterValue.trimEnd(); if (parameterValue.length === 0) { continue; } @@ -6263,13 +10165,31 @@ var require_dataURL = __commonJS({ } return input.slice(positionStart, position.position); } + function serializeAMimeType(mimeType) { + assert(mimeType !== "failure"); + const { type, subtype, parameters } = mimeType; + let serialization = `${type}/${subtype}`; + for (let [name, value] of parameters.entries()) { + serialization += ";"; + serialization += name; + serialization += "="; + if (!isValidHTTPToken(value)) { + value = value.replace(/(\\|")/g, "\\$1"); + value = '"' + value; + value += '"'; + } + serialization += value; + } + return serialization; + } module2.exports = { dataURLProcessor, URLSerializer, collectASequenceOfCodePoints, stringPercentDecode, parseMIMEType, - collectAnHTTPQuotedString + collectAnHTTPQuotedString, + serializeAMimeType }; } }); @@ -6328,7 +10248,7 @@ var require_fetch = __commonJS({ var EE = require("events"); var { Readable, pipeline } = require("stream"); var { isErrored, isReadable } = require_util(); - var { dataURLProcessor } = require_dataURL(); + var { dataURLProcessor, serializeAMimeType } = require_dataURL(); var { TransformStream } = require("stream/web"); var resolveObjectURL; var ReadableStream; @@ -6670,24 +10590,11 @@ var require_fetch = __commonJS({ if (dataURLStruct === "failure") { return makeNetworkError("failed to fetch the data URL"); } - const { mimeType } = dataURLStruct; - let contentType = `${mimeType.type}/${mimeType.subtype}`; - const contentTypeParams = []; - if (mimeType.parameters.size > 0) { - contentType += ";"; - } - for (const [key, value] of mimeType.parameters) { - if (value.length > 0) { - contentTypeParams.push(`${key}=${value}`); - } else { - contentTypeParams.push(key); - } - } - contentType += contentTypeParams.join(","); + const mimeType = serializeAMimeType(dataURLStruct.mimeType); return makeResponse({ statusText: "OK", headersList: [ - ["content-type", contentType] + ["content-type", mimeType] ], body: extractBody(dataURLStruct.body)[0] }); @@ -6773,7 +10680,9 @@ var require_fetch = __commonJS({ return makeNetworkError("blocked"); } if (redirectStatus.includes(actualResponse.status)) { - fetchParams.controller.connection.destroy(); + if (request.redirect !== "manual") { + fetchParams.controller.connection.destroy(); + } if (request.redirect === "error") { response = makeNetworkError("unexpected redirect"); } else if (request.redirect === "manual") { @@ -7138,7 +11047,8 @@ var require_fetch = __commonJS({ } this.body = new Readable({ read: resume }); const decoders = []; - if (request.method !== "HEAD" && request.method !== "CONNECT" && !nullBodyStatus.includes(status) && !(request.redirect === "follow" && location)) { + const willFollow = request.redirect === "follow" && location && redirectStatus.includes(status); + if (request.method !== "HEAD" && request.method !== "CONNECT" && !nullBodyStatus.includes(status) && !willFollow) { for (const coding of codings) { if (/(x-)?gzip/.test(coding)) { decoders.push(zlib.createGunzip()); @@ -7188,16 +11098,26 @@ var require_fetch = __commonJS({ })); } } - module2.exports = fetch2; + module2.exports = { + fetch: fetch2, + Fetch, + fetching, + finalizeAndReportTiming + }; } }); // index-fetch.js var { getGlobalDispatcher } = require_global(); -var fetchImpl = require_fetch(); +var fetchImpl = require_fetch().fetch; module.exports.fetch = async function fetch(resource) { const dispatcher = arguments[1] && arguments[1].dispatcher || getGlobalDispatcher(); - return fetchImpl.apply(dispatcher, arguments); + try { + return await fetchImpl.apply(dispatcher, arguments); + } catch (err) { + Error.captureStackTrace(err, this); + throw err; + } }; module.exports.FormData = require_formdata().FormData; module.exports.Headers = require_headers().Headers; diff --git a/deps/v8/.gitignore b/deps/v8/.gitignore index b8d1d934bcf610..489f0b64f9b1ef 100644 --- a/deps/v8/.gitignore +++ b/deps/v8/.gitignore @@ -30,6 +30,7 @@ .cproject .gclient_entries .gdb_history +.idea .jslint-cache .landmines .project diff --git a/deps/v8/.gn b/deps/v8/.gn index a691fa339b0430..8edbdf34c51807 100644 --- a/deps/v8/.gn +++ b/deps/v8/.gn @@ -19,10 +19,17 @@ no_check_targets = [ "//:cppgc_base", "//:v8_internal_headers", "//src/inspector:inspector", - "//test/cctest:cctest_sources", + "//test/cctest:cctest_sources", # 15 errors + "//test/unittests:inspector_unittests_sources", # 2 errors "//third_party/icu:*", ] +default_args = { + # Overwrite default args declared in the Fuchsia sdk + # Please maintain this in sync with Chromium version in src/.gn + fuchsia_target_api_level = 9 +} + # These are the list of GN files that run exec_script. This whitelist exists # to force additional review for new uses of exec_script, which is strongly # discouraged except for gypi_to_gn calls. diff --git a/deps/v8/.mailmap b/deps/v8/.mailmap index 7f2e3b9e5e9098..780084c4138133 100644 --- a/deps/v8/.mailmap +++ b/deps/v8/.mailmap @@ -11,4 +11,6 @@ # Please keep the list sorted. Clemens Backes Clemens Hammacher +Jakob Linke +Jakob Linke Timothy Gu diff --git a/deps/v8/.vpython3 b/deps/v8/.vpython3 index d1842bb8dd2eda..50fab3bb519735 100644 --- a/deps/v8/.vpython3 +++ b/deps/v8/.vpython3 @@ -69,3 +69,8 @@ wheel: < name: "infra/python/wheels/numpy/${vpython_platform}" version: "version:1.2x.supported.1" > + +wheel: < + name: "infra/python/wheels/protobuf-py3" + version: "version:3.19.3" +> diff --git a/deps/v8/AUTHORS b/deps/v8/AUTHORS index e095f812659d7a..fd10aa4e360309 100644 --- a/deps/v8/AUTHORS +++ b/deps/v8/AUTHORS @@ -42,6 +42,7 @@ Cloudflare, Inc. <*@cloudflare.com> Julia Computing, Inc. <*@juliacomputing.com> CodeWeavers, Inc. <*@codeweavers.com> Alibaba, Inc. <*@alibaba-inc.com> +SiFive, Inc. <*@sifive.com> Aaron Bieber Aaron O'Mullan @@ -99,21 +100,25 @@ David Sanders Deepak Mohan Deon Dior Derek Tu +Divy Srivastava Dominic Chen Dominic Farolini Douglas Crosher Dusan Milosavljevic +Eden Wang Eric Rannaud Erich Ocean Evan Lucas Fedor Indutny Felix Geisendörfer +Feng Yu Filipe David Manana Franziska Hinkelmann Gao Sheng Geoffrey Garside Gergely Nagy Gilang Mentari Hamidy +Giovanny Gutierrez Gus Caplan Gwang Yoon Hwang Haichuan Wang @@ -122,6 +127,7 @@ Harshal Nandigramwar Harshil Jain Henrique Ferreiro Hirofumi Mako +Hisham Muhammad Honggyu Kim Huáng Jùnliàng HyeockJin Kim @@ -194,6 +200,7 @@ Paolo Giarrusso Patrick Gansterer Paul Lind Pavel Medvedev +Pedro Falcato Peng Fei Peng Wu Peng-Yu Chen @@ -201,6 +208,7 @@ Peter Rybin Peter Varga Peter Wong PhistucK +Pierrick Bouvier Rafal Krypa Raul Tambre Ray Glover diff --git a/deps/v8/BUILD.bazel b/deps/v8/BUILD.bazel index 279e3e55a0dca8..4e89f90e7e31e1 100644 --- a/deps/v8/BUILD.bazel +++ b/deps/v8/BUILD.bazel @@ -68,6 +68,7 @@ load(":bazel/v8-non-pointer-compression.bzl", "v8_binary_non_pointer_compression # cppgc_enable_caged_heap # cppgc_enable_check_assignments_in_prefinalizers # cppgc_enable_object_names +# cppgc_enable_pointer_compression # cppgc_enable_verify_heap # cppgc_enable_young_generation # v8_enable_zone_compression @@ -323,7 +324,6 @@ v8_config( }, defines = [ "GOOGLE3", - "CHROMIUM_ZLIB_NO_CHROMECONF", "ENABLE_DEBUGGER_SUPPORT", "V8_ADVANCED_BIGINT_ALGORITHMS", "V8_CONCURRENT_MARKING", @@ -457,15 +457,19 @@ filegroup( "include/cppgc/garbage-collected.h", "include/cppgc/heap.h", "include/cppgc/heap-consistency.h", + "include/cppgc/heap-handle.h", "include/cppgc/heap-state.h", "include/cppgc/heap-statistics.h", "include/cppgc/internal/api-constants.h", "include/cppgc/internal/atomic-entry-flag.h", + "include/cppgc/internal/base-page-handle.h", "include/cppgc/internal/caged-heap-local-data.h", + "include/cppgc/internal/caged-heap.h", "include/cppgc/internal/compiler-specific.h", "include/cppgc/internal/finalizer-trait.h", "include/cppgc/internal/gc-info.h", "include/cppgc/internal/logging.h", + "include/cppgc/internal/member-storage.h", "include/cppgc/internal/name-trait.h", "include/cppgc/internal/persistent-node.h", "include/cppgc/internal/pointer-policies.h", @@ -579,7 +583,6 @@ filegroup( "src/base/address-region.h", "src/base/atomic-utils.h", "src/base/atomicops.h", - "src/base/atomicops_internals_atomicword_compat.h", "src/base/base-export.h", "src/base/bit-field.h", "src/base/bits-iterator.h", @@ -590,6 +593,7 @@ filegroup( "src/base/bounds.h", "src/base/build_config.h", "src/base/compiler-specific.h", + "src/base/container-utils.h", "src/base/cpu.cc", "src/base/cpu.h", "src/base/debug/stack_trace.cc", @@ -604,7 +608,6 @@ filegroup( "src/base/file-utils.h", "src/base/flags.h", "src/base/free_deleter.h", - "src/base/functional.cc", "src/base/functional.h", "src/base/hashmap-entry.h", "src/base/hashmap.h", @@ -643,6 +646,9 @@ filegroup( "src/base/platform/condition-variable.cc", "src/base/platform/condition-variable.h", "src/base/platform/elapsed-timer.h", + "src/base/platform/memory.h", + "src/base/platform/memory-protection-key.cc", + "src/base/platform/memory-protection-key.h", "src/base/platform/mutex.cc", "src/base/platform/mutex.h", "src/base/platform/platform.h", @@ -659,6 +665,7 @@ filegroup( "src/base/safe_conversions_arm_impl.h", "src/base/safe_conversions_impl.h", "src/base/small-vector.h", + "src/base/string-format.h", "src/base/strings.cc", "src/base/strings.h", "src/base/sys-info.cc", @@ -689,6 +696,7 @@ filegroup( "@v8//bazel/config:is_linux": [ "src/base/debug/stack_trace_posix.cc", "src/base/platform/platform-linux.cc", + "src/base/platform/platform-linux.h", ], "@v8//bazel/config:is_android": [ "src/base/debug/stack_trace_android.cc", @@ -779,7 +787,11 @@ filegroup( "src/builtins/array-slice.tq", "src/builtins/array-some.tq", "src/builtins/array-splice.tq", + "src/builtins/array-to-reversed.tq", + "src/builtins/array-to-sorted.tq", + "src/builtins/array-to-spliced.tq", "src/builtins/array-unshift.tq", + "src/builtins/array-with.tq", "src/builtins/array.tq", "src/builtins/arraybuffer.tq", "src/builtins/base.tq", @@ -878,7 +890,9 @@ filegroup( "src/builtins/typed-array-some.tq", "src/builtins/typed-array-sort.tq", "src/builtins/typed-array-subarray.tq", + "src/builtins/typed-array-to-reversed.tq", "src/builtins/typed-array-values.tq", + "src/builtins/typed-array-with.tq", "src/builtins/typed-array.tq", "src/builtins/weak-ref.tq", "src/ic/handler-configuration.tq", @@ -903,6 +917,7 @@ filegroup( "src/objects/heap-object.tq", "src/objects/js-array-buffer.tq", "src/objects/js-array.tq", + "src/objects/js-atomics-synchronization.tq", "src/objects/js-collection-iterator.tq", "src/objects/js-collection.tq", "src/objects/js-function.tq", @@ -912,7 +927,8 @@ filegroup( "src/objects/js-proxy.tq", "src/objects/js-regexp-string-iterator.tq", "src/objects/js-regexp.tq", - "src/objects/js-shadow-realms.tq", + "src/objects/js-shadow-realm.tq", + "src/objects/js-shared-array.tq", "src/objects/js-struct.tq", "src/objects/js-temporal-objects.tq", "src/objects/js-weak-refs.tq", @@ -1034,6 +1050,15 @@ filegroup( ], ) +# Default setting for v8_enable_pointer_compression when target is x64. +selects.config_setting_group( + name = "is_v8_enable_webassembly_on_non_android_posix_x64", + match_all = [ + ":is_v8_enable_webassembly", + "@v8//bazel/config:is_non_android_posix_x64", + ], +) + filegroup( name = "v8_base_without_compiler_files", srcs = [ @@ -1091,6 +1116,7 @@ filegroup( "src/builtins/builtins-array.cc", "src/builtins/builtins-arraybuffer.cc", "src/builtins/builtins-async-module.cc", + "src/builtins/builtins-atomics-synchronization.cc", "src/builtins/builtins-bigint.cc", "src/builtins/builtins-callsite.cc", "src/builtins/builtins-collections.cc", @@ -1110,8 +1136,9 @@ filegroup( "src/builtins/builtins-promise.h", "src/builtins/builtins-reflect.cc", "src/builtins/builtins-regexp.cc", - "src/builtins/builtins-shadow-realms.cc", + "src/builtins/builtins-shadow-realm.cc", "src/builtins/builtins-sharedarraybuffer.cc", + "src/builtins/builtins-shared-array.cc", "src/builtins/builtins-string.cc", "src/builtins/builtins-struct.cc", "src/builtins/builtins-symbol.cc", @@ -1121,6 +1148,7 @@ filegroup( "src/builtins/builtins-utils-inl.h", "src/builtins/builtins-utils.h", "src/builtins/builtins-weak-refs.cc", + "src/builtins/builtins-web-snapshots.cc", "src/builtins/builtins.cc", "src/builtins/builtins.h", "src/builtins/constants-table-builder.cc", @@ -1133,6 +1161,7 @@ filegroup( "src/codegen/assembler.cc", "src/codegen/assembler.h", "src/codegen/atomic-memory-order.h", + "src/codegen/background-merge-task.h", "src/codegen/bailout-reason.cc", "src/codegen/bailout-reason.h", "src/codegen/callable.h", @@ -1170,6 +1199,8 @@ filegroup( "src/codegen/machine-type.h", "src/codegen/macro-assembler-inl.h", "src/codegen/macro-assembler.h", + "src/codegen/maglev-safepoint-table.cc", + "src/codegen/maglev-safepoint-table.h", "src/codegen/optimized-compilation-info.cc", "src/codegen/optimized-compilation-info.h", "src/codegen/pending-optimization-table.cc", @@ -1183,6 +1214,7 @@ filegroup( "src/codegen/reglist.h", "src/codegen/reloc-info.cc", "src/codegen/reloc-info.h", + "src/codegen/safepoint-table-base.h", "src/codegen/safepoint-table.cc", "src/codegen/safepoint-table.h", "src/codegen/script-details.h", @@ -1191,8 +1223,6 @@ filegroup( "src/codegen/source-position-table.h", "src/codegen/source-position.cc", "src/codegen/source-position.h", - "src/codegen/string-constants.cc", - "src/codegen/string-constants.h", "src/codegen/tick-counter.cc", "src/codegen/tick-counter.h", "src/codegen/tnode.cc", @@ -1203,8 +1233,10 @@ filegroup( "src/codegen/unoptimized-compilation-info.h", "src/common/assert-scope.cc", "src/common/assert-scope.h", - "src/common/allow-deprecated.h", "src/common/checks.h", + "src/common/code-memory-access-inl.h", + "src/common/code-memory-access.cc", + "src/common/code-memory-access.h", "src/common/high-allocation-throughput-scope.h", "src/common/message-template.h", "src/common/operation.h", @@ -1240,6 +1272,8 @@ filegroup( "src/debug/debug.cc", "src/debug/debug.h", "src/debug/interface-types.h", + "src/debug/liveedit-diff.cc", + "src/debug/liveedit-diff.h", "src/debug/liveedit.cc", "src/debug/liveedit.h", "src/deoptimizer/deoptimize-reason.cc", @@ -1356,6 +1390,8 @@ filegroup( "src/handles/maybe-handles.h", "src/handles/persistent-handles.cc", "src/handles/persistent-handles.h", + "src/handles/shared-object-conveyor-handles.cc", + "src/handles/shared-object-conveyor-handles.h", "src/heap/base/active-system-pages.cc", "src/heap/base/active-system-pages.h", "src/heap/allocation-observer.cc", @@ -1410,11 +1446,14 @@ filegroup( "src/heap/free-list-inl.h", "src/heap/free-list.cc", "src/heap/free-list.h", + "src/heap/gc-callbacks.h", "src/heap/gc-idle-time-handler.cc", "src/heap/gc-idle-time-handler.h", "src/heap/gc-tracer.cc", "src/heap/gc-tracer-inl.h", "src/heap/gc-tracer.h", + "src/heap/global-handle-marking-visitor.cc", + "src/heap/global-handle-marking-visitor.h", "src/heap/heap-allocator-inl.h", "src/heap/heap-allocator.cc", "src/heap/heap-allocator.h", @@ -1423,6 +1462,8 @@ filegroup( "src/heap/heap-inl.h", "src/heap/heap-layout-tracer.cc", "src/heap/heap-layout-tracer.h", + "src/heap/heap-verifier.cc", + "src/heap/heap-verifier.h", "src/heap/heap-write-barrier-inl.h", "src/heap/heap-write-barrier.cc", "src/heap/heap-write-barrier.h", @@ -1595,8 +1636,8 @@ filegroup( "src/logging/local-logger.cc", "src/logging/local-logger.h", "src/logging/log-inl.h", - "src/logging/log-utils.cc", - "src/logging/log-utils.h", + "src/logging/log-file.cc", + "src/logging/log-file.h", "src/logging/log.cc", "src/logging/log.h", "src/logging/metrics.cc", @@ -1693,6 +1734,9 @@ filegroup( "src/objects/js-array-buffer.h", "src/objects/js-array-inl.h", "src/objects/js-array.h", + "src/objects/js-atomics-synchronization-inl.h", + "src/objects/js-atomics-synchronization.h", + "src/objects/js-atomics-synchronization.cc", "src/objects/js-collection-inl.h", "src/objects/js-collection-iterator.h", "src/objects/js-collection-iterator-inl.h", @@ -1714,8 +1758,10 @@ filegroup( "src/objects/js-regexp-string-iterator.h", "src/objects/js-regexp.cc", "src/objects/js-regexp.h", - "src/objects/js-shadow-realms.h", - "src/objects/js-shadow-realms-inl.h", + "src/objects/js-shadow-realm.h", + "src/objects/js-shadow-realm-inl.h", + "src/objects/js-shared-array.h", + "src/objects/js-shared-array-inl.h", "src/objects/js-struct.h", "src/objects/js-struct-inl.h", "src/objects/js-temporal-objects.h", @@ -1771,9 +1817,6 @@ filegroup( "src/objects/ordered-hash-table-inl.h", "src/objects/ordered-hash-table.cc", "src/objects/ordered-hash-table.h", - "src/objects/osr-optimized-code-cache-inl.h", - "src/objects/osr-optimized-code-cache.cc", - "src/objects/osr-optimized-code-cache.h", "src/objects/primitive-heap-object-inl.h", "src/objects/primitive-heap-object.h", "src/objects/promise-inl.h", @@ -1803,6 +1846,8 @@ filegroup( "src/objects/shared-function-info-inl.h", "src/objects/shared-function-info.cc", "src/objects/shared-function-info.h", + "src/objects/simd.cc", + "src/objects/simd.h", "src/objects/slots-atomic-inl.h", "src/objects/slots-inl.h", "src/objects/slots.h", @@ -1816,6 +1861,9 @@ filegroup( "src/objects/string-inl.h", "src/objects/string-set-inl.h", "src/objects/string-set.h", + "src/objects/string-forwarding-table-inl.h", + "src/objects/string-forwarding-table.cc", + "src/objects/string-forwarding-table.h", "src/objects/string-table-inl.h", "src/objects/string-table.cc", "src/objects/symbol-table.cc", @@ -1994,6 +2042,7 @@ filegroup( "src/runtime/runtime-shadow-realm.cc", "src/runtime/runtime-strings.cc", "src/runtime/runtime-symbol.cc", + "src/runtime/runtime-temporal.cc", "src/runtime/runtime-test.cc", "src/runtime/runtime-trace.cc", "src/runtime/runtime-typedarray.cc", @@ -2006,6 +2055,8 @@ filegroup( "src/sandbox/external-pointer-table.cc", "src/sandbox/external-pointer-table-inl.h", "src/sandbox/external-pointer-table.h", + "src/sandbox/testing.cc", + "src/sandbox/testing.h", "src/sandbox/sandbox.cc", "src/sandbox/sandbox.h", "src/sandbox/sandboxed-pointer-inl.h", @@ -2047,8 +2098,6 @@ filegroup( "src/snapshot/shared-heap-deserializer.cc", "src/snapshot/shared-heap-serializer.h", "src/snapshot/shared-heap-serializer.cc", - "src/snapshot/snapshot-compression.cc", - "src/snapshot/snapshot-compression.h", "src/snapshot/snapshot-data.cc", "src/snapshot/snapshot-data.h", "src/snapshot/snapshot-source-sink.cc", @@ -2097,12 +2146,6 @@ filegroup( "src/tracing/traced-value.h", "src/tracing/tracing-category-observer.cc", "src/tracing/tracing-category-observer.h", - "src/trap-handler/handler-inside-posix.h", - "src/trap-handler/handler-inside.cc", - "src/trap-handler/handler-outside.cc", - "src/trap-handler/handler-shared.cc", - "src/trap-handler/trap-handler-internal.h", - "src/trap-handler/trap-handler.h", "src/utils/address-map.cc", "src/utils/address-map.h", "src/utils/allocation.cc", @@ -2112,6 +2155,8 @@ filegroup( "src/utils/boxed-float.h", "src/utils/detachable-vector.cc", "src/utils/detachable-vector.h", + "src/utils/hex-format.cc", + "src/utils/hex-format.h", "src/utils/identity-map.cc", "src/utils/identity-map.h", "src/utils/locked-queue-inl.h", @@ -2121,6 +2166,9 @@ filegroup( "src/utils/ostreams.cc", "src/utils/ostreams.h", "src/utils/scoped-list.h", + "src/utils/sha-256.cc", + "src/utils/sha-256.h", + "src/utils/sparse-bit-vector.h", "src/utils/utils-inl.h", "src/utils/utils.cc", "src/utils/utils.h", @@ -2386,7 +2434,11 @@ filegroup( ], }) + select({ # Only for x64 builds and for arm64 with x64 host simulator. - "@v8//bazel/config:is_non_android_posix_x64": [ + ":is_v8_enable_webassembly_on_non_android_posix_x64": [ + "src/trap-handler/handler-inside-posix.cc", + "src/trap-handler/handler-outside-posix.cc", + ], + "@v8//bazel/config:is_macos_arm64": [ "src/trap-handler/handler-inside-posix.cc", "src/trap-handler/handler-outside-posix.cc", ], @@ -2420,16 +2472,20 @@ filegroup( "src/asmjs/asm-scanner.h", "src/asmjs/asm-types.cc", "src/asmjs/asm-types.h", - "src/compiler/int64-lowering.h", - "src/compiler/wasm-compiler.h", - "src/compiler/wasm-escape-analysis.h", - "src/compiler/wasm-inlining.h", - "src/compiler/wasm-loop-peeling.h", "src/debug/debug-wasm-objects.cc", "src/debug/debug-wasm-objects.h", "src/debug/debug-wasm-objects-inl.h", "src/runtime/runtime-test-wasm.cc", "src/runtime/runtime-wasm.cc", + "src/third_party/utf8-decoder/generalized-utf8-decoder.h", + "src/trap-handler/handler-inside-posix.h", + "src/trap-handler/handler-inside.cc", + "src/trap-handler/handler-outside.cc", + "src/trap-handler/handler-shared.cc", + "src/trap-handler/trap-handler-internal.h", + "src/trap-handler/trap-handler.h", + "src/wasm/assembler-buffer-cache.cc", + "src/wasm/assembler-buffer-cache.h", "src/wasm/baseline/liftoff-assembler.cc", "src/wasm/baseline/liftoff-assembler-defs.h", "src/wasm/baseline/liftoff-assembler.h", @@ -2442,6 +2498,10 @@ filegroup( "src/wasm/code-space-access.cc", "src/wasm/code-space-access.h", "src/wasm/compilation-environment.h", + "src/wasm/constant-expression.cc", + "src/wasm/constant-expression.h", + "src/wasm/constant-expression-interface.cc", + "src/wasm/constant-expression-interface.h", "src/wasm/decoder.h", "src/wasm/function-body-decoder.cc", "src/wasm/function-body-decoder.h", @@ -2450,31 +2510,33 @@ filegroup( "src/wasm/function-compiler.h", "src/wasm/graph-builder-interface.cc", "src/wasm/graph-builder-interface.h", - "src/wasm/init-expr-interface.cc", - "src/wasm/init-expr-interface.h", "src/wasm/jump-table-assembler.cc", "src/wasm/jump-table-assembler.h", "src/wasm/leb-helper.h", "src/wasm/local-decl-encoder.cc", "src/wasm/local-decl-encoder.h", - "src/wasm/memory-protection-key.cc", - "src/wasm/memory-protection-key.h", "src/wasm/memory-tracing.cc", "src/wasm/memory-tracing.h", "src/wasm/module-compiler.cc", "src/wasm/module-compiler.h", "src/wasm/module-decoder.cc", "src/wasm/module-decoder.h", + "src/wasm/module-decoder-impl.h", "src/wasm/module-instantiate.cc", "src/wasm/module-instantiate.h", + "src/wasm/names-provider.cc", + "src/wasm/names-provider.h", "src/wasm/object-access.h", "src/wasm/signature-map.cc", "src/wasm/signature-map.h", "src/wasm/simd-shuffle.cc", "src/wasm/simd-shuffle.h", + "src/wasm/stacks.cc", "src/wasm/stacks.h", "src/wasm/streaming-decoder.cc", "src/wasm/streaming-decoder.h", + "src/wasm/string-builder.h", + "src/wasm/string-builder-multiline.h", "src/wasm/struct-types.h", "src/wasm/sync-streaming-decoder.cc", "src/wasm/value-type.cc", @@ -2484,6 +2546,9 @@ filegroup( "src/wasm/wasm-code-manager.h", "src/wasm/wasm-debug.cc", "src/wasm/wasm-debug.h", + "src/wasm/wasm-disassembler.cc", + "src/wasm/wasm-disassembler.h", + "src/wasm/wasm-disassembler-impl.h", "src/wasm/wasm-engine.cc", "src/wasm/wasm-engine.h", "src/wasm/wasm-external-refs.cc", @@ -2646,6 +2711,7 @@ filegroup( "src/compiler/control-equivalence.h", "src/compiler/control-flow-optimizer.cc", "src/compiler/control-flow-optimizer.h", + "src/compiler/control-path-state.h", "src/compiler/csa-load-elimination.cc", "src/compiler/csa-load-elimination.h", "src/compiler/dead-code-elimination.cc", @@ -2708,6 +2774,8 @@ filegroup( "src/compiler/js-type-hint-lowering.h", "src/compiler/js-typed-lowering.cc", "src/compiler/js-typed-lowering.h", + "src/compiler/late-escape-analysis.cc", + "src/compiler/late-escape-analysis.h", "src/compiler/linkage.cc", "src/compiler/linkage.h", "src/compiler/load-elimination.cc", @@ -2793,6 +2861,26 @@ filegroup( "src/compiler/state-values-utils.h", "src/compiler/store-store-elimination.cc", "src/compiler/store-store-elimination.h", + "src/compiler/turboshaft/assembler.h", + "src/compiler/turboshaft/decompression-optimization.cc", + "src/compiler/turboshaft/decompression-optimization.h", + "src/compiler/turboshaft/deopt-data.h", + "src/compiler/turboshaft/fast-hash.h", + "src/compiler/turboshaft/graph-builder.cc", + "src/compiler/turboshaft/graph-builder.h", + "src/compiler/turboshaft/graph.cc", + "src/compiler/turboshaft/graph.h", + "src/compiler/turboshaft/graph-visualizer.cc", + "src/compiler/turboshaft/graph-visualizer.h", + "src/compiler/turboshaft/operations.cc", + "src/compiler/turboshaft/operations.h", + "src/compiler/turboshaft/optimization-phase.cc", + "src/compiler/turboshaft/optimization-phase.h", + "src/compiler/turboshaft/recreate-schedule.cc", + "src/compiler/turboshaft/recreate-schedule.h", + "src/compiler/turboshaft/sidetable.h", + "src/compiler/turboshaft/utils.h", + "src/compiler/turboshaft/value-numbering-assembler.h", "src/compiler/type-cache.cc", "src/compiler/type-cache.h", "src/compiler/type-narrowing-reducer.cc", @@ -2813,10 +2901,24 @@ filegroup( ] + select({ ":is_v8_enable_webassembly": [ "src/compiler/int64-lowering.cc", + "src/compiler/int64-lowering.h", + "src/compiler/wasm-compiler-definitions.h", "src/compiler/wasm-compiler.cc", - "src/compiler/wasm-loop-peeling.cc", + "src/compiler/wasm-compiler.h", "src/compiler/wasm-escape-analysis.cc", + "src/compiler/wasm-escape-analysis.h", + "src/compiler/wasm-loop-peeling.cc", + "src/compiler/wasm-loop-peeling.h", + "src/compiler/wasm-gc-lowering.cc", + "src/compiler/wasm-gc-lowering.h", + "src/compiler/wasm-gc-operator-reducer.cc", + "src/compiler/wasm-gc-operator-reducer.h", + "src/compiler/wasm-graph-assembler.cc", + "src/compiler/wasm-graph-assembler.h", "src/compiler/wasm-inlining.cc", + "src/compiler/wasm-inlining.h", + "src/compiler/wasm-typer.cc", + "src/compiler/wasm-typer.h", ], "//conditions:default": [], }), @@ -2863,7 +2965,7 @@ filegroup( "src/builtins/builtins-proxy-gen.h", "src/builtins/builtins-regexp-gen.cc", "src/builtins/builtins-regexp-gen.h", - "src/builtins/builtins-shadowrealm-gen.cc", + "src/builtins/builtins-shadow-realm-gen.cc", "src/builtins/builtins-sharedarraybuffer-gen.cc", "src/builtins/builtins-string-gen.cc", "src/builtins/builtins-string-gen.h", @@ -2966,6 +3068,8 @@ filegroup( "src/heap/cppgc/marking-visitor.h", "src/heap/cppgc/marking-worklists.cc", "src/heap/cppgc/marking-worklists.h", + "src/heap/cppgc/member-storage.cc", + "src/heap/cppgc/member-storage.h", "src/heap/cppgc/memory.cc", "src/heap/cppgc/memory.h", "src/heap/cppgc/metric-recorder.h", @@ -3030,8 +3134,8 @@ filegroup( "@v8//bazel/config:is_inline_asm_s390x": ["src/heap/base/asm/s390/push_registers_asm.cc"], "@v8//bazel/config:is_inline_asm_riscv64": ["src/heap/base/asm/riscv64/push_registers_asm.cc"], "@v8//bazel/config:is_inline_asm_ppc64le": ["src/heap/base/asm/ppc/push_registers_asm.cc"], - "@v8//bazel/config:is_msvc_asm_ia32": ["src/heap/base/asm/ia32/push_registers_masm.S"], - "@v8//bazel/config:is_msvc_asm_x64": ["src/heap/base/asm/x64/push_registers_masm.S"], + "@v8//bazel/config:is_msvc_asm_ia32": ["src/heap/base/asm/ia32/push_registers_masm.asm"], + "@v8//bazel/config:is_msvc_asm_x64": ["src/heap/base/asm/x64/push_registers_masm.asm"], "@v8//bazel/config:is_msvc_asm_arm64": ["src/heap/base/asm/arm64/push_registers_masm.S"], }), ) @@ -3136,6 +3240,8 @@ filegroup( "src/inspector/v8-string-conversions.h", "src/inspector/v8-value-utils.cc", "src/inspector/v8-value-utils.h", + "src/inspector/v8-webdriver-serializer.cc", + "src/inspector/v8-webdriver-serializer.h", "src/inspector/value-mirror.cc", "src/inspector/value-mirror.h", ":crdtp_platform_files", @@ -3285,8 +3391,6 @@ py_binary( "third_party/inspector_protocol/lib/ValueConversions_h.template", "third_party/inspector_protocol/lib/Values_cpp.template", "third_party/inspector_protocol/lib/Values_h.template", - "third_party/inspector_protocol/lib/base_string_adapter_cc.template", - "third_party/inspector_protocol/lib/base_string_adapter_h.template", "third_party/inspector_protocol/templates/Exported_h.template", "third_party/inspector_protocol/templates/Imported_h.template", "third_party/inspector_protocol/templates/TypeBuilder_cpp.template", @@ -3479,8 +3583,6 @@ v8_library( deps = [ ":v8_libbase", "//external:base_trace_event_common", - "//external:zlib", - "//external:zlib_compression_utils", ], ) @@ -3596,7 +3698,7 @@ v8_binary_non_pointer_compression( alias( name = "v8ci", - actual = "icu/v8", + actual = "noicu/v8", ) # ================================================= diff --git a/deps/v8/BUILD.gn b/deps/v8/BUILD.gn index 988c907d964a25..3f78b1773f3907 100644 --- a/deps/v8/BUILD.gn +++ b/deps/v8/BUILD.gn @@ -40,9 +40,12 @@ declare_args() { # Sets -DV8_ENABLE_FUTURE. v8_enable_future = false - # Sets -DSYSTEM_INSTRUMENTATION. Enables OS-dependent event tracing + # Sets -DENABLE_SYSTEM_INSTRUMENTATION. Enables OS-dependent event tracing v8_enable_system_instrumentation = (is_win || is_mac) && !v8_use_perfetto + # Sets -DV8_ENABLE_ETW_STACK_WALKING. Enables ETW Stack Walking + v8_enable_etw_stack_walking = is_win + # Sets the GUID for the ETW provider v8_etw_guid = "" @@ -83,7 +86,7 @@ declare_args() { v8_enable_hugepage = false # Sets -dENABLE_HANDLE_ZAPPING. - v8_enable_handle_zapping = !is_on_release_branch || is_debug + v8_enable_handle_zapping = is_asan || is_debug # Enable slow dchecks. v8_enable_slow_dchecks = false @@ -175,16 +178,19 @@ declare_args() { # # To do profile-guided optimizations of builtins: # 1. Build with v8_enable_builtins_profiling = true - # 2. Run your chosen workload with the --turbo-profiling-log-builtins flag. + # 2. Run your chosen workload with the --turbo-profiling-output flag. # For Chrome, the invocation might look like this: # chrome --no-sandbox --disable-extensions - # --js-flags="--turbo-profiling-log-builtins --logfile=path/to/v8.log" + # --js-flags="--turbo-profiling-output=v8.builtins.pgo" # "http://localhost/test-suite" - # 3. Optionally repeat step 2 for additional workloads, and concatenate all of - # the resulting log files into a single file. - # 4. Build again with v8_builtins_profiling_log_file set to the file created - # in steps 2-3. - v8_builtins_profiling_log_file = "" + # 3. Run tools/builtins-pgo/get_hints.py to produce the branch hints, + # selecting min_count and threshold_ratio as you wish. + # 4. Optionally repeat steps 2-3 for additional workloads, and use + # tools/builtins-pgo/combine_hints.py to combine the hints produced in + # step 3 into a single file. + # 5. Build again with v8_builtins_profiling_log_file set to the file created + # in step 3 or 4. + v8_builtins_profiling_log_file = "default" # Enables various testing features. v8_enable_test_features = "" @@ -298,20 +304,17 @@ declare_args() { v8_enable_zone_compression = "" # Enable the experimental V8 sandbox. - # Sets -DV8_SANDBOX. + # Sets -DV8_ENABLE_SANDBOX. v8_enable_sandbox = "" - # Enable external pointer sandboxing. Requires v8_enable_sandbox. - # Sets -DV8_SANDBOXED_EXTERNAL_POINRTERS. - v8_enable_sandboxed_external_pointers = false - - # Enable sandboxed pointers. Requires v8_enable_sandbox. - # Sets -DV8_SANDBOXED_POINTERS. - v8_enable_sandboxed_pointers = false - # Enable all available sandbox features. Implies v8_enable_sandbox. v8_enable_sandbox_future = false + # Expose the memory corruption API to JavaScript. Useful for testing the sandbox. + # WARNING This will expose builtins that (by design) cause memory corruption. + # Sets -DV8_EXPOSE_MEMORY_CORRUPTION_API + v8_expose_memory_corruption_api = false + # Experimental feature for collecting per-class zone memory stats. # Requires use_rtti = true v8_enable_precise_zone_stats = false @@ -362,6 +365,14 @@ declare_args() { # TODO(victorgomes): Remove this flag once Chormium no longer needs # the deprecated feature. v8_fuchsia_use_vmex_resource = is_fuchsia && !build_with_chromium + + # Enables pointer compression for 8GB heaps. + # Sets -DV8_COMPRESS_POINTERS_8GB. + v8_enable_pointer_compression_8gb = "" + + # Compile V8 using zlib as dependency. + # Sets -DV8_USE_ZLIB + v8_use_zlib = true } # Derived defaults. @@ -407,9 +418,27 @@ if (v8_enable_pointer_compression == "") { v8_enable_pointer_compression = v8_current_cpu == "arm64" || v8_current_cpu == "x64" } + +# Toggle pointer compression for correctness fuzzing when building the +# clang_x64_pointer_compression toolchain. We'll correctness-compare the +# default build with the clang_x64_pointer_compression build. +if (v8_multi_arch_build && + rebase_path(get_label_info(":d8", "root_out_dir"), root_build_dir) == + "clang_x64_pointer_compression") { + v8_enable_pointer_compression = !v8_enable_pointer_compression +} + +# Ensure the sandbox is on/off in the same way as pointer compression for +# correctness fuzzing builds. +if (v8_multi_arch_build) { + v8_enable_sandbox = v8_enable_pointer_compression +} if (v8_enable_pointer_compression_shared_cage == "") { v8_enable_pointer_compression_shared_cage = v8_enable_pointer_compression } +if (v8_enable_pointer_compression_8gb == "") { + v8_enable_pointer_compression_8gb = false +} if (v8_enable_fast_torque == "") { v8_enable_fast_torque = v8_enable_fast_mksnapshot } @@ -418,7 +447,7 @@ if (v8_enable_zone_compression == "") { } if (v8_enable_short_builtin_calls == "") { v8_enable_short_builtin_calls = - v8_current_cpu == "x64" || (!is_android && v8_current_cpu == "arm64") + v8_current_cpu == "x64" || v8_current_cpu == "arm64" } if (v8_enable_external_code_space == "") { v8_enable_external_code_space = @@ -429,6 +458,16 @@ if (v8_enable_external_code_space == "") { if (v8_enable_maglev == "") { v8_enable_maglev = v8_current_cpu == "x64" && v8_enable_pointer_compression } +if (v8_builtins_profiling_log_file == "default") { + v8_builtins_profiling_log_file = "" + if (is_debug == false) { + if (v8_current_cpu == "x64") { + v8_builtins_profiling_log_file = "tools/builtins-pgo/x64.profile" + } else if (v8_current_cpu == "arm64") { + v8_builtins_profiling_log_file = "tools/builtins-pgo/arm64.profile" + } + } +} if (v8_enable_single_generation == "") { v8_enable_single_generation = v8_disable_write_barriers } @@ -457,17 +496,6 @@ assert(!v8_enable_trace_ignition || v8_enable_trace_unoptimized, assert(!v8_enable_trace_baseline_exec || v8_enable_trace_unoptimized, "Baseline tracing requires unoptimized tracing to be enabled.") -# Toggle pointer compression for correctness fuzzing when building the -# clang_x64_pointer_compression toolchain. We'll correctness-compare the -# default build with the clang_x64_pointer_compression build. -if (v8_multi_arch_build && - rebase_path(get_label_info(":d8", "root_out_dir"), root_build_dir) == - "clang_x64_pointer_compression") { - v8_enable_pointer_compression = !v8_enable_pointer_compression - v8_enable_pointer_compression_shared_cage = v8_enable_pointer_compression - v8_enable_external_code_space = v8_enable_pointer_compression -} - # Check if it is a Chromium build and activate PAC/BTI if needed. # TODO(cavalcantii): have a single point of integration with PAC/BTI flags. if (build_with_chromium && v8_current_cpu == "arm64" && @@ -477,10 +505,8 @@ if (build_with_chromium && v8_current_cpu == "arm64" && } if (v8_enable_short_builtin_calls && - ((!v8_enable_pointer_compression && v8_current_cpu != "x64") || - v8_control_flow_integrity)) { - # Disable short calls when pointer compression is not enabled. - # Or when CFI is enabled (until the CFI-related issues are fixed), except x64, + (!v8_enable_pointer_compression && v8_current_cpu != "x64")) { + # Disable short calls when pointer compression is not enabled, except x64, # where short builtin calls can still be enabled if the code range is # guaranteed to be close enough to embedded builtins. v8_enable_short_builtin_calls = false @@ -493,15 +519,15 @@ if (v8_enable_shared_ro_heap == "") { if (v8_enable_sandbox == "") { # TODO(saelo, v8:11880) remove dependency on v8_enable_external_code_space # once that is enabled everywhere by default. + # TODO(chromium:1325784) the sandbox is not currently supported in Chromium + # on Fuchsia. v8_enable_sandbox = build_with_chromium && v8_enable_pointer_compression_shared_cage && - v8_enable_external_code_space + v8_enable_external_code_space && target_os != "fuchsia" } # Enable all available sandbox features if sandbox future is enabled. if (v8_enable_sandbox_future) { - v8_enable_sandboxed_pointers = true - v8_enable_sandboxed_external_pointers = true v8_enable_sandbox = true } @@ -527,17 +553,17 @@ assert(!v8_enable_map_packing || v8_current_cpu == "x64", assert(!v8_enable_external_code_space || v8_enable_pointer_compression, "External code space feature requires pointer compression") +assert(!v8_enable_pointer_compression_8gb || v8_enable_pointer_compression, + "Pointer compression for 8GB cages requires pointer compression") + assert(!v8_enable_sandbox || v8_enable_pointer_compression_shared_cage, "The sandbox requires the shared pointer compression cage") assert(!v8_enable_sandbox || v8_enable_external_code_space, "The sandbox requires the external code space") -assert(!v8_enable_sandboxed_pointers || v8_enable_sandbox, - "Sandboxed pointers require the sandbox") - -assert(!v8_enable_sandboxed_external_pointers || v8_enable_sandbox, - "Sandboxed external pointers require the sandbox") +assert(!v8_expose_memory_corruption_api || v8_enable_sandbox, + "The Memory Corruption API requires the sandbox") assert( !v8_enable_pointer_compression_shared_cage || v8_enable_pointer_compression, @@ -558,19 +584,28 @@ assert(!cppgc_enable_caged_heap || v8_current_cpu == "x64" || assert(!cppgc_enable_young_generation || cppgc_enable_caged_heap, "Young generation in CppGC requires caged heap") +assert(!cppgc_enable_pointer_compression || cppgc_enable_caged_heap, + "Pointer compression in CppGC requires caged heap") + +assert( + !v8_enable_conservative_stack_scanning || + v8_enable_inner_pointer_resolution_osb || + v8_enable_inner_pointer_resolution_mb, + "Conservative stack scanning requires inner pointer resolution (OSB or MB)") + if (v8_enable_single_generation == true) { assert( v8_enable_unconditional_write_barriers || v8_disable_write_barriers, "Requires unconditional write barriers or none (which disables incremental marking)") } -assert(!v8_enable_conservative_stack_scanning || v8_enable_single_generation, - "Conservative stack scanning requires single generation") - if (v8_fuchsia_use_vmex_resource) { assert(target_os == "fuchsia", "VMEX resource only available on Fuchsia") } +assert(!v8_enable_snapshot_compression || v8_use_zlib, + "Snapshot compression requires zlib") + v8_random_seed = "314159265" v8_toolset_for_shell = "host" @@ -609,7 +644,7 @@ config("internal_config") { defines += [ "BUILDING_V8_SHARED" ] } - if (v8_current_cpu == "riscv64") { + if (v8_current_cpu == "riscv64" || v8_current_cpu == "riscv32") { libs = [ "atomic" ] } } @@ -681,7 +716,7 @@ config("external_config") { defines += [ "USING_V8_SHARED" ] } - if (current_cpu == "riscv64") { + if (current_cpu == "riscv64" || current_cpu == "riscv32") { libs = [ "atomic" ] } } @@ -703,9 +738,7 @@ external_v8_defines = [ "V8_COMPRESS_POINTERS_IN_ISOLATE_CAGE", "V8_31BIT_SMIS_ON_64BIT_ARCH", "V8_COMPRESS_ZONES", - "V8_SANDBOX", - "V8_SANDBOXED_POINTERS", - "V8_SANDBOXED_EXTERNAL_POINTERS", + "V8_ENABLE_SANDBOX", "V8_DEPRECATION_WARNINGS", "V8_IMMINENT_DEPRECATION_WARNINGS", "V8_NO_ARGUMENTS_ADAPTOR", @@ -734,13 +767,7 @@ if (v8_enable_zone_compression) { enabled_external_v8_defines += [ "V8_COMPRESS_ZONES" ] } if (v8_enable_sandbox) { - enabled_external_v8_defines += [ "V8_SANDBOX" ] -} -if (v8_enable_sandboxed_pointers) { - enabled_external_v8_defines += [ "V8_SANDBOXED_POINTERS" ] -} -if (v8_enable_sandboxed_external_pointers) { - enabled_external_v8_defines += [ "V8_SANDBOXED_EXTERNAL_POINTERS" ] + enabled_external_v8_defines += [ "V8_ENABLE_SANDBOX" ] } if (v8_deprecation_warnings) { enabled_external_v8_defines += [ "V8_DEPRECATION_WARNINGS" ] @@ -778,6 +805,7 @@ external_cppgc_defines = [ "CPPGC_SUPPORTS_OBJECT_NAMES", "CPPGC_CAGED_HEAP", "CPPGC_YOUNG_GENERATION", + "CPPGC_POINTER_COMPRESSION", ] enabled_external_cppgc_defines = [] @@ -787,10 +815,24 @@ if (cppgc_enable_object_names) { } if (cppgc_enable_caged_heap) { enabled_external_cppgc_defines += [ "CPPGC_CAGED_HEAP" ] + + # Always enable young generation compile time flag if caged heap is enabled. + cppgc_enable_young_generation = true + + # Pointer compression regresses binary size on Fuchsia by about 300K. + # However, the change improves Oilpan memory by 15-20% (2-4% of PMF), + # which is beneficial for memory-impoverished platforms. + cppgc_enable_pointer_compression = true } if (cppgc_enable_young_generation) { enabled_external_cppgc_defines += [ "CPPGC_YOUNG_GENERATION" ] } +if (cppgc_enable_pointer_compression) { + enabled_external_cppgc_defines += [ "CPPGC_POINTER_COMPRESSION" ] +} +if (cppgc_enable_2gb_cage) { + enabled_external_cppgc_defines += [ "CPPGC_2GB_CAGE" ] +} disabled_external_cppgc_defines = external_cppgc_defines - enabled_external_cppgc_defines @@ -909,6 +951,12 @@ config("features") { if (v8_enable_conservative_stack_scanning) { defines += [ "V8_ENABLE_CONSERVATIVE_STACK_SCANNING" ] } + if (v8_enable_inner_pointer_resolution_osb) { + defines += [ "V8_ENABLE_INNER_POINTER_RESOLUTION_OSB" ] + } + if (v8_enable_inner_pointer_resolution_mb) { + defines += [ "V8_ENABLE_INNER_POINTER_RESOLUTION_MB" ] + } if (v8_disable_write_barriers) { defines += [ "V8_DISABLE_WRITE_BARRIERS" ] } @@ -972,6 +1020,9 @@ config("features") { if (v8_enable_system_instrumentation) { defines += [ "V8_ENABLE_SYSTEM_INSTRUMENTATION" ] } + if (v8_enable_etw_stack_walking) { + defines += [ "V8_ENABLE_ETW_STACK_WALKING" ] + } if (v8_etw_guid != "") { defines += [ "V8_ETW_GUID=\"$v8_etw_guid\"" ] } @@ -999,6 +1050,15 @@ config("features") { if (v8_fuchsia_use_vmex_resource) { defines += [ "V8_USE_VMEX_RESOURCE" ] } + if (v8_expose_memory_corruption_api) { + defines += [ "V8_EXPOSE_MEMORY_CORRUPTION_API" ] + } + if (v8_enable_pointer_compression_8gb) { + defines += [ "V8_COMPRESS_POINTERS_8GB" ] + } + if (v8_use_zlib) { + defines += [ "V8_USE_ZLIB" ] + } } config("toolchain") { @@ -1057,49 +1117,11 @@ config("toolchain") { } } - # Mips64el/mipsel simulators. - if (target_is_simulator && - (v8_current_cpu == "mipsel" || v8_current_cpu == "mips64el")) { + # Mips64el simulators. + if (target_is_simulator && v8_current_cpu == "mips64el") { defines += [ "_MIPS_TARGET_SIMULATOR" ] } - if (v8_current_cpu == "mipsel" || v8_current_cpu == "mips") { - defines += [ "V8_TARGET_ARCH_MIPS" ] - if (v8_can_use_fpu_instructions) { - defines += [ "CAN_USE_FPU_INSTRUCTIONS" ] - } - if (v8_use_mips_abi_hardfloat) { - defines += [ - "__mips_hard_float=1", - "CAN_USE_FPU_INSTRUCTIONS", - ] - } else { - defines += [ "__mips_soft_float=1" ] - } - if (mips_arch_variant == "r6") { - defines += [ - "_MIPS_ARCH_MIPS32R6", - "FPU_MODE_FP64", - ] - if (mips_use_msa) { - defines += [ "_MIPS_MSA" ] - } - } else if (mips_arch_variant == "r2") { - defines += [ "_MIPS_ARCH_MIPS32R2" ] - if (mips_fpu_mode == "fp64") { - defines += [ "FPU_MODE_FP64" ] - } else if (mips_fpu_mode == "fpxx") { - defines += [ "FPU_MODE_FPXX" ] - } else if (mips_fpu_mode == "fp32") { - defines += [ "FPU_MODE_FP32" ] - } - } else if (mips_arch_variant == "r1") { - defines += [ "FPU_MODE_FP32" ] - } - - # TODO(infra): Add support for mips_arch_variant rx and loongson. - } - if (v8_current_cpu == "mips64el" || v8_current_cpu == "mips64") { defines += [ "V8_TARGET_ARCH_MIPS64" ] if (v8_can_use_fpu_instructions) { @@ -1176,14 +1198,21 @@ config("toolchain") { if (v8_current_cpu == "riscv64") { defines += [ "V8_TARGET_ARCH_RISCV64" ] defines += [ "__riscv_xlen=64" ] - - #FIXME: Temporarily use MIPS macro for the building. defines += [ "CAN_USE_FPU_INSTRUCTIONS" ] + if (!is_clang) { + cflags += [ "-ffp-contract=off" ] + } if (target_is_simulator) { defines += [ "CAN_USE_RVV_INSTRUCTIONS" ] } } + if (v8_current_cpu == "riscv32") { + defines += [ "V8_TARGET_ARCH_RISCV32" ] + defines += [ "__riscv_xlen=32" ] + defines += [ "CAN_USE_FPU_INSTRUCTIONS" ] + } + if (v8_current_cpu == "x86") { defines += [ "V8_TARGET_ARCH_IA32" ] if (is_win) { @@ -1266,16 +1295,17 @@ config("toolchain") { if (is_clang) { cflags += [ "-Wmissing-field-initializers", + "-Wunreachable-code", + + # Google3 enables this warning, so we should also enable it to find issue + # earlier. See https://reviews.llvm.org/D56731 for details about this + # warning. + "-Wctad-maybe-unsupported", # TODO(v8:12245): Fix shadowing instances and remove. "-Wno-shadow", ] - if (v8_current_cpu != "mips" && v8_current_cpu != "mipsel") { - # We exclude MIPS because the IsMipsArchVariant macro causes trouble. - cflags += [ "-Wunreachable-code" ] - } - if (v8_current_cpu == "x64" || v8_current_cpu == "arm64" || v8_current_cpu == "mips64el" || v8_current_cpu == "riscv64") { cflags += [ "-Wshorten-64-to-32" ] @@ -1470,7 +1500,7 @@ config("toolchain") { # For code that is hot during mksnapshot. In fast-mksnapshot builds, we # optimize some files even in debug builds to speed up mksnapshot times. -config("always_optimize") { +config("always_turbofanimize") { configs = [ ":internal_config" ] # TODO(crbug.com/621335) Rework this so that we don't have the confusion @@ -1488,6 +1518,10 @@ config("v8_gcov_coverage_cflags") { cflags = [ "-fprofile-arcs", "-ftest-coverage", + + # We already block on gcc warnings on other bots. Let's not block here to + # always generate coverage reports. + "-Wno-error", ] } @@ -1531,8 +1565,7 @@ if (is_android && enable_java_templates) { if (v8_use_external_startup_data) { deps = [ "//v8" ] renaming_sources = [ "$root_out_dir/snapshot_blob.bin" ] - if (current_cpu == "arm" || current_cpu == "x86" || - current_cpu == "mipsel") { + if (current_cpu == "arm" || current_cpu == "x86") { renaming_destinations = [ "snapshot_blob_32.bin" ] } else { renaming_destinations = [ "snapshot_blob_64.bin" ] @@ -1653,7 +1686,11 @@ torque_files = [ "src/builtins/array-slice.tq", "src/builtins/array-some.tq", "src/builtins/array-splice.tq", + "src/builtins/array-to-reversed.tq", + "src/builtins/array-to-sorted.tq", + "src/builtins/array-to-spliced.tq", "src/builtins/array-unshift.tq", + "src/builtins/array-with.tq", "src/builtins/array.tq", "src/builtins/arraybuffer.tq", "src/builtins/base.tq", @@ -1752,7 +1789,9 @@ torque_files = [ "src/builtins/typed-array-some.tq", "src/builtins/typed-array-sort.tq", "src/builtins/typed-array-subarray.tq", + "src/builtins/typed-array-to-reversed.tq", "src/builtins/typed-array-values.tq", + "src/builtins/typed-array-with.tq", "src/builtins/typed-array.tq", "src/builtins/weak-ref.tq", "src/ic/handler-configuration.tq", @@ -1777,6 +1816,7 @@ torque_files = [ "src/objects/heap-object.tq", "src/objects/js-array-buffer.tq", "src/objects/js-array.tq", + "src/objects/js-atomics-synchronization.tq", "src/objects/js-collection-iterator.tq", "src/objects/js-collection.tq", "src/objects/js-function.tq", @@ -1786,7 +1826,8 @@ torque_files = [ "src/objects/js-proxy.tq", "src/objects/js-regexp-string-iterator.tq", "src/objects/js-regexp.tq", - "src/objects/js-shadow-realms.tq", + "src/objects/js-shadow-realm.tq", + "src/objects/js-shared-array.tq", "src/objects/js-struct.tq", "src/objects/js-temporal-objects.tq", "src/objects/js-weak-refs.tq", @@ -2113,7 +2154,7 @@ template("run_mksnapshot") { if (v8_builtins_profiling_log_file != "") { sources += [ v8_builtins_profiling_log_file ] args += [ - "--turbo-profiling-log-file", + "--turbo-profiling-input", rebase_path(v8_builtins_profiling_log_file, root_build_dir), ] } @@ -2182,10 +2223,11 @@ template("run_mksnapshot") { } if (v8_enable_fast_mksnapshot) { - args += [ - "--no-turbo-rewrite-far-jumps", - "--no-turbo-verify-allocation", - ] + args += [ "--no-turbo-verify-allocation" ] + + if (v8_current_cpu == "x86" || v8_current_cpu == "x64") { + args += [ "--no-turbo-rewrite-far-jumps" ] + } if (v8_enable_debugging_features && v8_enable_slow_dchecks) { # mksnapshot only accepts this flag if ENABLE_SLOW_DCHECKS is defined. @@ -2253,8 +2295,7 @@ action("v8_dump_build_config") { "v8_enable_cet_shadow_stack=$v8_enable_cet_shadow_stack", ] - if (v8_current_cpu == "mips" || v8_current_cpu == "mipsel" || - v8_current_cpu == "mips64" || v8_current_cpu == "mips64el") { + if (v8_current_cpu == "mips64" || v8_current_cpu == "mips64el") { args += [ "mips_arch_variant=\"$mips_arch_variant\"", "mips_use_msa=$mips_use_msa", @@ -2365,7 +2406,7 @@ v8_source_set("v8_initializers") { "src/builtins/builtins-proxy-gen.h", "src/builtins/builtins-regexp-gen.cc", "src/builtins/builtins-regexp-gen.h", - "src/builtins/builtins-shadowrealm-gen.cc", + "src/builtins/builtins-shadow-realm-gen.cc", "src/builtins/builtins-sharedarraybuffer-gen.cc", "src/builtins/builtins-string-gen.cc", "src/builtins/builtins-string-gen.h", @@ -2427,11 +2468,6 @@ v8_source_set("v8_initializers") { ### gcmole(arch:arm64) ### "src/builtins/arm64/builtins-arm64.cc", ] - } else if (v8_current_cpu == "mips" || v8_current_cpu == "mipsel") { - sources += [ - ### gcmole(arch:mipsel) ### - "src/builtins/mips/builtins-mips.cc", - ] } else if (v8_current_cpu == "mips64" || v8_current_cpu == "mips64el") { sources += [ ### gcmole(arch:mips64el) ### @@ -2460,7 +2496,12 @@ v8_source_set("v8_initializers") { } else if (v8_current_cpu == "riscv64") { sources += [ ### gcmole(arch:riscv64) ### - "src/builtins/riscv64/builtins-riscv64.cc", + "src/builtins/riscv/builtins-riscv.cc", + ] + } else if (v8_current_cpu == "riscv32") { + sources += [ + ### gcmole(arch:riscv32) ### + "src/builtins/riscv/builtins-riscv.cc", ] } @@ -2652,7 +2693,10 @@ v8_header_set("v8_flags") { "src/flags/flags.h", ] - deps = [ ":v8_shared_internal_headers" ] + deps = [ + ":v8_libbase", + ":v8_shared_internal_headers", + ] } v8_header_set("v8_internal_headers") { @@ -2706,6 +2750,7 @@ v8_header_set("v8_internal_headers") { "src/codegen/assembler-inl.h", "src/codegen/assembler.h", "src/codegen/atomic-memory-order.h", + "src/codegen/background-merge-task.h", "src/codegen/bailout-reason.h", "src/codegen/callable.h", "src/codegen/code-comments.h", @@ -2728,6 +2773,7 @@ v8_header_set("v8_internal_headers") { "src/codegen/machine-type.h", "src/codegen/macro-assembler-inl.h", "src/codegen/macro-assembler.h", + "src/codegen/maglev-safepoint-table.h", "src/codegen/optimized-compilation-info.h", "src/codegen/pending-optimization-table.h", "src/codegen/register-arch.h", @@ -2737,19 +2783,20 @@ v8_header_set("v8_internal_headers") { "src/codegen/reglist-base.h", "src/codegen/reglist.h", "src/codegen/reloc-info.h", + "src/codegen/safepoint-table-base.h", "src/codegen/safepoint-table.h", "src/codegen/script-details.h", "src/codegen/signature.h", "src/codegen/source-position-table.h", "src/codegen/source-position.h", - "src/codegen/string-constants.h", "src/codegen/tick-counter.h", "src/codegen/tnode.h", "src/codegen/turbo-assembler.h", "src/codegen/unoptimized-compilation-info.h", - "src/common/allow-deprecated.h", "src/common/assert-scope.h", "src/common/checks.h", + "src/common/code-memory-access-inl.h", + "src/common/code-memory-access.h", "src/common/high-allocation-throughput-scope.h", "src/common/message-template.h", "src/common/operation.h", @@ -2796,6 +2843,7 @@ v8_header_set("v8_internal_headers") { "src/compiler/constant-folding-reducer.h", "src/compiler/control-equivalence.h", "src/compiler/control-flow-optimizer.h", + "src/compiler/control-path-state.h", "src/compiler/csa-load-elimination.h", "src/compiler/dead-code-elimination.h", "src/compiler/decompression-optimizer.h", @@ -2829,6 +2877,7 @@ v8_header_set("v8_internal_headers") { "src/compiler/js-operator.h", "src/compiler/js-type-hint-lowering.h", "src/compiler/js-typed-lowering.h", + "src/compiler/late-escape-analysis.h", "src/compiler/linkage.h", "src/compiler/load-elimination.h", "src/compiler/loop-analysis.h", @@ -2874,6 +2923,19 @@ v8_header_set("v8_internal_headers") { "src/compiler/simplified-operator.h", "src/compiler/state-values-utils.h", "src/compiler/store-store-elimination.h", + "src/compiler/turboshaft/assembler.h", + "src/compiler/turboshaft/decompression-optimization.h", + "src/compiler/turboshaft/deopt-data.h", + "src/compiler/turboshaft/fast-hash.h", + "src/compiler/turboshaft/graph-builder.h", + "src/compiler/turboshaft/graph-visualizer.h", + "src/compiler/turboshaft/graph.h", + "src/compiler/turboshaft/operations.h", + "src/compiler/turboshaft/optimization-phase.h", + "src/compiler/turboshaft/recreate-schedule.h", + "src/compiler/turboshaft/sidetable.h", + "src/compiler/turboshaft/utils.h", + "src/compiler/turboshaft/value-numbering-assembler.h", "src/compiler/type-cache.h", "src/compiler/type-narrowing-reducer.h", "src/compiler/typed-optimization.h", @@ -2897,6 +2959,7 @@ v8_header_set("v8_internal_headers") { "src/debug/debug-type-profile.h", "src/debug/debug.h", "src/debug/interface-types.h", + "src/debug/liveedit-diff.h", "src/debug/liveedit.h", "src/deoptimizer/deoptimize-reason.h", "src/deoptimizer/deoptimized-frame-info.h", @@ -2963,6 +3026,7 @@ v8_header_set("v8_internal_headers") { "src/handles/maybe-handles-inl.h", "src/handles/maybe-handles.h", "src/handles/persistent-handles.h", + "src/handles/shared-object-conveyor-handles.h", "src/heap/allocation-observer.h", "src/heap/allocation-result.h", "src/heap/allocation-stats.h", @@ -2996,9 +3060,11 @@ v8_header_set("v8_internal_headers") { "src/heap/finalization-registry-cleanup-task.h", "src/heap/free-list-inl.h", "src/heap/free-list.h", + "src/heap/gc-callbacks.h", "src/heap/gc-idle-time-handler.h", "src/heap/gc-tracer-inl.h", "src/heap/gc-tracer.h", + "src/heap/global-handle-marking-visitor.h", "src/heap/heap-allocator-inl.h", "src/heap/heap-allocator.h", "src/heap/heap-controller.h", @@ -3108,8 +3174,8 @@ v8_header_set("v8_internal_headers") { "src/logging/counters-scopes.h", "src/logging/counters.h", "src/logging/local-logger.h", + "src/logging/log-file.h", "src/logging/log-inl.h", - "src/logging/log-utils.h", "src/logging/log.h", "src/logging/metrics.h", "src/logging/runtime-call-stats-scope.h", @@ -3187,6 +3253,8 @@ v8_header_set("v8_internal_headers") { "src/objects/js-array-buffer.h", "src/objects/js-array-inl.h", "src/objects/js-array.h", + "src/objects/js-atomics-synchronization-inl.h", + "src/objects/js-atomics-synchronization.h", "src/objects/js-collection-inl.h", "src/objects/js-collection-iterator-inl.h", "src/objects/js-collection-iterator.h", @@ -3207,8 +3275,10 @@ v8_header_set("v8_internal_headers") { "src/objects/js-regexp.h", "src/objects/js-segments-inl.h", "src/objects/js-segments.h", - "src/objects/js-shadow-realms-inl.h", - "src/objects/js-shadow-realms.h", + "src/objects/js-shadow-realm-inl.h", + "src/objects/js-shadow-realm.h", + "src/objects/js-shared-array-inl.h", + "src/objects/js-shared-array.h", "src/objects/js-struct-inl.h", "src/objects/js-struct.h", "src/objects/js-temporal-objects-inl.h", @@ -3251,8 +3321,6 @@ v8_header_set("v8_internal_headers") { "src/objects/option-utils.h", "src/objects/ordered-hash-table-inl.h", "src/objects/ordered-hash-table.h", - "src/objects/osr-optimized-code-cache-inl.h", - "src/objects/osr-optimized-code-cache.h", "src/objects/primitive-heap-object-inl.h", "src/objects/primitive-heap-object.h", "src/objects/promise-inl.h", @@ -3277,6 +3345,7 @@ v8_header_set("v8_internal_headers") { "src/objects/script.h", "src/objects/shared-function-info-inl.h", "src/objects/shared-function-info.h", + "src/objects/simd.h", "src/objects/slots-atomic-inl.h", "src/objects/slots-inl.h", "src/objects/slots.h", @@ -3285,6 +3354,8 @@ v8_header_set("v8_internal_headers") { "src/objects/source-text-module-inl.h", "src/objects/source-text-module.h", "src/objects/string-comparator.h", + "src/objects/string-forwarding-table-inl.h", + "src/objects/string-forwarding-table.h", "src/objects/string-inl.h", "src/objects/string-set-inl.h", "src/objects/string-set.h", @@ -3391,6 +3462,7 @@ v8_header_set("v8_internal_headers") { "src/sandbox/sandbox.h", "src/sandbox/sandboxed-pointer-inl.h", "src/sandbox/sandboxed-pointer.h", + "src/sandbox/testing.h", "src/snapshot/code-serializer.h", "src/snapshot/context-deserializer.h", "src/snapshot/context-serializer.h", @@ -3408,7 +3480,6 @@ v8_header_set("v8_internal_headers") { "src/snapshot/serializer.h", "src/snapshot/shared-heap-deserializer.h", "src/snapshot/shared-heap-serializer.h", - "src/snapshot/snapshot-compression.h", "src/snapshot/snapshot-data.h", "src/snapshot/snapshot-source-sink.h", "src/snapshot/snapshot-utils.h", @@ -3442,12 +3513,15 @@ v8_header_set("v8_internal_headers") { "src/utils/bit-vector.h", "src/utils/boxed-float.h", "src/utils/detachable-vector.h", + "src/utils/hex-format.h", "src/utils/identity-map.h", "src/utils/locked-queue-inl.h", "src/utils/locked-queue.h", "src/utils/memcopy.h", "src/utils/ostreams.h", "src/utils/scoped-list.h", + "src/utils/sha-256.h", + "src/utils/sparse-bit-vector.h", "src/utils/utils-inl.h", "src/utils/utils.h", "src/utils/version.h", @@ -3468,12 +3542,18 @@ v8_header_set("v8_internal_headers") { "src/zone/zone.h", ] + if (v8_enable_snapshot_compression) { + sources += [ "src/snapshot/snapshot-compression.h" ] + } + if (v8_use_perfetto) { sources -= [ "//base/trace_event/common/trace_event_common.h" ] } if (v8_enable_maglev) { sources += [ + "src/maglev/maglev-assembler-inl.h", + "src/maglev/maglev-assembler.h", "src/maglev/maglev-basic-block.h", "src/maglev/maglev-code-gen-state.h", "src/maglev/maglev-code-generator.h", @@ -3488,6 +3568,7 @@ v8_header_set("v8_internal_headers") { "src/maglev/maglev-graph-verifier.h", "src/maglev/maglev-graph.h", "src/maglev/maglev-interpreter-frame-state.h", + "src/maglev/maglev-ir-inl.h", "src/maglev/maglev-ir.h", "src/maglev/maglev-regalloc-data.h", "src/maglev/maglev-regalloc.h", @@ -3505,14 +3586,21 @@ v8_header_set("v8_internal_headers") { "src/asmjs/asm-scanner.h", "src/asmjs/asm-types.h", "src/compiler/int64-lowering.h", + "src/compiler/wasm-compiler-definitions.h", "src/compiler/wasm-compiler.h", "src/compiler/wasm-escape-analysis.h", + "src/compiler/wasm-gc-lowering.h", + "src/compiler/wasm-gc-operator-reducer.h", + "src/compiler/wasm-graph-assembler.h", "src/compiler/wasm-inlining.h", "src/compiler/wasm-loop-peeling.h", + "src/compiler/wasm-typer.h", "src/debug/debug-wasm-objects-inl.h", "src/debug/debug-wasm-objects.h", + "src/third_party/utf8-decoder/generalized-utf8-decoder.h", "src/trap-handler/trap-handler-internal.h", "src/trap-handler/trap-handler.h", + "src/wasm/assembler-buffer-cache.h", "src/wasm/baseline/liftoff-assembler-defs.h", "src/wasm/baseline/liftoff-assembler.h", "src/wasm/baseline/liftoff-compiler.h", @@ -3520,29 +3608,36 @@ v8_header_set("v8_internal_headers") { "src/wasm/canonical-types.h", "src/wasm/code-space-access.h", "src/wasm/compilation-environment.h", + "src/wasm/constant-expression-interface.h", + "src/wasm/constant-expression.h", "src/wasm/decoder.h", "src/wasm/function-body-decoder-impl.h", "src/wasm/function-body-decoder.h", "src/wasm/function-compiler.h", "src/wasm/graph-builder-interface.h", - "src/wasm/init-expr-interface.h", "src/wasm/jump-table-assembler.h", "src/wasm/leb-helper.h", "src/wasm/local-decl-encoder.h", - "src/wasm/memory-protection-key.h", "src/wasm/memory-tracing.h", "src/wasm/module-compiler.h", + "src/wasm/module-decoder-impl.h", "src/wasm/module-decoder.h", "src/wasm/module-instantiate.h", + "src/wasm/names-provider.h", "src/wasm/object-access.h", "src/wasm/signature-map.h", "src/wasm/simd-shuffle.h", "src/wasm/stacks.h", "src/wasm/streaming-decoder.h", + "src/wasm/string-builder-multiline.h", + "src/wasm/string-builder.h", "src/wasm/struct-types.h", "src/wasm/value-type.h", "src/wasm/wasm-arguments.h", "src/wasm/wasm-code-manager.h", + "src/wasm/wasm-debug.h", + "src/wasm/wasm-disassembler-impl.h", + "src/wasm/wasm-disassembler.h", "src/wasm/wasm-engine.h", "src/wasm/wasm-external-refs.h", "src/wasm/wasm-feature-flags.h", @@ -3566,6 +3661,10 @@ v8_header_set("v8_internal_headers") { ] } + if (v8_enable_wasm_simd256_revec) { + sources += [ "src/compiler/linear-scheduler.h" ] + } + if (!v8_enable_third_party_heap) { sources += filter_include(v8_third_party_heap_files, [ "*.h" ]) } else { @@ -3607,8 +3706,12 @@ v8_header_set("v8_internal_headers") { } if (v8_enable_conservative_stack_scanning) { + sources += [ "src/heap/conservative-stack-visitor.h" ] + } + + if (v8_enable_inner_pointer_resolution_osb) { sources += [ - "src/heap/conservative-stack-visitor.h", + "src/heap/object-start-bitmap-inl.h", "src/heap/object-start-bitmap.h", ] } @@ -3744,22 +3847,6 @@ v8_header_set("v8_internal_headers") { if (is_win) { sources += [ "src/diagnostics/unwinding-info-win64.h" ] } - } else if (v8_current_cpu == "mips" || v8_current_cpu == "mipsel") { - sources += [ ### gcmole(arch:mipsel) ### - "src/baseline/mips/baseline-assembler-mips-inl.h", - "src/baseline/mips/baseline-compiler-mips-inl.h", - "src/codegen/mips/assembler-mips-inl.h", - "src/codegen/mips/assembler-mips.h", - "src/codegen/mips/constants-mips.h", - "src/codegen/mips/macro-assembler-mips.h", - "src/codegen/mips/register-mips.h", - "src/codegen/mips/reglist-mips.h", - "src/compiler/backend/mips/instruction-codes-mips.h", - "src/execution/mips/frame-constants-mips.h", - "src/execution/mips/simulator-mips.h", - "src/regexp/mips/regexp-macro-assembler-mips.h", - "src/wasm/baseline/mips/liftoff-assembler-mips.h", - ] } else if (v8_current_cpu == "mips64" || v8_current_cpu == "mips64el") { sources += [ ### gcmole(arch:mips64el) ### "src/baseline/mips64/baseline-assembler-mips64-inl.h", @@ -3846,20 +3933,81 @@ v8_header_set("v8_internal_headers") { ] } else if (v8_current_cpu == "riscv64") { sources += [ ### gcmole(arch:riscv64) ### - "src/baseline/riscv64/baseline-assembler-riscv64-inl.h", - "src/baseline/riscv64/baseline-compiler-riscv64-inl.h", - "src/codegen/riscv64/assembler-riscv64-inl.h", - "src/codegen/riscv64/assembler-riscv64.h", - "src/codegen/riscv64/constants-riscv64.h", - "src/codegen/riscv64/macro-assembler-riscv64.h", - "src/codegen/riscv64/register-riscv64.h", - "src/codegen/riscv64/reglist-riscv64.h", - "src/compiler/backend/riscv64/instruction-codes-riscv64.h", - "src/execution/riscv64/frame-constants-riscv64.h", - "src/execution/riscv64/simulator-riscv64.h", - "src/regexp/riscv64/regexp-macro-assembler-riscv64.h", + "src/baseline/riscv/baseline-assembler-riscv-inl.h", + "src/baseline/riscv/baseline-compiler-riscv-inl.h", + "src/codegen/riscv/assembler-riscv-inl.h", + "src/codegen/riscv/assembler-riscv-inl.h", + "src/codegen/riscv/assembler-riscv.h", + "src/codegen/riscv/base-assembler-riscv.h", + "src/codegen/riscv/base-constants-riscv.h", + "src/codegen/riscv/base-riscv-i.h", + "src/codegen/riscv/base-riscv-i.h", + "src/codegen/riscv/constant-riscv-a.h", + "src/codegen/riscv/constant-riscv-c.h", + "src/codegen/riscv/constant-riscv-d.h", + "src/codegen/riscv/constant-riscv-f.h", + "src/codegen/riscv/constant-riscv-m.h", + "src/codegen/riscv/constant-riscv-v.h", + "src/codegen/riscv/constant-riscv-zicsr.h", + "src/codegen/riscv/constant-riscv-zifencei.h", + "src/codegen/riscv/constants-riscv.h", + "src/codegen/riscv/extension-riscv-a.h", + "src/codegen/riscv/extension-riscv-c.h", + "src/codegen/riscv/extension-riscv-d.h", + "src/codegen/riscv/extension-riscv-d.h", + "src/codegen/riscv/extension-riscv-inl.h", + "src/codegen/riscv/extension-riscv-m.h", + "src/codegen/riscv/extension-riscv-v.h", + "src/codegen/riscv/extension-riscv-zicsr.h", + "src/codegen/riscv/extension-riscv-zifencei.h", + "src/codegen/riscv/interface-descriptors-riscv-inl.h", + "src/codegen/riscv/macro-assembler-riscv.h", + "src/codegen/riscv/register-riscv.h", + "src/codegen/riscv/reglist-riscv.h", + "src/compiler/backend/riscv/instruction-codes-riscv.h", + "src/execution/riscv/frame-constants-riscv.h", + "src/execution/riscv/simulator-riscv.h", + "src/regexp/riscv/regexp-macro-assembler-riscv.h", "src/wasm/baseline/riscv64/liftoff-assembler-riscv64.h", ] + } else if (v8_current_cpu == "riscv32") { + sources += [ ### gcmole(arch:riscv32) ### + "src/baseline/riscv/baseline-assembler-riscv-inl.h", + "src/baseline/riscv/baseline-compiler-riscv-inl.h", + "src/codegen/riscv/assembler-riscv.h", + "src/codegen/riscv/assembler-riscv32-inl.h", + "src/codegen/riscv/base-assembler-riscv.h", + "src/codegen/riscv/base-constants-riscv.h", + "src/codegen/riscv/base-riscv-i.h", + "src/codegen/riscv/constant-riscv-a.h", + "src/codegen/riscv/constant-riscv-c.h", + "src/codegen/riscv/constant-riscv-d.h", + "src/codegen/riscv/constant-riscv-f.h", + "src/codegen/riscv/constant-riscv-i.h", + "src/codegen/riscv/constant-riscv-m.h", + "src/codegen/riscv/constant-riscv-v.h", + "src/codegen/riscv/constant-riscv-zicsr.h", + "src/codegen/riscv/constant-riscv-zifencei.h", + "src/codegen/riscv/constants-riscv.h", + "src/codegen/riscv/extension-riscv-a.h", + "src/codegen/riscv/extension-riscv-c.h", + "src/codegen/riscv/extension-riscv-d.h", + "src/codegen/riscv/extension-riscv-f.h", + "src/codegen/riscv/extension-riscv-inl.h", + "src/codegen/riscv/extension-riscv-m.h", + "src/codegen/riscv/extension-riscv-v.h", + "src/codegen/riscv/extension-riscv-zicsr.h", + "src/codegen/riscv/extension-riscv-zifencei.h", + "src/codegen/riscv/interface-descriptors-riscv-inl.h", + "src/codegen/riscv/macro-assembler-riscv.h", + "src/codegen/riscv/register-riscv.h", + "src/codegen/riscv/reglist-riscv.h", + "src/compiler/backend/riscv/instruction-codes-riscv.h", + "src/execution/riscv/frame-constants-riscv.h", + "src/execution/riscv/simulator-riscv.h", + "src/regexp/riscv/regexp-macro-assembler-riscv.h", + "src/wasm/baseline/riscv32/liftoff-assembler-riscv32.h", + ] } public_deps = [ @@ -3943,6 +4091,7 @@ v8_compiler_sources = [ "src/compiler/js-operator.cc", "src/compiler/js-type-hint-lowering.cc", "src/compiler/js-typed-lowering.cc", + "src/compiler/late-escape-analysis.cc", "src/compiler/linkage.cc", "src/compiler/load-elimination.cc", "src/compiler/loop-analysis.cc", @@ -3991,6 +4140,8 @@ v8_compiler_sources = [ "src/compiler/value-numbering-reducer.cc", "src/compiler/verifier.cc", "src/compiler/zone-stats.cc", + "src/utils/hex-format.cc", + "src/utils/sha-256.cc", ] if (v8_enable_webassembly) { @@ -3998,11 +4149,19 @@ if (v8_enable_webassembly) { "src/compiler/int64-lowering.cc", "src/compiler/wasm-compiler.cc", "src/compiler/wasm-escape-analysis.cc", + "src/compiler/wasm-gc-lowering.cc", + "src/compiler/wasm-gc-operator-reducer.cc", + "src/compiler/wasm-graph-assembler.cc", "src/compiler/wasm-inlining.cc", "src/compiler/wasm-loop-peeling.cc", + "src/compiler/wasm-typer.cc", ] } +if (v8_enable_wasm_simd256_revec) { + v8_compiler_sources += [ "src/compiler/linear-scheduler.cc" ] +} + # The src/compiler files with optimizations. v8_source_set("v8_compiler_opt") { visibility = [ ":*" ] # Only targets in this file can depend on this. @@ -4026,7 +4185,7 @@ v8_source_set("v8_compiler_opt") { if (is_debug && !v8_optimized_debug && v8_enable_fast_mksnapshot) { # The :no_optimize config is added to v8_add_configs in v8.gni. remove_configs = [ "//build/config/compiler:no_optimize" ] - configs = [ ":always_optimize" ] + configs = [ ":always_turbofanimize" ] } else { # Without this else branch, gn fails to generate build files for non-debug # builds (because we try to remove a config that is not present). @@ -4058,6 +4217,37 @@ v8_source_set("v8_compiler") { configs = [ ":internal_config" ] } +# The src/compiler files with default optimization behavior. +v8_source_set("v8_turboshaft") { + visibility = [ ":*" ] # Only targets in this file can depend on this. + + sources = [ + "src/compiler/turboshaft/decompression-optimization.cc", + "src/compiler/turboshaft/graph-builder.cc", + "src/compiler/turboshaft/graph-visualizer.cc", + "src/compiler/turboshaft/graph.cc", + "src/compiler/turboshaft/operations.cc", + "src/compiler/turboshaft/optimization-phase.cc", + "src/compiler/turboshaft/recreate-schedule.cc", + ] + + public_deps = [ + ":generate_bytecode_builtins_list", + ":run_torque", + ":v8_internal_headers", + ":v8_maybe_icu", + ":v8_tracing", + ] + + deps = [ + ":v8_base_without_compiler", + ":v8_libbase", + ":v8_shared_internal_headers", + ] + + configs = [ ":internal_config" ] +} + group("v8_compiler_for_mksnapshot") { if (is_debug && !v8_optimized_debug && v8_enable_fast_mksnapshot) { deps = [ ":v8_compiler_opt" ] @@ -4106,6 +4296,7 @@ v8_source_set("v8_base_without_compiler") { "src/builtins/builtins-array.cc", "src/builtins/builtins-arraybuffer.cc", "src/builtins/builtins-async-module.cc", + "src/builtins/builtins-atomics-synchronization.cc", "src/builtins/builtins-bigint.cc", "src/builtins/builtins-callsite.cc", "src/builtins/builtins-collections.cc", @@ -4122,7 +4313,8 @@ v8_source_set("v8_base_without_compiler") { "src/builtins/builtins-object.cc", "src/builtins/builtins-reflect.cc", "src/builtins/builtins-regexp.cc", - "src/builtins/builtins-shadow-realms.cc", + "src/builtins/builtins-shadow-realm.cc", + "src/builtins/builtins-shared-array.cc", "src/builtins/builtins-sharedarraybuffer.cc", "src/builtins/builtins-string.cc", "src/builtins/builtins-struct.cc", @@ -4131,6 +4323,7 @@ v8_source_set("v8_base_without_compiler") { "src/builtins/builtins-trace.cc", "src/builtins/builtins-typed-array.cc", "src/builtins/builtins-weak-refs.cc", + "src/builtins/builtins-web-snapshots.cc", "src/builtins/builtins.cc", "src/builtins/constants-table-builder.cc", "src/codegen/aligned-slot-allocator.cc", @@ -4150,6 +4343,7 @@ v8_source_set("v8_base_without_compiler") { "src/codegen/handler-table.cc", "src/codegen/interface-descriptors.cc", "src/codegen/machine-type.cc", + "src/codegen/maglev-safepoint-table.cc", "src/codegen/optimized-compilation-info.cc", "src/codegen/pending-optimization-table.cc", "src/codegen/register-configuration.cc", @@ -4157,12 +4351,12 @@ v8_source_set("v8_base_without_compiler") { "src/codegen/safepoint-table.cc", "src/codegen/source-position-table.cc", "src/codegen/source-position.cc", - "src/codegen/string-constants.cc", "src/codegen/tick-counter.cc", "src/codegen/tnode.cc", "src/codegen/turbo-assembler.cc", "src/codegen/unoptimized-compilation-info.cc", "src/common/assert-scope.cc", + "src/common/code-memory-access.cc", "src/compiler-dispatcher/lazy-compile-dispatcher.cc", "src/compiler-dispatcher/optimizing-compile-dispatcher.cc", "src/date/date.cc", @@ -4177,6 +4371,7 @@ v8_source_set("v8_base_without_compiler") { "src/debug/debug-stack-trace-iterator.cc", "src/debug/debug-type-profile.cc", "src/debug/debug.cc", + "src/debug/liveedit-diff.cc", "src/debug/liveedit.cc", "src/deoptimizer/deoptimize-reason.cc", "src/deoptimizer/deoptimized-frame-info.cc", @@ -4223,6 +4418,7 @@ v8_source_set("v8_base_without_compiler") { "src/handles/handles.cc", "src/handles/local-handles.cc", "src/handles/persistent-handles.cc", + "src/handles/shared-object-conveyor-handles.cc", "src/heap/allocation-observer.cc", "src/heap/array-buffer-sweeper.cc", "src/heap/base-space.cc", @@ -4246,9 +4442,11 @@ v8_source_set("v8_base_without_compiler") { "src/heap/free-list.cc", "src/heap/gc-idle-time-handler.cc", "src/heap/gc-tracer.cc", + "src/heap/global-handle-marking-visitor.cc", "src/heap/heap-allocator.cc", "src/heap/heap-controller.cc", "src/heap/heap-layout-tracer.cc", + "src/heap/heap-verifier.cc", "src/heap/heap-write-barrier.cc", "src/heap/heap.cc", "src/heap/incremental-marking-job.cc", @@ -4316,7 +4514,7 @@ v8_source_set("v8_base_without_compiler") { "src/libsampler/sampler.cc", "src/logging/counters.cc", "src/logging/local-logger.cc", - "src/logging/log-utils.cc", + "src/logging/log-file.cc", "src/logging/log.cc", "src/logging/metrics.cc", "src/logging/runtime-call-stats.cc", @@ -4338,6 +4536,7 @@ v8_source_set("v8_base_without_compiler") { "src/objects/field-type.cc", "src/objects/intl-objects.cc", "src/objects/js-array-buffer.cc", + "src/objects/js-atomics-synchronization.cc", "src/objects/js-break-iterator.cc", "src/objects/js-collator.cc", "src/objects/js-date-time-format.cc", @@ -4366,13 +4565,14 @@ v8_source_set("v8_base_without_compiler") { "src/objects/objects.cc", "src/objects/option-utils.cc", "src/objects/ordered-hash-table.cc", - "src/objects/osr-optimized-code-cache.cc", "src/objects/property-descriptor.cc", "src/objects/property.cc", "src/objects/scope-info.cc", "src/objects/shared-function-info.cc", + "src/objects/simd.cc", "src/objects/source-text-module.cc", "src/objects/string-comparator.cc", + "src/objects/string-forwarding-table.cc", "src/objects/string-table.cc", "src/objects/string.cc", "src/objects/swiss-name-dictionary.cc", @@ -4458,6 +4658,7 @@ v8_source_set("v8_base_without_compiler") { "src/runtime/runtime-shadow-realm.cc", "src/runtime/runtime-strings.cc", "src/runtime/runtime-symbol.cc", + "src/runtime/runtime-temporal.cc", "src/runtime/runtime-test.cc", "src/runtime/runtime-trace.cc", "src/runtime/runtime-typedarray.cc", @@ -4465,6 +4666,7 @@ v8_source_set("v8_base_without_compiler") { "src/runtime/runtime.cc", "src/sandbox/external-pointer-table.cc", "src/sandbox/sandbox.cc", + "src/sandbox/testing.cc", "src/snapshot/code-serializer.cc", "src/snapshot/context-deserializer.cc", "src/snapshot/context-serializer.cc", @@ -4478,7 +4680,6 @@ v8_source_set("v8_base_without_compiler") { "src/snapshot/serializer.cc", "src/snapshot/shared-heap-deserializer.cc", "src/snapshot/shared-heap-serializer.cc", - "src/snapshot/snapshot-compression.cc", "src/snapshot/snapshot-data.cc", "src/snapshot/snapshot-source-sink.cc", "src/snapshot/snapshot-utils.cc", @@ -4517,6 +4718,10 @@ v8_source_set("v8_base_without_compiler") { "src/zone/zone.cc", ] + if (v8_enable_snapshot_compression) { + sources += [ "src/snapshot/snapshot-compression.cc" ] + } + if (v8_enable_maglev) { sources += [ "src/maglev/maglev-code-generator.cc", @@ -4526,6 +4731,7 @@ v8_source_set("v8_base_without_compiler") { "src/maglev/maglev-concurrent-dispatcher.cc", "src/maglev/maglev-graph-builder.cc", "src/maglev/maglev-graph-printer.cc", + "src/maglev/maglev-interpreter-frame-state.cc", "src/maglev/maglev-ir.cc", "src/maglev/maglev-regalloc.cc", "src/maglev/maglev.cc", @@ -4544,29 +4750,32 @@ v8_source_set("v8_base_without_compiler") { "src/trap-handler/handler-inside.cc", "src/trap-handler/handler-outside.cc", "src/trap-handler/handler-shared.cc", + "src/wasm/assembler-buffer-cache.cc", "src/wasm/baseline/liftoff-assembler.cc", "src/wasm/baseline/liftoff-compiler.cc", "src/wasm/canonical-types.cc", "src/wasm/code-space-access.cc", + "src/wasm/constant-expression-interface.cc", + "src/wasm/constant-expression.cc", "src/wasm/function-body-decoder.cc", "src/wasm/function-compiler.cc", "src/wasm/graph-builder-interface.cc", - "src/wasm/init-expr-interface.cc", "src/wasm/jump-table-assembler.cc", "src/wasm/local-decl-encoder.cc", - "src/wasm/memory-protection-key.cc", "src/wasm/memory-tracing.cc", "src/wasm/module-compiler.cc", "src/wasm/module-decoder.cc", "src/wasm/module-instantiate.cc", + "src/wasm/names-provider.cc", "src/wasm/signature-map.cc", "src/wasm/simd-shuffle.cc", + "src/wasm/stacks.cc", "src/wasm/streaming-decoder.cc", "src/wasm/sync-streaming-decoder.cc", "src/wasm/value-type.cc", "src/wasm/wasm-code-manager.cc", "src/wasm/wasm-debug.cc", - "src/wasm/wasm-debug.h", + "src/wasm/wasm-disassembler.cc", "src/wasm/wasm-engine.cc", "src/wasm/wasm-external-refs.cc", "src/wasm/wasm-features.cc", @@ -4729,23 +4938,6 @@ v8_source_set("v8_base_without_compiler") { if (is_win) { sources += [ "src/diagnostics/unwinding-info-win64.cc" ] } - } else if (v8_current_cpu == "mips" || v8_current_cpu == "mipsel") { - sources += [ ### gcmole(arch:mipsel) ### - "src/codegen/mips/assembler-mips.cc", - "src/codegen/mips/constants-mips.cc", - "src/codegen/mips/cpu-mips.cc", - "src/codegen/mips/interface-descriptors-mips-inl.h", - "src/codegen/mips/macro-assembler-mips.cc", - "src/compiler/backend/mips/code-generator-mips.cc", - "src/compiler/backend/mips/instruction-scheduler-mips.cc", - "src/compiler/backend/mips/instruction-selector-mips.cc", - "src/deoptimizer/mips/deoptimizer-mips.cc", - "src/diagnostics/mips/disasm-mips.cc", - "src/diagnostics/mips/unwinder-mips.cc", - "src/execution/mips/frame-constants-mips.cc", - "src/execution/mips/simulator-mips.cc", - "src/regexp/mips/regexp-macro-assembler-mips.cc", - ] } else if (v8_current_cpu == "mips64" || v8_current_cpu == "mips64el") { sources += [ ### gcmole(arch:mips64el) ### "src/codegen/mips64/assembler-mips64.cc", @@ -4836,33 +5028,64 @@ v8_source_set("v8_base_without_compiler") { ] } else if (v8_current_cpu == "riscv64") { sources += [ ### gcmole(arch:riscv64) ### - "src/baseline/riscv64/baseline-assembler-riscv64-inl.h", - "src/baseline/riscv64/baseline-compiler-riscv64-inl.h", - "src/codegen/riscv64/assembler-riscv64-inl.h", - "src/codegen/riscv64/assembler-riscv64.cc", - "src/codegen/riscv64/constants-riscv64.cc", - "src/codegen/riscv64/cpu-riscv64.cc", - "src/codegen/riscv64/interface-descriptors-riscv64-inl.h", - "src/codegen/riscv64/macro-assembler-riscv64.cc", - "src/compiler/backend/riscv64/code-generator-riscv64.cc", - "src/compiler/backend/riscv64/instruction-scheduler-riscv64.cc", - "src/compiler/backend/riscv64/instruction-selector-riscv64.cc", - "src/deoptimizer/riscv64/deoptimizer-riscv64.cc", - "src/diagnostics/riscv64/disasm-riscv64.cc", - "src/diagnostics/riscv64/unwinder-riscv64.cc", - "src/execution/riscv64/frame-constants-riscv64.cc", - "src/execution/riscv64/simulator-riscv64.cc", - "src/regexp/riscv64/regexp-macro-assembler-riscv64.cc", + "src/codegen/riscv/assembler-riscv.cc", + "src/codegen/riscv/base-assembler-riscv.cc", + "src/codegen/riscv/base-constants-riscv.cc", + "src/codegen/riscv/base-riscv-i.cc", + "src/codegen/riscv/cpu-riscv.cc", + "src/codegen/riscv/extension-riscv-a.cc", + "src/codegen/riscv/extension-riscv-c.cc", + "src/codegen/riscv/extension-riscv-d.cc", + "src/codegen/riscv/extension-riscv-f.cc", + "src/codegen/riscv/extension-riscv-m.cc", + "src/codegen/riscv/extension-riscv-v.cc", + "src/codegen/riscv/extension-riscv-zicsr.cc", + "src/codegen/riscv/extension-riscv-zifencei.cc", + "src/codegen/riscv/macro-assembler-riscv.cc", + "src/compiler/backend/riscv/code-generator-riscv.cc", + "src/compiler/backend/riscv/instruction-scheduler-riscv.cc", + "src/compiler/backend/riscv/instruction-selector-riscv64.cc", + "src/deoptimizer/riscv/deoptimizer-riscv.cc", + "src/diagnostics/riscv/disasm-riscv.cc", + "src/diagnostics/riscv/unwinder-riscv.cc", + "src/execution/riscv/frame-constants-riscv.cc", + "src/execution/riscv/simulator-riscv.cc", + "src/regexp/riscv/regexp-macro-assembler-riscv.cc", + ] + } else if (v8_current_cpu == "riscv32") { + sources += [ ### gcmole(arch:riscv32) ### + "src/codegen/riscv/assembler-riscv.cc", + "src/codegen/riscv/base-assembler-riscv.cc", + "src/codegen/riscv/base-constants-riscv.cc", + "src/codegen/riscv/base-riscv-i.cc", + "src/codegen/riscv/cpu-riscv.cc", + "src/codegen/riscv/extension-riscv-a.cc", + "src/codegen/riscv/extension-riscv-c.cc", + "src/codegen/riscv/extension-riscv-d.cc", + "src/codegen/riscv/extension-riscv-f.cc", + "src/codegen/riscv/extension-riscv-m.cc", + "src/codegen/riscv/extension-riscv-v.cc", + "src/codegen/riscv/extension-riscv-zicsr.cc", + "src/codegen/riscv/extension-riscv-zifencei.cc", + "src/codegen/riscv/macro-assembler-riscv.cc", + "src/compiler/backend/riscv/code-generator-riscv.cc", + "src/compiler/backend/riscv/instruction-scheduler-riscv.cc", + "src/compiler/backend/riscv/instruction-selector-riscv32.cc", + "src/deoptimizer/riscv/deoptimizer-riscv.cc", + "src/diagnostics/riscv/disasm-riscv.cc", + "src/diagnostics/riscv/unwinder-riscv.cc", + "src/execution/riscv/frame-constants-riscv.cc", + "src/execution/riscv/simulator-riscv.cc", + "src/regexp/riscv/regexp-macro-assembler-riscv.cc", ] } # Architecture independent but platform-specific sources if (is_win) { - if (v8_enable_system_instrumentation) { + if (v8_enable_etw_stack_walking) { sources += [ - "src/diagnostics/system-jit-metadata-win.h", - "src/diagnostics/system-jit-win.cc", - "src/diagnostics/system-jit-win.h", + "src/diagnostics/etw-jit-win.cc", + "src/diagnostics/etw-jit-win.h", ] } } @@ -4920,10 +5143,12 @@ v8_source_set("v8_base_without_compiler") { ] } - deps += [ - "//third_party/zlib", - "//third_party/zlib/google:compression_utils_portable", - ] + if (v8_use_zlib) { + deps += [ + "//third_party/zlib", + "//third_party/zlib/google:compression_utils_portable", + ] + } if (v8_postmortem_support) { sources += [ "$target_gen_dir/debug-support.cc" ] @@ -4938,11 +5163,10 @@ v8_source_set("v8_base_without_compiler") { # Platforms that don't have CAS support need to link atomic library # to implement atomic memory access - if (v8_current_cpu == "mips" || v8_current_cpu == "mipsel" || - v8_current_cpu == "mips64" || v8_current_cpu == "mips64el" || + if (v8_current_cpu == "mips64" || v8_current_cpu == "mips64el" || v8_current_cpu == "ppc" || v8_current_cpu == "ppc64" || v8_current_cpu == "s390" || v8_current_cpu == "s390x" || - v8_current_cpu == "riscv64") { + v8_current_cpu == "riscv64" || v8_current_cpu == "riscv32") { libs += [ "atomic" ] } @@ -4966,6 +5190,7 @@ group("v8_base") { public_deps = [ ":v8_base_without_compiler", ":v8_compiler", + ":v8_turboshaft", ] } @@ -5057,7 +5282,7 @@ v8_source_set("torque_base") { if (is_debug && !v8_optimized_debug && v8_enable_fast_torque) { # The :no_optimize config is added to v8_add_configs in v8.gni. remove_configs += [ "//build/config/compiler:no_optimize" ] - configs += [ ":always_optimize" ] + configs += [ ":always_turbofanimize" ] } } @@ -5101,7 +5326,6 @@ v8_component("v8_libbase") { "src/base/address-region.h", "src/base/atomic-utils.h", "src/base/atomicops.h", - "src/base/atomicops_internals_atomicword_compat.h", "src/base/base-export.h", "src/base/bit-field.h", "src/base/bits-iterator.h", @@ -5112,6 +5336,7 @@ v8_component("v8_libbase") { "src/base/bounds.h", "src/base/build_config.h", "src/base/compiler-specific.h", + "src/base/container-utils.h", "src/base/cpu.cc", "src/base/cpu.h", "src/base/debug/stack_trace.cc", @@ -5126,7 +5351,6 @@ v8_component("v8_libbase") { "src/base/file-utils.h", "src/base/flags.h", "src/base/free_deleter.h", - "src/base/functional.cc", "src/base/functional.h", "src/base/hashmap-entry.h", "src/base/hashmap.h", @@ -5165,6 +5389,9 @@ v8_component("v8_libbase") { "src/base/platform/condition-variable.cc", "src/base/platform/condition-variable.h", "src/base/platform/elapsed-timer.h", + "src/base/platform/memory-protection-key.cc", + "src/base/platform/memory-protection-key.h", + "src/base/platform/memory.h", "src/base/platform/mutex.cc", "src/base/platform/mutex.h", "src/base/platform/platform.h", @@ -5190,6 +5417,7 @@ v8_component("v8_libbase") { "src/base/sanitizer/msan.h", "src/base/sanitizer/tsan.h", "src/base/small-vector.h", + "src/base/string-format.h", "src/base/strings.cc", "src/base/strings.h", "src/base/sys-info.cc", @@ -5243,6 +5471,7 @@ v8_component("v8_libbase") { sources += [ "src/base/debug/stack_trace_posix.cc", "src/base/platform/platform-linux.cc", + "src/base/platform/platform-linux.h", ] libs = [ @@ -5317,14 +5546,14 @@ v8_component("v8_libbase") { "ws2_32.lib", ] - if (v8_enable_system_instrumentation) { + if (v8_enable_etw_stack_walking) { libs += [ "advapi32.lib" ] # Needed for TraceLoggingProvider.h } data_deps += [ "//build/win:runtime_libs" ] } - if (v8_current_cpu == "mips" || v8_current_cpu == "mips64") { + if (v8_current_cpu == "mips64") { # Add runtime libs for mips. data += [ "tools/mips_toolchain/sysroot/usr/lib/", @@ -5332,13 +5561,12 @@ v8_component("v8_libbase") { ] } - if (is_ubsan && (v8_current_cpu == "x86" || v8_current_cpu == "arm" || - v8_current_cpu == "mips")) { + if (is_ubsan && (v8_current_cpu == "x86" || v8_current_cpu == "arm")) { # Special UBSan 32-bit requirement. sources += [ "src/base/ubsan.cc" ] } - if (v8_current_cpu == "riscv64") { + if (v8_current_cpu == "riscv64" || v8_current_cpu == "riscv32") { libs += [ "atomic" ] } @@ -5427,7 +5655,7 @@ v8_component("v8_libplatform") { } } - if (v8_current_cpu == "riscv64") { + if (v8_current_cpu == "riscv64" || v8_current_cpu == "riscv32") { libs = [ "atomic" ] } } @@ -5481,7 +5709,7 @@ v8_source_set("v8_bigint") { configs = [ ":internal_config" ] } -v8_source_set("v8_heap_base_headers") { +v8_header_set("v8_heap_base_headers") { sources = [ "src/heap/base/active-system-pages.h", "src/heap/base/stack.h", @@ -5513,20 +5741,18 @@ v8_source_set("v8_heap_base") { sources += [ "src/heap/base/asm/ppc/push_registers_asm.cc" ] } else if (current_cpu == "s390x") { sources += [ "src/heap/base/asm/s390/push_registers_asm.cc" ] - } else if (current_cpu == "mipsel") { - sources += [ "src/heap/base/asm/mips/push_registers_asm.cc" ] } else if (current_cpu == "mips64el") { sources += [ "src/heap/base/asm/mips64/push_registers_asm.cc" ] } else if (current_cpu == "loong64") { sources += [ "src/heap/base/asm/loong64/push_registers_asm.cc" ] - } else if (current_cpu == "riscv64") { - sources += [ "src/heap/base/asm/riscv64/push_registers_asm.cc" ] + } else if (current_cpu == "riscv64" || current_cpu == "riscv32") { + sources += [ "src/heap/base/asm/riscv/push_registers_asm.cc" ] } } else if (is_win) { if (current_cpu == "x64") { - sources += [ "src/heap/base/asm/x64/push_registers_masm.S" ] + sources += [ "src/heap/base/asm/x64/push_registers_masm.asm" ] } else if (current_cpu == "x86") { - sources += [ "src/heap/base/asm/ia32/push_registers_masm.S" ] + sources += [ "src/heap/base/asm/ia32/push_registers_masm.asm" ] } else if (current_cpu == "arm64") { sources += [ "src/heap/base/asm/arm64/push_registers_masm.S" ] } @@ -5559,14 +5785,17 @@ v8_header_set("cppgc_headers") { "include/cppgc/explicit-management.h", "include/cppgc/garbage-collected.h", "include/cppgc/heap-consistency.h", + "include/cppgc/heap-handle.h", "include/cppgc/heap-state.h", "include/cppgc/heap-statistics.h", "include/cppgc/heap.h", "include/cppgc/internal/api-constants.h", "include/cppgc/internal/atomic-entry-flag.h", + "include/cppgc/internal/base-page-handle.h", "include/cppgc/internal/compiler-specific.h", "include/cppgc/internal/finalizer-trait.h", "include/cppgc/internal/gc-info.h", + "include/cppgc/internal/member-storage.h", "include/cppgc/internal/name-trait.h", "include/cppgc/internal/persistent-node.h", "include/cppgc/internal/pointer-policies.h", @@ -5593,6 +5822,7 @@ v8_header_set("cppgc_headers") { if (cppgc_enable_caged_heap) { sources += [ "include/cppgc/internal/caged-heap-local-data.h" ] + sources += [ "include/cppgc/internal/caged-heap.h" ] } deps = [ @@ -5656,6 +5886,8 @@ v8_source_set("cppgc_base") { "src/heap/cppgc/marking-visitor.h", "src/heap/cppgc/marking-worklists.cc", "src/heap/cppgc/marking-worklists.h", + "src/heap/cppgc/member-storage.cc", + "src/heap/cppgc/member-storage.h", "src/heap/cppgc/memory.cc", "src/heap/cppgc/memory.h", "src/heap/cppgc/metric-recorder.h", @@ -5874,6 +6106,7 @@ if (current_toolchain == v8_snapshot_toolchain) { ":v8_maybe_icu", ":v8_shared_internal_headers", ":v8_tracing", + ":v8_turboshaft", "//build/win:default_exe_manifest", ] } @@ -6043,6 +6276,14 @@ group("v8_clusterfuzz") { } } +# Targets we ensure work with gcc. The aim is to keep this list small to have +# a fast overall compile time. +group("v8_gcc_light") { + testonly = true + + deps = [ ":d8" ] +} + group("v8_archive") { testonly = true @@ -6057,19 +6298,26 @@ group("v8_archive") { # TODO(dglazkov): Remove the "!build_with_chromium" condition once this clause # is removed from Chromium. if (is_fuchsia && !build_with_chromium) { - import("//build/config/fuchsia/rules.gni") + import("//build/config/fuchsia/generate_runner_scripts.gni") + import("//third_party/fuchsia-sdk/sdk/build/component.gni") + import("//third_party/fuchsia-sdk/sdk/build/package.gni") - cr_fuchsia_package("d8_fuchsia_pkg") { + fuchsia_component("d8_component") { testonly = true - binary = ":d8" - manifest = "gni/v8.cmx" - package_name_override = "d8" + manifest = "gni/v8.cml" + data_deps = [ ":d8" ] } - fuchsia_package_runner("d8_fuchsia") { + fuchsia_package("d8_pkg") { testonly = true - package = ":d8_fuchsia_pkg" - package_name_override = "d8" + package_name = "d8" + deps = [ ":d8_component" ] + } + + fuchsia_package_installer("d8_fuchsia") { + testonly = true + package = ":d8_pkg" + package_name = "d8" } } @@ -6090,6 +6338,7 @@ group("v8_fuzzers") { ":v8_simple_wasm_code_fuzzer", ":v8_simple_wasm_compile_fuzzer", ":v8_simple_wasm_fuzzer", + ":v8_simple_wasm_streaming_fuzzer", ] } } @@ -6311,6 +6560,10 @@ if (want_v8_shell) { ":internal_config_base", ] + if (is_win && !v8_enable_cet_shadow_stack) { + v8_remove_configs += [ "//build/config/compiler:cet_shadow_stack" ] + } + deps = [ ":v8", ":v8_libbase", @@ -6323,7 +6576,7 @@ if (want_v8_shell) { v8_executable("cppgc_hello_world") { sources = [ "samples/cppgc/hello-world.cc" ] - if (v8_current_cpu == "riscv64") { + if (v8_current_cpu == "riscv64" || v8_current_cpu == "riscv32") { libs = [ "atomic" ] } @@ -6560,6 +6813,24 @@ if (v8_enable_webassembly) { v8_fuzzer("wasm_compile_fuzzer") { } + + v8_source_set("wasm_streaming_fuzzer") { + sources = [ "test/fuzzer/wasm-streaming.cc" ] + + deps = [ + ":fuzzer_support", + ":lib_wasm_fuzzer_common", + ":wasm_test_common", + ] + + configs = [ + ":external_config", + ":internal_config_base", + ] + } + + v8_fuzzer("wasm_streaming_fuzzer") { + } } v8_source_set("inspector_fuzzer") { diff --git a/deps/v8/DEPS b/deps/v8/DEPS index 54ac85a4bdbb8a..595c243abcc602 100644 --- a/deps/v8/DEPS +++ b/deps/v8/DEPS @@ -12,17 +12,20 @@ vars = { # Fetches only the SDK boot images which match at least one of the whitelist # entries in a comma-separated list. # - # Only the X64 and ARM64 QEMU images are downloaded by default. Developers - # that need to boot on other target architectures or devices can opt to - # download more boot images. Example of images include: + # Available images: + # Emulation: + # - qemu.x64 (pulls terminal.qemu-x64-release) + # - qemu.arm64 (pulls terminal.qemu-arm64-release) + # - workstation.qemu-x64-release + # Hardware: + # - generic.x64 (pulls terminal.x64-debug) + # - generic.arm64 (pulls terminal.arm64-debug) + # - chromebook.x64 (pulls terminal.chromebook-x64-debug) # - # Emulation: - # qemu.x64, qemu.arm64 - # Hardware: - # generic.x64, generic.arm64 - # - # Wildcards are supported (e.g. "qemu.*"). - 'checkout_fuchsia_boot_images': "qemu.x64,qemu.arm64", + # Since the images are hundreds of MB, default to only downloading the image + # most commonly useful for developers. Bots and developers that need to use + # other images (e.g., qemu.arm64) can override this with additional images. + 'checkout_fuchsia_boot_images': "qemu.x64", 'checkout_instrumented_libraries': False, 'checkout_ittapi': False, @@ -36,27 +39,35 @@ vars = { 'check_v8_header_includes': False, 'checkout_reclient': False, + # By default, download the fuchsia sdk from the public sdk directory. + 'fuchsia_sdk_cipd_prefix': 'fuchsia/sdk/gn/', + # reclient CIPD package version - 'reclient_version': 're_client_version:0.40.0.40ff5a5', + 'reclient_version': 're_client_version:0.69.0.458df98-gomaip', # GN CIPD package version. - 'gn_version': 'git_revision:ae110f8b525009255ba1f9ae96982176d3bfad3d', + 'gn_version': 'git_revision:b4851eb2062f76a880c07f7fa0d12913beb6d79e', # luci-go CIPD package version. - 'luci_go': 'git_revision:6da0608e4fa8a3c6d1fa4f855485c0038b05bf72', + 'luci_go': 'git_revision:c93fd3c5ebdc3999eea86a7623dbd1ed4b40bc78', + + # Three lines of non-changing comments so that + # the commit queue can handle CLs rolling Fuchsia sdk + # and whatever else without interference from each other. + 'fuchsia_version': 'version:9.20220913.3.1', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling android_sdk_build-tools_version # and whatever else without interference from each other. - 'android_sdk_build-tools_version': 'tRoD45SCi7UleQqSV7MrMQO1_e5P8ysphkCcj6z_cCQC', + 'android_sdk_build-tools_version': '-VRKr36Uw8L_iFqqo9nevIBgNMggND5iWxjidyjnCgsC', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling android_sdk_emulator_version # and whatever else without interference from each other. - 'android_sdk_emulator_version': 'gMHhUuoQRKfxr-MBn3fNNXZtkAVXtOwMwT7kfx8jkIgC', + 'android_sdk_emulator_version': '9lGp8nTUCRRWGMnI_96HcKfzjnxEJKUcfvfwmA3wXNkC', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling android_sdk_extras_version # and whatever else without interference from each other. - 'android_sdk_extras_version': 'ppQ4TnqDvBHQ3lXx5KPq97egzF5X2FFyOrVHkGmiTMQC', + 'android_sdk_extras_version': 'bY55nDqO6FAm6FkGIj09sh2KW9oqAkCGKjYok5nUvBMC', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling android_sdk_patcher_version # and whatever else without interference from each other. @@ -64,39 +75,39 @@ vars = { # Three lines of non-changing comments so that # the commit queue can handle CLs rolling android_sdk_platform-tools_version # and whatever else without interference from each other. - 'android_sdk_platform-tools_version': 'g7n_-r6yJd_SGRklujGB1wEt8iyr77FZTUJVS9w6O34C', + 'android_sdk_platform-tools_version': 'RSI3iwryh7URLGRgJHsCvUxj092woTPnKt4pwFcJ6L8C', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling android_sdk_platforms_version # and whatever else without interference from each other. - 'android_sdk_platforms_version': 'lL3IGexKjYlwjO_1Ga-xwxgwbE_w-lmi2Zi1uOlWUIAC', + 'android_sdk_platforms_version': 'eo5KvW6UVor92LwZai8Zulc624BQZoCu-yn7wa1z_YcC', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling android_sdk_sources_version # and whatever else without interference from each other. - 'android_sdk_sources_version': '7EcXjyZWkTu3sCA8d8eRXg_aCBCYt8ihXgxp29VXLs8C', + 'android_sdk_sources_version': 'qfTSF99e29-w3eIVPpfcif0Em5etyvxuicTDTntWHQMC', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling android_sdk_tools-lint_version # and whatever else without interference from each other. - 'android_sdk_cmdline-tools_version': 'PGPmqJtSIQ84If155ba7iTU846h5WJ-bL5d_OoUWEWYC', + 'android_sdk_cmdline-tools_version': 'IPzAG-uU5zVMxohpg9-7-N0tQC1TCSW1VbrBFw7Ld04C', } deps = { 'base/trace_event/common': - Var('chromium_url') + '/chromium/src/base/trace_event/common.git' + '@' + 'd115b033c4e53666b535cbd1985ffe60badad082', + Var('chromium_url') + '/chromium/src/base/trace_event/common.git' + '@' + '521ac34ebd795939c7e16b37d9d3ddb40e8ed556', 'build': - Var('chromium_url') + '/chromium/src/build.git' + '@' + 'b37c340767cf9e7777d4ca5a588c34c5744df9b2', + Var('chromium_url') + '/chromium/src/build.git' + '@' + '4157fb6cb44135013300168c9f4c5b95d04acf70', 'buildtools': - Var('chromium_url') + '/chromium/src/buildtools.git' + '@' + 'c2e4795660817c2776dbabd778b92ed58c074032', + Var('chromium_url') + '/chromium/src/buildtools.git' + '@' + 'e713c13e2fa3b7aa9131276f27990011e1aa6a73', 'buildtools/clang_format/script': - Var('chromium_url') + '/external/github.com/llvm/llvm-project/clang/tools/clang-format.git' + '@' + 'e435ad79c17b1888b34df88d6a30a094936e3836', + Var('chromium_url') + '/external/github.com/llvm/llvm-project/clang/tools/clang-format.git' + '@' + '8b525d2747f2584fc35d8c7e612e66f377858df7', 'buildtools/linux64': { 'packages': [ { - 'package': 'gn/gn/linux-amd64', + 'package': 'gn/gn/linux-${{arch}}', 'version': Var('gn_version'), } ], 'dep_type': 'cipd', - 'condition': 'host_os == "linux"', + 'condition': 'host_os == "linux" and host_cpu != "s390" and host_cpu != "ppc"', }, 'buildtools/mac': { 'packages': [ @@ -109,11 +120,11 @@ deps = { 'condition': 'host_os == "mac"', }, 'buildtools/third_party/libc++/trunk': - Var('chromium_url') + '/external/github.com/llvm/llvm-project/libcxx.git' + '@' + '79a2e924d96e2fc1e4b937c42efd08898fa472d7', + Var('chromium_url') + '/external/github.com/llvm/llvm-project/libcxx.git' + '@' + 'c1e647c7c30238f7c512457eec55798e3458fd8a', 'buildtools/third_party/libc++abi/trunk': - Var('chromium_url') + '/external/github.com/llvm/llvm-project/libcxxabi.git' + '@' + 'e025ba5dc85202540099d7cd8e72eae2d4ee9e33', + Var('chromium_url') + '/external/github.com/llvm/llvm-project/libcxxabi.git' + '@' + '5c3e02e92ae8bbc1bf1001bd9ef0d76e044ddb86', 'buildtools/third_party/libunwind/trunk': - Var('chromium_url') + '/external/github.com/llvm/llvm-project/libunwind.git' + '@' + 'c39fea88739be63a2d5590a938ce19d762b915fc', + Var('chromium_url') + '/external/github.com/llvm/llvm-project/libunwind.git' + '@' + '60a480ee1819266cf8054548454f99838583cd76', 'buildtools/win': { 'packages': [ { @@ -132,46 +143,26 @@ deps = { } ], 'dep_type': 'cipd', - 'condition': '(host_os == "linux" or host_os == "win") and checkout_reclient', + 'condition': '(host_os == "linux" or host_os == "mac" or host_os == "win") and checkout_reclient', }, 'test/benchmarks/data': Var('chromium_url') + '/v8/deps/third_party/benchmarks.git' + '@' + '05d7188267b4560491ff9155c5ee13e207ecd65f', 'test/mozilla/data': Var('chromium_url') + '/v8/deps/third_party/mozilla-tests.git' + '@' + 'f6c578a10ea707b1a8ab0b88943fe5115ce2b9be', 'test/test262/data': - Var('chromium_url') + '/external/github.com/tc39/test262.git' + '@' + 'd7c0a2076c2b0c1531aef7069d4abe70eec44ee3', - 'third_party/aemu-linux-x64': { - 'packages': [ - { - 'package': 'fuchsia/third_party/aemu/linux-amd64', - 'version': 'vRCm89BzABss-_H8vC-tLjcSf6uusZA9IBSSYtdw4_kC' - }, - ], - 'condition': 'host_os == "linux" and checkout_fuchsia', - 'dep_type': 'cipd', - }, - 'third_party/aemu-mac-x64': { - 'packages': [ - { - 'package': 'fuchsia/third_party/aemu/mac-amd64', - 'version': 'T9bWxf8aUC5TwCFgPxpuW29Mfy-7Z9xCfXB9QO8MfU0C' - }, - ], - 'condition': 'host_os == "mac" and checkout_fuchsia', - 'dep_type': 'cipd', - }, + Var('chromium_url') + '/external/github.com/tc39/test262.git' + '@' + '746197355c1705b7d4463fc75c29433c0ce2fd0d', 'third_party/android_ndk': { 'url': Var('chromium_url') + '/android_ndk.git' + '@' + '8388a2be5421311dc75c5f937aae13d821a27f3d', 'condition': 'checkout_android', }, 'third_party/android_platform': { - 'url': Var('chromium_url') + '/chromium/src/third_party/android_platform.git' + '@' + '2760db43ffc8b074cb7960c90b5254f74a5c299a', + 'url': Var('chromium_url') + '/chromium/src/third_party/android_platform.git' + '@' + '04b33506bfd9d0e866bd8bd62f4cbf323d84dc79', 'condition': 'checkout_android', }, 'third_party/android_sdk/public': { 'packages': [ { - 'package': 'chromium/third_party/android_sdk/public/build-tools/31.0.0', + 'package': 'chromium/third_party/android_sdk/public/build-tools/33.0.0', 'version': Var('android_sdk_build-tools_version'), }, { @@ -191,7 +182,7 @@ deps = { 'version': Var('android_sdk_platform-tools_version'), }, { - 'package': 'chromium/third_party/android_sdk/public/platforms/android-31', + 'package': 'chromium/third_party/android_sdk/public/platforms/android-33', 'version': Var('android_sdk_platforms_version'), }, { @@ -207,7 +198,7 @@ deps = { 'dep_type': 'cipd', }, 'third_party/catapult': { - 'url': Var('chromium_url') + '/catapult.git' + '@' + '3a1ae18f882d024686144edbec3050aae055f146', + 'url': Var('chromium_url') + '/catapult.git' + '@' + '37391a1619e953e23d3441dbc61e658e881fede4', 'condition': 'checkout_android', }, 'third_party/colorama/src': { @@ -215,18 +206,24 @@ deps = { 'condition': 'checkout_android', }, 'third_party/depot_tools': - Var('chromium_url') + '/chromium/tools/depot_tools.git' + '@' + '3b97fa826eee4bd1978c4c049038b1e4f201e8f2', - 'third_party/fuchsia-sdk': { - 'url': Var('chromium_url') + '/chromium/src/third_party/fuchsia-sdk.git' + '@' + '7c9c220d13ab367d49420144a257886ebfbce278', + Var('chromium_url') + '/chromium/tools/depot_tools.git' + '@' + '9ebcfa6be17c2d1e7bd72135ceab5e767ed89b7d', + 'third_party/fuchsia-sdk/sdk': { + 'packages': [ + { + 'package': Var('fuchsia_sdk_cipd_prefix') + '${{platform}}', + 'version': Var('fuchsia_version'), + }, + ], 'condition': 'checkout_fuchsia', + 'dep_type': 'cipd', }, 'third_party/google_benchmark/src': { - 'url': Var('chromium_url') + '/external/github.com/google/benchmark.git' + '@' + 'dc901ff9090e2b931433790cc44afc3af3b09ab2', + 'url': Var('chromium_url') + '/external/github.com/google/benchmark.git' + '@' + 'e8baf2622591569a27615b31372d1e9cc046af10', }, 'third_party/googletest/src': Var('chromium_url') + '/external/github.com/google/googletest.git' + '@' + 'af29db7ec28d6df1c7f0f745186884091e602e07', 'third_party/icu': - Var('chromium_url') + '/chromium/deps/icu.git' + '@' + '1fd0dbea04448c3f73fe5cb7599f9472f0f107f1', + Var('chromium_url') + '/chromium/deps/icu.git' + '@' + '20f8ac695af59b6c830def7d4e95bfeb13dd7be5', 'third_party/instrumented_libraries': Var('chromium_url') + '/chromium/src/third_party/instrumented_libraries.git' + '@' + 'e09c4b66b6e87116eb190651421f1a6e2f3b9c52', 'third_party/ittapi': { @@ -238,43 +235,23 @@ deps = { 'third_party/jinja2': Var('chromium_url') + '/chromium/src/third_party/jinja2.git' + '@' + 'ee69aa00ee8536f61db6a451f3858745cf587de6', 'third_party/jsoncpp/source': - Var('chromium_url') + '/external/github.com/open-source-parsers/jsoncpp.git'+ '@' + '9059f5cad030ba11d37818847443a53918c327b1', + Var('chromium_url') + '/external/github.com/open-source-parsers/jsoncpp.git'+ '@' + '42e892d96e47b1f6e29844cc705e148ec4856448', 'third_party/logdog/logdog': Var('chromium_url') + '/infra/luci/luci-py/client/libs/logdog' + '@' + '0b2078a90f7a638d576b3a7c407d136f2fb62399', 'third_party/markupsafe': Var('chromium_url') + '/chromium/src/third_party/markupsafe.git' + '@' + '1b882ef6372b58bfd55a3285f37ed801be9137cd', 'third_party/perfetto': - Var('android_url') + '/platform/external/perfetto.git' + '@' + 'aa4385bc5997ecad4c633885e1b331b1115012fb', + Var('android_url') + '/platform/external/perfetto.git' + '@' + '0eba417b2c72264fa825dc21067b9adc9b8adf70', 'third_party/protobuf': Var('chromium_url') + '/external/github.com/google/protobuf'+ '@' + '6a59a2ad1f61d9696092f79b6d74368b4d7970a3', - 'third_party/qemu-linux-x64': { - 'packages': [ - { - 'package': 'fuchsia/qemu/linux-amd64', - 'version': '9cc486c5b18a0be515c39a280ca9a309c54cf994' - }, - ], - 'condition': 'host_os == "linux" and checkout_fuchsia', - 'dep_type': 'cipd', - }, - 'third_party/qemu-mac-x64': { - 'packages': [ - { - 'package': 'fuchsia/qemu/mac-amd64', - 'version': '2d3358ae9a569b2d4a474f498b32b202a152134f' - }, - ], - 'condition': 'host_os == "mac" and checkout_fuchsia', - 'dep_type': 'cipd', - }, 'third_party/requests': { - 'url': Var('chromium_url') + '/external/github.com/kennethreitz/requests.git' + '@' + '2c2138e811487b13020eb331482fb991fd399d4e', + 'url': Var('chromium_url') + '/external/github.com/kennethreitz/requests.git' + '@' + 'refs/tags/v2.23.0', 'condition': 'checkout_android', }, 'third_party/zlib': - Var('chromium_url') + '/chromium/src/third_party/zlib.git'+ '@' + 'a6d209ab932df0f1c9d5b7dc67cfa74e8a3272c0', + Var('chromium_url') + '/chromium/src/third_party/zlib.git'+ '@' + 'f48cb14d487038d20c85680e29351e095a0fea8b', 'tools/clang': - Var('chromium_url') + '/chromium/src/tools/clang.git' + '@' + 'b5e2f7c16bbf3aefc9354e8fbad3de0a543f2193', + Var('chromium_url') + '/chromium/src/tools/clang.git' + '@' + '02a202a7b1fa863352c0c9fb088fd3c0cf48c978', 'tools/luci-go': { 'packages': [ { @@ -580,15 +557,6 @@ hooks = [ 'action': ['python3', 'build/util/lastchange.py', '-o', 'build/util/LASTCHANGE'], }, - { - 'name': 'Download Fuchsia SDK', - 'pattern': '.', - 'condition': 'checkout_fuchsia', - 'action': [ - 'python3', - 'build/fuchsia/update_sdk.py', - ], - }, { 'name': 'Download Fuchsia system images', 'pattern': '.', @@ -634,4 +602,14 @@ hooks = [ 'tools/generate-header-include-checks.py', ], }, + { + # Clean up build dirs for crbug.com/1337238. + # After a libc++ roll and revert, .ninja_deps would get into a state + # that breaks Ninja on Windows. + # TODO(crbug.com/1337238): Remove in a month or so. + 'name': 'del_ninja_deps_cache', + 'pattern': '.', + 'condition': 'host_os == "win"', + 'action': ['python3', 'build/del_ninja_deps_cache.py'], + }, ] diff --git a/deps/v8/ENG_REVIEW_OWNERS b/deps/v8/ENG_REVIEW_OWNERS index 3943c49432ce82..78d53b821d67e5 100644 --- a/deps/v8/ENG_REVIEW_OWNERS +++ b/deps/v8/ENG_REVIEW_OWNERS @@ -6,3 +6,4 @@ adamk@chromium.org danno@chromium.org hpayer@chromium.org verwaest@chromium.org +vahl@chromium.org diff --git a/deps/v8/INFRA_OWNERS b/deps/v8/INFRA_OWNERS index b5b36aa26844cd..33c1024df844fd 100644 --- a/deps/v8/INFRA_OWNERS +++ b/deps/v8/INFRA_OWNERS @@ -1,4 +1,5 @@ -machenbach@chromium.org -tmrts@chromium.org +alexschulze@chromium.org almuthanna@chromium.org liviurau@chromium.org +machenbach@chromium.org +tmrts@chromium.org diff --git a/deps/v8/LICENSE b/deps/v8/LICENSE index 53d9c47e33c182..f665c480d2c169 100644 --- a/deps/v8/LICENSE +++ b/deps/v8/LICENSE @@ -15,8 +15,7 @@ are: - Strongtalk assembler, the basis of the files assembler-arm-inl.h, assembler-arm.cc, assembler-arm.h, assembler-ia32-inl.h, assembler-ia32.cc, assembler-ia32.h, assembler-x64-inl.h, - assembler-x64.cc, assembler-x64.h, assembler-mips-inl.h, - assembler-mips.cc, assembler-mips.h, assembler.cc and assembler.h. + assembler-x64.cc, assembler-x64.h, assembler.cc and assembler.h. This code is copyrighted by Sun Microsystems Inc. and released under a 3-clause BSD license. diff --git a/deps/v8/OWNERS b/deps/v8/OWNERS index 42d7d9981da461..db579fb0e6a2d3 100644 --- a/deps/v8/OWNERS +++ b/deps/v8/OWNERS @@ -3,20 +3,21 @@ file:ENG_REVIEW_OWNERS per-file .*=file:INFRA_OWNERS -per-file .mailmap=file:COMMON_OWNERS per-file .bazelrc=file:COMMON_OWNERS +per-file .mailmap=file:COMMON_OWNERS +per-file codereview.settings=file:INFRA_OWNERS +per-file AUTHORS=file:COMMON_OWNERS per-file BUILD.bazel=file:COMMON_OWNERS per-file BUILD.gn=file:COMMON_OWNERS -per-file WORKSPACE=file:COMMON_OWNERS per-file DEPS=file:INFRA_OWNERS +per-file INFRA_OWNERS=file:INFRA_OWNERS +per-file PRESUBMIT.py=file:INFRA_OWNERS +per-file WATCHLISTS=file:COMMON_OWNERS +per-file WORKSPACE=file:COMMON_OWNERS + # For Test262 rolls. per-file DEPS=mathias@chromium.org per-file DEPS=syg@chromium.org -per-file PRESUBMIT.py=file:INFRA_OWNERS -per-file codereview.settings=file:INFRA_OWNERS - -per-file AUTHORS=file:COMMON_OWNERS -per-file WATCHLISTS=file:COMMON_OWNERS # Needed by the auto_tag builder per-file WATCHLISTS=v8-ci-autoroll-builder@chops-service-accounts.iam.gserviceaccount.com @@ -26,5 +27,5 @@ per-file ...-loong64*=file:LOONG_OWNERS per-file ...-mips*=file:MIPS_OWNERS per-file ...-mips64*=file:MIPS_OWNERS per-file ...-ppc*=file:PPC_OWNERS -per-file ...-riscv64*=file:RISCV_OWNERS +per-file ...-riscv*=file:RISCV_OWNERS per-file ...-s390*=file:S390_OWNERS diff --git a/deps/v8/PRESUBMIT.py b/deps/v8/PRESUBMIT.py index cb6888d32a23e2..03db4c126f346d 100644 --- a/deps/v8/PRESUBMIT.py +++ b/deps/v8/PRESUBMIT.py @@ -486,14 +486,18 @@ def _CheckNoexceptAnnotations(input_api, output_api): """ def FilterFile(affected_file): - return input_api.FilterSourceFile( - affected_file, - files_to_check=(r'src[\\\/].*', r'test[\\\/].*'), + files_to_skip = _EXCLUDED_PATHS + ( # Skip api.cc since we cannot easily add the 'noexcept' annotation to # public methods. + r'src[\\\/]api[\\\/]api\.cc', # Skip src/bigint/ because it's meant to be V8-independent. - files_to_skip=(r'src[\\\/]api[\\\/]api\.cc', - r'src[\\\/]bigint[\\\/].*')) + r'src[\\\/]bigint[\\\/].*', + ) + return input_api.FilterSourceFile( + affected_file, + files_to_check=(r'src[\\\/].*\.cc', r'src[\\\/].*\.h', + r'test[\\\/].*\.cc', r'test[\\\/].*\.h'), + files_to_skip=files_to_skip) # matches any class name. class_name = r'\b([A-Z][A-Za-z0-9_:]*)(?:::\1)?' diff --git a/deps/v8/WATCHLISTS b/deps/v8/WATCHLISTS index feadac3fab5afc..a078c5568e4707 100644 --- a/deps/v8/WATCHLISTS +++ b/deps/v8/WATCHLISTS @@ -108,6 +108,7 @@ 'jgruber+watch@chromium.org', 'leszeks+watch@chromium.org', 'verwaest+watch@chromium.org', + 'victorgomes+watch@chromium.org', ], 'snapshot': [ 'jgruber+watch@chromium.org', @@ -129,6 +130,7 @@ 'arm': [ 'v8-mips-ports@googlegroups.com', 'v8-ppc-ports@googlegroups.com', + 'v8-risc-v-ports@chromium.org', ], 'merges': [ # Only enabled on branches created with tools/release/create_release.py diff --git a/deps/v8/WORKSPACE b/deps/v8/WORKSPACE index 490e973a762a5a..306aff18091e2e 100644 --- a/deps/v8/WORKSPACE +++ b/deps/v8/WORKSPACE @@ -34,22 +34,6 @@ pip_install( requirements = "//:bazel/requirements.txt", ) -new_local_repository( - name = "com_googlesource_chromium_zlib", - build_file = "bazel/BUILD.zlib", - path = "third_party/zlib", -) - -bind( - name = "zlib", - actual = "@com_googlesource_chromium_zlib//:zlib", -) - -bind( - name = "zlib_compression_utils", - actual = "@com_googlesource_chromium_zlib//:zlib_compression_utils", -) - new_local_repository( name = "com_googlesource_chromium_icu", build_file = "bazel/BUILD.icu", diff --git a/deps/v8/base/trace_event/common/trace_event_common.h b/deps/v8/base/trace_event/common/trace_event_common.h index fb1ce8a053c3d4..f07f19b3095f57 100644 --- a/deps/v8/base/trace_event/common/trace_event_common.h +++ b/deps/v8/base/trace_event/common/trace_event_common.h @@ -1,4 +1,4 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. +// Copyright 2015 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -404,6 +404,10 @@ struct BASE_EXPORT TraceTimestampTraits<::base::TimeTicks> { // - |timestamp| must be non-null or it crashes. Use DCHECK(timestamp) before // calling this to detect an invalid timestamp even when tracing is not // enabled, as the commit queue doesn't run all tests with tracing enabled. +// Note: This legacy macro is deprecated. It should not be used in new code. +// If thread_id is different from current thread id, it will result into +// DCHECK failure. This note is also applicable to `_COPY` and `_END` +// variant of this macro. #define TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0(category_group, name, id, \ thread_id, timestamp) \ INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \ @@ -1024,18 +1028,6 @@ struct BASE_EXPORT TraceTimestampTraits<::base::TimeTicks> { TRACE_EVENT_PHASE_DELETE_OBJECT, category_group, name, id, \ TRACE_EVENT_FLAG_NONE) -// Records entering and leaving trace event contexts. |category_group| and -// |name| specify the context category and type. |context| is a -// snapshotted context object id. -#define TRACE_EVENT_ENTER_CONTEXT(category_group, name, context) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID( \ - TRACE_EVENT_PHASE_ENTER_CONTEXT, category_group, name, context, \ - TRACE_EVENT_FLAG_NONE) -#define TRACE_EVENT_LEAVE_CONTEXT(category_group, name, context) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID( \ - TRACE_EVENT_PHASE_LEAVE_CONTEXT, category_group, name, context, \ - TRACE_EVENT_FLAG_NONE) - // Macro to efficiently determine if a given category group is enabled. #define TRACE_EVENT_CATEGORY_GROUP_ENABLED(category_group, ret) \ do { \ @@ -1099,12 +1091,15 @@ struct BASE_EXPORT TraceTimestampTraits<::base::TimeTicks> { #define TRACE_EVENT_PHASE_MEMORY_DUMP ('v') #define TRACE_EVENT_PHASE_MARK ('R') #define TRACE_EVENT_PHASE_CLOCK_SYNC ('c') -#define TRACE_EVENT_PHASE_ENTER_CONTEXT ('(') -#define TRACE_EVENT_PHASE_LEAVE_CONTEXT (')') // Flags for changing the behavior of TRACE_EVENT_API_ADD_TRACE_EVENT. #define TRACE_EVENT_FLAG_NONE (static_cast(0)) + +// Should not be used outside this file or +// except `trace_event_impl.cc` (implementation details). +// If used, it will result in CHECK failure in SDK build. #define TRACE_EVENT_FLAG_COPY (static_cast(1 << 0)) + #define TRACE_EVENT_FLAG_HAS_ID (static_cast(1 << 1)) #define TRACE_EVENT_FLAG_SCOPE_OFFSET (static_cast(1 << 2)) #define TRACE_EVENT_FLAG_SCOPE_EXTRA (static_cast(1 << 3)) diff --git a/deps/v8/bazel/BUILD.zlib b/deps/v8/bazel/BUILD.zlib deleted file mode 100644 index 25a2c35313b981..00000000000000 --- a/deps/v8/bazel/BUILD.zlib +++ /dev/null @@ -1,69 +0,0 @@ -# Copyright 2021 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. - -cc_library( - name = "zlib", - srcs = [ - "adler32.c", - "chromeconf.h", - "compress.c", - "contrib/optimizations/insert_string.h", - "contrib/optimizations/slide_hash_neon.h", - "cpu_features.c", - "cpu_features.h", - "crc32.c", - "crc32.h", - "deflate.c", - "deflate.h", - "gzclose.c", - "gzguts.h", - "gzlib.c", - "gzread.c", - "gzwrite.c", - "infback.c", - "inffast.c", - "inffast.h", - "inffixed.h", - "inflate.c", - "inflate.h", - "inftrees.c", - "inftrees.h", - "trees.c", - "trees.h", - "uncompr.c", - "zconf.h", - "zlib.h", - "zutil.c", - "zutil.h", - ], - hdrs = [ - "zlib.h", - ], - defines = [ - "CHROMIUM_ZLIB_NO_CHROMECONF", - "CPU_NO_SIMD", - ] + select({ - "@platforms//os:windows": [], - "//conditions:default": [ - "HAVE_HIDDEN", - ], - }), - include_prefix = "third_party/zlib", - visibility = ["//visibility:public"], -) - -cc_library( - name = "zlib_compression_utils", - srcs = [ - "google/compression_utils_portable.cc", - ], - hdrs = [ - "google/compression_utils_portable.h", - ], - include_prefix = "third_party/zlib", - visibility = ["//visibility:public"], - deps = [ - "//external:zlib", - ], -) diff --git a/deps/v8/bazel/config/BUILD.bazel b/deps/v8/bazel/config/BUILD.bazel index ffa9ef040722b4..448260de88465d 100644 --- a/deps/v8/bazel/config/BUILD.bazel +++ b/deps/v8/bazel/config/BUILD.bazel @@ -290,6 +290,14 @@ selects.config_setting_group( ], ) +selects.config_setting_group( + name = "is_macos_arm64", + match_all = [ + ":is_macos", + ":is_arm64", + ], +) + config_setting( name = "is_compiler_default", flag_values = { diff --git a/deps/v8/bazel/defs.bzl b/deps/v8/bazel/defs.bzl index ed7dea9581deff..e957c0fad3bc4b 100644 --- a/deps/v8/bazel/defs.bzl +++ b/deps/v8/bazel/defs.bzl @@ -493,7 +493,6 @@ def build_config_content(cpu, icu): ("target_cpu", cpu), ("v8_current_cpu", cpu), ("v8_dict_property_const_tracking", "false"), - ("v8_enable_atomic_marking_state", "false"), ("v8_enable_atomic_object_field_writes", "false"), ("v8_enable_concurrent_marking", "false"), ("v8_enable_i18n_support", icu), diff --git a/deps/v8/gni/OWNERS b/deps/v8/gni/OWNERS index fa1262b503174e..c20b8de5a25442 100644 --- a/deps/v8/gni/OWNERS +++ b/deps/v8/gni/OWNERS @@ -1,5 +1,5 @@ file:../INFRA_OWNERS -per-file v8.cmx=victorgomes@chromium.org +per-file v8.cml=victorgomes@chromium.org per-file release_branch_toggle.gni=v8-ci-autoroll-builder@chops-service-accounts.iam.gserviceaccount.com -per-file release_branch_toggle.gni=vahl@chromium.org \ No newline at end of file +per-file release_branch_toggle.gni=vahl@chromium.org diff --git a/deps/v8/gni/proto_library.gni b/deps/v8/gni/proto_library.gni index 583057e0a5a3e8..a8690999f97710 100644 --- a/deps/v8/gni/proto_library.gni +++ b/deps/v8/gni/proto_library.gni @@ -76,6 +76,17 @@ template("proto_library") { out_dir = "$root_gen_dir/" + proto_out_dir rel_out_dir = rebase_path(out_dir, root_build_dir) + # exclude_imports is only used for generating the descriptor. Therefore, the + # check needs to be here to avoid complaints from GN about the unused + # variable. + if (generate_descriptor != "") { + if (defined(invoker.exclude_imports)) { + exclude_imports = invoker.exclude_imports + } else { + exclude_imports = false + } + } + # Prevent unused errors when generating descriptor only. if (generate_descriptor != "") { not_needed([ "rel_out_dir" ]) @@ -163,8 +174,10 @@ template("proto_library") { } if (generate_descriptor != "") { depfile = "$out_dir/$generate_descriptor.d" + if (!exclude_imports) { + args += [ "--include_imports" ] + } args += [ - "--include_imports", "--descriptor_set_out", rebase_path("$out_dir/$generate_descriptor", root_build_dir), "--dependency_out", diff --git a/deps/v8/gni/protoc.py b/deps/v8/gni/protoc.py index dc8920009dede0..d529d1c65a536b 100755 --- a/deps/v8/gni/protoc.py +++ b/deps/v8/gni/protoc.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright 2021 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. diff --git a/deps/v8/gni/release_branch_toggle.gni b/deps/v8/gni/release_branch_toggle.gni index 43e3b6ae567631..c502c8c62e5836 100644 --- a/deps/v8/gni/release_branch_toggle.gni +++ b/deps/v8/gni/release_branch_toggle.gni @@ -4,4 +4,4 @@ declare_args() { is_on_release_branch = true -} +} \ No newline at end of file diff --git a/deps/v8/gni/snapshot_toolchain.gni b/deps/v8/gni/snapshot_toolchain.gni index 39b196521c35ad..5f5e53a30d0789 100644 --- a/deps/v8/gni/snapshot_toolchain.gni +++ b/deps/v8/gni/snapshot_toolchain.gni @@ -64,8 +64,7 @@ if (v8_snapshot_toolchain == "") { current_cpu == "arm") { # Trying to compile 32-bit arm on arm64. Good luck! v8_snapshot_toolchain = current_toolchain - } else if (host_cpu == "x64" && - (v8_current_cpu == "mips" || v8_current_cpu == "mips64")) { + } else if (host_cpu == "x64" && v8_current_cpu == "mips64") { # We don't support snapshot generation for big-endian targets, # therefore snapshots will need to be built using native mksnapshot # in combination with qemu @@ -96,7 +95,7 @@ if (v8_snapshot_toolchain == "") { } else { _cpus = "x64_v8_${v8_current_cpu}" } - } else if (v8_current_cpu == "arm" || v8_current_cpu == "mipsel") { + } else if (v8_current_cpu == "arm" || v8_current_cpu == "riscv32") { _cpus = "x86_v8_${v8_current_cpu}" } else { # This branch should not be reached; leave _cpus blank so the assert @@ -121,7 +120,6 @@ assert(v8_snapshot_toolchain != "", # avoid building v8_libbase on the host more than once. On mips with big endian, # the snapshot toolchain is the target toolchain and, hence, can't be used. v8_generator_toolchain = v8_snapshot_toolchain -if (host_cpu == "x64" && - (v8_current_cpu == "mips" || v8_current_cpu == "mips64")) { +if (host_cpu == "x64" && v8_current_cpu == "mips64") { v8_generator_toolchain = "//build/toolchain/linux:clang_x64" } diff --git a/deps/v8/gni/v8.cml b/deps/v8/gni/v8.cml new file mode 100644 index 00000000000000..4d74c7626cfb36 --- /dev/null +++ b/deps/v8/gni/v8.cml @@ -0,0 +1,21 @@ +// Copyright 2022 The V8 project authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +{ + include: [ "syslog/client.shard.cml" ], + program: { + runner: "elf", + binary: "d8", + }, + use: [ + { + protocol: [ + "fuchsia.kernel.VmexResource", + ], + }, + { + storage: "tmp", + path: "/tmp", + }, + ], +} diff --git a/deps/v8/gni/v8.cmx b/deps/v8/gni/v8.cmx deleted file mode 100644 index 45fd74a09faffa..00000000000000 --- a/deps/v8/gni/v8.cmx +++ /dev/null @@ -1,52 +0,0 @@ -{ - "facets": { - "fuchsia.test": { - "system-services": [ - "fuchsia.kernel.VmexResource" - ] - } - }, - "sandbox": { - "dev": [ - "null", - "zero" - ], - "features": [ - "deprecated-ambient-replace-as-executable", - "isolated-cache-storage", - "isolated-persistent-storage", - "isolated-temp", - "root-ssl-certificates", - "vulkan" - ], - "services": [ - "fuchsia.accessibility.semantics.SemanticsManager", - "fuchsia.camera3.DeviceWatcher", - "fuchsia.device.NameProvider", - "fuchsia.fonts.Provider", - "fuchsia.intl.PropertyProvider", - "fuchsia.kernel.VmexResource", - "fuchsia.logger.Log", - "fuchsia.logger.LogSink", - "fuchsia.media.Audio", - "fuchsia.media.SessionAudioConsumerFactory", - "fuchsia.media.drm.Widevine", - "fuchsia.mediacodec.CodecFactory", - "fuchsia.memorypressure.Provider", - "fuchsia.net.NameLookup", - "fuchsia.net.interfaces.State", - "fuchsia.posix.socket.Provider", - "fuchsia.process.Launcher", - "fuchsia.sys.Environment", - "fuchsia.sys.Launcher", - "fuchsia.sys.Loader", - "fuchsia.sysmem.Allocator", - "fuchsia.ui.input.ImeService", - "fuchsia.ui.input.ImeVisibilityService", - "fuchsia.ui.scenic.Scenic", - "fuchsia.ui.policy.Presenter", - "fuchsia.vulkan.loader.Loader", - "fuchsia.web.ContextProvider" - ] - } -} diff --git a/deps/v8/gni/v8.gni b/deps/v8/gni/v8.gni index 7b9da1f06a6539..3f093597faccdc 100644 --- a/deps/v8/gni/v8.gni +++ b/deps/v8/gni/v8.gni @@ -69,6 +69,9 @@ declare_args() { # executed as standard JavaScript instead. v8_enable_webassembly = "" + # Enable 256-bit long vector re-vectorization pass in WASM compilation pipeline. + v8_enable_wasm_simd256_revec = false + # Enable runtime call stats. v8_enable_runtime_call_stats = !is_on_release_branch @@ -78,6 +81,12 @@ declare_args() { # Scan the call stack conservatively during garbage collection. v8_enable_conservative_stack_scanning = false + # Use the object start bitmap for inner pointer resolution. + v8_enable_inner_pointer_resolution_osb = false + + # Use the marking bitmap for inner pointer resolution. + v8_enable_inner_pointer_resolution_mb = false + v8_enable_google_benchmark = false cppgc_is_standalone = false @@ -88,6 +97,13 @@ declare_args() { # Enable young generation in cppgc. cppgc_enable_young_generation = false + # Enable pointer compression in cppgc. + cppgc_enable_pointer_compression = false + + # Enable 2gb cage for fast compression/decompression. Currently disabled + # due to an increased number of OOMs. + cppgc_enable_2gb_cage = false + # Enable advanced BigInt algorithms, costing about 10-30 KB binary size # depending on platform. Disabled on Android to save binary size. v8_advanced_bigint_algorithms = !is_android @@ -142,7 +158,7 @@ if (is_debug && !v8_optimized_debug) { # TODO(crbug.com/621335) Rework this so that we don't have the confusion # between "optimize_speed" and "optimize_max". - if (((is_posix && !is_android) || is_fuchsia) && !using_sanitizer) { + if (is_posix && !is_android && !using_sanitizer) { v8_add_configs += [ "//build/config/compiler:optimize_speed" ] } else { v8_add_configs += [ "//build/config/compiler:optimize_max" ] @@ -183,8 +199,7 @@ if ((is_posix || is_fuchsia) && } # On MIPS gcc_target_rpath and ldso_path might be needed for all builds. -if (target_cpu == "mipsel" || target_cpu == "mips64el" || - target_cpu == "mips" || target_cpu == "mips64") { +if (target_cpu == "mips64el" || target_cpu == "mips64") { v8_add_configs += [ "//build/config/gcc:rpath_for_built_shared_libraries" ] } diff --git a/deps/v8/include/cppgc/common.h b/deps/v8/include/cppgc/common.h index b6dbff3dd6f007..961038360ac428 100644 --- a/deps/v8/include/cppgc/common.h +++ b/deps/v8/include/cppgc/common.h @@ -5,7 +5,6 @@ #ifndef INCLUDE_CPPGC_COMMON_H_ #define INCLUDE_CPPGC_COMMON_H_ -// TODO(chromium:1056170): Remove dependency on v8. #include "v8config.h" // NOLINT(build/include_directory) namespace cppgc { diff --git a/deps/v8/include/cppgc/cross-thread-persistent.h b/deps/v8/include/cppgc/cross-thread-persistent.h index c8751e1d64121a..1fa28afa136eb4 100644 --- a/deps/v8/include/cppgc/cross-thread-persistent.h +++ b/deps/v8/include/cppgc/cross-thread-persistent.h @@ -120,7 +120,7 @@ class BasicCrossThreadPersistent final : public CrossThreadPersistentBase, if (!IsValid(raw)) return; PersistentRegionLock guard; CrossThreadPersistentRegion& region = this->GetPersistentRegion(raw); - SetNode(region.AllocateNode(this, &Trace)); + SetNode(region.AllocateNode(this, &TraceAsRoot)); this->CheckPointer(raw); } @@ -138,7 +138,7 @@ class BasicCrossThreadPersistent final : public CrossThreadPersistentBase, : CrossThreadPersistentBase(raw), LocationPolicy(loc) { if (!IsValid(raw)) return; CrossThreadPersistentRegion& region = this->GetPersistentRegion(raw); - SetNode(region.AllocateNode(this, &Trace)); + SetNode(region.AllocateNode(this, &TraceAsRoot)); this->CheckPointer(raw); } @@ -349,9 +349,8 @@ class BasicCrossThreadPersistent final : public CrossThreadPersistentBase, return ptr && ptr != kSentinelPointer; } - static void Trace(Visitor* v, const void* ptr) { - const auto* handle = static_cast(ptr); - v->TraceRoot(*handle, handle->Location()); + static void TraceAsRoot(RootVisitor& root_visitor, const void* ptr) { + root_visitor.Trace(*static_cast(ptr)); } void AssignUnsafe(T* ptr) { @@ -378,7 +377,7 @@ class BasicCrossThreadPersistent final : public CrossThreadPersistentBase, SetValue(ptr); if (!IsValid(ptr)) return; PersistentRegionLock guard; - SetNode(this->GetPersistentRegion(ptr).AllocateNode(this, &Trace)); + SetNode(this->GetPersistentRegion(ptr).AllocateNode(this, &TraceAsRoot)); this->CheckPointer(ptr); } @@ -398,7 +397,7 @@ class BasicCrossThreadPersistent final : public CrossThreadPersistentBase, } SetValue(ptr); if (!IsValid(ptr)) return; - SetNode(this->GetPersistentRegion(ptr).AllocateNode(this, &Trace)); + SetNode(this->GetPersistentRegion(ptr).AllocateNode(this, &TraceAsRoot)); this->CheckPointer(ptr); } @@ -416,7 +415,7 @@ class BasicCrossThreadPersistent final : public CrossThreadPersistentBase, return static_cast(const_cast(GetValueFromGC())); } - friend class cppgc::Visitor; + friend class internal::RootVisitor; }; template diff --git a/deps/v8/include/cppgc/heap-consistency.h b/deps/v8/include/cppgc/heap-consistency.h index 54a4dbc21ed2eb..35c59ed1ad417f 100644 --- a/deps/v8/include/cppgc/heap-consistency.h +++ b/deps/v8/include/cppgc/heap-consistency.h @@ -9,6 +9,7 @@ #include "cppgc/internal/write-barrier.h" #include "cppgc/macros.h" +#include "cppgc/member.h" #include "cppgc/trace-trait.h" #include "v8config.h" // NOLINT(build/include_directory) @@ -47,6 +48,29 @@ class HeapConsistency final { return internal::WriteBarrier::GetWriteBarrierType(slot, value, params); } + /** + * Gets the required write barrier type for a specific write. This override is + * only used for all the BasicMember types. + * + * \param slot Slot containing the pointer to the object. The slot itself + * must reside in an object that has been allocated using + * `MakeGarbageCollected()`. + * \param value The pointer to the object held via `BasicMember`. + * \param params Parameters that may be used for actual write barrier calls. + * Only filled if return value indicates that a write barrier is needed. The + * contents of the `params` are an implementation detail. + * \returns whether a write barrier is needed and which barrier to invoke. + */ + template + static V8_INLINE WriteBarrierType GetWriteBarrierType( + const internal::BasicMember& value, + WriteBarrierParams& params) { + return internal::WriteBarrier::GetWriteBarrierType( + value.GetRawSlot(), value.GetRawStorage(), params); + } + /** * Gets the required write barrier type for a specific write. * @@ -146,7 +170,25 @@ class HeapConsistency final { */ static V8_INLINE void GenerationalBarrier(const WriteBarrierParams& params, const void* slot) { - internal::WriteBarrier::GenerationalBarrier(params, slot); + internal::WriteBarrier::GenerationalBarrier< + internal::WriteBarrier::GenerationalBarrierType::kPreciseSlot>(params, + slot); + } + + /** + * Generational barrier for maintaining consistency when running with multiple + * generations. This version is used when slot contains uncompressed pointer. + * + * \param params The parameters retrieved from `GetWriteBarrierType()`. + * \param slot Uncompressed slot containing the direct pointer to the object. + * The slot itself must reside in an object that has been allocated using + * `MakeGarbageCollected()`. + */ + static V8_INLINE void GenerationalBarrierForUncompressedSlot( + const WriteBarrierParams& params, const void* uncompressed_slot) { + internal::WriteBarrier::GenerationalBarrier< + internal::WriteBarrier::GenerationalBarrierType:: + kPreciseUncompressedSlot>(params, uncompressed_slot); } /** @@ -158,8 +200,9 @@ class HeapConsistency final { */ static V8_INLINE void GenerationalBarrierForSourceObject( const WriteBarrierParams& params, const void* inner_pointer) { - internal::WriteBarrier::GenerationalBarrierForSourceObject(params, - inner_pointer); + internal::WriteBarrier::GenerationalBarrier< + internal::WriteBarrier::GenerationalBarrierType::kImpreciseSlot>( + params, inner_pointer); } private: diff --git a/deps/v8/include/cppgc/heap-handle.h b/deps/v8/include/cppgc/heap-handle.h new file mode 100644 index 00000000000000..5a0f9cd2edcb9f --- /dev/null +++ b/deps/v8/include/cppgc/heap-handle.h @@ -0,0 +1,41 @@ +// Copyright 2022 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. + +#ifndef INCLUDE_CPPGC_HEAP_HANDLE_H_ +#define INCLUDE_CPPGC_HEAP_HANDLE_H_ + +#include "v8config.h" // NOLINT(build/include_directory) + +namespace cppgc { + +namespace internal { +class HeapBase; +class WriteBarrierTypeForCagedHeapPolicy; +} // namespace internal + +/** + * Opaque handle used for additional heap APIs. + */ +class HeapHandle { + private: + HeapHandle() = default; + + V8_INLINE bool is_incremental_marking_in_progress() const { + return is_incremental_marking_in_progress_; + } + + V8_INLINE bool is_young_generation_enabled() const { + return is_young_generation_enabled_; + } + + bool is_incremental_marking_in_progress_ = false; + bool is_young_generation_enabled_ = false; + + friend class internal::HeapBase; + friend class internal::WriteBarrierTypeForCagedHeapPolicy; +}; + +} // namespace cppgc + +#endif // INCLUDE_CPPGC_HEAP_HANDLE_H_ diff --git a/deps/v8/include/cppgc/heap-statistics.h b/deps/v8/include/cppgc/heap-statistics.h index 8e626596e5b07b..5e389874099426 100644 --- a/deps/v8/include/cppgc/heap-statistics.h +++ b/deps/v8/include/cppgc/heap-statistics.h @@ -56,7 +56,7 @@ struct HeapStatistics final { /** Amount of memory actually used on the page. */ size_t used_size_bytes = 0; /** Statistics for object allocated on the page. Filled only when - * NameProvider::HideInternalNames() is false. */ + * NameProvider::SupportsCppClassNamesAsObjectNames() is true. */ std::vector object_statistics; }; @@ -98,7 +98,7 @@ struct HeapStatistics final { /** Overall committed amount of memory for the heap. */ size_t committed_size_bytes = 0; - /** Resident amount of memory help by the heap. */ + /** Resident amount of memory held by the heap. */ size_t resident_size_bytes = 0; /** Amount of memory actually used on the heap. */ size_t used_size_bytes = 0; diff --git a/deps/v8/include/cppgc/heap.h b/deps/v8/include/cppgc/heap.h index aa3c6f468a21de..02ee12eaba09d5 100644 --- a/deps/v8/include/cppgc/heap.h +++ b/deps/v8/include/cppgc/heap.h @@ -21,6 +21,7 @@ namespace cppgc { class AllocationHandle; +class HeapHandle; /** * Implementation details of cppgc. Those details are considered internal and @@ -31,11 +32,6 @@ namespace internal { class Heap; } // namespace internal -/** - * Used for additional heap APIs. - */ -class HeapHandle; - class V8_EXPORT Heap { public: /** @@ -59,7 +55,7 @@ class V8_EXPORT Heap { }; /** - * Specifies supported marking types + * Specifies supported marking types. */ enum class MarkingType : uint8_t { /** @@ -79,7 +75,7 @@ class V8_EXPORT Heap { }; /** - * Specifies supported sweeping types + * Specifies supported sweeping types. */ enum class SweepingType : uint8_t { /** diff --git a/deps/v8/include/cppgc/internal/api-constants.h b/deps/v8/include/cppgc/internal/api-constants.h index a50d4d046c953c..023426e94b04c9 100644 --- a/deps/v8/include/cppgc/internal/api-constants.h +++ b/deps/v8/include/cppgc/internal/api-constants.h @@ -32,12 +32,22 @@ static constexpr uint16_t kFullyConstructedBitMask = uint16_t{1}; static constexpr size_t kPageSize = size_t{1} << 17; +#if defined(V8_TARGET_ARCH_ARM64) && defined(V8_OS_MACOS) +constexpr size_t kGuardPageSize = 0; +#else +constexpr size_t kGuardPageSize = 4096; +#endif + static constexpr size_t kLargeObjectSizeThreshold = kPageSize / 2; #if defined(CPPGC_CAGED_HEAP) +#if defined(CPPGC_2GB_CAGE) +constexpr size_t kCagedHeapReservationSize = static_cast(2) * kGB; +#else // !defined(CPPGC_2GB_CAGE) constexpr size_t kCagedHeapReservationSize = static_cast(4) * kGB; +#endif // !defined(CPPGC_2GB_CAGE) constexpr size_t kCagedHeapReservationAlignment = kCagedHeapReservationSize; -#endif +#endif // defined(CPPGC_CAGED_HEAP) static constexpr size_t kDefaultAlignment = sizeof(void*); diff --git a/deps/v8/include/cppgc/internal/base-page-handle.h b/deps/v8/include/cppgc/internal/base-page-handle.h new file mode 100644 index 00000000000000..9c6907555e21d4 --- /dev/null +++ b/deps/v8/include/cppgc/internal/base-page-handle.h @@ -0,0 +1,45 @@ +// Copyright 2022 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. + +#ifndef INCLUDE_CPPGC_INTERNAL_BASE_PAGE_HANDLE_H_ +#define INCLUDE_CPPGC_INTERNAL_BASE_PAGE_HANDLE_H_ + +#include "cppgc/heap-handle.h" +#include "cppgc/internal/api-constants.h" +#include "cppgc/internal/logging.h" +#include "v8config.h" // NOLINT(build/include_directory) + +namespace cppgc { +namespace internal { + +// The class is needed in the header to allow for fast access to HeapHandle in +// the write barrier. +class BasePageHandle { + public: + static V8_INLINE BasePageHandle* FromPayload(void* payload) { + return reinterpret_cast( + (reinterpret_cast(payload) & + ~(api_constants::kPageSize - 1)) + + api_constants::kGuardPageSize); + } + static V8_INLINE const BasePageHandle* FromPayload(const void* payload) { + return FromPayload(const_cast(payload)); + } + + HeapHandle& heap_handle() { return heap_handle_; } + const HeapHandle& heap_handle() const { return heap_handle_; } + + protected: + explicit BasePageHandle(HeapHandle& heap_handle) : heap_handle_(heap_handle) { + CPPGC_DCHECK(reinterpret_cast(this) % api_constants::kPageSize == + api_constants::kGuardPageSize); + } + + HeapHandle& heap_handle_; +}; + +} // namespace internal +} // namespace cppgc + +#endif // INCLUDE_CPPGC_INTERNAL_BASE_PAGE_HANDLE_H_ diff --git a/deps/v8/include/cppgc/internal/caged-heap-local-data.h b/deps/v8/include/cppgc/internal/caged-heap-local-data.h index a27649c17fce5b..7d689f87e71da1 100644 --- a/deps/v8/include/cppgc/internal/caged-heap-local-data.h +++ b/deps/v8/include/cppgc/internal/caged-heap-local-data.h @@ -10,46 +10,76 @@ #include #include "cppgc/internal/api-constants.h" +#include "cppgc/internal/caged-heap.h" #include "cppgc/internal/logging.h" #include "cppgc/platform.h" #include "v8config.h" // NOLINT(build/include_directory) +#if __cpp_lib_bitopts +#include +#endif // __cpp_lib_bitopts + +#if defined(CPPGC_CAGED_HEAP) + namespace cppgc { namespace internal { class HeapBase; +class HeapBaseHandle; #if defined(CPPGC_YOUNG_GENERATION) // AgeTable is the bytemap needed for the fast generation check in the write -// barrier. AgeTable contains entries that correspond to 512 bytes memory +// barrier. AgeTable contains entries that correspond to 4096 bytes memory // regions (cards). Each entry in the table represents generation of the objects // that reside on the corresponding card (young, old or mixed). -class AgeTable final { +class V8_EXPORT AgeTable final { static constexpr size_t kRequiredSize = 1 * api_constants::kMB; static constexpr size_t kAllocationGranularity = api_constants::kAllocationGranularity; public: + // Represents age of the objects living on a single card. enum class Age : uint8_t { kOld, kYoung, kMixed }; + // When setting age for a range, consider or ignore ages of the adjacent + // cards. + enum class AdjacentCardsPolicy : uint8_t { kConsider, kIgnore }; static constexpr size_t kCardSizeInBytes = - (api_constants::kCagedHeapReservationSize / kAllocationGranularity) / - kRequiredSize; + api_constants::kCagedHeapReservationSize / kRequiredSize; void SetAge(uintptr_t cage_offset, Age age) { table_[card(cage_offset)] = age; } + V8_INLINE Age GetAge(uintptr_t cage_offset) const { return table_[card(cage_offset)]; } - void Reset(PageAllocator* allocator); + void SetAgeForRange(uintptr_t cage_offset_begin, uintptr_t cage_offset_end, + Age age, AdjacentCardsPolicy adjacent_cards_policy); + + Age GetAgeForRange(uintptr_t cage_offset_begin, + uintptr_t cage_offset_end) const; + + void ResetForTesting(); private: V8_INLINE size_t card(uintptr_t offset) const { constexpr size_t kGranularityBits = +#if __cpp_lib_bitopts + std::countr_zero(static_cast(kCardSizeInBytes)); +#elif V8_HAS_BUILTIN_CTZ __builtin_ctz(static_cast(kCardSizeInBytes)); +#else //! V8_HAS_BUILTIN_CTZ + // Hardcode and check with assert. +#if defined(CPPGC_2GB_CAGE) + 11; +#else // !defined(CPPGC_2GB_CAGE) + 12; +#endif // !defined(CPPGC_2GB_CAGE) +#endif // !V8_HAS_BUILTIN_CTZ + static_assert((1 << kGranularityBits) == kCardSizeInBytes); const size_t entry = offset >> kGranularityBits; CPPGC_DCHECK(table_.size() > entry); return entry; @@ -64,10 +94,10 @@ static_assert(sizeof(AgeTable) == 1 * api_constants::kMB, #endif // CPPGC_YOUNG_GENERATION struct CagedHeapLocalData final { - CagedHeapLocalData(HeapBase&, PageAllocator&); + V8_INLINE static CagedHeapLocalData& Get() { + return *reinterpret_cast(CagedHeapBase::GetBase()); + } - bool is_incremental_marking_in_progress = false; - HeapBase& heap_base; #if defined(CPPGC_YOUNG_GENERATION) AgeTable age_table; #endif @@ -76,4 +106,6 @@ struct CagedHeapLocalData final { } // namespace internal } // namespace cppgc +#endif // defined(CPPGC_CAGED_HEAP) + #endif // INCLUDE_CPPGC_INTERNAL_CAGED_HEAP_LOCAL_DATA_H_ diff --git a/deps/v8/include/cppgc/internal/caged-heap.h b/deps/v8/include/cppgc/internal/caged-heap.h new file mode 100644 index 00000000000000..4db42aee089b5d --- /dev/null +++ b/deps/v8/include/cppgc/internal/caged-heap.h @@ -0,0 +1,61 @@ +// Copyright 2022 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. + +#ifndef INCLUDE_CPPGC_INTERNAL_CAGED_HEAP_H_ +#define INCLUDE_CPPGC_INTERNAL_CAGED_HEAP_H_ + +#include +#include + +#include "cppgc/internal/api-constants.h" +#include "cppgc/internal/base-page-handle.h" +#include "v8config.h" // NOLINT(build/include_directory) + +#if defined(CPPGC_CAGED_HEAP) + +namespace cppgc { +namespace internal { + +class V8_EXPORT CagedHeapBase { + public: + V8_INLINE static uintptr_t OffsetFromAddress(const void* address) { + return reinterpret_cast(address) & + (api_constants::kCagedHeapReservationAlignment - 1); + } + + V8_INLINE static bool IsWithinCage(const void* address) { + CPPGC_DCHECK(g_heap_base_); + return (reinterpret_cast(address) & + ~(api_constants::kCagedHeapReservationAlignment - 1)) == + g_heap_base_; + } + + V8_INLINE static bool AreWithinCage(const void* addr1, const void* addr2) { +#if defined(CPPGC_2GB_CAGE) + static constexpr size_t kHalfWordShift = sizeof(uint32_t) * CHAR_BIT - 1; +#else //! defined(CPPGC_2GB_CAGE) + static constexpr size_t kHalfWordShift = sizeof(uint32_t) * CHAR_BIT; +#endif //! defined(CPPGC_2GB_CAGE) + static_assert((static_cast(1) << kHalfWordShift) == + api_constants::kCagedHeapReservationSize); + CPPGC_DCHECK(g_heap_base_); + return !(((reinterpret_cast(addr1) ^ g_heap_base_) | + (reinterpret_cast(addr2) ^ g_heap_base_)) >> + kHalfWordShift); + } + + V8_INLINE static uintptr_t GetBase() { return g_heap_base_; } + + private: + friend class CagedHeap; + + static uintptr_t g_heap_base_; +}; + +} // namespace internal +} // namespace cppgc + +#endif // defined(CPPGC_CAGED_HEAP) + +#endif // INCLUDE_CPPGC_INTERNAL_CAGED_HEAP_H_ diff --git a/deps/v8/include/cppgc/internal/gc-info.h b/deps/v8/include/cppgc/internal/gc-info.h index 82a0d053431f8a..e8f90fed57109f 100644 --- a/deps/v8/include/cppgc/internal/gc-info.h +++ b/deps/v8/include/cppgc/internal/gc-info.h @@ -48,7 +48,6 @@ struct V8_EXPORT EnsureGCInfoIndexTrait final { static GCInfoIndex EnsureGCInfoIndexNonPolymorphic(std::atomic&, TraceCallback, FinalizationCallback, - NameCallback); static GCInfoIndex EnsureGCInfoIndexNonPolymorphic(std::atomic&, TraceCallback, diff --git a/deps/v8/include/cppgc/internal/member-storage.h b/deps/v8/include/cppgc/internal/member-storage.h new file mode 100644 index 00000000000000..98389b8cd3d531 --- /dev/null +++ b/deps/v8/include/cppgc/internal/member-storage.h @@ -0,0 +1,236 @@ +// Copyright 2022 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. + +#ifndef INCLUDE_CPPGC_INTERNAL_MEMBER_STORAGE_H_ +#define INCLUDE_CPPGC_INTERNAL_MEMBER_STORAGE_H_ + +#include +#include +#include + +#include "cppgc/internal/api-constants.h" +#include "cppgc/internal/logging.h" +#include "cppgc/sentinel-pointer.h" +#include "v8config.h" // NOLINT(build/include_directory) + +namespace cppgc { +namespace internal { + +#if defined(CPPGC_POINTER_COMPRESSION) + +#if defined(__clang__) +// Attribute const allows the compiler to assume that CageBaseGlobal::g_base_ +// doesn't change (e.g. across calls) and thereby avoid redundant loads. +#define CPPGC_CONST __attribute__((const)) +#define CPPGC_REQUIRE_CONSTANT_INIT \ + __attribute__((require_constant_initialization)) +#else // defined(__clang__) +#define CPPGC_CONST +#define CPPGC_REQUIRE_CONSTANT_INIT +#endif // defined(__clang__) + +class CageBaseGlobal final { + public: + V8_INLINE CPPGC_CONST static uintptr_t Get() { + CPPGC_DCHECK(IsBaseConsistent()); + return g_base_; + } + + V8_INLINE CPPGC_CONST static bool IsSet() { + CPPGC_DCHECK(IsBaseConsistent()); + return (g_base_ & ~kLowerHalfWordMask) != 0; + } + + private: + // We keep the lower halfword as ones to speed up decompression. + static constexpr uintptr_t kLowerHalfWordMask = + (api_constants::kCagedHeapReservationAlignment - 1); + + static V8_EXPORT uintptr_t g_base_ CPPGC_REQUIRE_CONSTANT_INIT; + + CageBaseGlobal() = delete; + + V8_INLINE static bool IsBaseConsistent() { + return kLowerHalfWordMask == (g_base_ & kLowerHalfWordMask); + } + + friend class CageBaseGlobalUpdater; +}; + +#undef CPPGC_REQUIRE_CONSTANT_INIT +#undef CPPGC_CONST + +class CompressedPointer final { + public: + using IntegralType = uint32_t; + + V8_INLINE CompressedPointer() : value_(0u) {} + V8_INLINE explicit CompressedPointer(const void* ptr) + : value_(Compress(ptr)) {} + V8_INLINE explicit CompressedPointer(std::nullptr_t) : value_(0u) {} + V8_INLINE explicit CompressedPointer(SentinelPointer) + : value_(kCompressedSentinel) {} + + V8_INLINE const void* Load() const { return Decompress(value_); } + V8_INLINE const void* LoadAtomic() const { + return Decompress( + reinterpret_cast&>(value_).load( + std::memory_order_relaxed)); + } + + V8_INLINE void Store(const void* ptr) { value_ = Compress(ptr); } + V8_INLINE void StoreAtomic(const void* value) { + reinterpret_cast&>(value_).store( + Compress(value), std::memory_order_relaxed); + } + + V8_INLINE void Clear() { value_ = 0u; } + V8_INLINE bool IsCleared() const { return !value_; } + + V8_INLINE bool IsSentinel() const { return value_ == kCompressedSentinel; } + + V8_INLINE uint32_t GetAsInteger() const { return value_; } + + V8_INLINE friend bool operator==(CompressedPointer a, CompressedPointer b) { + return a.value_ == b.value_; + } + V8_INLINE friend bool operator!=(CompressedPointer a, CompressedPointer b) { + return a.value_ != b.value_; + } + V8_INLINE friend bool operator<(CompressedPointer a, CompressedPointer b) { + return a.value_ < b.value_; + } + V8_INLINE friend bool operator<=(CompressedPointer a, CompressedPointer b) { + return a.value_ <= b.value_; + } + V8_INLINE friend bool operator>(CompressedPointer a, CompressedPointer b) { + return a.value_ > b.value_; + } + V8_INLINE friend bool operator>=(CompressedPointer a, CompressedPointer b) { + return a.value_ >= b.value_; + } + + static V8_INLINE IntegralType Compress(const void* ptr) { + static_assert( + SentinelPointer::kSentinelValue == 0b10, + "The compression scheme relies on the sentinel encoded as 0b10"); + static constexpr size_t kGigaCageMask = + ~(api_constants::kCagedHeapReservationAlignment - 1); + + CPPGC_DCHECK(CageBaseGlobal::IsSet()); + const uintptr_t base = CageBaseGlobal::Get(); + CPPGC_DCHECK(!ptr || ptr == kSentinelPointer || + (base & kGigaCageMask) == + (reinterpret_cast(ptr) & kGigaCageMask)); + +#if defined(CPPGC_2GB_CAGE) + // Truncate the pointer. + auto compressed = + static_cast(reinterpret_cast(ptr)); +#else // !defined(CPPGC_2GB_CAGE) + const auto uptr = reinterpret_cast(ptr); + // Shift the pointer by one and truncate. + auto compressed = static_cast(uptr >> 1); +#endif // !defined(CPPGC_2GB_CAGE) + // Normal compressed pointers must have the MSB set. + CPPGC_DCHECK((!compressed || compressed == kCompressedSentinel) || + (compressed & (1 << 31))); + return compressed; + } + + static V8_INLINE void* Decompress(IntegralType ptr) { + CPPGC_DCHECK(CageBaseGlobal::IsSet()); + const uintptr_t base = CageBaseGlobal::Get(); + // Treat compressed pointer as signed and cast it to uint64_t, which will + // sign-extend it. +#if defined(CPPGC_2GB_CAGE) + const uint64_t mask = static_cast(static_cast(ptr)); +#else // !defined(CPPGC_2GB_CAGE) + // Then, shift the result by one. It's important to shift the unsigned + // value, as otherwise it would result in undefined behavior. + const uint64_t mask = static_cast(static_cast(ptr)) << 1; +#endif // !defined(CPPGC_2GB_CAGE) + return reinterpret_cast(mask & base); + } + + private: +#if defined(CPPGC_2GB_CAGE) + static constexpr IntegralType kCompressedSentinel = + SentinelPointer::kSentinelValue; +#else // !defined(CPPGC_2GB_CAGE) + static constexpr IntegralType kCompressedSentinel = + SentinelPointer::kSentinelValue >> 1; +#endif // !defined(CPPGC_2GB_CAGE) + // All constructors initialize `value_`. Do not add a default value here as it + // results in a non-atomic write on some builds, even when the atomic version + // of the constructor is used. + IntegralType value_; +}; + +#endif // defined(CPPGC_POINTER_COMPRESSION) + +class RawPointer final { + public: + using IntegralType = uintptr_t; + + V8_INLINE RawPointer() : ptr_(nullptr) {} + V8_INLINE explicit RawPointer(const void* ptr) : ptr_(ptr) {} + + V8_INLINE const void* Load() const { return ptr_; } + V8_INLINE const void* LoadAtomic() const { + return reinterpret_cast&>(ptr_).load( + std::memory_order_relaxed); + } + + V8_INLINE void Store(const void* ptr) { ptr_ = ptr; } + V8_INLINE void StoreAtomic(const void* ptr) { + reinterpret_cast&>(ptr_).store( + ptr, std::memory_order_relaxed); + } + + V8_INLINE void Clear() { ptr_ = nullptr; } + V8_INLINE bool IsCleared() const { return !ptr_; } + + V8_INLINE bool IsSentinel() const { return ptr_ == kSentinelPointer; } + + V8_INLINE uintptr_t GetAsInteger() const { + return reinterpret_cast(ptr_); + } + + V8_INLINE friend bool operator==(RawPointer a, RawPointer b) { + return a.ptr_ == b.ptr_; + } + V8_INLINE friend bool operator!=(RawPointer a, RawPointer b) { + return a.ptr_ != b.ptr_; + } + V8_INLINE friend bool operator<(RawPointer a, RawPointer b) { + return a.ptr_ < b.ptr_; + } + V8_INLINE friend bool operator<=(RawPointer a, RawPointer b) { + return a.ptr_ <= b.ptr_; + } + V8_INLINE friend bool operator>(RawPointer a, RawPointer b) { + return a.ptr_ > b.ptr_; + } + V8_INLINE friend bool operator>=(RawPointer a, RawPointer b) { + return a.ptr_ >= b.ptr_; + } + + private: + // All constructors initialize `ptr_`. Do not add a default value here as it + // results in a non-atomic write on some builds, even when the atomic version + // of the constructor is used. + const void* ptr_; +}; + +#if defined(CPPGC_POINTER_COMPRESSION) +using MemberStorage = CompressedPointer; +#else // !defined(CPPGC_POINTER_COMPRESSION) +using MemberStorage = RawPointer; +#endif // !defined(CPPGC_POINTER_COMPRESSION) + +} // namespace internal +} // namespace cppgc + +#endif // INCLUDE_CPPGC_INTERNAL_MEMBER_STORAGE_H_ diff --git a/deps/v8/include/cppgc/internal/name-trait.h b/deps/v8/include/cppgc/internal/name-trait.h index 32a334785926d7..1d927a9d0a962c 100644 --- a/deps/v8/include/cppgc/internal/name-trait.h +++ b/deps/v8/include/cppgc/internal/name-trait.h @@ -6,6 +6,7 @@ #define INCLUDE_CPPGC_INTERNAL_NAME_TRAIT_H_ #include +#include #include #include "cppgc/name-provider.h" @@ -58,6 +59,11 @@ struct HeapObjectName { bool name_was_hidden; }; +enum class HeapObjectNameForUnnamedObject : uint8_t { + kUseClassNameIfSupported, + kUseHiddenName, +}; + class V8_EXPORT NameTraitBase { protected: static HeapObjectName GetNameFromTypeSignature(const char*); @@ -78,16 +84,24 @@ class NameTrait final : public NameTraitBase { #endif // !CPPGC_SUPPORTS_OBJECT_NAMES } - static HeapObjectName GetName(const void* obj) { - return GetNameFor(static_cast(obj)); + static HeapObjectName GetName( + const void* obj, HeapObjectNameForUnnamedObject name_retrieval_mode) { + return GetNameFor(static_cast(obj), name_retrieval_mode); } private: - static HeapObjectName GetNameFor(const NameProvider* name_provider) { + static HeapObjectName GetNameFor(const NameProvider* name_provider, + HeapObjectNameForUnnamedObject) { + // Objects inheriting from `NameProvider` are not considered unnamed as + // users already provided a name for them. return {name_provider->GetHumanReadableName(), false}; } - static HeapObjectName GetNameFor(...) { + static HeapObjectName GetNameFor( + const void*, HeapObjectNameForUnnamedObject name_retrieval_mode) { + if (name_retrieval_mode == HeapObjectNameForUnnamedObject::kUseHiddenName) + return {NameProvider::kHiddenName, true}; + #if CPPGC_SUPPORTS_COMPILE_TIME_TYPENAME return {GetTypename(), false}; #elif CPPGC_SUPPORTS_OBJECT_NAMES @@ -102,7 +116,7 @@ class NameTrait final : public NameTraitBase { static const HeapObjectName leaky_name = GetNameFromTypeSignature(PRETTY_FUNCTION_VALUE); - return {leaky_name, false}; + return leaky_name; #undef PRETTY_FUNCTION_VALUE @@ -112,7 +126,8 @@ class NameTrait final : public NameTraitBase { } }; -using NameCallback = HeapObjectName (*)(const void*); +using NameCallback = HeapObjectName (*)(const void*, + HeapObjectNameForUnnamedObject); } // namespace internal } // namespace cppgc diff --git a/deps/v8/include/cppgc/internal/persistent-node.h b/deps/v8/include/cppgc/internal/persistent-node.h index 22b4cf093c110f..d22692a768c49f 100644 --- a/deps/v8/include/cppgc/internal/persistent-node.h +++ b/deps/v8/include/cppgc/internal/persistent-node.h @@ -14,13 +14,11 @@ #include "v8config.h" // NOLINT(build/include_directory) namespace cppgc { - -class Visitor; - namespace internal { class CrossThreadPersistentRegion; class FatalOutOfMemoryHandler; +class RootVisitor; // PersistentNode represents a variant of two states: // 1) traceable node with a back pointer to the Persistent object; @@ -32,7 +30,7 @@ class PersistentNode final { PersistentNode(const PersistentNode&) = delete; PersistentNode& operator=(const PersistentNode&) = delete; - void InitializeAsUsedNode(void* owner, TraceCallback trace) { + void InitializeAsUsedNode(void* owner, TraceRootCallback trace) { CPPGC_DCHECK(trace); owner_ = owner; trace_ = trace; @@ -53,9 +51,9 @@ class PersistentNode final { return next_; } - void Trace(Visitor* visitor) const { + void Trace(RootVisitor& root_visitor) const { CPPGC_DCHECK(IsUsed()); - trace_(visitor, owner_); + trace_(root_visitor, owner_); } bool IsUsed() const { return trace_; } @@ -73,7 +71,7 @@ class PersistentNode final { void* owner_ = nullptr; PersistentNode* next_; }; - TraceCallback trace_ = nullptr; + TraceRootCallback trace_ = nullptr; }; class V8_EXPORT PersistentRegionBase { @@ -86,7 +84,7 @@ class V8_EXPORT PersistentRegionBase { PersistentRegionBase(const PersistentRegionBase&) = delete; PersistentRegionBase& operator=(const PersistentRegionBase&) = delete; - void Trace(Visitor*); + void Iterate(RootVisitor&); size_t NodesInUse() const; @@ -96,7 +94,7 @@ class V8_EXPORT PersistentRegionBase { explicit PersistentRegionBase(const FatalOutOfMemoryHandler& oom_handler); PersistentNode* TryAllocateNodeFromFreeList(void* owner, - TraceCallback trace) { + TraceRootCallback trace) { PersistentNode* node = nullptr; if (V8_LIKELY(free_list_head_)) { node = free_list_head_; @@ -118,7 +116,7 @@ class V8_EXPORT PersistentRegionBase { } PersistentNode* RefillFreeListAndAllocateNode(void* owner, - TraceCallback trace); + TraceRootCallback trace); private: template @@ -145,7 +143,7 @@ class V8_EXPORT PersistentRegion final : public PersistentRegionBase { PersistentRegion(const PersistentRegion&) = delete; PersistentRegion& operator=(const PersistentRegion&) = delete; - V8_INLINE PersistentNode* AllocateNode(void* owner, TraceCallback trace) { + V8_INLINE PersistentNode* AllocateNode(void* owner, TraceRootCallback trace) { CPPGC_DCHECK(IsCreationThread()); auto* node = TryAllocateNodeFromFreeList(owner, trace); if (V8_LIKELY(node)) return node; @@ -189,7 +187,7 @@ class V8_EXPORT CrossThreadPersistentRegion final CrossThreadPersistentRegion& operator=(const CrossThreadPersistentRegion&) = delete; - V8_INLINE PersistentNode* AllocateNode(void* owner, TraceCallback trace) { + V8_INLINE PersistentNode* AllocateNode(void* owner, TraceRootCallback trace) { PersistentRegionLock::AssertLocked(); auto* node = TryAllocateNodeFromFreeList(owner, trace); if (V8_LIKELY(node)) return node; @@ -202,7 +200,7 @@ class V8_EXPORT CrossThreadPersistentRegion final PersistentRegionBase::FreeNode(node); } - void Trace(Visitor*); + void Iterate(RootVisitor&); size_t NodesInUse() const; diff --git a/deps/v8/include/cppgc/internal/pointer-policies.h b/deps/v8/include/cppgc/internal/pointer-policies.h index 853d7031530979..8455b3df8196b4 100644 --- a/deps/v8/include/cppgc/internal/pointer-policies.h +++ b/deps/v8/include/cppgc/internal/pointer-policies.h @@ -8,6 +8,7 @@ #include #include +#include "cppgc/internal/member-storage.h" #include "cppgc/internal/write-barrier.h" #include "cppgc/sentinel-pointer.h" #include "cppgc/source-location.h" @@ -27,15 +28,34 @@ class WeakMemberTag; class UntracedMemberTag; struct DijkstraWriteBarrierPolicy { - static void InitializingBarrier(const void*, const void*) { + V8_INLINE static void InitializingBarrier(const void*, const void*) { // Since in initializing writes the source object is always white, having no // barrier doesn't break the tri-color invariant. } - static void AssigningBarrier(const void* slot, const void* value) { + + V8_INLINE static void AssigningBarrier(const void* slot, const void* value) { + WriteBarrier::Params params; + const WriteBarrier::Type type = + WriteBarrier::GetWriteBarrierType(slot, value, params); + WriteBarrier(type, params, slot, value); + } + + V8_INLINE static void AssigningBarrier(const void* slot, + MemberStorage storage) { WriteBarrier::Params params; - switch (WriteBarrier::GetWriteBarrierType(slot, value, params)) { + const WriteBarrier::Type type = + WriteBarrier::GetWriteBarrierType(slot, storage, params); + WriteBarrier(type, params, slot, storage.Load()); + } + + private: + V8_INLINE static void WriteBarrier(WriteBarrier::Type type, + const WriteBarrier::Params& params, + const void* slot, const void* value) { + switch (type) { case WriteBarrier::Type::kGenerational: - WriteBarrier::GenerationalBarrier(params, slot); + WriteBarrier::GenerationalBarrier< + WriteBarrier::GenerationalBarrierType::kPreciseSlot>(params, slot); break; case WriteBarrier::Type::kMarking: WriteBarrier::DijkstraMarkingBarrier(params, value); @@ -47,8 +67,9 @@ struct DijkstraWriteBarrierPolicy { }; struct NoWriteBarrierPolicy { - static void InitializingBarrier(const void*, const void*) {} - static void AssigningBarrier(const void*, const void*) {} + V8_INLINE static void InitializingBarrier(const void*, const void*) {} + V8_INLINE static void AssigningBarrier(const void*, const void*) {} + V8_INLINE static void AssigningBarrier(const void*, MemberStorage) {} }; class V8_EXPORT SameThreadEnabledCheckingPolicyBase { @@ -89,7 +110,7 @@ class V8_EXPORT SameThreadEnabledCheckingPolicy class DisabledCheckingPolicy { protected: - void CheckPointer(const void*) {} + V8_INLINE void CheckPointer(const void*) {} }; #ifdef DEBUG diff --git a/deps/v8/include/cppgc/internal/write-barrier.h b/deps/v8/include/cppgc/internal/write-barrier.h index bfabc31e13a969..2d8e14be086d64 100644 --- a/deps/v8/include/cppgc/internal/write-barrier.h +++ b/deps/v8/include/cppgc/internal/write-barrier.h @@ -8,9 +8,11 @@ #include #include +#include "cppgc/heap-handle.h" #include "cppgc/heap-state.h" #include "cppgc/internal/api-constants.h" #include "cppgc/internal/atomic-entry-flag.h" +#include "cppgc/internal/member-storage.h" #include "cppgc/platform.h" #include "cppgc/sentinel-pointer.h" #include "cppgc/trace-trait.h" @@ -18,6 +20,7 @@ #if defined(CPPGC_CAGED_HEAP) #include "cppgc/internal/caged-heap-local-data.h" +#include "cppgc/internal/caged-heap.h" #endif namespace cppgc { @@ -40,16 +43,18 @@ class V8_EXPORT WriteBarrier final { kGenerational, }; + enum class GenerationalBarrierType : uint8_t { + kPreciseSlot, + kPreciseUncompressedSlot, + kImpreciseSlot, + }; + struct Params { HeapHandle* heap = nullptr; #if V8_ENABLE_CHECKS Type type = Type::kNone; #endif // !V8_ENABLE_CHECKS #if defined(CPPGC_CAGED_HEAP) - uintptr_t start = 0; - CagedHeapLocalData& caged_heap() const { - return *reinterpret_cast(start); - } uintptr_t slot_offset = 0; uintptr_t value_offset = 0; #endif // CPPGC_CAGED_HEAP @@ -63,6 +68,9 @@ class V8_EXPORT WriteBarrier final { // Returns the required write barrier for a given `slot` and `value`. static V8_INLINE Type GetWriteBarrierType(const void* slot, const void* value, Params& params); + // Returns the required write barrier for a given `slot` and `value`. + static V8_INLINE Type GetWriteBarrierType(const void* slot, MemberStorage, + Params& params); // Returns the required write barrier for a given `slot`. template static V8_INLINE Type GetWriteBarrierType(const void* slot, Params& params, @@ -78,15 +86,13 @@ class V8_EXPORT WriteBarrier final { static V8_INLINE void SteeleMarkingBarrier(const Params& params, const void* object); #if defined(CPPGC_YOUNG_GENERATION) + template static V8_INLINE void GenerationalBarrier(const Params& params, const void* slot); - static V8_INLINE void GenerationalBarrierForSourceObject( - const Params& params, const void* inner_pointer); #else // !CPPGC_YOUNG_GENERATION + template static V8_INLINE void GenerationalBarrier(const Params& params, - const void* slot) {} - static V8_INLINE void GenerationalBarrierForSourceObject( - const Params& params, const void* inner_pointer) {} + const void* slot){} #endif // CPPGC_YOUNG_GENERATION #if V8_ENABLE_CHECKS @@ -95,12 +101,10 @@ class V8_EXPORT WriteBarrier final { static void CheckParams(Type expected_type, const Params& params) {} #endif // !V8_ENABLE_CHECKS - // The IncrementalOrConcurrentUpdater class allows cppgc internal to update - // |incremental_or_concurrent_marking_flag_|. - class IncrementalOrConcurrentMarkingFlagUpdater; - static bool IsAnyIncrementalOrConcurrentMarking() { - return incremental_or_concurrent_marking_flag_.MightBeEntered(); - } + // The FlagUpdater class allows cppgc internal to update + // |write_barrier_enabled_|. + class FlagUpdater; + static bool IsEnabled() { return write_barrier_enabled_.MightBeEntered(); } private: WriteBarrier() = delete; @@ -125,17 +129,23 @@ class V8_EXPORT WriteBarrier final { static CagedHeapLocalData& GetLocalData(HeapHandle&); static void GenerationalBarrierSlow(const CagedHeapLocalData& local_data, const AgeTable& age_table, - const void* slot, uintptr_t value_offset); + const void* slot, uintptr_t value_offset, + HeapHandle* heap_handle); + static void GenerationalBarrierForUncompressedSlotSlow( + const CagedHeapLocalData& local_data, const AgeTable& age_table, + const void* slot, uintptr_t value_offset, HeapHandle* heap_handle); static void GenerationalBarrierForSourceObjectSlow( - const CagedHeapLocalData& local_data, const void* object); + const CagedHeapLocalData& local_data, const void* object, + HeapHandle* heap_handle); #endif // CPPGC_YOUNG_GENERATION - static AtomicEntryFlag incremental_or_concurrent_marking_flag_; + static AtomicEntryFlag write_barrier_enabled_; }; template V8_INLINE WriteBarrier::Type SetAndReturnType(WriteBarrier::Params& params) { - if (type == WriteBarrier::Type::kNone) return WriteBarrier::Type::kNone; + if constexpr (type == WriteBarrier::Type::kNone) + return WriteBarrier::Type::kNone; #if V8_ENABLE_CHECKS params.type = type; #endif // !V8_ENABLE_CHECKS @@ -152,6 +162,13 @@ class V8_EXPORT WriteBarrierTypeForCagedHeapPolicy final { return ValueModeDispatch::Get(slot, value, params, callback); } + template + static V8_INLINE WriteBarrier::Type Get(const void* slot, MemberStorage value, + WriteBarrier::Params& params, + HeapHandleCallback callback) { + return ValueModeDispatch::Get(slot, value, params, callback); + } + template static V8_INLINE WriteBarrier::Type Get(const void* value, WriteBarrier::Params& params, @@ -166,69 +183,77 @@ class V8_EXPORT WriteBarrierTypeForCagedHeapPolicy final { static V8_INLINE WriteBarrier::Type GetNoSlot(const void* value, WriteBarrier::Params& params, HeapHandleCallback) { - if (!TryGetCagedHeap(value, value, params)) { - return WriteBarrier::Type::kNone; - } - if (V8_UNLIKELY(params.caged_heap().is_incremental_marking_in_progress)) { + const bool within_cage = CagedHeapBase::IsWithinCage(value); + if (!within_cage) return WriteBarrier::Type::kNone; + + // We know that |value| points either within the normal page or to the + // beginning of large-page, so extract the page header by bitmasking. + BasePageHandle* page = + BasePageHandle::FromPayload(const_cast(value)); + + HeapHandle& heap_handle = page->heap_handle(); + if (V8_UNLIKELY(heap_handle.is_incremental_marking_in_progress())) { return SetAndReturnType(params); } + return SetAndReturnType(params); } template struct ValueModeDispatch; - - static V8_INLINE bool TryGetCagedHeap(const void* slot, const void* value, - WriteBarrier::Params& params) { - // TODO(chromium:1056170): Check if the null check can be folded in with - // the rest of the write barrier. - if (!value) return false; - params.start = reinterpret_cast(value) & - ~(api_constants::kCagedHeapReservationAlignment - 1); - const uintptr_t slot_offset = - reinterpret_cast(slot) - params.start; - if (slot_offset > api_constants::kCagedHeapReservationSize) { - // Check if slot is on stack or value is sentinel or nullptr. This relies - // on the fact that kSentinelPointer is encoded as 0x1. - return false; - } - return true; - } - - // Returns whether marking is in progress. If marking is not in progress - // sets the start of the cage accordingly. - // - // TODO(chromium:1056170): Create fast path on API. - static bool IsMarking(const HeapHandle&, WriteBarrier::Params&); }; template <> struct WriteBarrierTypeForCagedHeapPolicy::ValueModeDispatch< WriteBarrier::ValueMode::kValuePresent> { + template + static V8_INLINE WriteBarrier::Type Get(const void* slot, + MemberStorage storage, + WriteBarrier::Params& params, + HeapHandleCallback) { + if (V8_LIKELY(!WriteBarrier::IsEnabled())) + return SetAndReturnType(params); + + return BarrierEnabledGet(slot, storage.Load(), params); + } + template static V8_INLINE WriteBarrier::Type Get(const void* slot, const void* value, WriteBarrier::Params& params, HeapHandleCallback) { -#if !defined(CPPGC_YOUNG_GENERATION) - if (V8_LIKELY(!WriteBarrier::IsAnyIncrementalOrConcurrentMarking())) { + if (V8_LIKELY(!WriteBarrier::IsEnabled())) return SetAndReturnType(params); - } -#endif // !CPPGC_YOUNG_GENERATION - bool within_cage = TryGetCagedHeap(slot, value, params); - if (!within_cage) { - return WriteBarrier::Type::kNone; - } - if (V8_LIKELY(!params.caged_heap().is_incremental_marking_in_progress)) { + + return BarrierEnabledGet(slot, value, params); + } + + private: + static V8_INLINE WriteBarrier::Type BarrierEnabledGet( + const void* slot, const void* value, WriteBarrier::Params& params) { + const bool within_cage = CagedHeapBase::AreWithinCage(slot, value); + if (!within_cage) return WriteBarrier::Type::kNone; + + // We know that |value| points either within the normal page or to the + // beginning of large-page, so extract the page header by bitmasking. + BasePageHandle* page = + BasePageHandle::FromPayload(const_cast(value)); + + HeapHandle& heap_handle = page->heap_handle(); + if (V8_LIKELY(!heap_handle.is_incremental_marking_in_progress())) { #if defined(CPPGC_YOUNG_GENERATION) - params.heap = reinterpret_cast(params.start); - params.slot_offset = reinterpret_cast(slot) - params.start; - params.value_offset = reinterpret_cast(value) - params.start; + if (!heap_handle.is_young_generation_enabled()) + return WriteBarrier::Type::kNone; + params.heap = &heap_handle; + params.slot_offset = CagedHeapBase::OffsetFromAddress(slot); + params.value_offset = CagedHeapBase::OffsetFromAddress(value); return SetAndReturnType(params); #else // !CPPGC_YOUNG_GENERATION return SetAndReturnType(params); #endif // !CPPGC_YOUNG_GENERATION } - params.heap = reinterpret_cast(params.start); + + // Use marking barrier. + params.heap = &heap_handle; return SetAndReturnType(params); } }; @@ -240,28 +265,28 @@ struct WriteBarrierTypeForCagedHeapPolicy::ValueModeDispatch< static V8_INLINE WriteBarrier::Type Get(const void* slot, const void*, WriteBarrier::Params& params, HeapHandleCallback callback) { -#if defined(CPPGC_YOUNG_GENERATION) + if (V8_LIKELY(!WriteBarrier::IsEnabled())) + return SetAndReturnType(params); + HeapHandle& handle = callback(); - if (V8_LIKELY(!IsMarking(handle, params))) { - // params.start is populated by IsMarking(). +#if defined(CPPGC_YOUNG_GENERATION) + if (V8_LIKELY(!handle.is_incremental_marking_in_progress())) { + if (!handle.is_young_generation_enabled()) { + return WriteBarrier::Type::kNone; + } params.heap = &handle; - params.slot_offset = reinterpret_cast(slot) - params.start; - // params.value_offset stays 0. - if (params.slot_offset > api_constants::kCagedHeapReservationSize) { - // Check if slot is on stack. + // Check if slot is on stack. + if (V8_UNLIKELY(!CagedHeapBase::IsWithinCage(slot))) { return SetAndReturnType(params); } + params.slot_offset = CagedHeapBase::OffsetFromAddress(slot); return SetAndReturnType(params); } -#else // !CPPGC_YOUNG_GENERATION - if (V8_LIKELY(!WriteBarrier::IsAnyIncrementalOrConcurrentMarking())) { - return SetAndReturnType(params); - } - HeapHandle& handle = callback(); +#else // !defined(CPPGC_YOUNG_GENERATION) if (V8_UNLIKELY(!subtle::HeapState::IsMarking(handle))) { return SetAndReturnType(params); } -#endif // !CPPGC_YOUNG_GENERATION +#endif // !defined(CPPGC_YOUNG_GENERATION) params.heap = &handle; return SetAndReturnType(params); } @@ -278,6 +303,16 @@ class V8_EXPORT WriteBarrierTypeForNonCagedHeapPolicy final { return ValueModeDispatch::Get(slot, value, params, callback); } + template + static V8_INLINE WriteBarrier::Type Get(const void* slot, MemberStorage value, + WriteBarrier::Params& params, + HeapHandleCallback callback) { + // `MemberStorage` will always be `RawPointer` for non-caged heap builds. + // Just convert to `void*` in this case. + return ValueModeDispatch::Get(slot, value.Load(), params, + callback); + } + template static V8_INLINE WriteBarrier::Type Get(const void* value, WriteBarrier::Params& params, @@ -310,7 +345,7 @@ struct WriteBarrierTypeForNonCagedHeapPolicy::ValueModeDispatch< if (object <= static_cast(kSentinelPointer)) { return SetAndReturnType(params); } - if (V8_LIKELY(!WriteBarrier::IsAnyIncrementalOrConcurrentMarking())) { + if (V8_LIKELY(!WriteBarrier::IsEnabled())) { return SetAndReturnType(params); } if (IsMarking(object, ¶ms.heap)) { @@ -327,7 +362,7 @@ struct WriteBarrierTypeForNonCagedHeapPolicy::ValueModeDispatch< static V8_INLINE WriteBarrier::Type Get(const void*, const void*, WriteBarrier::Params& params, HeapHandleCallback callback) { - if (V8_UNLIKELY(WriteBarrier::IsAnyIncrementalOrConcurrentMarking())) { + if (V8_UNLIKELY(WriteBarrier::IsEnabled())) { HeapHandle& handle = callback(); if (IsMarking(handle)) { params.heap = &handle; @@ -345,6 +380,13 @@ WriteBarrier::Type WriteBarrier::GetWriteBarrierType( params, []() {}); } +// static +WriteBarrier::Type WriteBarrier::GetWriteBarrierType( + const void* slot, MemberStorage value, WriteBarrier::Params& params) { + return WriteBarrierTypePolicy::Get(slot, value, + params, []() {}); +} + // static template WriteBarrier::Type WriteBarrier::GetWriteBarrierType( @@ -397,34 +439,32 @@ void WriteBarrier::SteeleMarkingBarrier(const Params& params, } #if defined(CPPGC_YOUNG_GENERATION) -// static -void WriteBarrier::GenerationalBarrier(const Params& params, const void* slot) { - CheckParams(Type::kGenerational, params); - - const CagedHeapLocalData& local_data = params.caged_heap(); - const AgeTable& age_table = local_data.age_table; - - // Bail out if the slot is in young generation. - if (V8_LIKELY(age_table.GetAge(params.slot_offset) == AgeTable::Age::kYoung)) - return; - - GenerationalBarrierSlow(local_data, age_table, slot, params.value_offset); -} // static -void WriteBarrier::GenerationalBarrierForSourceObject( - const Params& params, const void* inner_pointer) { +template +void WriteBarrier::GenerationalBarrier(const Params& params, const void* slot) { CheckParams(Type::kGenerational, params); - const CagedHeapLocalData& local_data = params.caged_heap(); + const CagedHeapLocalData& local_data = CagedHeapLocalData::Get(); const AgeTable& age_table = local_data.age_table; - // Assume that if the first element is in young generation, the whole range is - // in young generation. + // Bail out if the slot (precise or imprecise) is in young generation. if (V8_LIKELY(age_table.GetAge(params.slot_offset) == AgeTable::Age::kYoung)) return; - GenerationalBarrierForSourceObjectSlow(local_data, inner_pointer); + // Dispatch between different types of barriers. + // TODO(chromium:1029379): Consider reload local_data in the slow path to + // reduce register pressure. + if constexpr (type == GenerationalBarrierType::kPreciseSlot) { + GenerationalBarrierSlow(local_data, age_table, slot, params.value_offset, + params.heap); + } else if constexpr (type == + GenerationalBarrierType::kPreciseUncompressedSlot) { + GenerationalBarrierForUncompressedSlotSlow( + local_data, age_table, slot, params.value_offset, params.heap); + } else { + GenerationalBarrierForSourceObjectSlow(local_data, slot, params.heap); + } } #endif // !CPPGC_YOUNG_GENERATION diff --git a/deps/v8/include/cppgc/liveness-broker.h b/deps/v8/include/cppgc/liveness-broker.h index c94eef0d4acdad..2c94f1c0fade96 100644 --- a/deps/v8/include/cppgc/liveness-broker.h +++ b/deps/v8/include/cppgc/liveness-broker.h @@ -7,6 +7,7 @@ #include "cppgc/heap.h" #include "cppgc/member.h" +#include "cppgc/sentinel-pointer.h" #include "cppgc/trace-trait.h" #include "v8config.h" // NOLINT(build/include_directory) @@ -44,24 +45,24 @@ class V8_EXPORT LivenessBroker final { public: template bool IsHeapObjectAlive(const T* object) const { - // nullptr objects are considered alive to allow weakness to be used from + // - nullptr objects are considered alive to allow weakness to be used from // stack while running into a conservative GC. Treating nullptr as dead - // would mean that e.g. custom collectins could not be strongified on stack. - return !object || + // would mean that e.g. custom collections could not be strongified on + // stack. + // - Sentinel pointers are also preserved in weakness and not cleared. + return !object || object == kSentinelPointer || IsHeapObjectAliveImpl( TraceTrait::GetTraceDescriptor(object).base_object_payload); } template bool IsHeapObjectAlive(const WeakMember& weak_member) const { - return (weak_member != kSentinelPointer) && - IsHeapObjectAlive(weak_member.Get()); + return IsHeapObjectAlive(weak_member.Get()); } template bool IsHeapObjectAlive(const UntracedMember& untraced_member) const { - return (untraced_member != kSentinelPointer) && - IsHeapObjectAlive(untraced_member.Get()); + return IsHeapObjectAlive(untraced_member.Get()); } private: diff --git a/deps/v8/include/cppgc/member.h b/deps/v8/include/cppgc/member.h index 66a8cfd80294c3..71f9cab65280da 100644 --- a/deps/v8/include/cppgc/member.h +++ b/deps/v8/include/cppgc/member.h @@ -9,6 +9,8 @@ #include #include +#include "cppgc/internal/api-constants.h" +#include "cppgc/internal/member-storage.h" #include "cppgc/internal/pointer-policies.h" #include "cppgc/sentinel-pointer.h" #include "cppgc/type-traits.h" @@ -16,6 +18,10 @@ namespace cppgc { +namespace subtle { +class HeapConsistency; +} // namespace subtle + class Visitor; namespace internal { @@ -23,33 +29,46 @@ namespace internal { // MemberBase always refers to the object as const object and defers to // BasicMember on casting to the right type as needed. class MemberBase { + public: +#if defined(CPPGC_POINTER_COMPRESSION) + using RawStorage = CompressedPointer; +#else // !defined(CPPGC_POINTER_COMPRESSION) + using RawStorage = RawPointer; +#endif // !defined(CPPGC_POINTER_COMPRESSION) protected: struct AtomicInitializerTag {}; - MemberBase() : raw_(nullptr) {} - explicit MemberBase(const void* value) : raw_(value) {} - MemberBase(const void* value, AtomicInitializerTag) { SetRawAtomic(value); } + V8_INLINE MemberBase() = default; + V8_INLINE explicit MemberBase(const void* value) : raw_(value) {} + V8_INLINE MemberBase(const void* value, AtomicInitializerTag) { + SetRawAtomic(value); + } - const void** GetRawSlot() const { return &raw_; } - const void* GetRaw() const { return raw_; } - void SetRaw(void* value) { raw_ = value; } + V8_INLINE explicit MemberBase(RawStorage raw) : raw_(raw) {} + V8_INLINE explicit MemberBase(std::nullptr_t) : raw_(nullptr) {} + V8_INLINE explicit MemberBase(SentinelPointer s) : raw_(s) {} - const void* GetRawAtomic() const { - return reinterpret_cast*>(&raw_)->load( - std::memory_order_relaxed); + V8_INLINE const void** GetRawSlot() const { + return reinterpret_cast(const_cast(this)); } - void SetRawAtomic(const void* value) { - reinterpret_cast*>(&raw_)->store( - value, std::memory_order_relaxed); + V8_INLINE const void* GetRaw() const { return raw_.Load(); } + V8_INLINE void SetRaw(void* value) { raw_.Store(value); } + + V8_INLINE const void* GetRawAtomic() const { return raw_.LoadAtomic(); } + V8_INLINE void SetRawAtomic(const void* value) { raw_.StoreAtomic(value); } + + V8_INLINE RawStorage GetRawStorage() const { return raw_; } + V8_INLINE void SetRawStorageAtomic(RawStorage other) { + reinterpret_cast&>(raw_).store( + other, std::memory_order_relaxed); } - void ClearFromGC() const { raw_ = nullptr; } + V8_INLINE bool IsCleared() const { return raw_.IsCleared(); } + + V8_INLINE void ClearFromGC() const { raw_.Clear(); } private: - // All constructors initialize `raw_`. Do not add a default value here as it - // results in a non-atomic write on some builds, even when the atomic version - // of the constructor is used. - mutable const void* raw_; + mutable RawStorage raw_; }; // The basic class from which all Member classes are 'generated'. @@ -59,134 +78,184 @@ class BasicMember final : private MemberBase, private CheckingPolicy { public: using PointeeType = T; - constexpr BasicMember() = default; - constexpr BasicMember(std::nullptr_t) {} // NOLINT - BasicMember(SentinelPointer s) : MemberBase(s) {} // NOLINT - BasicMember(T* raw) : MemberBase(raw) { // NOLINT - InitializingWriteBarrier(); + V8_INLINE constexpr BasicMember() = default; + V8_INLINE constexpr BasicMember(std::nullptr_t) {} // NOLINT + V8_INLINE BasicMember(SentinelPointer s) : MemberBase(s) {} // NOLINT + V8_INLINE BasicMember(T* raw) : MemberBase(raw) { // NOLINT + InitializingWriteBarrier(raw); this->CheckPointer(Get()); } - BasicMember(T& raw) : BasicMember(&raw) {} // NOLINT + V8_INLINE BasicMember(T& raw) // NOLINT + : BasicMember(&raw) {} + // Atomic ctor. Using the AtomicInitializerTag forces BasicMember to // initialize using atomic assignments. This is required for preventing // data races with concurrent marking. using AtomicInitializerTag = MemberBase::AtomicInitializerTag; - BasicMember(std::nullptr_t, AtomicInitializerTag atomic) + V8_INLINE BasicMember(std::nullptr_t, AtomicInitializerTag atomic) : MemberBase(nullptr, atomic) {} - BasicMember(SentinelPointer s, AtomicInitializerTag atomic) + V8_INLINE BasicMember(SentinelPointer s, AtomicInitializerTag atomic) : MemberBase(s, atomic) {} - BasicMember(T* raw, AtomicInitializerTag atomic) : MemberBase(raw, atomic) { - InitializingWriteBarrier(); + V8_INLINE BasicMember(T* raw, AtomicInitializerTag atomic) + : MemberBase(raw, atomic) { + InitializingWriteBarrier(raw); this->CheckPointer(Get()); } - BasicMember(T& raw, AtomicInitializerTag atomic) + V8_INLINE BasicMember(T& raw, AtomicInitializerTag atomic) : BasicMember(&raw, atomic) {} + // Copy ctor. - BasicMember(const BasicMember& other) : BasicMember(other.Get()) {} - // Allow heterogeneous construction. + V8_INLINE BasicMember(const BasicMember& other) + : BasicMember(other.GetRawStorage()) {} + + // Heterogeneous copy constructors. When the source pointer have a different + // type, perform a compress-decompress round, because the source pointer may + // need to be adjusted. template ::value>> - BasicMember( // NOLINT + std::enable_if_t>* = nullptr> + V8_INLINE BasicMember( // NOLINT + const BasicMember& other) + : BasicMember(other.GetRawStorage()) {} + + template >* = nullptr> + V8_INLINE BasicMember( // NOLINT const BasicMember& other) : BasicMember(other.Get()) {} + // Move ctor. - BasicMember(BasicMember&& other) noexcept : BasicMember(other.Get()) { + V8_INLINE BasicMember(BasicMember&& other) noexcept + : BasicMember(other.GetRawStorage()) { other.Clear(); } - // Allow heterogeneous move construction. + + // Heterogeneous move constructors. When the source pointer have a different + // type, perform a compress-decompress round, because the source pointer may + // need to be adjusted. template ::value>> - BasicMember(BasicMember&& other) noexcept + std::enable_if_t>* = nullptr> + V8_INLINE BasicMember(BasicMember&& other) noexcept + : BasicMember(other.GetRawStorage()) { + other.Clear(); + } + + template >* = nullptr> + V8_INLINE BasicMember(BasicMember&& other) noexcept : BasicMember(other.Get()) { other.Clear(); } + // Construction from Persistent. template ::value>> - BasicMember(const BasicPersistent& p) + V8_INLINE BasicMember(const BasicPersistent& p) : BasicMember(p.Get()) {} // Copy assignment. - BasicMember& operator=(const BasicMember& other) { - return operator=(other.Get()); + V8_INLINE BasicMember& operator=(const BasicMember& other) { + return operator=(other.GetRawStorage()); } - // Allow heterogeneous copy assignment. + + // Heterogeneous copy assignment. When the source pointer have a different + // type, perform a compress-decompress round, because the source pointer may + // need to be adjusted. template ::value>> - BasicMember& operator=( + typename OtherCheckingPolicy> + V8_INLINE BasicMember& operator=( const BasicMember& other) { - return operator=(other.Get()); + if constexpr (internal::IsDecayedSameV) { + return operator=(other.GetRawStorage()); + } else { + static_assert(internal::IsStrictlyBaseOfV); + return operator=(other.Get()); + } } + // Move assignment. - BasicMember& operator=(BasicMember&& other) noexcept { - operator=(other.Get()); + V8_INLINE BasicMember& operator=(BasicMember&& other) noexcept { + operator=(other.GetRawStorage()); other.Clear(); return *this; } - // Heterogeneous move assignment. + + // Heterogeneous move assignment. When the source pointer have a different + // type, perform a compress-decompress round, because the source pointer may + // need to be adjusted. template ::value>> - BasicMember& operator=(BasicMember&& other) noexcept { - operator=(other.Get()); + typename OtherCheckingPolicy> + V8_INLINE BasicMember& operator=( + BasicMember&& other) noexcept { + if constexpr (internal::IsDecayedSameV) { + operator=(other.GetRawStorage()); + } else { + static_assert(internal::IsStrictlyBaseOfV); + operator=(other.Get()); + } other.Clear(); return *this; } + // Assignment from Persistent. template ::value>> - BasicMember& operator=( + V8_INLINE BasicMember& operator=( const BasicPersistent& other) { return operator=(other.Get()); } - BasicMember& operator=(T* other) { + + V8_INLINE BasicMember& operator=(T* other) { SetRawAtomic(other); - AssigningWriteBarrier(); + AssigningWriteBarrier(other); this->CheckPointer(Get()); return *this; } - BasicMember& operator=(std::nullptr_t) { + + V8_INLINE BasicMember& operator=(std::nullptr_t) { Clear(); return *this; } - BasicMember& operator=(SentinelPointer s) { + V8_INLINE BasicMember& operator=(SentinelPointer s) { SetRawAtomic(s); return *this; } template - void Swap(BasicMember& other) { - T* tmp = Get(); + V8_INLINE void Swap(BasicMember& other) { + auto tmp = GetRawStorage(); *this = other; other = tmp; } - explicit operator bool() const { return Get(); } - operator T*() const { return Get(); } - T* operator->() const { return Get(); } - T& operator*() const { return *Get(); } + V8_INLINE explicit operator bool() const { return !IsCleared(); } + V8_INLINE operator T*() const { return Get(); } + V8_INLINE T* operator->() const { return Get(); } + V8_INLINE T& operator*() const { return *Get(); } // CFI cast exemption to allow passing SentinelPointer through T* and support // heterogeneous assignments between different Member and Persistent handles // based on their actual types. - V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") T* Get() const { + V8_INLINE V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") T* Get() const { // Executed by the mutator, hence non atomic load. // // The const_cast below removes the constness from MemberBase storage. The @@ -195,59 +264,262 @@ class BasicMember final : private MemberBase, private CheckingPolicy { return static_cast(const_cast(MemberBase::GetRaw())); } - void Clear() { SetRawAtomic(nullptr); } + V8_INLINE void Clear() { SetRawStorageAtomic(RawStorage{}); } - T* Release() { + V8_INLINE T* Release() { T* result = Get(); Clear(); return result; } - const T** GetSlotForTesting() const { + V8_INLINE const T** GetSlotForTesting() const { return reinterpret_cast(GetRawSlot()); } + V8_INLINE RawStorage GetRawStorage() const { + return MemberBase::GetRawStorage(); + } + private: - const T* GetRawAtomic() const { + V8_INLINE explicit BasicMember(RawStorage raw) : MemberBase(raw) { + InitializingWriteBarrier(Get()); + this->CheckPointer(Get()); + } + + V8_INLINE BasicMember& operator=(RawStorage other) { + SetRawStorageAtomic(other); + AssigningWriteBarrier(); + this->CheckPointer(Get()); + return *this; + } + + V8_INLINE const T* GetRawAtomic() const { return static_cast(MemberBase::GetRawAtomic()); } - void InitializingWriteBarrier() const { - WriteBarrierPolicy::InitializingBarrier(GetRawSlot(), GetRaw()); + V8_INLINE void InitializingWriteBarrier(T* value) const { + WriteBarrierPolicy::InitializingBarrier(GetRawSlot(), value); + } + V8_INLINE void AssigningWriteBarrier(T* value) const { + WriteBarrierPolicy::AssigningBarrier(GetRawSlot(), value); } - void AssigningWriteBarrier() const { - WriteBarrierPolicy::AssigningBarrier(GetRawSlot(), GetRaw()); + V8_INLINE void AssigningWriteBarrier() const { + WriteBarrierPolicy::AssigningBarrier(GetRawSlot(), GetRawStorage()); } - void ClearFromGC() const { MemberBase::ClearFromGC(); } + V8_INLINE void ClearFromGC() const { MemberBase::ClearFromGC(); } - T* GetFromGC() const { return Get(); } + V8_INLINE T* GetFromGC() const { return Get(); } + friend class cppgc::subtle::HeapConsistency; friend class cppgc::Visitor; template friend struct cppgc::TraceTrait; + template + friend class BasicMember; }; +// Member equality operators. template -bool operator==(const BasicMember& member1, - const BasicMember& member2) { - return member1.Get() == member2.Get(); +V8_INLINE bool operator==( + const BasicMember& + member1, + const BasicMember& + member2) { + if constexpr (internal::IsDecayedSameV) { + // Check compressed pointers if types are the same. + return member1.GetRawStorage() == member2.GetRawStorage(); + } else { + static_assert(internal::IsStrictlyBaseOfV || + internal::IsStrictlyBaseOfV); + // Otherwise, check decompressed pointers. + return member1.Get() == member2.Get(); + } } template -bool operator!=(const BasicMember& member1, - const BasicMember& member2) { +V8_INLINE bool operator!=( + const BasicMember& + member1, + const BasicMember& + member2) { return !(member1 == member2); } +// Equality with raw pointers. +template +V8_INLINE bool operator==(const BasicMember& member, + U* raw) { + // Never allow comparison with erased pointers. + static_assert(!internal::IsDecayedSameV); + + if constexpr (internal::IsDecayedSameV) { + // Check compressed pointers if types are the same. + return member.GetRawStorage() == MemberBase::RawStorage(raw); + } else if constexpr (internal::IsStrictlyBaseOfV) { + // Cast the raw pointer to T, which may adjust the pointer. + return member.GetRawStorage() == + MemberBase::RawStorage(static_cast(raw)); + } else { + // Otherwise, decompressed the member. + return member.Get() == raw; + } +} + +template +V8_INLINE bool operator!=(const BasicMember& member, + U* raw) { + return !(member == raw); +} + +template +V8_INLINE bool operator==(T* raw, + const BasicMember& member) { + return member == raw; +} + +template +V8_INLINE bool operator!=(T* raw, + const BasicMember& member) { + return !(raw == member); +} + +// Equality with sentinel. +template +V8_INLINE bool operator==(const BasicMember& member, + SentinelPointer) { + return member.GetRawStorage().IsSentinel(); +} + +template +V8_INLINE bool operator!=(const BasicMember& member, + SentinelPointer s) { + return !(member == s); +} + +template +V8_INLINE bool operator==(SentinelPointer s, + const BasicMember& member) { + return member == s; +} + +template +V8_INLINE bool operator!=(SentinelPointer s, + const BasicMember& member) { + return !(s == member); +} + +// Equality with nullptr. +template +V8_INLINE bool operator==(const BasicMember& member, + std::nullptr_t) { + return !static_cast(member); +} + +template +V8_INLINE bool operator!=(const BasicMember& member, + std::nullptr_t n) { + return !(member == n); +} + +template +V8_INLINE bool operator==(std::nullptr_t n, + const BasicMember& member) { + return member == n; +} + +template +V8_INLINE bool operator!=(std::nullptr_t n, + const BasicMember& member) { + return !(n == member); +} + +// Relational operators. +template +V8_INLINE bool operator<( + const BasicMember& + member1, + const BasicMember& + member2) { + static_assert( + internal::IsDecayedSameV, + "Comparison works only for same pointer type modulo cv-qualifiers"); + return member1.GetRawStorage() < member2.GetRawStorage(); +} + +template +V8_INLINE bool operator<=( + const BasicMember& + member1, + const BasicMember& + member2) { + static_assert( + internal::IsDecayedSameV, + "Comparison works only for same pointer type modulo cv-qualifiers"); + return member1.GetRawStorage() <= member2.GetRawStorage(); +} + +template +V8_INLINE bool operator>( + const BasicMember& + member1, + const BasicMember& + member2) { + static_assert( + internal::IsDecayedSameV, + "Comparison works only for same pointer type modulo cv-qualifiers"); + return member1.GetRawStorage() > member2.GetRawStorage(); +} + +template +V8_INLINE bool operator>=( + const BasicMember& + member1, + const BasicMember& + member2) { + static_assert( + internal::IsDecayedSameV, + "Comparison works only for same pointer type modulo cv-qualifiers"); + return member1.GetRawStorage() >= member2.GetRawStorage(); +} + template struct IsWeak< internal::BasicMember> diff --git a/deps/v8/include/cppgc/name-provider.h b/deps/v8/include/cppgc/name-provider.h index 224dd4b5d678ec..216f6098d99dd1 100644 --- a/deps/v8/include/cppgc/name-provider.h +++ b/deps/v8/include/cppgc/name-provider.h @@ -37,15 +37,15 @@ class V8_EXPORT NameProvider { static constexpr const char kNoNameDeducible[] = ""; /** - * Indicating whether internal names are hidden or not. + * Indicating whether the build supports extracting C++ names as object names. * * @returns true if C++ names should be hidden and represented by kHiddenName. */ - static constexpr bool HideInternalNames() { + static constexpr bool SupportsCppClassNamesAsObjectNames() { #if CPPGC_SUPPORTS_OBJECT_NAMES - return false; -#else // !CPPGC_SUPPORTS_OBJECT_NAMES return true; +#else // !CPPGC_SUPPORTS_OBJECT_NAMES + return false; #endif // !CPPGC_SUPPORTS_OBJECT_NAMES } diff --git a/deps/v8/include/cppgc/persistent.h b/deps/v8/include/cppgc/persistent.h index 244f94c81958b8..3a66ccc0864328 100644 --- a/deps/v8/include/cppgc/persistent.h +++ b/deps/v8/include/cppgc/persistent.h @@ -16,9 +16,6 @@ #include "v8config.h" // NOLINT(build/include_directory) namespace cppgc { - -class Visitor; - namespace internal { // PersistentBase always refers to the object as const object and defers to @@ -78,7 +75,7 @@ class BasicPersistent final : public PersistentBase, : PersistentBase(raw), LocationPolicy(loc) { if (!IsValid()) return; SetNode(WeaknessPolicy::GetPersistentRegion(GetValue()) - .AllocateNode(this, &BasicPersistent::Trace)); + .AllocateNode(this, &TraceAsRoot)); this->CheckPointer(Get()); } @@ -221,9 +218,8 @@ class BasicPersistent final : public PersistentBase, } private: - static void Trace(Visitor* v, const void* ptr) { - const auto* persistent = static_cast(ptr); - v->TraceRoot(*persistent, persistent->Location()); + static void TraceAsRoot(RootVisitor& root_visitor, const void* ptr) { + root_visitor.Trace(*static_cast(ptr)); } bool IsValid() const { @@ -247,7 +243,7 @@ class BasicPersistent final : public PersistentBase, SetValue(ptr); if (!IsValid()) return; SetNode(WeaknessPolicy::GetPersistentRegion(GetValue()) - .AllocateNode(this, &BasicPersistent::Trace)); + .AllocateNode(this, &TraceAsRoot)); this->CheckPointer(Get()); } @@ -264,7 +260,7 @@ class BasicPersistent final : public PersistentBase, return static_cast(const_cast(GetValue())); } - friend class cppgc::Visitor; + friend class internal::RootVisitor; }; template operator T*() const { - static constexpr intptr_t kSentinelValue = 1; return reinterpret_cast(kSentinelValue); } // Hidden friends. diff --git a/deps/v8/include/cppgc/trace-trait.h b/deps/v8/include/cppgc/trace-trait.h index 83619b1d51848b..694fbfdccf4dcb 100644 --- a/deps/v8/include/cppgc/trace-trait.h +++ b/deps/v8/include/cppgc/trace-trait.h @@ -16,6 +16,10 @@ class Visitor; namespace internal { +class RootVisitor; + +using TraceRootCallback = void (*)(RootVisitor&, const void* object); + // Implementation of the default TraceTrait handling GarbageCollected and // GarbageCollectedMixin. template ()))::value; }; +template +constexpr bool IsDecayedSameV = + std::is_same_v, std::decay_t>; + +template +constexpr bool IsStrictlyBaseOfV = + std::is_base_of_v, std::decay_t> && + !IsDecayedSameV; + } // namespace internal /** diff --git a/deps/v8/include/cppgc/visitor.h b/deps/v8/include/cppgc/visitor.h index 57e2ce3963af1e..f7ebc1d01f566e 100644 --- a/deps/v8/include/cppgc/visitor.h +++ b/deps/v8/include/cppgc/visitor.h @@ -62,22 +62,6 @@ class V8_EXPORT Visitor { virtual ~Visitor() = default; - /** - * Trace method for raw pointers. Prefer the versions for managed pointers. - * - * \param member Reference retaining an object. - */ - template - void Trace(const T* t) { - static_assert(sizeof(T), "Pointee type must be fully defined."); - static_assert(internal::IsGarbageCollectedOrMixinType::value, - "T must be GarbageCollected or GarbageCollectedMixin type"); - if (!t) { - return; - } - Visit(t, TraceTrait::GetTraceDescriptor(t)); - } - /** * Trace method for Member. * @@ -87,7 +71,7 @@ class V8_EXPORT Visitor { void Trace(const Member& member) { const T* value = member.GetRawAtomic(); CPPGC_DCHECK(value != kSentinelPointer); - Trace(value); + TraceImpl(value); } /** @@ -231,23 +215,33 @@ class V8_EXPORT Visitor { void TraceStrongly(const WeakMember& weak_member) { const T* value = weak_member.GetRawAtomic(); CPPGC_DCHECK(value != kSentinelPointer); - Trace(value); + TraceImpl(value); + } + + /** + * Trace method for retaining containers strongly. + * + * \param object reference to the container. + */ + template + void TraceStrongContainer(const T* object) { + TraceImpl(object); } /** - * Trace method for weak containers. + * Trace method for retaining containers weakly. * - * \param object reference of the weak container. + * \param object reference to the container. * \param callback to be invoked. - * \param data custom data that is passed to the callback. + * \param callback_data custom data that is passed to the callback. */ template void TraceWeakContainer(const T* object, WeakCallback callback, - const void* data) { + const void* callback_data) { if (!object) return; VisitWeakContainer(object, TraceTrait::GetTraceDescriptor(object), TraceTrait::GetWeakTraceDescriptor(object), callback, - data); + callback_data); } /** @@ -255,6 +249,7 @@ class V8_EXPORT Visitor { * compactable space. Such references maybe be arbitrarily moved by the GC. * * \param slot location of reference to object that might be moved by the GC. + * The slot must contain an uncompressed pointer. */ template void RegisterMovableReference(const T** slot) { @@ -297,9 +292,6 @@ class V8_EXPORT Visitor { virtual void Visit(const void* self, TraceDescriptor) {} virtual void VisitWeak(const void* self, TraceDescriptor, WeakCallback, const void* weak_member) {} - virtual void VisitRoot(const void*, TraceDescriptor, const SourceLocation&) {} - virtual void VisitWeakRoot(const void* self, TraceDescriptor, WeakCallback, - const void* weak_root, const SourceLocation&) {} virtual void VisitEphemeron(const void* key, const void* value, TraceDescriptor value_desc) {} virtual void VisitWeakContainer(const void* self, TraceDescriptor strong_desc, @@ -320,44 +312,20 @@ class V8_EXPORT Visitor { static void HandleWeak(const LivenessBroker& info, const void* object) { const PointerType* weak = static_cast(object); auto* raw_ptr = weak->GetFromGC(); - // Sentinel values are preserved for weak pointers. - if (raw_ptr == kSentinelPointer) return; if (!info.IsHeapObjectAlive(raw_ptr)) { weak->ClearFromGC(); } } - template * = nullptr> - void TraceRoot(const Persistent& p, const SourceLocation& loc) { - using PointeeType = typename Persistent::PointeeType; - static_assert(sizeof(PointeeType), - "Persistent's pointee type must be fully defined"); - static_assert(internal::IsGarbageCollectedOrMixinType::value, - "Persistent's pointee type must be GarbageCollected or " - "GarbageCollectedMixin"); - auto* ptr = p.GetFromGC(); - if (!ptr) { + template + void TraceImpl(const T* t) { + static_assert(sizeof(T), "Pointee type must be fully defined."); + static_assert(internal::IsGarbageCollectedOrMixinType::value, + "T must be GarbageCollected or GarbageCollectedMixin type"); + if (!t) { return; } - VisitRoot(ptr, TraceTrait::GetTraceDescriptor(ptr), loc); - } - - template < - typename WeakPersistent, - std::enable_if_t* = nullptr> - void TraceRoot(const WeakPersistent& p, const SourceLocation& loc) { - using PointeeType = typename WeakPersistent::PointeeType; - static_assert(sizeof(PointeeType), - "Persistent's pointee type must be fully defined"); - static_assert(internal::IsGarbageCollectedOrMixinType::value, - "Persistent's pointee type must be GarbageCollected or " - "GarbageCollectedMixin"); - static_assert(!internal::IsAllocatedOnCompactableSpace::value, - "Weak references to compactable objects are not allowed"); - auto* ptr = p.GetFromGC(); - VisitWeakRoot(ptr, TraceTrait::GetTraceDescriptor(ptr), - &HandleWeak, &p, loc); + Visit(t, TraceTrait::GetTraceDescriptor(t)); } #if V8_ENABLE_CHECKS @@ -374,6 +342,70 @@ class V8_EXPORT Visitor { friend class internal::VisitorBase; }; +namespace internal { + +class V8_EXPORT RootVisitor { + public: + explicit RootVisitor(Visitor::Key) {} + + virtual ~RootVisitor() = default; + + template * = nullptr> + void Trace(const AnyStrongPersistentType& p) { + using PointeeType = typename AnyStrongPersistentType::PointeeType; + const void* object = Extract(p); + if (!object) { + return; + } + VisitRoot(object, TraceTrait::GetTraceDescriptor(object), + p.Location()); + } + + template * = nullptr> + void Trace(const AnyWeakPersistentType& p) { + using PointeeType = typename AnyWeakPersistentType::PointeeType; + static_assert(!internal::IsAllocatedOnCompactableSpace::value, + "Weak references to compactable objects are not allowed"); + const void* object = Extract(p); + if (!object) { + return; + } + VisitWeakRoot(object, TraceTrait::GetTraceDescriptor(object), + &HandleWeak, &p, p.Location()); + } + + protected: + virtual void VisitRoot(const void*, TraceDescriptor, const SourceLocation&) {} + virtual void VisitWeakRoot(const void* self, TraceDescriptor, WeakCallback, + const void* weak_root, const SourceLocation&) {} + + private: + template + static const void* Extract(AnyPersistentType& p) { + using PointeeType = typename AnyPersistentType::PointeeType; + static_assert(sizeof(PointeeType), + "Persistent's pointee type must be fully defined"); + static_assert(internal::IsGarbageCollectedOrMixinType::value, + "Persistent's pointee type must be GarbageCollected or " + "GarbageCollectedMixin"); + return p.GetFromGC(); + } + + template + static void HandleWeak(const LivenessBroker& info, const void* object) { + const PointerType* weak = static_cast(object); + auto* raw_ptr = weak->GetFromGC(); + if (!info.IsHeapObjectAlive(raw_ptr)) { + weak->ClearFromGC(); + } + } +}; + +} // namespace internal } // namespace cppgc #endif // INCLUDE_CPPGC_VISITOR_H_ diff --git a/deps/v8/include/js_protocol.pdl b/deps/v8/include/js_protocol.pdl index 53a5f4c11dcc02..8d8211bf989f13 100644 --- a/deps/v8/include/js_protocol.pdl +++ b/deps/v8/include/js_protocol.pdl @@ -113,6 +113,11 @@ domain Debugger Runtime.RemoteObject this # The value being returned, if the function is at return point. optional Runtime.RemoteObject returnValue + # Valid only while the VM is paused and indicates whether this frame + # can be restarted or not. Note that a `true` value here does not + # guarantee that Debugger#restartFrame with this CallFrameId will be + # successful, but it is very likely. + experimental optional boolean canBeRestarted # Scope description. type Scope extends object @@ -239,6 +244,40 @@ domain Debugger # Wasm bytecode. optional binary bytecode + experimental type WasmDisassemblyChunk extends object + properties + # The next chunk of disassembled lines. + array of string lines + # The bytecode offsets describing the start of each line. + array of integer bytecodeOffsets + + experimental command disassembleWasmModule + parameters + # Id of the script to disassemble + Runtime.ScriptId scriptId + returns + # For large modules, return a stream from which additional chunks of + # disassembly can be read successively. + optional string streamId + # The total number of lines in the disassembly text. + integer totalNumberOfLines + # The offsets of all function bodies, in the format [start1, end1, + # start2, end2, ...] where all ends are exclusive. + array of integer functionBodyOffsets + # The first chunk of disassembly. + WasmDisassemblyChunk chunk + + # Disassemble the next chunk of lines for the module corresponding to the + # stream. If disassembly is complete, this API will invalidate the streamId + # and return an empty chunk. Any subsequent calls for the now invalid stream + # will return errors. + experimental command nextWasmDisassemblyChunk + parameters + string streamId + returns + # The next chunk of disassembly. + WasmDisassemblyChunk chunk + # This command is deprecated. Use getScriptSource instead. deprecated command getWasmBytecode parameters @@ -268,18 +307,35 @@ domain Debugger parameters BreakpointId breakpointId - # Restarts particular call frame from the beginning. - deprecated command restartFrame + # Restarts particular call frame from the beginning. The old, deprecated + # behavior of `restartFrame` is to stay paused and allow further CDP commands + # after a restart was scheduled. This can cause problems with restarting, so + # we now continue execution immediatly after it has been scheduled until we + # reach the beginning of the restarted frame. + # + # To stay back-wards compatible, `restartFrame` now expects a `mode` + # parameter to be present. If the `mode` parameter is missing, `restartFrame` + # errors out. + # + # The various return values are deprecated and `callFrames` is always empty. + # Use the call frames from the `Debugger#paused` events instead, that fires + # once V8 pauses at the beginning of the restarted function. + command restartFrame parameters # Call frame identifier to evaluate on. CallFrameId callFrameId + # The `mode` parameter must be present and set to 'StepInto', otherwise + # `restartFrame` will error out. + experimental optional enum mode + # Pause at the beginning of the restarted function + StepInto returns # New stack trace. - array of CallFrame callFrames + deprecated array of CallFrame callFrames # Async stack trace, if any. - optional Runtime.StackTrace asyncStackTrace + deprecated optional Runtime.StackTrace asyncStackTrace # Async stack trace, if any. - experimental optional Runtime.StackTraceId asyncStackTraceId + deprecated optional Runtime.StackTraceId asyncStackTraceId # Resumes JavaScript execution. command resume @@ -419,6 +475,12 @@ domain Debugger Runtime.CallArgument newValue # Edits JavaScript source live. + # + # In general, functions that are currently on the stack can not be edited with + # a single exception: If the edited function is the top-most stack frame and + # that is the only activation of that function on the stack. In this case + # the live edit will be successful and a `Debugger.restartFrame` for the + # top-most function is automatically triggered. command setScriptSource parameters # Id of the script to edit. @@ -428,16 +490,27 @@ domain Debugger # If true the change will not actually be applied. Dry run may be used to get result # description without actually modifying the code. optional boolean dryRun + # If true, then `scriptSource` is allowed to change the function on top of the stack + # as long as the top-most stack frame is the only activation of that function. + experimental optional boolean allowTopFrameEditing returns # New stack trace in case editing has happened while VM was stopped. - optional array of CallFrame callFrames + deprecated optional array of CallFrame callFrames # Whether current call stack was modified after applying the changes. - optional boolean stackChanged + deprecated optional boolean stackChanged # Async stack trace, if any. - optional Runtime.StackTrace asyncStackTrace + deprecated optional Runtime.StackTrace asyncStackTrace # Async stack trace, if any. - experimental optional Runtime.StackTraceId asyncStackTraceId - # Exception details if any. + deprecated optional Runtime.StackTraceId asyncStackTraceId + # Whether the operation was successful or not. Only `Ok` denotes a + # successful live edit while the other enum variants denote why + # the live edit failed. + experimental enum status + Ok + CompileError + BlockedByActiveGenerator + BlockedByActiveFunction + # Exception details if any. Only present when `status` is `CompileError`. optional Runtime.ExceptionDetails exceptionDetails # Makes page not interrupt on any pauses (breakpoint, exception, dom exception etc). @@ -554,7 +627,7 @@ domain Debugger integer endColumn # Specifies script creation context. Runtime.ExecutionContextId executionContextId - # Content hash of the script. + # Content hash of the script, SHA-256. string hash # Embedder-specific auxiliary data. optional object executionContextAuxData @@ -593,7 +666,7 @@ domain Debugger integer endColumn # Specifies script creation context. Runtime.ExecutionContextId executionContextId - # Content hash of the script. + # Content hash of the script, SHA-256. string hash # Embedder-specific auxiliary data. optional object executionContextAuxData @@ -708,18 +781,24 @@ experimental domain HeapProfiler # If true 'reportHeapSnapshotProgress' events will be generated while snapshot is being taken # when the tracking is stopped. optional boolean reportProgress - optional boolean treatGlobalObjectsAsRoots + # Deprecated in favor of `exposeInternals`. + deprecated optional boolean treatGlobalObjectsAsRoots # If true, numerical values are included in the snapshot optional boolean captureNumericValue + # If true, exposes internals of the snapshot. + experimental optional boolean exposeInternals command takeHeapSnapshot parameters # If true 'reportHeapSnapshotProgress' events will be generated while snapshot is being taken. optional boolean reportProgress - # If true, a raw snapshot without artificial roots will be generated - optional boolean treatGlobalObjectsAsRoots + # If true, a raw snapshot without artificial roots will be generated. + # Deprecated in favor of `exposeInternals`. + deprecated optional boolean treatGlobalObjectsAsRoots # If true, numerical values are included in the snapshot optional boolean captureNumericValue + # If true, exposes internals of the snapshot. + experimental optional boolean exposeInternals event addHeapSnapshotChunk parameters @@ -1342,7 +1421,9 @@ domain Runtime optional string objectGroup # Whether to throw an exception if side effect cannot be ruled out during evaluation. experimental optional boolean throwOnSideEffect - # Whether the result should be serialized according to https://w3c.github.io/webdriver-bidi. + # Whether the result should contain `webDriverValue`, serialized according to + # https://w3c.github.io/webdriver-bidi. This is mutually exclusive with `returnByValue`, but + # resulting `objectId` is still provided. experimental optional boolean generateWebDriverValue returns # Call result. diff --git a/deps/v8/include/v8-callbacks.h b/deps/v8/include/v8-callbacks.h index 70b9c2ae9308a5..c02059a5891a74 100644 --- a/deps/v8/include/v8-callbacks.h +++ b/deps/v8/include/v8-callbacks.h @@ -12,6 +12,7 @@ #include "cppgc/common.h" #include "v8-data.h" // NOLINT(build/include_directory) #include "v8-local-handle.h" // NOLINT(build/include_directory) +#include "v8-promise.h" // NOLINT(build/include_directory) #include "v8config.h" // NOLINT(build/include_directory) #if defined(V8_OS_WIN) @@ -105,7 +106,7 @@ struct JitCodeEvent { size_t line_number_table_size; }; - wasm_source_info_t* wasm_source_info; + wasm_source_info_t* wasm_source_info = nullptr; union { // Only valid for CODE_ADDED. @@ -216,7 +217,13 @@ using AddHistogramSampleCallback = void (*)(void* histogram, int sample); using FatalErrorCallback = void (*)(const char* location, const char* message); -using OOMErrorCallback = void (*)(const char* location, bool is_heap_oom); +struct OOMDetails { + bool is_heap_oom = false; + const char* detail = nullptr; +}; + +using OOMErrorCallback = void (*)(const char* location, + const OOMDetails& details); using MessageCallback = void (*)(Local message, Local data); @@ -231,8 +238,11 @@ enum class CrashKeyId { kIsolateAddress, kReadonlySpaceFirstPageAddress, kMapSpaceFirstPageAddress, + kCodeRangeBaseAddress, kCodeSpaceFirstPageAddress, kDumpType, + kSnapshotChecksumCalculated, + kSnapshotChecksumExpected, }; using AddCrashKeyCallback = void (*)(CrashKeyId id, const std::string& value); @@ -300,6 +310,13 @@ using ApiImplementationCallback = void (*)(const FunctionCallbackInfo&); // --- Callback for WebAssembly.compileStreaming --- using WasmStreamingCallback = void (*)(const FunctionCallbackInfo&); +enum class WasmAsyncSuccess { kSuccess, kFail }; + +// --- Callback called when async WebAssembly operations finish --- +using WasmAsyncResolvePromiseCallback = void (*)( + Isolate* isolate, Local context, Local resolver, + Local result, WasmAsyncSuccess success); + // --- Callback for loading source map file for Wasm profiling support using WasmLoadSourceMapCallback = Local (*)(Isolate* isolate, const char* name); @@ -310,9 +327,6 @@ using WasmSimdEnabledCallback = bool (*)(Local context); // --- Callback for checking if WebAssembly exceptions are enabled --- using WasmExceptionsEnabledCallback = bool (*)(Local context); -// --- Callback for checking if WebAssembly dynamic tiering is enabled --- -using WasmDynamicTieringEnabledCallback = bool (*)(Local context); - // --- Callback for checking if the SharedArrayBuffer constructor is enabled --- using SharedArrayBufferConstructorEnabledCallback = bool (*)(Local context); diff --git a/deps/v8/include/v8-context.h b/deps/v8/include/v8-context.h index 72dfbaad74d1f9..be52c414b4e028 100644 --- a/deps/v8/include/v8-context.h +++ b/deps/v8/include/v8-context.h @@ -244,6 +244,12 @@ class V8_EXPORT Context : public Data { */ void SetErrorMessageForCodeGenerationFromStrings(Local message); + /** + * Sets the error description for the exception that is thrown when + * wasm code generation is not allowed. + */ + void SetErrorMessageForWasmCodeGeneration(Local message); + /** * Return data that was previously attached to the context snapshot via * SnapshotCreator, and removes the reference to it. @@ -374,15 +380,13 @@ void* Context::GetAlignedPointerFromEmbedderData(int index) { A ctx = *reinterpret_cast(this); A embedder_data = I::ReadTaggedPointerField(ctx, I::kNativeContextEmbedderDataOffset); - int value_offset = - I::kEmbedderDataArrayHeaderSize + (I::kEmbedderDataSlotSize * index); -#ifdef V8_SANDBOXED_EXTERNAL_POINTERS - value_offset += I::kEmbedderDataSlotRawPayloadOffset; -#endif - internal::Isolate* isolate = I::GetIsolateForSandbox(ctx); + int value_offset = I::kEmbedderDataArrayHeaderSize + + (I::kEmbedderDataSlotSize * index) + + I::kEmbedderDataSlotExternalPointerOffset; + Isolate* isolate = I::GetIsolateForSandbox(ctx); return reinterpret_cast( - I::ReadExternalPointerField(isolate, embedder_data, value_offset, - internal::kEmbedderDataSlotPayloadTag)); + I::ReadExternalPointerField( + isolate, embedder_data, value_offset)); #else return SlowGetAlignedPointerFromEmbedderData(index); #endif diff --git a/deps/v8/include/v8-cppgc.h b/deps/v8/include/v8-cppgc.h index 401e492210609f..00ea5c5ae502ef 100644 --- a/deps/v8/include/v8-cppgc.h +++ b/deps/v8/include/v8-cppgc.h @@ -82,6 +82,18 @@ struct V8_EXPORT CppHeapCreateParams { std::vector> custom_spaces; WrapperDescriptor wrapper_descriptor; + /** + * Specifies which kind of marking are supported by the heap. The type may be + * further reduced via runtime flags when attaching the heap to an Isolate. + */ + cppgc::Heap::MarkingType marking_support = + cppgc::Heap::MarkingType::kIncrementalAndConcurrent; + /** + * Specifies which kind of sweeping is supported by the heap. The type may be + * further reduced via runtime flags when attaching the heap to an Isolate. + */ + cppgc::Heap::SweepingType sweeping_support = + cppgc::Heap::SweepingType::kIncrementalAndConcurrent; }; /** diff --git a/deps/v8/include/v8-date.h b/deps/v8/include/v8-date.h index e7a01f29b2d3b7..8d82ccc9ea60bb 100644 --- a/deps/v8/include/v8-date.h +++ b/deps/v8/include/v8-date.h @@ -27,6 +27,11 @@ class V8_EXPORT Date : public Object { */ double ValueOf() const; + /** + * Generates ISO string representation. + */ + v8::Local ToISOString() const; + V8_INLINE static Date* Cast(Value* value) { #ifdef V8_ENABLE_CHECKS CheckCast(value); diff --git a/deps/v8/include/v8-embedder-heap.h b/deps/v8/include/v8-embedder-heap.h index 09dbae1fd8778b..d3920c5f3b5580 100644 --- a/deps/v8/include/v8-embedder-heap.h +++ b/deps/v8/include/v8-embedder-heap.h @@ -69,7 +69,12 @@ class V8_EXPORT EmbedderRootsHandler { * trace through its heap and use reporter to report each JavaScript object * reachable from any of the given wrappers. */ -class V8_EXPORT EmbedderHeapTracer { +class V8_EXPORT +// GCC doesn't like combining __attribute__(()) with [[deprecated]]. +#ifdef __clang__ +V8_DEPRECATE_SOON("Use CppHeap when working with v8::TracedReference.") +#endif // __clang__ + EmbedderHeapTracer { public: using EmbedderStackState = cppgc::EmbedderStackState; @@ -205,10 +210,10 @@ class V8_EXPORT EmbedderHeapTracer { * Returns the v8::Isolate this tracer is attached too and |nullptr| if it * is not attached to any v8::Isolate. */ - v8::Isolate* isolate() const { return isolate_; } + v8::Isolate* isolate() const { return v8_isolate_; } protected: - v8::Isolate* isolate_ = nullptr; + v8::Isolate* v8_isolate_ = nullptr; friend class internal::LocalEmbedderHeapTracer; }; diff --git a/deps/v8/include/v8-exception.h b/deps/v8/include/v8-exception.h index 64126c420a6928..bc058e3fc7b874 100644 --- a/deps/v8/include/v8-exception.h +++ b/deps/v8/include/v8-exception.h @@ -197,7 +197,7 @@ class V8_EXPORT TryCatch { void ResetInternal(); - internal::Isolate* isolate_; + internal::Isolate* i_isolate_; TryCatch* next_; void* exception_; void* message_obj_; diff --git a/deps/v8/include/v8-fast-api-calls.h b/deps/v8/include/v8-fast-api-calls.h index 3403de93eca852..1826f133210477 100644 --- a/deps/v8/include/v8-fast-api-calls.h +++ b/deps/v8/include/v8-fast-api-calls.h @@ -240,6 +240,7 @@ class CTypeInfo { enum class Type : uint8_t { kVoid, kBool, + kUint8, kInt32, kUint32, kInt64, @@ -302,8 +303,9 @@ class CTypeInfo { constexpr Flags GetFlags() const { return flags_; } static constexpr bool IsIntegralType(Type type) { - return type == Type::kInt32 || type == Type::kUint32 || - type == Type::kInt64 || type == Type::kUint64; + return type == Type::kUint8 || type == Type::kInt32 || + type == Type::kUint32 || type == Type::kInt64 || + type == Type::kUint64; } static constexpr bool IsFloatingPointType(Type type) { @@ -429,6 +431,7 @@ struct AnyCType { double double_value; Local object_value; Local sequence_value; + const FastApiTypedArray* uint8_ta_value; const FastApiTypedArray* int32_ta_value; const FastApiTypedArray* uint32_ta_value; const FastApiTypedArray* int64_ta_value; @@ -544,7 +547,7 @@ struct FastApiCallbackOptions { * returned instance may be filled with mock data. */ static FastApiCallbackOptions CreateForTesting(Isolate* isolate) { - return {false, {0}}; + return {false, {0}, nullptr}; } /** @@ -566,8 +569,13 @@ struct FastApiCallbackOptions { */ union { uintptr_t data_ptr; - v8::Value data; + v8::Local data; }; + + /** + * When called from WebAssembly, a view of the calling module's memory. + */ + FastApiTypedArray* const wasm_memory; }; namespace internal { @@ -648,7 +656,8 @@ struct CTypeInfoTraits {}; V(int64_t, kInt64) \ V(uint64_t, kUint64) \ V(float, kFloat32) \ - V(double, kFloat64) + V(double, kFloat64) \ + V(uint8_t, kUint8) // Same as above, but includes deprecated types for compatibility. #define ALL_C_TYPES(V) \ @@ -687,7 +696,8 @@ PRIMITIVE_C_TYPES(DEFINE_TYPE_INFO_TRAITS) V(int64_t, kInt64) \ V(uint64_t, kUint64) \ V(float, kFloat32) \ - V(double, kFloat64) + V(double, kFloat64) \ + V(uint8_t, kUint8) TYPED_ARRAY_C_TYPES(SPECIALIZE_GET_TYPE_INFO_HELPER_FOR_TA) @@ -802,6 +812,16 @@ class CFunctionBuilderWithFunction { std::make_index_sequence()); } + // Provided for testing purposes. + template + auto Patch(Ret (*patching_func)(Args...)) { + static_assert( + sizeof...(Args) == sizeof...(ArgBuilders), + "The patching function must have the same number of arguments."); + fn_ = reinterpret_cast(patching_func); + return *this; + } + auto Build() { static CFunctionInfoImpl instance; return CFunction(fn_, &instance); @@ -881,31 +901,6 @@ static constexpr CTypeInfo kTypeInfoFloat64 = * to the requested destination type, is considered unsupported. The operation * returns true on success. `type_info` will be used for conversions. */ -template -V8_DEPRECATED( - "Use TryToCopyAndConvertArrayToCppBuffer()") -bool V8_EXPORT V8_WARN_UNUSED_RESULT - TryCopyAndConvertArrayToCppBuffer(Local src, T* dst, - uint32_t max_length); - -template <> -V8_DEPRECATED( - "Use TryToCopyAndConvertArrayToCppBuffer()") -inline bool V8_WARN_UNUSED_RESULT - TryCopyAndConvertArrayToCppBuffer<&kTypeInfoInt32, int32_t>( - Local src, int32_t* dst, uint32_t max_length) { - return false; -} - -template <> -V8_DEPRECATED( - "Use TryToCopyAndConvertArrayToCppBuffer()") -inline bool V8_WARN_UNUSED_RESULT - TryCopyAndConvertArrayToCppBuffer<&kTypeInfoFloat64, double>( - Local src, double* dst, uint32_t max_length) { - return false; -} - template bool V8_EXPORT V8_WARN_UNUSED_RESULT TryToCopyAndConvertArrayToCppBuffer( Local src, T* dst, uint32_t max_length); diff --git a/deps/v8/include/v8-function.h b/deps/v8/include/v8-function.h index 897e6ed6175931..2dc7e722bb9e8c 100644 --- a/deps/v8/include/v8-function.h +++ b/deps/v8/include/v8-function.h @@ -106,6 +106,14 @@ class V8_EXPORT Function : public Object { V8_WARN_UNUSED_RESULT MaybeLocal FunctionProtoToString( Local context); + /** + * Returns true if the function does nothing. + * The function returns false on error. + * Note that this function is experimental. Embedders should not rely on + * this existing. We may remove this function in the future. + */ + V8_WARN_UNUSED_RESULT bool Experimental_IsNopFunction() const; + ScriptOrigin GetScriptOrigin() const; V8_INLINE static Function* Cast(Value* value) { #ifdef V8_ENABLE_CHECKS diff --git a/deps/v8/include/v8-initialization.h b/deps/v8/include/v8-initialization.h index 3d59c73f7c9caf..d3e35d6ec5f860 100644 --- a/deps/v8/include/v8-initialization.h +++ b/deps/v8/include/v8-initialization.h @@ -100,9 +100,6 @@ class V8_EXPORT V8 { const int kBuildConfiguration = (internal::PointerCompressionIsEnabled() ? kPointerCompression : 0) | (internal::SmiValuesAre31Bits() ? k31BitSmis : 0) | - (internal::SandboxedExternalPointersAreEnabled() - ? kSandboxedExternalPointers - : 0) | (internal::SandboxIsEnabled() ? kSandbox : 0); return Initialize(kBuildConfiguration); } @@ -184,30 +181,19 @@ class V8_EXPORT V8 { * V8 was disposed. */ static void DisposePlatform(); - V8_DEPRECATED("Use DisposePlatform()") - static void ShutdownPlatform() { DisposePlatform(); } - -#ifdef V8_SANDBOX - // - // Sandbox related API. - // - // This API is not yet stable and subject to changes in the future. - // +#if defined(V8_ENABLE_SANDBOX) /** - * Initializes the V8 sandbox. - * - * This must be invoked after the platform was initialized but before V8 is - * initialized. The sandbox is torn down during platform shutdown. - * Returns true on success, false otherwise. + * Returns true if the sandbox is configured securely. * - * TODO(saelo) Once it is no longer optional to initialize the sandbox when - * compiling with V8_SANDBOX, the sandbox initialization will likely happen - * as part of V8::Initialize, at which point this function should be removed. + * If V8 cannot create a regular sandbox during initialization, for example + * because not enough virtual address space can be reserved, it will instead + * create a fallback sandbox that still allows it to function normally but + * does not have the same security properties as a regular sandbox. This API + * can be used to determine if such a fallback sandbox is being used, in + * which case it will return false. */ - static bool InitializeSandbox(); - V8_DEPRECATE_SOON("Use InitializeSandbox()") - static bool InitializeVirtualMemoryCage() { return InitializeSandbox(); } + static bool IsSandboxConfiguredSecurely(); /** * Provides access to the virtual address subspace backing the sandbox. @@ -220,39 +206,29 @@ class V8_EXPORT V8 { * and so in particular the contents of pages allocagted in this virtual * address space, arbitrarily and concurrently. Due to this, it is * recommended to to only place pure data buffers in them. - * - * This function must only be called after initializing the sandbox. */ static VirtualAddressSpace* GetSandboxAddressSpace(); - V8_DEPRECATE_SOON("Use GetSandboxAddressSpace()") - static PageAllocator* GetVirtualMemoryCagePageAllocator(); /** * Returns the size of the sandbox in bytes. * - * If the sandbox has not been initialized, or if the initialization failed, - * this returns zero. + * This represents the size of the address space that V8 can directly address + * and in which it allocates its objects. */ static size_t GetSandboxSizeInBytes(); - V8_DEPRECATE_SOON("Use GetSandboxSizeInBytes()") - static size_t GetVirtualMemoryCageSizeInBytes() { - return GetSandboxSizeInBytes(); - } /** - * Returns whether the sandbox is configured securely. + * Returns the size of the address space reservation backing the sandbox. * - * If V8 cannot create a proper sandbox, it will fall back to creating a - * sandbox that doesn't have the desired security properties but at least - * still allows V8 to function. This API can be used to determine if such an - * insecure sandbox is being used, in which case it will return false. + * This may be larger than the sandbox (i.e. |GetSandboxSizeInBytes()|) due + * to surrounding guard regions, or may be smaller than the sandbox in case a + * fallback sandbox is being used, which will use a smaller virtual address + * space reservation. In the latter case this will also be different from + * |GetSandboxAddressSpace()->size()| as that will cover a larger part of the + * address space than what has actually been reserved. */ - static bool IsSandboxConfiguredSecurely(); - V8_DEPRECATE_SOON("Use IsSandboxConfiguredSecurely()") - static bool IsUsingSecureVirtualMemoryCage() { - return IsSandboxConfiguredSecurely(); - } -#endif + static size_t GetSandboxReservationSizeInBytes(); +#endif // V8_ENABLE_SANDBOX /** * Activate trap-based bounds checking for WebAssembly. @@ -273,7 +249,7 @@ class V8_EXPORT V8 { * exceptions in V8-generated code. */ static void SetUnhandledExceptionCallback( - UnhandledExceptionCallback unhandled_exception_callback); + UnhandledExceptionCallback callback); #endif /** @@ -281,8 +257,7 @@ class V8_EXPORT V8 { * v8 has encountered a fatal failure to allocate memory and is about to * terminate. */ - - static void SetFatalMemoryErrorCallback(OOMErrorCallback oom_error_callback); + static void SetFatalMemoryErrorCallback(OOMErrorCallback callback); /** * Get statistics about the shared memory usage. @@ -295,8 +270,7 @@ class V8_EXPORT V8 { enum BuildConfigurationFeatures { kPointerCompression = 1 << 0, k31BitSmis = 1 << 1, - kSandboxedExternalPointers = 1 << 2, - kSandbox = 1 << 3, + kSandbox = 1 << 2, }; /** diff --git a/deps/v8/include/v8-inspector.h b/deps/v8/include/v8-inspector.h index ce5430bd039870..aa5a044afb61c4 100644 --- a/deps/v8/include/v8-inspector.h +++ b/deps/v8/include/v8-inspector.h @@ -207,10 +207,10 @@ class V8_EXPORT V8InspectorSession { class V8_EXPORT WebDriverValue { public: - explicit WebDriverValue(StringView type, v8::MaybeLocal value = {}) - : type(type), value(value) {} - - StringView type; + explicit WebDriverValue(std::unique_ptr type, + v8::MaybeLocal value = {}) + : type(std::move(type)), value(value) {} + std::unique_ptr type; v8::MaybeLocal value; }; @@ -219,6 +219,9 @@ class V8_EXPORT V8InspectorClient { virtual ~V8InspectorClient() = default; virtual void runMessageLoopOnPause(int contextGroupId) {} + virtual void runMessageLoopOnInstrumentationPause(int contextGroupId) { + runMessageLoopOnPause(contextGroupId); + } virtual void quitMessageLoopOnPause() {} virtual void runIfWaitingForDebugger(int contextGroupId) {} @@ -361,9 +364,12 @@ class V8_EXPORT V8Inspector { virtual void sendNotification(std::unique_ptr message) = 0; virtual void flushProtocolNotifications() = 0; }; - virtual std::unique_ptr connect(int contextGroupId, - Channel*, - StringView state) = 0; + enum ClientTrustLevel { kUntrusted, kFullyTrusted }; + virtual std::unique_ptr connect( + int contextGroupId, Channel*, StringView state, + ClientTrustLevel client_trust_level) { + return nullptr; + } // API methods. virtual std::unique_ptr createStackTrace( diff --git a/deps/v8/include/v8-internal.h b/deps/v8/include/v8-internal.h index e6e9cc5f9f5bbc..c97942ed1b476a 100644 --- a/deps/v8/include/v8-internal.h +++ b/deps/v8/include/v8-internal.h @@ -8,6 +8,8 @@ #include #include #include + +#include #include #include "v8-version.h" // NOLINT(build/include_directory) @@ -50,6 +52,7 @@ const int kHeapObjectTag = 1; const int kWeakHeapObjectTag = 3; const int kHeapObjectTagSize = 2; const intptr_t kHeapObjectTagMask = (1 << kHeapObjectTagSize) - 1; +const intptr_t kHeapObjectReferenceTagMask = 1 << (kHeapObjectTagSize - 1); // Tag information for fowarding pointers stored in object headers. // 0b00 at the lowest 2 bits in the header indicates that the map word is a @@ -157,15 +160,7 @@ V8_INLINE static constexpr internal::Address IntToSmi(int value) { * Sandbox related types, constants, and functions. */ constexpr bool SandboxIsEnabled() { -#ifdef V8_SANDBOX - return true; -#else - return false; -#endif -} - -constexpr bool SandboxedExternalPointersAreEnabled() { -#ifdef V8_SANDBOXED_EXTERNAL_POINTERS +#ifdef V8_ENABLE_SANDBOX return true; #else return false; @@ -176,19 +171,18 @@ constexpr bool SandboxedExternalPointersAreEnabled() { // for example by storing them as offset rather than as raw pointers. using SandboxedPointer_t = Address; -// ExternalPointers point to objects located outside the sandbox. When sandboxed -// external pointers are enabled, these are stored in an external pointer table -// and referenced from HeapObjects through indices. -#ifdef V8_SANDBOXED_EXTERNAL_POINTERS -using ExternalPointer_t = uint32_t; -#else -using ExternalPointer_t = Address; -#endif - -#ifdef V8_SANDBOX_IS_AVAILABLE +#ifdef V8_ENABLE_SANDBOX // Size of the sandbox, excluding the guard regions surrounding it. +#ifdef V8_TARGET_OS_ANDROID +// On Android, most 64-bit devices seem to be configured with only 39 bits of +// virtual address space for userspace. As such, limit the sandbox to 128GB (a +// quarter of the total available address space). +constexpr size_t kSandboxSizeLog2 = 37; // 128 GB +#else +// Everywhere else use a 1TB sandbox. constexpr size_t kSandboxSizeLog2 = 40; // 1 TB +#endif // V8_OS_ANDROID constexpr size_t kSandboxSize = 1ULL << kSandboxSizeLog2; // Required alignment of the sandbox. For simplicity, we require the @@ -213,20 +207,6 @@ static_assert((kSandboxGuardRegionSize % kSandboxAlignment) == 0, "The size of the guard regions around the sandbox must be a " "multiple of its required alignment."); -// Minimum size of the sandbox, excluding the guard regions surrounding it. If -// the virtual memory reservation for the sandbox fails, its size is currently -// halved until either the reservation succeeds or the minimum size is reached. -// A minimum of 32GB allows the 4GB pointer compression region as well as the -// ArrayBuffer partition and two 10GB Wasm memory cages to fit into the -// sandbox. 32GB should also be the minimum possible size of the userspace -// address space as there are some machine configurations with only 36 virtual -// address bits. -constexpr size_t kSandboxMinimumSize = 32ULL * GB; - -static_assert(kSandboxMinimumSize <= kSandboxSize, - "The minimal size of the sandbox must be smaller or equal to the " - "regular size."); - // On OSes where reserving virtual memory is too expensive to reserve the // entire address space backing the sandbox, notably Windows pre 8.1, we create // a partially reserved sandbox that doesn't actually reserve most of the @@ -239,82 +219,253 @@ static_assert(kSandboxMinimumSize <= kSandboxSize, // well as the ArrayBuffer partition. constexpr size_t kSandboxMinimumReservationSize = 8ULL * GB; -static_assert(kSandboxMinimumSize > kPtrComprCageReservationSize, - "The sandbox must be larger than the pointer compression cage " - "contained within it."); static_assert(kSandboxMinimumReservationSize > kPtrComprCageReservationSize, "The minimum reservation size for a sandbox must be larger than " "the pointer compression cage contained within it."); -// For now, even if the sandbox is enabled, we still allow backing stores to be -// allocated outside of it as fallback. This will simplify the initial rollout. -// However, if sandboxed pointers are also enabled, we must always place -// backing stores inside the sandbox as they will be referenced though them. -#ifdef V8_SANDBOXED_POINTERS -constexpr bool kAllowBackingStoresOutsideSandbox = false; -#else -constexpr bool kAllowBackingStoresOutsideSandbox = true; -#endif // V8_SANDBOXED_POINTERS +#endif // V8_ENABLE_SANDBOX + +#ifdef V8_COMPRESS_POINTERS // The size of the virtual memory reservation for an external pointer table. // This determines the maximum number of entries in a table. Using a maximum // size allows omitting bounds checks on table accesses if the indices are // guaranteed (e.g. through shifting) to be below the maximum index. This // value must be a power of two. -static const size_t kExternalPointerTableReservationSize = 128 * MB; +static const size_t kExternalPointerTableReservationSize = 512 * MB; // The maximum number of entries in an external pointer table. -static const size_t kMaxSandboxedExternalPointers = +static const size_t kMaxExternalPointers = kExternalPointerTableReservationSize / kApiSystemPointerSize; // The external pointer table indices stored in HeapObjects as external // pointers are shifted to the left by this amount to guarantee that they are // smaller than the maximum table size. -static const uint32_t kExternalPointerIndexShift = 8; -static_assert((1 << (32 - kExternalPointerIndexShift)) == - kMaxSandboxedExternalPointers, +static const uint32_t kExternalPointerIndexShift = 6; +static_assert((1 << (32 - kExternalPointerIndexShift)) == kMaxExternalPointers, "kExternalPointerTableReservationSize and " "kExternalPointerIndexShift don't match"); -#endif // V8_SANDBOX_IS_AVAILABLE - -// If sandboxed external pointers are enabled, these tag values will be ORed -// with the external pointers in the external pointer table to prevent use of -// pointers of the wrong type. When a pointer is loaded, it is ANDed with the -// inverse of the expected type's tag. The tags are constructed in a way that -// guarantees that a failed type check will result in one or more of the top -// bits of the pointer to be set, rendering the pointer inacessible. Besides -// the type tag bits (48 through 62), the tags also have the GC mark bit (63) -// set, so that the mark bit is automatically set when a pointer is written -// into the external pointer table (in which case it is clearly alive) and is -// cleared when the pointer is loaded. The exception to this is the free entry -// tag, which doesn't have the mark bit set, as the entry is not alive. This +#else // !V8_COMPRESS_POINTERS + +// Needed for the V8.SandboxedExternalPointersCount histogram. +static const size_t kMaxExternalPointers = 0; + +#endif // V8_COMPRESS_POINTERS + +// A ExternalPointerHandle represents a (opaque) reference to an external +// pointer that can be stored inside the sandbox. A ExternalPointerHandle has +// meaning only in combination with an (active) Isolate as it references an +// external pointer stored in the currently active Isolate's +// ExternalPointerTable. Internally, an ExternalPointerHandles is simply an +// index into an ExternalPointerTable that is shifted to the left to guarantee +// that it is smaller than the size of the table. +using ExternalPointerHandle = uint32_t; + +// ExternalPointers point to objects located outside the sandbox. When +// sandboxed external pointers are enabled, these are stored on heap as +// ExternalPointerHandles, otherwise they are simply raw pointers. +#ifdef V8_ENABLE_SANDBOX +using ExternalPointer_t = ExternalPointerHandle; +#else +using ExternalPointer_t = Address; +#endif + +// When the sandbox is enabled, external pointers are stored in an external +// pointer table and are referenced from HeapObjects through an index (a +// "handle"). When stored in the table, the pointers are tagged with per-type +// tags to prevent type confusion attacks between different external objects. +// Besides type information bits, these tags also contain the GC marking bit +// which indicates whether the pointer table entry is currently alive. When a +// pointer is written into the table, the tag is ORed into the top bits. When +// that pointer is later loaded from the table, it is ANDed with the inverse of +// the expected tag. If the expected and actual type differ, this will leave +// some of the top bits of the pointer set, rendering the pointer inaccessible. +// The AND operation also removes the GC marking bit from the pointer. +// +// The tags are constructed such that UNTAG(TAG(0, T1), T2) != 0 for any two +// (distinct) tags T1 and T2. In practice, this is achieved by generating tags +// that all have the same number of zeroes and ones but different bit patterns. +// With N type tag bits, this allows for (N choose N/2) possible type tags. +// Besides the type tag bits, the tags also have the GC marking bit set so that +// the marking bit is automatically set when a pointer is written into the +// external pointer table (in which case it is clearly alive) and is cleared +// when the pointer is loaded. The exception to this is the free entry tag, +// which doesn't have the mark bit set, as the entry is not alive. This // construction allows performing the type check and removing GC marking bits -// (the MSB) from the pointer at the same time. -// Note: this scheme assumes a 48-bit address space and will likely break if -// more virtual address bits are used. -constexpr uint64_t kExternalPointerTagMask = 0xffff000000000000; +// from the pointer in one efficient operation (bitwise AND). The number of +// available bits is limited in the following way: on x64, bits [47, 64) are +// generally available for tagging (userspace has 47 address bits available). +// On Arm64, userspace typically has a 40 or 48 bit address space. However, due +// to top-byte ignore (TBI) and memory tagging (MTE), the top byte is unusable +// for type checks as type-check failures would go unnoticed or collide with +// MTE bits. Some bits of the top byte can, however, still be used for the GC +// marking bit. The bits available for the type tags are therefore limited to +// [48, 56), i.e. (8 choose 4) = 70 different types. +// The following options exist to increase the number of possible types: +// - Using multiple ExternalPointerTables since tags can safely be reused +// across different tables +// - Using "extended" type checks, where additional type information is stored +// either in an adjacent pointer table entry or at the pointed-to location +// - Using a different tagging scheme, for example based on XOR which would +// allow for 2**8 different tags but require a separate operation to remove +// the marking bit +// +// The external pointer sandboxing mechanism ensures that every access to an +// external pointer field will result in a valid pointer of the expected type +// even in the presence of an attacker able to corrupt memory inside the +// sandbox. However, if any data related to the external object is stored +// inside the sandbox it may still be corrupted and so must be validated before +// use or moved into the external object. Further, an attacker will always be +// able to substitute different external pointers of the same type for each +// other. Therefore, code using external pointers must be written in a +// "substitution-safe" way, i.e. it must always be possible to substitute +// external pointers of the same type without causing memory corruption outside +// of the sandbox. Generally this is achieved by referencing any group of +// related external objects through a single external pointer. +// +// Currently we use bit 62 for the marking bit which should always be unused as +// it's part of the non-canonical address range. When Arm's top-byte ignore +// (TBI) is enabled, this bit will be part of the ignored byte, and we assume +// that the Embedder is not using this byte (really only this one bit) for any +// other purpose. This bit also does not collide with the memory tagging +// extension (MTE) which would use bits [56, 60). +constexpr uint64_t kExternalPointerMarkBit = 1ULL << 62; +constexpr uint64_t kExternalPointerTagMask = 0x40ff000000000000; constexpr uint64_t kExternalPointerTagShift = 48; -#define MAKE_TAG(v) (static_cast(v) << kExternalPointerTagShift) + +// All possible 8-bit type tags. +// These are sorted so that tags can be grouped together and it can efficiently +// be checked if a tag belongs to a given group. See for example the +// IsSharedExternalPointerType routine. +constexpr uint64_t kAllExternalPointerTypeTags[] = { + 0b00001111, 0b00010111, 0b00011011, 0b00011101, 0b00011110, 0b00100111, + 0b00101011, 0b00101101, 0b00101110, 0b00110011, 0b00110101, 0b00110110, + 0b00111001, 0b00111010, 0b00111100, 0b01000111, 0b01001011, 0b01001101, + 0b01001110, 0b01010011, 0b01010101, 0b01010110, 0b01011001, 0b01011010, + 0b01011100, 0b01100011, 0b01100101, 0b01100110, 0b01101001, 0b01101010, + 0b01101100, 0b01110001, 0b01110010, 0b01110100, 0b01111000, 0b10000111, + 0b10001011, 0b10001101, 0b10001110, 0b10010011, 0b10010101, 0b10010110, + 0b10011001, 0b10011010, 0b10011100, 0b10100011, 0b10100101, 0b10100110, + 0b10101001, 0b10101010, 0b10101100, 0b10110001, 0b10110010, 0b10110100, + 0b10111000, 0b11000011, 0b11000101, 0b11000110, 0b11001001, 0b11001010, + 0b11001100, 0b11010001, 0b11010010, 0b11010100, 0b11011000, 0b11100001, + 0b11100010, 0b11100100, 0b11101000, 0b11110000}; + // clang-format off +// New entries should be added with state "sandboxed". +// When adding new tags, please ensure that the code using these tags is +// "substitution-safe", i.e. still operate safely if external pointers of the +// same type are swapped by an attacker. See comment above for more details. +#define TAG(i) (kAllExternalPointerTypeTags[i]) + +// Shared external pointers are owned by the shared Isolate and stored in the +// shared external pointer table associated with that Isolate, where they can +// be accessed from multiple threads at the same time. The objects referenced +// in this way must therefore always be thread-safe. +#define SHARED_EXTERNAL_POINTER_TAGS(V) \ + V(kFirstSharedTag, sandboxed, TAG(0)) \ + V(kWaiterQueueNodeTag, sandboxed, TAG(0)) \ + V(kExternalStringResourceTag, sandboxed, TAG(1)) \ + V(kExternalStringResourceDataTag, sandboxed, TAG(2)) \ + V(kLastSharedTag, sandboxed, TAG(2)) + +// External pointers using these tags are kept in a per-Isolate external +// pointer table and can only be accessed when this Isolate is active. +#define PER_ISOLATE_EXTERNAL_POINTER_TAGS(V) \ + V(kForeignForeignAddressTag, sandboxed, TAG(10)) \ + V(kNativeContextMicrotaskQueueTag, sandboxed, TAG(11)) \ + V(kEmbedderDataSlotPayloadTag, sandboxed, TAG(12)) \ + V(kExternalObjectValueTag, sandboxed, TAG(13)) \ + V(kCallHandlerInfoCallbackTag, sandboxed, TAG(14)) \ + V(kAccessorInfoGetterTag, sandboxed, TAG(15)) \ + V(kAccessorInfoSetterTag, sandboxed, TAG(16)) \ + V(kWasmInternalFunctionCallTargetTag, sandboxed, TAG(17)) \ + V(kWasmTypeInfoNativeTypeTag, sandboxed, TAG(18)) \ + V(kWasmExportedFunctionDataSignatureTag, sandboxed, TAG(19)) \ + V(kWasmContinuationJmpbufTag, sandboxed, TAG(20)) + +// All external pointer tags. +#define ALL_EXTERNAL_POINTER_TAGS(V) \ + SHARED_EXTERNAL_POINTER_TAGS(V) \ + PER_ISOLATE_EXTERNAL_POINTER_TAGS(V) + +// When the sandbox is enabled, external pointers marked as "sandboxed" above +// use the external pointer table (i.e. are sandboxed). This allows a gradual +// rollout of external pointer sandboxing. If the sandbox is off, no external +// pointers are sandboxed. +// +// Sandboxed external pointer tags are available when compressing pointers even +// when the sandbox is off. Some tags (e.g. kWaiterQueueNodeTag) are used +// manually with the external pointer table even when the sandbox is off to ease +// alignment requirements. +#define sandboxed(X) (X << kExternalPointerTagShift) | kExternalPointerMarkBit +#define unsandboxed(X) kUnsandboxedExternalPointerTag +#if defined(V8_COMPRESS_POINTERS) +#define EXTERNAL_POINTER_TAG_ENUM(Name, State, Bits) Name = State(Bits), +#else +#define EXTERNAL_POINTER_TAG_ENUM(Name, State, Bits) Name = unsandboxed(Bits), +#endif + +#define MAKE_TAG(HasMarkBit, TypeTag) \ + ((static_cast(TypeTag) << kExternalPointerTagShift) | \ + (HasMarkBit ? kExternalPointerMarkBit : 0)) enum ExternalPointerTag : uint64_t { - kExternalPointerNullTag = MAKE_TAG(0b0000000000000000), - kExternalPointerFreeEntryTag = MAKE_TAG(0b0111111110000000), - kExternalStringResourceTag = MAKE_TAG(0b1000000011111111), - kExternalStringResourceDataTag = MAKE_TAG(0b1000000101111111), - kForeignForeignAddressTag = MAKE_TAG(0b1000000110111111), - kNativeContextMicrotaskQueueTag = MAKE_TAG(0b1000000111011111), - kEmbedderDataSlotPayloadTag = MAKE_TAG(0b1000000111101111), - kCodeEntryPointTag = MAKE_TAG(0b1000000111110111), - kExternalObjectValueTag = MAKE_TAG(0b1000000111111011), + // Empty tag value. Mostly used as placeholder. + kExternalPointerNullTag = MAKE_TAG(0, 0b00000000), + // Tag to use for unsandboxed external pointers, which are still stored as + // raw pointers on the heap. + kUnsandboxedExternalPointerTag = MAKE_TAG(0, 0b00000000), + // External pointer tag that will match any external pointer. Use with care! + kAnyExternalPointerTag = MAKE_TAG(1, 0b11111111), + // The free entry tag has all type bits set so every type check with a + // different type fails. It also doesn't have the mark bit set as free + // entries are (by definition) not alive. + kExternalPointerFreeEntryTag = MAKE_TAG(0, 0b11111111), + // Evacuation entries are used during external pointer table compaction. + kExternalPointerEvacuationEntryTag = MAKE_TAG(1, 0b11100111), + + ALL_EXTERNAL_POINTER_TAGS(EXTERNAL_POINTER_TAG_ENUM) }; -// clang-format on + #undef MAKE_TAG +#undef unsandboxed +#undef sandboxed +#undef TAG +#undef EXTERNAL_POINTER_TAG_ENUM + +// clang-format on + +// True if the external pointer is sandboxed and so must be referenced through +// an external pointer table. +V8_INLINE static constexpr bool IsSandboxedExternalPointerType( + ExternalPointerTag tag) { + return tag != kUnsandboxedExternalPointerTag; +} -// Converts encoded external pointer to address. -V8_EXPORT Address DecodeExternalPointerImpl(const Isolate* isolate, - ExternalPointer_t pointer, - ExternalPointerTag tag); +// True if the external pointer must be accessed from the shared isolate's +// external pointer table. +V8_INLINE static constexpr bool IsSharedExternalPointerType( + ExternalPointerTag tag) { + return tag >= kFirstSharedTag && tag <= kLastSharedTag; +} + +// Sanity checks. +#define CHECK_SHARED_EXTERNAL_POINTER_TAGS(Tag, ...) \ + static_assert(!IsSandboxedExternalPointerType(Tag) || \ + IsSharedExternalPointerType(Tag)); +#define CHECK_NON_SHARED_EXTERNAL_POINTER_TAGS(Tag, ...) \ + static_assert(!IsSandboxedExternalPointerType(Tag) || \ + !IsSharedExternalPointerType(Tag)); + +SHARED_EXTERNAL_POINTER_TAGS(CHECK_SHARED_EXTERNAL_POINTER_TAGS) +PER_ISOLATE_EXTERNAL_POINTER_TAGS(CHECK_NON_SHARED_EXTERNAL_POINTER_TAGS) + +#undef CHECK_NON_SHARED_EXTERNAL_POINTER_TAGS +#undef CHECK_SHARED_EXTERNAL_POINTER_TAGS + +#undef SHARED_EXTERNAL_POINTER_TAGS +#undef EXTERNAL_POINTER_TAGS // {obj} must be the raw tagged pointer representation of a HeapObject // that's guaranteed to never be in ReadOnlySpace. @@ -324,9 +475,6 @@ V8_EXPORT internal::Isolate* IsolateFromNeverReadOnlySpaceObject(Address obj); // mode based on the current context and the closure. This returns true if the // language mode is strict. V8_EXPORT bool ShouldThrowOnError(v8::internal::Isolate* isolate); - -V8_EXPORT bool CanHaveInternalField(int instance_type); - /** * This class exports constants and functionality from within v8 that * is necessary to implement inline functions in the v8 api. Don't @@ -354,8 +502,10 @@ class Internals { static const int kFixedArrayHeaderSize = 2 * kApiTaggedSize; static const int kEmbedderDataArrayHeaderSize = 2 * kApiTaggedSize; static const int kEmbedderDataSlotSize = kApiSystemPointerSize; -#ifdef V8_SANDBOXED_EXTERNAL_POINTERS - static const int kEmbedderDataSlotRawPayloadOffset = kApiTaggedSize; +#ifdef V8_ENABLE_SANDBOX + static const int kEmbedderDataSlotExternalPointerOffset = kApiTaggedSize; +#else + static const int kEmbedderDataSlotExternalPointerOffset = 0; #endif static const int kNativeContextEmbedderDataOffset = 6 * kApiTaggedSize; static const int kStringRepresentationAndEncodingMask = 0x0f; @@ -365,15 +515,21 @@ class Internals { static const uint32_t kNumIsolateDataSlots = 4; static const int kStackGuardSize = 7 * kApiSystemPointerSize; - static const int kBuiltinTier0EntryTableSize = 10 * kApiSystemPointerSize; - static const int kBuiltinTier0TableSize = 10 * kApiSystemPointerSize; + static const int kBuiltinTier0EntryTableSize = 7 * kApiSystemPointerSize; + static const int kBuiltinTier0TableSize = 7 * kApiSystemPointerSize; + + // ExternalPointerTable layout guarantees. + static const int kExternalPointerTableBufferOffset = 0; + static const int kExternalPointerTableSize = 4 * kApiSystemPointerSize; // IsolateData layout guarantees. static const int kIsolateCageBaseOffset = 0; static const int kIsolateStackGuardOffset = kIsolateCageBaseOffset + kApiSystemPointerSize; - static const int kBuiltinTier0EntryTableOffset = + static const int kVariousBooleanFlagsOffset = kIsolateStackGuardOffset + kStackGuardSize; + static const int kBuiltinTier0EntryTableOffset = + kVariousBooleanFlagsOffset + kApiSystemPointerSize; static const int kBuiltinTier0TableOffset = kBuiltinTier0EntryTableOffset + kBuiltinTier0EntryTableSize; static const int kIsolateEmbedderDataOffset = @@ -386,14 +542,17 @@ class Internals { kIsolateFastCCallCallerPcOffset + kApiSystemPointerSize; static const int kIsolateLongTaskStatsCounterOffset = kIsolateFastApiCallTargetOffset + kApiSystemPointerSize; +#ifdef V8_COMPRESS_POINTERS + static const int kIsolateExternalPointerTableOffset = + kIsolateLongTaskStatsCounterOffset + kApiSizetSize; + static const int kIsolateSharedExternalPointerTableAddressOffset = + kIsolateExternalPointerTableOffset + kExternalPointerTableSize; + static const int kIsolateRootsOffset = + kIsolateSharedExternalPointerTableAddressOffset + kApiSystemPointerSize; +#else static const int kIsolateRootsOffset = kIsolateLongTaskStatsCounterOffset + kApiSizetSize; - - static const int kExternalPointerTableBufferOffset = 0; - static const int kExternalPointerTableCapacityOffset = - kExternalPointerTableBufferOffset + kApiSystemPointerSize; - static const int kExternalPointerTableFreelistHeadOffset = - kExternalPointerTableCapacityOffset + kApiInt32Size; +#endif static const int kUndefinedValueRootIndex = 4; static const int kTheHoleValueRootIndex = 5; @@ -404,9 +563,8 @@ class Internals { static const int kNodeClassIdOffset = 1 * kApiSystemPointerSize; static const int kNodeFlagsOffset = 1 * kApiSystemPointerSize + 3; - static const int kNodeStateMask = 0x7; + static const int kNodeStateMask = 0x3; static const int kNodeStateIsWeakValue = 2; - static const int kNodeStateIsPendingValue = 3; static const int kFirstNonstringType = 0x80; static const int kOddballType = 0x83; @@ -481,6 +639,18 @@ class Internals { return representation == kExternalTwoByteRepresentationTag; } + V8_INLINE static constexpr bool CanHaveInternalField(int instance_type) { + static_assert(kJSObjectType + 1 == kFirstJSApiObjectType); + static_assert(kJSObjectType < kLastJSApiObjectType); + static_assert(kFirstJSApiObjectType < kLastJSApiObjectType); + // Check for IsJSObject() || IsJSSpecialApiObject() || IsJSApiObject() + return instance_type == kJSSpecialApiObjectType || + // inlined version of base::IsInRange + (static_cast(static_cast(instance_type) - + static_cast(kJSObjectType)) <= + static_cast(kLastJSApiObjectType - kJSObjectType)); + } + V8_INLINE static uint8_t GetNodeFlag(internal::Address* obj, int shift) { uint8_t* addr = reinterpret_cast(obj) + kNodeFlagsOffset; return *addr & static_cast(1U << shift); @@ -532,6 +702,25 @@ class Internals { return reinterpret_cast(addr); } +#ifdef V8_ENABLE_SANDBOX + V8_INLINE static internal::Address* GetExternalPointerTableBase( + v8::Isolate* isolate) { + internal::Address addr = reinterpret_cast(isolate) + + kIsolateExternalPointerTableOffset + + kExternalPointerTableBufferOffset; + return *reinterpret_cast(addr); + } + + V8_INLINE static internal::Address* GetSharedExternalPointerTableBase( + v8::Isolate* isolate) { + internal::Address addr = reinterpret_cast(isolate) + + kIsolateSharedExternalPointerTableAddressOffset; + addr = *reinterpret_cast(addr); + addr += kExternalPointerTableBufferOffset; + return *reinterpret_cast(addr); + } +#endif + template V8_INLINE static T ReadRawField(internal::Address heap_object_ptr, int offset) { @@ -572,38 +761,38 @@ class Internals { #endif } - V8_INLINE static internal::Isolate* GetIsolateForSandbox( - internal::Address obj) { -#ifdef V8_SANDBOXED_EXTERNAL_POINTERS - return internal::IsolateFromNeverReadOnlySpaceObject(obj); + V8_INLINE static v8::Isolate* GetIsolateForSandbox(internal::Address obj) { +#ifdef V8_ENABLE_SANDBOX + return reinterpret_cast( + internal::IsolateFromNeverReadOnlySpaceObject(obj)); #else // Not used in non-sandbox mode. return nullptr; #endif } - V8_INLINE static Address DecodeExternalPointer( - const Isolate* isolate, ExternalPointer_t encoded_pointer, - ExternalPointerTag tag) { -#ifdef V8_SANDBOXED_EXTERNAL_POINTERS - return internal::DecodeExternalPointerImpl(isolate, encoded_pointer, tag); -#else - return encoded_pointer; -#endif - } - + template V8_INLINE static internal::Address ReadExternalPointerField( - internal::Isolate* isolate, internal::Address heap_object_ptr, int offset, - ExternalPointerTag tag) { -#ifdef V8_SANDBOXED_EXTERNAL_POINTERS - internal::ExternalPointer_t encoded_value = - ReadRawField(heap_object_ptr, offset); - // We currently have to treat zero as nullptr in embedder slots. - return encoded_value ? DecodeExternalPointer(isolate, encoded_value, tag) - : 0; -#else - return ReadRawField
(heap_object_ptr, offset); + v8::Isolate* isolate, internal::Address heap_object_ptr, int offset) { +#ifdef V8_ENABLE_SANDBOX + if (IsSandboxedExternalPointerType(tag)) { + // See src/sandbox/external-pointer-table-inl.h. Logic duplicated here so + // it can be inlined and doesn't require an additional call. + internal::Address* table = + IsSharedExternalPointerType(tag) + ? GetSharedExternalPointerTableBase(isolate) + : GetExternalPointerTableBase(isolate); + internal::ExternalPointerHandle handle = + ReadRawField(heap_object_ptr, offset); + uint32_t index = handle >> kExternalPointerIndexShift; + std::atomic* ptr = + reinterpret_cast*>(&table[index]); + internal::Address entry = + std::atomic_load_explicit(ptr, std::memory_order_relaxed); + return entry & ~tag; + } #endif + return ReadRawField
(heap_object_ptr, offset); } #ifdef V8_COMPRESS_POINTERS @@ -652,7 +841,7 @@ class BackingStoreBase {}; // The maximum value in enum GarbageCollectionReason, defined in heap.h. // This is needed for histograms sampling garbage collection reasons. -constexpr int kGarbageCollectionReasonMaxValue = 25; +constexpr int kGarbageCollectionReasonMaxValue = 27; } // namespace internal diff --git a/deps/v8/include/v8-isolate.h b/deps/v8/include/v8-isolate.h index 2849d7cae1e9e8..4f31d8c7a80835 100644 --- a/deps/v8/include/v8-isolate.h +++ b/deps/v8/include/v8-isolate.h @@ -194,6 +194,11 @@ enum RAILMode : unsigned { */ enum class MemoryPressureLevel { kNone, kModerate, kCritical }; +/** + * Indicator for the stack state. + */ +using StackState = cppgc::EmbedderStackState; + /** * Isolate represents an isolated instance of the V8 engine. V8 isolates have * completely separate states. Objects from one isolate must not be used in @@ -211,6 +216,8 @@ class V8_EXPORT Isolate { CreateParams(); ~CreateParams(); + ALLOW_COPY_AND_MOVE_WITH_DEPRECATED_FIELDS(CreateParams) + /** * Allows the host application to provide the address of a function that is * notified each time code is added, moved or removed. @@ -287,12 +294,6 @@ class V8_EXPORT Isolate { */ FatalErrorCallback fatal_error_callback = nullptr; OOMErrorCallback oom_error_callback = nullptr; - - /** - * The following parameter is experimental and may change significantly. - * This is currently for internal testing. - */ - Isolate* experimental_attach_to_shared_isolate = nullptr; }; /** @@ -301,16 +302,18 @@ class V8_EXPORT Isolate { */ class V8_EXPORT V8_NODISCARD Scope { public: - explicit Scope(Isolate* isolate) : isolate_(isolate) { isolate->Enter(); } + explicit Scope(Isolate* isolate) : v8_isolate_(isolate) { + v8_isolate_->Enter(); + } - ~Scope() { isolate_->Exit(); } + ~Scope() { v8_isolate_->Exit(); } // Prevent copying of Scope objects. Scope(const Scope&) = delete; Scope& operator=(const Scope&) = delete; private: - Isolate* const isolate_; + Isolate* const v8_isolate_; }; /** @@ -331,7 +334,7 @@ class V8_EXPORT Isolate { private: OnFailure on_failure_; - Isolate* isolate_; + v8::Isolate* v8_isolate_; bool was_execution_allowed_assert_; bool was_execution_allowed_throws_; @@ -353,7 +356,7 @@ class V8_EXPORT Isolate { const AllowJavascriptExecutionScope&) = delete; private: - Isolate* isolate_; + Isolate* v8_isolate_; bool was_execution_allowed_assert_; bool was_execution_allowed_throws_; bool was_execution_allowed_dump_; @@ -376,7 +379,7 @@ class V8_EXPORT Isolate { const SuppressMicrotaskExecutionScope&) = delete; private: - internal::Isolate* const isolate_; + internal::Isolate* const i_isolate_; internal::MicrotaskQueue* const microtask_queue_; internal::Address previous_stack_height_; @@ -389,7 +392,7 @@ class V8_EXPORT Isolate { */ class V8_EXPORT V8_NODISCARD SafeForTerminationScope { public: - explicit SafeForTerminationScope(v8::Isolate* isolate); + explicit SafeForTerminationScope(v8::Isolate* v8_isolate); ~SafeForTerminationScope(); // Prevent copying of Scope objects. @@ -397,7 +400,7 @@ class V8_EXPORT Isolate { SafeForTerminationScope& operator=(const SafeForTerminationScope&) = delete; private: - internal::Isolate* isolate_; + internal::Isolate* i_isolate_; bool prev_value_; }; @@ -531,6 +534,8 @@ class V8_EXPORT Isolate { kInvalidatedMegaDOMProtector = 112, kFunctionPrototypeArguments = 113, kFunctionPrototypeCaller = 114, + kTurboFanOsrCompileStarted = 115, + kAsyncStackTaggingCreateTaskCall = 116, // If you add new values here, you'll also need to update Chromium's: // web_feature.mojom, use_counter_callback.cc, and enums.xml. V8 changes to @@ -636,9 +641,6 @@ class V8_EXPORT Isolate { * This specifies the callback called by the upcoming dynamic * import() language feature to load modules. */ - V8_DEPRECATED("Use HostImportModuleDynamicallyCallback") - void SetHostImportModuleDynamicallyCallback( - HostImportModuleDynamicallyWithImportAssertionsCallback callback); void SetHostImportModuleDynamicallyCallback( HostImportModuleDynamicallyCallback callback); @@ -839,12 +841,6 @@ class V8_EXPORT Isolate { */ int64_t AdjustAmountOfExternalAllocatedMemory(int64_t change_in_bytes); - /** - * Returns the number of phantom handles without callbacks that were reset - * by the garbage collector since the last call to this function. - */ - size_t NumberOfPhantomHandleResetsSinceLastCall(); - /** * Returns heap profiler for this isolate. Will return NULL until the isolate * is initialized. @@ -927,6 +923,7 @@ class V8_EXPORT Isolate { void RemoveGCPrologueCallback(GCCallbackWithData, void* data = nullptr); void RemoveGCPrologueCallback(GCCallback callback); + START_ALLOW_USE_DEPRECATED() /** * Sets the embedder heap tracer for the isolate. * SetEmbedderHeapTracer cannot be used simultaneously with AttachCppHeap. @@ -938,6 +935,7 @@ class V8_EXPORT Isolate { * SetEmbedderHeapTracer. */ EmbedderHeapTracer* GetEmbedderHeapTracer(); + END_ALLOW_USE_DEPRECATED() /** * Sets an embedder roots handle that V8 should consider when performing @@ -1163,9 +1161,8 @@ class V8_EXPORT Isolate { * LowMemoryNotification() instead to influence the garbage collection * schedule. */ - void RequestGarbageCollectionForTesting( - GarbageCollectionType type, - EmbedderHeapTracer::EmbedderStackState stack_state); + void RequestGarbageCollectionForTesting(GarbageCollectionType type, + StackState stack_state); /** * Set the callback to invoke for logging event. @@ -1523,15 +1520,15 @@ class V8_EXPORT Isolate { void SetWasmStreamingCallback(WasmStreamingCallback callback); + void SetWasmAsyncResolvePromiseCallback( + WasmAsyncResolvePromiseCallback callback); + void SetWasmLoadSourceMapCallback(WasmLoadSourceMapCallback callback); void SetWasmSimdEnabledCallback(WasmSimdEnabledCallback callback); void SetWasmExceptionsEnabledCallback(WasmExceptionsEnabledCallback callback); - void SetWasmDynamicTieringEnabledCallback( - WasmDynamicTieringEnabledCallback callback); - void SetSharedArrayBufferConstructorEnabledCallback( SharedArrayBufferConstructorEnabledCallback callback); @@ -1598,19 +1595,6 @@ class V8_EXPORT Isolate { */ void VisitExternalResources(ExternalResourceVisitor* visitor); - /** - * Iterates through all the persistent handles in the current isolate's heap - * that have class_ids. - */ - void VisitHandlesWithClassIds(PersistentHandleVisitor* visitor); - - /** - * Iterates through all the persistent handles in the current isolate's heap - * that have class_ids and are weak to be marked as inactive if there is no - * pending activity for the handle. - */ - void VisitWeakHandles(PersistentHandleVisitor* visitor); - /** * Check if this isolate is in use. * True if at least one thread Enter'ed this isolate. diff --git a/deps/v8/include/v8-local-handle.h b/deps/v8/include/v8-local-handle.h index 5ae974081f8e32..cbf87f949d09fa 100644 --- a/deps/v8/include/v8-local-handle.h +++ b/deps/v8/include/v8-local-handle.h @@ -86,7 +86,7 @@ class V8_EXPORT V8_NODISCARD HandleScope { static int NumberOfHandles(Isolate* isolate); V8_INLINE Isolate* GetIsolate() const { - return reinterpret_cast(isolate_); + return reinterpret_cast(i_isolate_); } HandleScope(const HandleScope&) = delete; @@ -97,7 +97,7 @@ class V8_EXPORT V8_NODISCARD HandleScope { void Initialize(Isolate* isolate); - static internal::Address* CreateHandle(internal::Isolate* isolate, + static internal::Address* CreateHandle(internal::Isolate* i_isolate, internal::Address value); private: @@ -108,7 +108,7 @@ class V8_EXPORT V8_NODISCARD HandleScope { void operator delete(void*, size_t); void operator delete[](void*, size_t); - internal::Isolate* isolate_; + internal::Isolate* i_isolate_; internal::Address* prev_next_; internal::Address* prev_limit_; @@ -354,7 +354,7 @@ class MaybeLocal { /** * Converts this MaybeLocal<> to a Local<>. If this MaybeLocal<> is empty, - * |false| is returned and |out| is left untouched. + * |false| is returned and |out| is assigned with nullptr. */ template V8_WARN_UNUSED_RESULT V8_INLINE bool ToLocal(Local* out) const { @@ -445,7 +445,7 @@ class V8_EXPORT V8_NODISCARD SealHandleScope { void operator delete(void*, size_t); void operator delete[](void*, size_t); - internal::Isolate* const isolate_; + internal::Isolate* const i_isolate_; internal::Address* prev_limit_; int prev_sealed_level_; }; diff --git a/deps/v8/include/v8-locker.h b/deps/v8/include/v8-locker.h index 7ca5bf6e421e41..22b7a8767a83a7 100644 --- a/deps/v8/include/v8-locker.h +++ b/deps/v8/include/v8-locker.h @@ -121,17 +121,6 @@ class V8_EXPORT Locker { */ static bool IsLocked(Isolate* isolate); - /** - * Returns whether any v8::Locker has ever been used in this process. - * TODO(cbruni, chromium:1240851): Fix locking checks on a per-thread basis. - * The current implementation is quite confusing and leads to unexpected - * results if anybody uses v8::Locker in the current process. - */ - V8_DEPRECATE_SOON("This method will be removed.") - static bool WasEverUsed(); - V8_DEPRECATED("Use WasEverUsed instead") - static bool IsActive(); - // Disallow copying and assigning. Locker(const Locker&) = delete; void operator=(const Locker&) = delete; diff --git a/deps/v8/include/v8-maybe.h b/deps/v8/include/v8-maybe.h index 0532a510059d02..8d3aeabe02af45 100644 --- a/deps/v8/include/v8-maybe.h +++ b/deps/v8/include/v8-maybe.h @@ -5,6 +5,9 @@ #ifndef INCLUDE_V8_MAYBE_H_ #define INCLUDE_V8_MAYBE_H_ +#include +#include + #include "v8-internal.h" // NOLINT(build/include_directory) #include "v8config.h" // NOLINT(build/include_directory) @@ -57,11 +60,20 @@ class Maybe { * Converts this Maybe<> to a value of type T. If this Maybe<> is * nothing (empty), V8 will crash the process. */ - V8_INLINE T FromJust() const { + V8_INLINE T FromJust() const& { if (V8_UNLIKELY(!IsJust())) api_internal::FromJustIsNothing(); return value_; } + /** + * Converts this Maybe<> to a value of type T. If this Maybe<> is + * nothing (empty), V8 will crash the process. + */ + V8_INLINE T FromJust() && { + if (V8_UNLIKELY(!IsJust())) api_internal::FromJustIsNothing(); + return std::move(value_); + } + /** * Converts this Maybe<> to a value of type T, using a default value if this * Maybe<> is nothing (empty). @@ -82,6 +94,7 @@ class Maybe { private: Maybe() : has_value_(false) {} explicit Maybe(const T& t) : has_value_(true), value_(t) {} + explicit Maybe(T&& t) : has_value_(true), value_(std::move(t)) {} bool has_value_; T value_; @@ -90,6 +103,8 @@ class Maybe { friend Maybe Nothing(); template friend Maybe Just(const U& u); + template >*> + friend Maybe Just(U&& u); }; template @@ -102,6 +117,14 @@ inline Maybe Just(const T& t) { return Maybe(t); } +// Don't use forwarding references here but instead use two overloads. +// Forwarding references only work when type deduction takes place, which is not +// the case for callsites such as Just(t). +template >* = nullptr> +inline Maybe Just(T&& t) { + return Maybe(std::move(t)); +} + // A template specialization of Maybe for the case of T = void. template <> class Maybe { diff --git a/deps/v8/include/v8-message.h b/deps/v8/include/v8-message.h index a13276412a8152..09f9a0a97ddb64 100644 --- a/deps/v8/include/v8-message.h +++ b/deps/v8/include/v8-message.h @@ -70,7 +70,7 @@ class V8_EXPORT ScriptOrigin { bool resource_is_opaque = false, bool is_wasm = false, bool is_module = false, Local host_defined_options = Local()) - : isolate_(isolate), + : v8_isolate_(isolate), resource_name_(resource_name), resource_line_offset_(resource_line_offset), resource_column_offset_(resource_column_offset), @@ -87,14 +87,12 @@ class V8_EXPORT ScriptOrigin { V8_INLINE int ColumnOffset() const; V8_INLINE int ScriptId() const; V8_INLINE Local SourceMapUrl() const; - V8_DEPRECATE_SOON("Use GetHostDefinedOptions") - Local HostDefinedOptions() const; V8_INLINE Local GetHostDefinedOptions() const; V8_INLINE ScriptOriginOptions Options() const { return options_; } private: void VerifyHostDefinedOptions() const; - Isolate* isolate_; + Isolate* v8_isolate_; Local resource_name_; int resource_line_offset_; int resource_column_offset_; diff --git a/deps/v8/include/v8-metrics.h b/deps/v8/include/v8-metrics.h index d8e8bd865bfc03..887012ac8c3a0b 100644 --- a/deps/v8/include/v8-metrics.h +++ b/deps/v8/include/v8-metrics.h @@ -125,31 +125,10 @@ struct WasmModuleInstantiated { int64_t wall_clock_duration_in_us = -1; }; -struct WasmModuleTieredUp { - bool lazy = false; - size_t code_size_in_bytes = 0; - int64_t wall_clock_duration_in_us = -1; - int64_t cpu_duration_in_us = -1; -}; - struct WasmModulesPerIsolate { size_t count = 0; }; -#define V8_MAIN_THREAD_METRICS_EVENTS(V) \ - V(GarbageCollectionFullCycle) \ - V(GarbageCollectionFullMainThreadIncrementalMark) \ - V(GarbageCollectionFullMainThreadBatchedIncrementalMark) \ - V(GarbageCollectionFullMainThreadIncrementalSweep) \ - V(GarbageCollectionFullMainThreadBatchedIncrementalSweep) \ - V(GarbageCollectionYoungCycle) \ - V(WasmModuleDecoded) \ - V(WasmModuleCompiled) \ - V(WasmModuleInstantiated) \ - V(WasmModuleTieredUp) - -#define V8_THREAD_SAFE_METRICS_EVENTS(V) V(WasmModulesPerIsolate) - /** * This class serves as a base class for recording event-based metrics in V8. * There a two kinds of metrics, those which are expected to be thread-safe and @@ -159,19 +138,6 @@ struct WasmModulesPerIsolate { * background thread, it will be delayed and executed by the foreground task * runner. * - * The thread-safe events are listed in the V8_THREAD_SAFE_METRICS_EVENTS - * macro above while the main thread event are listed in - * V8_MAIN_THREAD_METRICS_EVENTS above. For the former, a virtual method - * AddMainThreadEvent(const E& event, v8::Context::Token token) will be - * generated and for the latter AddThreadSafeEvent(const E& event). - * - * Thread-safe events are not allowed to access the context and therefore do - * not carry a context ID with them. These IDs can be generated using - * Recorder::GetContextId() and the ID will be valid throughout the lifetime - * of the isolate. It is not guaranteed that the ID will still resolve to - * a valid context using Recorder::GetContext() at the time the metric is - * recorded. In this case, an empty handle will be returned. - * * The embedder is expected to call v8::Isolate::SetMetricsRecorder() * providing its implementation and have the virtual methods overwritten * for the events it cares about. @@ -202,14 +168,30 @@ class V8_EXPORT Recorder { virtual ~Recorder() = default; + // Main thread events. Those are only triggered on the main thread, and hence + // can access the context. #define ADD_MAIN_THREAD_EVENT(E) \ - virtual void AddMainThreadEvent(const E& event, ContextId context_id) {} - V8_MAIN_THREAD_METRICS_EVENTS(ADD_MAIN_THREAD_EVENT) + virtual void AddMainThreadEvent(const E&, ContextId) {} + ADD_MAIN_THREAD_EVENT(GarbageCollectionFullCycle) + ADD_MAIN_THREAD_EVENT(GarbageCollectionFullMainThreadIncrementalMark) + ADD_MAIN_THREAD_EVENT(GarbageCollectionFullMainThreadBatchedIncrementalMark) + ADD_MAIN_THREAD_EVENT(GarbageCollectionFullMainThreadIncrementalSweep) + ADD_MAIN_THREAD_EVENT(GarbageCollectionFullMainThreadBatchedIncrementalSweep) + ADD_MAIN_THREAD_EVENT(GarbageCollectionYoungCycle) + ADD_MAIN_THREAD_EVENT(WasmModuleDecoded) + ADD_MAIN_THREAD_EVENT(WasmModuleCompiled) + ADD_MAIN_THREAD_EVENT(WasmModuleInstantiated) #undef ADD_MAIN_THREAD_EVENT + // Thread-safe events are not allowed to access the context and therefore do + // not carry a context ID with them. These IDs can be generated using + // Recorder::GetContextId() and the ID will be valid throughout the lifetime + // of the isolate. It is not guaranteed that the ID will still resolve to + // a valid context using Recorder::GetContext() at the time the metric is + // recorded. In this case, an empty handle will be returned. #define ADD_THREAD_SAFE_EVENT(E) \ - virtual void AddThreadSafeEvent(const E& event) {} - V8_THREAD_SAFE_METRICS_EVENTS(ADD_THREAD_SAFE_EVENT) + virtual void AddThreadSafeEvent(const E&) {} + ADD_THREAD_SAFE_EVENT(WasmModulesPerIsolate) #undef ADD_THREAD_SAFE_EVENT virtual void NotifyIsolateDisposal() {} diff --git a/deps/v8/include/v8-microtask-queue.h b/deps/v8/include/v8-microtask-queue.h index af9caa54a8ff51..f1624b903b13c1 100644 --- a/deps/v8/include/v8-microtask-queue.h +++ b/deps/v8/include/v8-microtask-queue.h @@ -142,7 +142,7 @@ class V8_EXPORT V8_NODISCARD MicrotasksScope { MicrotasksScope& operator=(const MicrotasksScope&) = delete; private: - internal::Isolate* const isolate_; + internal::Isolate* const i_isolate_; internal::MicrotaskQueue* const microtask_queue_; bool run_; }; diff --git a/deps/v8/include/v8-object.h b/deps/v8/include/v8-object.h index bad299fc42948d..d7332ba0c88d12 100644 --- a/deps/v8/include/v8-object.h +++ b/deps/v8/include/v8-object.h @@ -594,8 +594,6 @@ class V8_EXPORT Object : public Value { /** * Returns the context in which the object was created. */ - V8_DEPRECATED("Use MaybeLocal GetCreationContext()") - Local CreationContext(); MaybeLocal GetCreationContext(); /** @@ -604,10 +602,6 @@ class V8_EXPORT Object : public Value { Local GetCreationContextChecked(); /** Same as above, but works for Persistents */ - V8_DEPRECATED( - "Use MaybeLocal GetCreationContext(const " - "PersistentBase& object)") - static Local CreationContext(const PersistentBase& object); V8_INLINE static MaybeLocal GetCreationContext( const PersistentBase& object) { return object.val_->GetCreationContext(); @@ -717,7 +711,7 @@ Local Object::GetInternalField(int index) { // Fast path: If the object is a plain JSObject, which is the common case, we // know where to find the internal fields and can return the value directly. int instance_type = I::GetInstanceType(obj); - if (v8::internal::CanHaveInternalField(instance_type)) { + if (I::CanHaveInternalField(instance_type)) { int offset = I::kJSObjectHeaderSize + (I::kEmbedderDataSlotSize * index); A value = I::ReadRawField(obj, offset); #ifdef V8_COMPRESS_POINTERS @@ -742,14 +736,13 @@ void* Object::GetAlignedPointerFromInternalField(int index) { // Fast path: If the object is a plain JSObject, which is the common case, we // know where to find the internal fields and can return the value directly. auto instance_type = I::GetInstanceType(obj); - if (v8::internal::CanHaveInternalField(instance_type)) { - int offset = I::kJSObjectHeaderSize + (I::kEmbedderDataSlotSize * index); -#ifdef V8_SANDBOXED_EXTERNAL_POINTERS - offset += I::kEmbedderDataSlotRawPayloadOffset; -#endif - internal::Isolate* isolate = I::GetIsolateForSandbox(obj); - A value = I::ReadExternalPointerField( - isolate, obj, offset, internal::kEmbedderDataSlotPayloadTag); + if (I::CanHaveInternalField(instance_type)) { + int offset = I::kJSObjectHeaderSize + (I::kEmbedderDataSlotSize * index) + + I::kEmbedderDataSlotExternalPointerOffset; + Isolate* isolate = I::GetIsolateForSandbox(obj); + A value = + I::ReadExternalPointerField( + isolate, obj, offset); return reinterpret_cast(value); } #endif diff --git a/deps/v8/include/v8-persistent-handle.h b/deps/v8/include/v8-persistent-handle.h index a6c21268d6ab54..dbda4edb9baf4e 100644 --- a/deps/v8/include/v8-persistent-handle.h +++ b/deps/v8/include/v8-persistent-handle.h @@ -169,8 +169,6 @@ class PersistentBase { * Turns this handle into a weak phantom handle without finalization callback. * The handle will be reset automatically when the garbage collector detects * that the object is no longer reachable. - * A related function Isolate::NumberOfPhantomHandleResetsSinceLastCall - * returns how many phantom handles were reset by the garbage collector. */ V8_INLINE void SetWeak(); diff --git a/deps/v8/include/v8-platform.h b/deps/v8/include/v8-platform.h index 91b3fd9cc3f9a3..5d34372df50c2b 100644 --- a/deps/v8/include/v8-platform.h +++ b/deps/v8/include/v8-platform.h @@ -158,9 +158,10 @@ class TaskRunner { class JobDelegate { public: /** - * Returns true if this thread should return from the worker task on the + * Returns true if this thread *must* return from the worker task on the * current thread ASAP. Workers should periodically invoke ShouldYield (or * YieldIfNeeded()) as often as is reasonable. + * After this method returned true, ShouldYield must not be called again. */ virtual bool ShouldYield() = 0; @@ -429,6 +430,17 @@ class PageAllocator { virtual bool SetPermissions(void* address, size_t length, Permission permissions) = 0; + /** + * Recommits discarded pages in the given range with given permissions. + * Discarded pages must be recommitted with their original permissions + * before they are used again. + */ + virtual bool RecommitPages(void* address, size_t length, + Permission permissions) { + // TODO(v8:12797): make it pure once it's implemented on Chromium side. + return false; + } + /** * Frees memory in the given [address, address + size) range. address and size * should be operating system page-aligned. The next write to this @@ -698,6 +710,10 @@ class VirtualAddressSpace { /** * Sets permissions of all allocated pages in the given range. * + * This operation can fail due to OOM, in which case false is returned. If + * the operation fails for a reason other than OOM, this function will + * terminate the process as this implies a bug in the client. + * * \param address The start address of the range. Must be aligned to * page_size(). * @@ -706,7 +722,7 @@ class VirtualAddressSpace { * * \param permissions The new permissions for the range. * - * \returns true on success, false otherwise. + * \returns true on success, false on OOM. */ virtual V8_WARN_UNUSED_RESULT bool SetPagePermissions( Address address, size_t size, PagePermissions permissions) = 0; @@ -820,6 +836,24 @@ class VirtualAddressSpace { // takes a command enum as parameter. // + /** + * Recommits discarded pages in the given range with given permissions. + * Discarded pages must be recommitted with their original permissions + * before they are used again. + * + * \param address The start address of the range. Must be aligned to + * page_size(). + * + * \param size The size in bytes of the range. Must be a multiple + * of page_size(). + * + * \param permissions The permissions for the range that the pages must have. + * + * \returns true on success, false otherwise. + */ + virtual V8_WARN_UNUSED_RESULT bool RecommitPages( + Address address, size_t size, PagePermissions permissions) = 0; + /** * Frees memory in the given [address, address + size) range. address and * size should be aligned to the page_size(). The next write to this memory @@ -890,10 +924,7 @@ class Platform { /** * Allows the embedder to manage memory page allocations. */ - virtual PageAllocator* GetPageAllocator() { - // TODO(bbudge) Make this abstract after all embedders implement this. - return nullptr; - } + virtual PageAllocator* GetPageAllocator() = 0; /** * Allows the embedder to specify a custom allocator used for zones. @@ -910,10 +941,7 @@ class Platform { * error. * Embedder overrides of this function must NOT call back into V8. */ - virtual void OnCriticalMemoryPressure() { - // TODO(bbudge) Remove this when embedders override the following method. - // See crbug.com/634547. - } + virtual void OnCriticalMemoryPressure() {} /** * Enables the embedder to respond in cases where V8 can't allocate large @@ -924,6 +952,7 @@ class Platform { * * Embedder overrides of this function must NOT call back into V8. */ + V8_DEPRECATED("Use the method without informative parameter") virtual bool OnCriticalMemoryPressure(size_t length) { return false; } /** @@ -1022,16 +1051,28 @@ class Platform { * thread (A=>B/B=>A deadlock) and [2] JobTask::Run or * JobTask::GetMaxConcurrency may be invoked synchronously from JobHandle * (B=>JobHandle::foo=>B deadlock). + */ + virtual std::unique_ptr PostJob( + TaskPriority priority, std::unique_ptr job_task) { + auto handle = CreateJob(priority, std::move(job_task)); + handle->NotifyConcurrencyIncrease(); + return handle; + } + + /** + * Creates and returns a JobHandle associated with a Job. Unlike PostJob(), + * this doesn't immediately schedules |worker_task| to run; the Job is then + * scheduled by calling either NotifyConcurrencyIncrease() or Join(). * - * A sufficient PostJob() implementation that uses the default Job provided in - * libplatform looks like: - * std::unique_ptr PostJob( + * A sufficient CreateJob() implementation that uses the default Job provided + * in libplatform looks like: + * std::unique_ptr CreateJob( * TaskPriority priority, std::unique_ptr job_task) override { * return v8::platform::NewDefaultJobHandle( * this, priority, std::move(job_task), NumberOfWorkerThreads()); * } */ - virtual std::unique_ptr PostJob( + virtual std::unique_ptr CreateJob( TaskPriority priority, std::unique_ptr job_task) = 0; /** diff --git a/deps/v8/include/v8-primitive.h b/deps/v8/include/v8-primitive.h index 1b6de16686b10d..4fef8da7f8d5e7 100644 --- a/deps/v8/include/v8-primitive.h +++ b/deps/v8/include/v8-primitive.h @@ -20,6 +20,7 @@ class String; namespace internal { class ExternalString; class ScopedExternalStringLock; +class StringForwardingTable; } // namespace internal /** @@ -269,6 +270,7 @@ class V8_EXPORT String : public Name { private: friend class internal::ExternalString; friend class v8::String; + friend class internal::StringForwardingTable; friend class internal::ScopedExternalStringLock; }; @@ -785,10 +787,9 @@ String::ExternalStringResource* String::GetExternalStringResource() const { ExternalStringResource* result; if (I::IsExternalTwoByteString(I::GetInstanceType(obj))) { - internal::Isolate* isolate = I::GetIsolateForSandbox(obj); - A value = - I::ReadExternalPointerField(isolate, obj, I::kStringResourceOffset, - internal::kExternalStringResourceTag); + Isolate* isolate = I::GetIsolateForSandbox(obj); + A value = I::ReadExternalPointerField( + isolate, obj, I::kStringResourceOffset); result = reinterpret_cast(value); } else { result = GetExternalStringResourceSlow(); @@ -809,10 +810,9 @@ String::ExternalStringResourceBase* String::GetExternalStringResourceBase( ExternalStringResourceBase* resource; if (type == I::kExternalOneByteRepresentationTag || type == I::kExternalTwoByteRepresentationTag) { - internal::Isolate* isolate = I::GetIsolateForSandbox(obj); - A value = - I::ReadExternalPointerField(isolate, obj, I::kStringResourceOffset, - internal::kExternalStringResourceTag); + Isolate* isolate = I::GetIsolateForSandbox(obj); + A value = I::ReadExternalPointerField( + isolate, obj, I::kStringResourceOffset); resource = reinterpret_cast(value); } else { resource = GetExternalStringResourceBaseSlow(encoding_out); diff --git a/deps/v8/include/v8-profiler.h b/deps/v8/include/v8-profiler.h index 268104073231c6..8894641993e42a 100644 --- a/deps/v8/include/v8-profiler.h +++ b/deps/v8/include/v8-profiler.h @@ -331,6 +331,9 @@ class V8_EXPORT CpuProfilingOptions { unsigned max_samples = kNoSampleLimit, int sampling_interval_us = 0, MaybeLocal filter_context = MaybeLocal()); + CpuProfilingOptions(CpuProfilingOptions&&) = default; + CpuProfilingOptions& operator=(CpuProfilingOptions&&) = default; + CpuProfilingMode mode() const { return mode_; } unsigned max_samples() const { return max_samples_; } int sampling_interval_us() const { return sampling_interval_us_; } @@ -344,7 +347,7 @@ class V8_EXPORT CpuProfilingOptions { CpuProfilingMode mode_; unsigned max_samples_; int sampling_interval_us_; - CopyablePersistentTraits::CopyablePersistent filter_context_; + Global filter_context_; }; /** @@ -542,7 +545,9 @@ class V8_EXPORT HeapGraphNode { kConsString = 10, // Concatenated string. A pair of pointers to strings. kSlicedString = 11, // Sliced string. A fragment of another string. kSymbol = 12, // A Symbol (ES6). - kBigInt = 13 // BigInt. + kBigInt = 13, // BigInt. + kObjectShape = 14, // Internal data used for tracking the shapes (or + // "hidden classes") of JS objects. }; /** Returns node type (see HeapGraphNode::Type). */ @@ -975,14 +980,71 @@ class V8_EXPORT HeapProfiler { virtual ~ObjectNameResolver() = default; }; + enum class HeapSnapshotMode { + /** + * Heap snapshot for regular developers. + */ + kRegular, + /** + * Heap snapshot is exposing internals that may be useful for experts. + */ + kExposeInternals, + }; + + enum class NumericsMode { + /** + * Numeric values are hidden as they are values of the corresponding + * objects. + */ + kHideNumericValues, + /** + * Numeric values are exposed in artificial fields. + */ + kExposeNumericValues + }; + + struct HeapSnapshotOptions final { + // Manually define default constructor here to be able to use it in + // `TakeSnapshot()` below. + // NOLINTNEXTLINE + HeapSnapshotOptions() {} + + /** + * The control used to report intermediate progress to. + */ + ActivityControl* control = nullptr; + /** + * The resolver used by the snapshot generator to get names for V8 objects. + */ + ObjectNameResolver* global_object_name_resolver = nullptr; + /** + * Mode for taking the snapshot, see `HeapSnapshotMode`. + */ + HeapSnapshotMode snapshot_mode = HeapSnapshotMode::kRegular; + /** + * Mode for dealing with numeric values, see `NumericsMode`. + */ + NumericsMode numerics_mode = NumericsMode::kHideNumericValues; + }; + /** - * Takes a heap snapshot and returns it. + * Takes a heap snapshot. + * + * \returns the snapshot. + */ + const HeapSnapshot* TakeHeapSnapshot( + const HeapSnapshotOptions& options = HeapSnapshotOptions()); + + /** + * Takes a heap snapshot. See `HeapSnapshotOptions` for details on the + * parameters. + * + * \returns the snapshot. */ const HeapSnapshot* TakeHeapSnapshot( - ActivityControl* control = nullptr, + ActivityControl* control, ObjectNameResolver* global_object_name_resolver = nullptr, - bool treat_global_objects_as_roots = true, - bool capture_numeric_value = false); + bool hide_internals = true, bool capture_numeric_value = false); /** * Starts tracking of heap objects population statistics. After calling @@ -1101,18 +1163,18 @@ struct HeapStatsUpdate { uint32_t size; // New value of size field for the interval with this index. }; -#define CODE_EVENTS_LIST(V) \ - V(Builtin) \ - V(Callback) \ - V(Eval) \ - V(Function) \ - V(InterpretedFunction) \ - V(Handler) \ - V(BytecodeHandler) \ - V(LazyCompile) \ - V(RegExp) \ - V(Script) \ - V(Stub) \ +#define CODE_EVENTS_LIST(V) \ + V(Builtin) \ + V(Callback) \ + V(Eval) \ + V(Function) \ + V(InterpretedFunction) \ + V(Handler) \ + V(BytecodeHandler) \ + V(LazyCompile) /* Unused, use kFunction instead */ \ + V(RegExp) \ + V(Script) \ + V(Stub) \ V(Relocation) /** diff --git a/deps/v8/include/v8-regexp.h b/deps/v8/include/v8-regexp.h index 3791bc0368718d..135977bfbb85ee 100644 --- a/deps/v8/include/v8-regexp.h +++ b/deps/v8/include/v8-regexp.h @@ -37,9 +37,10 @@ class V8_EXPORT RegExp : public Object { kDotAll = 1 << 5, kLinear = 1 << 6, kHasIndices = 1 << 7, + kUnicodeSets = 1 << 8, }; - static constexpr int kFlagCount = 8; + static constexpr int kFlagCount = 9; /** * Creates a regular expression from the given pattern string and diff --git a/deps/v8/include/v8-script.h b/deps/v8/include/v8-script.h index 5644a3bb70c6b1..dbd98ed55b4ce0 100644 --- a/deps/v8/include/v8-script.h +++ b/deps/v8/include/v8-script.h @@ -20,6 +20,7 @@ namespace v8 { class Function; +class Message; class Object; class PrimitiveArray; class Script; @@ -47,8 +48,6 @@ class V8_EXPORT ScriptOrModule { * The options that were passed by the embedder as HostDefinedOptions to * the ScriptOrigin. */ - V8_DEPRECATED("Use HostDefinedOptions") - Local GetHostDefinedOptions(); Local HostDefinedOptions(); }; @@ -78,7 +77,13 @@ class V8_EXPORT UnboundScript { * Returns zero based line number of the code_pos location in the script. * -1 will be returned if no information available. */ - int GetLineNumber(int code_pos); + int GetLineNumber(int code_pos = 0); + + /** + * Returns zero based column number of the code_pos location in the script. + * -1 will be returned if no information available. + */ + int GetColumnNumber(int code_pos = 0); static const int kNoScriptId = 0; }; @@ -286,6 +291,16 @@ class V8_EXPORT Module : public Data { V8_WARN_UNUSED_RESULT Maybe SetSyntheticModuleExport( Isolate* isolate, Local export_name, Local export_value); + /** + * Search the modules requested directly or indirectly by the module for + * any top-level await that has not yet resolved. If there is any, the + * returned vector contains a tuple of the unresolved module and a message + * with the pending top-level await. + * An embedder may call this before exiting to improve error messages. + */ + std::vector, Local>> + GetStalledTopLevelAwaitMessage(Isolate* isolate); + V8_INLINE static Module* Cast(Data* data); private: @@ -489,7 +504,7 @@ class V8_EXPORT ScriptCompiler { /** * A task which the embedder must run on a background thread to * consume a V8 code cache. Returned by - * ScriptCompiler::StarConsumingCodeCache. + * ScriptCompiler::StartConsumingCodeCache. */ class V8_EXPORT ConsumeCodeCacheTask final { public: @@ -497,6 +512,36 @@ class V8_EXPORT ScriptCompiler { void Run(); + /** + * Provides the source text string and origin information to the consumption + * task. May be called before, during, or after Run(). This step checks + * whether the script matches an existing script in the Isolate's + * compilation cache. To check whether such a script was found, call + * ShouldMergeWithExistingScript. + * + * The Isolate provided must be the same one used during + * StartConsumingCodeCache and must be currently entered on the thread that + * calls this function. The source text and origin provided in this step + * must precisely match those used later in the ScriptCompiler::Source that + * will contain this ConsumeCodeCacheTask. + */ + void SourceTextAvailable(Isolate* isolate, Local source_text, + const ScriptOrigin& origin); + + /** + * Returns whether the embedder should call MergeWithExistingScript. This + * function may be called from any thread, any number of times, but its + * return value is only meaningful after SourceTextAvailable has completed. + */ + bool ShouldMergeWithExistingScript() const; + + /** + * Merges newly deserialized data into an existing script which was found + * during SourceTextAvailable. May be called only after Run() has completed. + * Can execute on any thread, like Run(). + */ + void MergeWithExistingScript(); + private: friend class ScriptCompiler; @@ -581,7 +626,8 @@ class V8_EXPORT ScriptCompiler { */ static ScriptStreamingTask* StartStreaming( Isolate* isolate, StreamedSource* source, - ScriptType type = ScriptType::kClassic); + ScriptType type = ScriptType::kClassic, + CompileOptions options = kNoCompileOptions); static ConsumeCodeCacheTask* StartConsumingCodeCache( Isolate* isolate, std::unique_ptr source); @@ -650,6 +696,7 @@ class V8_EXPORT ScriptCompiler { * It is possible to specify multiple context extensions (obj in the above * example). */ + V8_DEPRECATED("Use CompileFunction") static V8_WARN_UNUSED_RESULT MaybeLocal CompileFunctionInContext( Local context, Source* source, size_t arguments_count, Local arguments[], size_t context_extension_count, @@ -657,6 +704,7 @@ class V8_EXPORT ScriptCompiler { CompileOptions options = kNoCompileOptions, NoCacheReason no_cache_reason = kNoCacheNoReason, Local* script_or_module_out = nullptr); + static V8_WARN_UNUSED_RESULT MaybeLocal CompileFunction( Local context, Source* source, size_t arguments_count = 0, Local arguments[] = nullptr, size_t context_extension_count = 0, diff --git a/deps/v8/include/v8-template.h b/deps/v8/include/v8-template.h index 0afdccaafb68fe..669012a9814465 100644 --- a/deps/v8/include/v8-template.h +++ b/deps/v8/include/v8-template.h @@ -14,7 +14,6 @@ namespace v8 { -class AccessorSignature; class CFunction; class FunctionTemplate; class ObjectTemplate; @@ -83,28 +82,7 @@ class V8_EXPORT Template : public Data { * cross-context access. * \param attribute The attributes of the property for which an accessor * is added. - * \param signature The signature describes valid receivers for the accessor - * and is used to perform implicit instance checks against them. If the - * receiver is incompatible (i.e. is not an instance of the constructor as - * defined by FunctionTemplate::HasInstance()), an implicit TypeError is - * thrown and no callback is invoked. */ - V8_DEPRECATED("Do signature check in accessor") - void SetNativeDataProperty( - Local name, AccessorGetterCallback getter, - AccessorSetterCallback setter, Local data, - PropertyAttribute attribute, Local signature, - AccessControl settings = DEFAULT, - SideEffectType getter_side_effect_type = SideEffectType::kHasSideEffect, - SideEffectType setter_side_effect_type = SideEffectType::kHasSideEffect); - V8_DEPRECATED("Do signature check in accessor") - void SetNativeDataProperty( - Local name, AccessorNameGetterCallback getter, - AccessorNameSetterCallback setter, Local data, - PropertyAttribute attribute, Local signature, - AccessControl settings = DEFAULT, - SideEffectType getter_side_effect_type = SideEffectType::kHasSideEffect, - SideEffectType setter_side_effect_type = SideEffectType::kHasSideEffect); void SetNativeDataProperty( Local name, AccessorGetterCallback getter, AccessorSetterCallback setter = nullptr, @@ -151,7 +129,8 @@ class V8_EXPORT Template : public Data { * Interceptor for get requests on an object. * * Use `info.GetReturnValue().Set()` to set the return value of the - * intercepted get request. + * intercepted get request. If the property does not exist the callback should + * not set the result and must not produce side effects. * * \param property The name of the property for which the request was * intercepted. @@ -192,9 +171,9 @@ using GenericNamedPropertyGetterCallback = * Use `info.GetReturnValue()` to indicate whether the request was intercepted * or not. If the setter successfully intercepts the request, i.e., if the * request should not be further executed, call - * `info.GetReturnValue().Set(value)`. If the setter - * did not intercept the request, i.e., if the request should be handled as - * if no interceptor is present, do not not call `Set()`. + * `info.GetReturnValue().Set(value)`. If the setter did not intercept the + * request, i.e., if the request should be handled as if no interceptor is + * present, do not not call `Set()` and do not produce side effects. * * \param property The name of the property for which the request was * intercepted. @@ -217,7 +196,9 @@ using GenericNamedPropertySetterCallback = * defineProperty(). * * Use `info.GetReturnValue().Set(value)` to set the property attributes. The - * value is an integer encoding a `v8::PropertyAttribute`. + * value is an integer encoding a `v8::PropertyAttribute`. If the property does + * not exist the callback should not set the result and must not produce side + * effects. * * \param property The name of the property for which the request was * intercepted. @@ -242,7 +223,8 @@ using GenericNamedPropertyQueryCallback = * or not. If the deleter successfully intercepts the request, i.e., if the * request should not be further executed, call * `info.GetReturnValue().Set(value)` with a boolean `value`. The `value` is - * used as the return value of `delete`. + * used as the return value of `delete`. If the deleter does not intercept the + * request then it should not set the result and must not produce side effects. * * \param property The name of the property for which the request was * intercepted. @@ -274,9 +256,9 @@ using GenericNamedPropertyEnumeratorCallback = * Use `info.GetReturnValue()` to indicate whether the request was intercepted * or not. If the definer successfully intercepts the request, i.e., if the * request should not be further executed, call - * `info.GetReturnValue().Set(value)`. If the definer - * did not intercept the request, i.e., if the request should be handled as - * if no interceptor is present, do not not call `Set()`. + * `info.GetReturnValue().Set(value)`. If the definer did not intercept the + * request, i.e., if the request should be handled as if no interceptor is + * present, do not not call `Set()` and do not produce side effects. * * \param property The name of the property for which the request was * intercepted. @@ -821,27 +803,7 @@ class V8_EXPORT ObjectTemplate : public Template { * cross-context access. * \param attribute The attributes of the property for which an accessor * is added. - * \param signature The signature describes valid receivers for the accessor - * and is used to perform implicit instance checks against them. If the - * receiver is incompatible (i.e. is not an instance of the constructor as - * defined by FunctionTemplate::HasInstance()), an implicit TypeError is - * thrown and no callback is invoked. */ - V8_DEPRECATED("Do signature check in accessor") - void SetAccessor( - Local name, AccessorGetterCallback getter, - AccessorSetterCallback setter, Local data, AccessControl settings, - PropertyAttribute attribute, Local signature, - SideEffectType getter_side_effect_type = SideEffectType::kHasSideEffect, - SideEffectType setter_side_effect_type = SideEffectType::kHasSideEffect); - V8_DEPRECATED("Do signature check in accessor") - void SetAccessor( - Local name, AccessorNameGetterCallback getter, - AccessorNameSetterCallback setter, Local data, - AccessControl settings, PropertyAttribute attribute, - Local signature, - SideEffectType getter_side_effect_type = SideEffectType::kHasSideEffect, - SideEffectType setter_side_effect_type = SideEffectType::kHasSideEffect); void SetAccessor( Local name, AccessorGetterCallback getter, AccessorSetterCallback setter = nullptr, @@ -1019,24 +981,6 @@ class V8_EXPORT Signature : public Data { static void CheckCast(Data* that); }; -/** - * An AccessorSignature specifies which receivers are valid parameters - * to an accessor callback. - */ -class V8_EXPORT AccessorSignature : public Data { - public: - static Local New( - Isolate* isolate, - Local receiver = Local()); - - V8_INLINE static AccessorSignature* Cast(Data* data); - - private: - AccessorSignature(); - - static void CheckCast(Data* that); -}; - // --- Implementation --- void Template::Set(Isolate* isolate, const char* name, Local value, @@ -1067,13 +1011,6 @@ Signature* Signature::Cast(Data* data) { return reinterpret_cast(data); } -AccessorSignature* AccessorSignature::Cast(Data* data) { -#ifdef V8_ENABLE_CHECKS - CheckCast(data); -#endif - return reinterpret_cast(data); -} - } // namespace v8 #endif // INCLUDE_V8_TEMPLATE_H_ diff --git a/deps/v8/include/v8-unwinder-state.h b/deps/v8/include/v8-unwinder-state.h index a30f7325f48285..18bb410d2b163b 100644 --- a/deps/v8/include/v8-unwinder-state.h +++ b/deps/v8/include/v8-unwinder-state.h @@ -17,10 +17,10 @@ struct CalleeSavedRegisters { void* arm_r9; void* arm_r10; }; -#elif V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_ARM64 || \ - V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC || \ - V8_TARGET_ARCH_PPC64 || V8_TARGET_ARCH_RISCV64 || V8_TARGET_ARCH_S390 || \ - V8_TARGET_ARCH_LOONG64 +#elif V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_ARM64 || \ + V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_PPC64 || \ + V8_TARGET_ARCH_RISCV64 || V8_TARGET_ARCH_S390 || V8_TARGET_ARCH_LOONG64 || \ + V8_TARGET_ARCH_RISCV32 struct CalleeSavedRegisters {}; #else #error Target architecture was not detected as supported by v8 diff --git a/deps/v8/include/v8-util.h b/deps/v8/include/v8-util.h index c54418aa251534..159027d31786ff 100644 --- a/deps/v8/include/v8-util.h +++ b/deps/v8/include/v8-util.h @@ -537,7 +537,6 @@ class StdGlobalValueMap : public GlobalValueMap { : GlobalValueMap(isolate) {} }; - class DefaultPersistentValueVectorTraits { public: typedef std::vector Impl; @@ -562,7 +561,6 @@ class DefaultPersistentValueVectorTraits { } }; - /** * A vector wrapper that safely stores Global values. * C++11 embedders don't need this class, as they can use Global @@ -573,8 +571,8 @@ class DefaultPersistentValueVectorTraits { * PersistentContainerValue, with all conversion into and out of V8 * handles being transparently handled by this class. */ -template -class PersistentValueVector { +template +class V8_DEPRECATE_SOON("Use std::vector>.") PersistentValueVector { public: explicit PersistentValueVector(Isolate* isolate) : isolate_(isolate) { } diff --git a/deps/v8/include/v8-value-serializer.h b/deps/v8/include/v8-value-serializer.h index 078f367c646d06..729730c608dbe4 100644 --- a/deps/v8/include/v8-value-serializer.h +++ b/deps/v8/include/v8-value-serializer.h @@ -8,6 +8,7 @@ #include #include +#include #include #include "v8-local-handle.h" // NOLINT(build/include_directory) @@ -26,8 +27,37 @@ class Value; namespace internal { struct ScriptStreamingData; +class SharedObjectConveyorHandles; +class ValueDeserializer; +class ValueSerializer; } // namespace internal +/** + * A move-only class for managing the lifetime of shared value conveyors used + * by V8 to keep JS shared values alive in transit when serialized. + * + * This class is not directly constructible and is always passed to a + * ValueSerializer::Delegate via ValueSerializer::SetSharedValueConveyor. + * + * The embedder must not destruct the SharedValueConveyor until the associated + * serialized data will no longer be deserialized. + */ +class V8_EXPORT SharedValueConveyor final { + public: + SharedValueConveyor(SharedValueConveyor&&) noexcept; + ~SharedValueConveyor(); + + SharedValueConveyor& operator=(SharedValueConveyor&&) noexcept; + + private: + friend class internal::ValueSerializer; + friend class internal::ValueDeserializer; + + explicit SharedValueConveyor(Isolate* isolate); + + std::unique_ptr private_; +}; + /** * Value serialization compatible with the HTML structured clone algorithm. * The format is backward-compatible (i.e. safe to store to disk). @@ -69,20 +99,20 @@ class V8_EXPORT ValueSerializer { Isolate* isolate, Local module); /** - * Returns whether shared values are supported. GetSharedValueId is only - * called if SupportsSharedValues() returns true. - */ - virtual bool SupportsSharedValues() const; - - /** - * Called when the ValueSerializer serializes a value that is shared across - * Isolates. The embedder must return an ID for the object. This function - * must be idempotent for the same object. When deserializing, the ID will - * be passed to ValueDeserializer::Delegate::GetSharedValueFromId as - * |shared_value_id|. + * Called when the first shared value is serialized. All subsequent shared + * values will use the same conveyor. + * + * The embedder must ensure the lifetime of the conveyor matches the + * lifetime of the serialized data. + * + * If the embedder supports serializing shared values, this method should + * return true. Otherwise the embedder should throw an exception and return + * false. + * + * This method is called at most once per serializer. */ - virtual Maybe GetSharedValueId(Isolate* isolate, - Local shared_value); + virtual bool AdoptSharedValueConveyor(Isolate* isolate, + SharedValueConveyor&& conveyor); /** * Allocates memory for the buffer of at least the size provided. The actual @@ -196,17 +226,10 @@ class V8_EXPORT ValueDeserializer { Isolate* isolate, uint32_t clone_id); /** - * Returns whether shared values are supported. GetSharedValueFromId is only - * called if SupportsSharedValues() returns true. - */ - virtual bool SupportsSharedValues() const; - - /** - * Get a value shared across Isolates given a shared_value_id provided by - * ValueSerializer::Delegate::GetSharedValueId. + * Get the SharedValueConveyor previously provided by + * ValueSerializer::Delegate::AdoptSharedValueConveyor. */ - virtual MaybeLocal GetSharedValueFromId(Isolate* isolate, - uint32_t shared_value_id); + virtual const SharedValueConveyor* GetSharedValueConveyor(Isolate* isolate); }; ValueDeserializer(Isolate* isolate, const uint8_t* data, size_t size); diff --git a/deps/v8/include/v8-version.h b/deps/v8/include/v8-version.h index d2b7b508132e7e..4dd63447ed886e 100644 --- a/deps/v8/include/v8-version.h +++ b/deps/v8/include/v8-version.h @@ -9,9 +9,9 @@ // NOTE these macros are used by some of the tool scripts and the build // system so their names cannot be changed without changing the scripts. #define V8_MAJOR_VERSION 10 -#define V8_MINOR_VERSION 2 -#define V8_BUILD_NUMBER 154 -#define V8_PATCH_LEVEL 15 +#define V8_MINOR_VERSION 7 +#define V8_BUILD_NUMBER 193 +#define V8_PATCH_LEVEL 13 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.) diff --git a/deps/v8/include/v8-wasm.h b/deps/v8/include/v8-wasm.h index 59b2a69b1244ca..05acd2e86deff8 100644 --- a/deps/v8/include/v8-wasm.h +++ b/deps/v8/include/v8-wasm.h @@ -5,6 +5,7 @@ #ifndef INCLUDE_V8_WASM_H_ #define INCLUDE_V8_WASM_H_ +#include #include #include @@ -130,19 +131,6 @@ class V8_EXPORT WasmStreaming final { public: class WasmStreamingImpl; - /** - * Client to receive streaming event notifications. - */ - class Client { - public: - virtual ~Client() = default; - /** - * Passes the fully compiled module to the client. This can be used to - * implement code caching. - */ - virtual void OnModuleCompiled(CompiledWasmModule compiled_module) = 0; - }; - explicit WasmStreaming(std::unique_ptr impl); ~WasmStreaming(); @@ -183,10 +171,11 @@ class V8_EXPORT WasmStreaming final { bool SetCompiledModuleBytes(const uint8_t* bytes, size_t size); /** - * Sets the client object that will receive streaming event notifications. - * This must be called before {OnBytesReceived}, {Finish}, or {Abort}. + * Sets a callback which is called whenever a significant number of new + * functions are ready for serialization. */ - void SetClient(std::shared_ptr client); + void SetMoreFunctionsCanBeSerializedCallback( + std::function); /* * Sets the UTF-8 encoded source URL for the {Script} object. This must be @@ -206,52 +195,6 @@ class V8_EXPORT WasmStreaming final { std::unique_ptr impl_; }; -// TODO(mtrofin): when streaming compilation is done, we can rename this -// to simply WasmModuleObjectBuilder -class V8_EXPORT WasmModuleObjectBuilderStreaming final { - public: - explicit WasmModuleObjectBuilderStreaming(Isolate* isolate); - /** - * The buffer passed into OnBytesReceived is owned by the caller. - */ - void OnBytesReceived(const uint8_t*, size_t size); - void Finish(); - /** - * Abort streaming compilation. If {exception} has a value, then the promise - * associated with streaming compilation is rejected with that value. If - * {exception} does not have value, the promise does not get rejected. - */ - void Abort(MaybeLocal exception); - Local GetPromise(); - - ~WasmModuleObjectBuilderStreaming() = default; - - private: - WasmModuleObjectBuilderStreaming(const WasmModuleObjectBuilderStreaming&) = - delete; - WasmModuleObjectBuilderStreaming(WasmModuleObjectBuilderStreaming&&) = - default; - WasmModuleObjectBuilderStreaming& operator=( - const WasmModuleObjectBuilderStreaming&) = delete; - WasmModuleObjectBuilderStreaming& operator=( - WasmModuleObjectBuilderStreaming&&) = default; - Isolate* isolate_ = nullptr; - -#if V8_CC_MSVC - /** - * We don't need the static Copy API, so the default - * NonCopyablePersistentTraits would be sufficient, however, - * MSVC eagerly instantiates the Copy. - * We ensure we don't use Copy, however, by compiling with the - * defaults everywhere else. - */ - Persistent> promise_; -#else - Persistent promise_; -#endif - std::shared_ptr streaming_decoder_; -}; - } // namespace v8 #endif // INCLUDE_V8_WASM_H_ diff --git a/deps/v8/include/v8-weak-callback-info.h b/deps/v8/include/v8-weak-callback-info.h index 6d0fb3ac1d40f8..df4dcb8eb9644c 100644 --- a/deps/v8/include/v8-weak-callback-info.h +++ b/deps/v8/include/v8-weak-callback-info.h @@ -63,13 +63,6 @@ enum class WeakCallbackType { * Passes the first two internal fields of the object back to the callback. */ kInternalFields, - /** - * Passes a user-defined void* parameter back to the callback. Will do so - * before the object is actually reclaimed, allowing it to be resurrected. In - * this case it is not possible to set a second-pass callback. - */ - kFinalizer V8_ENUM_DEPRECATED("Resurrecting finalizers are deprecated " - "and will not be supported going forward.") }; template diff --git a/deps/v8/include/v8config.h b/deps/v8/include/v8config.h index 77fd65c6c5b7d8..6753eb083b3c1c 100644 --- a/deps/v8/include/v8config.h +++ b/deps/v8/include/v8config.h @@ -308,6 +308,7 @@ path. Add it with -I to the command line // V8_HAS_BUILTIN_SADD_OVERFLOW - __builtin_sadd_overflow() supported // V8_HAS_BUILTIN_SSUB_OVERFLOW - __builtin_ssub_overflow() supported // V8_HAS_BUILTIN_UADD_OVERFLOW - __builtin_uadd_overflow() supported +// V8_HAS_BUILTIN_SMUL_OVERFLOW - __builtin_smul_overflow() supported // V8_HAS_COMPUTED_GOTO - computed goto/labels as values // supported // V8_HAS_DECLSPEC_NOINLINE - __declspec(noinline) supported @@ -344,6 +345,7 @@ path. Add it with -I to the command line # define V8_HAS_CPP_ATTRIBUTE_NO_UNIQUE_ADDRESS \ (V8_HAS_CPP_ATTRIBUTE(no_unique_address)) +# define V8_HAS_BUILTIN_ASSUME (__has_builtin(__builtin_assume)) # define V8_HAS_BUILTIN_ASSUME_ALIGNED (__has_builtin(__builtin_assume_aligned)) # define V8_HAS_BUILTIN_BSWAP16 (__has_builtin(__builtin_bswap16)) # define V8_HAS_BUILTIN_BSWAP32 (__has_builtin(__builtin_bswap32)) @@ -356,6 +358,8 @@ path. Add it with -I to the command line # define V8_HAS_BUILTIN_SADD_OVERFLOW (__has_builtin(__builtin_sadd_overflow)) # define V8_HAS_BUILTIN_SSUB_OVERFLOW (__has_builtin(__builtin_ssub_overflow)) # define V8_HAS_BUILTIN_UADD_OVERFLOW (__has_builtin(__builtin_uadd_overflow)) +# define V8_HAS_BUILTIN_SMUL_OVERFLOW (__has_builtin(__builtin_smul_overflow)) +# define V8_HAS_BUILTIN_UNREACHABLE (__has_builtin(__builtin_unreachable)) // Clang has no __has_feature for computed gotos. // GCC doc: https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html @@ -394,6 +398,7 @@ path. Add it with -I to the command line # define V8_HAS_BUILTIN_EXPECT 1 # define V8_HAS_BUILTIN_FRAME_ADDRESS 1 # define V8_HAS_BUILTIN_POPCOUNT 1 +# define V8_HAS_BUILTIN_UNREACHABLE 1 // GCC doc: https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html #define V8_HAS_COMPUTED_GOTO 1 @@ -425,6 +430,18 @@ path. Add it with -I to the command line # define V8_INLINE inline #endif +#ifdef DEBUG +// In debug mode, check assumptions instead of actually adding annotations. +# define V8_ASSUME(condition) DCHECK(condition) +#elif V8_HAS_BUILTIN_ASSUME +# define V8_ASSUME(condition) __builtin_assume(condition) +#elif V8_HAS_BUILTIN_UNREACHABLE +# define V8_ASSUME(condition) \ + do { if (!(condition)) __builtin_unreachable(); } while (false) +#else +# define V8_ASSUME(condition) +#endif + #if V8_HAS_BUILTIN_ASSUME_ALIGNED # define V8_ASSUME_ALIGNED(ptr, alignment) \ __builtin_assume_aligned((ptr), (alignment)) @@ -471,6 +488,34 @@ path. Add it with -I to the command line #endif +#if defined(V8_IMMINENT_DEPRECATION_WARNINGS) || \ + defined(V8_DEPRECATION_WARNINGS) +#if defined(V8_CC_MSVC) +# define START_ALLOW_USE_DEPRECATED() \ + __pragma(warning(push)) \ + __pragma(warning(disable : 4996)) +# define END_ALLOW_USE_DEPRECATED() __pragma(warning(pop)) +#else // !defined(V8_CC_MSVC) +# define START_ALLOW_USE_DEPRECATED() \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#define END_ALLOW_USE_DEPRECATED() _Pragma("GCC diagnostic pop") +#endif // !defined(V8_CC_MSVC) +#else // !(defined(V8_IMMINENT_DEPRECATION_WARNINGS) || + // defined(V8_DEPRECATION_WARNINGS)) +#define START_ALLOW_USE_DEPRECATED() +#define END_ALLOW_USE_DEPRECATED() +#endif // !(defined(V8_IMMINENT_DEPRECATION_WARNINGS) || + // defined(V8_DEPRECATION_WARNINGS)) +#define ALLOW_COPY_AND_MOVE_WITH_DEPRECATED_FIELDS(ClassName) \ + START_ALLOW_USE_DEPRECATED() \ + ClassName(const ClassName&) = default; \ + ClassName(ClassName&&) = default; \ + ClassName& operator=(const ClassName&) = default; \ + ClassName& operator=(ClassName&&) = default; \ + END_ALLOW_USE_DEPRECATED() + + #if defined(__GNUC__) && !defined(__clang__) && (__GNUC__ < 6) # define V8_ENUM_DEPRECATED(message) # define V8_ENUM_DEPRECATE_SOON(message) @@ -580,25 +625,214 @@ V8 shared library set USING_V8_SHARED. #endif // V8_OS_WIN -// The sandbox is available (i.e. defined) when pointer compression -// is enabled, but it is only used when V8_SANDBOX is enabled as -// well. This allows better test coverage of the sandbox. -#if defined(V8_COMPRESS_POINTERS) -#define V8_SANDBOX_IS_AVAILABLE +// clang-format on + +// Processor architecture detection. For more info on what's defined, see: +// http://msdn.microsoft.com/en-us/library/b0084kay.aspx +// http://www.agner.org/optimize/calling_conventions.pdf +// or with gcc, run: "echo | gcc -E -dM -" +// The V8_HOST_ARCH_* macros correspond to the architecture on which V8, as a +// virtual machine and compiler, runs. Don't confuse this with the architecture +// on which V8 is built. +#if defined(_M_X64) || defined(__x86_64__) +#define V8_HOST_ARCH_X64 1 +#if defined(__x86_64__) && __SIZEOF_POINTER__ == 4 // Check for x32. +#define V8_HOST_ARCH_32_BIT 1 +#else +#define V8_HOST_ARCH_64_BIT 1 +#endif +#elif defined(_M_IX86) || defined(__i386__) +#define V8_HOST_ARCH_IA32 1 +#define V8_HOST_ARCH_32_BIT 1 +#elif defined(__AARCH64EL__) || defined(_M_ARM64) +#define V8_HOST_ARCH_ARM64 1 +#define V8_HOST_ARCH_64_BIT 1 +#elif defined(__ARMEL__) +#define V8_HOST_ARCH_ARM 1 +#define V8_HOST_ARCH_32_BIT 1 +#elif defined(__mips64) +#define V8_HOST_ARCH_MIPS64 1 +#define V8_HOST_ARCH_64_BIT 1 +#elif defined(__loongarch64) +#define V8_HOST_ARCH_LOONG64 1 +#define V8_HOST_ARCH_64_BIT 1 +#elif defined(__PPC64__) || defined(_ARCH_PPC64) +#define V8_HOST_ARCH_PPC64 1 +#define V8_HOST_ARCH_64_BIT 1 +#elif defined(__PPC__) || defined(_ARCH_PPC) +#define V8_HOST_ARCH_PPC 1 +#define V8_HOST_ARCH_32_BIT 1 +#elif defined(__s390__) || defined(__s390x__) +#define V8_HOST_ARCH_S390 1 +#if defined(__s390x__) +#define V8_HOST_ARCH_64_BIT 1 +#else +#define V8_HOST_ARCH_32_BIT 1 +#endif +#elif defined(__riscv) || defined(__riscv__) +#if __riscv_xlen == 64 +#define V8_HOST_ARCH_RISCV64 1 +#define V8_HOST_ARCH_64_BIT 1 +#elif __riscv_xlen == 32 +#define V8_HOST_ARCH_RISCV32 1 +#define V8_HOST_ARCH_32_BIT 1 +#else +#error "Cannot detect Riscv's bitwidth" +#endif +#else +#error "Host architecture was not detected as supported by v8" +#endif + +// Target architecture detection. This corresponds to the architecture for which +// V8's JIT will generate code (the last stage of the canadian cross-compiler). +// The macros may be set externally. If not, detect in the same way as the host +// architecture, that is, target the native environment as presented by the +// compiler. +#if !V8_TARGET_ARCH_X64 && !V8_TARGET_ARCH_IA32 && !V8_TARGET_ARCH_ARM && \ + !V8_TARGET_ARCH_ARM64 && !V8_TARGET_ARCH_MIPS64 && !V8_TARGET_ARCH_PPC && \ + !V8_TARGET_ARCH_PPC64 && !V8_TARGET_ARCH_S390 && \ + !V8_TARGET_ARCH_RISCV64 && !V8_TARGET_ARCH_LOONG64 && \ + !V8_TARGET_ARCH_RISCV32 +#if defined(_M_X64) || defined(__x86_64__) +#define V8_TARGET_ARCH_X64 1 +#elif defined(_M_IX86) || defined(__i386__) +#define V8_TARGET_ARCH_IA32 1 +#elif defined(__AARCH64EL__) || defined(_M_ARM64) +#define V8_TARGET_ARCH_ARM64 1 +#elif defined(__ARMEL__) +#define V8_TARGET_ARCH_ARM 1 +#elif defined(__mips64) +#define V8_TARGET_ARCH_MIPS64 1 +#elif defined(_ARCH_PPC64) +#define V8_TARGET_ARCH_PPC64 1 +#elif defined(_ARCH_PPC) +#define V8_TARGET_ARCH_PPC 1 +#elif defined(__s390__) +#define V8_TARGET_ARCH_S390 1 +#if defined(__s390x__) +#define V8_TARGET_ARCH_S390X 1 +#endif +#elif defined(__riscv) || defined(__riscv__) +#if __riscv_xlen == 64 +#define V8_TARGET_ARCH_RISCV64 1 +#elif __riscv_xlen == 32 +#define V8_TARGET_ARCH_RISCV32 1 +#endif +#else +#error Target architecture was not detected as supported by v8 +#endif #endif -#if defined(V8_SANDBOX) && !defined(V8_SANDBOX_IS_AVAILABLE) -#error Inconsistent configuration: sandbox is enabled but not available +// Determine architecture pointer size. +#if V8_TARGET_ARCH_IA32 +#define V8_TARGET_ARCH_32_BIT 1 +#elif V8_TARGET_ARCH_X64 +#if !V8_TARGET_ARCH_32_BIT && !V8_TARGET_ARCH_64_BIT +#if defined(__x86_64__) && __SIZEOF_POINTER__ == 4 // Check for x32. +#define V8_TARGET_ARCH_32_BIT 1 +#else +#define V8_TARGET_ARCH_64_BIT 1 +#endif +#endif +#elif V8_TARGET_ARCH_ARM +#define V8_TARGET_ARCH_32_BIT 1 +#elif V8_TARGET_ARCH_ARM64 +#define V8_TARGET_ARCH_64_BIT 1 +#elif V8_TARGET_ARCH_MIPS +#define V8_TARGET_ARCH_32_BIT 1 +#elif V8_TARGET_ARCH_MIPS64 +#define V8_TARGET_ARCH_64_BIT 1 +#elif V8_TARGET_ARCH_LOONG64 +#define V8_TARGET_ARCH_64_BIT 1 +#elif V8_TARGET_ARCH_PPC +#define V8_TARGET_ARCH_32_BIT 1 +#elif V8_TARGET_ARCH_PPC64 +#define V8_TARGET_ARCH_64_BIT 1 +#elif V8_TARGET_ARCH_S390 +#if V8_TARGET_ARCH_S390X +#define V8_TARGET_ARCH_64_BIT 1 +#else +#define V8_TARGET_ARCH_32_BIT 1 +#endif +#elif V8_TARGET_ARCH_RISCV64 +#define V8_TARGET_ARCH_64_BIT 1 +#elif V8_TARGET_ARCH_RISCV32 +#define V8_TARGET_ARCH_32_BIT 1 +#else +#error Unknown target architecture pointer size #endif -// From C++17 onwards, static constexpr member variables are defined to be -// "inline", and adding a separate definition for them can trigger deprecation -// warnings. For C++14 and below, however, these definitions are required. -#if __cplusplus < 201703L && (!defined(_MSVC_LANG) || _MSVC_LANG < 201703L) -#define V8_STATIC_CONSTEXPR_VARIABLES_NEED_DEFINITIONS +// Check for supported combinations of host and target architectures. +#if V8_TARGET_ARCH_IA32 && !V8_HOST_ARCH_IA32 +#error Target architecture ia32 is only supported on ia32 host +#endif +#if (V8_TARGET_ARCH_X64 && V8_TARGET_ARCH_64_BIT && \ + !((V8_HOST_ARCH_X64 || V8_HOST_ARCH_ARM64) && V8_HOST_ARCH_64_BIT)) +#error Target architecture x64 is only supported on x64 and arm64 host +#endif +#if (V8_TARGET_ARCH_X64 && V8_TARGET_ARCH_32_BIT && \ + !(V8_HOST_ARCH_X64 && V8_HOST_ARCH_32_BIT)) +#error Target architecture x32 is only supported on x64 host with x32 support +#endif +#if (V8_TARGET_ARCH_ARM && !(V8_HOST_ARCH_IA32 || V8_HOST_ARCH_ARM)) +#error Target architecture arm is only supported on arm and ia32 host +#endif +#if (V8_TARGET_ARCH_ARM64 && !(V8_HOST_ARCH_X64 || V8_HOST_ARCH_ARM64)) +#error Target architecture arm64 is only supported on arm64 and x64 host +#endif +#if (V8_TARGET_ARCH_MIPS64 && !(V8_HOST_ARCH_X64 || V8_HOST_ARCH_MIPS64)) +#error Target architecture mips64 is only supported on mips64 and x64 host +#endif +#if (V8_TARGET_ARCH_RISCV64 && !(V8_HOST_ARCH_X64 || V8_HOST_ARCH_RISCV64)) +#error Target architecture riscv64 is only supported on riscv64 and x64 host +#endif +#if (V8_TARGET_ARCH_RISCV32 && !(V8_HOST_ARCH_IA32 || V8_HOST_ARCH_RISCV32)) +#error Target architecture riscv32 is only supported on riscv32 and ia32 host +#endif +#if (V8_TARGET_ARCH_LOONG64 && !(V8_HOST_ARCH_X64 || V8_HOST_ARCH_LOONG64)) +#error Target architecture loong64 is only supported on loong64 and x64 host #endif -// clang-format on +// Determine architecture endianness. +#if V8_TARGET_ARCH_IA32 +#define V8_TARGET_LITTLE_ENDIAN 1 +#elif V8_TARGET_ARCH_X64 +#define V8_TARGET_LITTLE_ENDIAN 1 +#elif V8_TARGET_ARCH_ARM +#define V8_TARGET_LITTLE_ENDIAN 1 +#elif V8_TARGET_ARCH_ARM64 +#define V8_TARGET_LITTLE_ENDIAN 1 +#elif V8_TARGET_ARCH_LOONG64 +#define V8_TARGET_LITTLE_ENDIAN 1 +#elif V8_TARGET_ARCH_MIPS64 +#if defined(__MIPSEB__) || defined(V8_TARGET_ARCH_MIPS64_BE) +#define V8_TARGET_BIG_ENDIAN 1 +#else +#define V8_TARGET_LITTLE_ENDIAN 1 +#endif +#elif defined(__BIG_ENDIAN__) // FOR PPCGR on AIX +#define V8_TARGET_BIG_ENDIAN 1 +#elif V8_TARGET_ARCH_PPC_LE +#define V8_TARGET_LITTLE_ENDIAN 1 +#elif V8_TARGET_ARCH_PPC_BE +#define V8_TARGET_BIG_ENDIAN 1 +#elif V8_TARGET_ARCH_S390 +#if V8_TARGET_ARCH_S390_LE_SIM +#define V8_TARGET_LITTLE_ENDIAN 1 +#else +#define V8_TARGET_BIG_ENDIAN 1 +#endif +#elif V8_TARGET_ARCH_RISCV32 || V8_TARGET_ARCH_RISCV64 +#define V8_TARGET_LITTLE_ENDIAN 1 +#elif defined(__BYTE_ORDER__) +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define V8_TARGET_BIG_ENDIAN 1 +#else +#define V8_TARGET_LITTLE_ENDIAN 1 +#endif +#else +#error Unknown target architecture endianness +#endif #undef V8_HAS_CPP_ATTRIBUTE diff --git a/deps/v8/infra/mb/PRESUBMIT.py b/deps/v8/infra/mb/PRESUBMIT.py index 85e257c2d4cd1c..0896d46b372e8a 100644 --- a/deps/v8/infra/mb/PRESUBMIT.py +++ b/deps/v8/infra/mb/PRESUBMIT.py @@ -20,7 +20,7 @@ def _CommonChecks(input_api, output_api): '..', 'tools', 'mb', 'mb.py') mb_config_path = input_api.os_path.join(input_api.PresubmitLocalPath(), 'mb_config.pyl') - cmd = [input_api.python_executable, mb_script, 'validate', '--config-file', + cmd = [input_api.python3_executable, mb_script, 'validate', '--config-file', mb_config_path] kwargs = {'cwd': input_api.PresubmitLocalPath()} results.extend(input_api.RunTests([ diff --git a/deps/v8/infra/mb/gn_isolate_map.pyl b/deps/v8/infra/mb/gn_isolate_map.pyl index a5031f1a203a43..5732d862189c1a 100644 --- a/deps/v8/infra/mb/gn_isolate_map.pyl +++ b/deps/v8/infra/mb/gn_isolate_map.pyl @@ -32,7 +32,7 @@ "type": "script", }, "generate-bytecode-expectations": { - "label": "//test/cctest:generate-bytecode-expectations", + "label": "//test/unittests:generate-bytecode-expectations", "type": "script", }, "mjsunit": { diff --git a/deps/v8/infra/mb/mb_config.pyl b/deps/v8/infra/mb/mb_config.pyl index 769582188a11d5..5488996a641ae4 100644 --- a/deps/v8/infra/mb/mb_config.pyl +++ b/deps/v8/infra/mb/mb_config.pyl @@ -22,9 +22,6 @@ 'ia32.debug': 'default_debug_x86', 'ia32.optdebug': 'default_optdebug_x86', 'ia32.release': 'default_release_x86', - 'mipsel.debug': 'default_debug_mipsel', - 'mipsel.optdebug': 'default_optdebug_mipsel', - 'mipsel.release': 'default_release_mipsel', 'mips64el.debug': 'default_debug_mips64el', 'mips64el.optdebug': 'default_optdebug_mips64el', 'mips64el.release': 'default_release_mips64el', @@ -67,33 +64,38 @@ 'V8 Linux64 - builder (reclient)': 'release_x64_reclient', 'V8 Linux64 - builder (reclient compare)': 'release_x64_reclient', 'V8 Linux64 - debug builder': 'debug_x64', - 'V8 Linux64 - dict tracking - debug - builder': 'debug_x64_dict_tracking_trybot', 'V8 Linux64 - external code space - debug - builder': 'debug_x64_external_code_space', 'V8 Linux64 - custom snapshot - debug builder': 'debug_x64_custom', 'V8 Linux64 - heap sandbox - debug - builder': 'debug_x64_heap_sandbox', 'V8 Linux64 - internal snapshot - builder': 'release_x64_internal', 'V8 Linux64 - debug - header includes - builder': 'debug_x64_header_includes', + 'V8 Linux64 - no sandbox - debug builder': 'debug_x64_no_sandbox', + 'V8 Linux64 - no sandbox - builder': 'release_x64_no_sandbox', 'V8 Linux64 - shared - builder': 'release_x64_shared_verify_heap', 'V8 Linux64 - verify csa - builder': 'release_x64_verify_csa', 'V8 Linux64 - no wasm - builder': 'release_x64_webassembly_disabled', # Windows. 'V8 Win32 - builder': 'release_x86_minimal_symbols', - 'V8 Win32 - builder (goma cache silo)': 'release_x64', + 'V8 Win32 - builder (goma cache silo)': 'release_x86', 'V8 Win32 - builder (reclient)': 'release_x86_minimal_symbols_reclient', 'V8 Win32 - builder (reclient compare)': 'release_x86_minimal_symbols_reclient', 'V8 Win32 - debug builder': 'debug_x86_minimal_symbols', # TODO(machenbach): Remove after switching to x64 on infra side. 'V8 Win64 ASAN - builder': 'release_x64_asan_no_lsan', 'V8 Win64 - builder': 'release_x64_minimal_symbols', + 'V8 Win64 - builder (reclient)': 'release_x64_minimal_symbols_reclient', + 'V8 Win64 - builder (reclient compare)': 'release_x64_minimal_symbols_reclient', 'V8 Win64 - dev image': 'release_x64_minimal_symbols', 'V8 Win64 - debug builder': 'debug_x64_minimal_symbols', 'V8 Win64 - msvc - builder': 'release_x64_msvc', # Mac. 'V8 Mac64 - builder': 'release_x64', 'V8 Mac64 - debug builder': 'debug_x64', + 'V8 Mac64 - builder (reclient)': 'release_x64_reclient', 'V8 Official Mac ARM64': 'release_arm64', 'V8 Official Mac ARM64 Debug': 'debug_arm64', 'V8 Mac64 ASAN - builder': 'release_x64_asan_no_lsan', + 'V8 Mac - arm64 - no pointer compression debug builder': 'debug_arm64_no_pointer_compression', 'V8 Mac - arm64 - release builder': 'release_arm64', 'V8 Mac - arm64 - debug builder': 'debug_arm64', 'V8 Mac - arm64 - sim - debug builder': 'debug_simulate_arm64', @@ -104,21 +106,19 @@ 'V8 Linux64 TSAN - no-concurrent-marking - builder': 'release_x64_tsan_no_cm', 'V8 Linux - arm64 - sim - CFI - builder': 'release_simulate_arm64_cfi', 'V8 Linux - arm64 - sim - MSAN - builder': 'release_simulate_arm64_msan', - # Misc. - 'V8 Linux gcc - builder': 'release_x86_gcc', # FYI. 'V8 iOS - sim - builder': 'release_x64_ios_simulator', 'V8 Linux64 - arm64 - sim - heap sandbox - debug - builder': 'debug_x64_heap_sandbox_arm64_sim', + 'V8 Linux64 - arm64 - sim - no pointer compression - builder': + 'release_simulate_arm64_no_pointer_compression', 'V8 Linux64 - cppgc-non-default - debug - builder': 'debug_x64_non_default_cppgc', 'V8 Linux64 - debug - perfetto - builder': 'debug_x64_perfetto', 'V8 Linux64 - disable runtime call stats - builder': 'release_x64_disable_runtime_call_stats', 'V8 Linux64 - debug - single generation - builder': 'debug_x64_single_generation', - 'V8 Linux64 - pointer compression - builder': 'release_x64_pointer_compression', - 'V8 Linux64 - pointer compression without dchecks': - 'release_x64_pointer_compression_without_dchecks', - 'V8 Linux64 - arm64 - sim - pointer compression - builder': - 'release_simulate_arm64_pointer_compression', + 'V8 Linux64 - no pointer compression - builder': 'release_x64_no_pointer_compression', + 'V8 Linux64 gcc - builder': 'release_x64_gcc', 'V8 Linux64 gcc - debug builder': 'debug_x64_gcc', + 'V8 Linux64 gcc light - debug builder': 'debug_x64_gcc', 'V8 Fuchsia - builder': 'release_x64_fuchsia', 'V8 Fuchsia - debug builder': 'debug_x64_fuchsia', 'V8 Linux64 - cfi - builder': 'release_x64_cfi', @@ -126,7 +126,7 @@ 'V8 Linux - vtunejit': 'debug_x86_vtunejit', 'V8 Linux64 - gcov coverage': 'release_x64_gcc_coverage', 'V8 Linux64 - Fuzzilli - builder': 'release_x64_fuzzilli', - 'V8 Linux - predictable - builder': 'release_x86_predictable', + 'V8 Linux64 - predictable - builder': 'release_x64_predictable', 'V8 Linux - full debug builder': 'full_debug_x86', 'V8 Mac64 - full debug builder': 'full_debug_x64', 'V8 Random Deopt Fuzzer - debug': 'debug_x64', @@ -166,6 +166,8 @@ 'V8 Clusterfuzz Linux64 TSAN - release builder': 'release_x64_tsan', 'V8 Clusterfuzz Linux64 UBSan - release builder': 'release_x64_ubsan_recover', + 'V8 Clusterfuzz Linux64 ASAN sandbox testing - release builder': + 'release_x64_asan_sandbox_testing', }, 'client.v8.perf' : { 'V8 Arm - builder - perf': 'official_arm', @@ -173,6 +175,7 @@ 'V8 Android Arm64 - builder - perf': 'official_android_arm64', 'V8 Linux - builder - perf': 'official_x86', 'V8 Linux64 - builder - perf': 'official_x64', + 'V8 Mac Arm64 - builder - perf': 'official_mac_arm64', }, 'client.v8.ports': { # Arm. @@ -191,12 +194,12 @@ 'V8 Linux - arm64 - sim - debug builder': 'debug_simulate_arm64', 'V8 Linux - arm64 - sim - gc stress - builder': 'debug_simulate_arm64', # Mips. - 'V8 Linux - mipsel - sim - builder': 'release_simulate_mipsel', 'V8 Linux - mips64el - sim - builder': 'release_simulate_mips64el', # IBM. 'V8 Linux - ppc64 - sim - builder': 'release_simulate_ppc64', 'V8 Linux - s390x - sim - builder': 'release_simulate_s390x', # RISC-V + 'V8 Linux - riscv32 - sim - builder': 'release_simulate_riscv32', 'V8 Linux - riscv64 - sim - builder': 'release_simulate_riscv64', # Loongson 'V8 Linux - loong64 - sim - builder': 'release_simulate_loong64', @@ -216,28 +219,34 @@ 'v8_linux_noi18n_compile_dbg': 'debug_x86_no_i18n', 'v8_linux_noi18n_rel_ng': 'release_x86_no_i18n_trybot', 'v8_linux_gc_stress_dbg_ng': 'debug_x86_trybot', - 'v8_linux_gcc_compile_rel': 'release_x86_gcc_minimal_symbols', - 'v8_linux_gcc_rel_ng': 'release_x86_gcc_minimal_symbols', 'v8_linux_shared_compile_rel': 'release_x86_shared_verify_heap', 'v8_linux_vtunejit': 'debug_x86_vtunejit', - 'v8_linux64_arm64_pointer_compression_rel_ng': - 'release_simulate_arm64_pointer_compression', + 'v8_linux64_arm64_no_pointer_compression_rel_ng': + 'release_simulate_arm64_no_pointer_compression', 'v8_linux64_cppgc_non_default_dbg_ng': 'debug_x64_non_default_cppgc', 'v8_linux64_dbg_ng': 'debug_x64_trybot', + 'v8_linux64_no_sandbox_dbg_ng': 'debug_x64_no_sandbox', 'v8_linux64_dict_tracking_dbg_ng': 'debug_x64_dict_tracking_trybot', 'v8_linux64_disable_runtime_call_stats_rel_ng': 'release_x64_disable_runtime_call_stats', 'v8_linux64_external_code_space_dbg_ng': 'debug_x64_external_code_space', 'v8_linux64_gc_stress_custom_snapshot_dbg_ng': 'debug_x64_trybot_custom', + 'v8_linux64_gc_stress_dbg_ng': 'debug_x64_trybot', 'v8_linux64_gcc_compile_dbg': 'debug_x64_gcc', + 'v8_linux64_gcc_compile_rel': 'release_x64_gcc', + 'v8_linux64_gcc_light_compile_dbg': 'debug_x64_gcc', + 'v8_linux64_gcc_rel_ng': 'release_x64_gcc', 'v8_linux64_gcov_coverage': 'release_x64_gcc_coverage', 'v8_linux64_header_includes_dbg': 'debug_x64_header_includes', 'v8_linux64_heap_sandbox_dbg_ng': 'debug_x64_heap_sandbox', + 'v8_linux64_minor_mc_dbg_ng': 'debug_x64_trybot', 'v8_linux_arm64_sim_heap_sandbox_dbg_ng': 'debug_x64_heap_sandbox_arm64_sim', 'v8_linux64_fyi_rel_ng': 'release_x64_test_features_trybot', 'v8_linux64_nodcheck_rel_ng': 'release_x64', 'v8_linux64_perfetto_dbg_ng': 'debug_x64_perfetto', - 'v8_linux64_pointer_compression_rel_ng': 'release_x64_pointer_compression', + 'v8_linux64_no_pointer_compression_rel_ng': 'release_x64_no_pointer_compression', 'v8_linux64_rel_ng': 'release_x64_test_features_trybot', + 'v8_linux64_no_sandbox_rel_ng': 'release_x64_no_sandbox', + 'v8_linux64_predictable_rel_ng': 'release_x64_predictable', 'v8_linux64_shared_compile_rel': 'release_x64_shared_verify_heap', 'v8_linux64_single_generation_dbg_ng': 'debug_x64_single_generation', 'v8_linux64_no_wasm_compile_rel': 'release_x64_webassembly_disabled', @@ -247,6 +256,7 @@ 'v8_linux64_fuzzilli_ng': 'release_x64_fuzzilli', 'v8_linux64_loong64_rel_ng': 'release_simulate_loong64', 'v8_linux64_msan_rel_ng': 'release_simulate_arm64_msan_minimal_symbols', + 'v8_linux_riscv32_rel_ng': 'release_simulate_riscv32', 'v8_linux64_riscv64_rel_ng': 'release_simulate_riscv64', 'v8_linux64_tsan_rel_ng': 'release_x64_tsan_minimal_symbols', 'v8_linux64_tsan_no_cm_rel_ng': 'release_x64_tsan_no_cm', @@ -267,6 +277,7 @@ 'v8_mac_arm64_rel_ng': 'release_arm64', 'v8_mac_arm64_dbg_ng': 'debug_arm64', 'v8_mac_arm64_full_dbg_ng': 'full_debug_arm64', + 'v8_mac_arm64_no_pointer_compression_dbg_ng': 'debug_arm64_no_pointer_compression', 'v8_mac_arm64_compile_dbg': 'debug_arm64', 'v8_mac_arm64_compile_rel': 'release_arm64', 'v8_mac_arm64_sim_compile_dbg': 'debug_simulate_arm64', @@ -279,7 +290,7 @@ 'v8_mac64_dbg': 'debug_x64', 'v8_mac64_dbg_ng': 'debug_x64', 'v8_mac64_compile_full_dbg_ng': 'full_debug_x64', - 'v8_mac64_asan_compile_rel_ng': 'release_x64_asan_no_lsan', + 'v8_mac64_asan_compile_rel': 'release_x64_asan_no_lsan', 'v8_mac64_asan_rel_ng': 'release_x64_asan_no_lsan', 'v8_linux_arm_rel_ng': 'release_simulate_arm_trybot', 'v8_linux_arm_lite_compile_dbg': 'debug_simulate_arm_lite', @@ -291,7 +302,6 @@ 'v8_linux_arm64_cfi_rel_ng' : 'release_simulate_arm64_cfi', 'v8_linux_arm64_dbg_ng': 'debug_simulate_arm64', 'v8_linux_arm64_gc_stress_dbg_ng': 'debug_simulate_arm64', - 'v8_linux_mipsel_compile_rel': 'release_simulate_mipsel', 'v8_linux_mips64el_compile_rel': 'release_simulate_mips64el', 'v8_numfuzz_ng': 'release_x64', 'v8_numfuzz_dbg_ng': 'debug_x64', @@ -324,12 +334,6 @@ 'release', 'simulate_arm64'], 'release_arm64_sample': [ 'release', 'arm64', 'sample'], - 'default_debug_mipsel': [ - 'debug', 'simulate_mipsel', 'v8_enable_slow_dchecks', 'v8_full_debug'], - 'default_optdebug_mipsel': [ - 'debug', 'simulate_mipsel', 'v8_enable_slow_dchecks'], - 'default_release_mipsel': [ - 'release', 'simulate_mipsel'], 'default_debug_mips64el': [ 'debug', 'simulate_mips64el', 'v8_enable_slow_dchecks', 'v8_full_debug'], 'default_optdebug_mips64el': [ @@ -413,11 +417,8 @@ 'release_bot', 'simulate_arm64'], 'release_simulate_arm64_cfi': [ 'release_bot', 'simulate_arm64', 'v8_control_flow_integrity'], - 'release_simulate_arm64_pointer_compression': [ - # TODO(v8:v7703): Make pointer compression bots testing non pointer - # compression mode while pointer compression is temporarily enabled - # on arm64 - 'release_bot', 'simulate_arm64', 'dcheck_always_on', + 'release_simulate_arm64_no_pointer_compression': [ + 'release_bot', 'simulate_arm64_no_sandbox', 'dcheck_always_on', 'v8_enable_slow_dchecks', 'v8_disable_pointer_compression'], 'release_simulate_arm64_msan': [ 'release_bot', 'simulate_arm64', 'msan'], @@ -431,12 +432,12 @@ 'release_trybot', 'simulate_arm64'], 'release_simulate_loong64': [ 'release_bot', 'simulate_loong64'], - 'release_simulate_mipsel': [ - 'release_bot', 'simulate_mipsel'], 'release_simulate_mips64el': [ 'release_bot', 'simulate_mips64el'], 'release_simulate_ppc64': [ 'release_bot', 'simulate_ppc64'], + 'release_simulate_riscv32': [ + 'release_bot', 'simulate_riscv32'], 'release_simulate_riscv64': [ 'release_bot', 'simulate_riscv64'], 'release_simulate_s390x': [ @@ -449,6 +450,9 @@ 'debug_bot', 'arm', 'hard_float'], 'debug_arm64': [ 'debug_bot', 'arm64'], + 'debug_arm64_no_pointer_compression': [ + 'debug_bot', 'arm64_no_sandbox', 'dcheck_always_on', 'v8_enable_slow_dchecks', 'v8_enable_javascript_promise_hooks', + 'v8_disable_pointer_compression'], 'full_debug_arm64': [ 'debug_bot', 'arm64', 'v8_full_debug'], @@ -475,6 +479,8 @@ 'official_android_arm64': [ 'release_bot', 'arm64', 'android', 'minimal_symbols', 'android_strip_outputs', 'official', 'disable_pgo'], + 'official_mac_arm64': [ + 'release_bot', 'arm64', 'official', 'disable_pgo'], # Release configs for x64. 'release_x64': [ @@ -512,6 +518,8 @@ 'release_bot', 'x64', 'fuchsia'], 'release_x64_fuchsia_trybot': [ 'release_trybot', 'x64', 'fuchsia'], + 'release_x64_gcc': [ + 'release_bot_no_goma', 'x64', 'gcc', 'lld', 'no_custom_libcxx'], 'release_x64_gcc_coverage': [ 'release_bot_no_goma', 'x64', 'coverage', 'gcc', 'lld', 'no_custom_libcxx', 'no_sysroot'], @@ -521,13 +529,15 @@ 'release_bot', 'x64', 'v8_snapshot_internal'], 'release_x64_minimal_symbols': [ 'release_bot', 'x64', 'minimal_symbols'], - 'release_x64_pointer_compression': [ - 'release_bot', 'x64', 'dcheck_always_on', 'v8_enable_slow_dchecks', 'v8_enable_javascript_promise_hooks', + 'release_x64_minimal_symbols_reclient': [ + 'release_bot_reclient', 'x64', 'minimal_symbols'], + 'release_x64_no_pointer_compression': [ + 'release_bot', 'x64_no_sandbox', 'dcheck_always_on', 'v8_enable_slow_dchecks', 'v8_enable_javascript_promise_hooks', 'v8_disable_pointer_compression'], - 'release_x64_pointer_compression_without_dchecks': [ - 'release_bot', 'x64', 'v8_disable_pointer_compression'], 'release_x64_reclient': [ 'release_bot_reclient', 'x64'], + 'release_x64_no_sandbox': [ + 'release_bot', 'x64_no_sandbox'], 'release_x64_trybot': [ 'release_trybot', 'x64'], 'release_x64_test_features_trybot': [ @@ -551,6 +561,9 @@ 'v8_enable_slow_dchecks', 'v8_verify_csa'], 'release_x64_webassembly_disabled': [ 'release_bot', 'x64', 'webassembly_disabled'], + 'release_x64_asan_sandbox_testing': [ + 'release_bot', 'x64', 'asan', 'symbolized', 'v8_enable_sandbox_future', + 'v8_expose_memory_corruption_api'], # Official configs for x64. 'official_x64': [ @@ -571,20 +584,21 @@ 'debug_x64_fuchsia': [ 'debug_bot', 'x64', 'fuchsia'], 'debug_x64_gcc': [ - 'debug_bot_no_goma', 'x64', 'gcc', 'lld', 'no_custom_libcxx', - 'v8_check_header_includes'], + 'debug_bot_no_goma', 'x64', 'gcc', 'lld', 'no_custom_libcxx'], 'debug_x64_header_includes': [ 'debug_bot', 'x64', 'v8_check_header_includes'], 'debug_x64_heap_sandbox': [ - 'debug_bot', 'x64', 'v8_enable_sandbox_future'], + 'debug_bot', 'x64', 'v8_enable_sandbox_future', 'v8_expose_memory_corruption_api'], 'debug_x64_heap_sandbox_arm64_sim': [ - 'debug_bot', 'simulate_arm64', 'v8_enable_sandbox_future'], + 'debug_bot', 'simulate_arm64', 'v8_enable_sandbox_future', 'v8_expose_memory_corruption_api'], 'debug_x64_minimal_symbols': [ 'debug_bot', 'x64', 'minimal_symbols'], 'debug_x64_non_default_cppgc': [ 'debug_bot', 'x64', 'non_default_cppgc'], 'debug_x64_perfetto': [ 'debug_bot', 'x64', 'perfetto'], + 'debug_x64_no_sandbox': [ + 'debug_bot', 'x64_no_sandbox'], 'debug_x64_single_generation': [ 'debug_bot', 'x64', 'v8_enable_single_generation'], 'debug_x64_trybot': [ @@ -613,15 +627,11 @@ 'debug', 'x86', 'goma', 'v8_enable_slow_dchecks', 'v8_full_debug'], # Release configs for x86. + 'release_x86': [ + 'release_bot', 'x86'], 'release_x86_asan_symbolized_verify_heap': [ 'release_bot', 'x86', 'asan', 'lsan', 'symbolized', 'v8_verify_heap'], - 'release_x86_gcc': [ - 'release_bot_no_goma', 'x86', 'gcc', 'lld', 'no_custom_libcxx', - 'v8_check_header_includes'], - 'release_x86_gcc_minimal_symbols': [ - 'release_bot_no_goma', 'x86', 'gcc', 'lld', 'no_custom_libcxx', - 'minimal_symbols', 'v8_check_header_includes'], 'release_x86_gcmole': [ 'release_bot', 'x86', 'gcmole'], 'release_x86_gcmole_trybot': [ @@ -632,8 +642,8 @@ 'release_bot_reclient', 'x86', 'minimal_symbols'], 'release_x86_no_i18n_trybot': [ 'release_trybot', 'x86', 'v8_no_i18n'], - 'release_x86_predictable': [ - 'release_bot', 'x86', 'v8_enable_verify_predictable'], + 'release_x64_predictable': [ + 'release_bot', 'x64', 'v8_enable_verify_predictable'], 'release_x86_shared_verify_heap': [ 'release', 'x86', 'goma', 'shared', 'v8_verify_heap'], 'release_x86_trybot': [ @@ -665,7 +675,11 @@ }, 'arm64': { - 'gn_args': 'target_cpu="arm64"', + 'gn_args': 'target_cpu="arm64" v8_enable_sandbox=true', + }, + + 'arm64_no_sandbox': { + 'gn_args': 'target_cpu="arm64" v8_enable_sandbox=false', }, 'asan': { @@ -723,8 +737,7 @@ # atomic marking state enabled because that is needed for the concurrent # write-barrier used by background compilation. 'gn_args': 'v8_enable_concurrent_marking=false ' - 'v8_enable_atomic_object_field_writes=false ' - 'v8_enable_atomic_marking_state=true ', + 'v8_enable_atomic_object_field_writes=false ', }, 'disable_pgo': { @@ -812,7 +825,7 @@ }, 'reclient': { - 'gn_args': 'use_rbe=true use_remoteexec=true', + 'gn_args': 'use_remoteexec=true', }, 'release': { @@ -848,16 +861,15 @@ }, 'simulate_arm64': { - 'gn_args': 'target_cpu="x64" v8_target_cpu="arm64"', + 'gn_args': 'target_cpu="x64" v8_target_cpu="arm64" v8_enable_sandbox=true', }, - 'simulate_loong64': { - 'gn_args': 'target_cpu="x64" v8_target_cpu="loong64"', + 'simulate_arm64_no_sandbox': { + 'gn_args': 'target_cpu="x64" v8_target_cpu="arm64" v8_enable_sandbox=false', }, - 'simulate_mipsel': { - 'gn_args': - 'target_cpu="x86" v8_target_cpu="mipsel" mips_arch_variant="r2"', + 'simulate_loong64': { + 'gn_args': 'target_cpu="x64" v8_target_cpu="loong64"', }, 'simulate_mips64el': { @@ -868,6 +880,10 @@ 'gn_args': 'target_cpu="x64" v8_target_cpu="ppc64"', }, + 'simulate_riscv32': { + 'gn_args': 'target_cpu="x86" v8_target_cpu="riscv32"', + }, + 'simulate_riscv64': { 'gn_args': 'target_cpu="x64" v8_target_cpu="riscv64"', }, @@ -925,6 +941,10 @@ 'gn_args': 'v8_enable_sandbox_future=true', }, + 'v8_expose_memory_corruption_api': { + 'gn_args': 'v8_expose_memory_corruption_api=true', + }, + 'v8_enable_lite_mode': { 'gn_args': 'v8_enable_lite_mode=true', }, @@ -1010,7 +1030,11 @@ }, 'x64': { - 'gn_args': 'target_cpu="x64"', + 'gn_args': 'target_cpu="x64" v8_enable_sandbox=true', + }, + + 'x64_no_sandbox': { + 'gn_args': 'target_cpu="x64" v8_enable_sandbox=false', }, 'x86': { diff --git a/deps/v8/infra/testing/builders.pyl b/deps/v8/infra/testing/builders.pyl index 11db9b11f714a3..ca2fab5eac8e90 100644 --- a/deps/v8/infra/testing/builders.pyl +++ b/deps/v8/infra/testing/builders.pyl @@ -77,8 +77,8 @@ {'name': 'mozilla', 'variant': 'extra'}, {'name': 'test262', 'variant': 'default', 'shards': 2}, {'name': 'test262', 'variant': 'extra', 'shards': 5}, - {'name': 'v8testing', 'shards': 3}, - {'name': 'v8testing', 'variant': 'extra', 'shards': 2}, + {'name': 'v8testing', 'shards': 4}, + {'name': 'v8testing', 'variant': 'extra', 'shards': 4}, # Noavx. { 'name': 'mozilla', @@ -95,7 +95,17 @@ 'name': 'v8testing', 'suffix': 'noavx', 'test_args': ['--extra-flags', '--noenable-avx'], - 'shards': 2 + 'shards': 4 + }, + # Nosse3. + { + 'name': 'v8testing', + 'suffix': 'nosse3', + 'test_args': [ + '--extra-flags', + '--noenable-sse3 --noenable-ssse3 --noenable-sse4-1 --noenable-avx', + ], + 'shards': 4, }, ], }, @@ -108,14 +118,6 @@ {'name': 'd8testing', 'test_args': ['--gc-stress'], 'shards': 5}, ], }, - 'v8_linux_gcc_rel_ng_triggered': { - 'swarming_dimensions' : { - 'os': 'Ubuntu-18.04', - }, - 'tests': [ - {'name': 'v8testing'}, - ], - }, 'v8_linux_nodcheck_rel_ng_triggered': { 'swarming_dimensions' : { 'cpu': 'x86-64-avx2', @@ -130,6 +132,15 @@ {'name': 'test262', 'variant': 'extra', 'shards': 2}, {'name': 'v8testing', 'shards': 2}, {'name': 'v8testing', 'variant': 'extra'}, + { + 'name': 'v8testing', + 'suffix': 'nosse3', + 'test_args': [ + '--extra-flags', + '--noenable-sse3 --noenable-ssse3 --noenable-sse4-1 --noenable-avx', + ], + 'shards': 2, + }, ], }, 'v8_linux_noi18n_rel_ng_triggered': { @@ -156,10 +167,19 @@ {'name': 'mozilla', 'variant': 'extra'}, {'name': 'optimize_for_size'}, {'name': 'test262', 'shards': 4}, - {'name': 'test262', 'variant': 'extra', 'shards': 3}, - {'name': 'v8testing', 'shards': 2}, - {'name': 'v8testing', 'suffix': 'isolates', 'test_args': ['--isolates'], 'shards': 2}, - {'name': 'v8testing', 'variant': 'extra', 'shards': 2}, + {'name': 'test262', 'variant': 'extra', 'shards': 6}, + {'name': 'v8testing', 'shards': 4}, + {'name': 'v8testing', 'suffix': 'isolates', 'test_args': ['--isolates'], 'shards': 4}, + {'name': 'v8testing', 'variant': 'extra', 'shards': 4}, + { + 'name': 'v8testing', + 'suffix': 'nosse3', + 'test_args': [ + '--extra-flags', + '--noenable-sse3 --noenable-ssse3 --noenable-sse4-1 --noenable-avx', + ], + 'shards': 4, + }, ], }, 'v8_linux_optional_rel_ng_triggered': { @@ -314,9 +334,9 @@ 'os': 'Ubuntu-18.04', }, 'tests': [ - {'name': 'test262', 'shards': 7}, - {'name': 'v8testing', 'shards': 3}, - {'name': 'v8testing', 'variant': 'extra', 'shards': 3}, + {'name': 'test262', 'shards': 12}, + {'name': 'v8testing', 'shards': 5}, + {'name': 'v8testing', 'variant': 'extra', 'shards': 5}, {'name': 'v8testing', 'variant': 'slow_path'}, ], }, @@ -361,6 +381,8 @@ {'name': 'v8testing', 'variant': 'stress_instruction_scheduling'}, {'name': 'v8testing', 'variant': 'stress_concurrent_allocation'}, {'name': 'v8testing', 'variant': 'stress_concurrent_inlining'}, + # Maglev -- move to extra once more architectures are supported. + {'name': 'mjsunit', 'variant': 'maglev'}, ], }, 'v8_linux64_dict_tracking_dbg_ng_triggered': { @@ -408,6 +430,10 @@ {'name': 'webkit', 'variant': 'stress_sampling'}, # Stress snapshot. {'name': 'mjsunit', 'variant': 'stress_snapshot'}, + # Maglev. + {'name': 'mjsunit', 'variant': 'maglev'}, + # Stress maglev. + {'name': 'mjsunit', 'variant': 'stress_maglev'}, # Experimental regexp engine. {'name': 'mjsunit', 'variant': 'experimental_regexp'}, # Wasm write protect code space. @@ -426,6 +452,35 @@ }, ], }, + 'v8_linux64_gc_stress_dbg_ng_triggered': { + 'swarming_dimensions' : { + 'cpu': 'x86-64-avx2', + 'os': 'Ubuntu-18.04', + }, + 'tests': [ + {'name': 'd8testing', 'test_args': ['--gc-stress'], 'shards': 5}, + { + 'name': 'mjsunit', + 'variant': 'slow_path', + 'test_args': ['--gc-stress'], + 'shards': 2 + }, + { + 'name': 'mjsunit', + 'variant': 'maglev', + 'test_args': ['--gc-stress'], + 'shards': 2 + }, + ], + }, + 'v8_linux64_gcc_rel_ng_triggered': { + 'swarming_dimensions' : { + 'os': 'Ubuntu-20.04', + }, + 'tests': [ + {'name': 'v8testing'}, + ], + }, 'v8_linux64_gcov_coverage': { 'swarming_dimensions' : { 'os': 'Ubuntu-18.04', @@ -439,7 +494,20 @@ 'os': 'Ubuntu-18.04', }, 'tests': [ - {'name': 'v8testing', 'shards': 2}, + {'name': 'v8testing', 'shards': 4}, + ], + }, + 'v8_linux64_minor_mc_dbg_ng_triggered': { + 'swarming_dimensions' : { + 'cpu': 'x86-64-avx2', + 'os': 'Ubuntu-18.04', + }, + 'tests': [ + {'name': 'v8testing', 'variant': 'minor_mc'}, + {'name': 'benchmarks', 'variant': 'minor_mc'}, + {'name': 'mozilla', 'variant': 'minor_mc'}, + {'name': 'test262', 'variant': 'minor_mc', 'shards': 2}, + {'name': 'mjsunit', 'variant': 'minor_mc'}, ], }, 'v8_linux64_msan_rel_ng_triggered': { @@ -473,6 +541,8 @@ {'name': 'v8testing', 'variant': 'extra'}, {'name': 'v8testing', 'variant': 'no_lfa'}, {'name': 'v8testing', 'variant': 'stress_instruction_scheduling'}, + # Maglev -- move to extra once more architectures are supported. + {'name': 'mjsunit', 'variant': 'maglev'}, ], }, 'v8_linux64_perfetto_dbg_ng_triggered': { @@ -483,7 +553,7 @@ {'name': 'v8testing', 'shards': 3}, ], }, - 'v8_linux64_pointer_compression_rel_ng_triggered': { + 'v8_linux64_no_pointer_compression_rel_ng_triggered': { 'swarming_dimensions' : { 'os': 'Ubuntu-18.04', }, @@ -491,6 +561,15 @@ {'name': 'v8testing', 'shards': 3}, ], }, + 'v8_linux64_no_sandbox_dbg_ng_triggered': { + 'swarming_dimensions' : { + 'cpu': 'x86-64-avx2', + 'os': 'Ubuntu-18.04', + }, + 'tests': [ + {'name': 'v8testing', 'shards': 5}, + ], + }, 'v8_linux64_single_generation_dbg_ng_triggered': { 'swarming_dimensions' : { 'os': 'Ubuntu-18.04', @@ -518,6 +597,28 @@ {'name': 'v8testing', 'variant': 'no_lfa'}, {'name': 'v8testing', 'variant': 'slow_path'}, {'name': 'v8testing', 'variant': 'stress_instruction_scheduling'}, + # Maglev -- move to extra once more architectures are supported. + {'name': 'mjsunit', 'variant': 'maglev'}, + ], + }, + 'v8_linux64_predictable_rel_ng_triggered': { + 'swarming_dimensions': { + 'cpu': 'x86-64-avx2', + 'os': 'Ubuntu-18.04', + }, + 'tests': [ + {'name': 'benchmarks'}, + {'name': 'd8testing'}, + {'name': 'mozilla'}, + ], + }, + 'v8_linux64_no_sandbox_rel_ng_triggered': { + 'swarming_dimensions' : { + 'cpu': 'x86-64-avx2', + 'os': 'Ubuntu-18.04', + }, + 'tests': [ + {'name': 'v8testing', 'shards': 2}, ], }, 'v8_linux64_tsan_rel_ng_triggered': { @@ -587,7 +688,7 @@ {'name': 'mozilla', 'shards': 4}, {'name': 'test262', 'variant': 'default', 'shards': 4}, {'name': 'v8testing', 'shards': 14}, - {'name': 'v8testing', 'variant': 'extra', 'shards': 12}, + {'name': 'v8testing', 'variant': 'extra', 'shards': 14}, ], }, 'v8_linux_arm64_gc_stress_dbg_ng_triggered': { @@ -615,7 +716,7 @@ {'name': 'mozilla', 'shards': 4}, {'name': 'test262', 'variant': 'default', 'shards': 4}, {'name': 'v8testing', 'shards': 14}, - {'name': 'v8testing', 'variant': 'extra', 'shards': 12}, + {'name': 'v8testing', 'variant': 'extra', 'shards': 14}, ], }, 'v8_linux_arm64_cfi_rel_ng_triggered': { @@ -627,7 +728,7 @@ {'name': 'v8testing', 'shards': 4}, ], }, - 'v8_linux64_arm64_pointer_compression_rel_ng_triggered': { + 'v8_linux64_arm64_no_pointer_compression_rel_ng_triggered': { 'swarming_dimensions' : { 'os': 'Ubuntu-18.04', }, @@ -646,7 +747,15 @@ ], }, ############################################################################## - # Linux64 with RISC-V simulators + # Linux with RISC-V simulators + 'v8_linux_riscv32_rel_ng_triggered': { + 'swarming_dimensions': { + 'os': 'Ubuntu-18.04', + }, + 'tests': [ + {'name': 'v8testing', 'shards': 3}, + ], + }, 'v8_linux64_riscv64_rel_ng_triggered': { 'swarming_dimensions': { 'os': 'Ubuntu-18.04', @@ -700,7 +809,7 @@ # Win64 'v8_win64_asan_rel_ng_triggered': { 'swarming_dimensions' : { - 'os': 'Windows-10-15063', + 'os': 'Windows-10-19042', }, 'tests': [ {'name': 'v8testing', 'shards': 5}, @@ -709,11 +818,11 @@ 'v8_win64_dbg_ng_triggered': { 'swarming_dimensions' : { 'cpu': 'x86-64', - 'os': 'Windows-10-15063', + 'os': 'Windows-10-19042', }, 'tests': [ {'name': 'mozilla'}, - {'name': 'test262', 'variant': 'default', 'shards': 2}, + {'name': 'test262', 'variant': 'default', 'shards': 4}, {'name': 'v8testing', 'shards': 3}, {'name': 'v8testing', 'variant': 'extra', 'shards': 2}, ], @@ -721,22 +830,22 @@ 'v8_win64_msvc_rel_ng_triggered': { 'swarming_dimensions' : { 'cpu': 'x86-64', - 'os': 'Windows-10-15063', + 'os': 'Windows-10-19042', }, 'tests': [ {'name': 'mozilla'}, - {'name': 'test262', 'variant': 'default'}, + {'name': 'test262', 'variant': 'default', 'shards': 2}, {'name': 'v8testing', 'shards': 2}, ], }, 'v8_win64_rel_ng_triggered': { 'swarming_dimensions' : { 'cpu': 'x86-64', - 'os': 'Windows-10-15063', + 'os': 'Windows-10-19042', }, 'tests': [ {'name': 'mozilla'}, - {'name': 'test262', 'variant': 'default'}, + {'name': 'test262', 'variant': 'default', 'shards': 2}, {'name': 'v8testing', 'shards': 2}, {'name': 'v8testing', 'variant': 'extra'}, ], @@ -815,6 +924,16 @@ {'name': 'v8testing'}, ], }, + 'v8_mac_arm64_no_pointer_compression_dbg_ng_triggered': { + 'swarming_dimensions' : { + 'cpu': 'arm64', + 'os': 'Mac-11', + 'pool': 'chromium.tests', + }, + 'tests': [ + {'name': 'v8testing'}, + ], + }, 'v8_mac_arm64_sim_rel_ng_triggered': { 'swarming_dimensions' : { 'cpu': 'x86-64', @@ -1088,8 +1207,9 @@ {'name': 'v8testing', 'variant': 'default'}, ], }, - 'V8 Linux - predictable': { + 'V8 Linux64 - predictable': { 'swarming_dimensions': { + 'cpu': 'x86-64-avx2', 'os': 'Ubuntu-18.04', }, 'tests': [ @@ -1116,14 +1236,6 @@ {'name': 'v8testing'}, ], }, - 'V8 Linux gcc': { - 'swarming_dimensions' : { - 'os': 'Ubuntu-18.04', - }, - 'tests': [ - {'name': 'v8testing'}, - ], - }, 'V8 Linux64': { 'swarming_dimensions': { 'cpu': 'x86-64-avx2', @@ -1150,6 +1262,8 @@ {'name': 'v8testing', 'variant': 'minor_mc'}, {'name': 'v8testing', 'variant': 'no_lfa'}, {'name': 'v8testing', 'variant': 'stress_instruction_scheduling'}, + # Maglev -- move to extra once more architectures are supported. + {'name': 'mjsunit', 'variant': 'maglev'}, # Noavx. { 'name': 'mozilla', @@ -1211,6 +1325,8 @@ {'name': 'v8testing', 'variant': 'stress_instruction_scheduling'}, {'name': 'v8testing', 'variant': 'stress_concurrent_allocation'}, {'name': 'v8testing', 'variant': 'stress_concurrent_inlining'}, + # Maglev -- move to extra once more architectures are supported. + {'name': 'mjsunit', 'variant': 'maglev'}, # Noavx. { 'name': 'mozilla', @@ -1231,13 +1347,17 @@ }, ], }, - 'V8 Linux64 - dict tracking - debug': { + 'V8 Linux64 - minor mc - debug': { 'swarming_dimensions': { 'cpu': 'x86-64-avx2', 'os': 'Ubuntu-18.04', }, 'tests': [ - {'name': 'v8testing', 'shards': 3}, + {'name': 'v8testing', 'variant': 'minor_mc'}, + {'name': 'benchmarks', 'variant': 'minor_mc'}, + {'name': 'mozilla', 'variant': 'minor_mc'}, + {'name': 'test262', 'variant': 'minor_mc', 'shards': 2}, + {'name': 'mjsunit', 'variant': 'minor_mc'}, ], }, 'V8 Linux64 - disable runtime call stats': { @@ -1260,6 +1380,10 @@ {'name': 'webkit', 'variant': 'stress_sampling'}, # Stress snapshot. {'name': 'mjsunit', 'variant': 'stress_snapshot'}, + # Maglev. + {'name': 'mjsunit', 'variant': 'maglev'}, + # Stress maglev. + {'name': 'mjsunit', 'variant': 'stress_maglev'}, # Experimental regexp engine. {'name': 'mjsunit', 'variant': 'experimental_regexp'}, # Wasm write protect code space. @@ -1322,12 +1446,49 @@ {'name': 'webkit', 'variant': 'stress_sampling'}, # Stress snapshot. {'name': 'mjsunit', 'variant': 'stress_snapshot'}, + # Maglev. + {'name': 'mjsunit', 'variant': 'maglev'}, + # Stress maglev. + {'name': 'mjsunit', 'variant': 'stress_maglev'}, # Experimental regexp engine. {'name': 'mjsunit', 'variant': 'experimental_regexp'}, # Wasm write protect code space. {'name': 'mjsunit', 'variant': 'wasm_write_protect_code'}, ], }, + 'V8 Linux64 gcc': { + 'swarming_dimensions' : { + 'os': 'Ubuntu-20.04', + }, + 'tests': [ + {'name': 'v8testing'}, + ], + }, + 'V8 Linux64 - gc stress': { + 'swarming_dimensions': { + 'cpu': 'x86-64-avx2', + 'os': 'Ubuntu-18.04', + }, + 'tests': [ + { + 'name': 'd8testing', + 'test_args': ['--gc-stress'], + 'shards': 5, + }, + { + 'name': 'mjsunit', + 'variant': 'slow_path', + 'test_args': ['--gc-stress'], + 'shards': 2, + }, + { + 'name': 'mjsunit', + 'variant': 'maglev', + 'test_args': ['--gc-stress'], + 'shards': 2 + }, + ], + }, 'V8 Linux64 - gcov coverage': { 'swarming_dimensions' : { 'os': 'Ubuntu-18.04', @@ -1352,7 +1513,7 @@ {'name': 'v8testing'}, ], }, - 'V8 Linux64 - pointer compression': { + 'V8 Linux64 - no pointer compression': { 'swarming_dimensions' : { 'os': 'Ubuntu-18.04', }, @@ -1360,6 +1521,24 @@ {'name': 'v8testing', 'shards': 2}, ], }, + 'V8 Linux64 - no sandbox': { + 'swarming_dimensions': { + 'cpu': 'x86-64-avx2', + 'os': 'Ubuntu-18.04', + }, + 'tests': [ + {'name': 'v8testing'}, + ], + }, + 'V8 Linux64 - no sandbox - debug': { + 'swarming_dimensions': { + 'cpu': 'x86-64-avx2', + 'os': 'Ubuntu-18.04', + }, + 'tests': [ + {'name': 'v8testing', 'shards': 2}, + ], + }, 'V8 Linux64 - shared': { 'swarming_dimensions' : { 'os': 'Ubuntu-18.04', @@ -1559,6 +1738,16 @@ {'name': 'v8testing', 'variant': 'extra', 'shards': 2}, ], }, + 'V8 Mac - arm64 - no pointer compression debug': { + 'swarming_dimensions' : { + 'cpu': 'arm64', + 'os': 'Mac-11', + 'pool': 'chromium.tests', + }, + 'tests': [ + {'name': 'v8testing'}, + ], + }, 'V8 Mac - arm64 - sim - debug': { 'swarming_dimensions' : { 'cpu': 'x86-64', @@ -1613,7 +1802,7 @@ }, 'V8 Win64': { 'swarming_dimensions': { - 'os': 'Windows-10-15063', + 'os': 'Windows-10-19042', }, 'tests': [ {'name': 'mozilla'}, @@ -1624,18 +1813,18 @@ }, 'V8 Win64 - debug': { 'swarming_dimensions': { - 'os': 'Windows-10-15063', + 'os': 'Windows-10-19042', }, 'tests': [ {'name': 'mozilla'}, - {'name': 'test262', 'variant': 'default'}, + {'name': 'test262', 'variant': 'default', 'shards': 2}, {'name': 'v8testing', 'shards': 4}, {'name': 'v8testing', 'variant': 'extra', 'shards': 3}, ], }, 'V8 Win64 - msvc': { 'swarming_dimensions': { - 'os': 'Windows-10-15063', + 'os': 'Windows-10-19042', }, 'tests': [ {'name': 'mozilla'}, @@ -1645,7 +1834,7 @@ }, 'V8 Win64 ASAN': { 'swarming_dimensions': { - 'os': 'Windows-10-15063', + 'os': 'Windows-10-19042', }, 'tests': [ {'name': 'v8testing', 'shards': 5}, @@ -1818,7 +2007,7 @@ 'name': 'v8testing', 'suffix': 'armv8-a', 'test_args': ['--extra-flags', '--enable-armv8'], - 'shards': 8 + 'shards': 10 }, # Novfp3. { @@ -1839,7 +2028,7 @@ 'suffix': 'novfp3', 'variant': 'default', 'test_args': ['--novfp3'], - 'shards': 8 + 'shards': 3 }, ], }, @@ -1884,7 +2073,7 @@ {'name': 'mozilla', 'shards': 2}, {'name': 'test262', 'variant': 'default', 'shards': 2}, {'name': 'v8testing', 'shards': 12}, - {'name': 'v8testing', 'variant': 'extra', 'shards': 11}, + {'name': 'v8testing', 'variant': 'extra', 'shards': 14}, ], }, 'V8 Linux - arm64 - sim - gc stress': { @@ -1900,7 +2089,7 @@ { 'name': 'd8testing', 'test_args': ['--gc-stress', '--extra-flags=--verify-heap-skip-remembered-set'], - 'shards': 5 + 'shards': 7 }, ], }, @@ -1944,7 +2133,7 @@ {'name': 'v8testing', 'shards': 4}, ], }, - 'V8 Linux - mipsel - sim': { + 'V8 Linux - ppc64 - sim': { 'swarming_dimensions': { 'os': 'Ubuntu-18.04', }, @@ -1954,11 +2143,10 @@ 'priority': 35, }, 'tests': [ - {'name': 'test262', 'variant': 'default'}, - {'name': 'v8testing', 'shards': 4}, + {'name': 'v8testing', 'shards': 3}, ], }, - 'V8 Linux - ppc64 - sim': { + 'V8 Linux - riscv32 - sim': { 'swarming_dimensions': { 'os': 'Ubuntu-18.04', }, @@ -1997,7 +2185,7 @@ {'name': 'v8testing', 'shards': 3}, ], }, - 'V8 Linux64 - arm64 - sim - pointer compression': { + 'V8 Linux64 - arm64 - sim - no pointer compression': { 'swarming_dimensions': { 'os': 'Ubuntu-18.04', }, diff --git a/deps/v8/samples/hello-world.cc b/deps/v8/samples/hello-world.cc index 3ca9ff68024566..557ba63e0fd85e 100644 --- a/deps/v8/samples/hello-world.cc +++ b/deps/v8/samples/hello-world.cc @@ -20,12 +20,6 @@ int main(int argc, char* argv[]) { v8::V8::InitializeExternalStartupData(argv[0]); std::unique_ptr platform = v8::platform::NewDefaultPlatform(); v8::V8::InitializePlatform(platform.get()); -#ifdef V8_SANDBOX - if (!v8::V8::InitializeSandbox()) { - fprintf(stderr, "Error initializing the V8 sandbox\n"); - return 1; - } -#endif v8::V8::Initialize(); // Create a new Isolate and make it the current one. diff --git a/deps/v8/samples/process.cc b/deps/v8/samples/process.cc index 1e9498038836d8..28b6f119c3acd2 100644 --- a/deps/v8/samples/process.cc +++ b/deps/v8/samples/process.cc @@ -703,12 +703,6 @@ int main(int argc, char* argv[]) { v8::V8::InitializeExternalStartupData(argv[0]); std::unique_ptr platform = v8::platform::NewDefaultPlatform(); v8::V8::InitializePlatform(platform.get()); -#ifdef V8_SANDBOX - if (!v8::V8::InitializeSandbox()) { - fprintf(stderr, "Error initializing the V8 sandbox\n"); - return 1; - } -#endif v8::V8::Initialize(); map options; string file; diff --git a/deps/v8/samples/shell.cc b/deps/v8/samples/shell.cc index 7e6be6f8723d19..046ed1e4eb53b7 100644 --- a/deps/v8/samples/shell.cc +++ b/deps/v8/samples/shell.cc @@ -73,14 +73,8 @@ int main(int argc, char* argv[]) { v8::V8::InitializeExternalStartupData(argv[0]); std::unique_ptr platform = v8::platform::NewDefaultPlatform(); v8::V8::InitializePlatform(platform.get()); -#ifdef V8_SANDBOX - if (!v8::V8::InitializeSandbox()) { - fprintf(stderr, "Error initializing the V8 sandbox\n"); - return 1; - } -#endif - v8::V8::Initialize(); v8::V8::SetFlagsFromCommandLine(&argc, argv, true); + v8::V8::Initialize(); v8::Isolate::CreateParams create_params; create_params.array_buffer_allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator(); diff --git a/deps/v8/src/DEPS b/deps/v8/src/DEPS index 9846e7695c125b..1edad011be189c 100644 --- a/deps/v8/src/DEPS +++ b/deps/v8/src/DEPS @@ -12,6 +12,7 @@ include_rules = [ "-src/compiler", "+src/compiler/pipeline.h", "+src/compiler/code-assembler.h", + "+src/compiler/wasm-compiler-definitions.h", "+src/compiler/wasm-compiler.h", "-src/heap", "+src/heap/basic-memory-chunk.h", @@ -23,6 +24,7 @@ include_rules = [ # TODO(v8:10496): Don't expose so much (through transitive includes) outside # of heap/. "+src/heap/heap.h", + "+src/heap/heap-verifier.h", "+src/heap/heap-inl.h", "+src/heap/heap-write-barrier-inl.h", "+src/heap/heap-write-barrier.h", @@ -33,6 +35,7 @@ include_rules = [ # TODO(v8:10496): Don't expose memory chunk outside of heap/. "+src/heap/memory-chunk.h", "+src/heap/memory-chunk-inl.h", + "+src/heap/paged-spaces-inl.h", "+src/heap/parked-scope.h", "+src/heap/read-only-heap-inl.h", "+src/heap/read-only-heap.h", @@ -88,7 +91,10 @@ specific_include_rules = { "builtins-trace\.cc": [ "+protos/perfetto", ], - "system-jit-win\.cc": [ + "etw-jit-win\.cc": [ "+src/libplatform/tracing/recorder.h", ], + "etw-jit-metadata-win\.h": [ + "+src/libplatform/etw/etw-provider-win.h", + ] } diff --git a/deps/v8/src/api/api-arguments-inl.h b/deps/v8/src/api/api-arguments-inl.h index 5d437370bc0a08..470ab95e181e84 100644 --- a/deps/v8/src/api/api-arguments-inl.h +++ b/deps/v8/src/api/api-arguments-inl.h @@ -12,7 +12,6 @@ #include "src/logging/runtime-call-stats-scope.h" #include "src/objects/api-callbacks.h" #include "src/objects/slots-inl.h" -#include "src/tracing/trace-event.h" namespace v8 { namespace internal { @@ -134,7 +133,7 @@ Handle FunctionCallbackArguments::Call(CallHandlerInfo handler) { Isolate* isolate = this->isolate(); RCS_SCOPE(isolate, RuntimeCallCounterId::kFunctionCallback); v8::FunctionCallback f = - v8::ToCData(handler.callback()); + reinterpret_cast(handler.callback()); Handle receiver_check_unsupported; if (isolate->debug_execution_mode() == DebugInfo::kSideEffects && !isolate->debug()->PerformSideEffectCheckForCallback( @@ -148,6 +147,17 @@ Handle FunctionCallbackArguments::Call(CallHandlerInfo handler) { return GetReturnValue(isolate); } +PropertyCallbackArguments::~PropertyCallbackArguments(){ +#ifdef DEBUG +// TODO(chromium:1310062): enable this check. +// if (javascript_execution_counter_) { +// CHECK_WITH_MSG(javascript_execution_counter_ == +// isolate()->javascript_execution_counter(), +// "Unexpected side effect detected"); +// } +#endif // DEBUG +} + Handle PropertyCallbackArguments::CallNamedEnumerator( Handle interceptor) { DCHECK(interceptor->is_named()); @@ -296,8 +306,12 @@ Handle PropertyCallbackArguments::CallAccessorGetter( Handle info, Handle name) { Isolate* isolate = this->isolate(); RCS_SCOPE(isolate, RuntimeCallCounterId::kAccessorGetterCallback); + // Unlike interceptor callbacks we know that the property exists, so + // the callback is allowed to have side effects. + AcceptSideEffects(); + AccessorNameGetterCallback f = - ToCData(info->getter()); + reinterpret_cast(info->getter()); return BasicCallNamedGetterCallback(f, name, info, handle(receiver(), isolate)); } @@ -307,8 +321,12 @@ Handle PropertyCallbackArguments::CallAccessorSetter( Handle value) { Isolate* isolate = this->isolate(); RCS_SCOPE(isolate, RuntimeCallCounterId::kAccessorSetterCallback); + // Unlike interceptor callbacks we know that the property exists, so + // the callback is allowed to have side effects. + AcceptSideEffects(); + AccessorNameSetterCallback f = - ToCData(accessor_info->setter()); + reinterpret_cast(accessor_info->setter()); PREPARE_CALLBACK_INFO(isolate, f, Handle, void, accessor_info, handle(receiver(), isolate), Setter); f(v8::Utils::ToLocal(name), v8::Utils::ToLocal(value), callback_info); diff --git a/deps/v8/src/api/api-arguments.cc b/deps/v8/src/api/api-arguments.cc index 51317fd0bf14bb..452588b394f087 100644 --- a/deps/v8/src/api/api-arguments.cc +++ b/deps/v8/src/api/api-arguments.cc @@ -12,7 +12,12 @@ namespace internal { PropertyCallbackArguments::PropertyCallbackArguments( Isolate* isolate, Object data, Object self, JSObject holder, Maybe should_throw) - : Super(isolate) { + : Super(isolate) +#ifdef DEBUG + , + javascript_execution_counter_(isolate->javascript_execution_counter()) +#endif // DEBUG +{ slot_at(T::kThisIndex).store(self); slot_at(T::kHolderIndex).store(holder); slot_at(T::kDataIndex).store(data); @@ -33,8 +38,7 @@ PropertyCallbackArguments::PropertyCallbackArguments( } FunctionCallbackArguments::FunctionCallbackArguments( - internal::Isolate* isolate, internal::Object data, - internal::HeapObject callee, internal::Object holder, + internal::Isolate* isolate, internal::Object data, internal::Object holder, internal::HeapObject new_target, internal::Address* argv, int argc) : Super(isolate), argv_(argv), argc_(argc) { slot_at(T::kDataIndex).store(data); diff --git a/deps/v8/src/api/api-arguments.h b/deps/v8/src/api/api-arguments.h index 98354757be6500..39958964fd4233 100644 --- a/deps/v8/src/api/api-arguments.h +++ b/deps/v8/src/api/api-arguments.h @@ -6,8 +6,6 @@ #define V8_API_API_ARGUMENTS_H_ #include "include/v8-template.h" -#include "src/api/api.h" -#include "src/debug/debug.h" #include "src/execution/isolate.h" #include "src/objects/slots.h" #include "src/objects/visitors.h" @@ -58,7 +56,15 @@ class CustomArguments : public CustomArgumentsBase { // Note: Calling args.Call() sets the return value on args. For multiple // Call()'s, a new args should be used every time. -class PropertyCallbackArguments +// This class also serves as a side effects detection scope (JavaScript code +// execution). It is used for ensuring correctness of the interceptor callback +// implementations. The idea is that the interceptor callback that does not +// intercept an operation must not produce side effects. If the callback +// signals that it has handled the operation (by either returning a respective +// result or by throwing an exception) then the AcceptSideEffects() method +// must be called to "accept" the side effects that have happened during the +// lifetime of the PropertyCallbackArguments object. +class PropertyCallbackArguments final : public CustomArguments > { public: using T = PropertyCallbackInfo; @@ -74,6 +80,7 @@ class PropertyCallbackArguments PropertyCallbackArguments(Isolate* isolate, Object data, Object self, JSObject holder, Maybe should_throw); + inline ~PropertyCallbackArguments(); // Don't copy PropertyCallbackArguments, because they would both have the // same prev_ pointer. @@ -128,6 +135,14 @@ class PropertyCallbackArguments inline Handle CallIndexedEnumerator( Handle interceptor); + // Accept potential JavaScript side effects that might occurr during life + // time of this object. + inline void AcceptSideEffects() { +#ifdef DEBUG + javascript_execution_counter_ = 0; +#endif // DEBUG + } + private: /* * The following Call functions wrap the calling of all callbacks to handle @@ -148,6 +163,13 @@ class PropertyCallbackArguments inline JSObject holder(); inline Object receiver(); + +#ifdef DEBUG + // This stores current value of Isolate::javascript_execution_counter(). + // It's used for detecting whether JavaScript code was executed between + // PropertyCallbackArguments's constructior and destructor. + uint32_t javascript_execution_counter_; +#endif // DEBUG }; class FunctionCallbackArguments @@ -163,9 +185,8 @@ class FunctionCallbackArguments static const int kIsolateIndex = T::kIsolateIndex; static const int kNewTargetIndex = T::kNewTargetIndex; - FunctionCallbackArguments(Isolate* isolate, Object data, HeapObject callee, - Object holder, HeapObject new_target, Address* argv, - int argc); + FunctionCallbackArguments(Isolate* isolate, Object data, Object holder, + HeapObject new_target, Address* argv, int argc); /* * The following Call function wraps the calling of all callbacks to handle diff --git a/deps/v8/src/api/api-inl.h b/deps/v8/src/api/api-inl.h index 975976ae096ae2..ac675a87fc82ba 100644 --- a/deps/v8/src/api/api-inl.h +++ b/deps/v8/src/api/api-inl.h @@ -9,18 +9,16 @@ #include "src/api/api.h" #include "src/execution/interrupts-scope.h" #include "src/execution/microtask-queue.h" -#include "src/execution/protectors.h" #include "src/handles/handles-inl.h" #include "src/heap/heap-inl.h" #include "src/objects/foreign-inl.h" -#include "src/objects/js-weak-refs.h" #include "src/objects/objects-inl.h" namespace v8 { template inline T ToCData(v8::internal::Object obj) { - STATIC_ASSERT(sizeof(T) == sizeof(v8::internal::Address)); + static_assert(sizeof(T) == sizeof(v8::internal::Address)); if (obj == v8::internal::Smi::zero()) return nullptr; return reinterpret_cast( v8::internal::Foreign::cast(obj).foreign_address()); @@ -35,7 +33,7 @@ inline v8::internal::Address ToCData(v8::internal::Object obj) { template inline v8::internal::Handle FromCData( v8::internal::Isolate* isolate, T obj) { - STATIC_ASSERT(sizeof(T) == sizeof(v8::internal::Address)); + static_assert(sizeof(T) == sizeof(v8::internal::Address)); if (obj == nullptr) return handle(v8::internal::Smi::zero(), isolate); return isolate->factory()->NewForeign( reinterpret_cast(obj)); @@ -96,7 +94,6 @@ TYPED_ARRAYS(MAKE_TO_LOCAL_TYPED_ARRAY) MAKE_TO_LOCAL(ToLocal, FunctionTemplateInfo, FunctionTemplate) MAKE_TO_LOCAL(ToLocal, ObjectTemplateInfo, ObjectTemplate) MAKE_TO_LOCAL(SignatureToLocal, FunctionTemplateInfo, Signature) -MAKE_TO_LOCAL(AccessorSignatureToLocal, FunctionTemplateInfo, AccessorSignature) MAKE_TO_LOCAL(MessageToLocal, Object, Message) MAKE_TO_LOCAL(PromiseToLocal, JSObject, Promise) MAKE_TO_LOCAL(StackTraceToLocal, FixedArray, StackTrace) @@ -185,8 +182,8 @@ class V8_NODISCARD CallDepthScope { !microtask_queue->DebugMicrotasksScopeDepthIsZero()); } } -#endif DCHECK(CheckKeptObjectsClearedAfterMicrotaskCheckpoint(microtask_queue)); +#endif isolate_->set_next_v8_call_is_safe_for_termination(safe_for_termination_); } @@ -204,6 +201,7 @@ class V8_NODISCARD CallDepthScope { } private: +#ifdef DEBUG bool CheckKeptObjectsClearedAfterMicrotaskCheckpoint( i::MicrotaskQueue* microtask_queue) { bool did_perform_microtask_checkpoint = @@ -213,6 +211,7 @@ class V8_NODISCARD CallDepthScope { return !did_perform_microtask_checkpoint || isolate_->heap()->weak_refs_keep_during_job().IsUndefined(isolate_); } +#endif i::Isolate* const isolate_; Local context_; @@ -233,14 +232,6 @@ class V8_NODISCARD InternalEscapableScope : public EscapableHandleScope { : EscapableHandleScope(reinterpret_cast(isolate)) {} }; -inline bool IsExecutionTerminatingCheck(i::Isolate* isolate) { - if (isolate->has_scheduled_exception()) { - return isolate->scheduled_exception() == - i::ReadOnlyRoots(isolate).termination_exception(); - } - return false; -} - template void CopySmiElementsToTypedBuffer(T* dst, uint32_t length, i::FixedArray elements) { diff --git a/deps/v8/src/api/api-macros-undef.h b/deps/v8/src/api/api-macros-undef.h index d3eea83a5f0c21..ab1116d9cee7b7 100644 --- a/deps/v8/src/api/api-macros-undef.h +++ b/deps/v8/src/api/api-macros-undef.h @@ -5,8 +5,8 @@ // PRESUBMIT_INTENTIONALLY_MISSING_INCLUDE_GUARD #undef LOG_API -#undef ENTER_V8_DO_NOT_USE -#undef ENTER_V8_HELPER_DO_NOT_USE +#undef ENTER_V8_BASIC +#undef ENTER_V8_HELPER_INTERNAL #undef PREPARE_FOR_DEBUG_INTERFACE_EXECUTION_WITH_ISOLATE #undef PREPARE_FOR_EXECUTION_WITH_CONTEXT #undef PREPARE_FOR_EXECUTION diff --git a/deps/v8/src/api/api-macros.h b/deps/v8/src/api/api-macros.h index 9fbe9a973903ae..149dd0555a69be 100644 --- a/deps/v8/src/api/api-macros.h +++ b/deps/v8/src/api/api-macros.h @@ -35,98 +35,117 @@ * TODO(verwaest): Remove calls form API methods to DO_NOT_USE macros. */ -#define API_RCS_SCOPE(isolate, class_name, function_name) \ - RCS_SCOPE(isolate, \ +#define API_RCS_SCOPE(i_isolate, class_name, function_name) \ + RCS_SCOPE(i_isolate, \ i::RuntimeCallCounterId::kAPI_##class_name##_##function_name); -#define ENTER_V8_DO_NOT_USE(isolate) i::VMState __state__((isolate)) - -#define ENTER_V8_HELPER_DO_NOT_USE(isolate, context, class_name, \ - function_name, bailout_value, \ - HandleScopeClass, do_callback) \ - if (IsExecutionTerminatingCheck(isolate)) { \ - return bailout_value; \ - } \ - HandleScopeClass handle_scope(isolate); \ - CallDepthScope call_depth_scope(isolate, context); \ - API_RCS_SCOPE(isolate, class_name, function_name); \ - i::VMState __state__((isolate)); \ +#define ENTER_V8_BASIC(i_isolate) \ + /* Embedders should never enter V8 after terminating it */ \ + DCHECK(!i_isolate->is_execution_terminating()); \ + i::VMState __state__((i_isolate)) + +#define ENTER_V8_HELPER_INTERNAL(i_isolate, context, class_name, \ + function_name, bailout_value, \ + HandleScopeClass, do_callback) \ + if (i_isolate->is_execution_terminating()) { \ + return bailout_value; \ + } \ + HandleScopeClass handle_scope(i_isolate); \ + CallDepthScope call_depth_scope(i_isolate, context); \ + API_RCS_SCOPE(i_isolate, class_name, function_name); \ + i::VMState __state__((i_isolate)); \ bool has_pending_exception = false -#define PREPARE_FOR_DEBUG_INTERFACE_EXECUTION_WITH_ISOLATE(isolate, T) \ - if (IsExecutionTerminatingCheck(isolate)) { \ - return MaybeLocal(); \ - } \ - InternalEscapableScope handle_scope(isolate); \ - CallDepthScope call_depth_scope(isolate, v8::Local()); \ - i::VMState __state__((isolate)); \ +#define PREPARE_FOR_DEBUG_INTERFACE_EXECUTION_WITH_ISOLATE(i_isolate, T) \ + if (i_isolate->is_execution_terminating()) { \ + return MaybeLocal(); \ + } \ + InternalEscapableScope handle_scope(i_isolate); \ + CallDepthScope call_depth_scope(i_isolate, v8::Local()); \ + i::VMState __state__((i_isolate)); \ bool has_pending_exception = false #define PREPARE_FOR_EXECUTION_WITH_CONTEXT(context, class_name, function_name, \ bailout_value, HandleScopeClass, \ do_callback) \ - auto isolate = context.IsEmpty() \ - ? i::Isolate::Current() \ - : reinterpret_cast(context->GetIsolate()); \ - ENTER_V8_HELPER_DO_NOT_USE(isolate, context, class_name, function_name, \ - bailout_value, HandleScopeClass, do_callback); + auto i_isolate = context.IsEmpty() \ + ? i::Isolate::Current() \ + : reinterpret_cast(context->GetIsolate()); \ + ENTER_V8_HELPER_INTERNAL(i_isolate, context, class_name, function_name, \ + bailout_value, HandleScopeClass, do_callback); #define PREPARE_FOR_EXECUTION(context, class_name, function_name, T) \ PREPARE_FOR_EXECUTION_WITH_CONTEXT(context, class_name, function_name, \ MaybeLocal(), InternalEscapableScope, \ false) -#define ENTER_V8(isolate, context, class_name, function_name, bailout_value, \ - HandleScopeClass) \ - ENTER_V8_HELPER_DO_NOT_USE(isolate, context, class_name, function_name, \ - bailout_value, HandleScopeClass, true) +#define ENTER_V8(i_isolate, context, class_name, function_name, bailout_value, \ + HandleScopeClass) \ + ENTER_V8_HELPER_INTERNAL(i_isolate, context, class_name, function_name, \ + bailout_value, HandleScopeClass, true) #ifdef DEBUG -#define ENTER_V8_NO_SCRIPT(isolate, context, class_name, function_name, \ +#define ENTER_V8_NO_SCRIPT(i_isolate, context, class_name, function_name, \ bailout_value, HandleScopeClass) \ - ENTER_V8_HELPER_DO_NOT_USE(isolate, context, class_name, function_name, \ - bailout_value, HandleScopeClass, false); \ - i::DisallowJavascriptExecutionDebugOnly __no_script__((isolate)) + ENTER_V8_HELPER_INTERNAL(i_isolate, context, class_name, function_name, \ + bailout_value, HandleScopeClass, false); \ + i::DisallowJavascriptExecutionDebugOnly __no_script__((i_isolate)) + +#define DCHECK_NO_SCRIPT_NO_EXCEPTION_MAYBE_TEARDOWN(i_isolate) \ + i::DisallowJavascriptExecutionDebugOnly __no_script__((i_isolate)); \ + i::DisallowExceptions __no_exceptions__((i_isolate)) // Lightweight version for APIs that don't require an active context. -#define ASSERT_NO_SCRIPT_NO_EXCEPTION(isolate) \ - i::DisallowJavascriptExecutionDebugOnly __no_script__((isolate)); \ - i::DisallowExceptions __no_exceptions__((isolate)) - -#define ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate) \ - i::VMState __state__((isolate)); \ - ASSERT_NO_SCRIPT_NO_EXCEPTION(isolate) - -#define ENTER_V8_FOR_NEW_CONTEXT(isolate) \ - i::VMState __state__((isolate)); \ - i::DisallowExceptions __no_exceptions__((isolate)) -#else -#define ENTER_V8_NO_SCRIPT(isolate, context, class_name, function_name, \ +#define DCHECK_NO_SCRIPT_NO_EXCEPTION(i_isolate) \ + /* Embedders should never enter V8 after terminating it */ \ + DCHECK(!i_isolate->is_execution_terminating()); \ + DCHECK_NO_SCRIPT_NO_EXCEPTION_MAYBE_TEARDOWN(i_isolate) + +#define ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate) \ + i::VMState __state__((i_isolate)); \ + DCHECK_NO_SCRIPT_NO_EXCEPTION(i_isolate) + +// Used instead of ENTER_V8_NO_SCRIPT_NO_EXCEPTION where the V8 Api is entered +// during termination sequences. +#define ENTER_V8_MAYBE_TEARDOWN(i_isolate) \ + i::VMState __state__((i_isolate)); \ + DCHECK_NO_SCRIPT_NO_EXCEPTION_MAYBE_TEARDOWN(i_isolate) + +#define ENTER_V8_FOR_NEW_CONTEXT(i_isolate) \ + DCHECK(!(i_isolate)->is_execution_terminating()); \ + i::VMState __state__((i_isolate)); \ + i::DisallowExceptions __no_exceptions__((i_isolate)) +#else // DEBUG +#define ENTER_V8_NO_SCRIPT(i_isolate, context, class_name, function_name, \ bailout_value, HandleScopeClass) \ - ENTER_V8_HELPER_DO_NOT_USE(isolate, context, class_name, function_name, \ - bailout_value, HandleScopeClass, false) + ENTER_V8_HELPER_INTERNAL(i_isolate, context, class_name, function_name, \ + bailout_value, HandleScopeClass, false) + +#define DCHECK_NO_SCRIPT_NO_EXCEPTION(i_isolate) +#define DCHECK_NO_SCRIPT_NO_EXCEPTION_MAYBE_TEARDOWN(i_isolate) -#define ASSERT_NO_SCRIPT_NO_EXCEPTION(isolate) +#define ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate) \ + i::VMState __state__((i_isolate)); -#define ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate) \ - i::VMState __state__((isolate)); +#define ENTER_V8_MAYBE_TEARDOWN(i_isolate) \ + i::VMState __state__((i_isolate)); -#define ENTER_V8_FOR_NEW_CONTEXT(isolate) \ - i::VMState __state__((isolate)); +#define ENTER_V8_FOR_NEW_CONTEXT(i_isolate) \ + i::VMState __state__((i_isolate)); #endif // DEBUG -#define EXCEPTION_BAILOUT_CHECK_SCOPED_DO_NOT_USE(isolate, value) \ - do { \ - if (has_pending_exception) { \ - call_depth_scope.Escape(); \ - return value; \ - } \ +#define EXCEPTION_BAILOUT_CHECK_SCOPED_DO_NOT_USE(i_isolate, value) \ + do { \ + if (has_pending_exception) { \ + call_depth_scope.Escape(); \ + return value; \ + } \ } while (false) #define RETURN_ON_FAILED_EXECUTION(T) \ - EXCEPTION_BAILOUT_CHECK_SCOPED_DO_NOT_USE(isolate, MaybeLocal()) + EXCEPTION_BAILOUT_CHECK_SCOPED_DO_NOT_USE(i_isolate, MaybeLocal()) #define RETURN_ON_FAILED_EXECUTION_PRIMITIVE(T) \ - EXCEPTION_BAILOUT_CHECK_SCOPED_DO_NOT_USE(isolate, Nothing()) + EXCEPTION_BAILOUT_CHECK_SCOPED_DO_NOT_USE(i_isolate, Nothing()) #define RETURN_ESCAPED(value) return handle_scope.Escape(value); diff --git a/deps/v8/src/api/api-natives.cc b/deps/v8/src/api/api-natives.cc index 29b94d8dea1d71..562b7849b4061d 100644 --- a/deps/v8/src/api/api-natives.cc +++ b/deps/v8/src/api/api-natives.cc @@ -4,15 +4,12 @@ #include "src/api/api-natives.h" -#include "src/api/api-inl.h" #include "src/common/message-template.h" #include "src/execution/isolate-inl.h" #include "src/heap/heap-inl.h" #include "src/logging/runtime-call-stats-scope.h" #include "src/objects/api-callbacks.h" -#include "src/objects/hash-table-inl.h" #include "src/objects/lookup.h" -#include "src/objects/property-cell.h" #include "src/objects/templates.h" namespace v8 { diff --git a/deps/v8/src/api/api-natives.h b/deps/v8/src/api/api-natives.h index 38a8a7b9171e7c..034aad830c4186 100644 --- a/deps/v8/src/api/api-natives.h +++ b/deps/v8/src/api/api-natives.h @@ -6,7 +6,6 @@ #define V8_API_API_NATIVES_H_ #include "include/v8-template.h" -#include "src/base/macros.h" #include "src/handles/handles.h" #include "src/handles/maybe-handles.h" #include "src/objects/objects.h" diff --git a/deps/v8/src/api/api.cc b/deps/v8/src/api/api.cc index 580ba47f1a727d..608da3369fabaf 100644 --- a/deps/v8/src/api/api.cc +++ b/deps/v8/src/api/api.cc @@ -30,6 +30,7 @@ #include "src/api/api-natives.h" #include "src/base/functional.h" #include "src/base/logging.h" +#include "src/base/platform/memory.h" #include "src/base/platform/platform.h" #include "src/base/platform/time.h" #include "src/base/safe_conversions.h" @@ -61,6 +62,7 @@ #include "src/execution/vm-state-inl.h" #include "src/handles/global-handles.h" #include "src/handles/persistent-handles.h" +#include "src/handles/shared-object-conveyor-handles.h" #include "src/heap/embedder-tracing.h" #include "src/heap/heap-inl.h" #include "src/heap/heap-write-barrier.h" @@ -140,9 +142,13 @@ #if V8_OS_LINUX || V8_OS_DARWIN || V8_OS_FREEBSD #include + +#if V8_ENABLE_WEBASSEMBLY #include "include/v8-wasm-trap-handler-posix.h" #include "src/trap-handler/handler-inside-posix.h" -#endif +#endif // V8_ENABLE_WEBASSEMBLY + +#endif // V8_OS_LINUX || V8_OS_DARWIN || V8_OS_FREEBSD #if V8_OS_WIN #include @@ -158,31 +164,30 @@ #endif // V8_OS_WIN64 #endif // V8_OS_WIN +#if defined(V8_OS_WIN) && defined(V8_ENABLE_ETW_STACK_WALKING) +#include "src/diagnostics/etw-jit-win.h" +#endif + // Has to be the last include (doesn't have include guards): #include "src/api/api-macros.h" -#define TRACE_BS(...) \ - do { \ - if (i::FLAG_trace_backing_store) PrintF(__VA_ARGS__); \ - } while (false) - namespace v8 { static OOMErrorCallback g_oom_error_callback = nullptr; -static ScriptOrigin GetScriptOriginForScript(i::Isolate* isolate, +static ScriptOrigin GetScriptOriginForScript(i::Isolate* i_isolate, i::Handle script) { - i::Handle scriptName(script->GetNameOrSourceURL(), isolate); - i::Handle source_map_url(script->source_mapping_url(), isolate); + i::Handle scriptName(script->GetNameOrSourceURL(), i_isolate); + i::Handle source_map_url(script->source_mapping_url(), i_isolate); i::Handle host_defined_options(script->host_defined_options(), - isolate); + i_isolate); ScriptOriginOptions options(script->origin_options()); bool is_wasm = false; #if V8_ENABLE_WEBASSEMBLY is_wasm = script->type() == i::Script::TYPE_WASM; #endif // V8_ENABLE_WEBASSEMBLY v8::ScriptOrigin origin( - reinterpret_cast(isolate), Utils::ToLocal(scriptName), + reinterpret_cast(i_isolate), Utils::ToLocal(scriptName), script->line_offset(), script->column_offset(), options.IsSharedCrossOrigin(), script->id(), Utils::ToLocal(source_map_url), options.IsOpaque(), is_wasm, @@ -190,36 +195,21 @@ static ScriptOrigin GetScriptOriginForScript(i::Isolate* isolate, return origin; } -Local ScriptOrigin::HostDefinedOptions() const { - // TODO(cbruni, chromium:1244145): remove once migrated to the context. - Utils::ApiCheck(!host_defined_options_->IsFixedArray(), - "ScriptOrigin::HostDefinedOptions", - "HostDefinedOptions is not a PrimitiveArray, please use " - "ScriptOrigin::GetHostDefinedOptions()"); - i::Handle options = - Utils::OpenHandle(*host_defined_options_.As()); - return Utils::PrimitiveArrayToLocal(options); -} - // --- E x c e p t i o n B e h a v i o r --- -void i::FatalProcessOutOfMemory(i::Isolate* isolate, const char* location) { - i::V8::FatalProcessOutOfMemory(isolate, location, false); -} - // When V8 cannot allocate memory FatalProcessOutOfMemory is called. The default // OOM error handler is called and execution is stopped. -void i::V8::FatalProcessOutOfMemory(i::Isolate* isolate, const char* location, - bool is_heap_oom) { +void i::V8::FatalProcessOutOfMemory(i::Isolate* i_isolate, const char* location, + const OOMDetails& details) { char last_few_messages[Heap::kTraceRingBufferSize + 1]; char js_stacktrace[Heap::kStacktraceBufferSize + 1]; i::HeapStats heap_stats; - if (isolate == nullptr) { - isolate = Isolate::TryGetCurrent(); + if (i_isolate == nullptr) { + i_isolate = Isolate::TryGetCurrent(); } - if (isolate == nullptr) { + if (i_isolate == nullptr) { // If the Isolate is not available for the current thread we cannot retrieve // memory information from the Isolate. Write easy-to-recognize values on // the stack. @@ -228,7 +218,7 @@ void i::V8::FatalProcessOutOfMemory(i::Isolate* isolate, const char* location, memset(&heap_stats, 0xBADC0DE, sizeof(heap_stats)); // Give the embedder a chance to handle the condition. If it doesn't, // just crash. - if (g_oom_error_callback) g_oom_error_callback(location, is_heap_oom); + if (g_oom_error_callback) g_oom_error_callback(location, details); FATAL("Fatal process out of memory: %s", location); UNREACHABLE(); } @@ -290,10 +280,10 @@ void i::V8::FatalProcessOutOfMemory(i::Isolate* isolate, const char* location, heap_stats.js_stacktrace = js_stacktrace; intptr_t end_marker; heap_stats.end_marker = &end_marker; - if (isolate->heap()->HasBeenSetUp()) { + if (i_isolate->heap()->HasBeenSetUp()) { // BUG(1718): Don't use the take_snapshot since we don't support // HeapObjectIterator here without doing a special GC. - isolate->heap()->RecordStats(&heap_stats, false); + i_isolate->heap()->RecordStats(&heap_stats, false); if (!FLAG_correctness_fuzzer_suppressions) { char* first_newline = strchr(last_few_messages, '\n'); if (first_newline == nullptr || first_newline[1] == '\0') @@ -302,17 +292,24 @@ void i::V8::FatalProcessOutOfMemory(i::Isolate* isolate, const char* location, base::OS::PrintError("\n<--- JS stacktrace --->\n%s\n", js_stacktrace); } } - Utils::ReportOOMFailure(isolate, location, is_heap_oom); - if (g_oom_error_callback) g_oom_error_callback(location, is_heap_oom); + Utils::ReportOOMFailure(i_isolate, location, details); + if (g_oom_error_callback) g_oom_error_callback(location, details); // If the fatal error handler returns, we stop execution. FATAL("API fatal error handler returned after process out of memory"); } +void i::V8::FatalProcessOutOfMemory(i::Isolate* i_isolate, const char* location, + const char* detail) { + OOMDetails details; + details.detail = detail; + FatalProcessOutOfMemory(i_isolate, location, details); +} + void Utils::ReportApiFailure(const char* location, const char* message) { - i::Isolate* isolate = i::Isolate::TryGetCurrent(); + i::Isolate* i_isolate = i::Isolate::TryGetCurrent(); FatalErrorCallback callback = nullptr; - if (isolate != nullptr) { - callback = isolate->exception_behavior(); + if (i_isolate != nullptr) { + callback = i_isolate->exception_behavior(); } if (callback == nullptr) { base::OS::PrintError("\n#\n# Fatal error in %s\n# %s\n#\n\n", location, @@ -321,34 +318,36 @@ void Utils::ReportApiFailure(const char* location, const char* message) { } else { callback(location, message); } - isolate->SignalFatalError(); + i_isolate->SignalFatalError(); } -void Utils::ReportOOMFailure(i::Isolate* isolate, const char* location, - bool is_heap_oom) { - OOMErrorCallback oom_callback = isolate->oom_behavior(); - if (oom_callback == nullptr) { +void Utils::ReportOOMFailure(i::Isolate* i_isolate, const char* location, + const OOMDetails& details) { + if (auto oom_callback = i_isolate->oom_behavior()) { + oom_callback(location, details); + } else { // TODO(wfh): Remove this fallback once Blink is setting OOM handler. See // crbug.com/614440. - FatalErrorCallback fatal_callback = isolate->exception_behavior(); + FatalErrorCallback fatal_callback = i_isolate->exception_behavior(); if (fatal_callback == nullptr) { base::OS::PrintError("\n#\n# Fatal %s OOM in %s\n#\n\n", - is_heap_oom ? "javascript" : "process", location); + details.is_heap_oom ? "javascript" : "process", + location); #ifdef V8_FUZZILLI - exit(0); + // Ignore OOM crashes for fuzzing but exit with an error such that + // samples are discarded by Fuzzilli. + exit(1); #else base::OS::Abort(); #endif // V8_FUZZILLI } else { fatal_callback(location, - is_heap_oom + details.is_heap_oom ? "Allocation failed - JavaScript heap out of memory" : "Allocation failed - process out of memory"); } - } else { - oom_callback(location, is_heap_oom); } - isolate->SignalFatalError(); + i_isolate->SignalFatalError(); } void V8::SetSnapshotDataBlob(StartupData* snapshot_blob) { @@ -357,7 +356,7 @@ void V8::SetSnapshotDataBlob(StartupData* snapshot_blob) { namespace { -#ifdef V8_SANDBOXED_POINTERS +#ifdef V8_ENABLE_SANDBOX // ArrayBufferAllocator to use when sandboxed pointers are used in which case // all ArrayBuffer backing stores need to be allocated inside the sandbox. // Note, the current implementation is extremely inefficient as it uses the @@ -390,38 +389,16 @@ class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator { class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator { public: - void* Allocate(size_t length) override { -#if V8_OS_AIX && _LINUX_SOURCE_COMPAT - // Work around for GCC bug on AIX - // See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79839 - void* data = __linux_calloc(length, 1); -#else - void* data = base::Calloc(length, 1); -#endif - return data; - } + void* Allocate(size_t length) override { return base::Calloc(length, 1); } void* AllocateUninitialized(size_t length) override { -#if V8_OS_AIX && _LINUX_SOURCE_COMPAT - // Work around for GCC bug on AIX - // See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79839 - void* data = __linux_malloc(length); -#else - void* data = base::Malloc(length); -#endif - return data; + return base::Malloc(length); } void Free(void* data, size_t) override { base::Free(data); } void* Reallocate(void* data, size_t old_length, size_t new_length) override { -#if V8_OS_AIX && _LINUX_SOURCE_COMPAT - // Work around for GCC bug on AIX - // See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79839 - void* new_data = __linux_realloc(data, new_length); -#else void* new_data = base::Realloc(data, new_length); -#endif if (new_length > old_length) { memset(reinterpret_cast(new_data) + old_length, 0, new_length - old_length); @@ -429,14 +406,10 @@ class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator { return new_data; } }; -#endif // V8_SANDBOXED_POINTERS +#endif // V8_ENABLE_SANDBOX struct SnapshotCreatorData { - explicit SnapshotCreatorData(Isolate* isolate) - : isolate_(isolate), - default_context_(), - contexts_(isolate), - created_(false) {} + explicit SnapshotCreatorData(Isolate* v8_isolate) : isolate_(v8_isolate) {} static SnapshotCreatorData* cast(void* data) { return reinterpret_cast(data); @@ -446,34 +419,34 @@ struct SnapshotCreatorData { Isolate* isolate_; Persistent default_context_; SerializeInternalFieldsCallback default_embedder_fields_serializer_; - PersistentValueVector contexts_; + std::vector> contexts_; std::vector embedder_fields_serializers_; - bool created_; + bool created_ = false; }; } // namespace -SnapshotCreator::SnapshotCreator(Isolate* isolate, +SnapshotCreator::SnapshotCreator(Isolate* v8_isolate, const intptr_t* external_references, StartupData* existing_snapshot) { - SnapshotCreatorData* data = new SnapshotCreatorData(isolate); - i::Isolate* internal_isolate = reinterpret_cast(isolate); - internal_isolate->set_array_buffer_allocator(&data->allocator_); - internal_isolate->set_api_external_references(external_references); - internal_isolate->enable_serializer(); - isolate->Enter(); + SnapshotCreatorData* data = new SnapshotCreatorData(v8_isolate); + i::Isolate* i_isolate = reinterpret_cast(v8_isolate); + i_isolate->set_array_buffer_allocator(&data->allocator_); + i_isolate->set_api_external_references(external_references); + i_isolate->enable_serializer(); + v8_isolate->Enter(); const StartupData* blob = existing_snapshot ? existing_snapshot : i::Snapshot::DefaultSnapshotBlob(); if (blob && blob->raw_size > 0) { - internal_isolate->set_snapshot_blob(blob); - i::Snapshot::Initialize(internal_isolate); + i_isolate->set_snapshot_blob(blob); + i::Snapshot::Initialize(i_isolate); } else { - internal_isolate->InitWithoutSnapshot(); + i_isolate->InitWithoutSnapshot(); } data_ = data; // Disable batch compilation during snapshot creation. - internal_isolate->baseline_batch_compiler()->set_enabled(false); + i_isolate->baseline_batch_compiler()->set_enabled(false); } SnapshotCreator::SnapshotCreator(const intptr_t* external_references, @@ -483,9 +456,9 @@ SnapshotCreator::SnapshotCreator(const intptr_t* external_references, SnapshotCreator::~SnapshotCreator() { SnapshotCreatorData* data = SnapshotCreatorData::cast(data_); - Isolate* isolate = data->isolate_; - isolate->Exit(); - isolate->Dispose(); + Isolate* v8_isolate = data->isolate_; + v8_isolate->Exit(); + v8_isolate->Dispose(); delete data; } @@ -499,9 +472,9 @@ void SnapshotCreator::SetDefaultContext( SnapshotCreatorData* data = SnapshotCreatorData::cast(data_); DCHECK(!data->created_); DCHECK(data->default_context_.IsEmpty()); - Isolate* isolate = data->isolate_; - CHECK_EQ(isolate, context->GetIsolate()); - data->default_context_.Reset(isolate, context); + Isolate* v8_isolate = data->isolate_; + CHECK_EQ(v8_isolate, context->GetIsolate()); + data->default_context_.Reset(v8_isolate, context); data->default_embedder_fields_serializer_ = callback; } @@ -510,10 +483,10 @@ size_t SnapshotCreator::AddContext(Local context, DCHECK(!context.IsEmpty()); SnapshotCreatorData* data = SnapshotCreatorData::cast(data_); DCHECK(!data->created_); - Isolate* isolate = data->isolate_; - CHECK_EQ(isolate, context->GetIsolate()); - size_t index = data->contexts_.Size(); - data->contexts_.Append(context); + Isolate* v8_isolate = data->isolate_; + CHECK_EQ(v8_isolate, context->GetIsolate()); + size_t index = data->contexts_.size(); + data->contexts_.emplace_back(v8_isolate, context); data->embedder_fields_serializers_.push_back(callback); return index; } @@ -522,19 +495,19 @@ size_t SnapshotCreator::AddData(i::Address object) { DCHECK_NE(object, i::kNullAddress); SnapshotCreatorData* data = SnapshotCreatorData::cast(data_); DCHECK(!data->created_); - i::Isolate* isolate = reinterpret_cast(data->isolate_); - i::HandleScope scope(isolate); - i::Handle obj(i::Object(object), isolate); + i::Isolate* i_isolate = reinterpret_cast(data->isolate_); + i::HandleScope scope(i_isolate); + i::Handle obj(i::Object(object), i_isolate); i::Handle list; - if (!isolate->heap()->serialized_objects().IsArrayList()) { - list = i::ArrayList::New(isolate, 1); + if (!i_isolate->heap()->serialized_objects().IsArrayList()) { + list = i::ArrayList::New(i_isolate, 1); } else { list = i::Handle( - i::ArrayList::cast(isolate->heap()->serialized_objects()), isolate); + i::ArrayList::cast(i_isolate->heap()->serialized_objects()), i_isolate); } size_t index = static_cast(list->Length()); - list = i::ArrayList::Add(isolate, list, obj); - isolate->heap()->SetSerializedObjects(*list); + list = i::ArrayList::Add(i_isolate, list, obj); + i_isolate->heap()->SetSerializedObjects(*list); return index; } @@ -542,18 +515,18 @@ size_t SnapshotCreator::AddData(Local context, i::Address object) { DCHECK_NE(object, i::kNullAddress); DCHECK(!SnapshotCreatorData::cast(data_)->created_); i::Handle ctx = Utils::OpenHandle(*context); - i::Isolate* isolate = ctx->GetIsolate(); - i::HandleScope scope(isolate); - i::Handle obj(i::Object(object), isolate); + i::Isolate* i_isolate = ctx->GetIsolate(); + i::HandleScope scope(i_isolate); + i::Handle obj(i::Object(object), i_isolate); i::Handle list; if (!ctx->serialized_objects().IsArrayList()) { - list = i::ArrayList::New(isolate, 1); + list = i::ArrayList::New(i_isolate, 1); } else { list = i::Handle( - i::ArrayList::cast(ctx->serialized_objects()), isolate); + i::ArrayList::cast(ctx->serialized_objects()), i_isolate); } size_t index = static_cast(list->Length()); - list = i::ArrayList::Add(isolate, list, obj); + list = i::ArrayList::Add(i_isolate, list, obj); ctx->set_serialized_objects(*list); return index; } @@ -561,26 +534,27 @@ size_t SnapshotCreator::AddData(Local context, i::Address object) { namespace { void ConvertSerializedObjectsToFixedArray(Local context) { i::Handle ctx = Utils::OpenHandle(*context); - i::Isolate* isolate = ctx->GetIsolate(); + i::Isolate* i_isolate = ctx->GetIsolate(); if (!ctx->serialized_objects().IsArrayList()) { - ctx->set_serialized_objects(i::ReadOnlyRoots(isolate).empty_fixed_array()); + ctx->set_serialized_objects( + i::ReadOnlyRoots(i_isolate).empty_fixed_array()); } else { i::Handle list(i::ArrayList::cast(ctx->serialized_objects()), - isolate); - i::Handle elements = i::ArrayList::Elements(isolate, list); + i_isolate); + i::Handle elements = i::ArrayList::Elements(i_isolate, list); ctx->set_serialized_objects(*elements); } } -void ConvertSerializedObjectsToFixedArray(i::Isolate* isolate) { - if (!isolate->heap()->serialized_objects().IsArrayList()) { - isolate->heap()->SetSerializedObjects( - i::ReadOnlyRoots(isolate).empty_fixed_array()); +void ConvertSerializedObjectsToFixedArray(i::Isolate* i_isolate) { + if (!i_isolate->heap()->serialized_objects().IsArrayList()) { + i_isolate->heap()->SetSerializedObjects( + i::ReadOnlyRoots(i_isolate).empty_fixed_array()); } else { i::Handle list( - i::ArrayList::cast(isolate->heap()->serialized_objects()), isolate); - i::Handle elements = i::ArrayList::Elements(isolate, list); - isolate->heap()->SetSerializedObjects(*elements); + i::ArrayList::cast(i_isolate->heap()->serialized_objects()), i_isolate); + i::Handle elements = i::ArrayList::Elements(i_isolate, list); + i_isolate->heap()->SetSerializedObjects(*elements); } } } // anonymous namespace @@ -588,61 +562,61 @@ void ConvertSerializedObjectsToFixedArray(i::Isolate* isolate) { StartupData SnapshotCreator::CreateBlob( SnapshotCreator::FunctionCodeHandling function_code_handling) { SnapshotCreatorData* data = SnapshotCreatorData::cast(data_); - i::Isolate* isolate = reinterpret_cast(data->isolate_); + Isolate* isolate = data->isolate_; + i::Isolate* i_isolate = reinterpret_cast(isolate); Utils::ApiCheck(!data->created_, "v8::SnapshotCreator::CreateBlob", "CreateBlob() cannot be called more than once on the same " - "SnapshotCreator."); + "SnapshotCreator"); Utils::ApiCheck( !data->default_context_.IsEmpty(), "v8::SnapshotCreator::CreateBlob", - "CreateBlob() cannot be called before the default context is set."); - - const int num_additional_contexts = static_cast(data->contexts_.Size()); + "CreateBlob() cannot be called before the default context is set"); + const int num_additional_contexts = static_cast(data->contexts_.size()); const int num_contexts = num_additional_contexts + 1; // The default context. // Create and store lists of embedder-provided data needed during // serialization. { - i::HandleScope scope(isolate); + i::HandleScope scope(i_isolate); // Convert list of context-independent data to FixedArray. - ConvertSerializedObjectsToFixedArray(isolate); + ConvertSerializedObjectsToFixedArray(i_isolate); // Convert lists of context-dependent data to FixedArray. ConvertSerializedObjectsToFixedArray( data->default_context_.Get(data->isolate_)); for (int i = 0; i < num_additional_contexts; i++) { - ConvertSerializedObjectsToFixedArray(data->contexts_.Get(i)); + ConvertSerializedObjectsToFixedArray(data->contexts_[i].Get(isolate)); } // We need to store the global proxy size upfront in case we need the // bootstrapper to create a global proxy before we deserialize the context. i::Handle global_proxy_sizes = - isolate->factory()->NewFixedArray(num_additional_contexts, - i::AllocationType::kOld); + i_isolate->factory()->NewFixedArray(num_additional_contexts, + i::AllocationType::kOld); for (int i = 0; i < num_additional_contexts; i++) { i::Handle context = - v8::Utils::OpenHandle(*data->contexts_.Get(i)); + v8::Utils::OpenHandle(*data->contexts_[i].Get(isolate)); global_proxy_sizes->set(i, i::Smi::FromInt(context->global_proxy().Size())); } - isolate->heap()->SetSerializedGlobalProxySizes(*global_proxy_sizes); + i_isolate->heap()->SetSerializedGlobalProxySizes(*global_proxy_sizes); } // We might rehash strings and re-sort descriptors. Clear the lookup cache. - isolate->descriptor_lookup_cache()->Clear(); + i_isolate->descriptor_lookup_cache()->Clear(); // If we don't do this then we end up with a stray root pointing at the // context even after we have disposed of the context. - isolate->heap()->CollectAllAvailableGarbage( + i_isolate->heap()->CollectAllAvailableGarbage( i::GarbageCollectionReason::kSnapshotCreator); { - i::HandleScope scope(isolate); - isolate->heap()->CompactWeakArrayLists(); + i::HandleScope scope(i_isolate); + i_isolate->heap()->CompactWeakArrayLists(); } i::Snapshot::ClearReconstructableDataForSerialization( - isolate, function_code_handling == FunctionCodeHandling::kClear); + i_isolate, function_code_handling == FunctionCodeHandling::kClear); - i::GlobalSafepointScope global_safepoint(isolate); + i::GlobalSafepointScope global_safepoint(i_isolate); i::DisallowGarbageCollection no_gc_from_here_on; // Create a vector with all contexts and clear associated Persistent fields. @@ -652,20 +626,20 @@ StartupData SnapshotCreator::CreateBlob( std::vector contexts; contexts.reserve(num_contexts); { - i::HandleScope scope(isolate); + i::HandleScope scope(i_isolate); contexts.push_back( *v8::Utils::OpenHandle(*data->default_context_.Get(data->isolate_))); data->default_context_.Reset(); for (int i = 0; i < num_additional_contexts; i++) { i::Handle context = - v8::Utils::OpenHandle(*data->contexts_.Get(i)); + v8::Utils::OpenHandle(*data->contexts_[i].Get(isolate)); contexts.push_back(*context); } - data->contexts_.Clear(); + data->contexts_.clear(); } // Check that values referenced by global/eternal handles are accounted for. - i::SerializedHandleChecker handle_checker(isolate, &contexts); + i::SerializedHandleChecker handle_checker(i_isolate, &contexts); CHECK(handle_checker.CheckGlobalAndEternalHandles()); // Create a vector with all embedder fields serializers. @@ -679,7 +653,7 @@ StartupData SnapshotCreator::CreateBlob( } data->created_ = true; - return i::Snapshot::Create(isolate, &contexts, embedder_fields_serializers, + return i::Snapshot::Create(i_isolate, &contexts, embedder_fields_serializers, global_safepoint, no_gc_from_here_on); } @@ -810,19 +784,19 @@ void ResourceConstraints::ConfigureDefaults(uint64_t physical_memory, namespace internal { -i::Address* GlobalizeTracedReference(i::Isolate* isolate, i::Address* obj, +i::Address* GlobalizeTracedReference(i::Isolate* i_isolate, i::Address* obj, internal::Address* slot, GlobalHandleStoreMode store_mode) { - API_RCS_SCOPE(isolate, TracedGlobal, New); + API_RCS_SCOPE(i_isolate, TracedGlobal, New); #ifdef DEBUG Utils::ApiCheck((slot != nullptr), "v8::GlobalizeTracedReference", "the address slot must be not null"); #endif i::Handle result = - isolate->global_handles()->CreateTraced(*obj, slot, store_mode); + i_isolate->global_handles()->CreateTraced(*obj, slot, store_mode); #ifdef VERIFY_HEAP if (i::FLAG_verify_heap) { - i::Object(*obj).ObjectVerify(isolate); + i::Object(*obj).ObjectVerify(i_isolate); } #endif // VERIFY_HEAP return result.location(); @@ -845,12 +819,12 @@ void DisposeTracedReference(internal::Address* location) { namespace api_internal { -i::Address* GlobalizeReference(i::Isolate* isolate, i::Address* obj) { - API_RCS_SCOPE(isolate, Persistent, New); - i::Handle result = isolate->global_handles()->Create(*obj); +i::Address* GlobalizeReference(i::Isolate* i_isolate, i::Address* obj) { + API_RCS_SCOPE(i_isolate, Persistent, New); + i::Handle result = i_isolate->global_handles()->Create(*obj); #ifdef VERIFY_HEAP if (i::FLAG_verify_heap) { - i::Object(*obj).ObjectVerify(isolate); + i::Object(*obj).ObjectVerify(i_isolate); } #endif // VERIFY_HEAP return result.location(); @@ -888,56 +862,55 @@ void DisposeGlobal(i::Address* location) { } Value* Eternalize(Isolate* v8_isolate, Value* value) { - i::Isolate* isolate = reinterpret_cast(v8_isolate); + i::Isolate* i_isolate = reinterpret_cast(v8_isolate); i::Object object = *Utils::OpenHandle(value); int index = -1; - isolate->eternal_handles()->Create(isolate, object, &index); + i_isolate->eternal_handles()->Create(i_isolate, object, &index); return reinterpret_cast( - isolate->eternal_handles()->Get(index).location()); + i_isolate->eternal_handles()->Get(index).location()); } void FromJustIsNothing() { - Utils::ApiCheck(false, "v8::FromJust", "Maybe value is Nothing."); + Utils::ApiCheck(false, "v8::FromJust", "Maybe value is Nothing"); } void ToLocalEmpty() { - Utils::ApiCheck(false, "v8::ToLocalChecked", "Empty MaybeLocal."); + Utils::ApiCheck(false, "v8::ToLocalChecked", "Empty MaybeLocal"); } void InternalFieldOutOfBounds(int index) { Utils::ApiCheck(0 <= index && index < kInternalFieldsInWeakCallback, "WeakCallbackInfo::GetInternalField", - "Internal field out of bounds."); + "Internal field out of bounds"); } } // namespace api_internal // --- H a n d l e s --- -HandleScope::HandleScope(Isolate* isolate) { Initialize(isolate); } +HandleScope::HandleScope(Isolate* v8_isolate) { Initialize(v8_isolate); } -void HandleScope::Initialize(Isolate* isolate) { - i::Isolate* internal_isolate = reinterpret_cast(isolate); +void HandleScope::Initialize(Isolate* v8_isolate) { + i::Isolate* i_isolate = reinterpret_cast(v8_isolate); // We do not want to check the correct usage of the Locker class all over the // place, so we do it only here: Without a HandleScope, an embedder can do // almost nothing, so it is enough to check in this central place. // We make an exception if the serializer is enabled, which means that the // Isolate is exclusively used to create a snapshot. - Utils::ApiCheck( - !internal_isolate->was_locker_ever_used() || - internal_isolate->thread_manager()->IsLockedByCurrentThread() || - internal_isolate->serializer_enabled(), - "HandleScope::HandleScope", - "Entering the V8 API without proper locking in place"); - i::HandleScopeData* current = internal_isolate->handle_scope_data(); - isolate_ = internal_isolate; + Utils::ApiCheck(!i_isolate->was_locker_ever_used() || + i_isolate->thread_manager()->IsLockedByCurrentThread() || + i_isolate->serializer_enabled(), + "HandleScope::HandleScope", + "Entering the V8 API without proper locking in place"); + i::HandleScopeData* current = i_isolate->handle_scope_data(); + i_isolate_ = i_isolate; prev_next_ = current->next; prev_limit_ = current->limit; current->level++; } HandleScope::~HandleScope() { - i::HandleScope::CloseScope(isolate_, prev_next_, prev_limit_); + i::HandleScope::CloseScope(i_isolate_, prev_next_, prev_limit_); } void* HandleScope::operator new(size_t) { base::OS::Abort(); } @@ -945,19 +918,19 @@ void* HandleScope::operator new[](size_t) { base::OS::Abort(); } void HandleScope::operator delete(void*, size_t) { base::OS::Abort(); } void HandleScope::operator delete[](void*, size_t) { base::OS::Abort(); } -int HandleScope::NumberOfHandles(Isolate* isolate) { +int HandleScope::NumberOfHandles(Isolate* v8_isolate) { return i::HandleScope::NumberOfHandles( - reinterpret_cast(isolate)); + reinterpret_cast(v8_isolate)); } -i::Address* HandleScope::CreateHandle(i::Isolate* isolate, i::Address value) { - return i::HandleScope::CreateHandle(isolate, value); +i::Address* HandleScope::CreateHandle(i::Isolate* i_isolate, i::Address value) { + return i::HandleScope::CreateHandle(i_isolate, value); } EscapableHandleScope::EscapableHandleScope(Isolate* v8_isolate) { - i::Isolate* isolate = reinterpret_cast(v8_isolate); - escape_slot_ = - CreateHandle(isolate, i::ReadOnlyRoots(isolate).the_hole_value().ptr()); + i::Isolate* i_isolate = reinterpret_cast(v8_isolate); + escape_slot_ = CreateHandle( + i_isolate, i::ReadOnlyRoots(i_isolate).the_hole_value().ptr()); Initialize(v8_isolate); } @@ -980,9 +953,9 @@ void EscapableHandleScope::operator delete[](void*, size_t) { base::OS::Abort(); } -SealHandleScope::SealHandleScope(Isolate* isolate) - : isolate_(reinterpret_cast(isolate)) { - i::HandleScopeData* current = isolate_->handle_scope_data(); +SealHandleScope::SealHandleScope(Isolate* v8_isolate) + : i_isolate_(reinterpret_cast(v8_isolate)) { + i::HandleScopeData* current = i_isolate_->handle_scope_data(); prev_limit_ = current->limit; current->limit = current->next; prev_sealed_level_ = current->sealed_level; @@ -990,7 +963,7 @@ SealHandleScope::SealHandleScope(Isolate* isolate) } SealHandleScope::~SealHandleScope() { - i::HandleScopeData* current = isolate_->handle_scope_data(); + i::HandleScopeData* current = i_isolate_->handle_scope_data(); DCHECK_EQ(current->next, current->limit); current->limit = prev_limit_; DCHECK_EQ(current->level, current->sealed_level); @@ -1034,26 +1007,30 @@ bool Data::IsFunctionTemplate() const { bool Data::IsContext() const { return Utils::OpenHandle(this)->IsContext(); } void Context::Enter() { - i::Handle env = Utils::OpenHandle(this); - i::Isolate* isolate = env->GetIsolate(); - ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); - i::HandleScopeImplementer* impl = isolate->handle_scope_implementer(); - impl->EnterContext(*env); - impl->SaveContext(isolate->context()); - isolate->set_context(*env); + i::DisallowGarbageCollection no_gc; + i::Context env = *Utils::OpenHandle(this); + i::Isolate* i_isolate = env.GetIsolate(); + // TODO(cbruni): Use ENTER_V8_NO_SCRIPT_NO_EXCEPTION which also checks + // Isolate::is_execution_terminating + // ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); + ENTER_V8_MAYBE_TEARDOWN(i_isolate); + i::HandleScopeImplementer* impl = i_isolate->handle_scope_implementer(); + impl->EnterContext(env); + impl->SaveContext(i_isolate->context()); + i_isolate->set_context(env); } void Context::Exit() { i::Handle env = Utils::OpenHandle(this); - i::Isolate* isolate = env->GetIsolate(); - ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); - i::HandleScopeImplementer* impl = isolate->handle_scope_implementer(); + i::Isolate* i_isolate = env->GetIsolate(); + ENTER_V8_MAYBE_TEARDOWN(i_isolate); + i::HandleScopeImplementer* impl = i_isolate->handle_scope_implementer(); if (!Utils::ApiCheck(impl->LastEnteredContextWas(*env), "v8::Context::Exit()", "Cannot exit non-entered context")) { return; } impl->LeaveContext(); - isolate->set_context(impl->RestoreContext()); + i_isolate->set_context(impl->RestoreContext()); } Context::BackupIncumbentScope::BackupIncumbentScope( @@ -1062,52 +1039,54 @@ Context::BackupIncumbentScope::BackupIncumbentScope( DCHECK(!backup_incumbent_context_.IsEmpty()); i::Handle env = Utils::OpenHandle(*backup_incumbent_context_); - i::Isolate* isolate = env->GetIsolate(); + i::Isolate* i_isolate = env->GetIsolate(); js_stack_comparable_address_ = - i::SimulatorStack::RegisterJSStackComparableAddress(isolate); + i::SimulatorStack::RegisterJSStackComparableAddress(i_isolate); - prev_ = isolate->top_backup_incumbent_scope(); - isolate->set_top_backup_incumbent_scope(this); + prev_ = i_isolate->top_backup_incumbent_scope(); + i_isolate->set_top_backup_incumbent_scope(this); } Context::BackupIncumbentScope::~BackupIncumbentScope() { i::Handle env = Utils::OpenHandle(*backup_incumbent_context_); - i::Isolate* isolate = env->GetIsolate(); + i::Isolate* i_isolate = env->GetIsolate(); - i::SimulatorStack::UnregisterJSStackComparableAddress(isolate); + i::SimulatorStack::UnregisterJSStackComparableAddress(i_isolate); - isolate->set_top_backup_incumbent_scope(prev_); + i_isolate->set_top_backup_incumbent_scope(prev_); } -STATIC_ASSERT(i::Internals::kEmbedderDataSlotSize == i::kEmbedderDataSlotSize); +static_assert(i::Internals::kEmbedderDataSlotSize == i::kEmbedderDataSlotSize); +static_assert(i::Internals::kEmbedderDataSlotExternalPointerOffset == + i::EmbedderDataSlot::kExternalPointerOffset); static i::Handle EmbedderDataFor(Context* context, int index, bool can_grow, const char* location) { i::Handle env = Utils::OpenHandle(context); - i::Isolate* isolate = env->GetIsolate(); - ASSERT_NO_SCRIPT_NO_EXCEPTION(isolate); + i::Isolate* i_isolate = env->GetIsolate(); + DCHECK_NO_SCRIPT_NO_EXCEPTION_MAYBE_TEARDOWN(i_isolate); bool ok = Utils::ApiCheck(env->IsNativeContext(), location, "Not a native context") && Utils::ApiCheck(index >= 0, location, "Negative index"); if (!ok) return i::Handle(); // TODO(ishell): remove cast once embedder_data slot has a proper type. i::Handle data( - i::EmbedderDataArray::cast(env->embedder_data()), isolate); + i::EmbedderDataArray::cast(env->embedder_data()), i_isolate); if (index < data->length()) return data; if (!Utils::ApiCheck(can_grow && index < i::EmbedderDataArray::kMaxLength, location, "Index too large")) { return i::Handle(); } - data = i::EmbedderDataArray::EnsureCapacity(isolate, data, index); + data = i::EmbedderDataArray::EnsureCapacity(i_isolate, data, index); env->set_embedder_data(*data); return data; } uint32_t Context::GetNumberOfEmbedderDataFields() { i::Handle context = Utils::OpenHandle(this); - ASSERT_NO_SCRIPT_NO_EXCEPTION(context->GetIsolate()); + DCHECK_NO_SCRIPT_NO_EXCEPTION(context->GetIsolate()); Utils::ApiCheck(context->IsNativeContext(), "Context::GetNumberOfEmbedderDataFields", "Not a native context"); @@ -1121,9 +1100,9 @@ v8::Local Context::SlowGetEmbedderData(int index) { i::Handle data = EmbedderDataFor(this, index, false, location); if (data.is_null()) return Local(); - i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); + i::Isolate* i_isolate = Utils::OpenHandle(this)->GetIsolate(); i::Handle result(i::EmbedderDataSlot(*data, index).load_tagged(), - isolate); + i_isolate); return Utils::ToLocal(result); } @@ -1140,25 +1119,25 @@ void Context::SetEmbedderData(int index, v8::Local value) { void* Context::SlowGetAlignedPointerFromEmbedderData(int index) { const char* location = "v8::Context::GetAlignedPointerFromEmbedderData()"; - i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); - i::HandleScope handle_scope(isolate); + i::Isolate* i_isolate = Utils::OpenHandle(this)->GetIsolate(); + i::HandleScope handle_scope(i_isolate); i::Handle data = EmbedderDataFor(this, index, false, location); if (data.is_null()) return nullptr; void* result; Utils::ApiCheck( - i::EmbedderDataSlot(*data, index).ToAlignedPointer(isolate, &result), + i::EmbedderDataSlot(*data, index).ToAlignedPointer(i_isolate, &result), location, "Pointer is not aligned"); return result; } void Context::SetAlignedPointerInEmbedderData(int index, void* value) { const char* location = "v8::Context::SetAlignedPointerInEmbedderData()"; - i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); + i::Isolate* i_isolate = Utils::OpenHandle(this)->GetIsolate(); i::Handle data = EmbedderDataFor(this, index, true, location); bool ok = - i::EmbedderDataSlot(*data, index).store_aligned_pointer(isolate, value); + i::EmbedderDataSlot(*data, index).store_aligned_pointer(i_isolate, value); Utils::ApiCheck(ok, location, "Pointer is not aligned"); DCHECK_EQ(value, GetAlignedPointerFromEmbedderData(index)); } @@ -1177,9 +1156,9 @@ static void InitializeTemplate(i::TemplateInfo that, int type, void Template::Set(v8::Local name, v8::Local value, v8::PropertyAttribute attribute) { auto templ = Utils::OpenHandle(this); - i::Isolate* isolate = templ->GetIsolate(); - ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); - i::HandleScope scope(isolate); + i::Isolate* i_isolate = templ->GetIsolate(); + ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); + i::HandleScope scope(i_isolate); auto value_obj = Utils::OpenHandle(*value); Utils::ApiCheck(!value_obj->IsJSReceiver() || value_obj->IsTemplateInfo(), @@ -1193,7 +1172,7 @@ void Template::Set(v8::Local name, v8::Local value, templ->set_serial_number(i::TemplateInfo::kDoNotCache); } - i::ApiNatives::AddDataProperty(isolate, templ, Utils::OpenHandle(*name), + i::ApiNatives::AddDataProperty(i_isolate, templ, Utils::OpenHandle(*name), value_obj, static_cast(attribute)); } @@ -1209,16 +1188,25 @@ void Template::SetAccessorProperty(v8::Local name, v8::Local setter, v8::PropertyAttribute attribute, v8::AccessControl access_control) { + Utils::ApiCheck( + getter.IsEmpty() || + !Utils::OpenHandle(*getter)->call_code(kAcquireLoad).IsUndefined(), + "v8::Template::SetAccessorProperty", "Getter must have a call handler"); + Utils::ApiCheck( + setter.IsEmpty() || + !Utils::OpenHandle(*setter)->call_code(kAcquireLoad).IsUndefined(), + "v8::Template::SetAccessorProperty", "Setter must have a call handler"); + // TODO(verwaest): Remove |access_control|. DCHECK_EQ(v8::DEFAULT, access_control); auto templ = Utils::OpenHandle(this); - auto isolate = templ->GetIsolate(); - ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); + auto i_isolate = templ->GetIsolate(); + ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); DCHECK(!name.IsEmpty()); DCHECK(!getter.IsEmpty() || !setter.IsEmpty()); - i::HandleScope scope(isolate); + i::HandleScope scope(i_isolate); i::ApiNatives::AddAccessorProperty( - isolate, templ, Utils::OpenHandle(*name), + i_isolate, templ, Utils::OpenHandle(*name), Utils::OpenHandle(*getter, true), Utils::OpenHandle(*setter, true), static_cast(attribute)); } @@ -1230,9 +1218,29 @@ static void InitializeFunctionTemplate(i::FunctionTemplateInfo info, info.set_flag(0); } -static Local ObjectTemplateNew( - i::Isolate* isolate, v8::Local constructor, - bool do_not_cache); +namespace { +Local ObjectTemplateNew(i::Isolate* i_isolate, + v8::Local constructor, + bool do_not_cache) { + API_RCS_SCOPE(i_isolate, ObjectTemplate, New); + ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); + i::Handle struct_obj = i_isolate->factory()->NewStruct( + i::OBJECT_TEMPLATE_INFO_TYPE, i::AllocationType::kOld); + i::Handle obj = + i::Handle::cast(struct_obj); + { + // Disallow GC until all fields of obj have acceptable types. + i::DisallowGarbageCollection no_gc; + i::ObjectTemplateInfo raw = *obj; + InitializeTemplate(raw, Consts::OBJECT_TEMPLATE, do_not_cache); + raw.set_data(0); + if (!constructor.IsEmpty()) { + raw.set_constructor(*Utils::OpenHandle(*constructor)); + } + } + return Utils::ToLocal(obj); +} +} // namespace Local FunctionTemplate::PrototypeTemplate() { auto self = Utils::OpenHandle(this); @@ -1265,6 +1273,7 @@ void FunctionTemplate::SetPrototypeProviderTemplate( result); } +namespace { static void EnsureNotPublished(i::Handle info, const char* func) { DCHECK_IMPLIES(info->instantiated(), info->published()); @@ -1272,20 +1281,8 @@ static void EnsureNotPublished(i::Handle info, "FunctionTemplate already instantiated"); } -void FunctionTemplate::Inherit(v8::Local value) { - auto info = Utils::OpenHandle(this); - EnsureNotPublished(info, "v8::FunctionTemplate::Inherit"); - i::Isolate* i_isolate = info->GetIsolate(); - ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); - Utils::ApiCheck(info->GetPrototypeProviderTemplate().IsUndefined(i_isolate), - "v8::FunctionTemplate::Inherit", - "Protoype provider must be empty"); - i::FunctionTemplateInfo::SetParentTemplate(i_isolate, info, - Utils::OpenHandle(*value)); -} - -static Local FunctionTemplateNew( - i::Isolate* isolate, FunctionCallback callback, v8::Local data, +Local FunctionTemplateNew( + i::Isolate* i_isolate, FunctionCallback callback, v8::Local data, v8::Local signature, int length, ConstructorBehavior behavior, bool do_not_cache, v8::Local cached_property_name = v8::Local(), @@ -1294,7 +1291,7 @@ static Local FunctionTemplateNew( uint8_t instance_type = 0, uint8_t allowed_receiver_instance_type_range_start = 0, uint8_t allowed_receiver_instance_type_range_end = 0) { - i::Handle struct_obj = isolate->factory()->NewStruct( + i::Handle struct_obj = i_isolate->factory()->NewStruct( i::FUNCTION_TEMPLATE_INFO_TYPE, i::AllocationType::kOld); i::Handle obj = i::Handle::cast(struct_obj); @@ -1312,7 +1309,7 @@ static Local FunctionTemplateNew( } raw.set_cached_property_name( cached_property_name.IsEmpty() - ? i::ReadOnlyRoots(isolate).the_hole_value() + ? i::ReadOnlyRoots(i_isolate).the_hole_value() : *Utils::OpenHandle(*cached_property_name)); if (behavior == ConstructorBehavior::kThrow) raw.set_remove_prototype(true); raw.SetInstanceType(instance_type); @@ -1327,14 +1324,27 @@ static Local FunctionTemplateNew( } return Utils::ToLocal(obj); } +} // namespace + +void FunctionTemplate::Inherit(v8::Local value) { + auto info = Utils::OpenHandle(this); + EnsureNotPublished(info, "v8::FunctionTemplate::Inherit"); + i::Isolate* i_isolate = info->GetIsolate(); + ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); + Utils::ApiCheck(info->GetPrototypeProviderTemplate().IsUndefined(i_isolate), + "v8::FunctionTemplate::Inherit", + "Protoype provider must be empty"); + i::FunctionTemplateInfo::SetParentTemplate(i_isolate, info, + Utils::OpenHandle(*value)); +} Local FunctionTemplate::New( - Isolate* isolate, FunctionCallback callback, v8::Local data, + Isolate* v8_isolate, FunctionCallback callback, v8::Local data, v8::Local signature, int length, ConstructorBehavior behavior, SideEffectType side_effect_type, const CFunction* c_function, uint16_t instance_type, uint16_t allowed_receiver_instance_type_range_start, uint16_t allowed_receiver_instance_type_range_end) { - i::Isolate* i_isolate = reinterpret_cast(isolate); + i::Isolate* i_isolate = reinterpret_cast(v8_isolate); // Changes to the environment cannot be captured in the snapshot. Expect no // function templates when the isolate is created for serialization. API_RCS_SCOPE(i_isolate, FunctionTemplate, New); @@ -1342,10 +1352,20 @@ Local FunctionTemplate::New( if (!Utils::ApiCheck( !c_function || behavior == ConstructorBehavior::kThrow, "FunctionTemplate::New", - "Fast API calls are not supported for constructor functions.")) { + "Fast API calls are not supported for constructor functions")) { return Local(); } + if (instance_type != 0) { + if (!Utils::ApiCheck( + instance_type >= i::Internals::kFirstJSApiObjectType && + instance_type <= i::Internals::kLastJSApiObjectType, + "FunctionTemplate::New", + "instance_type is outside the range of valid JSApiObject types")) { + return Local(); + } + } + ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); return FunctionTemplateNew( i_isolate, callback, data, signature, length, behavior, false, @@ -1357,18 +1377,18 @@ Local FunctionTemplate::New( } Local FunctionTemplate::NewWithCFunctionOverloads( - Isolate* isolate, FunctionCallback callback, v8::Local data, + Isolate* v8_isolate, FunctionCallback callback, v8::Local data, v8::Local signature, int length, ConstructorBehavior behavior, SideEffectType side_effect_type, const MemorySpan& c_function_overloads) { - i::Isolate* i_isolate = reinterpret_cast(isolate); + i::Isolate* i_isolate = reinterpret_cast(v8_isolate); API_RCS_SCOPE(i_isolate, FunctionTemplate, New); if (!Utils::ApiCheck( c_function_overloads.size() == 0 || behavior == ConstructorBehavior::kThrow, "FunctionTemplate::NewWithCFunctionOverloads", - "Fast API calls are not supported for constructor functions.")) { + "Fast API calls are not supported for constructor functions")) { return Local(); } @@ -1379,10 +1399,10 @@ Local FunctionTemplate::NewWithCFunctionOverloads( } Local FunctionTemplate::NewWithCache( - Isolate* isolate, FunctionCallback callback, Local cache_property, - Local data, Local signature, int length, - SideEffectType side_effect_type) { - i::Isolate* i_isolate = reinterpret_cast(isolate); + Isolate* v8_isolate, FunctionCallback callback, + Local cache_property, Local data, + Local signature, int length, SideEffectType side_effect_type) { + i::Isolate* i_isolate = reinterpret_cast(v8_isolate); API_RCS_SCOPE(i_isolate, FunctionTemplate, NewWithCache); ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); return FunctionTemplateNew(i_isolate, callback, data, signature, length, @@ -1390,20 +1410,15 @@ Local FunctionTemplate::NewWithCache( side_effect_type); } -Local Signature::New(Isolate* isolate, +Local Signature::New(Isolate* v8_isolate, Local receiver) { return Utils::SignatureToLocal(Utils::OpenHandle(*receiver)); } -Local AccessorSignature::New( - Isolate* isolate, Local receiver) { - return Utils::AccessorSignatureToLocal(Utils::OpenHandle(*receiver)); -} - -#define SET_FIELD_WRAPPED(isolate, obj, setter, cdata) \ - do { \ - i::Handle foreign = FromCData(isolate, cdata); \ - (obj)->setter(*foreign); \ +#define SET_FIELD_WRAPPED(i_isolate, obj, setter, cdata) \ + do { \ + i::Handle foreign = FromCData(i_isolate, cdata); \ + (obj)->setter(*foreign); \ } while (false) void FunctionTemplate::SetCallHandler( @@ -1412,38 +1427,37 @@ void FunctionTemplate::SetCallHandler( const MemorySpan& c_function_overloads) { auto info = Utils::OpenHandle(this); EnsureNotPublished(info, "v8::FunctionTemplate::SetCallHandler"); - i::Isolate* isolate = info->GetIsolate(); - ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); - i::HandleScope scope(isolate); - i::Handle obj = isolate->factory()->NewCallHandlerInfo( + i::Isolate* i_isolate = info->GetIsolate(); + ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); + i::HandleScope scope(i_isolate); + i::Handle obj = i_isolate->factory()->NewCallHandlerInfo( side_effect_type == SideEffectType::kHasNoSideEffect); - SET_FIELD_WRAPPED(isolate, obj, set_callback, callback); - SET_FIELD_WRAPPED(isolate, obj, set_js_callback, obj->redirected_callback()); + obj->set_callback(i_isolate, reinterpret_cast(callback)); if (data.IsEmpty()) { - data = v8::Undefined(reinterpret_cast(isolate)); + data = v8::Undefined(reinterpret_cast(i_isolate)); } obj->set_data(*Utils::OpenHandle(*data)); if (c_function_overloads.size() > 0) { // Stores the data for a sequence of CFunction overloads into a single // FixedArray, as [address_0, signature_0, ... address_n-1, signature_n-1]. i::Handle function_overloads = - isolate->factory()->NewFixedArray(static_cast( + i_isolate->factory()->NewFixedArray(static_cast( c_function_overloads.size() * i::FunctionTemplateInfo::kFunctionOverloadEntrySize)); int function_count = static_cast(c_function_overloads.size()); for (int i = 0; i < function_count; i++) { const CFunction& c_function = c_function_overloads.data()[i]; i::Handle address = - FromCData(isolate, c_function.GetAddress()); + FromCData(i_isolate, c_function.GetAddress()); function_overloads->set( i::FunctionTemplateInfo::kFunctionOverloadEntrySize * i, *address); i::Handle signature = - FromCData(isolate, c_function.GetTypeInfo()); + FromCData(i_isolate, c_function.GetTypeInfo()); function_overloads->set( i::FunctionTemplateInfo::kFunctionOverloadEntrySize * i + 1, *signature); } - i::FunctionTemplateInfo::SetCFunctionOverloads(isolate, info, + i::FunctionTemplateInfo::SetCFunctionOverloads(i_isolate, info, function_overloads); } info->set_call_code(*obj, kReleaseStore); @@ -1453,32 +1467,27 @@ namespace { template i::Handle MakeAccessorInfo( - i::Isolate* isolate, v8::Local name, Getter getter, Setter setter, + i::Isolate* i_isolate, v8::Local name, Getter getter, Setter setter, v8::Local data, v8::AccessControl settings, - v8::Local signature, bool is_special_data_property, - bool replace_on_access) { - i::Handle obj = isolate->factory()->NewAccessorInfo(); - SET_FIELD_WRAPPED(isolate, obj, set_getter, getter); + bool is_special_data_property, bool replace_on_access) { + i::Handle obj = i_isolate->factory()->NewAccessorInfo(); + obj->set_getter(i_isolate, reinterpret_cast(getter)); DCHECK_IMPLIES(replace_on_access, is_special_data_property && setter == nullptr); if (is_special_data_property && setter == nullptr) { setter = reinterpret_cast(&i::Accessors::ReconfigureToDataProperty); } - SET_FIELD_WRAPPED(isolate, obj, set_setter, setter); - i::Address redirected = obj->redirected_getter(); - if (redirected != i::kNullAddress) { - SET_FIELD_WRAPPED(isolate, obj, set_js_getter, redirected); - } + obj->set_setter(i_isolate, reinterpret_cast(setter)); i::Handle accessor_name = Utils::OpenHandle(*name); if (!accessor_name->IsUniqueName()) { - accessor_name = isolate->factory()->InternalizeString( + accessor_name = i_isolate->factory()->InternalizeString( i::Handle::cast(accessor_name)); } i::DisallowGarbageCollection no_gc; i::AccessorInfo raw_obj = *obj; if (data.IsEmpty()) { - raw_obj.set_data(i::ReadOnlyRoots(isolate).undefined_value()); + raw_obj.set_data(i::ReadOnlyRoots(i_isolate).undefined_value()); } else { raw_obj.set_data(*Utils::OpenHandle(*data)); } @@ -1488,9 +1497,6 @@ i::Handle MakeAccessorInfo( if (settings & ALL_CAN_READ) raw_obj.set_all_can_read(true); if (settings & ALL_CAN_WRITE) raw_obj.set_all_can_write(true); raw_obj.set_initial_property_attributes(i::NONE); - if (!signature.IsEmpty()) { - raw_obj.set_expected_receiver_type(*Utils::OpenHandle(*signature)); - } return obj; } @@ -1503,124 +1509,103 @@ Local FunctionTemplate::InstanceTemplate() { "Reading from empty handle")) { return Local(); } - i::Isolate* isolate = handle->GetIsolate(); - ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); - if (handle->GetInstanceTemplate().IsUndefined(isolate)) { + i::Isolate* i_isolate = handle->GetIsolate(); + ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); + if (handle->GetInstanceTemplate().IsUndefined(i_isolate)) { Local templ = - ObjectTemplate::New(isolate, ToApiHandle(handle)); - i::FunctionTemplateInfo::SetInstanceTemplate(isolate, handle, + ObjectTemplate::New(i_isolate, ToApiHandle(handle)); + i::FunctionTemplateInfo::SetInstanceTemplate(i_isolate, handle, Utils::OpenHandle(*templ)); } i::Handle result( - i::ObjectTemplateInfo::cast(handle->GetInstanceTemplate()), isolate); + i::ObjectTemplateInfo::cast(handle->GetInstanceTemplate()), i_isolate); return Utils::ToLocal(result); } void FunctionTemplate::SetLength(int length) { auto info = Utils::OpenHandle(this); EnsureNotPublished(info, "v8::FunctionTemplate::SetLength"); - auto isolate = info->GetIsolate(); - ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); + auto i_isolate = info->GetIsolate(); + ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); info->set_length(length); } void FunctionTemplate::SetClassName(Local name) { auto info = Utils::OpenHandle(this); EnsureNotPublished(info, "v8::FunctionTemplate::SetClassName"); - auto isolate = info->GetIsolate(); - ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); + auto i_isolate = info->GetIsolate(); + ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); info->set_class_name(*Utils::OpenHandle(*name)); } void FunctionTemplate::SetAcceptAnyReceiver(bool value) { auto info = Utils::OpenHandle(this); EnsureNotPublished(info, "v8::FunctionTemplate::SetAcceptAnyReceiver"); - auto isolate = info->GetIsolate(); - ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); + auto i_isolate = info->GetIsolate(); + ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); info->set_accept_any_receiver(value); } void FunctionTemplate::ReadOnlyPrototype() { auto info = Utils::OpenHandle(this); EnsureNotPublished(info, "v8::FunctionTemplate::ReadOnlyPrototype"); - auto isolate = info->GetIsolate(); - ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); + auto i_isolate = info->GetIsolate(); + ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); info->set_read_only_prototype(true); } void FunctionTemplate::RemovePrototype() { auto info = Utils::OpenHandle(this); EnsureNotPublished(info, "v8::FunctionTemplate::RemovePrototype"); - auto isolate = info->GetIsolate(); - ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); + auto i_isolate = info->GetIsolate(); + ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); info->set_remove_prototype(true); } // --- O b j e c t T e m p l a t e --- Local ObjectTemplate::New( - Isolate* isolate, v8::Local constructor) { - return New(reinterpret_cast(isolate), constructor); -} - -static Local ObjectTemplateNew( - i::Isolate* isolate, v8::Local constructor, - bool do_not_cache) { - API_RCS_SCOPE(isolate, ObjectTemplate, New); - ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); - i::Handle struct_obj = isolate->factory()->NewStruct( - i::OBJECT_TEMPLATE_INFO_TYPE, i::AllocationType::kOld); - i::Handle obj = - i::Handle::cast(struct_obj); - { - // Disallow GC until all fields of obj have acceptable types. - i::DisallowGarbageCollection no_gc; - i::ObjectTemplateInfo raw = *obj; - InitializeTemplate(raw, Consts::OBJECT_TEMPLATE, do_not_cache); - raw.set_data(0); - if (!constructor.IsEmpty()) { - raw.set_constructor(*Utils::OpenHandle(*constructor)); - } - } - return Utils::ToLocal(obj); + Isolate* v8_isolate, v8::Local constructor) { + return New(reinterpret_cast(v8_isolate), constructor); } Local ObjectTemplate::New( - i::Isolate* isolate, v8::Local constructor) { - return ObjectTemplateNew(isolate, constructor, false); + i::Isolate* i_isolate, v8::Local constructor) { + return ObjectTemplateNew(i_isolate, constructor, false); } +namespace { // Ensure that the object template has a constructor. If no // constructor is available we create one. -static i::Handle EnsureConstructor( - i::Isolate* isolate, ObjectTemplate* object_template) { +i::Handle EnsureConstructor( + i::Isolate* i_isolate, ObjectTemplate* object_template) { i::Object obj = Utils::OpenHandle(object_template)->constructor(); - if (!obj.IsUndefined(isolate)) { + if (!obj.IsUndefined(i_isolate)) { i::FunctionTemplateInfo info = i::FunctionTemplateInfo::cast(obj); - return i::Handle(info, isolate); + return i::Handle(info, i_isolate); } Local templ = - FunctionTemplate::New(reinterpret_cast(isolate)); + FunctionTemplate::New(reinterpret_cast(i_isolate)); i::Handle constructor = Utils::OpenHandle(*templ); i::FunctionTemplateInfo::SetInstanceTemplate( - isolate, constructor, Utils::OpenHandle(object_template)); + i_isolate, constructor, Utils::OpenHandle(object_template)); Utils::OpenHandle(object_template)->set_constructor(*constructor); return constructor; } template -static void TemplateSetAccessor( - Template* template_obj, v8::Local name, Getter getter, Setter setter, - Data data, AccessControl settings, PropertyAttribute attribute, - v8::Local signature, bool is_special_data_property, - bool replace_on_access, SideEffectType getter_side_effect_type, - SideEffectType setter_side_effect_type) { +void TemplateSetAccessor(Template* template_obj, v8::Local name, + Getter getter, Setter setter, Data data, + AccessControl settings, PropertyAttribute attribute, + bool is_special_data_property, bool replace_on_access, + SideEffectType getter_side_effect_type, + SideEffectType setter_side_effect_type) { auto info = Utils::OpenHandle(template_obj); - auto isolate = info->GetIsolate(); - ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); - i::HandleScope scope(isolate); + auto i_isolate = info->GetIsolate(); + ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); + i::HandleScope scope(i_isolate); i::Handle accessor_info = - MakeAccessorInfo(isolate, name, getter, setter, data, settings, signature, + MakeAccessorInfo(i_isolate, name, getter, setter, data, settings, is_special_data_property, replace_on_access); { i::DisallowGarbageCollection no_gc; @@ -1630,8 +1615,9 @@ static void TemplateSetAccessor( raw.set_getter_side_effect_type(getter_side_effect_type); raw.set_setter_side_effect_type(setter_side_effect_type); } - i::ApiNatives::AddNativeDataProperty(isolate, info, accessor_info); + i::ApiNatives::AddNativeDataProperty(i_isolate, info, accessor_info); } +} // namespace void Template::SetNativeDataProperty(v8::Local name, AccessorGetterCallback getter, @@ -1642,18 +1628,7 @@ void Template::SetNativeDataProperty(v8::Local name, SideEffectType getter_side_effect_type, SideEffectType setter_side_effect_type) { TemplateSetAccessor(this, name, getter, setter, data, settings, attribute, - Local(), true, false, - getter_side_effect_type, setter_side_effect_type); -} - -void Template::SetNativeDataProperty( - v8::Local name, AccessorGetterCallback getter, - AccessorSetterCallback setter, v8::Local data, - PropertyAttribute attribute, v8::Local signature, - AccessControl settings, SideEffectType getter_side_effect_type, - SideEffectType setter_side_effect_type) { - TemplateSetAccessor(this, name, getter, setter, data, settings, attribute, - signature, true, false, getter_side_effect_type, + true, false, getter_side_effect_type, setter_side_effect_type); } @@ -1666,18 +1641,7 @@ void Template::SetNativeDataProperty(v8::Local name, SideEffectType getter_side_effect_type, SideEffectType setter_side_effect_type) { TemplateSetAccessor(this, name, getter, setter, data, settings, attribute, - Local(), true, false, - getter_side_effect_type, setter_side_effect_type); -} - -void Template::SetNativeDataProperty( - v8::Local name, AccessorNameGetterCallback getter, - AccessorNameSetterCallback setter, v8::Local data, - PropertyAttribute attribute, v8::Local signature, - AccessControl settings, SideEffectType getter_side_effect_type, - SideEffectType setter_side_effect_type) { - TemplateSetAccessor(this, name, getter, setter, data, settings, attribute, - signature, true, false, getter_side_effect_type, + true, false, getter_side_effect_type, setter_side_effect_type); } @@ -1689,17 +1653,17 @@ void Template::SetLazyDataProperty(v8::Local name, SideEffectType setter_side_effect_type) { TemplateSetAccessor(this, name, getter, static_cast(nullptr), data, - DEFAULT, attribute, Local(), true, - true, getter_side_effect_type, setter_side_effect_type); + DEFAULT, attribute, true, true, getter_side_effect_type, + setter_side_effect_type); } void Template::SetIntrinsicDataProperty(Local name, Intrinsic intrinsic, PropertyAttribute attribute) { auto templ = Utils::OpenHandle(this); - i::Isolate* isolate = templ->GetIsolate(); - ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); - i::HandleScope scope(isolate); - i::ApiNatives::AddDataProperty(isolate, templ, Utils::OpenHandle(*name), + i::Isolate* i_isolate = templ->GetIsolate(); + ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); + i::HandleScope scope(i_isolate); + i::ApiNatives::AddDataProperty(i_isolate, templ, Utils::OpenHandle(*name), intrinsic, static_cast(attribute)); } @@ -1712,7 +1676,6 @@ void ObjectTemplate::SetAccessor(v8::Local name, SideEffectType getter_side_effect_type, SideEffectType setter_side_effect_type) { TemplateSetAccessor(this, name, getter, setter, data, settings, attribute, - Local(), i::FLAG_disable_old_api_accessors, false, getter_side_effect_type, setter_side_effect_type); } @@ -1725,56 +1688,33 @@ void ObjectTemplate::SetAccessor(v8::Local name, SideEffectType getter_side_effect_type, SideEffectType setter_side_effect_type) { TemplateSetAccessor(this, name, getter, setter, data, settings, attribute, - Local(), i::FLAG_disable_old_api_accessors, false, getter_side_effect_type, setter_side_effect_type); } -void ObjectTemplate::SetAccessor(v8::Local name, - AccessorGetterCallback getter, - AccessorSetterCallback setter, - v8::Local data, AccessControl settings, - PropertyAttribute attribute, - v8::Local signature, - SideEffectType getter_side_effect_type, - SideEffectType setter_side_effect_type) { - TemplateSetAccessor(this, name, getter, setter, data, settings, attribute, - signature, i::FLAG_disable_old_api_accessors, false, - getter_side_effect_type, setter_side_effect_type); -} - -void ObjectTemplate::SetAccessor(v8::Local name, - AccessorNameGetterCallback getter, - AccessorNameSetterCallback setter, - v8::Local data, AccessControl settings, - PropertyAttribute attribute, - v8::Local signature, - SideEffectType getter_side_effect_type, - SideEffectType setter_side_effect_type) { - TemplateSetAccessor(this, name, getter, setter, data, settings, attribute, - signature, i::FLAG_disable_old_api_accessors, false, - getter_side_effect_type, setter_side_effect_type); -} - +namespace { template -static i::Handle CreateInterceptorInfo( - i::Isolate* isolate, Getter getter, Setter setter, Query query, +i::Handle CreateInterceptorInfo( + i::Isolate* i_isolate, Getter getter, Setter setter, Query query, Descriptor descriptor, Deleter remover, Enumerator enumerator, Definer definer, Local data, PropertyHandlerFlags flags) { - auto obj = i::Handle::cast(isolate->factory()->NewStruct( - i::INTERCEPTOR_INFO_TYPE, i::AllocationType::kOld)); + auto obj = + i::Handle::cast(i_isolate->factory()->NewStruct( + i::INTERCEPTOR_INFO_TYPE, i::AllocationType::kOld)); obj->set_flags(0); - if (getter != nullptr) SET_FIELD_WRAPPED(isolate, obj, set_getter, getter); - if (setter != nullptr) SET_FIELD_WRAPPED(isolate, obj, set_setter, setter); - if (query != nullptr) SET_FIELD_WRAPPED(isolate, obj, set_query, query); + if (getter != nullptr) SET_FIELD_WRAPPED(i_isolate, obj, set_getter, getter); + if (setter != nullptr) SET_FIELD_WRAPPED(i_isolate, obj, set_setter, setter); + if (query != nullptr) SET_FIELD_WRAPPED(i_isolate, obj, set_query, query); if (descriptor != nullptr) - SET_FIELD_WRAPPED(isolate, obj, set_descriptor, descriptor); - if (remover != nullptr) SET_FIELD_WRAPPED(isolate, obj, set_deleter, remover); + SET_FIELD_WRAPPED(i_isolate, obj, set_descriptor, descriptor); + if (remover != nullptr) + SET_FIELD_WRAPPED(i_isolate, obj, set_deleter, remover); if (enumerator != nullptr) - SET_FIELD_WRAPPED(isolate, obj, set_enumerator, enumerator); - if (definer != nullptr) SET_FIELD_WRAPPED(isolate, obj, set_definer, definer); + SET_FIELD_WRAPPED(i_isolate, obj, set_enumerator, enumerator); + if (definer != nullptr) + SET_FIELD_WRAPPED(i_isolate, obj, set_definer, definer); obj->set_can_intercept_symbols( !(static_cast(flags) & static_cast(PropertyHandlerFlags::kOnlyInterceptStrings))); @@ -1787,7 +1727,7 @@ static i::Handle CreateInterceptorInfo( static_cast(PropertyHandlerFlags::kHasNoSideEffect)); if (data.IsEmpty()) { - data = v8::Undefined(reinterpret_cast(isolate)); + data = v8::Undefined(reinterpret_cast(i_isolate)); } obj->set_data(*Utils::OpenHandle(*data)); return obj; @@ -1795,46 +1735,47 @@ static i::Handle CreateInterceptorInfo( template -static i::Handle CreateNamedInterceptorInfo( - i::Isolate* isolate, Getter getter, Setter setter, Query query, +i::Handle CreateNamedInterceptorInfo( + i::Isolate* i_isolate, Getter getter, Setter setter, Query query, Descriptor descriptor, Deleter remover, Enumerator enumerator, Definer definer, Local data, PropertyHandlerFlags flags) { auto interceptor = - CreateInterceptorInfo(isolate, getter, setter, query, descriptor, remover, - enumerator, definer, data, flags); + CreateInterceptorInfo(i_isolate, getter, setter, query, descriptor, + remover, enumerator, definer, data, flags); interceptor->set_is_named(true); return interceptor; } template -static i::Handle CreateIndexedInterceptorInfo( - i::Isolate* isolate, Getter getter, Setter setter, Query query, +i::Handle CreateIndexedInterceptorInfo( + i::Isolate* i_isolate, Getter getter, Setter setter, Query query, Descriptor descriptor, Deleter remover, Enumerator enumerator, Definer definer, Local data, PropertyHandlerFlags flags) { auto interceptor = - CreateInterceptorInfo(isolate, getter, setter, query, descriptor, remover, - enumerator, definer, data, flags); + CreateInterceptorInfo(i_isolate, getter, setter, query, descriptor, + remover, enumerator, definer, data, flags); interceptor->set_is_named(false); return interceptor; } template -static void ObjectTemplateSetNamedPropertyHandler( +void ObjectTemplateSetNamedPropertyHandler( ObjectTemplate* templ, Getter getter, Setter setter, Query query, Descriptor descriptor, Deleter remover, Enumerator enumerator, Definer definer, Local data, PropertyHandlerFlags flags) { - i::Isolate* isolate = Utils::OpenHandle(templ)->GetIsolate(); - ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); - i::HandleScope scope(isolate); - auto cons = EnsureConstructor(isolate, templ); + i::Isolate* i_isolate = Utils::OpenHandle(templ)->GetIsolate(); + ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); + i::HandleScope scope(i_isolate); + auto cons = EnsureConstructor(i_isolate, templ); EnsureNotPublished(cons, "ObjectTemplateSetNamedPropertyHandler"); auto obj = - CreateNamedInterceptorInfo(isolate, getter, setter, query, descriptor, + CreateNamedInterceptorInfo(i_isolate, getter, setter, query, descriptor, remover, enumerator, definer, data, flags); - i::FunctionTemplateInfo::SetNamedPropertyHandler(isolate, cons, obj); + i::FunctionTemplateInfo::SetNamedPropertyHandler(i_isolate, cons, obj); } +} // namespace void ObjectTemplate::SetHandler( const NamedPropertyHandlerConfiguration& config) { @@ -1845,37 +1786,37 @@ void ObjectTemplate::SetHandler( } void ObjectTemplate::MarkAsUndetectable() { - i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); - ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); - i::HandleScope scope(isolate); - auto cons = EnsureConstructor(isolate, this); + i::Isolate* i_isolate = Utils::OpenHandle(this)->GetIsolate(); + ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); + i::HandleScope scope(i_isolate); + auto cons = EnsureConstructor(i_isolate, this); EnsureNotPublished(cons, "v8::ObjectTemplate::MarkAsUndetectable"); cons->set_undetectable(true); } void ObjectTemplate::SetAccessCheckCallback(AccessCheckCallback callback, Local data) { - i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); - ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); - i::HandleScope scope(isolate); - auto cons = EnsureConstructor(isolate, this); + i::Isolate* i_isolate = Utils::OpenHandle(this)->GetIsolate(); + ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); + i::HandleScope scope(i_isolate); + auto cons = EnsureConstructor(i_isolate, this); EnsureNotPublished(cons, "v8::ObjectTemplate::SetAccessCheckCallback"); - i::Handle struct_info = isolate->factory()->NewStruct( + i::Handle struct_info = i_isolate->factory()->NewStruct( i::ACCESS_CHECK_INFO_TYPE, i::AllocationType::kOld); i::Handle info = i::Handle::cast(struct_info); - SET_FIELD_WRAPPED(isolate, info, set_callback, callback); + SET_FIELD_WRAPPED(i_isolate, info, set_callback, callback); info->set_named_interceptor(i::Object()); info->set_indexed_interceptor(i::Object()); if (data.IsEmpty()) { - data = v8::Undefined(reinterpret_cast(isolate)); + data = v8::Undefined(reinterpret_cast(i_isolate)); } info->set_data(*Utils::OpenHandle(*data)); - i::FunctionTemplateInfo::SetAccessCheckInfo(isolate, cons, info); + i::FunctionTemplateInfo::SetAccessCheckInfo(i_isolate, cons, info); cons->set_needs_access_check(true); } @@ -1884,69 +1825,70 @@ void ObjectTemplate::SetAccessCheckCallbackAndHandler( const NamedPropertyHandlerConfiguration& named_handler, const IndexedPropertyHandlerConfiguration& indexed_handler, Local data) { - i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); - ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); - i::HandleScope scope(isolate); - auto cons = EnsureConstructor(isolate, this); + i::Isolate* i_isolate = Utils::OpenHandle(this)->GetIsolate(); + ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); + i::HandleScope scope(i_isolate); + auto cons = EnsureConstructor(i_isolate, this); EnsureNotPublished(cons, "v8::ObjectTemplate::SetAccessCheckCallbackWithHandler"); - i::Handle struct_info = isolate->factory()->NewStruct( + i::Handle struct_info = i_isolate->factory()->NewStruct( i::ACCESS_CHECK_INFO_TYPE, i::AllocationType::kOld); i::Handle info = i::Handle::cast(struct_info); - SET_FIELD_WRAPPED(isolate, info, set_callback, callback); + SET_FIELD_WRAPPED(i_isolate, info, set_callback, callback); auto named_interceptor = CreateNamedInterceptorInfo( - isolate, named_handler.getter, named_handler.setter, named_handler.query, - named_handler.descriptor, named_handler.deleter, named_handler.enumerator, - named_handler.definer, named_handler.data, named_handler.flags); + i_isolate, named_handler.getter, named_handler.setter, + named_handler.query, named_handler.descriptor, named_handler.deleter, + named_handler.enumerator, named_handler.definer, named_handler.data, + named_handler.flags); info->set_named_interceptor(*named_interceptor); auto indexed_interceptor = CreateIndexedInterceptorInfo( - isolate, indexed_handler.getter, indexed_handler.setter, + i_isolate, indexed_handler.getter, indexed_handler.setter, indexed_handler.query, indexed_handler.descriptor, indexed_handler.deleter, indexed_handler.enumerator, indexed_handler.definer, indexed_handler.data, indexed_handler.flags); info->set_indexed_interceptor(*indexed_interceptor); if (data.IsEmpty()) { - data = v8::Undefined(reinterpret_cast(isolate)); + data = v8::Undefined(reinterpret_cast(i_isolate)); } info->set_data(*Utils::OpenHandle(*data)); - i::FunctionTemplateInfo::SetAccessCheckInfo(isolate, cons, info); + i::FunctionTemplateInfo::SetAccessCheckInfo(i_isolate, cons, info); cons->set_needs_access_check(true); } void ObjectTemplate::SetHandler( const IndexedPropertyHandlerConfiguration& config) { - i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); - ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); - i::HandleScope scope(isolate); - auto cons = EnsureConstructor(isolate, this); + i::Isolate* i_isolate = Utils::OpenHandle(this)->GetIsolate(); + ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); + i::HandleScope scope(i_isolate); + auto cons = EnsureConstructor(i_isolate, this); EnsureNotPublished(cons, "v8::ObjectTemplate::SetHandler"); auto obj = CreateIndexedInterceptorInfo( - isolate, config.getter, config.setter, config.query, config.descriptor, + i_isolate, config.getter, config.setter, config.query, config.descriptor, config.deleter, config.enumerator, config.definer, config.data, config.flags); - i::FunctionTemplateInfo::SetIndexedPropertyHandler(isolate, cons, obj); + i::FunctionTemplateInfo::SetIndexedPropertyHandler(i_isolate, cons, obj); } void ObjectTemplate::SetCallAsFunctionHandler(FunctionCallback callback, Local data) { - i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); - ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); - i::HandleScope scope(isolate); - auto cons = EnsureConstructor(isolate, this); + i::Isolate* i_isolate = Utils::OpenHandle(this)->GetIsolate(); + ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); + i::HandleScope scope(i_isolate); + auto cons = EnsureConstructor(i_isolate, this); EnsureNotPublished(cons, "v8::ObjectTemplate::SetCallAsFunctionHandler"); - i::Handle obj = isolate->factory()->NewCallHandlerInfo(); - SET_FIELD_WRAPPED(isolate, obj, set_callback, callback); - SET_FIELD_WRAPPED(isolate, obj, set_js_callback, obj->redirected_callback()); + i::Handle obj = + i_isolate->factory()->NewCallHandlerInfo(); + obj->set_callback(i_isolate, reinterpret_cast(callback)); if (data.IsEmpty()) { - data = v8::Undefined(reinterpret_cast(isolate)); + data = v8::Undefined(reinterpret_cast(i_isolate)); } obj->set_data(*Utils::OpenHandle(*data)); - i::FunctionTemplateInfo::SetInstanceCallHandler(isolate, cons, obj); + i::FunctionTemplateInfo::SetInstanceCallHandler(i_isolate, cons, obj); } int ObjectTemplate::InternalFieldCount() const { @@ -1954,18 +1896,18 @@ int ObjectTemplate::InternalFieldCount() const { } void ObjectTemplate::SetInternalFieldCount(int value) { - i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); + i::Isolate* i_isolate = Utils::OpenHandle(this)->GetIsolate(); if (!Utils::ApiCheck(i::Smi::IsValid(value), "v8::ObjectTemplate::SetInternalFieldCount()", "Invalid embedder field count")) { return; } - ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); + ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); if (value > 0) { // The embedder field count is set by the constructor function's // construct code, so we ensure that there is a constructor // function to do the setting. - EnsureConstructor(isolate, this); + EnsureConstructor(i_isolate, this); } Utils::OpenHandle(this)->set_embedder_field_count(value); } @@ -1976,8 +1918,8 @@ bool ObjectTemplate::IsImmutableProto() const { void ObjectTemplate::SetImmutableProto() { auto self = Utils::OpenHandle(this); - i::Isolate* isolate = self->GetIsolate(); - ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); + i::Isolate* i_isolate = self->GetIsolate(); + ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); self->set_immutable_proto(true); } @@ -1987,8 +1929,8 @@ bool ObjectTemplate::IsCodeLike() const { void ObjectTemplate::SetCodeLike() { auto self = Utils::OpenHandle(this); - i::Isolate* isolate = self->GetIsolate(); - ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); + i::Isolate* i_isolate = self->GetIsolate(); + ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); self->set_code_like(true); } @@ -2019,11 +1961,11 @@ ScriptCompiler::StreamedSource::~StreamedSource() = default; Local