-
Notifications
You must be signed in to change notification settings - Fork 29.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
bootstrap: implement run-time user-land snapshots via --build-snapshot and --snapshot-blob #38905
Conversation
This comment has been minimized.
This comment has been minimized.
28bc446
to
3f409b7
Compare
Wow, that's really cool. Can't wait! ❤️ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
What is the compatibility of the snapshot blob WRT V8/Node version, other CLI flags, etc? |
And what happens if you try to load a snapshot with the wrong version of the runtime? |
@targos The blob requires the version of V8/Node to be the same between build time and load time - V8 checks the versions explicitly, and abort if there is a mismatch, while at the moment Node.js should work as long as the number/kind/order of external references etc. match between the binaries used to build and load the snapshot (what happens when there is a mismatch depends on what the mismatch actually is, I would say it's most likely that the process would abort when some V8 casting type check fails e.g. casting e.g. a String to a Function, because one version expects value at blob index n to be a String and the other expects value at blob index n to be a Function). Maybe we could explicitly check the Node.js versions as well so when there is a mismatch users can understand what's wrong immediately. The CLI flags can vary between between build time and load time, to some extent, it depends on the actual flags being used. |
Seems like a good idea. |
Also that reminded me that we need to regenerate |
3f409b7
to
752d82d
Compare
Another thing that we need to watch out for: right now some modules cache access to |
Fwiw, I think it’s generally a good idea not to cache these values, so that they become configurable – independently of snapshot support. |
At the source code level I agree - not caching it directly via the form of something like |
752d82d
to
8ed3b59
Compare
Updated the prototype a bit, now it loads the snapshot entry point from JS (the snapshot would only be generated when it runs to completion), this gives us more control in e.g. warning about unsupported modules. I've split some smaller commits to other PRs, there's also a small V8 debuggability thing that I'll upstream later. Some issues I discovered:
(Also, I realized that many modules just require the CJS module loader at the top level, which would in turn require the ESM loader at the top level, which leaves a promise immediately. Not sure how to work around that promise yet but I guess for now we could just make sure that other modules only load those loaders when they actually need to...) |
It's likely worth opening a separate issue for this particular piece. I agree that getting away from caching as a module-scope |
This is only necessary for the snapshot builder (because we have no way to resurrect the handles at the moment). In addition, print the handles if the debug flag is set or if the queues are not empty after snapshot is created. PR-URL: #39007 Refs: #35711 Refs: #38905 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
This is only necessary for the snapshot builder (because we have no way to resurrect the handles at the moment). In addition, print the handles if the debug flag is set or if the queues are not empty after snapshot is created. PR-URL: #39007 Refs: #35711 Refs: #38905 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
This way, internal modules can still require the module and cache the function getOptionValue() early (therefore these code can be included in the snapshots), but the options map won't be serialized from C++ land until the option values are actually queried. PR-URL: #38993 Refs: #35711 Refs: #38905 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Zijian Liu <lxxyxzj@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
3ae6d68
to
28f6bec
Compare
That worked! thanks @joyeecheung! Removing the |
This patch introduces `--build-snapshot` and `--snapshot-blob` options for creating and using user land snapshots. For the initial iteration, user land CJS modules and ESM are not yet supported in the snapshot, so only one single file can be snapshotted (users can bundle their applications into a single script with their bundler of choice to build a snapshot though). A subset of builtins should already work, and support for more builtins are being added. This PR includes tests checking that the TypeScript compiler and the marked markdown renderer (and the builtins they use) can be snapshotted and deserialized. To generate a snapshot using `snapshot.js` as entry point and write the snapshot blob to `snapshot.blob`: ``` $ echo "globalThis.foo = 'I am from the snapshot'" > snapshot.js $ node --snapshot-blob snapshot.blob --build-snapshot snapshot.js ``` To restore application state from `snapshot.blob`, with `index.js` as the entry point script for the deserialized application: ``` $ echo "console.log(globalThis.foo)" > index.js $ node --snapshot-blob snapshot.blob index.js I am from the snapshot ``` Users can also use the `v8.startupSnapshot` API to specify an entry point at snapshot building time, thus avoiding the need of an additional entry script at deserialization time: ``` $ echo "require('v8').startupSnapshot.setDeserializeMainFunction(() => console.log('I am from the snapshot'))" > snapshot.js $ node --snapshot-blob snapshot.blob --build-snapshot snapshot.js $ node --snapshot-blob snapshot.blob I am from the snapshot ``` Note that this patch only adds functionality to the `node` executable for building run-time user-land snapshots, the generated snapshot is stored into a separate file on disk. Building a single binary with both Node.js and an embedded snapshot has already been possible with the `--node-snapshot-main` option to the `configure` script if the user compiles Node.js from source. It would be a different task to enable the `node` executable to produce a single binary that contains both Node.js and an embedded snapshot without building Node.js from source, which should be layered on top of the SEA (Single Executable Apps) initiative. Known limitations/bugs that are being fixed in the upstream: - V8 hits a DCHECK when deserializing certain mutated globals, e.g. `Error.stackTraceLimit` (it should work fine in the release build, however): https://chromium-review.googlesource.com/c/v8/v8/+/3319481 - Layout of V8's read-only heap can be inconsistent after deserialization, resulting in memory corruption: https://bugs.chromium.org/p/v8/issues/detail?id=12921 PR-URL: #38905 Refs: #35711 Reviewed-By: Chengzhong Wu <legendecas@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Notable changes: * bootstrap: * implement run-time user-land snapshots via --build-snapshot and --snapshot-blob (Joyee Cheung) in #38905 * crypto: * (SEMVER-MINOR) allow zero-length IKM in HKDF and in webcrypto PBKDF2 (Filip Skokan) #44201 * (SEMVER-MINOR) allow zero-length secret KeyObject (Filip Skokan) #44201 * deps: * upgrade npm to 8.18.0 (npm team) #44263 - Adds a new npm query cmd * doc: * add Erick Wendel to collaborators (Erick Wendel) #44088 * add MoLow to collaborators (Moshe Atlow) #44214 * deprecate --trace-atomics-wait (Keyhan Vakil) #44093 * http: * (SEMVER-MINOR) make idle http parser count configurable (theanarkh) #43974 * net: * (SEMVER-MINOR) add local family (theanarkh) #43975 * src: * (SEMVER-MINOR) print source map error source on demand (Chengzhong Wu) #43875 * tls: * (SEMVER-MINOR) pass a valid socket on tlsClientError (Daeyeon Jeong) #44021 PR-URL: TBD
Notable changes: * bootstrap: * implement run-time user-land snapshots via --build-snapshot and --snapshot-blob (Joyee Cheung) in #38905 * crypto: * (SEMVER-MINOR) allow zero-length IKM in HKDF and in webcrypto PBKDF2 (Filip Skokan) #44201 * (SEMVER-MINOR) allow zero-length secret KeyObject (Filip Skokan) #44201 * deps: * upgrade npm to 8.18.0 (npm team) #44263 - Adds a new npm query cmd * doc: * add Erick Wendel to collaborators (Erick Wendel) #44088 * add MoLow to collaborators (Moshe Atlow) #44214 * deprecate --trace-atomics-wait (Keyhan Vakil) #44093 * http: * (SEMVER-MINOR) make idle http parser count configurable (theanarkh) #43974 * net: * (SEMVER-MINOR) add local family (theanarkh) #43975 * src: * (SEMVER-MINOR) print source map error source on demand (Chengzhong Wu) #43875 * tls: * (SEMVER-MINOR) pass a valid socket on tlsClientError (Daeyeon Jeong) #44021 PR-URL: #44353
Notable changes: * bootstrap: * implement run-time user-land snapshots via --build-snapshot and --snapshot-blob (Joyee Cheung) in #38905 * crypto: * (SEMVER-MINOR) allow zero-length IKM in HKDF and in webcrypto PBKDF2 (Filip Skokan) #44201 * (SEMVER-MINOR) allow zero-length secret KeyObject (Filip Skokan) #44201 * deps: * upgrade npm to 8.18.0 (npm team) #44263 - Adds a new npm query cmd * doc: * add Erick Wendel to collaborators (Erick Wendel) #44088 * add theanarkh to collaborators (theanarkh) #44131 * add MoLow to collaborators (Moshe Atlow) #44214 * add cola119 to collaborators (cola119) #44248 * deprecate --trace-atomics-wait (Keyhan Vakil) #44093 * http: * (SEMVER-MINOR) make idle http parser count configurable (theanarkh) #43974 * net: * (SEMVER-MINOR) add local family (theanarkh) #43975 * src: * (SEMVER-MINOR) print source map error source on demand (Chengzhong Wu) #43875 * tls: * (SEMVER-MINOR) pass a valid socket on tlsClientError (Daeyeon Jeong) #44021 PR-URL: #44353
Notable changes: * bootstrap: * implement run-time user-land snapshots via --build-snapshot and --snapshot-blob (Joyee Cheung) in #38905 * crypto: * (SEMVER-MINOR) allow zero-length IKM in HKDF and in webcrypto PBKDF2 (Filip Skokan) #44201 * (SEMVER-MINOR) allow zero-length secret KeyObject (Filip Skokan) #44201 * deps: * upgrade npm to 8.18.0 (npm team) #44263 - Adds a new npm query cmd * doc: * add Erick Wendel to collaborators (Erick Wendel) #44088 * add theanarkh to collaborators (theanarkh) #44131 * add MoLow to collaborators (Moshe Atlow) #44214 * add cola119 to collaborators (cola119) #44248 * deprecate --trace-atomics-wait (Keyhan Vakil) #44093 * http: * (SEMVER-MINOR) make idle http parser count configurable (theanarkh) #43974 * net: * (SEMVER-MINOR) add local family (theanarkh) #43975 * src: * (SEMVER-MINOR) print source map error source on demand (Chengzhong Wu) #43875 * tls: * (SEMVER-MINOR) pass a valid socket on tlsClientError (Daeyeon Jeong) #44021 PR-URL: #44353
Notable changes: * bootstrap: * implement run-time user-land snapshots via --build-snapshot and --snapshot-blob (Joyee Cheung) in nodejs#38905 * crypto: * (SEMVER-MINOR) allow zero-length IKM in HKDF and in webcrypto PBKDF2 (Filip Skokan) nodejs#44201 * (SEMVER-MINOR) allow zero-length secret KeyObject (Filip Skokan) nodejs#44201 * deps: * upgrade npm to 8.18.0 (npm team) nodejs#44263 - Adds a new npm query cmd * doc: * add Erick Wendel to collaborators (Erick Wendel) nodejs#44088 * add theanarkh to collaborators (theanarkh) nodejs#44131 * add MoLow to collaborators (Moshe Atlow) nodejs#44214 * add cola119 to collaborators (cola119) nodejs#44248 * deprecate --trace-atomics-wait (Keyhan Vakil) nodejs#44093 * http: * (SEMVER-MINOR) make idle http parser count configurable (theanarkh) nodejs#43974 * net: * (SEMVER-MINOR) add local family (theanarkh) nodejs#43975 * src: * (SEMVER-MINOR) print source map error source on demand (Chengzhong Wu) nodejs#43875 * tls: * (SEMVER-MINOR) pass a valid socket on tlsClientError (Daeyeon Jeong) nodejs#44021 PR-URL: nodejs#44353
Where can I track progress of this? |
@gajus The SEA effort is tracked in https://github.com/nodejs/single-executable and currently most activities take place in https://github.com/nodejs/single-executable/discussions |
PR-URL: nodejs#38905 Refs: nodejs#35711 Reviewed-By: Chengzhong Wu <legendecas@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
This patch introduces `--build-snapshot` and `--snapshot-blob` options for creating and using user land snapshots. For the initial iteration, user land CJS modules and ESM are not yet supported in the snapshot, so only one single file can be snapshotted (users can bundle their applications into a single script with their bundler of choice to build a snapshot though). A subset of builtins should already work, and support for more builtins are being added. This PR includes tests checking that the TypeScript compiler and the marked markdown renderer (and the builtins they use) can be snapshotted and deserialized. To generate a snapshot using `snapshot.js` as entry point and write the snapshot blob to `snapshot.blob`: ``` $ echo "globalThis.foo = 'I am from the snapshot'" > snapshot.js $ node --snapshot-blob snapshot.blob --build-snapshot snapshot.js ``` To restore application state from `snapshot.blob`, with `index.js` as the entry point script for the deserialized application: ``` $ echo "console.log(globalThis.foo)" > index.js $ node --snapshot-blob snapshot.blob index.js I am from the snapshot ``` Users can also use the `v8.startupSnapshot` API to specify an entry point at snapshot building time, thus avoiding the need of an additional entry script at deserialization time: ``` $ echo "require('v8').startupSnapshot.setDeserializeMainFunction(() => console.log('I am from the snapshot'))" > snapshot.js $ node --snapshot-blob snapshot.blob --build-snapshot snapshot.js $ node --snapshot-blob snapshot.blob I am from the snapshot ``` Note that this patch only adds functionality to the `node` executable for building run-time user-land snapshots, the generated snapshot is stored into a separate file on disk. Building a single binary with both Node.js and an embedded snapshot has already been possible with the `--node-snapshot-main` option to the `configure` script if the user compiles Node.js from source. It would be a different task to enable the `node` executable to produce a single binary that contains both Node.js and an embedded snapshot without building Node.js from source, which should be layered on top of the SEA (Single Executable Apps) initiative. Known limitations/bugs that are being fixed in the upstream: - V8 hits a DCHECK when deserializing certain mutated globals, e.g. `Error.stackTraceLimit` (it should work fine in the release build, however): https://chromium-review.googlesource.com/c/v8/v8/+/3319481 - Layout of V8's read-only heap can be inconsistent after deserialization, resulting in memory corruption: https://bugs.chromium.org/p/v8/issues/detail?id=12921 PR-URL: nodejs#38905 Refs: nodejs#35711 Reviewed-By: Chengzhong Wu <legendecas@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
PR-URL: nodejs#38905 Refs: nodejs#35711 Reviewed-By: Chengzhong Wu <legendecas@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
PR-URL: nodejs#38905 Refs: nodejs#35711 Reviewed-By: Chengzhong Wu <legendecas@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
PR-URL: nodejs#38905 Refs: nodejs#35711 Reviewed-By: Chengzhong Wu <legendecas@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Notable changes: * bootstrap: * implement run-time user-land snapshots via --build-snapshot and --snapshot-blob (Joyee Cheung) in nodejs#38905 * crypto: * (SEMVER-MINOR) allow zero-length IKM in HKDF and in webcrypto PBKDF2 (Filip Skokan) nodejs#44201 * (SEMVER-MINOR) allow zero-length secret KeyObject (Filip Skokan) nodejs#44201 * deps: * upgrade npm to 8.18.0 (npm team) nodejs#44263 - Adds a new npm query cmd * doc: * add Erick Wendel to collaborators (Erick Wendel) nodejs#44088 * add theanarkh to collaborators (theanarkh) nodejs#44131 * add MoLow to collaborators (Moshe Atlow) nodejs#44214 * add cola119 to collaborators (cola119) nodejs#44248 * deprecate --trace-atomics-wait (Keyhan Vakil) nodejs#44093 * http: * (SEMVER-MINOR) make idle http parser count configurable (theanarkh) nodejs#43974 * net: * (SEMVER-MINOR) add local family (theanarkh) nodejs#43975 * src: * (SEMVER-MINOR) print source map error source on demand (Chengzhong Wu) nodejs#43875 * tls: * (SEMVER-MINOR) pass a valid socket on tlsClientError (Daeyeon Jeong) nodejs#44021 PR-URL: nodejs#44353
bootstrap: implement run-time user-land snapshots via --build-snapshot and --snapshot-blob
bootstrap: implement run-time user-land snapshots via --build-snapshot and --snapshot-blob
bootstrap: implement run-time user-land snapshots via --build-snapshot and --snapshot-blob
bootstrap: implement run-time user-land snapshots via --build-snapshot and --snapshot-blob
bootstrap: implement run-time user-land snapshots via --build-snapshot and --snapshot-blob
* chore: update to Node.js v18 * child_process: improve argument validation nodejs/node#41305 * bootstrap: support configure-time user-land snapshot nodejs/node#42466 * chore: update GN patch * src: disambiguate terms used to refer to builtins and addons nodejs/node#44135 * src: use a typed array internally for process._exiting nodejs/node#43883 * chore: lib/internal/bootstrap -> lib/internal/process * src: disambiguate terms used to refer to builtins and addons nodejs/node#44135 * chore: remove redudant browserGlobals patch * chore: update BoringSSL patch * src: allow embedder-provided PageAllocator in NodePlatform nodejs/node#38362 * chore: fixup Node.js crypto tests - nodejs/node#44171 - nodejs/node#41600 * lib: add Promise methods to avoid-prototype-pollution lint rule nodejs/node#43849 * deps: update V8 to 10.1 nodejs/node#42657 * src: add kNoBrowserGlobals flag for Environment nodejs/node#40532 * chore: consolidate asar initialization patches * deps: update V8 to 10.1 nodejs/node#42657 * deps: update V8 to 9.8 nodejs/node#41610 * src,crypto: remove AllocatedBuffers from crypto_spkac nodejs/node#40752 * build: enable V8's shared read-only heap nodejs/node#42809 * src: fix ssize_t error from nghttp2.h nodejs/node#44393 * chore: fixup ESM patch * chore: fixup patch indices * src: merge NativeModuleEnv into NativeModuleLoader nodejs/node#43824 * [API] Pass OOMDetails to OOMErrorCallback https://chromium-review.googlesource.com/c/v8/v8/+/3647827 * src: iwyu in cleanup_queue.cc * src: return Maybe from a couple of functions nodejs/node#39603 * src: clean up embedder API nodejs/node#35897 * src: refactor DH groups to delete crypto_groups.h nodejs/node#43896 * deps,src: use SIMD for normal base64 encoding nodejs/node#39775 * chore: remove deleted source file * chore: update patches * chore: remove deleted source file * lib: add fetch nodejs/node#41749 * chore: remove nonexistent node specs * test: split report OOM tests nodejs/node#44389 * src: trace fs async api nodejs/node#44057 * http: trace http request / response nodejs/node#44102 * test: split test-crypto-dh.js nodejs/node#40451 * crypto: introduce X509Certificate API nodejs/node#36804 * src: split property helpers from node::Environment nodejs/node#44056 * nodejs/node#38905 bootstrap: implement run-time user-land snapshots via --build-snapshot and --snapshot-blob * lib,src: implement WebAssembly Web API nodejs/node#42701 * fixup! deps,src: use SIMD for normal base64 encoding * fixup! src: refactor DH groups to delete crypto_groups.h * chore: fixup base64 GN file * fix: check that node::InitializeContext() returns true * chore: delete _noBrowserGlobals usage * chore: disable fetch in renderer procceses * dns: default to verbatim=true in dns.lookup() nodejs/node#39987 Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
* chore: update to Node.js v18 * child_process: improve argument validation nodejs/node#41305 * bootstrap: support configure-time user-land snapshot nodejs/node#42466 * chore: update GN patch * src: disambiguate terms used to refer to builtins and addons nodejs/node#44135 * src: use a typed array internally for process._exiting nodejs/node#43883 * chore: lib/internal/bootstrap -> lib/internal/process * src: disambiguate terms used to refer to builtins and addons nodejs/node#44135 * chore: remove redudant browserGlobals patch * chore: update BoringSSL patch * src: allow embedder-provided PageAllocator in NodePlatform nodejs/node#38362 * chore: fixup Node.js crypto tests - nodejs/node#44171 - nodejs/node#41600 * lib: add Promise methods to avoid-prototype-pollution lint rule nodejs/node#43849 * deps: update V8 to 10.1 nodejs/node#42657 * src: add kNoBrowserGlobals flag for Environment nodejs/node#40532 * chore: consolidate asar initialization patches * deps: update V8 to 10.1 nodejs/node#42657 * deps: update V8 to 9.8 nodejs/node#41610 * src,crypto: remove AllocatedBuffers from crypto_spkac nodejs/node#40752 * build: enable V8's shared read-only heap nodejs/node#42809 * src: fix ssize_t error from nghttp2.h nodejs/node#44393 * chore: fixup ESM patch * chore: fixup patch indices * src: merge NativeModuleEnv into NativeModuleLoader nodejs/node#43824 * [API] Pass OOMDetails to OOMErrorCallback https://chromium-review.googlesource.com/c/v8/v8/+/3647827 * src: iwyu in cleanup_queue.cc * src: return Maybe from a couple of functions nodejs/node#39603 * src: clean up embedder API nodejs/node#35897 * src: refactor DH groups to delete crypto_groups.h nodejs/node#43896 * deps,src: use SIMD for normal base64 encoding nodejs/node#39775 * chore: remove deleted source file * chore: update patches * chore: remove deleted source file * lib: add fetch nodejs/node#41749 * chore: remove nonexistent node specs * test: split report OOM tests nodejs/node#44389 * src: trace fs async api nodejs/node#44057 * http: trace http request / response nodejs/node#44102 * test: split test-crypto-dh.js nodejs/node#40451 * crypto: introduce X509Certificate API nodejs/node#36804 * src: split property helpers from node::Environment nodejs/node#44056 * nodejs/node#38905 bootstrap: implement run-time user-land snapshots via --build-snapshot and --snapshot-blob * lib,src: implement WebAssembly Web API nodejs/node#42701 * fixup! deps,src: use SIMD for normal base64 encoding * fixup! src: refactor DH groups to delete crypto_groups.h * chore: fixup base64 GN file * fix: check that node::InitializeContext() returns true * chore: delete _noBrowserGlobals usage * chore: disable fetch in renderer procceses * dns: default to verbatim=true in dns.lookup() nodejs/node#39987 Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
This patch introduces
--build-snapshot
and--snapshot-blob
options for creating and using user land snapshots.For the initial iteration, user land CJS modules and ESM are not yet supported in the snapshot, so only one single file can be snapshotted (users can bundle their applications into a single script with their bundler of choice to build a snapshot though).
A subset of builtins should already work, and support for more builtins are being added. This PR includes tests checking that the TypeScript compiler and the marked markdown renderer (and the builtins they use) can be snapshotted and deserialized.
To generate a snapshot using
snapshot.js
as entry point and write the snapshot blob tosnapshot.blob
:To restore application state from
snapshot.blob
, withindex.js
as the entry point script for the deserialized application:Users can also use the
v8.startupSnapshot
API to specify an entry point at snapshot building time, thus avoiding the need of an additional entry script at deserialization time:Note that this patch only adds functionality to the
node
executable for building run-time user-land snapshots, the generated snapshot is stored into a separate file on disk. Building a single binary with both Node.js and an embedded snapshot has already been possible with the--node-snapshot-main
option to theconfigure
script if the user compiles Node.js from source. It would be a different task to enable thenode
executable to produce a single binary that contains both Node.js and an embedded snapshot without building Node.js from source, which should be layered on top of the SEA (Single Executable Apps) initiative.Known limitations/bugs that are being fixed in the V8 upstream:
Error.stackTraceLimit
(it should work fine in the release build, however): https://chromium-review.googlesource.com/c/v8/v8/+/3319481More known limitations/bugs in the tracking issue: #44014
Refs: #35711