This document summarizes the bootstrap process for Node.js core. It describes how Node.js initializes V8, parses command line arguments, loads built-in modules and the main script, sets up global objects and environments, and eventually runs the event loop. It also discusses ongoing work to optimize startup time through refactoring and integrating with V8's snapshot feature to deserialize context objects instead of re-executing initialization code.
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Bootstrap of Node.js Core (OpenJS Collaborator Summit Berlin 2019)
1. Bootstrap of Node.js Core
Joyee Cheung
Slides: https://github.com/nodejs/summit/issues/147
OpenJS collaboration summit, May 2019
2. A Node.js Process
Main Instance (JS thread)
Worker (if any)
(JS thread)
Task Scheduler
V8 Platform
thread pool
Inspector I/O
libuv
thread pool
Environment
Main V8
Context
VM V8
Context
V8 Isolate
Event
loop
6. Bootstrap (2019.05)
InitializeOncePerProcess()
Parse the CLI arguments, Initialize the V8
Platform,OpenSSL, ICU, signal handler…
node::Start()
NodeMainInstance() / Worker()
v8::Isolate
JS heap, JS exceptions,
Microtask queue...
7. Bootstrap (2019.05)
InitializeOncePerProcess()
Parse the CLI arguments, Initialize the V8
Platform,OpenSSL, ICU, signal handler…
node::Start()
NodeMainInstance() / Worker()
v8::Isolate
v8::Context
JS heap, JS exceptions,
Microtask queue...
global proxy, JS builtins
8. Bootstrap (2019.05)
InitializeOncePerProcess()
Parse the CLI arguments, Initialize the V8
Platform,OpenSSL, ICU, signal handler…
node::Start()
NodeMainInstance() / Worker()
v8::Isolate
v8::Context
JS heap, JS exceptions,
Microtask queue...
per_context/*.js Node.js primordials
global proxy, JS builtins
9. Primordials
u JavaScript builtins like Object, Object.prototype are cloned onto
an object and frozen for internal use
u Users can delete Function.prototype.call
u WIP to transition all internal usage of these
10. Bootstrap (2019.05)
InitializeOncePerProcess()
Parse the CLI arguments, Initialize the V8
Platform,signal handler…
node::Start()
NodeMainInstance() / Worker()
v8::Isolate
v8::Context
node::Environment
JS heap, JS exceptions,
Microtask queue...
per_context/*.js Node.js primordials
global proxy, JS builtins
Stuff that does not
have a better place to
go
11. Bootstrap (2019.05)
InitializeOncePerProcess()
Parse the CLI arguments, Initialize the V8
Platform,signal handler…
node::Start()
NodeMainInstance() / Worker()
v8::Isolate
v8::Context
node::Environment
JS heap, JS exceptions,
Microtask queue...
per_context/*.js Node.js primordials
global proxy, JS builtins
Stuff that does not
have a better place to
go
libuv handles
12. Bootstrap (2019.05)
InitializeOncePerProcess()
Parse the CLI arguments, Initialize the V8
Platform,signal handler…
node::Start()
NodeMainInstance() / Worker()
v8::Isolate
v8::Context
node::Environment
JS heap, JS exceptions,
Microtask queue...
per_context/*.js Node.js primordials
global proxy, JS builtins
Stuff that does not
have a better place to
go
libuv handles
inspector agent
13. Bootstrap (2019.05)
InitializeOncePerProcess()
Parse the CLI arguments, Initialize the V8
Platform,signal handler…
node::Start()
NodeMainInstance() / Worker()
v8::Isolate
v8::Context
node::Environment
JS heap, JS exceptions,
Microtask queue...
per_context/*.js Node.js primordials
global proxy, JS builtins
Stuff that does not
have a better place to
go
bootstrap/*.js
global, process, task
queues, ESM/CJS
loaders ...
libuv handles
inspector agent
14. lib/internal/bootstrap/loaders.js
u Internal module loaders
u C++ binding loaders
u process.binding()
u process._linkedBinding()
u internalBinding()
u require() for loading other internal JavaScript modules
17. Built-in Modules (Native Modules)
Compiled with a special wrapper
that include access to more internals
function (exports, require, module, process,
internalBinding, primordials) {
require(‘internal/fs/utils’);
module.exports = {…};
}
18. lib/internal/bootstrap/node.js
u Set up most stuff on process and global
u C++ passes isMainThread, ownsProcessState into the script
u false for workers, true for the main thread
19. lib/internal/bootstrap/node.js
u Set up most stuff on process and global
u C++ passes isMainThread, ownsProcessState into the script
u false for workers, true for the main thread
u Set up JavaScript callbacks that will be added as v8::Persistent to the
Environment
u Async hook callbacks
u Timers & process.nextTick() schedulers
u Must not run async operations (not snapshottable)
u Must not depend on any CLI arguments or environment variables
21. Bootstrap (2019.05)
InitializeOncePerProcess()
Parse the CLI arguments, Initialize the V8
Platform,signal handler…
node::Start()
NodeMainInstance() / Worker()
v8::Isolate
v8::Context
node::Environment
JS heap, JS exceptions,
Microtask queue...
per_context/*.js Node.js primordials
global proxy, JS builtins
Stuff that does not
have a better place to
go
bootstrap/*.js
main/?.js e.g.
run_main_module.js
global, process, task
queues, ESM/CJS
loaders ...
libuv handles
inspector agent
22. Main scripts
u lib/internal/main/*.js
u Main thread
uStartMainThreadExecution()
uSelect a script based on CLI arguments, etc.
u Worker threads
uworker_thread.js
u Runs lib/internal/bootstrap/pre_execution.js
first to bootstrap the parts that depend on run time states
23. Main scripts
u check_syntax.js: node –c test.js
u eval_stdin.js: cat test.js | node –e
u eval_string.js: node –e ‘1’
u inspect.js: node inspect ...
u print_bash_completion.js: node --completion-bash
u print_help.js: node --help
u prof_process.js: node --prof-process v8.log
24. Main scripts
u run_third_party_main.js
u Run lib/_third_party_main.js embedders
u environment.js
u For C++ test fixtures
Requested
u bundled cli tool entry point?
u better entry point for embedders?
25. Main scripts
u repl.js: node
u worker_thread.js: for workers
u run_main_module.js
u node index.js
u node --experimental-modules index.mjs
26. Main scripts
u repl.js: node
u run_main_module.js
u node index.js
u node --experimental-modules index.mjs
u worker_thread.js: for workers
27. lib/internal/bootstrap/pre_execution.js
u Bootstrap that depend on run time states
ue.g. CLI arguments, environment variables
uIncluding CJS & ESM loader initilization
if (!getOptionValue('--no-warnings') &&
process.env.NODE_NO_WARNINGS !== '1') {
process.on('warning', onWarning);
}
28. User land CommonJS Modules
function (exports, require, module, __filename, __dirname) {
require(‘fs’);
}
u Loader implemented in lib/internal/modules/cjs/
Wrap user code with objects initialized by Node.js
29. User land ECMAScript Modules
u Loader implementation in lib/internal/modules/esm/
u Does not mess with the context except things added to the
global proxy
uBuffer, process, etc.
30. User land ECMAScript Modules
u An internal WeakMap holding ModuleWrap -> Options
uOptions includes dynamic import() callback and
import.meta data
uPer-isolate
uHostImportModuleDynamicallyCallback
uHostInitializeImportMetaObjectCallback
31. Bootstrap (2019.05)
InitializeOncePerProcess()
Parse the CLI arguments, Initialize the V8
Platform,signal handler…
node::Start()
NodeMainInstance() / Worker()
v8::Isolate
v8::Context
node::Environment
do {
uv_run(...)
} while (...)
Event Loop
JS heap, JS exceptions,
Microtask queue...
per_context/*.js Node.js primordials
global proxy, JS builtins
Stuff that does not
have a better place to
go
bootstrap/*.js
main/?.js e.g.
run_main_module.js
global, process, task
queues, ESM/CJS
loaders ...
libuv handles
inspector agent
38. Snapshot Integration
Environment:: FromSnapshot()
The bootstrap process must be
independent of run time states before
the snapshot is captured.
v8::Isolate
Context::FromSnapshot()
SetIsolateUpForNode()
Re-install callbacks
main/?.js
loop & inspector
Refactoring
42. Current state
u v12.3.1 v.s. v10.16.0
u ~60% faster child process startup
u ~120% faster worker startup
u Some refactoring has also been backported to v10 so the
actual speed up is higher
43. Current state
u v12.3.1 v.s. v10.16.0
u ~60% faster child process startup
u ~120% faster worker startup
u Some refactoring has also been backported to v10 so the
actual speed up is higher
u Mostly from lazy-loading and embedded code cache
u Further speedup anticipated from snapshot integration
u 4x in https://github.com/nodejs/node/issues/17058
44. Challenges
u Lack of reviews
u https://github.com/nodejs/node/pull/27539 27 days without
reviews
u Incrementally refactoring the spaghetti code + 7-day wait = slow
45. Challenges
u Lack of reviews
u https://github.com/nodejs/node/pull/27539 27 days without
reviews
u Incrementally refactoring the spaghetti code + 7-day wait = slow
u Fixed hash seed
u Rehashing maps & sets
u https://bugs.chromium.org/p/v8/issues/detail?id=9187
u Snapshot is currently still disabled on master behind a build time
flag
46. Future plans
u Finish integration before v12 LTS
u Explore user-land snapshot builder & loader