ECMAScript Realms Spec Proposal

Table 1: Well-known Intrinsic Objects
Intrinsic Name Global Name ECMAScript Language Association
%Realm% Realm
%RealmPrototype% Realm.prototype

1Realms

Table 2: Realm Record Fields
Field Name Value Meaning
[[HostDefined]] ... ...
[[TransformTrap]] A function object or undefined The function that is used as the transform trap. If [[TransformTrap]] is undefined, the trap invoker will carry on the default behavior.
[[IsDirectEvalTrap]] A function object or undefined The function that is used as the direct eval check trap. If [[IsDirectEvalTrap]] is undefined, the trap invoker will carry on the default behavior.
[[PreventImportExpression]] A boolean value Whether or not import declarations or expressions are allowed. Default to false.

1.1InvokeIsDirectEvalTrap( trap, func )

The abstract operation InvokeIsDirectEvalTrap with arguments trap and func performs the following steps:

  1. Assert: IsCallable(trap) is true.
  2. Let result be ToBoolean( ? Call(trap, undefined, « func »)).
  3. Return result.

1.2InvokeTransformTrap ( trap, sourceText )

The abstract operation InvokeTransformTrap with arguments trap and sourceText performs the following steps:

  1. Assert: IsCallable(trap) is true.
  2. Let newSourceText be ? Call(trap, undefined, « sourceText »).
  3. Return ? ToString(newSourceText).

2Runtime Semantics: PerformEval ( x, evalRealm, strictCaller, direct )

The abstract operation PerformEval with arguments x, evalRealm, strictCaller, and direct performs the following steps:

  1. Assert: If direct is false, then strictCaller is also false.
  2. If Type(x) is not String, return x.
  3. Let fn be evalRealm.[[TransformTrap]].
  4. If IsCallable(fn) is true, then
    1. Let x be ? InvokeTransformTrap(fn, x)..
  5. Let thisEnvRec be ! GetThisEnvironment().
  6. If thisEnvRec is a function Environment Record, then
    1. Let F be thisEnvRec.[[FunctionObject]].
    2. Let inFunction be true.
    3. Let inMethod be thisEnvRec.HasSuperBinding().
    4. If F.[[ConstructorKind]] is "derived", let inDerivedConstructor be true; otherwise, let inDerivedConstructor be false.
  7. Else,
    1. Let inFunction be false.
    2. Let inMethod be false.
    3. Let inDerivedConstructor be false.
  8. Let preventImport is evalRealm.[[PreventImportExpression]].
  9. Let script be the ECMAScript code that is the result of parsing x, interpreted as UTF-16 encoded Unicode text as described in 6.1.4, for the goal symbol Script. If preventImport is true, additional early error rules from 2.1 are applied. If inFunction is false, additional early error rules from 18.2.1.1.1 are applied. If inMethod is false, additional early error rules from 18.2.1.1.2 are applied. If inDerivedConstructor is false, additional early error rules from 18.2.1.1.3 are applied. If the parse fails, throw a SyntaxError exception. If any early errors are detected, throw a SyntaxError or a ReferenceError exception, depending on the type of the error (but see also clause 16). Parsing and early error detection may be interweaved in an implementation-dependent manner.
  10. If script Contains ScriptBody is false, return undefined.
  11. Let body be the ScriptBody of script.
  12. If strictCaller is true, let strictEval be true.
  13. Else, let strictEval be IsStrict of script.
  14. Let ctx be the running execution context.
  15. NOTE: If direct is true, ctx will be the execution context that performed the direct eval. If direct is false, ctx will be the execution context for the invocation of the eval function.
  16. If direct is true, then
    1. Let lexEnv be NewDeclarativeEnvironment(ctx's LexicalEnvironment).
    2. Let varEnv be ctx's VariableEnvironment.
  17. Else,
    1. Let lexEnv be NewDeclarativeEnvironment(evalRealm.[[GlobalEnv]]).
    2. Let varEnv be evalRealm.[[GlobalEnv]].
  18. If strictEval is true, set varEnv to lexEnv.
  19. If ctx is not already suspended, suspend ctx.
  20. Let evalCxt be a new ECMAScript code execution context.
  21. Set the evalCxt's Function to null.
  22. Set the evalCxt's Realm to evalRealm.
  23. Set the evalCxt's ScriptOrModule to ctx's ScriptOrModule.
  24. Set the evalCxt's VariableEnvironment to varEnv.
  25. Set the evalCxt's LexicalEnvironment to lexEnv.
  26. Push evalCxt on to the execution context stack; evalCxt is now the running execution context.
  27. Let result be EvalDeclarationInstantiation(body, varEnv, lexEnv, strictEval).
  28. If result.[[Type]] is normal, then
    1. Set result to the result of evaluating body.
  29. If result.[[Type]] is normal and result.[[Value]] is empty, then
    1. Set result to NormalCompletion(undefined).
  30. Suspend evalCxt and remove it from the execution context stack.
  31. Resume the context that is now on the top of the execution context stack as the running execution context.
  32. Return Completion(result).

2.1Additional Early Error Rules for Eval in Realms

These static semantics are applied by PerformEval and PerformRealmEvaluation when evaluating code in a Realm Record associated to a Realm Object.

CallExpression:ImportCall
  • It is a Reference Error if the Realm Record Field Name [[PreventImportExpression]] has the value of true.

3Runtime Semantics: Evaluation

CallExpression:CoverCallExpressionAndAsyncArrowHead
  1. Let expr be CoveredCallExpression of CoverCallExpressionAndAsyncArrowHead.
  2. Let memberExpr be the MemberExpression of expr.
  3. Let arguments be the Arguments of expr.
  4. Let ref be the result of evaluating memberExpr.
  5. Let func be ? GetValue(ref).
  6. If Type(ref) is Reference and IsPropertyReference(ref) is false and GetReferencedName(ref) is "eval", then
    1. Let evalRealm be the current Realm Record..
    2. Let trapFn be evalRealm.[[IsDirectEvalTrap]].
    3. If IsCallable(trapFn) is true, then
      1. Let isDirectEval be ? InvokeIsDirectEvalTrap(trapFn, func)..
    4. Else,
      1. Let isDirectEval be SameValue(func, %eval%).
    5. If isDirectEvalSameValue(func, %eval%) is true, then
      1. Let argList be ? ArgumentListEvaluation(arguments).
      2. If argList has no elements, return undefined.
      3. Let evalText be the first element of argList.
      4. If the source code matching this CallExpression is strict mode code, let strictCaller be true. Otherwise let strictCaller be false.
      5. Let evalRealm be the current Realm Record.
      6. Perform ? HostEnsureCanCompileStrings(evalRealm, evalRealm).
      7. Return ? PerformEval(evalText, evalRealm, strictCaller, true).
  7. Let thisCall be this CallExpression.
  8. Let tailCall be IsInTailPosition(thisCall).
  9. Return ? EvaluateCall(func, ref, arguments, tailCall).

4ParseScript ( sourceText, realm, hostDefined )

The abstract operation ParseScript with arguments sourceText, realm, and hostDefined creates a Script Record based upon the result of parsing sourceText as a Script. ParseScript performs the following steps:

  1. Assert: sourceText is an ECMAScript source text (see clause 10).
  2. Let preventImport is realm.[[PreventImportExpression]].
  3. Parse sourceText using Script as the goal symbol and analyse the parse result for any Early Error conditions. If preventImport is true, additional early error rules from 2.1 are applied. If the parse was successful and no early errors were found, let body be the resulting parse tree. Otherwise, let body be a List of one or more SyntaxError or ReferenceError objects representing the parsing errors and/or early errors. Parsing and early error detection may be interweaved in an implementation-dependent manner. If more than one parsing error or early error is present, the number and ordering of error objects in the list is implementation-dependent, but at least one must be present.
  4. If body is a List of errors, return body.
  5. Return Script Record {[[Realm]]: realm, [[Environment]]: undefined, [[ECMAScriptCode]]: body, [[HostDefined]]: hostDefined}.

5Realm Objects

5.1Realm Abstract Operations

5.1.1CreateRealmRec ( intrinsics )

  1. Let realmRec be a new Realm Record.
  2. If intrinsics is undefined, then
    1. Perform CreateIntrinsics(realmRec).
  3. Else
    1. Assert: In this case, intrinsics must be a Record with field names listed in column one of Table 7.
    2. Set realmRec.[[Intrinsics]] to intrinsics.
  4. Set realmRec.[[GlobalObject]] to undefined.
  5. Set realmRec.[[GlobalEnv]] to undefined.
  6. Set realmRec.[[TemplateMap]] to a new empty List.
  7. Return realmRec.

5.1.2PerformRealmEvaluation ( x, evalRealm )

  1. Assert: Type(x) is String.
  2. Assert: evalRealm is a Realm Record.
  3. Let hostDefined be evalRealm.[[HostDefined]].
  4. Let s be ParseScript(x, evalRealm, hostDefined).
  5. If s is a List of errors, then
    1. Perform HostReportErrors(s).
    2. Return NormalCompletion(undefined).
  6. Return ? ScriptEvaluation(s).

5.2The Realm Constructor

The Ream constructor is the %Realm% intrinsic object and the initial value of the Realm property of the global object. When called as a constructor it creates and initializes a new Realm object. Realm is not intended to be called as a function and will throw an exception when called in that manner.

The Realm 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 Realm behaviour must include a super call to the Realm constructor to create and initialize the subclass instance with the internal state necessary to support the Realm.prototype built-in methods.

5.2.1Realm ([ options ])

When Realm is called with argument option performs the following steps:
  1. If NewTarget is undefined, throw a TypeError exception.
  2. Let O be ? OrdinaryCreateFromConstructor(NewTarget, "%RealmPrototype%", « [[Realm]] »).
  3. If options is not undefined, then
    1. Let parentRealm be the current Realm Record.
    2. Let opts be ? ToObject(options).
    3. Let transformTrap be ? Get(opts, "transform").
    4. If transformTrap is equal "inherit", then
      1. Set transformTrap to parentRealm.[[TransformTrap]].
    5. Else if transformTrap is not undefined and IsCallable(transformTrap) is false, throw a TypeError exception.
    6. Let isDirectEvalTrap be ? Get(opts, "isDirectEval").
    7. If isDirectEvalTrap is equal "inherit", then
      1. Set isDirectEvalTrap to parentRealm.[[IsDirectEvalTrap]].
    8. Else if isDirectEvalTrap is not undefined and IsCallable(isDirectEvalTrap) is false, throw a TypeError exception.
    9. Let intrinsics be ? Get(opts, "intrinsics").
    10. If intrinsics is equal "inherit", then
      1. Set intrinsics to parentRealm.[[Intrinsics]].
    11. Else if intrinsics is not undefined, throw a TypeError exception.
    12. Let thisValue be ? Get(opts, "thisValue").
    13. If thisValue is not undefined and Type(thisValue) is not Object, throw a TypeError exception.
  4. Let realmRec be CreateRealmRec(intrinsics).
  5. Set O.[[Realm]] to realmRec.
  6. Perform ? SetRealmGlobalObject(realmRec, undefined, thisValue).
  7. Set realmRec.[[PreventImportExpression]] to true.
  8. If transformTrap is not undefined, then
    1. Set realmRec.[[TransformTrap]] to transformTrap.
  9. If isDirectEvalTrap is not undefined, then
    1. Set realmRec.[[IsDirectEvalTrap]] to isDirectEvalTrap.
  10. Let init be ? GetMethod(O, "init").
  11. If IsCallable(init) is not true, throw a TypeError exception.
  12. Perform ? Call(init, O).
  13. Return O.

5.3Properties of the Realm Constructor

The value of the [[Prototype]] internal slot of the Realm constructor is the intrinsic object %FunctionPrototype%.

5.4Properties of the Realm Prototype Object

5.4.1Realm.prototype.init ()

  1. Let O be this value.
  2. If Type(O) is not Object, throw a TypeError exception.
  3. If O does not have an [[Realm]] internal slot, throw a TypeError exception.
  4. Perform ? SetDefaultGlobalBindings(O.[[Realm]]).
Note
Extensible web: This is the dynamic way to define globals in a new realm.

5.4.2Realm.prototype.evaluate ( sourceText )

Synchronously execute a top-level script. The x is interpreted as a Script and evaluated with this bound to the realm's global object.
  1. Let O be this value.
  2. If Type(O) is not Object, throw a TypeError exception.
  3. If O does not have an [[Realm]] internal slot, throw a TypeError exception.
  4. If Type(sourceText) is not String, throw a TypeError exception.
  5. Let realm be O.[[Realm]].
  6. Return ? PerformRealmEvaluation(sourceText, realm).
Note 1
Extensible web: This is the dynamic equivalent of a <script> in HTML.
Note 2
Invocation of this method does not transform x via the [[TransformTrap]].

5.4.3get Realm.prototype.global

Realm.prototype.global is an accessor property whose set accessor function is undefined. Its get accessor function performs the following steps:
  1. Let O be this value.
  2. If Type(O) is not Object, throw a TypeError exception.
  3. If O does not have an [[Realm]] internal slot, throw a TypeError exception.
  4. Return O.[[Realm]].[[GlobalObject]].

5.4.4get Realm.prototype.thisValue

Realm.prototype.thisValue is an accessor property whose set accessor function is undefined. Its get accessor function performs the following steps:
  1. Let O be this value.
  2. If Type(O) is not Object, throw a TypeError exception.
  3. If O does not have an [[Realm]] internal slot, throw a TypeError exception.
  4. Let envRec be O.[[Realm]].[[GlobalEnv]].
  5. Return envRec.[[GlobalThisValue]].

5.4.5get Realm.prototype.stdlib

Realm.prototype.stdlib is an accessor property whose set accessor function is undefined. Its get accessor function performs the following steps:
  1. Let O be this value.
  2. If Type(O) is not Object, throw a TypeError exception.
  3. If O does not have an [[Realm]] internal slot, throw a TypeError exception.
  4. Let realmRec be O.[[Realm]].
  5. Let global be realmRec.[[GlobalObject]].
  6. Let stdlib be ObjectCreate(%ObjectPrototype%).
  7. For each property of the Global Object specified in clause 18 that correspond to an intrinsic object, do:
    1. Let name be the String value of the property name.
    2. Let value be the corresponding value of the intrinsic object from record realmRec.[[Intrinsics]].
    3. Let descObj be ObjectCreate(%ObjectPrototype%).
    4. Perform ? DefinePropertyOrThrow(descObj, "value", PropertyDescriptor{[[Value]]: value, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}).
    5. Perform ? DefinePropertyOrThrow(stdlib, name, PropertyDescriptor{[[Value]]: descObj, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}).
  8. Return stdlib.

5.4.6get Realm.prototype.intrinsics

Realm.prototype.intrinsics is an accessor property whose set accessor function is undefined. Its get accessor function performs the following steps:
  1. Let O be this value.
  2. If Type(O) is not Object, throw a TypeError exception.
  3. If O does not have an [[Realm]] internal slot, throw a TypeError exception.
  4. Let realmRec be O.[[Realm]].
  5. Let intrinsics be ObjectCreate(%ObjectPrototype%).
  6. For each intrinsic name listed in Table 7, do:
    1. Let intrinsicName be the String value in column one of the table.
    2. Let name be the String value of intrinsicName without the % symbols.
    3. Let value be the value of the field name intrisicName from record realmRec.[[Intrinsics]].
    4. Perform ? DefinePropertyOrThrow(intrinsics, name, PropertyDescriptor{[[Value]]: value, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}).
  7. Return intrinsics.

5.4.7Realm.prototype [ @@toStringTag ]

The initial value of the @@toStringTag property is the String value "Realm". This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.

5.5Properties of Realm Instances

Realm instances are ordinary objects that inherit properties from the Realm prototype object (the intrinsic, %RealmPrototype%). Realm instances are initially created with the internal slots described in Table 3.
Table 3: Internal Slots of Realm Instances
Internal Slot Type Description
[[Realm]] Realm Record The Realm Record for the initial execution context.