Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

src: add Realm document in the src README.md #47932

Merged
merged 3 commits into from
Jun 1, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 68 additions & 21 deletions src/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ Typical ways of accessing the current `Isolate` in the Node.js code are:
using `args.GetIsolate()`.
* Given a [`Context`][], using `context->GetIsolate()`.
* Given a [`Environment`][], using `env->isolate()`.
* Given a [`Realm`][], using `realm->isolate()`.

### V8 JavaScript values

Expand Down Expand Up @@ -264,19 +265,25 @@ heap. Node.js exposes this ability through the [`vm` module][].
V8 refers to each of these global objects and their associated builtins as a
`Context`.

Currently, in Node.js there is one main `Context` associated with an
[`Environment`][] instance, and most Node.js features will only work inside
that context. (The only exception at the time of writing are
[`MessagePort`][] objects.) This restriction is not inherent to the design of
Node.js, and a sufficiently committed person could restructure Node.js to
provide built-in modules inside of `vm.Context`s.
Currently, in Node.js there is one main `Context` associated with the
principal [`Realm`][] of an [`Environment`][] instance, and a number of
subsidiary `Context`s that are created with `vm.Context` or associated with
[`ShadowRealm`][].

Most Node.js features will only work inside a context associated with a
`Realm`. The only exception at the time of writing are [`MessagePort`][]
objects. This restriction is not inherent to the design of Node.js, and a
sufficiently committed person could restructure Node.js to provide built-in
modules inside of `vm.Context`s.

Often, the `Context` is passed around for [exception handling][].
Typical ways of accessing the current `Context` in the Node.js code are:

* Given an [`Isolate`][], using `isolate->GetCurrentContext()`.
* Given an [`Environment`][], using `env->context()` to get the `Environment`'s
main context.
principal [`Realm`][]'s context.
* Given a [`Realm`][], using `realm->context()` to get the `Realm`'s
context.

<a id="event-loop"></a>

Expand All @@ -303,15 +310,11 @@ Currently, every `Environment` class is associated with:

* One [event loop][]
* One [`Isolate`][]
* One main [`Context`][]
* One principal [`Realm`][]

The `Environment` class contains a large number of different fields for
different Node.js modules, for example a libuv timer for `setTimeout()` or
the memory for a `Float64Array` that the `fs` module uses for storing data
returned from a `fs.stat()` call.

It also provides [cleanup hooks][] and maintains a list of [`BaseObject`][]
instances.
different built-in modules that can be shared across different `Realm`
instances, for example, the inspector agent, async hooks info.

Typical ways of accessing the current `Environment` in the Node.js code are:

Expand All @@ -325,6 +328,45 @@ Typical ways of accessing the current `Environment` in the Node.js code are:
* Given an [`Isolate`][], using `Environment::GetCurrent(isolate)`. This looks
up the current [`Context`][] and then uses that.

<a id="realm"></a>

### `Realm`

The `Realm` class is a container for a set of JavaScript objects and functions
that are associated with a particular [ECMAScript realm][].

Each ECMAScript realm comes with a global object and a set of intrinsic
objects. An ECMAScript realm has a `[[HostDefined]]` field, which represents
the Node.js [`Realm`][] object.

Every `Realm` instance is created for a particular [`Context`][]. A `Realm`
can be a principal realm or a synthetic realm. A principal realm is created
for each `Environment`'s main [`Context`][]. A synthetic realm is created
for the [`Context`][] of each [`ShadowRealm`][] constructed from the JS API. No
`Realm` is created for the [`Context`][] of a `vm.Context`.

Native bindings and built-in modules can be evaluated in either a principal
realm or a synthetic realm.

The `Realm` class contains a large number of different fields for
different built-in modules, for example the memory for a `Uint32Array` that
the `url` module uses for storing data returned from a
`urlBinding.update()` call.

It also provides [cleanup hooks][] and maintains a list of [`BaseObject`][]
instances.

Typical ways of accessing the current `Realm` in the Node.js code are:

* Given a `FunctionCallbackInfo` for a [binding function][],
using `Realm::GetCurrent(args)`.
* Given a [`BaseObject`][], using `realm()` or `self->realm()`.
* Given a [`Context`][], using `Realm::GetCurrent(context)`.
This requires that `context` has been associated with the `Realm`
instance, e.g. is the principal `Realm` for the `Environment`.
* Given an [`Isolate`][], using `Realm::GetCurrent(isolate)`. This looks
up the current [`Context`][] and then uses its `Realm`.

<a id="isolate-data"></a>

### `IsolateData`
Expand Down Expand Up @@ -509,7 +551,7 @@ implement them. Otherwise, add the id and the class name to the
// In the HTTP parser source code file:
class BindingData : public BaseObject {
public:
BindingData(Environment* env, Local<Object> obj) : BaseObject(env, obj) {}
BindingData(Realm* realm, Local<Object> obj) : BaseObject(realm, obj) {}

SET_BINDING_ID(http_parser_binding_data)

Expand All @@ -525,7 +567,7 @@ static void New(const FunctionCallbackInfo<Value>& args) {
new Parser(binding_data, args.This());
}

// ... because the initialization function told the Environment to store the
// ... because the initialization function told the Realm to store the
// BindingData object:
void InitializeHttpParser(Local<Object> target,
Local<Value> unused,
Expand Down Expand Up @@ -710,11 +752,13 @@ any resources owned by it, e.g. memory or libuv requests/handles.

#### Cleanup hooks

Cleanup hooks are provided that run before the [`Environment`][]
is destroyed. They can be added and removed through by using
Cleanup hooks are provided that run before the [`Environment`][] or the
[`Realm`][] is destroyed. They can be added and removed by using
`env->AddCleanupHook(callback, hint);` and
`env->RemoveCleanupHook(callback, hint);`, where callback takes a `void* hint`
argument.
`env->RemoveCleanupHook(callback, hint);`, or
`realm->AddCleanupHook(callback, hint);` and
`realm->RemoveCleanupHook(callback, hint);` respectively, where callback takes
a `void* hint` argument.

Inside these cleanup hooks, new asynchronous operations _may_ be started on the
event loop, although ideally that is avoided as much as possible.
Expand Down Expand Up @@ -776,7 +820,7 @@ need to be tied together. `BaseObject` is the main abstraction for that in
Node.js, and most classes that are associated with JavaScript objects are
subclasses of it. It is defined in [`base_object.h`][].

Every `BaseObject` is associated with one [`Environment`][] and one
Every `BaseObject` is associated with one [`Realm`][] and one
`v8::Object`. The `v8::Object` needs to have at least one [internal field][]
that is used for storing the pointer to the C++ object. In order to ensure this,
the V8 `SetInternalFieldCount()` function is usually used when setting up the
Expand Down Expand Up @@ -1038,6 +1082,7 @@ static void GetUserInfo(const FunctionCallbackInfo<Value>& args) {

[C++ coding style]: ../doc/contributing/cpp-style-guide.md
[Callback scopes]: #callback-scopes
[ECMAScript realm]: https://tc39.es/ecma262/#sec-code-realms
[JavaScript value handles]: #js-handles
[N-API]: https://nodejs.org/api/n-api.html
[`BaseObject`]: #baseobject
Expand All @@ -1050,7 +1095,9 @@ static void GetUserInfo(const FunctionCallbackInfo<Value>& args) {
[`Local`]: #local-handles
[`MakeCallback()`]: #makecallback
[`MessagePort`]: https://nodejs.org/api/worker_threads.html#worker_threads_class_messageport
[`Realm`]: #realm
[`ReqWrap`]: #reqwrap
[`ShadowRealm`]: https://github.com/tc39/proposal-shadowrealm
[`async_hooks` module]: https://nodejs.org/api/async_hooks.html
[`async_wrap.h`]: async_wrap.h
[`base_object.h`]: base_object.h
Expand Down