Stage 3 Draft / November 25, 2024

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 10.1. These methods are installed in WrappedFunctionCreate.

Wrapped function exotic objects do not have the internal slots of ECMAScript function objects listed in Table 30. 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) and returns either a normal completion containing either a primitive value or a wrapped function exotic object, or a throw completion. It performs the following steps when called:

  1. Let callerContext be the running execution context.
  2. Let calleeContext be PrepareForWrappedFunctionCall(F).
  3. Assert: calleeContext is now the running execution context.
  4. Let result be Completion(OrdinaryWrappedFunctionCall(F, thisArgument, argumentsList)).
  5. Remove calleeContext from the execution context stack and restore callerContext as the running execution context.
  6. Return ? result.

If an execution in a ShadowRealm R1 oblivious of host or implementation-defined APIs can observe the identity of an object O1, a host or implementation-defined API must not allow an execution in any other realm than R1 to also observe the identity of O1. Similarly if an execution in a realm R2 can observe the identity of an object O2, a host or implementation-defined API must not allow execution in any other realm than R2 that is a ShadowRealm to also observe the identity of O2.

Note
The text above imposes the callable boundary semantics only when at least one of the two realms involved is a ShadowRealm. Other realms can continue sharing objects whose identities can be observed. Colloquially, the environment must not allow ECMAScript code running in a ShadowRealm to observe the identity of an object from any other realm. Similarly, the environment must not allow ECMAScript code running in a realm to observe the identity of an object from a ShadowRealm.

2.2 CreateTypeErrorCopy ( realmRecord, originalError )

The abstract operation CreateTypeErrorCopy takes arguments realmRecord (a Realm Record) and originalError (an ECMAScript language value) and returns a TypeError object. It performs the following steps when called:

  1. Let newError be a newly created TypeError object.
  2. NOTE: newError is created in realmRecord.
  3. Return newError.

Host environments may provide implementation-specific message value. CreateTypeErrorCopy abstract operation must not cause any ECMAScript code execution. The implementation may store additional information on originalError to produce the newError's message.

2.3 OrdinaryWrappedFunctionCall ( F, thisArgument, argumentsList )

The abstract operation OrdinaryWrappedFunctionCall takes arguments F (a wrapped function exotic object), thisArgument (an ECMAScript language value), and argumentsList (a List of ECMAScript language values) and returns either a normal completion containing either a primitive value or a wrapped function exotic object, or a throw completion. ... It performs the following steps when called:

  1. Let target be F.[[WrappedTargetFunction]].
  2. Assert: IsCallable(target) is true.
  3. Let callerRealm be F.[[Realm]].
  4. NOTE: Any exception objects produced after this point are associated with callerRealm.
  5. Let targetRealm be ? GetFunctionRealm(target).
  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 be ? GetWrappedValue(targetRealm, thisArgument).
  9. Let result be Completion(Call(target, wrappedThisArgument, wrappedArgs)).
  10. If result.[[Type]] is normal, then
    1. Return ? GetWrappedValue(callerRealm, result.[[Value]]).
  11. Else,
    1. Let copiedError be CreateTypeErrorCopy(callerRealm, result.[[Value]]).
    2. Return ThrowCompletion(copiedError).

2.4 PrepareForWrappedFunctionCall ( F )

The abstract operation PrepareForWrappedFunctionCall takes argument F (a wrapped function exotic object) and returns an execution context. ... It performs the following steps when called:

  1. Let callerContext be the running execution context.
  2. Let calleeContext be a new execution context.
  3. Set the Function of calleeContext to F.
  4. Let calleeRealm be F.[[Realm]].
  5. Set the Realm of calleeContext to calleeRealm.
  6. Set the ScriptOrModule of calleeContext to null.
  7. If callerContext is not already suspended, suspend callerContext.
  8. Push calleeContext onto the execution context stack; calleeContext is now the running execution context.
  9. NOTE: Any exception objects produced after this point are associated with calleeRealm.
  10. Return calleeContext.

3 ShadowRealm Objects

3.1 ShadowRealm Abstract Operations

3.1.1 WrappedFunctionCreate ( callerRealm, Target )

The abstract operation WrappedFunctionCreate takes arguments callerRealm (a Realm Record) and Target (a function object) and returns either a normal completion containing a wrapped function exotic object, or a throw completion. 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 Completion(CopyNameAndLength(wrapped, Target)).
  8. If result is an abrupt completion, throw a TypeError exception.
  9. Return wrapped.

3.1.2 CopyNameAndLength ( F, Target [ , prefix [ , argCount ] ] )

The abstract operation CopyNameAndLength takes arguments F (a function object) and Target (a function object) and optional arguments prefix (a String) and argCount (a Number) and returns either a normal completion containing unused or a throw completion. ... It performs the following steps when called:

  1. If argCount is not present, 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 targetLen is a Number, then
      1. If targetLen is +∞𝔽, then
        1. Set L to +∞.
      2. Else if targetLen is -∞𝔽, then
        1. 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 targetName is not a String, set targetName to the empty String.
  8. If prefix is present, then
    1. Perform SetFunctionName(F, targetName, prefix).
  9. Else,
    1. Perform SetFunctionName(F, targetName).
Editor's Note
Function.prototype.bind can replace some steps with this abstraction.

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

This method performs the following steps when called:

  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 targetLen is a Number, then
      1. If targetLen is +∞𝔽, then
        1. Set L to +∞.
      2. Else if targetLen is -∞𝔽, then
        1. Set L to 0.
      3. 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 targetName is not a String, set targetName to the empty String.
  12. Perform SetFunctionName(F, targetName, "bound").
  13. Return F.

3.1.3 PerformShadowRealmEval ( sourceText, callerRealm, evalRealm )

The abstract operation PerformShadowRealmEval takes arguments sourceText (a String), callerRealm (a Realm Record), and evalRealm (a Realm Record) and returns either a normal completion containing either a primitive value or a wrapped function exotic object, or a throw completion. ... It performs the following steps when called:

  1. Perform ? HostEnsureCanCompileStrings(evalRealm, « », sourceText, false).
  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 ScriptIsStrict of script.
  4. Let runningContext be the running execution context.
  5. If runningContext is not already suspended, suspend runningContext.
  6. Let evalContext be GetShadowRealmContext(evalRealm, strictEval).
  7. Let lexEnv be evalContext's LexicalEnvironment.
  8. Let varEnv be evalContext's VariableEnvironment.
  9. Push evalContext onto the execution context stack; evalContext is now the running execution context.
  10. Let result be Completion(EvalDeclarationInstantiation(body, varEnv, lexEnv, null, strictEval)).
  11. If result.[[Type]] is normal, then
    1. Set result to Completion(Evaluation of body).
  12. If result.[[Type]] is normal and result.[[Value]] is empty, then
    1. Set result to NormalCompletion(undefined).
  13. Suspend evalContext and remove it from the execution context stack.
  14. Resume the context that is now on the top of the execution context stack as the running execution context.
  15. If result.[[Type]] is not normal, then
    1. Let copiedError be CreateTypeErrorCopy(callerRealm, result.[[Value]]).
    2. Return ThrowCompletion(copiedError).
  16. 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, exportNameString, callerRealm, evalRealm )

The abstract operation ShadowRealmImportValue takes arguments specifierString (a String), exportNameString (a String), callerRealm (a Realm Record), and evalRealm (a Realm Record) and returns an ECMAScript language value. ... It performs the following steps when called:

  1. Let evalContext be GetShadowRealmContext(evalRealm, true).
  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. Let referrer be the Realm component of evalContext.
  7. Perform HostLoadImportedModule(referrer, specifierString, empty, innerCapability).
  8. Suspend evalContext and remove it from the execution context stack.
  9. Resume the context that is now on the top of the execution context stack as the running execution context.
  10. Let steps be the algorithm steps defined in ExportGetter functions.
  11. Let onFulfilled be CreateBuiltinFunction(steps, 1, "", « [[ExportNameString]] », callerRealm).
  12. Set onFulfilled.[[ExportNameString]] to exportNameString.
  13. Let errorSteps be the algorithm steps defined in ImportValueError functions.
  14. Let onRejected be CreateBuiltinFunction(errorSteps, 1, "", «», callerRealm).
  15. Let promiseCapability be ! NewPromiseCapability(%Promise%).
  16. Return PerformPromiseThen(innerCapability.[[Promise]], onFulfilled, onRejected, promiseCapability).

3.1.4.1 ExportGetter functions

An ExportGetter function is an anonymous built-in function that has an [[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: string is a 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.4.2 ImportValueError functions

An ImportValueError function is an anonymous built-in function.

When an ImportValueError function is called with argument error, it performs the following steps:

  1. Let realmRecord be the function's associated Realm Record.
  2. Let copiedError be CreateTypeErrorCopy(realmRecord, error).
  3. Return ThrowCompletion(copiedError).

3.1.5 GetWrappedValue ( callerRealm, value )

The abstract operation GetWrappedValue takes arguments callerRealm (a Realm Record) and value (an ECMAScript language value) and returns either a normal completion containing either a primitive value or an wrapped function exotic object, or a throw completion. ... It performs the following steps when called:

  1. If value is an 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 )

The abstract operation ValidateShadowRealmObject takes argument O (an ECMAScript value) and returns either a normal completion containing unused or a throw completion. ... It performs the following steps when called:

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

3.1.7 GetShadowRealmContext ( shadowRealmRecord, strictEval )

The abstract operation GetShadowRealmContext takes arguments shadowRealmRecord (a Realm Record) and strictEval (a Boolean) and returns an ECMAScript code execution context. It performs the following steps when called:

  1. Let lexEnv be NewDeclarativeEnvironment(shadowRealmRecord.[[GlobalEnv]]).
  2. Let varEnv be shadowRealmRecord.[[GlobalEnv]].
  3. If strictEval is true, set varEnv to lexEnv.
  4. Let context be a new ECMAScript code execution context.
  5. Set context's Function to null.
  6. Set context's Realm to shadowRealmRecord.
  7. Set context's ScriptOrModule to null.
  8. Set context's VariableEnvironment to varEnv.
  9. Set context's LexicalEnvironment to lexEnv.
  10. Set context's PrivateEnvironment to null.
  11. Return context.

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.
  • 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 a subclass instance with the internal state necessary to support the ShadowRealm.prototype built-in methods.

3.2.1 ShadowRealm ( )

This function performs the following steps when called:

  1. If NewTarget is undefined, throw a TypeError exception.
  2. Let O be ? OrdinaryCreateFromConstructor(NewTarget, "%ShadowRealm.prototype%", « [[ShadowRealm]] »).
  3. Let callerContext be the running execution context.
  4. Perform ? InitializeHostDefinedRealm().
  5. Let innerContext be the running execution context.
  6. Remove innerContext from the execution context stack and restore callerContext as the running execution context.
  7. Let realmRec be the Realm of innerContext.
  8. Set O.[[ShadowRealm]] to realmRec.
  9. Perform ? HostInitializeShadowRealm(realmRec, innerContext, O).
  10. Assert: realmRec.[[GlobalObject]] is an ordinary object.
  11. 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 ShadowRealm 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 the this value.
  2. Perform ? ValidateShadowRealmObject(O).
  3. If sourceText is not a 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 the this value.
  2. Perform ? ValidateShadowRealmObject(O).
  3. Let specifierString be ? ToString(specifier).
  4. If exportName is not a String, throw a TypeError exception.
  5. Let callerRealm be the current Realm Record.
  6. Let evalRealm be O.[[ShadowRealm]].
  7. Return ShadowRealmImportValue(specifierString, exportName, callerRealm, evalRealm).
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.

3.6 Host operations

3.6.1 HostInitializeShadowRealm ( realm, context, O )

The host-defined abstract operation HostInitializeShadowRealm takes arguments realm (a Realm Record), context (an execution context), and O (a ShadowRealm object) and returns either a normal completion containing unused or a throw completion. It is used to inform the host of any newly created realms from the ShadowRealm constructor. The idea of this hook is to initialize host data structures related to the ShadowRealm, e.g., for module loading.

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, localStorage, fetch, etc.

3.6.2 Requirements on host-defined global objects

If a host defines that a specific global object is to be used for a ShadowRealm, that object must be an extensible ordinary object, and any properties on it must be configurable.