Skip to content

Commit c97651f

Browse files
authored
Update JS API for exnref (#301)
This change updates exception object allocation, initialization, and construction for exnref; as well as dealing with exception propagation from invoking exported functions; throwing exceptions from host functions into wasm; and wrapping and unwrapping JS exceptions as they propagate into and out of wasm.
1 parent 153ca9a commit c97651f

File tree

1 file changed

+75
-54
lines changed

1 file changed

+75
-54
lines changed

document/js-api/index.bs

+75-54
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ urlPrefix: https://webassembly.github.io/exception-handling/core/; spec: WebAsse
6464
text: ref.null
6565
text: ref.func
6666
text: ref.extern
67+
text: ref.exn
6768
text: function index; url: syntax/modules.html#syntax-funcidx
6869
text: function instance; url: exec/runtime.html#function-instances
6970
text: store_init; url: appendix/embedding.html#embed-store-init
@@ -101,6 +102,12 @@ urlPrefix: https://webassembly.github.io/exception-handling/core/; spec: WebAsse
101102
text: global address; url: exec/runtime.html#syntax-globaladdr
102103
text: extern address; url: exec/runtime.html#syntax-externaddr
103104
text: tag address; url: exec/runtime.html#syntax-tagaddr
105+
text: tag_alloc; url: appendix/embedding.html#embed-tag-alloc
106+
text: tag_type; url: appendix/embedding.html#embed-tag-type
107+
text: exception address; url: exec/runtime.html#syntax-exnaddr
108+
text: exn_alloc; url: appendix/embedding.html#embed-exn-alloc
109+
text: exn_read; url: appendix/embedding.html#embed-exn-read
110+
text: tag type; url: syntax/types.html#syntax-tagtype
104111
url: syntax/types.html#syntax-numtype
105112
text: i32
106113
text: i64
@@ -145,6 +152,7 @@ urlPrefix: https://webassembly.github.io/exception-handling/core/; spec: WebAsse
145152
text: address; url: exec/runtime.html#addresses
146153
text: signed_32; url: exec/numerics.html#aux-signed
147154
text: memory.grow; url: exec/instructions.html#exec-memory-grow
155+
text: throw_ref; url: exec/instructions.html#exec-throw-ref
148156
text: current frame; url: exec/conventions.html#exec-notation-textual
149157
text: module; for: frame; url: exec/runtime.html#syntax-frame
150158
text: memaddrs; for: moduleinst; url: exec/runtime.html#syntax-moduleinst
@@ -238,6 +246,8 @@ Each [=agent=] is associated with the following [=ordered map=]s:
238246
* The <dfn>Global object cache</dfn>, mapping [=global address=]es to {{Global}} objects.
239247
* The <dfn>Extern value cache</dfn>, mapping [=extern address=]es to values.
240248
* The <dfn>Tag object cache</dfn>, mapping [=tag addresses=] to {{Tag}} objects.
249+
* The <dfn>Exception object cache</dfn>, mapping [=exception address=]es to {{Exception}} objects.
250+
241251

242252
<h2 id="webassembly-namespace">The WebAssembly Namespace</h2>
243253

@@ -760,7 +770,7 @@ Each {{Table}} object has a \[[Table]] internal slot, which is a [=table address
760770
The <dfn constructor for="Table">Table(|descriptor|, |value|)</dfn> constructor, when invoked, performs the following steps:
761771
1. Let |elementType| be [=ToValueType=](|descriptor|["element"]).
762772
1. If |elementType| is not a [=reftype=],
763-
1. [=Throw=] a {{TypeError}} exception.
773+
1. Throw a {{TypeError}} exception.
764774
1. Let |initial| be |descriptor|["initial"].
765775
1. If |descriptor|["maximum"] [=map/exists=], let |maximum| be |descriptor|["maximum"]; otherwise, let |maximum| be empty.
766776
1. If |maximum| is not empty and |maximum| &lt; |initial|, throw a {{RangeError}} exception.
@@ -807,7 +817,7 @@ Each {{Table}} object has a \[[Table]] internal slot, which is a [=table address
807817
1. Let |store| be the [=surrounding agent=]'s [=associated store=].
808818
1. Let (<var ignore>limits</var>, |elementType|) be [=table_type=](|store|, |tableaddr|).
809819
1. If |elementType| is [=exnref=],
810-
1. [=Throw=] a {{TypeError}} exception.
820+
1. Throw a {{TypeError}} exception.
811821
1. Let |result| be [=table_read=](|store|, |tableaddr|, |index|).
812822
1. If |result| is [=error=], throw a {{RangeError}} exception.
813823
1. Return [=ToJSValue=](|result|).
@@ -819,7 +829,7 @@ Each {{Table}} object has a \[[Table]] internal slot, which is a [=table address
819829
1. Let |store| be the [=surrounding agent=]'s [=associated store=].
820830
1. Let (<var ignore>limits</var>, |elementType|) be [=table_type=](|store|, |tableaddr|).
821831
1. If |elementType| is [=exnref=],
822-
1. [=Throw=] a {{TypeError}} exception.
832+
1. Throw a {{TypeError}} exception.
823833
1. If |value| is missing,
824834
1. Let |ref| be [=DefaultValue=](|elementType|).
825835
1. Otherwise,
@@ -1011,15 +1021,16 @@ This slot holds a [=function address=] relative to the [=surrounding agent=]'s [
10111021
1. [=list/Append=] [=ToWebAssemblyValue=](|arg|, |t|) to |args|.
10121022
1. Set |i| to |i| + 1.
10131023
1. Let (|store|, |ret|) be the result of [=func_invoke=](|store|, |funcaddr|, |args|).
1014-
1. Note: The expectation is that [=func_invoke=] will be updated to return (|store|, <var ignore>val</var>* | [=error=] | (exception |exntag| |payload| |opaqueData|)).
10151024
1. Set the [=surrounding agent=]'s [=associated store=] to |store|.
10161025
1. If |ret| is [=error=], throw an exception. This exception should be a WebAssembly {{RuntimeError}} exception, unless otherwise indicated by <a href="#errors">the WebAssembly error mapping</a>.
1017-
1. If |ret| is exception |exntag| |payload| |opaqueData|, then
1018-
1. If |opaqueData| is not [=ref.null=] [=externref=],
1019-
1. Let « [=ref.extern=] |externaddr| » be |opaqueData|.
1020-
1. Throw the result of [=retrieving an extern value=] from |externaddr|.
1021-
1. Let |exception| be [=create an Exception object|a new Exception=] for |exntag| and |payload|.
1022-
1. Throw |exception|.
1026+
1. If |ret| is [=THROW=] [=ref.exn=] |exnaddr|, then
1027+
1. Let (|tagaddr|, |payload|) be [=exn_read=](|store|, |exnaddr|).
1028+
1. Let |jsTagAddr| be the result of [=get the JavaScript exception tag |getting the JavaScript exception tag=].
1029+
1. If |tagaddr| is equal to |jsTagAddr|,
1030+
1. Throw the result of [=retrieving an extern value=] from |payload|[0].
1031+
1. Otherwise,
1032+
1. Let |exception| be [=create an Exception object|a new Exception=] created from |exnaddr|.
1033+
1. Throw |exception|.
10231034
1. Let |outArity| be the [=list/size=] of |ret|.
10241035
1. If |outArity| is 0, return undefined.
10251036
1. Otherwise, if |outArity| is 1, return [=ToJSValue=](|ret|[0]).
@@ -1048,7 +1059,7 @@ Note: Exported Functions do not have a \[[Construct]] method and thus it is not
10481059
1. Otherwise, if |resultsSize| is 1, return « [=?=] [=ToWebAssemblyValue=](|ret|, |results|[0]) ».
10491060
1. Otherwise,
10501061
1. Let |method| be [=?=] [$GetMethod$](|ret|, {{@@iterator}}).
1051-
1. If |method| is undefined, [=throw=] a {{TypeError}}.
1062+
1. If |method| is undefined, throw a {{TypeError}}.
10521063
1. Let |values| be [=?=] [$IterableToList$](|ret|, |method|).
10531064
1. Let |wasmValues| be a new, empty [=list=].
10541065
1. If |values|'s [=list/size=] is not |resultsSize|, throw a {{TypeError}} exception.
@@ -1071,18 +1082,18 @@ Note: Exported Functions do not have a \[[Construct]] method and thus it is not
10711082
1. [=Clean up after running a callback=] with |stored settings|.
10721083
1. [=Clean up after running script=] with |relevant settings|.
10731084
1. Assert: |result|.\[[Type]] is <emu-const>throw</emu-const> or <emu-const>normal</emu-const>.
1085+
1. Let |store| be the [=surrounding agent=]'s [=associated store=].
10741086
1. If |result|.\[[Type]] is <emu-const>throw</emu-const>, then:
10751087
1. Let |v| be |result|.\[[Value]].
10761088
1. If |v| [=implements=] {{Exception}},
1077-
1. Let |type| be |v|.\[[Type]].
1078-
1. Let |payload| be |v|.\[[Payload]].
1089+
1. Let |address| be |v|.\[[Address]].
10791090
1. Otherwise,
1080-
1. Let |type| be the [=JavaScript exception tag=].
1081-
1. Let |payload| be « ».
1082-
1. Let |opaqueData| be [=ToWebAssemblyValue=](|v|, [=externref=])
1083-
1. [=WebAssembly/Throw=] with |type|, |payload| and |opaqueData|.
1091+
1. Let |type| be the result of [=get the JavaScript exception tag |getting the JavaScript exception tag=].
1092+
1. Let |payload| be [=!=] [=ToWebAssemblyValue=](|v|, [=externref=]).
1093+
1. Let (|store|, |address|) be [=exn_alloc=](|store|, |type|, « |payload| »).
1094+
1. Set the [=surrounding agent=]'s [=associated store=] to |store|.
1095+
1. Execute the WebAssembly instructions ([=ref.exn=] |address|) ([=throw_ref=]).
10841096
1. Otherwise, return |result|.\[[Value]].
1085-
1. Let |store| be the [=surrounding agent=]'s [=associated store=].
10861097
1. Let (|store|, |funcaddr|) be [=func_alloc=](|store|, |functype|, |hostfunc|).
10871098
1. Set the [=surrounding agent=]'s [=associated store=] to |store|.
10881099
1. Return |funcaddr|.
@@ -1171,10 +1182,6 @@ The algorithm <dfn>ToWebAssemblyValue</dfn>(|v|, |type|) coerces a JavaScript va
11711182

11721183
<h3 id="tags">Tags</h3>
11731184

1174-
The <dfn>tag_alloc</dfn>(|store|, |parameters|) algorithm creates a new [=tag address=] for |parameters| in |store| and returns the updated store and the [=tag address=].
1175-
1176-
The <dfn>tag_parameters</dfn>(|store|, |tagAddress|) algorithm returns the [=list=] of types for |tagAddress| in |store|.
1177-
11781185
<h4 id="exceptions-types">Exception types</h4>
11791186

11801187
<pre class="idl">
@@ -1235,7 +1242,7 @@ The <dfn constructor for="Tag" lt="Tag(type)">new Tag(|type|)</dfn> constructor
12351242
The <dfn method for="Tag">type()</dfn> method steps are:
12361243

12371244
1. Let |store| be the [=surrounding agent=]'s [=associated store=].
1238-
1. Let |parameters| be [=tag_parameters=](|store|, **this**.\[[Address]]).
1245+
1. Let [|parameters|] → [] be [=tag_type=](|store|, **this**.\[[Address]]).
12391246
1. Let |idlParameters| be «».
12401247
1. [=list/iterate|For each=] |type| of |parameters|,
12411248
1. [=list/Append=] [$FromValueType$](|type|) to |idlParameters|.
@@ -1255,7 +1262,7 @@ dictionary ExceptionOptions {
12551262
[LegacyNamespace=WebAssembly, Exposed=(Window,Worker,Worklet)]
12561263
interface Exception {
12571264
constructor(Tag exceptionTag, sequence&lt;any> payload, optional ExceptionOptions options = {});
1258-
any getArg(Tag exceptionTag, [EnforceRange] unsigned long index);
1265+
any getArg([EnforceRange] unsigned long index);
12591266
boolean is(Tag exceptionTag);
12601267
readonly attribute (DOMString or undefined) stack;
12611268
};
@@ -1265,19 +1272,31 @@ An {{Exception}} value represents an exception.
12651272

12661273
<div algorithm>
12671274

1268-
To <dfn>create an Exception object</dfn> from a [=tag address=] |tagAddress| and a [=list=] of
1269-
WebAssembly values |payload|, perform the following steps:
1275+
To <dfn>initialize an Exception object</dfn> |exn| from an [=Exception address=] |exnAddress|, perform the following steps:
12701276

1277+
1. Let |map| be the [=surrounding agent=]'s associated [=Exception object cache=].
1278+
1. Assert: |map|[|exnAddress|] doesn't [=map/exist=].
1279+
1. Set |exn|.\[[Address]] to |exnAddress|.
1280+
1. [=map/Set=] |map|[|exnAddress|] to |exn|.
12711281
1. Let |store| be the [=surrounding agent=]'s [=associated store=].
1272-
1. Let |types| be [=tag_parameters=](|store|, |tagAddress|).
1273-
1. Assert: |types|'s [=list/size=] is |payload|'s [=list/size=].
1274-
1. [=list/iterate|For each=] |value| and |resultType| of |payload| and |types|, paired linearly,
1275-
1. Assert: |value|'s type matches |resultType|.
1276-
1. Let |exception| be a [=new=] {{Exception}}.
1277-
1. Set |exception|.\[[Type]] to |tagAddress|.
1278-
1. Set |exception|.\[[Payload]] to |payload|.
1279-
1. Set |exception|.\[[Stack]] to undefined.
1280-
1. Return |exception|.
1282+
1. Let (|tagaddr|, |payload|) be [=exn_read=](|store|, |exnAddress|).
1283+
1. Set |exn|.\[[Type]] to |tagaddr|.
1284+
1. Set |exn|.\[[Payload]] to |payload|.
1285+
1. Set |exn|.\[[Stack]] to undefined.
1286+
1287+
</div>
1288+
1289+
<div algorithm>
1290+
1291+
To <dfn>create an Exception object</dfn> from a [=exception address=] |exnAddress|, perform the following steps:
1292+
1293+
1. Let |map| be the [=surrounding agent=]'s associated [=Exception object cache=].
1294+
1. If |map|[|exnAddress|] [=map/exists=],
1295+
1. Return |map|[|exnAddress|].
1296+
1. Let |exn| be a [=new=] {{Exception}}.
1297+
1. [=initialize an Exception object|Initialize=] |exn| from |exnAddress|.
1298+
1. Return |exn|.
1299+
12811300

12821301
</div>
12831302

@@ -1288,28 +1307,28 @@ lt="Exception(exceptionTag, payload, options)">new Exception(|exceptionTag|, |pa
12881307
constructor steps are:
12891308

12901309
1. Let |store| be the [=surrounding agent=]'s [=associated store=].
1291-
1. Let |types| be [=tag_parameters=](|store|, |exceptionTag|.\[[Address]]).
1310+
1. Let [|types|] → [] be [=tag_type=](|store|, |exceptionTag|.\[[Address]]).
12921311
1. If |types|'s [=list/size=] is not |payload|'s [=list/size=],
12931312
1. Throw a {{TypeError}}.
12941313
1. Let |wasmPayload| be « ».
12951314
1. [=list/iterate|For each=] |value| and |resultType| of |payload| and |types|, paired linearly,
1296-
1. [=list/Append=] ? [=ToWebAssemblyValue=](|value|, |resultType|) to |wasmPayload|.
1297-
1. Set **this**.\[[Type]] to |exceptionTag|.\[[Address]].
1298-
1. Set **this**.\[[Payload]] to |wasmPayload|.
1315+
1. [=list/Append=] [=?=] [=ToWebAssemblyValue=](|value|, |resultType|) to |wasmPayload|.
1316+
1. Let (|store|, |exceptionAddr|) be [=exn_alloc=](|store|, |exceptionTag|.\[[Address]], |wasmPayload|)
1317+
1. Set the [=surrounding agent=]'s [=associated store=] to |store|.
1318+
1. [=initialize an Exception object|Initialize=] **this** from |exceptionAddr|.
12991319
1. If |options|["traceStack"] is true,
13001320
1. Set **this**.\[[Stack]] to either a {{DOMString}} representation of the current call stack or undefined.
1301-
1. Otherwise,
1302-
1. Set **this**.\[[Stack]] to undefined.
1321+
13031322

13041323
</div>
13051324

13061325
<div algorithm>
13071326

1308-
The <dfn method for="Exception">getArg(|exceptionTag|, |index|)</dfn> method steps are:
1327+
The <dfn method for="Exception">getArg(|index|)</dfn> method steps are:
13091328

1310-
1. If **this**.\[[Type]] is not equal to |exceptionTag|.\[[Address]],
1311-
1. Throw a {{TypeError}}.
1312-
1. Let |payload| be **this**.\[[Payload]].
1329+
1. Let |store| be the [=surrounding agent=]'s [=associated store=].
1330+
1. Let (|tagaddr|, |payload|) be [=exn_read=](|store|, **this**.\[[Address]]).
1331+
1. Assert: |tagaddr| is equal to **this**.\[[Type]].
13131332
1. If |index| ≥ |payload|'s [=list/size=],
13141333
1. Throw a {{RangeError}}.
13151334
1. Return [=ToJSValue=](|payload|[|index|]).
@@ -1336,20 +1355,22 @@ The <dfn attribute for="Exception">stack</dfn> getter steps are:
13361355

13371356
<h4 id="js-exceptions">JavaScript exceptions</h4>
13381357

1339-
The <dfn>JavaScript exception tag</dfn> is a [=tag address=] reserved by this
1340-
specification to distinguish exceptions originating from JavaScript.
1358+
The <dfn>JavaScript exception tag</dfn> is a [=tag address=] associated with
1359+
the surrounding agent. It is allocated in the agent's [=associated store=] on
1360+
first use and cached. It always has the [=tag type=] « [=externref=] » → « ».
13411361

1342-
For any [=associated store=] |store|, the result of
1343-
[=tag_parameters=](|store|, [=JavaScript exception tag=]) must be « ».
13441362

13451363
<div algorithm>
13461364

1347-
To <dfn for=WebAssembly>throw</dfn> with a [=tag address=] |type|, a matching [=list=] of WebAssembly values |payload|, and an [=externref=] |opaqueData|, perform the following steps:
1348-
1349-
1. Unwind the stack until reaching the *catching try block* given |type|.
1350-
1. Invoke the catch block with |payload| and |opaqueData|.
1365+
To <dfn>get the JavaScript exception tag</dfn>, perform the following steps:
13511366

1352-
Note: This algorithm is expected to be moved into the core specification.
1367+
1. If the [=surrounding agent=]'s associated [=JavaScript exception tag=] has been initialized,
1368+
1. return the [=surrounding agent=]'s associated [=JavaScript exception tag=]
1369+
1. Let |store| be the [=surrounding agent=]'s [=associated store=].
1370+
1. Let (|store|, |tagAddress|) be [=tag_alloc=](|store|, « [=externref=] » → « »).
1371+
1. Set the current agent's [=associated store=] to |store|.
1372+
1. Set the current agent's associated [=JavaScript exception tag=] to |tagAddress|.
1373+
1. return |tagAddress|.
13531374

13541375
</div>
13551376

0 commit comments

Comments
 (0)