src: add initial shadow realm support

Add initial shadow realm support behind an off-by-default flag
`--experimental-shadow-realm`.

PR-URL: https://github.com/nodejs/node/pull/42869
Refs: https://github.com/nodejs/node/issues/42528
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Darshan Sen <raisinten@gmail.com>
This commit is contained in:
legendecas 2022-05-03 00:46:31 +08:00 committed by GitHub
parent 3bd87e1782
commit e86a638305
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 85 additions and 1 deletions

View File

@ -337,6 +337,7 @@ module.exports = {
TextEncoderStream: 'readable',
TransformStream: 'readable',
TransformStreamDefaultController: 'readable',
ShadowRealm: 'readable',
SubtleCrypto: 'readable',
WritableStream: 'readable',
WritableStreamDefaultWriter: 'readable',

View File

@ -346,10 +346,18 @@ Disable experimental support for the [Fetch API][].
<!-- YAML
added: v16.6.0
-->
-->
Use this flag to disable top-level await in REPL.
### `--experimental-shadow-realm`
<!-- YAML
added: REPLACEME
-->
Use this flag to enable [ShadowRealm][] support.
### `--experimental-specifier-resolution=mode`
<!-- YAML
@ -1622,6 +1630,7 @@ Node.js options that are allowed are:
* `--experimental-modules`
* `--experimental-network-imports`
* `--experimental-policy`
* `--experimental-shadow-realm`
* `--experimental-specifier-resolution`
* `--experimental-top-level-await`
* `--experimental-vm-modules`
@ -2017,6 +2026,7 @@ $ node --max-old-space-size=1536 index.js
[OSSL_PROVIDER-legacy]: https://www.openssl.org/docs/man3.0/man7/OSSL_PROVIDER-legacy.html
[REPL]: repl.md
[ScriptCoverage]: https://chromedevtools.github.io/devtools-protocol/tot/Profiler#type-ScriptCoverage
[ShadowRealm]: https://github.com/tc39/proposal-shadowrealm
[Source Map]: https://sourcemaps.info/spec.html
[Subresource Integrity]: https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity
[V8 JavaScript code coverage]: https://v8project.blogspot.com/2017/12/javascript-code-coverage.html

View File

@ -156,6 +156,9 @@ Enable experimental support for loading modules using `import` over `https:`.
.It Fl -experimental-policy
Use the specified file as a security policy.
.
.It Fl -experimental-shadow-realm
Use this flag to enable ShadowRealm support.
.
.It Fl -no-experimental-fetch
Disable experimental support for the Fetch API.
.

View File

@ -87,6 +87,10 @@ rules:
message: Use `const { Request } = require('internal/deps/undici/undici');` instead of the global.
- name: Response
message: Use `const { Response } = require('internal/deps/undici/undici');` instead of the global.
# ShadowRealm is not available in primordials because it can be
# disabled with --no-harmony-shadow-realm CLI flag.
- name: ShadowRealm
message: Use `const { ShadowRealm } = globalThis;` instead of the global.
# SharedArrayBuffer is not available in primordials because it can be
# disabled with --no-harmony-sharedarraybuffer CLI flag.
- name: SharedArrayBuffer

View File

@ -531,6 +531,7 @@
'src/node_report_module.cc',
'src/node_report_utils.cc',
'src/node_serdes.cc',
'src/node_shadow_realm.cc',
'src/node_snapshotable.cc',
'src/node_sockaddr.cc',
'src/node_stat_watcher.cc',
@ -637,6 +638,7 @@
'src/node_report.h',
'src/node_revert.h',
'src/node_root_certs.h',
'src/node_shadow_realm.h',
'src/node_snapshotable.h',
'src/node_snapshot_builder.h',
'src/node_sockaddr.h',

View File

@ -5,6 +5,7 @@
#include "node_native_module_env.h"
#include "node_options-inl.h"
#include "node_platform.h"
#include "node_shadow_realm.h"
#include "node_v8_platform-inl.h"
#include "node_wasm_web_api.h"
#include "uv.h"
@ -261,6 +262,12 @@ void SetIsolateMiscHandlers(v8::Isolate* isolate, const IsolateSettings& s) {
isolate->SetWasmStreamingCallback(wasm_web_api::StartStreamingCompilation);
}
if (per_process::cli_options->get_per_isolate_options()
->experimental_shadow_realm) {
isolate->SetHostCreateShadowRealmContextCallback(
shadow_realm::HostCreateShadowRealmContextCallback);
}
if ((s.flags & SHOULD_NOT_SET_PROMISE_REJECTION_CALLBACK) == 0) {
auto* promise_reject_cb = s.promise_reject_callback ?
s.promise_reject_callback : PromiseRejectCallback;

View File

@ -703,6 +703,15 @@ PerIsolateOptionsParser::PerIsolateOptionsParser(
AddOption(
"--experimental-top-level-await", "", NoOp{}, kAllowedInEnvironment);
AddOption("--experimental-shadow-realm",
"",
&PerIsolateOptions::experimental_shadow_realm,
kAllowedInEnvironment);
AddOption("--harmony-shadow-realm", "", V8Option{});
Implies("--experimental-shadow-realm", "--harmony-shadow-realm");
Implies("--harmony-shadow-realm", "--experimental-shadow-realm");
ImpliesNot("--no-harmony-shadow-realm", "--experimental-shadow-realm");
Insert(eop, &PerIsolateOptions::get_per_env_options);
}

View File

@ -205,6 +205,7 @@ class PerIsolateOptions : public Options {
bool track_heap_objects = false;
bool report_uncaught_exception = false;
bool report_on_signal = false;
bool experimental_shadow_realm = false;
std::string report_signal = "SIGUSR2";
inline EnvironmentOptions* get_per_env_options();
void CheckOptions(std::vector<std::string>* errors) override;

16
src/node_shadow_realm.cc Normal file
View File

@ -0,0 +1,16 @@
#include "node_shadow_realm.h"
namespace node {
namespace shadow_realm {
using v8::Context;
using v8::Local;
using v8::MaybeLocal;
// static
MaybeLocal<Context> HostCreateShadowRealmContextCallback(
Local<Context> initiator_context) {
return Context::New(initiator_context->GetIsolate());
}
} // namespace shadow_realm
} // namespace node

19
src/node_shadow_realm.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef SRC_NODE_SHADOW_REALM_H_
#define SRC_NODE_SHADOW_REALM_H_
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
#include "v8.h"
namespace node {
namespace shadow_realm {
v8::MaybeLocal<v8::Context> HostCreateShadowRealmContextCallback(
v8::Local<v8::Context> initiator_context);
} // namespace shadow_realm
} // namespace node
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
#endif // SRC_NODE_SHADOW_REALM_H_

View File

@ -0,0 +1,12 @@
// Flags: --experimental-shadow-realm
'use strict';
require('../common');
const assert = require('assert');
// Validates we can construct ShadowRealm successfully.
const shadowRealm = new ShadowRealm();
const getter = shadowRealm.evaluate('globalThis.realmValue = "inner"; () => globalThis.realmValue;');
assert.strictEqual(getter(), 'inner');
assert.strictEqual('realmValue' in globalThis, false);