From 7edbc7fd0ffa80a46eec12f3ae8b6949bd0fb542 Mon Sep 17 00:00:00 2001 From: codehag Date: Sun, 15 Aug 2021 12:44:16 -0700 Subject: [PATCH] Normative: Top Level Await (#2408) Co-authored-by: codehag Co-authored-by: Michael Dyck Co-authored-by: Kevin Gibbons --- img/module-graph-cycle-async.svg | 69 +++ spec.html | 791 ++++++++++++++++++++++++++++--- 2 files changed, 785 insertions(+), 75 deletions(-) create mode 100644 img/module-graph-cycle-async.svg diff --git a/img/module-graph-cycle-async.svg b/img/module-graph-cycle-async.svg new file mode 100644 index 0000000000..d9da548aa3 --- /dev/null +++ b/img/module-graph-cycle-async.svg @@ -0,0 +1,69 @@ + + + + + + + + + + +A + + +B + + +C + + +D + + +E + + + + + + + + + + diff --git a/spec.html b/spec.html index 2236398a5d..7c6fbee6d9 100644 --- a/spec.html +++ b/spec.html @@ -41,6 +41,16 @@ width: 100%; font-size: 80%; } + + .module-overflow { + overflow-y: scroll; + display: block; + } + + .module-overflow-note { + overflow-y: scroll; + } + @@ -10943,7 +10953,7 @@

1. If the binding for _N_ is an indirect binding, then 1. Let _M_ and _N2_ be the indirection values provided when this binding for _N_ was created. 1. Let _targetEnv_ be _M_.[[Environment]]. - 1. If _targetEnv_ is *undefined*, throw a *ReferenceError* exception. + 1. If _targetEnv_ is ~empty~, throw a *ReferenceError* exception. 1. Return ? _targetEnv_.GetBindingValue(_N2_, *true*). 1. If the binding for _N_ in _envRec_ is an uninitialized binding, throw a *ReferenceError* exception. 1. Return the value currently bound to _N_ in _envRec_. @@ -14607,7 +14617,7 @@

1. If _binding_.[[BindingName]] is *"\*namespace\*"*, then 1. Return ? GetModuleNamespace(_targetModule_). 1. Let _targetEnv_ be _targetModule_.[[Environment]]. - 1. If _targetEnv_ is *undefined*, throw a *ReferenceError* exception. + 1. If _targetEnv_ is ~empty~, throw a *ReferenceError* exception. 1. Return ? _targetEnv_.GetBindingValue(_binding_.[[BindingName]], *true*). @@ -14678,7 +14688,7 @@

1. Assert: _module_ is a Module Record. - 1. Assert: _module_.[[Namespace]] is *undefined*. + 1. Assert: _module_.[[Namespace]] is ~empty~. 1. Assert: _exports_ is a List of String values. 1. Let _internalSlotsList_ be the internal slots listed in . 1. Let _M_ be ! MakeBasicObject(_internalSlotsList_). @@ -24254,12 +24264,13 @@

Syntax

-

`await` is parsed as an |AwaitExpression| when the [Await] parameter is present. The [Await] parameter is present in the following contexts:

+

`await` is parsed as a keyword of an |AwaitExpression| when the [Await] parameter is present. The [Await] parameter is present in the top level of the following contexts, although the parameter may be absent in some contexts depending on the nonterminals, such as |FunctionBody|:

  • In an |AsyncFunctionBody|.
  • In the |FormalParameters| of an |AsyncFunctionDeclaration|, |AsyncFunctionExpression|, |AsyncGeneratorDeclaration|, or |AsyncGeneratorExpression|. |AwaitExpression| in this position is a Syntax error via static semantics.
  • +
  • In a |Module|.
-

When |Module| is the syntactic goal symbol and the [Await] parameter is absent, `await` is parsed as a keyword and will be a Syntax error. When |Script| is the syntactic goal symbol, `await` may be parsed as an identifier when the [Await] parameter is absent. This includes the following contexts:

+

When |Script| is the syntactic goal symbol, `await` may be parsed as an identifier when the [Await] parameter is absent. This includes the following contexts:

  • Anywhere outside of an |AsyncFunctionBody| or |FormalParameters| of an |AsyncFunctionDeclaration|, |AsyncFunctionExpression|, |AsyncGeneratorDeclaration|, or |AsyncGeneratorExpression|.
  • In the |BindingIdentifier| of a |FunctionExpression|, |GeneratorExpression|, or |AsyncGeneratorExpression|.
  • @@ -25181,7 +25192,7 @@

    Syntax

    ModuleItem : ImportDeclaration ExportDeclaration - StatementListItem[~Yield, ~Await, ~Return] + StatementListItem[~Yield, +Await, ~Return] @@ -25320,10 +25331,10 @@

    Abstract Module Records

    [[Realm]] - Realm Record | *undefined* + Realm Record - The Realm within which this module was created. *undefined* if not yet assigned. + The Realm within which this module was created. @@ -25331,7 +25342,7 @@

    Abstract Module Records

    [[Environment]] - module Environment Record | *undefined* + module Environment Record | ~empty~ The Environment Record containing the top level bindings for this module. This field is set when the module is linked. @@ -25342,10 +25353,10 @@

    Abstract Module Records

    [[Namespace]] - Object | *undefined* + Object | ~empty~ - The Module Namespace Object () if one has been created for this module. Otherwise *undefined*. + The Module Namespace Object () if one has been created for this module. @@ -25403,7 +25414,7 @@

    Abstract Module Records

    Evaluate() -

    If this module has already been evaluated successfully, return *undefined*; if it has already been evaluated unsuccessfully, throw the exception that was produced. Otherwise, transitively evaluate all module dependencies of this module and then evaluate this module.

    +

    Returns a promise for the evaluation of this module and its dependencies, resolving on successful evaluation or if it has already been evaluated successfully, and rejecting for an evaluation error or if it has already been evaluated unsuccessfully. If the promise is rejected, hosts are expected to handle the promise rejection and rethrow the evaluation error.

    Link must have completed successfully prior to invoking this method.

    @@ -25435,10 +25446,10 @@

    Cyclic Module Records

    [[Status]] - ~unlinked~ | ~linking~ | ~linked~ | ~evaluating~ | ~evaluated~ + ~unlinked~ | ~linking~ | ~linked~ | ~evaluating~ | ~evaluating-async~ | ~evaluated~ - Initially ~unlinked~. Transitions to ~linking~, ~linked~, ~evaluating~, ~evaluated~ (in that order) as the module progresses throughout its lifecycle. + Initially ~unlinked~. Transitions to ~linking~, ~linked~, ~evaluating~, possibly ~evaluating-async~, ~evaluated~ (in that order) as the module progresses throughout its lifecycle. ~evaluating-async~ indicates this module is queued to execute on completion of its asynchronous dependencies or it is a module whose [[HasTLA]] field is *true* that has been executed and is pending top-level completion. @@ -25446,7 +25457,7 @@

    Cyclic Module Records

    [[EvaluationError]] - An abrupt completion | *undefined* + An abrupt completion | ~empty~ A completion of type ~throw~ representing the exception that occurred during evaluation. *undefined* if no exception occurred or if [[Status]] is not ~evaluated~. @@ -25457,11 +25468,10 @@

    Cyclic Module Records

    [[DFSIndex]] - Integer | *undefined* + Integer | ~empty~ - Auxiliary field used during Link and Evaluate only. - If [[Status]] is ~linking~ or ~evaluating~, this non-negative number records the point at which the module was first visited during the ongoing depth-first traversal of the dependency graph. + Auxiliary field used during Link and Evaluate only. If [[Status]] is ~linking~ or ~evaluating~, this non-negative number records the point at which the module was first visited during the depth-first traversal of the dependency graph. @@ -25469,7 +25479,7 @@

    Cyclic Module Records

    [[DFSAncestorIndex]] - Integer | *undefined* + Integer | ~empty~ Auxiliary field used during Link and Evaluate only. If [[Status]] is ~linking~ or ~evaluating~, this is either the module's own [[DFSIndex]] or that of an "earlier" module in the same strongly connected component. @@ -25486,6 +25496,72 @@

    Cyclic Module Records

    A List of all the |ModuleSpecifier| strings used by the module represented by this record to request the importation of a module. The List is source code occurrence ordered. + + + [[CycleRoot]] + + + Cyclic Module Record | ~empty~ + + + The first visited module of the cycle, the root DFS ancestor of the strongly connected component. For a module not in a cycle this would be the module itself. Once Evaluate has completed, a module's [[DFSAncestorIndex]] is equal to the [[DFSIndex]] of its [[CycleRoot]]. + + + + + [[HasTLA]] + + + Boolean + + + Whether this module is individually asynchronous (for example, if it's a Source Text Module Record containing a top-level await). Having an asynchronous dependency does not mean this field is *true*. This field must not change after the module is parsed. + + + + + [[AsyncEvaluation]] + + + Boolean + + + Whether this module is either itself asynchronous or has an asynchronous dependency. Note: The order in which this field is set is used to order queued executions, see . + + + + + [[TopLevelCapability]] + + + PromiseCapability Record | ~empty~ + + + If this module is the [[CycleRoot]] of some cycle, and Evaluate() was called on some module in that cycle, this field contains the PromiseCapability Record for that entire evaluation. It is used to settle the Promise object that is returned from the Evaluate() abstract method. This field will be ~empty~ for any dependencies of that module, unless a top-level Evaluate() has been initiated for some of those dependencies. + + + + + [[AsyncParentModules]] + + + List of Cyclic Module Records + + + If this module or a dependency has [[HasTLA]] *true*, and execution is in progress, this tracks the parent importers of this module for the top-level execution job. These parent modules will not start executing before this module has successfully completed execution. + + + + + [[PendingAsyncDependencies]] + + + Integer | ~empty~ + + + If this module has any asynchronous dependencies, this tracks the number of asynchronous dependency modules remaining to execute for this module. A module with asynchronous dependencies will be executed when this field reaches 0 and there are no execution errors. + + @@ -25511,10 +25587,10 @@

    Cyclic Module Records

    - ExecuteModule() + ExecuteModule( [ _promiseCapability_ ] ) - Evaluate the module's code within its execution context. + Evaluate the module's code within its execution context. If this module has *true* in [[HasTLA]], then a PromiseCapability Record is passed as an argument, and the method is expected to resolve or reject the given capability. In this case, the method must not throw an exception, but instead reject the PromiseCapability Record if necessary. @@ -25539,12 +25615,9 @@

    Link ( )

    1. For each Cyclic Module Record _m_ of _stack_, do 1. Assert: _m_.[[Status]] is ~linking~. 1. Set _m_.[[Status]] to ~unlinked~. - 1. Set _m_.[[Environment]] to *undefined*. - 1. Set _m_.[[DFSIndex]] to *undefined*. - 1. Set _m_.[[DFSAncestorIndex]] to *undefined*. 1. Assert: _module_.[[Status]] is ~unlinked~. 1. Return _result_. - 1. Assert: _module_.[[Status]] is ~linked~ or ~evaluated~. + 1. Assert: _module_.[[Status]] is ~linked~, ~evaluating-async~, or ~evaluated~. 1. Assert: _stack_ is empty. 1. Return *undefined*. @@ -25566,7 +25639,7 @@

    1. If _module_ is not a Cyclic Module Record, then 1. Perform ? _module_.Link(). 1. Return _index_. - 1. If _module_.[[Status]] is ~linking~, ~linked~, or ~evaluated~, then + 1. If _module_.[[Status]] is ~linking~, ~linked~, ~evaluating-async~, or ~evaluated~, then 1. Return _index_. 1. Assert: _module_.[[Status]] is ~unlinked~. 1. Set _module_.[[Status]] to ~linking~. @@ -25578,7 +25651,7 @@

    1. Let _requiredModule_ be ? HostResolveImportedModule(_module_, _required_). 1. Set _index_ to ? InnerModuleLinking(_requiredModule_, _stack_, _index_). 1. If _requiredModule_ is a Cyclic Module Record, then - 1. Assert: _requiredModule_.[[Status]] is either ~linking~, ~linked~, or ~evaluated~. + 1. Assert: _requiredModule_.[[Status]] is either ~linking~, ~linked~, ~evaluating-async~, or ~evaluated~. 1. Assert: _requiredModule_.[[Status]] is ~linking~ if and only if _requiredModule_ is in _stack_. 1. If _requiredModule_.[[Status]] is ~linking~, then 1. Set _module_.[[DFSAncestorIndex]] to min(_module_.[[DFSAncestorIndex]], _requiredModule_.[[DFSAncestorIndex]]). @@ -25605,24 +25678,35 @@

    Evaluate ( )

    a Cyclic Module Record _module_
    description
    -
    Evaluate transitions this module's [[Status]] from ~linked~ to ~evaluated~. If execution results in an exception, that exception is recorded in the [[EvaluationError]] field and rethrown by future invocations of Evaluate. (Most of the work is done by the auxiliary function InnerModuleEvaluation.)
    +
    Evaluate transitions this module's [[Status]] from ~linked~ to either ~evaluating-async~ or ~evaluated~. The first time it is called on a module in a given strongly connected component, Evaluate creates and returns a Promise which resolves when the module has finished evaluating. This Promise is stored in the [[TopLevelCapability]] field of the [[CycleRoot]] for the component. Future invocations of Evaluate on any module in the component return the same Promise. (Most of the work is done by the auxiliary function InnerModuleEvaluation.)
    1. Assert: This call to Evaluate is not happening at the same time as another call to Evaluate within the surrounding agent. - 1. Assert: _module_.[[Status]] is ~linked~ or ~evaluated~. + 1. Assert: _module_.[[Status]] is ~linked~, ~evaluating-async~, or ~evaluated~. + 1. If _module_.[[Status]] is ~evaluating-async~ or ~evaluated~, set _module_ to _module_.[[CycleRoot]]. + 1. If _module_.[[TopLevelCapability]] is not ~empty~, then + 1. Return _module_.[[TopLevelCapability]].[[Promise]]. 1. Let _stack_ be a new empty List. + 1. Let _capability_ be ! NewPromiseCapability(%Promise%). + 1. Set _module_.[[TopLevelCapability]] to _capability_. 1. Let _result_ be InnerModuleEvaluation(_module_, _stack_, 0). 1. If _result_ is an abrupt completion, then 1. For each Cyclic Module Record _m_ of _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. Assert: _module_.[[Status]] is ~evaluated~ and _module_.[[EvaluationError]] is *undefined*. - 1. Assert: _stack_ is empty. - 1. Return *undefined*. + 1. Assert: _module_.[[Status]] is ~evaluated~. + 1. Assert: _module_.[[EvaluationError]] is _result_. + 1. Perform ! Call(_capability_.[[Reject]], *undefined*, « _result_.[[Value]] »). + 1. Else, + 1. Assert: _module_.[[Status]] is ~evaluating-async~ or ~evaluated~. + 1. Assert: _module_.[[EvaluationError]] is ~empty~. + 1. If _module_.[[AsyncEvaluation]] is *false*, then + 1. Assert: _module_.[[Status]] is ~evaluated~. + 1. Perform ! Call(_capability_.[[Resolve]], *undefined*, « *undefined* »). + 1. Assert: _stack_ is empty. + 1. Return _capability_.[[Promise]]. @@ -25640,16 +25724,20 @@

    1. If _module_ is not a Cyclic Module Record, then - 1. Perform ? _module_.Evaluate(). + 1. Let _promise_ be ! _module_.Evaluate(). + 1. Assert: _promise_.[[PromiseState]] is not ~pending~. + 1. If _promise_.[[PromiseState]] is ~rejected~, then + 1. Return ThrowCompletion(_promise_.[[PromiseResult]]). 1. Return _index_. - 1. If _module_.[[Status]] is ~evaluated~, then - 1. If _module_.[[EvaluationError]] is *undefined*, return _index_. + 1. If _module_.[[Status]] is ~evaluating-async~ or ~evaluated~, then + 1. If _module_.[[EvaluationError]] is ~empty~, return _index_. 1. Otherwise, return _module_.[[EvaluationError]]. 1. If _module_.[[Status]] is ~evaluating~, return _index_. 1. Assert: _module_.[[Status]] is ~linked~. 1. Set _module_.[[Status]] to ~evaluating~. 1. Set _module_.[[DFSIndex]] to _index_. 1. Set _module_.[[DFSAncestorIndex]] to _index_. + 1. Set _module_.[[PendingAsyncDependencies]] to 0. 1. Set _index_ to _index_ + 1. 1. Append _module_ to _stack_. 1. For each String _required_ of _module_.[[RequestedModules]], do @@ -25657,11 +25745,23 @@

    1. NOTE: Link 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. If _requiredModule_ is a Cyclic Module Record, then - 1. Assert: _requiredModule_.[[Status]] is either ~evaluating~ or ~evaluated~. + 1. Assert: _requiredModule_.[[Status]] is either ~evaluating~, ~evaluating-async~, or ~evaluated~. 1. Assert: _requiredModule_.[[Status]] is ~evaluating~ if and only if _requiredModule_ is in _stack_. 1. If _requiredModule_.[[Status]] is ~evaluating~, then 1. Set _module_.[[DFSAncestorIndex]] to min(_module_.[[DFSAncestorIndex]], _requiredModule_.[[DFSAncestorIndex]]). - 1. Perform ? _module_.ExecuteModule(). + 1. Else, + 1. Set _requiredModule_ to _requiredModule_.[[CycleRoot]]. + 1. Assert: _requiredModule_.[[Status]] is ~evaluating-async~ or ~evaluated~. + 1. If _requiredModule_.[[EvaluationError]] is not ~empty~, return _requiredModule_.[[EvaluationError]]. + 1. If _requiredModule_.[[AsyncEvaluation]] is *true*, then + 1. Set _module_.[[PendingAsyncDependencies]] to _module_.[[PendingAsyncDependencies]] + 1. + 1. Append _module_ to _requiredModule_.[[AsyncParentModules]]. + 1. If _module_.[[PendingAsyncDependencies]] > 0 or _module_.[[HasTLA]] is *true*, then + 1. Assert: _module_.[[AsyncEvaluation]] is *false* and was never previously set to *true*. + 1. Set _module_.[[AsyncEvaluation]] to *true*. + 1. NOTE: The order in which module records have their [[AsyncEvaluation]] fields transition to *true* is significant. (See .) + 1. If _module_.[[PendingAsyncDependencies]] is 0, perform ! ExecuteAsyncModule(_module_). + 1. Otherwise, perform ? _module_.ExecuteModule(). 1. Assert: _module_ occurs exactly once in _stack_. 1. Assert: _module_.[[DFSAncestorIndex]] ≤ _module_.[[DFSIndex]]. 1. If _module_.[[DFSAncestorIndex]] = _module_.[[DFSIndex]], then @@ -25670,10 +25770,137 @@

    1. Let _requiredModule_ be the last element in _stack_. 1. Remove the last element of _stack_. 1. Assert: _requiredModule_ is a Cyclic Module Record. - 1. Set _requiredModule_.[[Status]] to ~evaluated~. + 1. If _requiredModule_.[[AsyncEvaluation]] is *false*, set _requiredModule_.[[Status]] to ~evaluated~. + 1. Otherwise, set _requiredModule_.[[Status]] to ~evaluating-async~. 1. If _requiredModule_ and _module_ are the same Module Record, set _done_ to *true*. + 1. Set _requiredModule_.[[CycleRoot]] to _module_. 1. Return _index_. + +

    A module is ~evaluating~ while it is being traversed by InnerModuleEvaluation. A module is ~evaluated~ on execution completion or ~evaluating-async~ during execution if its [[HasTLA]] field is *true* or if it has asynchronous dependencies.

    +
    + +

    Any modules depending on a module of an asynchronous cycle when that cycle is not ~evaluating~ will instead depend on the execution of the root of the cycle via [[CycleRoot]]. This ensures that the cycle state can be treated as a single strongly connected component through its root module state.

    +
    + + + +

    + ExecuteAsyncModule ( + _module_: a Cyclic Module Record, + ) +

    +
    +
    + + + 1. Assert: _module_.[[Status]] is ~evaluating~ or ~evaluating-async~. + 1. Assert: _module_.[[HasTLA]] is *true*. + 1. Let _capability_ be ! NewPromiseCapability(%Promise%). + 1. Let _fulfilledClosure_ be a new Abstract Closure with no parameters that captures _module_ and performs the following steps when called: + 1. Perform ! AsyncModuleExecutionFulfilled(_module_). + 1. Return *undefined*. + 1. Let _onFulfilled_ be ! CreateBuiltinFunction(_fulfilledClosure_, 0, *""*, « »). + 1. Let _rejectedClosure_ be a new Abstract Closure with parameters (_error_) that captures _module_ and performs the following steps when called: + 1. Perform ! AsyncModuleExecutionRejected(_module_, _error_). + 1. Return *undefined*. + 1. Let _onRejected_ be ! CreateBuiltinFunction(_rejectedClosure_, 0, *""*, « »). + 1. Perform ! PerformPromiseThen(_capability_.[[Promise]], _onFulfilled_, _onRejected_). + 1. Perform ! _module_.ExecuteModule(_capability_). + +
    + + +

    + GatherAvailableAncestors ( + _module_: a Cyclic Module Record, + _execList_: a List of Cyclic Module Records, + ) +

    +
    +
    + + 1. For each Cyclic Module Record _m_ of _module_.[[AsyncParentModules]], do + 1. If _execList_ does not contain _m_ and _m_.[[CycleRoot]].[[EvaluationError]] is ~empty~, then + 1. Assert: _m_.[[Status]] is ~evaluating-async~. + 1. Assert: _m_.[[EvaluationError]] is ~empty~. + 1. Assert: _m_.[[AsyncEvaluation]] is *true*. + 1. Assert: _m_.[[PendingAsyncDependencies]] > 0. + 1. Set _m_.[[PendingAsyncDependencies]] to _m_.[[PendingAsyncDependencies]] - 1. + 1. If _m_.[[PendingAsyncDependencies]] = 0, then + 1. Append _m_ to _execList_. + 1. If _m_.[[HasTLA]] is *false*, perform ! GatherAvailableAncestors(_m_, _execList_). + + +

    When an asynchronous execution for a root _module_ is fulfilled, this function determines the list of modules which are able to synchronously execute together on this completion, populating them in _execList_.

    +
    +
    + + +

    + AsyncModuleExecutionFulfilled ( + _module_: a Cyclic Module Record, + ) +

    +
    +
    + + 1. If _module_.[[Status]] is ~evaluated~, then + 1. Assert: _module_.[[EvaluationError]] is not ~empty~. + 1. Return. + 1. Assert: _module_.[[Status]] is ~evaluating-async~. + 1. Assert: _module_.[[AsyncEvaluation]] is *true*. + 1. Assert: _module_.[[EvaluationError]] is ~empty~. + 1. Set _module_.[[AsyncEvaluation]] to *false*. + 1. Set _module_.[[Status]] to ~evaluated~. + 1. If _module_.[[TopLevelCapability]] is not ~empty~, then + 1. Assert: _module_.[[CycleRoot]] is _module_. + 1. Perform ! Call(_module_.[[TopLevelCapability]].[[Resolve]], *undefined*, « *undefined* »). + 1. Let _execList_ be a new empty List. + 1. Perform ! GatherAvailableAncestors(_module_, _execList_). + 1. Let _sortedExecList_ be a List whose elements are the elements of _execList_, in the order in which they had their [[AsyncEvaluation]] fields set to *true* in InnerModuleEvaluation. + 1. Assert: All elements of _sortedExecList_ have their [[AsyncEvaluation]] field set to *true*, [[PendingAsyncDependencies]] field set to 0, and [[EvaluationError]] field set to ~empty~. + 1. For each Cyclic Module Record _m_ of _sortedExecList_, do + 1. If _m_.[[Status]] is ~evaluated~, then + 1. Assert: _m_.[[EvaluationError]] is not ~empty~. + 1. Else if _m_.[[HasTLA]] is *true*, then + 1. Perform ! ExecuteAsyncModule(_m_). + 1. Else, + 1. Let _result_ be _m_.ExecuteModule(). + 1. If _result_ is an abrupt completion, then + 1. Perform ! AsyncModuleExecutionRejected(_m_, _result_.[[Value]]). + 1. Else, + 1. Set _m_.[[Status]] to ~evaluated~. + 1. If _m_.[[TopLevelCapability]] is not ~empty~, then + 1. Assert: _m_.[[CycleRoot]] is _m_. + 1. Perform ! Call(_m_.[[TopLevelCapability]].[[Resolve]], *undefined*, « *undefined* »). + +
    + + +

    + AsyncModuleExecutionRejected ( + _module_: a Cyclic Module Record, + _error_: an ECMAScript language value, + ) +

    +
    +
    + + 1. If _module_.[[Status]] is ~evaluated~, then + 1. Assert: _module_.[[EvaluationError]] is not ~empty~. + 1. Return. + 1. Assert: _module_.[[Status]] is ~evaluating-async~. + 1. Assert: _module_.[[AsyncEvaluation]] is *true*. + 1. Assert: _module_.[[EvaluationError]] is ~empty~. + 1. Set _module_.[[EvaluationError]] to ThrowCompletion(_error_). + 1. Set _module_.[[Status]] to ~evaluated~. + 1. For each Cyclic Module Record _m_ of _module_.[[AsyncParentModules]], do + 1. Perform ! AsyncModuleExecutionRejected(_m_, _error_). + 1. If _module_.[[TopLevelCapability]] is not ~empty~, then + 1. Assert: _module_.[[CycleRoot]] is _module_. + 1. Perform ! Call(_module_.[[TopLevelCapability]].[[Reject]], *undefined*, « _error_ »). +
    @@ -25688,11 +25915,10 @@

    Example Cyclic Module Record Graphs

    A module graph in which module A depends on module B, and module B depends on module C -

    Let's first assume that there are no error conditions. When a host first calls _A_.Link(), this will complete successfully by assumption, and recursively link modules _B_ and _C_ as well, such that _A_.[[Status]] = _B_.[[Status]] = _C_.[[Status]] = ~linked~. This preparatory step can be performed at any time. Later, when the host is ready to incur any possible side effects of the modules, it can call _A_.Evaluate(), which will complete successfully (again by assumption), recursively having evaluated first _C_ and then _B_. Each module's [[Status]] at this point will be ~evaluated~.

    - +

    Let's first assume that there are no error conditions. When a host first calls _A_.Link(), this will complete successfully by assumption, and recursively link modules _B_ and _C_ as well, such that _A_.[[Status]] = _B_.[[Status]] = _C_.[[Status]] = ~linked~. This preparatory step can be performed at any time. Later, when the host is ready to incur any possible side effects of the modules, it can call _A_.Evaluate(), which will complete successfully, returning a Promise resolving to *undefined* (again by assumption), recursively having evaluated first _C_ and then _B_. Each module's [[Status]] at this point will be ~evaluated~.

    Consider then cases involving linking errors. If InnerModuleLinking of _C_ succeeds but, thereafter, fails for _B_, for example because it imports something that _C_ does not provide, then the original _A_.Link() will fail, and both _A_ and _B_'s [[Status]] remain ~unlinked~. _C_'s [[Status]] has become ~linked~, though.

    -

    Finally, consider a case involving evaluation errors. If InnerModuleEvaluation of _C_ succeeds but, thereafter, fails for _B_, for example because _B_ contains code that throws an exception, then the original _A_.Evaluate() will fail. The resulting exception will be recorded in both _A_ and _B_'s [[EvaluationError]] fields, and their [[Status]] will become ~evaluated~. _C_ will also become ~evaluated~ but, in contrast to _A_ and _B_, will remain without an [[EvaluationError]], as it successfully completed evaluation. Storing the exception ensures that any time a host tries to reuse _A_ or _B_ by calling their Evaluate() method, it will encounter the same exception. (Hosts are not required to reuse Cyclic Module Records; similarly, hosts are not required to expose the exception objects thrown by these methods. However, the specification enables such uses.)

    +

    Finally, consider a case involving evaluation errors. If InnerModuleEvaluation of _C_ succeeds but, thereafter, fails for _B_, for example because _B_ contains code that throws an exception, then the original _A_.Evaluate() will fail, returning a rejected Promise. The resulting exception will be recorded in both _A_ and _B_'s [[EvaluationError]] fields, and their [[Status]] will become ~evaluated~. _C_ will also become ~evaluated~ but, in contrast to _A_ and _B_, will remain without an [[EvaluationError]], as it successfully completed evaluation. Storing the exception ensures that any time a host tries to reuse _A_ or _B_ by calling their Evaluate() method, it will encounter the same exception. (Hosts are not required to reuse Cyclic Module Records; similarly, hosts are not required to expose the exception objects thrown by these methods. However, the specification enables such uses.)

    The difference here between linking and evaluation errors is due to how evaluation must be only performed once, as it can cause side effects; it is thus important to remember whether evaluation has already been performed, even if unsuccessfully. (In the error case, it makes sense to also remember the exception because otherwise subsequent Evaluate() calls would have to synthesize a new one.) Linking, on the other hand, is side-effect-free, and thus even if it fails, it can be retried at a later time with no issues.

    @@ -25704,7 +25930,7 @@

    Example Cyclic Module Record Graphs

    In this scenario, module _A_ declares a dependency on some other module, but no Module Record exists for that module, i.e. HostResolveImportedModule throws an exception when asked for it. This could occur for a variety of reasons, such as the corresponding resource not existing, or the resource existing but ParseModule throwing an exception when trying to parse the resulting source text. Hosts can choose to expose the cause of failure via the exception they throw from HostResolveImportedModule. In any case, this exception causes a linking failure, which as before results in _A_'s [[Status]] remaining ~unlinked~.

    -

    Lastly, consider a module graph with a cycle:

    +

    Now, consider a module graph with a cycle:

    A module graph in which module A depends on module B and C, but module B also depends on module A @@ -25716,7 +25942,381 @@

    Example Cyclic Module Record Graphs

    Now consider a case where _A_ has an linking error; for example, it tries to import a binding from _C_ that does not exist. In that case, the above steps still occur, including the early return from the second call to InnerModuleLinking on _A_. However, once we unwind back to the original InnerModuleLinking on _A_, it fails during InitializeEnvironment, namely right after _C_.ResolveExport(). The thrown *SyntaxError* exception propagates up to _A_.Link, which resets all modules that are currently on its _stack_ (these are always exactly the modules that are still ~linking~). Hence both _A_ and _B_ become ~unlinked~. Note that _C_ is left as ~linked~.

    -

    Finally, consider a case where _A_ has an evaluation error; for example, its source code throws an exception. In that case, the evaluation-time analog of the above steps still occurs, including the early return from the second call to InnerModuleEvaluation on _A_. However, once we unwind back to the original InnerModuleEvaluation on _A_, it fails by assumption. The exception thrown propagates up to _A_.Evaluate(), which records the error in all modules that are currently on its _stack_ (i.e., the modules that are still ~evaluating~). Hence both _A_ and _B_ become ~evaluated~ and the exception is recorded in both _A_ and _B_'s [[EvaluationError]] fields, while _C_ is left as ~evaluated~ with no [[EvaluationError]].

    +

    Alternatively, consider a case where _A_ has an evaluation error; for example, its source code throws an exception. In that case, the evaluation-time analog of the above steps still occurs, including the early return from the second call to InnerModuleEvaluation on _A_. However, once we unwind back to the original InnerModuleEvaluation on _A_, it fails by assumption. The exception thrown propagates up to _A_.Evaluate(), which records the error in all modules that are currently on its _stack_ (i.e., the modules that are still ~evaluating~) as well as via [[AsyncParentModules]], which form a chain for modules which contain or depend on top-level `await` through the whole dependency graph through the AsyncModuleExecutionRejected algorithm. Hence both _A_ and _B_ become ~evaluated~ and the exception is recorded in both _A_ and _B_'s [[EvaluationError]] fields, while _C_ is left as ~evaluated~ with no [[EvaluationError]].

    + +

    Lastly, consider a module graph with a cycle, where all modules complete asynchronously:

    + + A module graph in which module A depends on module B and C, module B depends on module D, module C depends on module D and E, and module D depends on module A + +

    Linking happens as before, and all modules end up with [[Status]] set to ~linked~.

    + +

    Calling _A_.Evaluate() calls InnerModuleEvaluation on _A_, _B_, and _D_, which all transition to ~evaluating~. Then InnerModuleEvaluation is called on _A_ again, which is a no-op because it is already ~evaluating~. At this point, _D_.[[PendingAsyncDependencies]] is 0, so ExecuteAsyncModule(_D_) is called and we call _D_.ExecuteModule with a new PromiseCapability tracking the asynchronous execution of _D_. We unwind back to the InnerModuleEvaluation on _B_, setting _B_.[[PendingAsyncDependencies]] to 1 and _B_.[[AsyncEvaluation]] to *true*. We unwind back to the original InnerModuleEvaluation on _A_, setting _A_.[[PendingAsyncDependencies]] to 1. In the next iteration of the loop over _A_'s dependencies, we call InnerModuleEvaluation on _C_ and thus on _D_ (again a no-op) and _E_. As _E_ has no dependencies and is not part of a cycle, we call ExecuteAsyncModule(_E_) in the same manner as _D_ and _E_ is immediately removed from the stack. We unwind once more to the original InnerModuleEvaluation on _A_, setting _C_.[[AsyncEvaluation]] to *true*. Now we finish the loop over _A_'s dependencies, set _A_.[[AsyncEvaluation]] to *true*, and remove the entire strongly connected component from the stack, transitioning all of the modules to ~evaluating-async~ at once. At this point, the fields of the modules are as given in .

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Module[[DFSIndex]][[DFSAncestorIndex]][[Status]][[AsyncEvaluation]][[AsyncParentModules]][[PendingAsyncDependencies]]
    _A_00~evaluating-async~*true*« »2 (_B_ and _C_)
    _B_10~evaluating-async~*true*« _A_ »1 (_D_)
    _C_20~evaluating-async~*true*« _A_ »2 (_D_ and _E_)
    _D_30~evaluating-async~*true*« _B_, _C_ »0
    _E_44~evaluating-async~*true*« _C_ »0
    +
    + +

    Let us assume that _E_ finishes executing first. When that happens, AsyncModuleExecutionFulfilled is called, _E_.[[Status]] is set to ~evaluated~ and _C_.[[PendingAsyncDependencies]] is decremented to become 1. The fields of the updated modules are as given in .

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Module[[DFSIndex]][[DFSAncestorIndex]][[Status]][[AsyncEvaluation]][[AsyncParentModules]][[PendingAsyncDependencies]]
    _C_20~evaluating-async~*true*« _A_ »1 (_D_)
    _E_44~evaluated~*true*« _C_ »0
    +
    + +

    _D_ is next to finish (as it was the only module that was still executing). When that happens, AsyncModuleExecutionFulfilled is called again and _D_.[[Status]] is set to ~evaluated~. Then _B_.[[PendingAsyncDependencies]] is decremented to become 0, ExecuteAsyncModule is called on _B_, and it starts executing. _C_.[[PendingAsyncDependencies]] is also decremented to become 0, and _C_ starts executing (potentially in parallel to _B_ if _B_ contains an `await`). The fields of the updated modules are as given in .

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Module[[DFSIndex]][[DFSAncestorIndex]][[Status]][[AsyncEvaluation]][[AsyncParentModules]][[PendingAsyncDependencies]]
    _B_10~evaluating-async~*true*« _A_ »0
    _C_20~evaluating-async~*true*« _A_ »0
    _D_30~evaluated~*true*« _B_, _C_ »0
    +
    + +

    Let us assume that _C_ finishes executing next. When that happens, AsyncModuleExecutionFulfilled is called again, _C_.[[Status]] is set to ~evaluated~ and _A_.[[PendingAsyncDependencies]] is decremented to become 1. The fields of the updated modules are as given in .

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Module[[DFSIndex]][[DFSAncestorIndex]][[Status]][[AsyncEvaluation]][[AsyncParentModules]][[PendingAsyncDependencies]]
    _A_00~evaluating-async~*true*« »1 (_B_)
    _C_20~evaluated~*true*« _A_ »0
    +
    + +

    Then, _B_ finishes executing. When that happens, AsyncModuleExecutionFulfilled is called again and _B_.[[Status]] is set to ~evaluated~. _A_.[[PendingAsyncDependencies]] is decremented to become 0, so ExecuteAsyncModule is called and it starts executing. The fields of the updated modules are as given in .

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Module[[DFSIndex]][[DFSAncestorIndex]][[Status]][[AsyncEvaluation]][[AsyncParentModules]][[PendingAsyncDependencies]]
    _A_00~evaluating-async~*true*« »0
    _B_10~evaluated~*true*« _A_ »0
    +
    + +

    Finally, _A_ finishes executing. When that happens, AsyncModuleExecutionFulfilled is called again and _A_.[[Status]] is set to ~evaluated~. At this point, the Promise in _A_.[[TopLevelCapability]] (which was returned from _A_.Evaluate()) is resolved, and this concludes the handling of this module graph. The fields of the updated module are as given in .

    + + + + + + + + + + + + + + + + + + + + + + + + + +
    Module[[DFSIndex]][[DFSAncestorIndex]][[Status]][[AsyncEvaluation]][[AsyncParentModules]][[PendingAsyncDependencies]]
    _A_00~evaluated~*true*« »0
    +
    + +

    Alternatively, consider a failure case where _C_ fails execution and returns an error before _B_ has finished executing. When that happens, AsyncModuleExecutionRejected is called, which sets _C_.[[Status]] to ~evaluated~ and _C_.[[EvaluationError]] to the error. It then propagates this error to all of the AsyncParentModules by performing AsyncModuleExecutionRejected on each of them. The fields of the updated modules are as given in .

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Module[[DFSIndex]][[DFSAncestorIndex]][[Status]][[AsyncEvaluation]][[AsyncParentModules]][[PendingAsyncDependencies]][[EvaluationError]]
    _A_00~evaluated~*true*« »1 (_B_)~empty~
    _C_21~evaluated~*true*« _A_ »0_C_'s evaluation error
    +
    + +

    _A_ will be rejected with the same error as _C_ since _C_ will call AsyncModuleExecutionRejected on _A_ with _C_'s error. _A_.[[Status]] is set to ~evaluated~. At this point the Promise in _A_.[[TopLevelCapability]] (which was returned from _A_.Evaluate()) is rejected. The fields of the updated module are as given in .

    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Module[[DFSIndex]][[DFSAncestorIndex]][[Status]][[AsyncEvaluation]][[AsyncParentModules]][[PendingAsyncDependencies]][[EvaluationError]]
    _A_00~evaluated~*true*« »0_C_'s Evaluation Error
    +
    + +

    Then, _B_ finishes executing without an error. When that happens, AsyncModuleExecutionFulfilled is called again and _B_.[[Status]] is set to ~evaluated~. GatherAvailableAncestors is called on _B_. However, _A_.[[CycleRoot]] is _A_ which has an evaluation error, so it will not be added to the returned _sortedExecList_ and AsyncModuleExecutionFulfilled will return without further processing. Any future importer of _B_ will resolve the rejection of _B_.[[CycleRoot]].[[EvaluationError]] from the evaluation error from _C_ that was set on the cycle root _A_. The fields of the updated modules are as given in .

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Module[[DFSIndex]][[DFSAncestorIndex]][[Status]][[AsyncEvaluation]][[AsyncParentModules]][[PendingAsyncDependencies]][[EvaluationError]]
    _A_00~evaluated~*true*« »0_C_'s Evaluation Error
    _B_10~evaluated~*true*« _A_ »0~empty~
    +
    @@ -25873,7 +26473,7 @@

    Source Text Module Records

    - +

    gives examples of ImportEntry records fields used to represent the syntactic import forms:

    @@ -26022,7 +26622,7 @@

    Source Text Module Records

    - +

    gives examples of the ExportEntry record fields used to represent the syntactic export forms:

    @@ -26259,7 +26859,8 @@

    1. Append _ee_ to _starExportEntries_. 1. Else, 1. Append _ee_ to _indirectExportEntries_. - 1. Return Source Text Module Record { [[Realm]]: _realm_, [[Environment]]: *undefined*, [[Namespace]]: *undefined*, [[Status]]: ~unlinked~, [[EvaluationError]]: *undefined*, [[HostDefined]]: _hostDefined_, [[ECMAScriptCode]]: _body_, [[Context]]: ~empty~, [[ImportMeta]]: ~empty~, [[RequestedModules]]: _requestedModules_, [[ImportEntries]]: _importEntries_, [[LocalExportEntries]]: _localExportEntries_, [[IndirectExportEntries]]: _indirectExportEntries_, [[StarExportEntries]]: _starExportEntries_, [[DFSIndex]]: *undefined*, [[DFSAncestorIndex]]: *undefined* }. + 1. Let _async_ be _body_ Contains `await`. + 1. Return Source Text Module Record { [[Realm]]: _realm_, [[Environment]]: ~empty~, [[Namespace]]: ~empty~, [[CycleRoot]]: ~empty~, [[HasTLA]]: _async_, [[AsyncEvaluation]]: *false*, [[TopLevelCapability]]: ~empty~, [[AsyncParentModules]]: « », [[PendingAsyncDependencies]]: ~empty~, [[Status]]: ~unlinked~, [[EvaluationError]]: ~empty~, [[HostDefined]]: _hostDefined_, [[ECMAScriptCode]]: _body_, [[Context]]: ~empty~, [[ImportMeta]]: ~empty~, [[RequestedModules]]: _requestedModules_, [[ImportEntries]]: _importEntries_, [[LocalExportEntries]]: _localExportEntries_, [[IndirectExportEntries]]: _indirectExportEntries_, [[StarExportEntries]]: _starExportEntries_, [[DFSIndex]]: ~empty~, [[DFSAncestorIndex]]: ~empty~ }.

    An implementation may parse module source text and analyse it for Early Error conditions prior to the evaluation of ParseModule for that module source text. However, the reporting of any errors must be deferred until the point where this specification actually performs ParseModule upon that source text.

    @@ -26431,20 +27032,36 @@

    InitializeEnvironment ( )

    -

    ExecuteModule ( )

    +

    + ExecuteModule ( + optional _capability_: unknown, + ) +

    for
    a Source Text Module Record _module_
    + 1. Let _moduleContext_ be a new ECMAScript code execution context. + 1. Set the Function of _moduleContext_ to *null*. + 1. Set the Realm of _moduleContext_ to _module_.[[Realm]]. + 1. Set the ScriptOrModule of _moduleContext_ to _module_. + 1. Assert: _module_ has been linked and declarations in its module environment have been instantiated. + 1. Set the VariableEnvironment of _moduleContext_ to _module_.[[Environment]]. + 1. Set the LexicalEnvironment of _moduleContext_ to _module_.[[Environment]]. 1. Suspend the currently running execution context. - 1. Let _moduleContext_ be _module_.[[Context]]. - 1. Push _moduleContext_ onto the execution context stack; _moduleContext_ is now the running execution context. - 1. Let _result_ be the result of evaluating _module_.[[ECMAScriptCode]]. - 1. Suspend _moduleContext_ 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. If _module_.[[HasTLA]] is *false*, then + 1. Assert: _capability_ is not present. + 1. Push _moduleContext_ onto the execution context stack; _moduleContext_ is now the running execution context. + 1. Let _result_ be the result of evaluating _module_.[[ECMAScriptCode]]. + 1. Suspend _moduleContext_ 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. Else, + 1. Assert: _capability_ is a PromiseCapability Record. + 1. Perform ! AsyncBlockStart(_capability_, _module_.[[ECMAScriptCode]], _moduleContext_). + 1. Return NormalCompletion(~empty~).
    @@ -26509,7 +27126,7 @@

      -
    • At some future time, the host environment must perform FinishDynamicImport(_referencingScriptOrModule_, _specifier_, _promiseCapability_, NormalCompletion(*undefined*)).
    • +
    • At some future time, the host environment must perform FinishDynamicImport(_referencingScriptOrModule_, _specifier_, _promiseCapability_, _promise_), where _promise_ is a Promise resolved with *undefined*.
    • Any subsequent call to HostResolveImportedModule after FinishDynamicImport has completed, given the arguments _referencingScriptOrModule_ and _specifier_, must complete normally.
    • @@ -26521,7 +27138,7 @@

        -
      • At some future time, the host environment must perform FinishDynamicImport(_referencingScriptOrModule_, _specifier_, _promiseCapability_, an abrupt completion), with the abrupt completion representing the cause of failure.
      • +
      • At some future time, the host environment must perform FinishDynamicImport(_referencingScriptOrModule_, _specifier_, _promiseCapability_, _promise_), where _promise_ is a Promise rejected with an error representing the cause of failure.
      @@ -26543,22 +27160,30 @@

      _referencingScriptOrModule_: unknown, _specifier_: unknown, _promiseCapability_: a PromiseCapability Record, - _completion_: unknown, + _innerPromise_: unknown, )

      description
      -
      FinishDynamicImport completes the process of a dynamic import originally started by an `import()` call, resolving or rejecting the promise returned by that call as appropriate according to _completion_. It is performed by host environments as part of HostImportModuleDynamically.
      +
      FinishDynamicImport completes the process of a dynamic import originally started by an `import()` call, resolving or rejecting the promise returned by that call as appropriate according to _innerPromise_'s resolution. It is performed by host environments as part of HostImportModuleDynamically.
      - 1. If _completion_ is an abrupt completion, perform ! Call(_promiseCapability_.[[Reject]], *undefined*, « _completion_.[[Value]] »). - 1. Else, - 1. Assert: _completion_ is a normal completion and _completion_.[[Value]] is *undefined*. + 1. Let _fulfilledClosure_ be a new Abstract Closure with parameters (_result_) that captures _referencingScriptOrModule_, _specifier_, and _promiseCapability_ and performs the following steps when called: + 1. Assert: _result_ is *undefined*. 1. Let _moduleRecord_ be ! HostResolveImportedModule(_referencingScriptOrModule_, _specifier_). 1. Assert: Evaluate has already been invoked on _moduleRecord_ and successfully completed. 1. Let _namespace_ be GetModuleNamespace(_moduleRecord_). - 1. If _namespace_ is an abrupt completion, perform ! Call(_promiseCapability_.[[Reject]], *undefined*, « _namespace_.[[Value]] »). - 1. Else, perform ! Call(_promiseCapability_.[[Resolve]], *undefined*, « _namespace_.[[Value]] »). + 1. If _namespace_ is an abrupt completion, then + 1. Perform ! Call(_promiseCapability_.[[Reject]], *undefined*, « _namespace_.[[Value]] »). + 1. Else, + 1. Perform ! Call(_promiseCapability_.[[Resolve]], *undefined*, « _namespace_.[[Value]] »). + 1. Return *undefined*. + 1. Let _onFulfilled_ be ! CreateBuiltinFunction(_fulfilledClosure_, 0, *""*, « »). + 1. Let _rejectedClosure_ be a new Abstract Closure with parameters (_error_) that captures _promiseCapability_ and performs the following steps when called: + 1. Perform ! Call(_promiseCapability_.[[Reject]], *undefined*, « _error_ »). + 1. Return *undefined*. + 1. Let _onRejected_ be ! CreateBuiltinFunction(_rejectedClosure_, 0, *""*, « »). + 1. Perform ! PerformPromiseThen(_innerPromise_, _onFulfilled_, _onRejected_). @@ -26577,7 +27202,7 @@

      1. Assert: _module_ is an instance of a concrete subclass of Module Record. 1. Assert: If _module_ is a Cyclic Module Record, then _module_.[[Status]] is not ~unlinked~. 1. Let _namespace_ be _module_.[[Namespace]]. - 1. If _namespace_ is *undefined*, then + 1. If _namespace_ is ~empty~, then 1. Let _exportedNames_ be ? _module_.GetExportedNames(). 1. Let _unambiguousNames_ be a new empty List. 1. For each element _name_ of _exportedNames_, do @@ -26662,7 +27287,7 @@

      Syntax

      StringLiteral ImportedBinding : - BindingIdentifier[~Yield, ~Await] + BindingIdentifier[~Yield, +Await] @@ -26766,11 +27391,11 @@

      Syntax

      ExportDeclaration : `export` ExportFromClause FromClause `;` `export` NamedExports `;` - `export` VariableStatement[~Yield, ~Await] - `export` Declaration[~Yield, ~Await] - `export` `default` HoistableDeclaration[~Yield, ~Await, +Default] - `export` `default` ClassDeclaration[~Yield, ~Await, +Default] - `export` `default` [lookahead ∉ {`function`, `async` [no |LineTerminator| here] `function`, `class`}] AssignmentExpression[+In, ~Yield, ~Await] `;` + `export` VariableStatement[~Yield, +Await] + `export` Declaration[~Yield, +Await] + `export` `default` HoistableDeclaration[~Yield, +Await, +Default] + `export` `default` ClassDeclaration[~Yield, +Await, +Default] + `export` `default` [lookahead ∉ {`function`, `async` [no |LineTerminator| here] `function`, `class`}] AssignmentExpression[+In, ~Yield, +Await] `;` ExportFromClause : `*` @@ -44129,9 +44754,25 @@

      1. Let _runningContext_ be the running execution context. 1. Let _asyncContext_ be a copy of _runningContext_. - 1. NOTE: Copying the execution state is required for the step below to resume its execution. It is ill-defined to resume a currently executing context. + 1. NOTE: Copying the execution state is required for AsyncBlockStart to resume its execution. It is ill-defined to resume a currently executing context. + 1. Perform ! AsyncBlockStart(_promiseCapability_, _asyncFunctionBody_, _asyncContext_). + + + +

      + AsyncBlockStart ( + _promiseCapability_: a PromiseCapability Record, + _asyncBody_: a Parse Node, + _asyncContext_: an execution context, + ) +

      +
      +
      + + 1. Assert: _promiseCapability_ is a PromiseCapability Record. + 1. Let _runningContext_ be the running execution context. 1. Set the code evaluation state of _asyncContext_ such that when evaluation is resumed for that execution context the following steps will be performed: - 1. Let _result_ be the result of evaluating _asyncFunctionBody_. + 1. Let _result_ be the result of evaluating _asyncBody_. 1. Assert: If we return here, the async function either threw an exception or performed an implicit or explicit return; all awaiting is done. 1. Remove _asyncContext_ from the execution context stack and restore the execution context that is at the top of the execution context stack as the running execution context. 1. If _result_.[[Type]] is ~normal~, then @@ -44141,11 +44782,11 @@

      1. Else, 1. Assert: _result_.[[Type]] is ~throw~. 1. Perform ! Call(_promiseCapability_.[[Reject]], *undefined*, « _result_.[[Value]] »). - 1. [id="step-asyncfunctionstart-return-undefined"] Return. + 1. [id="step-asyncblockstart-return-undefined"] Return. 1. Push _asyncContext_ onto the execution context stack; _asyncContext_ is now the running execution context. 1. Resume the suspended evaluation of _asyncContext_. Let _result_ be the value returned by the resumed computation. 1. Assert: When we return here, _asyncContext_ has already been removed from the execution context stack and _runningContext_ is the currently running execution context. - 1. Assert: _result_ is a normal completion with a value of *undefined*. The possible sources of completion values are Await or, if the async function doesn't await anything, step above. + 1. Assert: _result_ is a normal completion with a value of *undefined*. The possible sources of completion values are Await or, if the async function doesn't await anything, step above. 1. Return.