Skip to content

Commit c1f9e4c

Browse files
committed
src: add initial shadow realm support
Add initial shadow realm support behind an off-by-default flag `--experimental-shadow-realm`.
1 parent 2691222 commit c1f9e4c

File tree

10 files changed

+82
-1
lines changed

10 files changed

+82
-1
lines changed

.eslintrc.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,7 @@ module.exports = {
337337
TextEncoderStream: 'readable',
338338
TransformStream: 'readable',
339339
TransformStreamDefaultController: 'readable',
340+
ShadowRealm: 'readable',
340341
SubtleCrypto: 'readable',
341342
WritableStream: 'readable',
342343
WritableStreamDefaultWriter: 'readable',

doc/api/cli.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,10 +342,18 @@ Disable experimental support for the [Fetch API][].
342342

343343
<!-- YAML
344344
added: v16.6.0
345-
-->
345+
-->
346346

347347
Use this flag to disable top-level await in REPL.
348348

349+
### `--experimental-shadow-realm`
350+
351+
<!-- YAML
352+
added: REPLACEME
353+
-->
354+
355+
Use this flag to enable [ShadowRealm][] support.
356+
349357
### `--experimental-specifier-resolution=mode`
350358

351359
<!-- YAML
@@ -1618,6 +1626,7 @@ Node.js options that are allowed are:
16181626
* `--experimental-modules`
16191627
* `--experimental-network-imports`
16201628
* `--experimental-policy`
1629+
* `--experimental-shadow-realm`
16211630
* `--experimental-specifier-resolution`
16221631
* `--experimental-top-level-await`
16231632
* `--experimental-vm-modules`
@@ -2013,6 +2022,7 @@ $ node --max-old-space-size=1536 index.js
20132022
[OSSL_PROVIDER-legacy]: https://www.openssl.org/docs/man3.0/man7/OSSL_PROVIDER-legacy.html
20142023
[REPL]: repl.md
20152024
[ScriptCoverage]: https://chromedevtools.github.io/devtools-protocol/tot/Profiler#type-ScriptCoverage
2025+
[ShadowRealm]: https://github.com/tc39/proposal-shadowrealm
20162026
[Source Map]: https://sourcemaps.info/spec.html
20172027
[Subresource Integrity]: https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity
20182028
[V8 JavaScript code coverage]: https://v8project.blogspot.com/2017/12/javascript-code-coverage.html

lib/.eslintrc.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@ rules:
8787
message: Use `const { Request } = require('internal/deps/undici/undici');` instead of the global.
8888
- name: Response
8989
message: Use `const { Response } = require('internal/deps/undici/undici');` instead of the global.
90+
# ShadowRealm is not available in primordials because it can be
91+
# disabled with --no-harmony-shadow-realm CLI flag.
92+
- name: ShadowRealm
93+
message: Use `const { ShadowRealm } = globalThis;` instead of the global.
9094
# SharedArrayBuffer is not available in primordials because it can be
9195
# disabled with --no-harmony-sharedarraybuffer CLI flag.
9296
- name: SharedArrayBuffer

node.gyp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,7 @@
531531
'src/node_report_module.cc',
532532
'src/node_report_utils.cc',
533533
'src/node_serdes.cc',
534+
'src/node_shadow_realm.cc',
534535
'src/node_snapshotable.cc',
535536
'src/node_sockaddr.cc',
536537
'src/node_stat_watcher.cc',
@@ -637,6 +638,7 @@
637638
'src/node_report.h',
638639
'src/node_revert.h',
639640
'src/node_root_certs.h',
641+
'src/node_shadow_realm.h',
640642
'src/node_snapshotable.h',
641643
'src/node_snapshot_builder.h',
642644
'src/node_sockaddr.h',

src/api/environment.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "node_native_module_env.h"
66
#include "node_options-inl.h"
77
#include "node_platform.h"
8+
#include "node_shadow_realm.h"
89
#include "node_v8_platform-inl.h"
910
#include "node_wasm_web_api.h"
1011
#include "uv.h"
@@ -261,6 +262,12 @@ void SetIsolateMiscHandlers(v8::Isolate* isolate, const IsolateSettings& s) {
261262
isolate->SetWasmStreamingCallback(wasm_web_api::StartStreamingCompilation);
262263
}
263264

265+
if (per_process::cli_options->get_per_isolate_options()
266+
->experimental_shadow_realm) {
267+
isolate->SetHostCreateShadowRealmContextCallback(
268+
shadow_realm::HostCreateShadowRealmContextCallback);
269+
}
270+
264271
if ((s.flags & SHOULD_NOT_SET_PROMISE_REJECTION_CALLBACK) == 0) {
265272
auto* promise_reject_cb = s.promise_reject_callback ?
266273
s.promise_reject_callback : PromiseRejectCallback;

src/node_options.cc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -713,6 +713,15 @@ PerIsolateOptionsParser::PerIsolateOptionsParser(
713713
Implies("--harmony-top-level-await", "--experimental-top-level-await");
714714
ImpliesNot("--no-harmony-top-level-await", "--experimental-top-level-await");
715715

716+
AddOption("--experimental-shadow-realm",
717+
"",
718+
&PerIsolateOptions::experimental_shadow_realm,
719+
kAllowedInEnvironment);
720+
AddOption("--harmony-shadow-realm", "", V8Option{});
721+
Implies("--experimental-shadow-realm", "--harmony-shadow-realm");
722+
Implies("--harmony-shadow-realm", "--experimental-shadow-realm");
723+
ImpliesNot("--no-harmony-shadow-realm", "--experimental-shadow-realm");
724+
716725
Insert(eop, &PerIsolateOptions::get_per_env_options);
717726
}
718727

src/node_options.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ class PerIsolateOptions : public Options {
207207
bool report_uncaught_exception = false;
208208
bool report_on_signal = false;
209209
bool experimental_top_level_await = true;
210+
bool experimental_shadow_realm = false;
210211
std::string report_signal = "SIGUSR2";
211212
inline EnvironmentOptions* get_per_env_options();
212213
void CheckOptions(std::vector<std::string>* errors) override;

src/node_shadow_realm.cc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#include "node_shadow_realm.h"
2+
3+
namespace node {
4+
namespace shadow_realm {
5+
using v8::Context;
6+
using v8::Local;
7+
using v8::MaybeLocal;
8+
9+
// static
10+
MaybeLocal<Context> HostCreateShadowRealmContextCallback(
11+
Local<Context> initiator_context) {
12+
return Context::New(initiator_context->GetIsolate());
13+
}
14+
15+
} // namespace shadow_realm
16+
} // namespace node

src/node_shadow_realm.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#ifndef SRC_NODE_SHADOW_REALM_H_
2+
#define SRC_NODE_SHADOW_REALM_H_
3+
4+
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
5+
6+
#include "v8.h"
7+
8+
namespace node {
9+
namespace shadow_realm {
10+
11+
v8::MaybeLocal<v8::Context> HostCreateShadowRealmContextCallback(
12+
v8::Local<v8::Context> initiator_context);
13+
14+
} // namespace shadow_realm
15+
} // namespace node
16+
17+
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
18+
19+
#endif // SRC_NODE_SHADOW_REALM_H_

test/parallel/test-shadow-realm.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Flags: --experimental-shadow-realm
2+
'use strict';
3+
4+
require('../common');
5+
const assert = require('assert');
6+
7+
// Validates we can construct ShadowRealm successfully.
8+
const shadowRealm = new ShadowRealm();
9+
10+
const getter = shadowRealm.evaluate('globalThis.realmValue = "inner"; () => globalThis.realmValue;');
11+
assert.strictEqual(getter(), 'inner');
12+
assert.strictEqual('realmValue' in globalThis, false);

0 commit comments

Comments
 (0)