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