nodejs/node
BaseObject and BindingData
BaseObject is the C++ side of every JS-visible Node native object. BindingData is per-Realm storage for a binding. Both are designed to interact correctly with V8 GC and with snapshots (which copy a V8 heap to/from disk and have to know which native objects need to be re-attached on the way back).
BaseObject
Defined in src/base_object.h / src/base_object.cc / src/base_object-inl.h.
Every *Wrap C++ class in Node descends from BaseObject:
BaseObject
├── AsyncWrap (src/async_wrap.h)
│ ├── HandleWrap (src/handle_wrap.h)
│ │ ├── LibuvStreamWrap (src/stream_wrap.h)
│ │ │ ├── ConnectionWrap<TCPWrap, uv_tcp_t> (src/connection_wrap.h)
│ │ │ │ └── TCPWrap (src/tcp_wrap.h)
│ │ │ └── PipeWrap (src/pipe_wrap.h)
│ │ ├── UDPWrap (src/udp_wrap.h)
│ │ ├── TimerWrap (src/timer_wrap.h)
│ │ └── FSEventWrap, ProcessWrap, TTYWrap, ...
│ └── ReqWrap<T> (src/req_wrap.h)
│ ├── WriteWrap, ShutdownWrap, ConnectWrap, GetAddrInfoReqWrap, ...
│ └── FSReqCallback, FSReqPromise, ...
├── TLSWrap (src/crypto/crypto_tls.h)
├── ContextifyContext (src/node_contextify.h)
├── BlobBindingData (src/node_blob.h)
├── ...A BaseObject instance:
- Holds a
v8::Local/v8::Globalto a JS object. - Knows the
Realm*it belongs to. - Implements
MemoryInfofor heap snapshotting (so the V8 heap snapshotter can attribute native memory to the right JS object). - Has a
OnGCCollecthook that runs when the JS object is collected.
BaseObjectPtr<T> and BaseObjectWeakPtr<T>
Plain raw pointers across async boundaries are dangerous because V8 can collect the JS object at any time. BaseObjectPtr<T> keeps the JS object alive (strong reference); BaseObjectWeakPtr<T> does not but knows when the underlying object goes away.
Use these in any structure that outlives the call stack — async work jobs, scheduled callbacks, request structs.
Snapshot integration
When node_mksnapshot builds the startup snapshot, every reachable BaseObject has to declare how it wants to be serialized. The pattern (src/base_object_types.h):
- The class registers a
kInternalFieldTypeenum value. - It implements
Serialize/Deserializecallbacks that round-trip the C++ state. - The V8 inspector's
EmbedderGraphis told about the C++ side so heap snapshots show the right edges.
This is why most binding Initialize functions register an EmbedderGraph callback and a SerializeBindingData callback.
BindingData
BindingData (src/node_realm.h, src/node_realm-inl.h) is per-Realm storage for a binding's pre-computed state. Bindings call Realm::AddBindingData<MyBindingData>() in their Initialize to register a struct that:
- Holds
PersistentJS values used by the binding (constructor functions, error templates). - Is preserved across snapshots through
BindingData::Serialize/Deserialize. - Is cheap to access via
BindingData::FromV8Value(the binding's first-arg dispatch path).
Examples:
node::fs::BindingData— caches the JS strings for stat fields.node::http2::Http2State—nghttp2callback table.node::quic::BindingData— QUIC binding constants.node::contextify::ContextifyContext::BindingData— vm-related caches.
Lifecycle
sequenceDiagram
participant Realm
participant Init as binding Initialize fn
participant BD as BindingData
Realm->>Init: load this binding for the current Realm
Init->>BD: Realm::AddBindingData<MyBindingData>()
BD-->>Init: register V8 functions, store in BindingData
Realm-->>Realm: snapshot? -> serialize BindingData
Realm-->>Realm: deserialize -> rehydrate BindingData
Realm->>BD: cleanup at Realm disposeWhere to put state
- If state is global to the binding (e.g. registered constants), put it on
BindingData. - If state is per-instance (e.g. one per
fs.readcall), put it on the per-call*WrapBaseObject.
Entry points for modification
- New native binding? Use
NODE_BINDING_CONTEXT_AWARE_INTERNAL(name, Initialize)(src/node_binding.h) and add aBindingDataif you need persistent state. - New
*Wrapclass? Inherit from the right level in the hierarchy:AsyncWrapfor async-resource semantics,HandleWrapfor libuv handles,ReqWrap<T>for one-shot requests, plainBaseObjectif neither applies. - Snapshot bug?
BaseObject::IsSnapshotableand the per-classSerialize/Deserializeare the place to look.
For deeper coverage of how snapshots and the bootstrap interact see Builtins and primordials and systems › bootstrap-and-startup.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.