README.md
1# Node.js C++ codebase
2
3Hi! You’ve found the C++ code backing Node.js. This README aims to help you
4get started working on it and document some idioms you may encounter while
5doing so.
6
7## Coding style
8
9Node.js has a document detailing its [C++ coding style][]
10that can be helpful as a reference for stylistic issues.
11
12## V8 API documentation
13
14A lot of the Node.js codebase is around what the underlying JavaScript engine,
15V8, provides through its API for embedders. Knowledge of this API can also be
16useful when working with native addons for Node.js written in C++, although for
17new projects [N-API][] is typically the better alternative.
18
19V8 does not provide much public API documentation beyond what is
20available in its C++ header files, most importantly `v8.h`, which can be
21accessed online in the following locations:
22
23* On GitHub: [`v8.h` in Node.js master][]
24* On GitHub: [`v8.h` in V8 master][]
25* On the Chromium project’s Code Search application: [`v8.h` in Code Search][]
26
27V8 also provides an [introduction for V8 embedders][],
28which can be useful for understanding some of the concepts it uses in its
29embedder API.
30
31Important concepts when using V8 are the ones of [`Isolate`][]s and
32[JavaScript value handles][].
33
34## libuv API documentation
35
36The other major dependency of Node.js is [libuv][], providing
37the [event loop][] and other operation system abstractions to Node.js.
38
39There is a [reference documentation for the libuv API][].
40
41## File structure
42
43The Node.js C++ files follow this structure:
44
45The `.h` header files contain declarations, and sometimes definitions that don’t
46require including other headers (e.g. getters, setters, etc.). They should only
47include other `.h` header files and nothing else.
48
49The `-inl.h` header files contain definitions of inline functions from the
50corresponding `.h` header file (e.g. functions marked `inline` in the
51declaration or `template` functions). They always include the corresponding
52`.h` header file, and can include other `.h` and `-inl.h` header files as
53needed. It is not mandatory to split out the definitions from the `.h` file
54into an `-inl.h` file, but it becomes necessary when there are multiple
55definitions and contents of other `-inl.h` files start being used. Therefore, it
56is recommended to split a `-inl.h` file when inline functions become longer than
57a few lines to keep the corresponding `.h` file readable and clean. All visible
58definitions from the `-inl.h` file should be declared in the corresponding `.h`
59header file.
60
61The `.cc` files contain definitions of non-inline functions from the
62corresponding `.h` header file. They always include the corresponding `.h`
63header file, and can include other `.h` and `-inl.h` header files as needed.
64
65## Helpful concepts
66
67A number of concepts are involved in putting together Node.js on top of V8 and
68libuv. This section aims to explain some of them and how they work together.
69
70<a id="isolate"></a>
71### `Isolate`
72
73The `v8::Isolate` class represents a single JavaScript engine instance, in
74particular a set of JavaScript objects that can refer to each other
75(the “heap”).
76
77The `v8::Isolate` is often passed to other V8 API functions, and provides some
78APIs for managing the behaviour of the JavaScript engine or querying about its
79current state or statistics such as memory usage.
80
81V8 APIs are not thread-safe unless explicitly specified. In a typical Node.js
82application, the main thread and any `Worker` threads each have one `Isolate`,
83and JavaScript objects from one `Isolate` cannot refer to objects from
84another `Isolate`.
85
86Garbage collection, as well as other operations that affect the entire heap,
87happen on a per-`Isolate` basis.
88
89Typical ways of accessing the current `Isolate` in the Node.js code are:
90
91* Given a `FunctionCallbackInfo` for a [binding function][],
92 using `args.GetIsolate()`.
93* Given a [`Context`][], using `context->GetIsolate()`.
94* Given a [`Environment`][], using `env->isolate()`.
95
96### V8 JavaScript values
97
98V8 provides classes that mostly correspond to JavaScript types; for example,
99`v8::Value` is a class representing any kind of JavaScript type, with
100subclasses such as `v8::Number` (which in turn has subclasses like `v8::Int32`),
101`v8::Boolean` or `v8::Object`. Most types are represented by subclasses
102of `v8::Object`, e.g. `v8::Uint8Array` or `v8::Date`.
103
104<a id="internal-fields"></a>
105### Internal fields
106
107V8 provides the ability to store data in so-called “internal fields” inside
108`v8::Object`s that were created as instances of C++-backed classes. The number
109of fields needs to be defined when creating that class.
110
111Both JavaScript values and `void*` pointers may be stored in such fields.
112In most native Node.js objects, the first internal field is used to store a
113pointer to a [`BaseObject`][] subclass, which then contains all relevant
114information associated with the JavaScript object.
115
116Typical ways of working with internal fields are:
117
118* `obj->InternalFieldCount()` to look up the number of internal fields for an
119 object (`0` for regular JavaScript objects).
120* `obj->GetInternalField(i)` to get a JavaScript value from an internal field.
121* `obj->SetInternalField(i, v)` to store a JavaScript value in an
122 internal field.
123* `obj->GetAlignedPointerFromInternalField(i)` to get a `void*` pointer from an
124 internal field.
125* `obj->SetAlignedPointerInInternalField(i, p)` to store a `void*` pointer in an
126 internal field.
127
128[`Context`][]s provide the same feature under the name “embedder data”.
129
130<a id="js-handles"></a>
131### JavaScript value handles
132
133All JavaScript values are accessed through the V8 API through so-called handles,
134of which there are two types: [`Local`][]s and [`Global`][]s.
135
136<a id="local-handles"></a>
137#### `Local` handles
138
139A `v8::Local` handle is a temporary pointer to a JavaScript object, where
140“temporary” usually means that is no longer needed after the current function
141is done executing. `Local` handles can only be allocated on the C++ stack.
142
143Most of the V8 API uses `Local` handles to work with JavaScript values or return
144them from functions.
145
146Whenever a `Local` handle is created, a `v8::HandleScope` or
147`v8::EscapableHandleScope` object must exist on the stack. The `Local` is then
148added to that scope and deleted along with it.
149
150When inside a [binding function][], a `HandleScope` already exists outside of
151it, so there is no need to explicitly create one.
152
153`EscapableHandleScope`s can be used to allow a single `Local` handle to be
154passed to the outer scope. This is useful when a function returns a `Local`.
155
156The following JavaScript and C++ functions are mostly equivalent:
157
158```js
159function getFoo(obj) {
160 return obj.foo;
161}
162```
163
164```cpp
165v8::Local<v8::Value> GetFoo(v8::Local<v8::Context> context,
166 v8::Local<v8::Object> obj) {
167 v8::Isolate* isolate = context->GetIsolate();
168 v8::EscapableHandleScope handle_scope(isolate);
169
170 // The 'foo_string' handle cannot be returned from this function because
171 // it is not “escaped” with `.Escape()`.
172 v8::Local<v8::String> foo_string =
173 v8::String::NewFromUtf8(isolate, "foo").ToLocalChecked();
174
175 v8::Local<v8::Value> return_value;
176 if (obj->Get(context, foo_string).ToLocal(&return_value)) {
177 return handle_scope.Escape(return_value);
178 } else {
179 // There was a JS exception! Handle it somehow.
180 return v8::Local<v8::Value>();
181 }
182}
183```
184
185See [exception handling][] for more information about the usage of `.To()`,
186`.ToLocalChecked()`, `v8::Maybe` and `v8::MaybeLocal` usage.
187
188##### Casting local handles
189
190If it is known that a `Local<Value>` refers to a more specific type, it can
191be cast to that type using `.As<...>()`:
192
193```cpp
194v8::Local<v8::Value> some_value;
195// CHECK() is a Node.js utilitity that works similar to assert().
196CHECK(some_value->IsUint8Array());
197v8::Local<v8::Uint8Array> as_uint8 = some_value.As<v8::Uint8Array>();
198```
199
200Generally, using `val.As<v8::X>()` is only valid if `val->IsX()` is true, and
201failing to follow that rule may lead to crashes.
202
203##### Detecting handle leaks
204
205If it is expected that no `Local` handles should be created within a given
206scope unless explicitly within a `HandleScope`, a `SealHandleScope` can be used.
207
208For example, there is a `SealHandleScope` around the event loop, forcing
209any functions that are called from the event loop and want to run or access
210JavaScript code to create `HandleScope`s.
211
212<a id="global-handles"></a>
213#### `Global` handles
214
215A `v8::Global` handle (sometimes also referred to by the name of its parent
216class `Persistent`, although use of that is discouraged in Node.js) is a
217reference to a JavaScript object that can remain active as long as the engine
218instance is active.
219
220Global handles can be either strong or weak. Strong global handles are so-called
221“GC roots”, meaning that they will keep the JavaScript object they refer to
222alive even if no other objects refer to them. Weak global handles do not do
223that, and instead optionally call a callback when the object they refer to
224is garbage-collected.
225
226```cpp
227v8::Global<v8::Object> reference;
228
229void StoreReference(v8::Isolate* isolate, v8::Local<v8::Object> obj) {
230 // Create a strong reference to `obj`.
231 reference.Reset(isolate, obj);
232}
233
234// Must be called with a HandleScope around it.
235v8::Local<v8::Object> LoadReference(v8::Isolate* isolate) {
236 return reference.Get(isolate);
237}
238```
239
240##### `Eternal` handles
241
242`v8::Eternal` handles are a special kind of handles similar to `v8::Global`
243handles, with the exception that the values they point to are never
244garbage-collected while the JavaScript Engine instance is alive, even if
245the `v8::Eternal` itself is destroyed at some point. This type of handle
246is rarely used.
247
248<a id="context"></a>
249### `Context`
250
251JavaScript allows multiple global objects and sets of built-in JavaScript
252objects (like the `Object` or `Array` functions) to coexist inside the same
253heap. Node.js exposes this ability through the [`vm` module][].
254
255V8 refers to each of these global objects and their associated builtins as a
256`Context`.
257
258Currently, in Node.js there is one main `Context` associated with an
259[`Environment`][] instance, and most Node.js features will only work inside
260that context. (The only exception at the time of writing are
261[`MessagePort`][] objects.) This restriction is not inherent to the design of
262Node.js, and a sufficiently committed person could restructure Node.js to
263provide built-in modules inside of `vm.Context`s.
264
265Often, the `Context` is passed around for [exception handling][].
266Typical ways of accessing the current `Context` in the Node.js code are:
267
268* Given an [`Isolate`][], using `isolate->GetCurrentContext()`.
269* Given an [`Environment`][], using `env->context()` to get the `Environment`’s
270 main context.
271
272<a id="event-loop"></a>
273### Event loop
274
275The main abstraction for an event loop inside Node.js is the `uv_loop_t` struct.
276Typically, there is one event loop per thread. This includes not only the main
277thread and Workers, but also helper threads that may occasionally be spawned
278in the course of running a Node.js program.
279
280The current event loop can be accessed using `env->event_loop()` given an
281[`Environment`][] instance. The restriction of using a single event loop
282is not inherent to the design of Node.js, and a sufficiently committed person
283could restructure Node.js to provide e.g. the ability to run parts of Node.js
284inside an event loop separate from the active thread’s event loop.
285
286<a id="environment"></a>
287### `Environment`
288
289Node.js instances are represented by the `Environment` class.
290
291Currently, every `Environment` class is associated with:
292
293* One [event loop][]
294* One [`Isolate`][]
295* One main [`Context`][]
296
297The `Environment` class contains a large number of different fields for
298different Node.js modules, for example a libuv timer for `setTimeout()` or
299the memory for a `Float64Array` that the `fs` module uses for storing data
300returned from a `fs.stat()` call.
301
302It also provides [cleanup hooks][] and maintains a list of [`BaseObject`][]
303instances.
304
305Typical ways of accessing the current `Environment` in the Node.js code are:
306
307* Given a `FunctionCallbackInfo` for a [binding function][],
308 using `Environment::GetCurrent(args)`.
309* Given a [`BaseObject`][], using `env()` or `self->env()`.
310* Given a [`Context`][], using `Environment::GetCurrent(context)`.
311 This requires that `context` has been associated with the `Environment`
312 instance, e.g. is the main `Context` for the `Environment` or one of its
313 `vm.Context`s.
314* Given an [`Isolate`][], using `Environment::GetCurrent(isolate)`. This looks
315 up the current [`Context`][] and then uses that.
316
317<a id="isolate-data"></a>
318### `IsolateData`
319
320Every Node.js instance ([`Environment`][]) is associated with one `IsolateData`
321instance that contains information about or associated with a given
322[`Isolate`][].
323
324#### String table
325
326`IsolateData` contains a list of strings that can be quickly accessed
327inside Node.js code, e.g. given an `Environment` instance `env` the JavaScript
328string “name” can be accessed through `env->name_string()` without actually
329creating a new JavaScript string.
330
331### Platform
332
333Every process that uses V8 has a `v8::Platform` instance that provides some
334functionalities to V8, most importantly the ability to schedule work on
335background threads.
336
337Node.js provides a `NodePlatform` class that implements the `v8::Platform`
338interface and uses libuv for providing background threading abilities.
339
340The platform can be accessed through `isolate_data->platform()` given an
341[`IsolateData`][] instance, although that only works when:
342
343* The current Node.js instance was not started by an embedder; or
344* The current Node.js instance was started by an embedder whose `v8::Platform`
345 implementation also implement’s the `node::MultiIsolatePlatform` interface
346 and who passed this to Node.js.
347
348<a id="binding-functions"></a>
349### Binding functions
350
351C++ functions exposed to JS follow a specific signature. The following example
352is from `node_util.cc`:
353
354```cpp
355void ArrayBufferViewHasBuffer(const FunctionCallbackInfo<Value>& args) {
356 CHECK(args[0]->IsArrayBufferView());
357 args.GetReturnValue().Set(args[0].As<ArrayBufferView>()->HasBuffer());
358}
359```
360
361(Namespaces are usually omitted through the use of `using` statements in the
362Node.js source code.)
363
364`args[n]` is a `Local<Value>` that represents the n-th argument passed to the
365function. `args.This()` is the `this` value inside this function call.
366`args.Holder()` is equivalent to `args.This()` in all use cases inside of
367Node.js.
368
369`args.GetReturnValue()` is a placeholder for the return value of the function,
370and provides a `.Set()` method that can be called with a boolean, integer,
371floating-point number or a `Local<Value>` to set the return value.
372
373Node.js provides various helpers for building JS classes in C++ and/or attaching
374C++ functions to the exports of a built-in module:
375
376```cpp
377void Initialize(Local<Object> target,
378 Local<Value> unused,
379 Local<Context> context,
380 void* priv) {
381 Environment* env = Environment::GetCurrent(context);
382
383 env->SetMethod(target, "getaddrinfo", GetAddrInfo);
384 env->SetMethod(target, "getnameinfo", GetNameInfo);
385
386 // 'SetMethodNoSideEffect' means that debuggers can safely execute this
387 // function for e.g. previews.
388 env->SetMethodNoSideEffect(target, "canonicalizeIP", CanonicalizeIP);
389
390 // ... more code ...
391
392 // Building the `ChannelWrap` class for JS:
393 Local<FunctionTemplate> channel_wrap =
394 env->NewFunctionTemplate(ChannelWrap::New);
395 // Allow for 1 internal field, see `BaseObject` for details on this:
396 channel_wrap->InstanceTemplate()->SetInternalFieldCount(1);
397 channel_wrap->Inherit(AsyncWrap::GetConstructorTemplate(env));
398
399 // Set various methods on the class (i.e. on the prototype):
400 env->SetProtoMethod(channel_wrap, "queryAny", Query<QueryAnyWrap>);
401 env->SetProtoMethod(channel_wrap, "queryA", Query<QueryAWrap>);
402 // ...
403 env->SetProtoMethod(channel_wrap, "querySoa", Query<QuerySoaWrap>);
404 env->SetProtoMethod(channel_wrap, "getHostByAddr", Query<GetHostByAddrWrap>);
405
406 env->SetProtoMethodNoSideEffect(channel_wrap, "getServers", GetServers);
407
408 env->SetConstructorFunction(target, "ChannelWrap", channel_wrap);
409}
410
411// Run the `Initialize` function when loading this module through
412// `internalBinding('cares_wrap')` in Node.js’s built-in JavaScript code:
413NODE_MODULE_CONTEXT_AWARE_INTERNAL(cares_wrap, Initialize)
414```
415
416If the C++ binding is loaded during bootstrap, it needs to be registered
417with the utilities in `node_external_reference.h`, like this:
418
419```cpp
420namespace node {
421namespace utils {
422void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
423 registry->Register(GetHiddenValue);
424 registry->Register(SetHiddenValue);
425 // ... register all C++ functions used to create FunctionTemplates.
426}
427} // namespace util
428} // namespace node
429
430// The first argument passed to `NODE_MODULE_EXTERNAL_REFERENCE`,
431// which is `util` here, needs to be added to the
432// `EXTERNAL_REFERENCE_BINDING_LIST_BASE` list in node_external_reference.h
433NODE_MODULE_EXTERNAL_REFERENCE(util, node::util::RegisterExternalReferences)
434```
435
436Otherwise, you might see an error message like this when building the
437executables:
438
439```console
440FAILED: gen/node_snapshot.cc
441cd ../../; out/Release/node_mksnapshot out/Release/gen/node_snapshot.cc
442Unknown external reference 0x107769200.
443<unresolved>
444/bin/sh: line 1: 6963 Illegal instruction: 4 out/Release/node_mksnapshot out/Release/gen/node_snapshot.cc
445```
446
447You can try using a debugger to symbolicate the external reference. For example,
448with lldb's `image lookup --address` command (with gdb it's `info symbol`):
449
450```console
451$ lldb -- out/Release/node_mksnapshot out/Release/gen/node_snapshot.cc
452(lldb) run
453Process 7012 launched: '/Users/joyee/projects/node/out/Release/node_mksnapshot' (x86_64)
454Unknown external reference 0x1004c8200.
455<unresolved>
456Process 7012 stopped
457(lldb) image lookup --address 0x1004c8200
458 Address: node_mksnapshot[0x00000001004c8200] (node_mksnapshot.__TEXT.__text + 5009920)
459 Summary: node_mksnapshot`node::util::GetHiddenValue(v8::FunctionCallbackInfo<v8::Value> const&) at node_util.cc:159
460```
461
462Which explains that the unregistered external reference is
463`node::util::GetHiddenValue` defined in `node_util.cc`.
464
465<a id="per-binding-state"></a>
466#### Per-binding state
467
468Some internal bindings, such as the HTTP parser, maintain internal state that
469only affects that particular binding. In that case, one common way to store
470that state is through the use of `Environment::AddBindingData`, which gives
471binding functions access to an object for storing such state.
472That object is always a [`BaseObject`][].
473
474Its class needs to have a static `type_name` field based on a
475constant string, in order to disambiguate it from other classes of this type,
476and which could e.g. match the binding’s name (in the example above, that would
477be `cares_wrap`).
478
479```cpp
480// In the HTTP parser source code file:
481class BindingData : public BaseObject {
482 public:
483 BindingData(Environment* env, Local<Object> obj) : BaseObject(env, obj) {}
484
485 static constexpr FastStringKey type_name { "http_parser" };
486
487 std::vector<char> parser_buffer;
488 bool parser_buffer_in_use = false;
489
490 // ...
491};
492
493// Available for binding functions, e.g. the HTTP Parser constructor:
494static void New(const FunctionCallbackInfo<Value>& args) {
495 BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
496 new Parser(binding_data, args.This());
497}
498
499// ... because the initialization function told the Environment to store the
500// BindingData object:
501void InitializeHttpParser(Local<Object> target,
502 Local<Value> unused,
503 Local<Context> context,
504 void* priv) {
505 Environment* env = Environment::GetCurrent(context);
506 BindingData* const binding_data =
507 env->AddBindingData<BindingData>(context, target);
508 if (binding_data == nullptr) return;
509
510 Local<FunctionTemplate> t = env->NewFunctionTemplate(Parser::New);
511 ...
512}
513```
514
515If the binding is loaded during bootstrap, add it to the
516`SERIALIZABLE_OBJECT_TYPES` list in `src/node_snapshotable.h` and
517inherit from the `SnapshotableObject` class instead. See the comments
518of `SnapshotableObject` on how to implement its serialization and
519deserialization.
520
521<a id="exception-handling"></a>
522### Exception handling
523
524The V8 engine provides multiple features to work with JavaScript exceptions,
525as C++ exceptions are disabled inside of Node.js:
526
527#### Maybe types
528
529V8 provides the `v8::Maybe<T>` and `v8::MaybeLocal<T>` types, typically used
530as return values from API functions that can run JavaScript code and therefore
531can throw exceptions.
532
533Conceptually, the idea is that every `v8::Maybe<T>` is either empty (checked
534through `.IsNothing()`) or holds a value of type `T` (checked through
535`.IsJust()`). If the `Maybe` is empty, then a JavaScript exception is pending.
536A typical way of accessing the value is using the `.To()` function, which
537returns a boolean indicating success of the operation (i.e. the `Maybe` not
538being empty) and taking a pointer to a `T` to store the value if there is one.
539
540##### Checked conversion
541
542`maybe.Check()` can be used to assert that the maybe is not empty, i.e. crash
543the process otherwise. `maybe.FromJust()` (aka `maybe.ToChecked()`) can be used
544to access the value and crash the process if it is not set.
545
546This should only be performed if it is actually sure that the operation has
547not failed. A lot of Node.js’s source code does **not** follow this rule, and
548can be brought to crash through this.
549
550In particular, it is often not safe to assume that an operation does not throw
551an exception, even if it seems like it would not do that.
552The most common reasons for this are:
553
554* Calls to functions like `object->Get(...)` or `object->Set(...)` may fail on
555 most objects, if the `Object.prototype` object has been modified from userland
556 code that added getters or setters.
557* Calls that invoke *any* JavaScript code, including JavaScript code that is
558 provided from Node.js internals or V8 internals, will fail when JavaScript
559 execution is being terminated. This typically happens inside Workers when
560 `worker.terminate()` is called, but it can also affect the main thread when
561 e.g. Node.js is used as an embedded library. These exceptions can happen at
562 any point.
563 It is not always obvious whether a V8 call will enter JavaScript. In addition
564 to unexpected getters and setters, accessing some types of built-in objects
565 like `Map`s and `Set`s can also run V8-internal JavaScript code.
566
567##### MaybeLocal
568
569`v8::MaybeLocal<T>` is a variant of `v8::Maybe<T>` that is either empty or
570holds a value of type `Local<T>`. It has methods that perform the same
571operations as the methods of `v8::Maybe`, but with different names:
572
573| `Maybe` | `MaybeLocal` |
574| -------------------- | ------------------------------ |
575| `maybe.IsNothing()` | `maybe_local.IsEmpty()` |
576| `maybe.IsJust()` | `!maybe_local.IsEmpty()` |
577| `maybe.To(&value)` | `maybe_local.ToLocal(&local)` |
578| `maybe.ToChecked()` | `maybe_local.ToLocalChecked()` |
579| `maybe.FromJust()` | `maybe_local.ToLocalChecked()` |
580| `maybe.Check()` | – |
581| `v8::Nothing<T>()` | `v8::MaybeLocal<T>()` |
582| `v8::Just<T>(value)` | `v8::MaybeLocal<T>(value)` |
583
584##### Handling empty `Maybe`s
585
586Usually, the best approach to encountering an empty `Maybe` is to just return
587from the current function as soon as possible, and let execution in JavaScript
588land resume. If the empty `Maybe` is encountered inside a nested function,
589is may be a good idea to use a `Maybe` or `MaybeLocal` for the return type
590of that function and pass information about pending JavaScript exceptions along
591that way.
592
593Generally, when an empty `Maybe` is encountered, it is not valid to attempt
594to perform further calls to APIs that return `Maybe`s.
595
596A typical pattern for dealing with APIs that return `Maybe` and `MaybeLocal` is
597using `.ToLocal()` and `.To()` and returning early in case there is an error:
598
599```cpp
600// This could also return a v8::MaybeLocal<v8::Number>, for example.
601v8::Maybe<double> SumNumbers(v8::Local<v8::Context> context,
602 v8::Local<v8::Array> array_of_integers) {
603 v8::Isolate* isolate = context->GetIsolate();
604 v8::HandleScope handle_scope(isolate);
605
606 double sum = 0;
607
608 for (uint32_t i = 0; i < array_of_integers->Length(); i++) {
609 v8::Local<v8::Value> entry;
610 if (array_of_integers->Get(context, i).ToLocal(&entry)) {
611 // Oops, we might have hit a getter that throws an exception!
612 // It’s better to not continue return an empty (“nothing”) Maybe.
613 return v8::Nothing<double>();
614 }
615
616 if (!entry->IsNumber()) {
617 // Let’s just skip any non-numbers. It would also be reasonable to throw
618 // an exception here, e.g. using the error system in src/node_errors.h,
619 // and then to return an empty Maybe again.
620 continue;
621 }
622
623 // This cast is valid, because we’ve made sure it’s really a number.
624 v8::Local<v8::Number> entry_as_number = entry.As<v8::Number>();
625
626 sum += entry_as_number->Value();
627 }
628
629 return v8::Just(sum);
630}
631
632// Function that is exposed to JS:
633void SumNumbers(const v8::FunctionCallbackInfo<v8::Value>& args) {
634 // This will crash if the first argument is not an array. Let’s assume we
635 // have performed type checking in a JavaScript wrapper function.
636 CHECK(args[0]->IsArray());
637
638 double sum;
639 if (!SumNumbers(args.GetIsolate()->GetCurrentContext(),
640 args[0].As<v8::Array>()).To(&sum)) {
641 // Nothing to do, we can just return directly to JavaScript.
642 return;
643 }
644
645 args.GetReturnValue().Set(sum);
646}
647```
648
649#### TryCatch
650
651If there is a need to catch JavaScript exceptions in C++, V8 provides the
652`v8::TryCatch` type for doing so, which we wrap into our own
653`node::errors::TryCatchScope` in Node.js. The latter has the additional feature
654of providing the ability to shut down the program in the typical Node.js way
655(printing the exception + stack trace) if an exception is caught.
656
657A `TryCatch` will catch regular JavaScript exceptions, as well as termination
658exceptions such as the ones thrown by `worker.terminate()` calls.
659In the latter case, the `try_catch.HasTerminated()` function will return `true`,
660and the exception object will not be a meaningful JavaScript value.
661`try_catch.ReThrow()` should not be used in this case.
662
663<a id="libuv-handles-and-requests"></a>
664### libuv handles and requests
665
666Two central concepts when working with libuv are handles and requests.
667
668Handles are subclasses of the `uv_handle_t` “class”, and generally refer to
669long-lived objects that can emit events multiple times, such as network sockets
670or file system watchers.
671
672In Node.js, handles are often managed through a [`HandleWrap`][] subclass.
673
674Requests are one-time asynchronous function calls on the event loop, such as
675file system requests or network write operations, that either succeed or fail.
676
677In Node.js, requests are often managed through a [`ReqWrap`][] subclass.
678
679### Environment cleanup
680
681When a Node.js [`Environment`][] is destroyed, it generally needs to clean up
682any resources owned by it, e.g. memory or libuv requests/handles.
683
684<a id="cleanup-hooks"></a>
685#### Cleanup hooks
686
687Cleanup hooks are provided that run before the [`Environment`][]
688is destroyed. They can be added and removed through by using
689`env->AddCleanupHook(callback, hint);` and
690`env->RemoveCleanupHook(callback, hint);`, where callback takes a `void* hint`
691argument.
692
693Inside these cleanup hooks, new asynchronous operations *may* be started on the
694event loop, although ideally that is avoided as much as possible.
695
696Every [`BaseObject`][] has its own cleanup hook that deletes it. For
697[`ReqWrap`][] and [`HandleWrap`][] instances, cleanup of the associated libuv
698objects is performed automatically, i.e. handles are closed and requests
699are cancelled if possible.
700
701#### Closing libuv handles
702
703If a libuv handle is not managed through a [`HandleWrap`][] instance,
704it needs to be closed explicitly. Do not use `uv_close()` for that, but rather
705`env->CloseHandle()`, which works the same way but keeps track of the number
706of handles that are still closing.
707
708#### Closing libuv requests
709
710There is no way to abort libuv requests in general. If a libuv request is not
711managed through a [`ReqWrap`][] instance, the
712`env->IncreaseWaitingRequestCounter()` and
713`env->DecreaseWaitingRequestCounter()` functions need to be used to keep track
714of the number of active libuv requests.
715
716#### Calling into JavaScript
717
718Calling into JavaScript is not allowed during cleanup. Worker threads explicitly
719forbid this during their shutdown sequence, but the main thread does not for
720backwards compatibility reasons.
721
722When calling into JavaScript without using [`MakeCallback()`][], check the
723`env->can_call_into_js()` flag and do not proceed if it is set to `false`.
724
725## Classes associated with JavaScript objects
726
727### `MemoryRetainer`
728
729A large number of classes in the Node.js C++ codebase refer to other objects.
730The `MemoryRetainer` class is a helper for annotating C++ classes with
731information that can be used by the heap snapshot builder in V8, so that
732memory retained by C++ can be tracked in V8 heap snapshots captured in
733Node.js applications.
734
735Inheriting from the `MemoryRetainer` class enables objects (both from JavaScript
736and C++) to refer to instances of that class, and in turn enables that class
737to point to other objects as well, including native C++ types
738such as `std::string` and track their memory usage.
739
740This can be useful for debugging memory leaks.
741
742The [`memory_tracker.h`][] header file explains how to use this class.
743
744<a id="baseobject"></a>
745### `BaseObject`
746
747A frequently recurring situation is that a JavaScript object and a C++ object
748need to be tied together. `BaseObject` is the main abstraction for that in
749Node.js, and most classes that are associated with JavaScript objects are
750subclasses of it. It is defined in [`base_object.h`][].
751
752Every `BaseObject` is associated with one [`Environment`][] and one
753`v8::Object`. The `v8::Object` needs to have at least one [internal field][]
754that is used for storing the pointer to the C++ object. In order to ensure this,
755the V8 `SetInternalFieldCount()` function is usually used when setting up the
756class from C++.
757
758The JavaScript object can be accessed as a `v8::Local<v8::Object>` by using
759`self->object()`, given a `BaseObject` named `self`.
760
761Accessing a `BaseObject` from a `v8::Local<v8::Object>` (frequently that is
762`args.This()` or `args.Holder()` in a [binding function][]) can be done using
763the `Unwrap<T>(obj)` function, where `T` is a subclass of `BaseObject`.
764A helper for this is the `ASSIGN_OR_RETURN_UNWRAP` macro that returns from the
765current function if unwrapping fails (typically that means that the `BaseObject`
766has been deleted earlier).
767
768```cpp
769void Http2Session::Request(const FunctionCallbackInfo<Value>& args) {
770 Http2Session* session;
771 ASSIGN_OR_RETURN_UNWRAP(&session, args.Holder());
772 Environment* env = session->env();
773 Local<Context> context = env->context();
774 Isolate* isolate = env->isolate();
775
776 // ...
777 // The actual function body, which can now use the `session` object.
778 // ...
779}
780```
781
782#### Lifetime management
783
784The `BaseObject` class comes with a set of features that allow managing the
785lifetime of its instances, either associating it with the lifetime of the
786corresponding JavaScript object or untying the two.
787
788The `BaseObject::MakeWeak()` method turns the underlying [`Global`][] handle
789into a weak one, and makes it so that the `BaseObject::OnGCCollect()` virtual
790method is called when the JavaScript object is garbage collected. By default,
791that methods deletes the `BaseObject` instance.
792
793`BaseObject::ClearWeak()` undoes this effect.
794
795It generally makes sense to call `MakeWeak()` in the constructor of a
796`BaseObject` subclass, unless that subclass is referred to by e.g. the event
797loop, as is the case for the [`HandleWrap`][] and [`ReqWrap`][] classes.
798
799In addition, there are two kinds of smart pointers that can be used to refer
800to `BaseObject`s.
801
802`BaseObjectWeakPtr<T>` is similar to `std::weak_ptr<T>`, but holds on to
803an object of a `BaseObject` subclass `T` and integrates with the lifetime
804management of the former. When the `BaseObject` no longer exists, e.g. when
805it was garbage collected, accessing it through `weak_ptr.get()` will return
806`nullptr`.
807
808`BaseObjectPtr<T>` is similar to `std::shared_ptr<T>`, but also holds on to
809objects of a `BaseObject` subclass `T`. While there are `BaseObjectPtr`s
810pointing to a given object, the `BaseObject` will always maintain a strong
811reference to its associated JavaScript object. This can be useful when one
812`BaseObject` refers to another `BaseObject` and wants to make sure it stays
813alive during the lifetime of that reference.
814
815A `BaseObject` can be “detached” through the `BaseObject::Detach()` method.
816In this case, it will be deleted once the last `BaseObjectPtr` referring to
817it is destroyed. There must be at least one such pointer when `Detach()` is
818called. This can be useful when one `BaseObject` fully owns another
819`BaseObject`.
820
821<a id="asyncwrap"></a>
822### `AsyncWrap`
823
824`AsyncWrap` is a subclass of `BaseObject` that additionally provides tracking
825functions for asynchronous calls. It is commonly used for classes whose methods
826make calls into JavaScript without any JavaScript stack below, i.e. more or less
827directly from the event loop. It is defined in [`async_wrap.h`][].
828
829Every `AsyncWrap` subclass has a “provider type”. A list of provider types is
830maintained in `src/async_wrap.h`.
831
832Every `AsyncWrap` instance is associated with two numbers, the “async id”
833and the “async trigger id”. The “async id” is generally unique per `AsyncWrap`
834instance, and only changes when the object is re-used in some way.
835
836See the [`async_hooks` module][] documentation for more information about how
837this information is provided to async tracking tools.
838
839<a id="makecallback"></a>
840#### `MakeCallback`
841
842The `AsyncWrap` class has a set of methods called `MakeCallback()`, with the
843intention of the naming being that it is used to “make calls back into
844JavaScript” from the event loop, rather than making callbacks in some way.
845(As the naming has made its way into Node.js’s public API, it’s not worth
846the breakage of fixing it).
847
848`MakeCallback()` generally calls a method on the JavaScript object associated
849with the current `AsyncWrap`, and informs async tracking code about these calls
850as well as takes care of running the `process.nextTick()` and `Promise` task
851queues once it returns.
852
853Before calling `MakeCallback()`, it is typically necessary to enter both a
854`HandleScope` and a `Context::Scope`.
855
856```cpp
857void StatWatcher::Callback(uv_fs_poll_t* handle,
858 int status,
859 const uv_stat_t* prev,
860 const uv_stat_t* curr) {
861 // Get the StatWatcher instance associated with this call from libuv,
862 // StatWatcher is a subclass of AsyncWrap.
863 StatWatcher* wrap = ContainerOf(&StatWatcher::watcher_, handle);
864 Environment* env = wrap->env();
865 HandleScope handle_scope(env->isolate());
866 Context::Scope context_scope(env->context());
867
868 // Transform 'prev' and 'curr' into an array:
869 Local<Value> arr = ...;
870
871 Local<Value> argv[] = { Integer::New(env->isolate(), status), arr };
872 wrap->MakeCallback(env->onchange_string(), arraysize(argv), argv);
873}
874```
875
876See [Callback scopes][] for more information.
877
878<a id="handlewrap"></a>
879### `HandleWrap`
880
881`HandleWrap` is a subclass of `AsyncWrap` specifically designed to make working
882with [libuv handles][] easier. It provides the `.ref()`, `.unref()` and
883`.hasRef()` methods as well as `.close()` to enable easier lifetime management
884from JavaScript. It is defined in [`handle_wrap.h`][].
885
886`HandleWrap` instances are [cleaned up][cleanup hooks] automatically when the
887current Node.js [`Environment`][] is destroyed, e.g. when a Worker thread stops.
888
889`HandleWrap` also provides facilities for diagnostic tooling to get an
890overview over libuv handles managed by Node.js.
891
892<a id="reqwrap"></a>
893### `ReqWrap`
894
895`ReqWrap` is a subclass of `AsyncWrap` specifically designed to make working
896with [libuv requests][] easier. It is defined in [`req_wrap.h`][].
897
898In particular, its `Dispatch()` method is designed to avoid the need to keep
899track of the current count of active libuv requests.
900
901`ReqWrap` also provides facilities for diagnostic tooling to get an
902overview over libuv handles managed by Node.js.
903
904<a id="callback-scopes"></a>
905### Callback scopes
906
907The public `CallbackScope` and the internally used `InternalCallbackScope`
908classes provide the same facilities as [`MakeCallback()`][], namely:
909
910* Emitting the `'before'` event for async tracking when entering the scope
911* Setting the current async IDs to the ones passed to the constructor
912* Emitting the `'after'` event for async tracking when leaving the scope
913* Running the `process.nextTick()` queue
914* Running microtasks, in particular `Promise` callbacks and async/await
915 functions
916
917Usually, using `AsyncWrap::MakeCallback()` or using the constructor taking
918an `AsyncWrap*` argument (i.e. used as
919`InternalCallbackScope callback_scope(this);`) suffices inside of Node.js’s
920C++ codebase.
921
922## C++ utilities
923
924Node.js uses a few custom C++ utilities, mostly defined in [`util.h`][].
925
926### Memory allocation
927
928Node.js provides `Malloc()`, `Realloc()` and `Calloc()` functions that work
929like their C stdlib counterparts, but crash if memory cannot be allocated.
930(As V8 does not handle out-of-memory situations gracefully, it does not make
931sense for Node.js to attempt to do so in all cases.)
932
933The `UncheckedMalloc()`, `UncheckedRealloc()` and `UncheckedCalloc()` functions
934return `nullptr` in these cases (or when `size == 0`).
935
936#### Optional stack-based memory allocation
937
938The `MaybeStackBuffer` class provides a way to allocate memory on the stack
939if it is smaller than a given limit, and falls back to allocating it on the
940heap if it is larger. This can be useful for performantly allocating temporary
941data if it is typically expected to be small (e.g. file paths).
942
943The `Utf8Value`, `TwoByteValue` (i.e. UTF-16 value) and `BufferValue`
944(`Utf8Value` but copy data from a `Buffer` if one is passed) helpers
945inherit from this class and allow accessing the characters in a JavaScript
946string this way.
947
948```cpp
949static void Chdir(const FunctionCallbackInfo<Value>& args) {
950 Environment* env = Environment::GetCurrent(args);
951 // ...
952 CHECK(args[0]->IsString());
953 Utf8Value path(env->isolate(), args[0]);
954 int err = uv_chdir(*path);
955 if (err) {
956 // ... error handling ...
957 }
958}
959```
960
961### Assertions
962
963Node.js provides a few macros that behave similar to `assert()`:
964
965* `CHECK(expression)` aborts the process with a stack trace
966 if `expression` is false.
967* `CHECK_EQ(a, b)` checks for `a == b`
968* `CHECK_GE(a, b)` checks for `a >= b`
969* `CHECK_GT(a, b)` checks for `a > b`
970* `CHECK_LE(a, b)` checks for `a <= b`
971* `CHECK_LT(a, b)` checks for `a < b`
972* `CHECK_NE(a, b)` checks for `a != b`
973* `CHECK_NULL(val)` checks for `a == nullptr`
974* `CHECK_NOT_NULL(val)` checks for `a != nullptr`
975* `CHECK_IMPLIES(a, b)` checks that `b` is true if `a` is true.
976* `UNREACHABLE([message])` aborts the process if it is reached.
977
978`CHECK`s are always enabled. For checks that should only run in debug mode, use
979`DCHECK()`, `DCHECK_EQ()`, etc.
980
981### Scope-based cleanup
982
983The `OnScopeLeave()` function can be used to run a piece of code when leaving
984the current C++ scope.
985
986```cpp
987static void GetUserInfo(const FunctionCallbackInfo<Value>& args) {
988 Environment* env = Environment::GetCurrent(args);
989 uv_passwd_t pwd;
990 // ...
991
992 const int err = uv_os_get_passwd(&pwd);
993
994 if (err) {
995 // ... error handling, return early ...
996 }
997
998 auto free_passwd = OnScopeLeave([&]() { uv_os_free_passwd(&pwd); });
999
1000 // ...
1001 // Turn `pwd` into a JavaScript object now; whenever we return from this
1002 // function, `uv_os_free_passwd()` will be called.
1003 // ...
1004}
1005```
1006
1007[C++ coding style]: ../doc/guides/cpp-style-guide.md
1008[Callback scopes]: #callback-scopes
1009[JavaScript value handles]: #js-handles
1010[N-API]: https://nodejs.org/api/n-api.html
1011[`BaseObject`]: #baseobject
1012[`Context`]: #context
1013[`Environment`]: #environment
1014[`Global`]: #global-handles
1015[`HandleWrap`]: #handlewrap
1016[`IsolateData`]: #isolate-data
1017[`Isolate`]: #isolate
1018[`Local`]: #local-handles
1019[`MakeCallback()`]: #makecallback
1020[`MessagePort`]: https://nodejs.org/api/worker_threads.html#worker_threads_class_messageport
1021[`ReqWrap`]: #reqwrap
1022[`async_hooks` module]: https://nodejs.org/api/async_hooks.html
1023[`async_wrap.h`]: async_wrap.h
1024[`base_object.h`]: base_object.h
1025[`handle_wrap.h`]: handle_wrap.h
1026[`memory_tracker.h`]: memory_tracker.h
1027[`req_wrap.h`]: req_wrap.h
1028[`util.h`]: util.h
1029[`v8.h` in Code Search]: https://cs.chromium.org/chromium/src/v8/include/v8.h
1030[`v8.h` in Node.js master]: https://github.com/nodejs/node/blob/master/deps/v8/include/v8.h
1031[`v8.h` in V8 master]: https://github.com/v8/v8/blob/master/include/v8.h
1032[`vm` module]: https://nodejs.org/api/vm.html
1033[binding function]: #binding-functions
1034[cleanup hooks]: #cleanup-hooks
1035[event loop]: #event-loop
1036[exception handling]: #exception-handling
1037[internal field]: #internal-fields
1038[introduction for V8 embedders]: https://v8.dev/docs/embed
1039[libuv]: https://libuv.org/
1040[libuv handles]: #libuv-handles-and-requests
1041[libuv requests]: #libuv-handles-and-requests
1042[reference documentation for the libuv API]: http://docs.libuv.org/en/v1.x/
1043