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