diff --git a/document/js-api/index.bs b/document/js-api/index.bs index 88cace6a4..fb94460a0 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -36,6 +36,15 @@ urlPrefix: https://tc39.github.io/ecma262/; spec: ECMASCRIPT text: NativeError; url: sec-nativeerror-constructors text: TypeError; url: sec-native-error-types-used-in-this-standard-typeerror text: RangeError; url: sec-native-error-types-used-in-this-standard-rangeerror + type: dfn; + text: AbstractClosure; url: sec-abstract-closure + text: CreateBuiltinFunction; url: sec-createbuiltinfunction + text: PromiseCapabilityRecord; url: sec-promisecapability-records + text: EvaluateCall; url: sec-evaluatecall + text: ExecutionContext; url: sec-execution-contexts + text: IsPromise; url: sec-ispromise + text: PerformPromiseThen; url: sec-performpromisethen + text: Execution Context Stack; url: execution-context-stack type: dfn url: sec-returnifabrupt-shorthands text: ! @@ -101,6 +110,8 @@ urlPrefix: https://webassembly.github.io/spec/core/; spec: WebAssembly; type: df text: func_alloc; url: appendix/embedding.html#embed-func-alloc text: func_type; url: appendix/embedding.html#embed-func-type text: func_invoke; url: appendix/embedding.html#embed-func-invoke + text: evaluation_suspend; url: appendix/embedding.html#embed-evaluation-suspend + text: evaluation_resume; url: appendix/embedding.html#embed-evaluation-resume text: table_alloc; url: appendix/embedding.html#embed-table-alloc text: table_type; url: appendix/embedding.html#embed-table-type text: table_read; url: appendix/embedding.html#embed-table-read @@ -295,6 +306,13 @@ Each [=agent=] is associated with the following [=ordered map=]s: * The Host value cache, mapping [=host address=]es to values. +

Execution Context Status Map

+ +Note: The Execution Context Status Map is used to enforce certain correspondences between JavaScript execution and WebAssembly execution; particularly in relation to the JavaScript Promise Integration API. + +Each [=agent=] is associated with the following [=ordered map=]: + * The Execution Context Status map is used to map [=execution context|execution contexts=] to [=stack status=] values. +

The WebAssembly Namespace

@@ -385,13 +403,18 @@ A {{Module}} object represents a single WebAssembly module. Each {{Module}} obje
         1. Let |o| be [=?=] [$Get$](|importObject|, |moduleName|).
         1. If [=Type=](|o|) is not Object, throw a {{TypeError}} exception.
         1. Let |v| be [=?=] [$Get$](|o|, |componentName|).
-        1. If |externtype| is of the form [=external-type/func=] |functype|,
-            1. If [$IsCallable$](|v|) is false, throw a {{LinkError}} exception.
-            1. If |v| has a \[[FunctionAddress]] internal slot, and therefore is an [=Exported Function=],
-                1. Let |funcaddr| be the value of |v|'s \[[FunctionAddress]] internal slot.
-            1. Otherwise,
-                1. [=Create a host function=] from |v| and |functype|, and let |funcaddr| be the result.
-                1. Let |index| be the number of external functions in |imports|. This value |index| is known as the index of the host function |funcaddr|.
+        1. If |externtype| is of the form [=func=] |functype|,
+            1. If [$IsCallable$](|v|) is true,
+                1. If |v| has a \[[FunctionAddress]] internal slot, and therefore is an [=Exported Function=],
+                    1. Let |funcaddr| be the value of |v|'s \[[FunctionAddress]] internal slot.
+                1. Otherwise,
+                    1. [=Create a host function=] from |v| and |functype|, and let |funcaddr| be the result.
+            1. Otherwise, if |v| has a \[[WrappedFunction]] internal slot,
+                    1. Let |func| be the value of |v|'s \[[WrappedFunction]] internal slot.
+                    1. Assert: [$IsCallable$](|func|) is true.
+                    1. [=Create a suspending function|create a suspending function=] from |func| and |functype|, and let |funcaddr| be the result.
+            1. Otherwise, throw a {{LinkError}} exception.
+            1. Let |index| be the number of external functions in |imports|. This value |index| is known as the index of the host function |funcaddr|.
             1. Let |externfunc| be the [=external value=] [=external value|func=] |funcaddr|.
             1. [=list/Append=] |externfunc| to |imports|.
         1. If |externtype| is of the form [=external-type/global=] mut |valtype|,
@@ -781,7 +804,7 @@ Immediately after a WebAssembly [=memory.grow=] instruction executes, perform th
 
1. If the top of the stack is not [=i32.const=] (−1), 1. Let |frame| be the [=current frame=]. - 1. Assert: due to validation, |frame|.[=frame/module=].[=moduleinst/memaddrs=][0] exists. + 1. Assert: Due to validation, |frame|.[=frame/module=].[=moduleinst/memaddrs=][0] exists. 1. Let |memaddr| be the memory address |frame|.[=frame/module=].[=moduleinst/memaddrs=][0]. 1. [=Refresh the memory buffer=] of |memaddr|.
@@ -1112,7 +1135,7 @@ This slot holds a [=function address=] relative to the [=surrounding agent=]'s [ 1. Let |map| be the [=surrounding agent=]'s associated [=Exported Function cache=]. 1. If |map|[|funcaddr|] [=map/exists=], 1. Return |map|[|funcaddr|]. - 1. Let |steps| be "[=call an Exported Function|call the Exported Function=] |funcaddr| with arguments." + 1. Let |steps| be "[=call an Exported Function|call the Exported Function=] |funcaddr| with arguments.". 1. Let |realm| be the [=current Realm=]. 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. 1. Let |functype| be [=func_type=](|store|, |funcaddr|). @@ -1126,13 +1149,9 @@ This slot holds a [=function address=] relative to the [=surrounding agent=]'s [
- To call an Exported Function with [=function address=] |funcaddr| and a [=list=] of JavaScript arguments |argValues|, perform the following steps: - - 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. - 1. Let |functype| be [=func_type=](|store|, |funcaddr|). + To coerce JavaScript arguments from a |functype| and a [=list=] of JavaScript arguments |argValues|, perform the following steps 1. Let [|parameters|] → [|results|] be |functype|. 1. If |parameters| or |results| contain [=v128=] or [=exnref=], throw a {{TypeError}}. - Note: the above error is thrown each time the \[[Call]] method is invoked. 1. Let |args| be « ». 1. Let |i| be 0. @@ -1141,10 +1160,18 @@ This slot holds a [=function address=] relative to the [=surrounding agent=]'s [ 1. Otherwise, let |arg| be undefined. 1. [=list/Append=] [=ToWebAssemblyValue=](|arg|, |t|) to |args|. 1. Set |i| to |i| + 1. + 1. return |args|. +
+ +
+ To call an Exported Function with [=function address=] |funcaddr| and a [=list=] of JavaScript arguments |argValues|, perform the following steps: + 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. + 1. Let |functype| be [=func_type=](|store|, |funcaddr|). + 1. Let |args| be the result of [=coerce JavaScript arguments|coercing arguments=] (|functype|,|argValues|). 1. Let (|store|, |ret|) be the result of [=func_invoke=](|store|, |funcaddr|, |args|). 1. Set the [=surrounding agent=]'s [=associated store=] to |store|. 1. If |ret| is [=error=], throw an exception. This exception should be a WebAssembly {{RuntimeError}} exception, unless otherwise indicated by the WebAssembly error mapping. - 1. If |ret| is [=THROW=] [=ref.exn=] |exnaddr|, then + 1. If |ret| is [=THROW=] [=ref.exn=] |exnaddr|, then: 1. Let |tagaddr| be [=exn_tag=](|store|, |exnaddr|). 1. Let |payload| be [=exn_read=](|store|, |exnaddr|). 1. Let |jsTagAddr| be the result of [=get the JavaScript exception tag |getting the JavaScript exception tag=]. @@ -1168,14 +1195,16 @@ Note: [=call an Exported Function|Calling an Exported Function=] executes in the Note: Exported Functions do not have a \[[Construct]] method and thus it is not possible to call one with the `new` operator.
- To run a host function from the JavaScript object |func|, type |functype|, and [=list=] of [=WebAssembly values=] |arguments|, perform the following steps: - - 1. Let [|parameters|] → [|results|] be |functype|. - 1. If |parameters| or |results| contain [=v128=] or [=exnref=], throw a {{TypeError}}. + To coerce WebAssembly arguments from a [=list=] of |parameterTypes| and a [=list=] of JavaScript arguments |arguments|, perform the following steps + 1. If |parameterTypes| contain [=v128=], throw a {{TypeError}}. 1. Let |jsArguments| be « ». 1. [=list/iterate|For each=] |arg| of |arguments|, 1. [=list/Append=] [=!=] [=ToJSValue=](|arg|) to |jsArguments|. - 1. Let |ret| be [=?=] [$Call$](|func|, undefined, |jsArguments|). + 1. Return |jsArguments|. +
+ +
+ To coerce a JavaScript return from a JavaScript |ret| and a list of |results| types, perform the following steps: 1. Let |resultsSize| be |results|'s [=list/size=]. 1. If |resultsSize| is 0, return « ». 1. Otherwise, if |resultsSize| is 1, return « [=?=] [=ToWebAssemblyValue=](|ret|, |results|[0]) ». @@ -1190,6 +1219,18 @@ Note: Exported Functions do not have a \[[Construct]] method and thus it is not 1. Return |wasmValues|.
+
+ To coerce a JavaScript exception from a JavaScript exception |v|, perform the following steps: + 1. If |v| [=implements=] {{Exception}}, + 1. Let |type| be |v|.\[[Type]]. + 1. Let |payload| be |v|.\[[Payload]]. + 1. Otherwise, + 1. Let |type| be the [=JavaScript exception tag=]. + 1. Let |payload| be « ». + 1. Let |opaqueData| be [=ToWebAssemblyValue=](|v|, [=externref=]). + 1. Return the triple |type|, |payload| and |opaqueData|. +
+
To create a host function from the JavaScript object |func| and type |functype|, perform the following steps: @@ -1200,27 +1241,34 @@ Note: Exported Functions do not have a \[[Construct]] method and thus it is not 1. Let |relevant settings| be |realm|'s [=realm/settings object=]. 1. [=Prepare to run script=] with |relevant settings|. 1. [=Prepare to run a callback=] with |stored settings|. - 1. Let |result| be the result of [=run a host function|running a host function=] from |func|, |functype|, and |arguments|. + 1. Let [|parameters|] → [|resultTypes|] be |functype|. + 1. Let |jsArguments| be the result of [=coerce WebAssembly arguments=](|parameters|,|arguments|). + 1. Let |result| be the result of Completion([$Call$](|func|, undefined, |jsArguments|)). 1. [=Clean up after running a callback=] with |stored settings|. 1. [=Clean up after running script=] with |relevant settings|. 1. Assert: |result|.\[[Type]] is throw or normal. 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. + 1. If |result|.\[[Type]] is normal, then: + 1. Return the result of performing [=coerce a JavaScript return=] on |resultTypes| and |ret|. 1. If |result|.\[[Type]] is throw, then: - 1. Let |v| be |result|.\[[Value]]. - 1. If |v| [=implements=] {{Exception}}, - 1. Let |address| be |v|.\[[Address]]. - 1. Otherwise, - 1. Let |type| be the result of [=get the JavaScript exception tag |getting the JavaScript exception tag=]. - 1. Let |payload| be [=!=] [=ToWebAssemblyValue=](|v|, [=externref=]). - 1. Let (|store|, |address|) be [=exn_alloc=](|store|, |type|, « |payload| »). - 1. Set the [=surrounding agent=]'s [=associated store=] to |store|. - 1. Execute the WebAssembly instructions ([=ref.exn=] |address|) ([=throw_ref=]). - 1. Otherwise, return |result|.\[[Value]]. + 1. Perform [=throw a JavaScript exception|throw the JavaScript exception=] on |result|.\[[Value]]. 1. Let (|store|, |funcaddr|) be [=func_alloc=](|store|, |functype|, |hostfunc|). 1. Set the [=surrounding agent=]'s [=associated store=] to |store|. 1. Return |funcaddr|.
+
+ To throw a JavaScript exception from the JavaScript object |v|, perform the following steps: + 1. If |v| [=implements=] {{Exception}}, + 1. Let |address| be |v|.\[[Address]]. + 1. Otherwise, + 1. Let |type| be the result of [=get the JavaScript exception tag |getting the JavaScript exception tag=]. + 1. Let |payload| be [=!=] [=ToWebAssemblyValue=](|v|, [=externref=]). + 1. Let (|store|, |address|) be [=exn_alloc=](|store|, |type|, « |payload| »). + 1. Set the [=surrounding agent=]'s [=associated store=] to |store|. + 1. Execute the WebAssembly instructions ([=ref.exn=] |address|) ([=throw_ref=]). +
+
The algorithm ToJSValue(|w|) coerces a [=WebAssembly value=] to a JavaScript value by performing the following steps: @@ -1250,7 +1298,6 @@ The algorithm ToJSValue(|w|) coerces a [=WebAssembly value=] to a Jav 1. If |w| is of the form [=ref.host=] |hostaddr|, return the result of [=retrieving a host value=] from |hostaddr|. 1. If |w| is of the form [=ref.extern=] |ref|, return [=ToJSValue=](|ref|). - Note: Number values which are equal to NaN may have various observable NaN payloads; see [$NumericToRawBytes$] for details.
@@ -1283,7 +1330,7 @@ The algorithm ToWebAssemblyValue(|v|, |type|) coerces a JavaScript va 1. Let |n| be an implementation-defined integer such that [=canon=]32 ≤ |n| < 2[=signif=](32). 1. Let |f32| be [=nan=](n). 1. Otherwise, - 1. Let |f32| be |number| rounded to the nearest representable value using IEEE 754-2008 round to nearest, ties to even mode. [[IEEE-754]] + \1. 1. Return [=f32.const=] |f32|. 1. If |type| is [=f64=], 1. Let |number| be [=?=] [$ToNumber$](|v|). @@ -1329,6 +1376,137 @@ The algorithm ToWebAssemblyValue(|v|, |type|) coerces a JavaScript va
+

JavaScript Promise Integration

+ +Note: The JavaScript Promise Integration API (JSPI) allows WebAssembly functions to suspend and resume their execution -- based on the behavior of JavaScript functions that return Promise objects. + +A {{Suspending}} marker object represents a JavaScript function whose calls via WebAssembly imports should be *suspended* when they return a Promise object. +Each {{Suspending}} marker object has a \[[WrappedFunction]] internal slot which holds a JavaScript function. + +In addition, the {{promising}} function takes as argument a WebAssembly function and returns a JavaScript function that returns a Promise that is resolved when the WebAssembly function completes. + +Each [=agent=] maintains a [=Execution Context Status map=], mapping from [=execution context|execution contexts=] to a status symbol. The purpose of this map is to ensure that applications do not try to suspend JavaScript frames and also to ensure that calls to imports marked with a {{Suspending}} marker object are properly balanced by corresponding uses of {{WebAssembly.promising}}. + +If present, a status can be one of two stack status values: + + * active. This signals that the associated execution context is actively executing and has the potential to be [=paused=]. + * paused. This signals that the associated execution is not currently involved in computation and has been paused. + +If an execution context is not present in the status mapping, then it may not be [=Pause|paused=] or [=Enter|reentered=]. + +When a new agent is created, its status mapping is set to the empty map. + +
+[Exposed=*]
+partial namespace WebAssembly {
+    Function promising(Function wasmFunc);
+};
+
+[LegacyNamespace=WebAssembly, Exposed=*]
+interface Suspending {
+    constructor(Function jsFun);
+};
+
+ +
+ The promising(|wasmFunc|) function, when invoked, performs the following steps: + 1. If [$IsCallable$](|wasmFunc|) is false, throw a {{TypeError}}. + 1. If |wasmFunc| does not have a \[[FunctionAddress]] internal slot, throw a {{TypeError}}. + 1. Let |builder| be a new [=AbstractClosure=] with no parameters that captures |wasmFunc| and performs [=run a Promising function=] when called. + 1. Returns the result of [=CreateBuiltinFunction=](|builder|,1,"", « »). +
+ +
+ The algorithm to run a Promising function from the JavaScript object |wasmFunc| and a [=list=] of [=WebAssembly values=] |arguments| consists of the following steps: + 1. Let |promise| be a new [=PromiseCapabilityRecord=]. + 1. Let |funcaddr| be the value of |wasmFunc|'s \[[FunctionAddress]] internal slot. + 1. Let |runner| be a new [=AbstractClosure=] with no parameters that captures |promise|, |funcaddr|, and |arguments| and performs the following steps when called: + 1. Perform [=evaluate a Promising function=](|promise|,|funcaddr|,|arguments|). + 1. Perform [=?=][$AsyncFunctionStart$](|promise|,|runner|). + 1. Return |promise|. +
+ +
+ The algorithm to evaluate a Promising function(|promise|, |funcaddr|, |arguments|) consists of the following steps: + 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. + 1. Let |functype| be [=func_type=](|store|, |funcaddr|). + 1. Let |args| be the result of [=coerce JavaScript arguments|coercing arguments=] (|functype|,|arguments|). + 1. Let |map| be the [=surrounding agent=]'s associated [=Execution Context Status map=]. + 1. Let |ec| be the currently executing [=execution context=], i.e., the [=execution context=] that is at the top of the [=surrounding agent=]'s current [=execution context stack=]. + 1. Assert: |map| does not contain any entry for |ec|. + 1. Add an entry mapping |ec| to [=active=] in |map|. + 1. Let (|store|, |result|) be the result of [=func_invoke=](|store|, |funcaddr|, |args|). + 1. Assert: If control reaches here, we have done waiting for suspended imports. + 1. If the entry for |ec| in |map| is not [=active=] then throw a WebAssembly {{RuntimeError}} exception. Otherwise, remove the entry for |ec| from [=map=]. + 1. Set the [=surrounding agent=]'s [=associated store=] to |store|. + 1. If |result| is [=error=], throw a WebAssembly {{RuntimeError}} exception, unless otherwise indicated by the WebAssembly error mapping. + 1. Otherwise, if |result| is of the form [=throw=] exnaddr, + 1. [=Reject=] |promise| with |result|. + 1. Otherwise, + 1. Assert: |result| is a [=list=] of WebAssembly values. + 1. Let |outArity| be the [=list/size=] of |result|. + 1. If |outArity| is 0, return undefined. + 1. Otherwise, if |outArity| is 1, let |jsReturnValue| be [=ToJSValue=](|result|[0]). + 1. Otherwise, + 1. Let |values| be « ». + 1. [=list/iterate|For each=] |r| of |result|, + 1. [=list/Append=] [=ToJSValue=](|r|) to |values|. + 1. Let |jsReturnValue| be [$CreateArrayFromList$](|values|). + 1. [=Resolve=] |promise| with |jsReturnValue|. + 1. Return UNUSED. +
+ +
+ The Suspending(|jsFun|) constructor, when invoked, performs the following steps: + 1. If [$IsCallable$](|jsFun|) is false, throw a {{TypeError}}. + 1. Let |suspendingProto| be \[[%WebAssembly.Suspending.prototype%]]. + 1. Let |susp| be the result of [$OrdinaryObjectCreate$](|suspendingProto|,«\[[WrappedFunction]]»). + 1. Set |susp|.\[[WrappedFunction]] to |jsFun|. + 1. Return |susp|. +
+ +
+To create a suspending function from a JavaScript function |func|, with type |functype| perform the following steps: + + 1. Assert: [$IsCallable$](|func|). + 1. Let |stored settings| be the incumbent settings object. + 1. Let |hostfunc| be a [=host function=] which performs the following steps when called with arguments |arguments|: + 1. Let |realm| be |func|'s [=associated Realm=]. + 1. Let |relevant settings| be |realm|'s [=realm/settings object=]. + 1. Let |async_context| be the [=surrounding agent=]'s [=running execution context=]. + 1. Let |map| be the [=surrounding agent=]'s associated [=Execution Context Status map=]. + 1. If the entry for |async_context| in |map| is not [=active=], then: + 1. Perform [=throw a JavaScript exception=] with a {{RuntimeError}} exception. + 1. [=Prepare to run script=] with |relevant settings|. + 1. [=Prepare to run a callback=] with |stored settings|. + 1. Let [|parameters|] → [|resultTypes|] be |functype|. + 1. Let |jsArguments| be the result of [=coerce WebAssembly arguments=](|parameters|,|arguments|). + 1. Let |ret| be [$Completion$]([$Call$](|func|, undefined, |jsArguments|)). + 1. [=Clean up after running a callback=] with |stored settings|. + 1. [=Clean up after running script=] with |relevant settings|. + 1. Assert: |ret|.\[[Type]] is throw or normal. + 1. If |ret|.\[[Type]] is throw, then: + 1. Let |type|, |payload| and |opaqueData| be the result of [=coerce a JavaScript exception|coercing the JavaScript exception=] |ret|.\[[Value]]. + 1. [=WebAssembly/Throw=] with |type|, |payload| and |opaqueData|. + 1. Otherwise, if [=list/size=] of |ret| is 1 and [$IsPromise$](|ret|.\[[Value]][0]): + 1. Let |promise| be |ret|.\[[Value]][0]. + 1. Set the entry for |async_context| in |map| to [=paused=]. + 1. Let |awaitResult| be the result of performing [$Completion$]([$Await$](|promise|)). + 1. Note: We only invoke [$Await$] if the call to |func| has returned a Promise object. + 1. Note: This will suspend both this algorithm, and the WebAssembly function being invoked by the [=evaluate a Promising function=] algorithm. On return, |ret| will be either a normal completion or a throw completion. + 1. If the entry for |async_context| in |map| is not [=paused=] then: + 1. Perform [=throw a JavaScript exception=] with a {{RuntimeError}}. + 1. Otherwise, set the entry to [=active=]. + 1. If |awaitResult|.\[[Type]] is throw, then: + 1. Let |type|, |payload| and |opaqueData| be the result of [=coerce a JavaScript exception|coercing the JavaScript exception=] |ret|.\[[Value]]. + 1. [=WebAssembly/Throw=] with |type|, |payload| and |opaqueData|. + 1. Otherwise, return the result of performing [=coerce a JavaScript return=] on |resultTypes| and |awaitResult|. + 1. Otherwise, return the result of performing [=coerce a JavaScript return=] on |resultTypes| and |ret|. + 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. + 1. Let (|store|, |funcaddr|) be [=func_alloc=](|store|, |functype|, |hostfunc|). + 1. Set the [=surrounding agent=]'s [=associated store=] to |store|. + 1. Return |funcaddr|. +

Tags

@@ -1561,7 +1739,7 @@ constructor steps are: 1. If |resultType| is [=v128=] or [=exnref=], 1. Throw a {{TypeError}}. 1. [=list/Append=] [=?=] [=ToWebAssemblyValue=](|value|, |resultType|) to |wasmPayload|. -1. Let (|store|, |exceptionAddr|) be [=exn_alloc=](|store|, |exceptionTag|.\[[Address]], |wasmPayload|) +1. Let (|store|, |exceptionAddr|) be [=exn_alloc=](|store|, |exceptionTag|.\[[Address]], |wasmPayload|). 1. Set the [=surrounding agent=]'s [=associated store=] to |store|. 1. [=initialize an Exception object|Initialize=] **this** from |exceptionAddr|. 1. If |options|["traceStack"] is true, @@ -1617,7 +1795,7 @@ first use and cached. It always has the [=tag type=] « [=externref=] » → « To get the JavaScript exception tag, perform the following steps: 1. If the [=surrounding agent=]'s associated [=JavaScript exception tag=] has been initialized, - 1. return the [=surrounding agent=]'s associated [=JavaScript exception tag=] + 1. return the [=surrounding agent=]'s associated [=JavaScript exception tag=]. 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. 1. Let (|store|, |tagAddress|) be [=tag_alloc=](|store|, « [=externref=] » → « »). 1. Set the current agent's [=associated store=] to |store|.