Skip to content

Commit

Permalink
src: add initial shadow realm support
Browse files Browse the repository at this point in the history
Add initial shadow realm support behind an off-by-default flag
`--experimental-shadow-realm`.

PR-URL: nodejs#42869
Refs: nodejs#42528
Reviewed-By: Antoine du Hamel <[email protected]>
Reviewed-By: Darshan Sen <[email protected]>
  • Loading branch information
legendecas authored and joyeecheung committed Oct 14, 2022
1 parent 3f20e5b commit c13a4bc
Show file tree
Hide file tree
Showing 11 changed files with 85 additions and 1 deletion.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,7 @@ module.exports = {
TextEncoderStream: 'readable',
TransformStream: 'readable',
TransformStreamDefaultController: 'readable',
ShadowRealm: 'readable',
SubtleCrypto: 'readable',
WritableStream: 'readable',
WritableStreamDefaultWriter: 'readable',
Expand Down
12 changes: 11 additions & 1 deletion doc/api/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -411,10 +411,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
Expand Down Expand Up @@ -1807,6 +1815,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`
Expand Down Expand Up @@ -2236,6 +2245,7 @@ done
[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
Expand Down
3 changes: 3 additions & 0 deletions doc/node.1
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,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.
.
Expand Down
4 changes: 4 additions & 0 deletions lib/.eslintrc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,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
Expand Down
2 changes: 2 additions & 0 deletions node.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,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',
Expand Down Expand Up @@ -634,6 +635,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',
Expand Down
7 changes: 7 additions & 0 deletions src/api/environment.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "node_internals.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"
Expand Down Expand Up @@ -264,6 +265,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;
Expand Down
9 changes: 9 additions & 0 deletions src/node_options.cc
Original file line number Diff line number Diff line change
Expand Up @@ -753,6 +753,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);
}

Expand Down
1 change: 1 addition & 0 deletions src/node_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,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;
Expand Down
16 changes: 16 additions & 0 deletions src/node_shadow_realm.cc
Original file line number Diff line number Diff line change
@@ -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 changes: 19 additions & 0 deletions src/node_shadow_realm.h
Original file line number Diff line number Diff line change
@@ -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_
12 changes: 12 additions & 0 deletions test/parallel/test-shadow-realm.js
Original file line number Diff line number Diff line change
@@ -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);

0 comments on commit c13a4bc

Please sign in to comment.