From 1547cde04f219729148255e7ab742f5796c843d2 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Mon, 23 Apr 2018 15:01:01 -0400 Subject: [PATCH 1/3] Small style tweak in ModuleExecution It was always pretty silly to use Completion() here, so in the new version, let's not do that. --- spec.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spec.html b/spec.html index 4c2111e..eacc7ca 100644 --- a/spec.html +++ b/spec.html @@ -107,7 +107,8 @@

ModuleExecution( _module_ )

1. Let _result_ be the result of evaluating _module_.[[ECMAScriptCode]]. 1. Suspend _moduleCxt_ 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 Completion(_result__promiseCapability_.[[Promise]]). + 1. Return Completion(_result_). + 1. Return _promiseCapability_.[[Promise]]. From ec0135bf6d410ba3768977e869ff1aeefd4fb7b4 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Mon, 23 Apr 2018 15:02:44 -0400 Subject: [PATCH 2/3] Propogate promise-ness to InnerModuleEvaluation Now InnerModuleEvaluation returns a promise for the index, instead of the index itself. It also awaits recursive invocations of itself, as well as the invocation of ModuleExecution. This implements variant A (sequential, blocking execution) since it is easier to write spec text for; we can in the future easily (?) convert to variant B by making local modifications to InnerModuleEvaluation's child-evaluation loop. --- spec.html | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/spec.html b/spec.html index eacc7ca..1127ec8 100644 --- a/spec.html +++ b/spec.html @@ -48,12 +48,20 @@

InnerModuleEvaluation( _module_, _stack_, _index_ )

This abstract operation performs the following steps:

+ 1. Let _promiseCapability_ be ! NewPromiseCapability(%Promise%). 1. If _module_ is not a Source Text Module Record, then - 1. Perform ? _module_.Evaluate(). - 1. Return _index_. + 1. Perform _module_.Evaluate(). + 1. Return _index_. + 1. Let _evaluateResult_ be Await(! _module_.Evaluate()) + 1. If _evaluateResult_ is an abrupt completion, perform ! Call(_promiseCapability_.[[Reject]], *undefined*, «_evaluateResult_.[[Value]]»). + 1. Otherwise, perform ! Call(_promiseCapability_.[[Resolve]], *undefined*, «_index_»). + 1. Return _promiseCapability_.[[Promise]] 1. If _module_.[[Status]] is `"evaluated"`, then - 1. If _module_.[[EvaluationError]] is *undefined*, return _index_. - 1. Otherwise return _module_.[[EvaluationError]]. + 1. If _module_.[[EvaluationError]] is *undefined*, return _index_. + 1. Otherwise return _module_.[[EvaluationError]]. + 1. If _module_.[[EvaluationError]] is an abrupt completion, perform ! Call(_promiseCapability_.[[Reject]], *undefined*, «_module_.[[EvaluationError]].[[Value]]»). + 1. Otherwise, perform ! Call(_promiseCapability_.[[Resolve]], *undefined*, «_index_»). + 1. Return _promiseCapability_.[[Promise]] 1. If _module_.[[Status]] is `"evaluating"`, return _index_. 1. Assert: _module_.[[Status]] is `"instantiated"`. 1. Set _module_.[[Status]] to `"evaluating"`. @@ -64,13 +72,17 @@

InnerModuleEvaluation( _module_, _stack_, _index_ )

1. For each String _required_ that is an element of _module_.[[RequestedModules]], do 1. Let _requiredModule_ be ! HostResolveImportedModule(_module_, _required_). 1. NOTE: Instantiate must be completed successfully prior to invoking this method, so every requested module is guaranteed to resolve successfully. - 1. Set _index_ to ? InnerModuleEvaluation(_requiredModule_, _stack_, _index_). + 1. Set _index_ to ? InnerModuleEvaluation(_requiredModule_, _stack_, _index_). + 1. Let _childResult_ be Await(! InnerModuleEvaluation(_requiredModule_, _stack_, _index_). + 1. IfAbruptRejectPromise(_childResult_, _promiseCapability_). 1. Assert: _requiredModule_.[[Status]] is either `"evaluating"` or `"evaluated"`. 1. Assert: _requiredModule_.[[Status]] is `"evaluating"` if and only if _requiredModule_ is in _stack_. 1. If _requiredModule_.[[Status]] is `"evaluating"`, then 1. Assert: _requiredModule_ is a Source Text Module Record. 1. Set _module_.[[DFSAncestorIndex]] to min(_module_.[[DFSAncestorIndex]], _requiredModule_.[[DFSAncestorIndex]]). - 1. Perform ? ModuleExecution(_module_). + 1. Perform ? ModuleExecution(_module_). + 1. Let _executionResult_ be Await(! ModuleExecution(_module_)). + 1. IfAbruptRejectPromise(_executionResult_, _promiseCapability_). 1. Assert: _module_ occurs exactly once in _stack_. 1. Assert: _module_.[[DFSAncestorIndex]] is less than or equal to _module_.[[DFSIndex]]. 1. If _module_.[[DFSAncestorIndex]] equals _module_.[[DFSIndex]], then @@ -80,7 +92,9 @@

InnerModuleEvaluation( _module_, _stack_, _index_ )

1. Remove the last element of _stack_. 1. Set _requiredModule_.[[Status]] to `"evaluated"`. 1. If _requiredModule_ and _module_ are the same Module Record, set _done_ to *true*. - 1. Return _index_. + 1. Return _index_. + 1. Perform ! Call(_promiseCapability_.[[Resolve]], *undefined*, «_index_»). + 1. Return _promiseCapability_.[[Promise]]
From de599b0f09dceef829b6ffa5bbe2a17e9d674fd1 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Mon, 23 Apr 2018 15:12:12 -0400 Subject: [PATCH 3/3] Propagate the promise-ness to stmr.Evaluate() Now all Source Text Module Records' Evaluate() concrete methods return promises, bubbling up the async-ness from InnerModuleEvaluation. --- spec.html | 182 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 108 insertions(+), 74 deletions(-) diff --git a/spec.html b/spec.html index 1127ec8..338d690 100644 --- a/spec.html +++ b/spec.html @@ -40,93 +40,127 @@

AsyncBlockStart ( _promiseCapability_, _asyncBody_, _asyncContext_ ) - -

InnerModuleEvaluation( _module_, _stack_, _index_ )

+ +

Evaluate( ) Concrete Method

-

The InnerModuleEvaluation abstract operation is used by Evaluate to perform the actual evaluation process for the Source Text Module Record _module_, as well as recursively on all other modules in the dependency graph. The _stack_ and _index_ parameters, as well as _module_'s [[DFSIndex]] and [[DFSAncestoreIndex]] fields, are used the same way as in InnerModuleInstantiation.

+

The Evaluate concrete method of a Source Text Module Record implements the corresponding Module Record abstract method.

+

By the time the promise returned by Evaluate settles, Evaluate transitions this module's [[Status]] from `"instantiated"` to `"evaluated"`.

-

This abstract operation performs the following steps:

+

If execution results in an exception, that exception is recorded in the [[EvaluationError]] field and rethrown by future invocations of Evaluate.

+ +

If execution results in a rejected promise, the promise's rejection reason is recorded in the [[EvaluationError]] field. Future invocations of Evaluate will then return a new promise rejected with that same rejection reason.

+ +

This abstract method performs the following steps (most of the work is done by the auxiliary function InnerModuleEvaluation):

+ 1. Let _module_ be this Source Text Module Record. + 1. Assert: _module_.[[Status]] is `"instantiated"` or `"evaluated"`. 1. Let _promiseCapability_ be ! NewPromiseCapability(%Promise%). - 1. If _module_ is not a Source Text Module Record, then - 1. Perform _module_.Evaluate(). + 1. Let _stack_ be a new empty List. + 1. Let _result_ be Await(InnerModuleEvaluation(_module_, _stack_, 0)). + 1. If _result_ is an abrupt completion, then + 1. For each module _m_ in _stack_, do + 1. Assert: _m_.[[Status]] is `"evaluating"`. + 1. Set _m_.[[Status]] to `"evaluated"`. + 1. Set _m_.[[EvaluationError]] to _result_. + 1. Assert: _module_.[[Status]] is `"evaluated"` and _module_.[[EvaluationError]] is _result_. + 1. Return _result_. + 1. Perform ! Call(_promiseCapability_.[[Reject]], *undefined*, «_result_.[[Value]]»). + 1. Return _promiseCapability_.[[Promise]]. + 1. Assert: _module_.[[Status]] is `"evaluated"` and _module_.[[EvaluationError]] is *undefined*. + 1. Assert: _stack_ is empty. + 1. Return *undefined*. + 1. Perform ! Call(_promiseCapability_.[[Resolve]], *undefined*, «*undefined*»). + 1. Return _promiseCapability_.[[Promise]]. + + + +

InnerModuleEvaluation( _module_, _stack_, _index_ )

+ +

The InnerModuleEvaluation abstract operation is used by Evaluate to perform the actual evaluation process for the Source Text Module Record _module_, as well as recursively on all other modules in the dependency graph. The _stack_ and _index_ parameters, as well as _module_'s [[DFSIndex]] and [[DFSAncestoreIndex]] fields, are used the same way as in InnerModuleInstantiation.

+ +

This abstract operation performs the following steps:

+ + + 1. Let _promiseCapability_ be ! NewPromiseCapability(%Promise%). + 1. If _module_ is not a Source Text Module Record, then + 1. Perform _module_.Evaluate(). + 1. Return _index_. + 1. Let _evaluateResult_ be Await(! _module_.Evaluate()) + 1. If _evaluateResult_ is an abrupt completion, perform ! Call(_promiseCapability_.[[Reject]], *undefined*, «_evaluateResult_.[[Value]]»). + 1. Otherwise, perform ! Call(_promiseCapability_.[[Resolve]], *undefined*, «_index_»). + 1. Return _promiseCapability_.[[Promise]]. + 1. If _module_.[[Status]] is `"evaluated"`, then + 1. If _module_.[[EvaluationError]] is *undefined*, return _index_. + 1. Otherwise return _module_.[[EvaluationError]]. + 1. If _module_.[[EvaluationError]] is an abrupt completion, perform ! Call(_promiseCapability_.[[Reject]], *undefined*, «_module_.[[EvaluationError]].[[Value]]»). + 1. Otherwise, perform ! Call(_promiseCapability_.[[Resolve]], *undefined*, «_index_»). + 1. Return _promiseCapability_.[[Promise]] + 1. If _module_.[[Status]] is `"evaluating"`, return _index_. + 1. Assert: _module_.[[Status]] is `"instantiated"`. + 1. Set _module_.[[Status]] to `"evaluating"`. + 1. Set _module_.[[DFSIndex]] to _index_. + 1. Set _module_.[[DFSAncestorIndex]] to _index_. + 1. Set _index_ to _index_ + 1. + 1. Append _module_ to _stack_. + 1. For each String _required_ that is an element of _module_.[[RequestedModules]], do + 1. Let _requiredModule_ be ! HostResolveImportedModule(_module_, _required_). + 1. NOTE: Instantiate must be completed successfully prior to invoking this method, so every requested module is guaranteed to resolve successfully. + 1. Set _index_ to ? InnerModuleEvaluation(_requiredModule_, _stack_, _index_). + 1. Let _childResult_ be Await(! InnerModuleEvaluation(_requiredModule_, _stack_, _index_). + 1. IfAbruptRejectPromise(_childResult_, _promiseCapability_). + 1. Assert: _requiredModule_.[[Status]] is either `"evaluating"` or `"evaluated"`. + 1. Assert: _requiredModule_.[[Status]] is `"evaluating"` if and only if _requiredModule_ is in _stack_. + 1. If _requiredModule_.[[Status]] is `"evaluating"`, then + 1. Assert: _requiredModule_ is a Source Text Module Record. + 1. Set _module_.[[DFSAncestorIndex]] to min(_module_.[[DFSAncestorIndex]], _requiredModule_.[[DFSAncestorIndex]]). + 1. Perform ? ModuleExecution(_module_). + 1. Let _executionResult_ be Await(! ModuleExecution(_module_)). + 1. IfAbruptRejectPromise(_executionResult_, _promiseCapability_). + 1. Assert: _module_ occurs exactly once in _stack_. + 1. Assert: _module_.[[DFSAncestorIndex]] is less than or equal to _module_.[[DFSIndex]]. + 1. If _module_.[[DFSAncestorIndex]] equals _module_.[[DFSIndex]], then + 1. Let _done_ be *false*. + 1. Repeat, while _done_ is *false*, + 1. Let _requiredModule_ be the last element in _stack_. + 1. Remove the last element of _stack_. + 1. Set _requiredModule_.[[Status]] to `"evaluated"`. + 1. If _requiredModule_ and _module_ are the same Module Record, set _done_ to *true*. 1. Return _index_. - 1. Let _evaluateResult_ be Await(! _module_.Evaluate()) - 1. If _evaluateResult_ is an abrupt completion, perform ! Call(_promiseCapability_.[[Reject]], *undefined*, «_evaluateResult_.[[Value]]»). - 1. Otherwise, perform ! Call(_promiseCapability_.[[Resolve]], *undefined*, «_index_»). + 1. Perform ! Call(_promiseCapability_.[[Resolve]], *undefined*, «_index_»). 1. Return _promiseCapability_.[[Promise]] - 1. If _module_.[[Status]] is `"evaluated"`, then - 1. If _module_.[[EvaluationError]] is *undefined*, return _index_. - 1. Otherwise return _module_.[[EvaluationError]]. - 1. If _module_.[[EvaluationError]] is an abrupt completion, perform ! Call(_promiseCapability_.[[Reject]], *undefined*, «_module_.[[EvaluationError]].[[Value]]»). - 1. Otherwise, perform ! Call(_promiseCapability_.[[Resolve]], *undefined*, «_index_»). - 1. Return _promiseCapability_.[[Promise]] - 1. If _module_.[[Status]] is `"evaluating"`, return _index_. - 1. Assert: _module_.[[Status]] is `"instantiated"`. - 1. Set _module_.[[Status]] to `"evaluating"`. - 1. Set _module_.[[DFSIndex]] to _index_. - 1. Set _module_.[[DFSAncestorIndex]] to _index_. - 1. Set _index_ to _index_ + 1. - 1. Append _module_ to _stack_. - 1. For each String _required_ that is an element of _module_.[[RequestedModules]], do - 1. Let _requiredModule_ be ! HostResolveImportedModule(_module_, _required_). - 1. NOTE: Instantiate must be completed successfully prior to invoking this method, so every requested module is guaranteed to resolve successfully. - 1. Set _index_ to ? InnerModuleEvaluation(_requiredModule_, _stack_, _index_). - 1. Let _childResult_ be Await(! InnerModuleEvaluation(_requiredModule_, _stack_, _index_). - 1. IfAbruptRejectPromise(_childResult_, _promiseCapability_). - 1. Assert: _requiredModule_.[[Status]] is either `"evaluating"` or `"evaluated"`. - 1. Assert: _requiredModule_.[[Status]] is `"evaluating"` if and only if _requiredModule_ is in _stack_. - 1. If _requiredModule_.[[Status]] is `"evaluating"`, then - 1. Assert: _requiredModule_ is a Source Text Module Record. - 1. Set _module_.[[DFSAncestorIndex]] to min(_module_.[[DFSAncestorIndex]], _requiredModule_.[[DFSAncestorIndex]]). - 1. Perform ? ModuleExecution(_module_). - 1. Let _executionResult_ be Await(! ModuleExecution(_module_)). - 1. IfAbruptRejectPromise(_executionResult_, _promiseCapability_). - 1. Assert: _module_ occurs exactly once in _stack_. - 1. Assert: _module_.[[DFSAncestorIndex]] is less than or equal to _module_.[[DFSIndex]]. - 1. If _module_.[[DFSAncestorIndex]] equals _module_.[[DFSIndex]], then - 1. Let _done_ be *false*. - 1. Repeat, while _done_ is *false*, - 1. Let _requiredModule_ be the last element in _stack_. - 1. Remove the last element of _stack_. - 1. Set _requiredModule_.[[Status]] to `"evaluated"`. - 1. If _requiredModule_ and _module_ are the same Module Record, set _done_ to *true*. - 1. Return _index_. - 1. Perform ! Call(_promiseCapability_.[[Resolve]], *undefined*, «_index_»). - 1. Return _promiseCapability_.[[Promise]] - -
+ +
- -

ModuleExecution( _module_ )

+ +

ModuleExecution( _module_ )

-

The ModuleExecution abstract operation is used by InnerModuleEvaluation to initialize the execution context of the module and evaluate the module's code within it.

+

The ModuleExecution abstract operation is used by InnerModuleEvaluation to initialize the execution context of the module and evaluate the module's code within it.

-

This abstract operation performs the following steps:

+

This abstract operation performs the following steps:

- - 1. Let _moduleCxt_ be a new ECMAScript code execution context. - 1. Set the Function of _moduleCxt_ to *null*. - 1. Assert: _module_.[[Realm]] is not *undefined*. - 1. Set the Realm of _moduleCxt_ to _module_.[[Realm]]. - 1. Set the ScriptOrModule of _moduleCxt_ to _module_. - 1. Assert: _module_ has been linked and declarations in its module environment have been instantiated. - 1. Set the VariableEnvironment of _moduleCxt_ to _module_.[[Environment]]. - 1. Set the LexicalEnvironment of _moduleCxt_ to _module_.[[Environment]]. - 1. Let _promiseCapability_ be ! NewPromiseCapability(%Promise%). - 1. Suspend the currently running execution context. - 1. Perform ! AsyncBlockStart(_promiseCapability_, _module_.[[ECMAScriptCode]], _moduleCxt_). - 1. Push _moduleCxt_ on to the execution context stack; _moduleCxt_ is now the running execution context. - 1. Let _result_ be the result of evaluating _module_.[[ECMAScriptCode]]. - 1. Suspend _moduleCxt_ 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 Completion(_result_). - 1. Return _promiseCapability_.[[Promise]]. - + + 1. Let _moduleCxt_ be a new ECMAScript code execution context. + 1. Set the Function of _moduleCxt_ to *null*. + 1. Assert: _module_.[[Realm]] is not *undefined*. + 1. Set the Realm of _moduleCxt_ to _module_.[[Realm]]. + 1. Set the ScriptOrModule of _moduleCxt_ to _module_. + 1. Assert: _module_ has been linked and declarations in its module environment have been instantiated. + 1. Set the VariableEnvironment of _moduleCxt_ to _module_.[[Environment]]. + 1. Set the LexicalEnvironment of _moduleCxt_ to _module_.[[Environment]]. + 1. Let _promiseCapability_ be ! NewPromiseCapability(%Promise%). + 1. Suspend the currently running execution context. + 1. Perform ! AsyncBlockStart(_promiseCapability_, _module_.[[ECMAScriptCode]], _moduleCxt_). + 1. Push _moduleCxt_ on to the execution context stack; _moduleCxt_ is now the running execution context. + 1. Let _result_ be the result of evaluating _module_.[[ECMAScriptCode]]. + 1. Suspend _moduleCxt_ 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 Completion(_result_). + 1. Return _promiseCapability_.[[Promise]]. + +
-

AsyncFunctionStart ( _promiseCapability_, _asyncFunctionBody_ )