From f0da57c8a8cd37804ca35a78cf9c6ba505fdb402 Mon Sep 17 00:00:00 2001 From: Chengzhong Wu Date: Tue, 9 May 2023 17:37:49 +0800 Subject: [PATCH 1/3] src: add Realm document in the src README.md --- src/README.md | 68 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 52 insertions(+), 16 deletions(-) diff --git a/src/README.md b/src/README.md index bcd6b6e8ccc4d9..d7535ac220ec5c 100644 --- a/src/README.md +++ b/src/README.md @@ -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 @@ -265,7 +266,7 @@ 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 +[`Realm`][] 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 @@ -276,7 +277,9 @@ 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 an [`Realm`][], using `realm->context()` to get the `Realm`'s + context. @@ -303,15 +306,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 a libuv timer for `setTimeout()`. Typical ways of accessing the current `Environment` in the Node.js code are: @@ -325,6 +324,40 @@ 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. + + +### `Realm` + +The `Realm` class is a container for a set of JavaScript objects and functions +that associated with a particular ECMAScript global environment. + +Every `Realm` instance is associated with a [`Context`][]. + +A `Realm` can be a principal realm or a synthetic realm. A principal realm is +created with an `Environment` as its principal global environment to evaluate +scripts. A synthetic realm is created with JS APIs like `ShadowRealm`. + +Native bindings and builtin 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 `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. + +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 that. + ### `IsolateData` @@ -509,7 +542,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 obj) : BaseObject(env, obj) {} + BindingData(Realm* realm, Local obj) : BaseObject(realm, obj) {} SET_BINDING_ID(http_parser_binding_data) @@ -525,7 +558,7 @@ static void New(const FunctionCallbackInfo& 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 target, Local unused, @@ -710,11 +743,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 through 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. @@ -776,7 +811,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 @@ -1050,6 +1085,7 @@ static void GetUserInfo(const FunctionCallbackInfo& args) { [`Local`]: #local-handles [`MakeCallback()`]: #makecallback [`MessagePort`]: https://nodejs.org/api/worker_threads.html#worker_threads_class_messageport +[`Realm`]: #realm [`ReqWrap`]: #reqwrap [`async_hooks` module]: https://nodejs.org/api/async_hooks.html [`async_wrap.h`]: async_wrap.h From 136cf142461541128df2c624f7a665427a04c2b5 Mon Sep 17 00:00:00 2001 From: Chengzhong Wu Date: Wed, 10 May 2023 14:56:29 +0800 Subject: [PATCH 2/3] fixup! src: add Realm document in the src README.md --- src/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/README.md b/src/README.md index d7535ac220ec5c..e4f3e108e78fce 100644 --- a/src/README.md +++ b/src/README.md @@ -265,7 +265,7 @@ 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 +Currently, in Node.js there is one main `Context` associated with a [`Realm`][] 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 @@ -278,7 +278,7 @@ 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 principal [`Realm`][]'s context. -* Given an [`Realm`][], using `realm->context()` to get the `Realm`'s +* Given a [`Realm`][], using `realm->context()` to get the `Realm`'s context. @@ -329,7 +329,7 @@ Typical ways of accessing the current `Environment` in the Node.js code are: ### `Realm` The `Realm` class is a container for a set of JavaScript objects and functions -that associated with a particular ECMAScript global environment. +that are associated with a particular ECMAScript global environment. Every `Realm` instance is associated with a [`Context`][]. @@ -337,7 +337,7 @@ A `Realm` can be a principal realm or a synthetic realm. A principal realm is created with an `Environment` as its principal global environment to evaluate scripts. A synthetic realm is created with JS APIs like `ShadowRealm`. -Native bindings and builtin modules can be evaluated in either a principal +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 @@ -744,7 +744,7 @@ any resources owned by it, e.g. memory or libuv requests/handles. #### Cleanup hooks Cleanup hooks are provided that run before the [`Environment`][] or the -[`Realm`][] is destroyed. They can be added and removed through by using +[`Realm`][] is destroyed. They can be added and removed by using `env->AddCleanupHook(callback, hint);` and `env->RemoveCleanupHook(callback, hint);`, or `realm->AddCleanupHook(callback, hint);` and From a907870aafe8273da3a70e281bc540b6d5ff0085 Mon Sep 17 00:00:00 2001 From: Chengzhong Wu Date: Tue, 16 May 2023 19:58:41 +0800 Subject: [PATCH 3/3] fixup! src: add Realm document in the src README.md --- src/README.md | 41 ++++++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/src/README.md b/src/README.md index e4f3e108e78fce..b87132c014cb99 100644 --- a/src/README.md +++ b/src/README.md @@ -265,12 +265,16 @@ 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 a -[`Realm`][] 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: @@ -310,7 +314,7 @@ Currently, every `Environment` class is associated with: The `Environment` class contains a large number of different fields for different built-in modules that can be shared across different `Realm` -instances, for example a libuv timer for `setTimeout()`. +instances, for example, the inspector agent, async hooks info. Typical ways of accessing the current `Environment` in the Node.js code are: @@ -329,20 +333,25 @@ Typical ways of accessing the current `Environment` in the Node.js code are: ### `Realm` The `Realm` class is a container for a set of JavaScript objects and functions -that are associated with a particular ECMAScript global environment. +that are associated with a particular [ECMAScript realm][]. -Every `Realm` instance is associated with a [`Context`][]. +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. -A `Realm` can be a principal realm or a synthetic realm. A principal realm is -created with an `Environment` as its principal global environment to evaluate -scripts. A synthetic realm is created with JS APIs like `ShadowRealm`. +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 `Float64Array` that -the `fs` module uses for storing data returned from a `fs.stat()` call. +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. @@ -356,7 +365,7 @@ Typical ways of accessing the current `Realm` in the Node.js code are: 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 that. + up the current [`Context`][] and then uses its `Realm`. @@ -1073,6 +1082,7 @@ static void GetUserInfo(const FunctionCallbackInfo& 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 @@ -1087,6 +1097,7 @@ static void GetUserInfo(const FunctionCallbackInfo& args) { [`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