Skip to content

Commit

Permalink
Merge pull request #291 from tc39/caridy/isolation
Browse files Browse the repository at this point in the history
[draft] first draft for isolated realms
  • Loading branch information
leobalter authored Mar 26, 2021
2 parents ff75839 + c90b0ca commit dc79d98
Show file tree
Hide file tree
Showing 3 changed files with 234 additions and 31 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ See more at the [explainer](explainer.md) document.
```ts
declare class Realm {
constructor();
readonly globalThis: typeof globalThis;
import(specifier: string): Promise<Namespace>;
importBinding(specifier: string, bindingName: string): Promise<PrimitiveValueOrCallable>;
evaluate(sourceText: string): PrimitiveValueOrCallable;
}
```

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,6 @@
"watch": "npm run build -- --watch"
},
"devDependencies": {
"ecmarkup": "^3.21.1"
"ecmarkup": "^7.0.3"
}
}
259 changes: 231 additions & 28 deletions spec.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
<!doctype html>
<html lang="en-GB-oxendict">
<head>
<meta charset="utf8">
<link href="ecmarkup.css" rel="stylesheet">
<script src="ecmarkup.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.5.0/styles/solarized-light.min.css">
</head>

<body>
<pre class="metadata">
title: 'Realms API'
stage: 2
Expand All @@ -8,9 +16,6 @@
copyright: false
location: https://tc39.es/proposal-realms/
</pre>
<link href="ecmarkup.css" rel="stylesheet">
<script src="ecmarkup.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.4/styles/github.min.css">

<emu-clause id="sec-well-known-intrinsic-objects">
<h1>Well-known intrinsic objects</h1>
Expand All @@ -32,8 +37,177 @@ <h1>Well-known intrinsic objects</h1>
</emu-table>
</emu-clause>

<emu-clause id="sec-wrapped-function-exotic-objects">
<h1>Wrapped Function Exotic Objects</h1>
<p>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.</p>

<p>An object is a <dfn id="wrapped-function-exotic-object">wrapped function exotic object</dfn> if its [[Call]] internal method use the following implementations, and its other essential internal methods use the definitions found in <emu-xref href="#sec-ordinary-object-internal-methods-and-internal-slots"></emu-xref>. These methods are installed in WrappedFunctionCreate.</p>

<p>Wrapped function exotic objects do not have the internal slots of ECMAScript function objects listed in <emu-xref href="#table-internal-slots-of-ecmascript-function-objects"></emu-xref>. Instead they have the internal slots listed in <emu-xref href="#table-internal-slots-of-wrapped-function-exotic-objects"></emu-xref>, in addition to [[Prototype]] and [[Extensible]].</p>
<emu-table id="table-internal-slots-of-wrapped-function-exotic-objects" caption="Internal Slots of Wrapped Function Exotic Objects">
<table>
<tbody>
<tr>
<th>
Internal Slot
</th>
<th>
Type
</th>
<th>
Description
</th>
</tr>
<tr>
<td>
[[WrappedTargetFunction]]
</td>
<td>
Callable Object
</td>
<td>
The wrapped function object.
</td>
</tr>
<tr>
<td>
[[Realm]]
</td>
<td>
Realm Record
</td>
<td>
The realm in which the wrapped function object was created.
</td>
</tr>
</tbody>
</table>
</emu-table>

<emu-clause id="sec-wrapped-function-exotic-objects-call-thisargument-argumentslist">
<h1>[[Call]] ( _thisArgument_, _argumentsList_ )</h1>
<p>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:</p>
<emu-alg>
1. Let _target_ be _F_.[[WrappedTargetFunction]].
1. Assert: IsCallable(_target_) is *true*.
1. Let _targetRealm_ be ? GetFunctionRealm(_target_).
1. Let _callerRealm_ be ? GetFunctionRealm(_F_).
1. For each element _key_ of _argumentsList_, do
1. Let o be _argumentsList_[_key_].
1. Set _argumentsList_[_key_] to ? GetWrappedValue(_targetRealm_, _o_).
1. Let _wrappedThisArgument_ to ? GetWrappedValue(_targetRealm_, _thisArgument_).
1. Let _result_ be the Completion Record of Call(_target_, _wrappedThisArgument_, _argumentsList_).
1. If _result_.[[Type]] is ~normal~ or _result_.[[Type]] is ~return~, then
1. Set _value_ to NormalCompletion(_result_.[[Value]]).
1. Return ? GetWrappedValue(_callerRealm_, _value_).
1. Else,
1. Throw a newly created TypeError object associate to the _callerRealm_.
</emu-alg>
<emu-note type=editor>
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.
</emu-note>
</emu-clause>

<emu-clause id="sec-wrappedfunctioncreate" aoid="WrappedFunctionCreate">
<h1>WrappedFunctionCreate ( _callerRealm_, _targetFunction_ )</h1>
<p>The abstract operation WrappedFunctionCreate takes arguments _callerRealm_ and _targetFunction_. It is used to specify the creation of new wrapped function exotic objects. It performs the following steps when called:</p>
<emu-alg>
1. Assert: _callerRealm_ is a Realm Record.
1. Assert: IsCallable(_targetFunction_) is *true*.
1. Let _internalSlotsList_ be the internal slots listed in <emu-xref href="#table-internal-slots-of-wrapped-function-exotic-objects"></emu-xref>, plus [[Prototype]] and [[Extensible]].
1. Let _obj_ be ! MakeBasicObject(_internalSlotsList_).
1. Set _obj_.[[Prototype]] to %Function.prototype% from _callerRealm_.
1. Set _obj_.[[Call]] as described in <emu-xref href="#sec-wrapped-function-exotic-objects-call-thisargument-argumentslist"></emu-xref>.
1. Set _obj_.[[Realm]] to _callerRealm_.
1. Set _obj_.[[WrappedTargetFunction]] to _targetFunction_.
1. Return _obj_.
</emu-alg>
</emu-clause>
</emu-clause>

<emu-clause id="sec-realm-objects">
<h1>Realm Objects</h1>
<emu-clause id="sec-realm-abstracts">
<h1>Realm Abstract Operations</h1>

<emu-clause id="sec-performrealmeval" aoid="PerformRealmEval">
<h1>PerformRealmEval ( _sourceText_, _callerRealm_, _evalRealm_ )</h1>
<emu-alg>
1. Assert: Type(_sourceText_) is String.
1. Assert: _callerRealm_ is a Realm Record.
1. Assert: _evalRealm_ is a Realm Record.
1. Perform ? HostEnsureCanCompileStrings(_callerRealm_, _evalRealm_).
1. Let _inFunction_ be *false*.
1. Let _inMethod_ be *false*.
1. Let _inDerivedConstructor_ be *false*.
1. Perform the following substeps in an implementation-defined order, possibly interleaving parsing and error detection:
1. Let _script_ be ParseText(! StringToCodePoints(_sourceText_), |Script|).
1. If _script_ is a List of errors, throw a *SyntaxError* exception.
1. If _script_ Contains |ScriptBody| is *false*, return *undefined*.
1. Let _body_ be the |ScriptBody| of _script_.
1. If _inFunction_ is *false*, and _body_ Contains |NewTarget|, throw a *SyntaxError* exception.
1. If _inMethod_ is *false*, and _body_ Contains |SuperProperty|, throw a *SyntaxError* exception.
1. If _inDerivedConstructor_ is *false*, and _body_ Contains |SuperCall|, throw a *SyntaxError* exception.
1. Let _strictEval_ be IsStrict of _script_.
1. Let _runningContext_ be the running execution context.
1. Let _lexEnv_ be NewDeclarativeEnvironment(_evalRealm_.[[GlobalEnv]]).
1. Let _varEnv_ be _evalRealm_.[[GlobalEnv]].
1. If _strictEval_ is *true*, set _varEnv_ to _lexEnv_.
1. If _runningContext_ is not already suspended, suspend _runningContext_.
1. Let _evalContext_ be a new ECMAScript code execution context.
1. Set _evalContext_'s Function to *null*.
1. Set _evalContext_'s Realm to _evalRealm_.
1. Set _evalContext_'s ScriptOrModule to *null*.
1. Set _evalContext_'s VariableEnvironment to _varEnv_.
1. Set _evalContext_'s LexicalEnvironment to _lexEnv_.
1. Push _evalContext_ onto the execution context stack; _evalContext_ is now the running execution context.
1. Let _result_ be EvalDeclarationInstantiation(_body_, _varEnv_, _lexEnv_, _strictEval_).
1. If _result_.[[Type]] is ~normal~, then
1. Set _result_ to the result of evaluating _body_.
1. Suspend _evalContext_ and remove it from the execution context stack.
1. Resume the context that is now on the top of the execution context stack as the running execution context.
1. If _result_.[[Type]] is not ~normal~, throw a newly created TypeError object associate to the _callerRealm_.
1. Return ? GetWrappedValue(_callerRealm_, _result_.[[Value]]).
</emu-alg>
<emu-note type=editor>
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.
</emu-note>
</emu-clause>

<emu-clause id="sec-performrealmimportbinding" aoid="PerformRealmImportBinding">
<h1>PerformRealmImportBinding ( _specifierString_, _exportNameString_, _callerRealm_, _evalRealm_, _evalContext_ )</h1>
<emu-alg>
1. Assert: Type(_specifierString_) is String.
1. Assert: Type(_exportNameString_) is String.
1. Assert: _callerRealm_ is a Realm Record.
1. Assert: _evalRealm_ is a Realm Record.
1. Let _promiseCapability_ be ! NewPromiseCapability(%Promise%).
1. IfAbruptRejectPromise(_specifierString_, _promiseCapability_).
1. Let _runningContext_ be the running execution context.
1. If _runningContext_ is not already suspended, suspend _runningContext_.
1. Push _evalContext_ onto the execution context stack; _evalContext_ is now the running execution context.
1. Perform ! HostImportModuleBindingDynamically(_callerRealm_, _evalRealm_, _specifierString_, _exportNameString_, _promiseCapability_).
1. Suspend _evalContext_ and remove it from the execution context stack.
1. Resume the context that is now on the top of the execution context stack as the running execution context.
1. Return _promiseCapability_.[[Promise]].
</emu-alg>

<emu-note type=editor>
The Realm's Execution Context is passed as a parameter _evalContext_. An alternative phrasing would be to create an extra execution context around the call to HostImportModuleBindingDynamically in order to execute within the appropriate Realm--the host can reference the current Realm to figure out how the import should work, similar to PerformRealmEval, which could be revisited when merging into the main specification.
</emu-note>
</emu-clause>

<emu-clause id="sec-getwrappedvalue" aoid="GetWrappedValue">
<h1>GetWrappedValue ( _callerRealm_, _value_ )</h1>
<emu-alg>
1. Assert: _callerRealm_ is a Realm Record.
1. If Type(_value_) is Object, then
1. If IsCallable(_value_) is *false*, throw a TypeError exception.
1. Return ? WrappedFunctionCreate(_callerRealm_, _value_).
1. Return _value_.
</emu-alg>
</emu-clause>
</emu-clause>

<emu-clause id="sec-realm-constructor">
<h1>The Realm Constructor</h1>
Expand Down Expand Up @@ -92,30 +266,42 @@ <h1>Properties of the Realm Prototype Object</h1>
<li>does not have a [[Realm]] or any other of the internal slots that are specific to _Realm_ instance objects.</li>
</ul>

<emu-clause id="sec-realm.prototype.import">
<h1>Realm.prototype.import ( _specifier_ )</h1>
<emu-clause id="sec-realm.prototype.eval">
<h1>Realm.prototype.evaluate ( _sourceText_ )</h1>

<p>Synchronously execute a top-level script. The _sourceText_ is interpreted as a Script and evaluated with this bound to the realm's global object.</p>

<emu-alg>
1. Let _O_ be *this* value.
1. Perform ? ValidateRealmObject(_O_).
1. If Type(_sourceText_) is not String, throw a *TypeError* exception.
1. Let _callerRealm_ be the current Realm Record.
1. Let _evalRealm_ be _O_.[[Realm]].
1. Return ? PerformRealmEval(_sourceText_, _callerRealm_, _evalRealm_).
</emu-alg>

<emu-note>
Extensible web: This is the dynamic equivalent of a &lt;script&gt; in HTML.
</emu-note>
</emu-clause>

<emu-clause id="sec-realm.prototype.importBinding">
<h1>Realm.prototype.importBinding ( _specifier_, _exportName_ )</h1>
<p>The following steps are performed:</p>
<emu-alg>
1. Let _O_ be *this* value.
1. Perform ? ValidateRealmObject(_O_).
1. Let _referencingScriptOrModule_ be *null*.
1. Let _specifierString_ be ? ToString(_specifier_).
1. Let _promiseCapability_ be ! NewPromiseCapability(%Promise%).
1. IfAbruptRejectPromise(_specifierString_, _promiseCapability_).
1. Let _callerContext_ be the running execution context.
1. Push _O_.[[ExecutionContext]] onto the execution context stack; _O_.[[ExecutionContext]] is now the running execution context.
1. Perform ! HostImportModuleDynamically(_referencingScriptOrModule_, _specifierString_, _promiseCapability_).
1. Remove _O_.[[ExecutionContext]] from the execution context stack and restore _callerContext_ as the running execution context.
1. Return _promiseCapability_.[[Promise]].
1. Let _exportNameString_ be ? ToString(_exportName_).
1. Let _callerRealm_ be the current Realm Record.
1. Let _evalRealm_ be _O_.[[Realm]].
1. Let _evalContext_ be _O_.[[ExecutionContext]].
1. Return ? PerformRealmImportBinding(_specifierString_, _exportNameString_, _callerRealm_, _evalRealm_, _evalContext_).
</emu-alg>

<emu-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).
</emu-note>

<emu-note type=editor>
An extra execution context is created around the call to HostImportModuleDynamically in order to execute within the appropriate Realm--the host can reference the current Realm to figure out how the import should work. An alternative phrasing would be to pass the Realm as a parameter to HostImportModuleDynamically, which could be revisited when merging into the main specification.
</emu-note>
</emu-clause>

<emu-clause id="sec-validaterealmobject">
Expand All @@ -128,17 +314,6 @@ <h1>ValidateRealmObject( _argument_ )</h1>
</emu-alg>
</emu-clause>

<emu-clause id="sec-realm.prototype.globalthis">
<h1>get Realm.prototype.globalThis</h1>
<p>Realm.prototype.globalThis is an accessor property whose set accessor function is *undefined*. Its get accessor function performs the following steps:</p>

<emu-alg>
1. Let _O_ be *this* value.
1. Perform ? ValidateRealmObject(_O_).
1. Return _O_.[[Realm]].[[GlobalEnv]].[[GlobalThisValue]].
</emu-alg>
</emu-clause>

<emu-clause id="sec-realm.prototype-@@tostringtag">
<h1>Realm.prototype [ @@toStringTag ]</h1>
<p>The initial value of the @@toStringTag property is the String value "Realm".</p>
Expand Down Expand Up @@ -187,6 +362,34 @@ <h1>Runtime Semantics: HostInitializeSyntheticRealm ( _realm_ )</h1>
global object.
</p>
</emu-clause>

<emu-clause id="sec-hostimportmodulebindingdynamically" aoid="HostImportModuleBindingDynamically">
<h1>HostImportModuleBindingDynamically (_callerRealm_, _evalRealm_, _specifier_, _exportName_, _promiseCapability_ )</h1>
<p>The host-defined abstract operation HostImportModuleBindingDynamically takes arguments _callerRealm_ (a Realm Record), _evalRealm_ (a Realm Record), _specifier_ (a |ModuleSpecifier| String), _exportName_ (a |IdentifierName| String) and _promiseCapability_ (a PromiseCapability Record). It performs any necessary setup work in order to make available the module corresponding to _specifier_ occurring within the context of the script or module represented by _referencingScriptOrModule_. _referencingScriptOrModule_ is *null*. It then performs FinishDynamicImport to finish the dynamic import process.</p>
<p>The implementation of HostImportModuleBindingDynamically must conform with the implementation of HostImportModuleDynamically first and foremost, second, it should conform with the following:</p>
<li>
The host environment must conform to one of the two following sets of requirements:
<dl>
<dt>Success path</dt>

<dd>
<ul>
<li>The completion value must be the wrapped value exported value for the _exportName_ associated to the Module Namespace Object for the _callerRealm_.</li>
</ul>
</dd>

<dt>Failure path</dt>

<dd>
<ul>
<li>At some future time, the Module Namespace Object does not contain the _exportName_ as part of the ExportNames, with the abrupt completion representing the cause of failure for the _callerRealm_.</li>
</ul>
</dd>
</dl>
</li>
</emu-clause>
</emu-clause>

</emu-clause>
</body>
</html>

0 comments on commit dc79d98

Please sign in to comment.