Stage 3 Draft / May 2, 2022

ShadowRealm API

1 Well-known intrinsic objects

Table 1: Well-known Intrinsic Objects
Intrinsic Name Global Name ECMAScript Language Association
%ShadowRealm% ShadowRealm The ShadowRealm constructor (3.2)

2 Wrapped Function Exotic Objects

A wrapped function exotic object is an exotic object that wraps a callable object. A wrapped function exotic object is callable (it has a [[Call]] internal method). Calling a wrapped function exotic object generally results in a call of its wrapped function.

An object is a wrapped function exotic object if its [[Call]] internal method uses the following implementation, and its other essential internal methods use the definitions found in 9.1. These methods are installed in WrappedFunctionCreate.

Wrapped function exotic objects do not have the internal slots of ECMAScript function objects listed in Internal Slots of ECMAScript Function Objects. Instead they have the internal slots listed in Table 2, in addition to [[Prototype]] and [[Extensible]].

Table 2: Internal Slots of Wrapped Function Exotic Objects
Internal Slot Type Description
[[WrappedTargetFunction]] Callable Object Stores the callable object.
[[Call]] The [[Call]] internal method Executes code associated with this object's [[WrappedTargetFunction]].
[[Realm]] Realm Record The realm in which the function was created.

2.1 [[Call]] ( thisArgument, argumentsList )

The [[Call]] internal method of a wrapped function exotic object F takes arguments thisArgument (an ECMAScript language value) and argumentsList (a List of ECMAScript language values). It performs the following steps when called:

  1. Let target be F.[[WrappedTargetFunction]].
  2. Assert: IsCallable(target) is true.
  3. Let targetRealm be ? GetFunctionRealm(target).
  4. Let callerRealm be ? GetFunctionRealm(F).
  5. NOTE: Any exception objects produced after this point are associated with callerRealm.
  6. Let wrappedArgs be a new empty List.
  7. For each element arg of argumentsList, do
    1. Let wrappedValue be ? GetWrappedValue(targetRealm, arg).
    2. Append wrappedValue to wrappedArgs.
  8. Let wrappedThisArgument to ? GetWrappedValue(targetRealm, thisArgument).
  9. Let result be the Completion Record of Call(target, wrappedThisArgument, wrappedArgs).
  10. If result.[[Type]] is normal or result.[[Type]] is return, then
    1. Return ? GetWrappedValue(callerRealm, result.[[Value]]).
  11. Else,
    1. Throw a TypeError exception.
Editor's Note
In the case of an abrupt throw completion, the type of error to be created should match the type of the abrupt throw completion record. This could be revisited when merging into the main specification. Additionally, in the case of a break or continue completion, since those are not supported, a TypeError is expected.

3 ShadowRealm Objects

3.1 ShadowRealm Abstract Operations

3.1.1 WrappedFunctionCreate ( callerRealm: a Realm Record, Target: a function object, )

The abstract operation WrappedFunctionCreate takes arguments callerRealm and Target. It is used to specify the creation of new wrapped function exotic objects. It performs the following steps when called:

  1. Let internalSlotsList be the internal slots listed in Table 2, plus [[Prototype]] and [[Extensible]].
  2. Let wrapped be MakeBasicObject(internalSlotsList).
  3. Set wrapped.[[Prototype]] to callerRealm.[[Intrinsics]].[[%Function.prototype%]].
  4. Set wrapped.[[Call]] as described in 2.1.
  5. Set wrapped.[[WrappedTargetFunction]] to Target.
  6. Set wrapped.[[Realm]] to callerRealm.
  7. Let result be CopyNameAndLength(wrapped, Target).
  8. If result is an Abrupt Completion, throw a TypeError exception.
  9. Return wrapped.

3.1.2 CopyNameAndLength ( F: a function object, Target: a function object, optional prefix: a String, optional argCount: a Number, )

  1. If argCount is undefined, then set argCount to 0.
  2. Let L be 0.
  3. Let targetHasLength be ? HasOwnProperty(Target, "length").
  4. If targetHasLength is true, then
    1. Let targetLen be ? Get(Target, "length").
    2. If Type(targetLen) is Number, then
      1. If targetLen is +∞𝔽, set L to +∞.
      2. Else if targetLen is -∞𝔽, set L to 0.
      3. Else,
        1. Let targetLenAsInt be ! ToIntegerOrInfinity(targetLen).
        2. Assert: targetLenAsInt is finite.
        3. Set L to max(targetLenAsInt - argCount, 0).
  5. Perform SetFunctionLength(F, L).
  6. Let targetName be ? Get(Target, "name").
  7. If Type(targetName) is not String, set targetName to the empty String.
  8. Perform SetFunctionName(F, targetName, prefix).
Editor's Note
Function.prototype.bind can replace steps 4 to 10 with this abstraction.

3.1.2.1 Function.prototype.bind ( thisArg, ...args )

When the bind method is called with argument thisArg and zero or more args, it performs the following steps:

  1. Let Target be the this value.
  2. If IsCallable(Target) is false, throw a TypeError exception.
  3. Let F be ? BoundFunctionCreate(Target, thisArg, args).
  4. Let argCount be the number of elements in args.
  5. Perform ? CopyNameAndLength(F, Target, "bound", argCount).
  6. Let L be 0.
  7. Let targetHasLength be ? HasOwnProperty(Target, "length").
  8. If targetHasLength is true, then
    1. Let targetLen be ? Get(Target, "length").
    2. If Type(targetLen) is Number, then
    3. If targetLen is +∞𝔽, set L to +∞.
    4. Else if targetLen is -∞𝔽, set L to 0.
    5. Else,
      1. Let targetLenAsInt be ! ToIntegerOrInfinity(targetLen).
      2. Assert: targetLenAsInt is finite.
      3. Let argCount be the number of elements in args.
      4. Set L to max(targetLenAsInt - argCount, 0).
  9. Perform SetFunctionLength(F, L).
  10. Let targetName be ? Get(Target, "name").
  11. If Type(targetName) is not String, set targetName to the empty String.
  12. Perform SetFunctionName(F, targetName, "bound").
  13. Return F.

3.1.3 PerformShadowRealmEval ( sourceText: a String, callerRealm: a Realm Record, evalRealm: a Realm Record, )

  1. Perform ? HostEnsureCanCompileStrings(callerRealm, evalRealm).
  2. Perform the following substeps in an implementation-defined order, possibly interleaving parsing and error detection:
    1. Let script be ParseText(StringToCodePoints(sourceText), Script).
    2. If script is a List of errors, throw a SyntaxError exception.
    3. If script Contains ScriptBody is false, return undefined.
    4. Let body be the ScriptBody of script.
    5. If body Contains NewTarget is true, throw a SyntaxError exception.
    6. If body Contains SuperProperty is true, throw a SyntaxError exception.
    7. If body Contains SuperCall is true, throw a SyntaxError exception.
  3. Let strictEval be IsStrict of script.
  4. Let runningContext be the running execution context.
  5. Let lexEnv be NewDeclarativeEnvironment(evalRealm.[[GlobalEnv]]).
  6. Let varEnv be evalRealm.[[GlobalEnv]].
  7. If strictEval is true, set varEnv to lexEnv.
  8. If runningContext is not already suspended, suspend runningContext.
  9. Let evalContext be a new ECMAScript code execution context.
  10. Set evalContext's Function to null.
  11. Set evalContext's Realm to evalRealm.
  12. Set evalContext's ScriptOrModule to null.
  13. Set evalContext's VariableEnvironment to varEnv.
  14. Set evalContext's LexicalEnvironment to lexEnv.
  15. Push evalContext onto the execution context stack; evalContext is now the running execution context.
  16. Let result be Completion(EvalDeclarationInstantiation(body, varEnv, lexEnv, null, strictEval)).
  17. If result.[[Type]] is normal, then
    1. Set result to the result of evaluating body.
  18. If result.[[Type]] is normal and result.[[Value]] is empty, then
    1. Set result to NormalCompletion(undefined).
  19. Suspend evalContext and remove it from the execution context stack.
  20. Resume the context that is now on the top of the execution context stack as the running execution context.
  21. If result.[[Type]] is not normal, throw a TypeError exception.
  22. Return ? GetWrappedValue(callerRealm, result.[[Value]]).
Editor's Note
In the case of an abrupt throw completion, the type of error to be created should match the type of the abrupt throw completion record. This could be revisited when merging into the main specification. Additionally, in the case of a break or continue completion, since those are not supported, a TypeError is expected. There should be no return completion because this is a top level script evaluation, in which case a return Statement must result in a parsing error.
Editor's Note
Some steps from PerformShadowRealmEval are shared with eval and Function and should result into a shared abstraction when merged to ECMA-262.
Note
This abstraction requires the performed evaluation to result into a normal completion. Otherwise, if the result is not a normal completion, the abstraction will throw a TypeError exception associated to its original running execution context.

3.1.4 ShadowRealmImportValue ( specifierString: a String, exportNameString: a String, callerRealm: a Realm Record, evalRealm: a Realm Record, evalContext: an execution context, )

  1. Assert: evalContext is an execution context associated to a ShadowRealm instance's [[ExecutionContext]].
  2. Let innerCapability be ! NewPromiseCapability(%Promise%).
  3. Let runningContext be the running execution context.
  4. If runningContext is not already suspended, suspend runningContext.
  5. Push evalContext onto the execution context stack; evalContext is now the running execution context.
  6. Perform HostImportModuleDynamically(null, specifierString, innerCapability).
  7. Suspend evalContext and remove it from the execution context stack.
  8. Resume the context that is now on the top of the execution context stack as the running execution context.
  9. Let steps be the steps of an ExportGetter function as described below.
  10. Let onFulfilled be CreateBuiltinFunction(steps, 1, "", « [[ExportNameString]] », callerRealm).
  11. Set onFulfilled.[[ExportNameString]] to exportNameString.
  12. Let promiseCapability be ! NewPromiseCapability(%Promise%).
  13. Return PerformPromiseThen(innerCapability.[[Promise]], onFulfilled, callerRealm.[[Intrinsics]].[[%ThrowTypeError%]], promiseCapability).

An ExportGetter function is an anonymous built-in function with a [[ExportNameString]] internal slot. When an ExportGetter function is called with argument exports, it performs the following steps:

  1. Assert: exports is a module namespace exotic object.
  2. Let f be the active function object.
  3. Let string be f.[[ExportNameString]].
  4. Assert: Type(string) is String.
  5. Let hasOwn be ? HasOwnProperty(exports, string).
  6. If hasOwn is false, throw a TypeError exception.
  7. Let value be ? Get(exports, string).
  8. Let realm be f.[[Realm]].
  9. Return ? GetWrappedValue(realm, value).

3.1.5 GetWrappedValue ( callerRealm: a Realm Record, value: unknown, )

  1. If Type(value) is Object, then
    1. If IsCallable(value) is false, throw a TypeError exception.
    2. Return ? WrappedFunctionCreate(callerRealm, value).
  2. Return value.

3.1.6 ValidateShadowRealmObject ( O: unknown )

  1. Perform ? RequireInternalSlot(O, [[ShadowRealm]]).
  2. Perform ? RequireInternalSlot(O, [[ExecutionContext]]).

3.2 The ShadowRealm Constructor

The ShadowRealm constructor:

  • is the intrinsic object %ShadowRealm%.
  • is the initial value of the "ShadowRealm" property of the global object.
  • is not intended to be called as a function and will throw an exception when called in that manner.
  • creates and initializes a new ShadowRealm object when called as a constructor.
  • is designed to be subclassable. It may be used as the value in an extends clause of a class definition. Subclass constructors that intend to inherit the specified ShadowRealm behaviour must include a super call to the ShadowRealm constructor to create and initialize the subclass instance with the internal state necessary to support the ShadowRealm.prototype built-in methods.

3.2.1 ShadowRealm ( )

When the ShadowRealm function is called, the following steps are taken:

  1. If NewTarget is undefined, throw a TypeError exception.
  2. Let O be ? OrdinaryCreateFromConstructor(NewTarget, "%ShadowRealm.prototype%", « [[ShadowRealm]], [[ExecutionContext]] »).
  3. Let realmRec be CreateRealm().
  4. Set O.[[ShadowRealm]] to realmRec.
  5. Let context be a new execution context.
  6. Set the Function of context to null.
  7. Set the Realm of context to realmRec.
  8. Set the ScriptOrModule of context to null.
  9. Set O.[[ExecutionContext]] to context.
  10. Perform ? SetRealmGlobalObject(realmRec, undefined, undefined).
  11. Perform ? SetDefaultGlobalBindings(O.[[ShadowRealm]]).
  12. Perform ? HostInitializeShadowRealm(O.[[ShadowRealm]]).
  13. Return O.

3.3 Properties of the ShadowRealm Constructor

The ShadowRealm constructor:

  • has a [[Prototype]] internal slot whose value is %Function.prototype%.
  • has the following properties:

3.3.1 ShadowRealm.prototype

The initial value of ShadowRealm.prototype is %ShadowRealm.prototype%.

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }.

3.4 Properties of the ShadowRealm Prototype Object

The ShadowRealm prototype object:

  • has a [[Prototype]] internal slot whose value is %Object.prototype%.
  • is %ShadowRealm.prototype%.
  • is an ordinary object.
  • does not have a [[ShadowRealm]] or any other of the internal slots that are specific to Realm instance objects.

3.4.1 ShadowRealm.prototype.evaluate ( sourceText )

Synchronously execute a top-level script. The sourceText is interpreted as a Script and evaluated with this bound to the shadowrealm's global object.

  1. Let O be this value.
  2. Perform ? ValidateShadowRealmObject(O).
  3. If Type(sourceText) is not String, throw a TypeError exception.
  4. Let callerRealm be the current Realm Record.
  5. Let evalRealm be O.[[ShadowRealm]].
  6. Return ? PerformShadowRealmEval(sourceText, callerRealm, evalRealm).
Editor's Note
Extensible web: This is the dynamic equivalent of a <script> in HTML.

3.4.2 ShadowRealm.prototype.importValue ( specifier, exportName )

The following steps are performed:

  1. Let O be this value.
  2. Perform ? ValidateShadowRealmObject(O).
  3. Let specifierString be ? ToString(specifier).
  4. If Type(exportName) is not String, throw a TypeError exception.
  5. Let callerRealm be the current Realm Record.
  6. Let evalRealm be O.[[ShadowRealm]].
  7. Let evalContext be O.[[ExecutionContext]].
  8. Return ? ShadowRealmImportValue(specifierString, exportName, callerRealm, evalRealm, evalContext).
Editor's Note
Extensible web: This is equivalent to dynamic import without having to evaluate a script source, which might not be available (e.g.: when CSP is blocking source evaluation).

3.4.3 ShadowRealm.prototype [ @@toStringTag ]

The initial value of the @@toStringTag property is the String value "ShadowRealm".

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.

3.5 Properties of ShadowRealm Instances

ShadowRealm instances are ordinary objects that inherit properties from the ShadowRealm prototype object (the intrinsic, %ShadowRealm.prototype%). ShadowRealm instances are initially created with the internal slots described in Table 3.

Table 3: Internal Slots of ShadowRealm Instances
Internal Slot Type Description
[[ShadowRealm]] Realm Record The Realm Record for the initial execution context.
[[ExecutionContext]] Execution context An execution context wherein the current Realm is this [[ShadowRealm]].

3.6 Host operations

3.6.1 Runtime Semantics: HostInitializeShadowRealm ( realm )

HostInitializeShadowRealm is an implementation-defined abstract operation used to inform the host of any newly created realms from the ShadowRealm constructor. Its return value is not used, though it may throw an exception. The idea of this hook is to initialize host data structures related to the ShadowRealm, e.g., for module loading.

The host may use this hook to add properties to the ShadowRealm's global object. Those properties must be configurable.

Note

This specification does not recommend any specific addition. In the Web embedding, HTML and WebIDL will specify which interfaces are included. The Web Platform and Web-like environments may decide to include EventTarget, atob, TextEncoder, URL, etc. while at the same time not including HTMLElement, console, localStorage, fetch, etc..

Editor's Note

The ShadowRealm constructor (3.2.1 creates a new global object as an ordinary object. This means all properties from the global object are deletable.