Skip to content
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

doc: improve internal documentation on built-in snapshot #56505

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions src/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -467,10 +467,16 @@ void Initialize(Local<Object> target,
NODE_BINDING_CONTEXT_AWARE_INTERNAL(cares_wrap, Initialize)
```

If the C++ binding is loaded during bootstrap, it needs to be registered
with the utilities in `node_external_reference.h`, like this:
#### Registering binding functions used in bootstrap

If the C++ binding is loaded during bootstrap, in addition to registering it
using `NODE_BINDING_CONTEXT_AWARE_INTERNAL` for `internalBinding()` lookup,
it also needs to be registered with `NODE_BINDING_EXTERNAL_REFERENCE` so that
the external references can be resolved from the built-in snapshot, like this:

```cpp
#include "node_external_reference.h"

namespace node {
namespace util {
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
Expand Down Expand Up @@ -498,7 +504,8 @@ Unknown external reference 0x107769200.
/bin/sh: line 1: 6963 Illegal instruction: 4 out/Release/node_mksnapshot out/Release/gen/node_snapshot.cc
```

You can try using a debugger to symbolicate the external reference. For example,
You can try using a debugger to symbolicate the external reference in order to find
out the binding functions that you forget to register. For example,
with lldb's `image lookup --address` command (with gdb it's `info symbol`):

```console
Expand All @@ -514,7 +521,9 @@ Process 7012 stopped
```

Which explains that the unregistered external reference is
`node::util::GetHiddenValue` defined in `node_util.cc`.
`node::util::GetHiddenValue` defined in `node_util.cc`, and should be registered
using `registry->Register()` in a registration function marked by
`NODE_BINDING_EXTERNAL_REFERENCE`.

<a id="per-binding-state"></a>

Expand Down
62 changes: 59 additions & 3 deletions tools/snapshot/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,46 @@ instead of executing code to bootstrap, it can deserialize the context from
an embedded snapshot, which readily contains the result of the bootstrap, so
that Node.js can start up faster.

Currently only the main context of the main Node.js instance supports snapshot
deserialization, and the snapshot does not yet cover the entire bootstrap
process. Work is being done to expand the support.
The built-in snapshot consists of the following snapshots:

## Isolate snapshot

Which is used whenever a `v8::Isolate` is created using the data returned by
`node::SnapshotBuilder::GetEmbeddedSnapshotData`.

## Context snapshots

Which are used when a `v8::Context` is created from a `v8::Isolate` deserialized
from the snapshot. There are four context snapshots in the snapshot blob.

1. The default context snapshot, used for contexts created by
`v8::Context::New()`, it only contains V8 built-ins, matching the
layout of the isolate snapshot.
1. The vm context snapshot, which can be deserialized using
`v8::Context::FromSnapshot(isolate, node::SnapshotData::kNodeVMContextIndex, ...)`.
It captures initializations specific to vm contexts done by
`node::contextify::ContextifyContext::CreateV8Context()`.
1. The base context snapshot, which can be deserialized using
`v8::Context::FromSnapshot(isolate, node::SnapshotData::kNodeBaseContextIndex, ...)`.
It currently captures initializations done by `node::NewContext()`
but is intended to include more as a basis for worker thread
contexts.
1. The main context snapshot, which can be deserialized using
`v8::Context::FromSnapshot(isolate, node::SnapshotData::kNodeMainContextIndex, ...)`.
This is the snapshot for the main context on the main thread, and
captures initializations done by `node::CommonEnvironmentSetup::CreateForSnapshotting()`,
most notably `node::CreateEnvironment()`, which runs the following scripts via
`node::Realm::RunBootstrapping()` for the main context as a principal realm,
so that at runtime, these scripts do not need to be run. Instead only the context
initialized by them is deserialized at runtime.
1. `internal/bootstrap/realm`
2. `internal/bootstrap/node`
3. `internal/bootstrap/web/exposed-wildcard`
4. `internal/bootstrap/web/exposed-window-or-worker`
5. `internal/bootstrap/switches/is_main_thread`
6. `internal/bootstrap/switches/does_own_process_state`

For more information about these contexts, see the comment in `src/node_context_data.h`.

## How it's built and used

Expand Down Expand Up @@ -39,3 +76,22 @@ For debugging, Node.js can be built without Node.js's own snapshot if
`--without-node-snapshot` is passed to `configure`. A Node.js executable
with Node.js snapshot embedded can also be launched without deserializing
from it if the command line argument `--no-node-snapshot` is passed.

### When `node_mksnapshot` crashes..

Due to this two-phase building process, sometimes when there is an issue
in the code, the build may crash early at executing `node_mksnapshot` instead of crashing
at executing the final executable `node`. If the crash can be reproduced when running
the `node` executable built with `--without-node-snapshot`, it means the crash likely
has nothing to do with snapshots, and only shows up in `node_mksnapshot` because it's
the first Node.js executable being run.

If the crash comes from a `mksnapshot` executable (notice that it doesn't have the `node_`
prefix), that comes from V8's own snapshot building process, not the one in Node.js, and the
fix likely needs to be in V8 or the build configurations of V8.

If it `node_mksnapshot` crashes with an error message containing
something like `Unknown external reference 0x107769200`, see
[Registering binding functions used in bootstrap][] on how to fix it.

[Registering binding functions used in bootstrap]: ../../src/README.md#registering-binding-functions-used-in-bootstrap
Loading