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