Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update JS API for exnref #301

Merged
merged 22 commits into from
Apr 11, 2024
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 73 additions & 6 deletions document/core/appendix/embedding.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,19 @@ For numeric parameters, notation like :math:`n:\u32` is used to specify a symbol

.. _embed-error:

Errors
~~~~~~
Exceptions and Errors
~~~~~~~~~~~~~~~~~~~~~

Failure of an interface operation is indicated by an auxiliary syntactic class:
Invoking an exported function may throw or propagate exceptions, expressed by an auxiliary syntactic class:

.. math::
\begin{array}{llll}
\production{exception} & \exception &::=& \ETHROW ~ \exnaddr \\
\end{array}

The exception instance :math:`exnaddr` identifies the exception thrown.

Failure of an interface operation is also indicated by an auxiliary syntactic class:

.. math::
\begin{array}{llll}
Expand All @@ -43,6 +52,8 @@ In addition to the error conditions specified explicitly in this section, implem
Implementations can refine it to carry suitable classifications and diagnostic messages.




Pre- and Post-Conditions
~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down Expand Up @@ -293,21 +304,24 @@ Functions
.. index:: invocation, value, result
.. _embed-func-invoke:

:math:`\F{func\_invoke}(\store, \funcaddr, \val^\ast) : (\store, \val^\ast ~|~ \error)`
........................................................................................
:math:`\F{func\_invoke}(\store, \funcaddr, \val^\ast) : (\store, \val^\ast ~|~ \exception ~|~ \error)`
......................................................................................................

1. Try :ref:`invoking <exec-invocation>` the function :math:`\funcaddr` in :math:`\store` with :ref:`values <syntax-val>` :math:`\val^\ast` as arguments:

a. If it succeeds with :ref:`values <syntax-val>` :math:`{\val'}^\ast` as results, then let :math:`\X{result}` be :math:`{\val'}^\ast`.

b. Else it has trapped, hence let :math:`\X{result}` be :math:`\ERROR`.
b. Else if the outcome is an exception with a thrown :ref:`exception <exec-throw_ref>` :math:`\REFEXNADDR~\exnaddr` as the result, then let :math:`\X{result}` be :math:`\ETHROW~\exnaddr`

c. Else it has trapped, hence let :math:`\X{result}` be :math:`\ERROR`.

2. Return the new store paired with :math:`\X{result}`.

.. math::
~ \\
\begin{array}{lclll}
\F{func\_invoke}(S, a, v^\ast) &=& (S', {v'}^\ast) && (\iff \invoke(S, a, v^\ast) \stepto^\ast S'; F; {v'}^\ast) \\
\F{func\_invoke}(S, a, v^\ast) &=& (S', \ETHROW~a') && (\iff \invoke(S, a, v^\ast) \stepto^\ast S'; F; \XT[(\REFEXNADDR~\exnaddr)~\THROWREF] \\
\F{func\_invoke}(S, a, v^\ast) &=& (S', \ERROR) && (\iff \invoke(S, a, v^\ast) \stepto^\ast S'; F; \TRAP) \\
\end{array}

Expand Down Expand Up @@ -562,6 +576,59 @@ Tags
\end{array}


.. _embed-tag-type:

:math:`\F{tag\_type}(\store, \tagaddr) : \tagtype`
........................................................

1. Return :math:`S.\STAGS[a].\TAGITYPE`.

2. Post-condition: the returned :ref:`tag type <syntax-tagtype>` is :ref:`valid <valid-tagtype>`.

.. math::
\begin{array}{lclll}
\F{tag\_type}(S, a) &=& S.\STAGS[a].\TAGITYPE \\
\end{array}


.. index:: exception, exception address, store, exception instance, exception type
.. _embed-exception:

Exceptions
~~~~~~~~~~

.. _embed-exn-alloc:

:math:`\F{exn\_alloc}(\store, \tagaddr, \val^\ast) : (\store, \exnaddr)`
............................................................................

1. Pre-condition: :math:`\tagaddr` is an allocated :ref:`tag address <syntax-tagaddr>`.

2. Let :math:`\exnaddr` be the result of :ref:`allocating an exception <alloc-exception>` in :math:`\store` with :ref:`tag address <syntax-tagaddr>` :math:`\tagaddr` and initialization values :math:`\val^\ast`.

3. Return the new store paired with :math:`\exnaddr`.

.. math::
\begin{array}{lclll}
\F{exn\_alloc}(S, \tagaddr, \val^\ast) &=& (S', a) && (\iff \allocexn(S, \tagaddr, \val^\ast) = S', a) \\
\end{array}


.. _embed-exn-read:

:math:`\F{exn\_read}(\store, \exnaddr) : (\tagaddr, \val^\ast)`
......................................................................

1. Let :math:`\X{ei}` be the :ref:`exception instance <syntax-exninst>` :math:`\store.\SEXNS[\exnaddr]`.

2. Return the :ref:`tag address <syntax-tagaddr>` :math:`\X{ei}.\EITAG~\tagaddr` paired with :ref:`values <syntax-val>` :math:`\X{ei}.\EIFIELDS~\val^\ast`.

.. math::
\begin{array}{lcll}
\F{exn\_read}(S, a) &=& (a', v^\ast) \\
\end{array}


.. index:: global, global address, store, global instance, global type, value
.. _embed-global:

Expand Down
16 changes: 7 additions & 9 deletions document/core/exec/instructions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2719,27 +2719,25 @@ Control Instructions

2. Assert: due to :ref:`validation <valid-throw>`, :math:`F.\AMODULE.\MITAGS[x]` exists.

3. Let :math:`a` be the :ref:`tag address <syntax-tagaddr>` :math:`F.\AMODULE.\MITAGS[x]`.
3. Let :math:`ta` be the :ref:`tag address <syntax-tagaddr>` :math:`F.\AMODULE.\MITAGS[x]`.

4. Assert: due to :ref:`validation <valid-throw>`, :math:`S.\STAGS[a]` exists.
4. Assert: due to :ref:`validation <valid-throw>`, :math:`S.\STAGS[ta]` exists.

5. Let :math:`\X{ti}` be the :ref:`tag instance <syntax-taginst>` :math:`S.\STAGS[a]`.
5. Let :math:`\X{ti}` be the :ref:`tag instance <syntax-taginst>` :math:`S.\STAGS[ta]`.

6. Let :math:`[t^n] \toF [{t'}^\ast]` be the :ref:`tag type <syntax-tagtype>` :math:`\X{ti}.\TAGITYPE`.

7. Assert: due to :ref:`validation <valid-throw>`, there are at least :math:`n` values on the top of the stack.

8. Pop the :math:`n` values :math:`\val^n` from the stack.

9. Let :math:`\X{exn}` be the :ref:`exception instance <syntax-exninst>` :math:`\{ \EITAG~a, \EIFIELDS~\val^n \}`.
9. Let :math:`\X{ea}` be the :ref:`exception address <syntax-exnaddr>` resulting from :ref:`allocating <alloc-exception>` an exception instance with tag address :math:`ta` and initializer values :math:`\val^n`.

10. Let :math:`\X{ea}` be the length of :math:`S.\SEXNS`.
10. Let :math:`\X{exn}` be :math:`S.\SEXNS[ea]`

11. Append :math:`\X{exn}` to :math:`S.\SEXNS`.
11. Push the value :math:`\REFEXNADDR~\X{ea}` to the stack.

12. Push the value :math:`\REFEXNADDR~\X{ea}` to the stack.

13. Execute the instruction |THROWREF|.
12. Execute the instruction |THROWREF|.

.. math::
~\\[-1ex]
Expand Down
28 changes: 27 additions & 1 deletion document/core/exec/modules.rst
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ The following auxiliary typing rules specify this typing relation relative to a
Allocation
~~~~~~~~~~

New instances of :ref:`functions <syntax-funcinst>`, :ref:`tables <syntax-tableinst>`, :ref:`memories <syntax-meminst>`, :ref:`tags <syntax-taginst>`, and :ref:`globals <syntax-globalinst>` are *allocated* in a :ref:`store <syntax-store>` :math:`S`, as defined by the following auxiliary functions.
New instances of :ref:`functions <syntax-funcinst>`, :ref:`tables <syntax-tableinst>`, :ref:`memories <syntax-meminst>`, :ref:`tags <syntax-taginst>`, :ref:`exceptions <syntax-exninst>`, and :ref:`globals <syntax-globalinst>` are *allocated* in a :ref:`store <syntax-store>` :math:`S`, as defined by the following auxiliary functions.


.. index:: function, function instance, function address, module instance, function type
Expand Down Expand Up @@ -338,6 +338,32 @@ New instances of :ref:`functions <syntax-funcinst>`, :ref:`tables <syntax-tablei
\end{array}


.. index:: exception, exception instance, exception address, tag address
.. _alloc-exception:

:ref:`Exceptions <syntax-exninst>`
..................................

1. Let :math:`ta` be the :ref:`tag address <syntax-tagaddr>` associated with the exception to allocate and :math:`\EIFIELDS~\val^\ast` be the values to initialize the exception with.

2. Let :math:`a` be the first free :ref:`exception address <syntax-exnaddr>` in :math:`S`.

3. Let :math:`\exninst` be the :ref:`exception instance <syntax-exninst>` :math:`\{ \EITAG~ta, \EIFIELDS~\val^\ast \}`.

4. Append :math:`\exninst` to the |SEXNS| of :math:`S`.

5. Return :math:`a`.

.. math::
\begin{array}{rlll}
\allocexn(S, \tagaddr, \val^\ast) &=& S', \exnaddr \\[1ex]
\mbox{where:} \hfill \\
\exnaddr &=& |S.\SEXNS| \\
\exninst &=& \{ \EITAG~\tagaddr, \EIFIELDS~\val^\ast \} \\
S' &=& S \compose \{\SEXNS~\exninst\} \\
\end{array}


.. index:: global, global instance, global address, global type, value type, mutability, value
.. _alloc-global:

Expand Down
3 changes: 3 additions & 0 deletions document/core/util/macros.def
Original file line number Diff line number Diff line change
Expand Up @@ -981,6 +981,7 @@
.. |alloctable| mathdef:: \xref{exec/modules}{alloc-table}{\F{alloctable}}
.. |allocmem| mathdef:: \xref{exec/modules}{alloc-mem}{\F{allocmem}}
.. |alloctag| mathdef:: \xref{exec/modules}{alloc-tag}{\F{alloctag}}
.. |allocexn| mathdef:: \xref{exec/modules}{alloc-exception}{\F{allocexn}}
.. |allocglobal| mathdef:: \xref{exec/modules}{alloc-global}{\F{allocglobal}}
.. |allocelem| mathdef:: \xref{exec/modules}{alloc-elem}{\F{allocelem}}
.. |allocdata| mathdef:: \xref{exec/modules}{alloc-data}{\F{allocdata}}
Expand Down Expand Up @@ -1335,3 +1336,5 @@

.. |error| mathdef:: \xref{appendix/embedding}{embed-error}{\X{error}}
.. |ERROR| mathdef:: \xref{appendix/embedding}{embed-error}{\K{error}}
.. |exception| mathdef:: \xref{appendix/embedding}{embed-error}{\X{exception}}
.. |ETHROW| mathdef:: \xref{appendix/embedding}{embed-error}{\K{THROW}}
69 changes: 41 additions & 28 deletions document/js-api/index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ urlPrefix: https://webassembly.github.io/exception-handling/core/; spec: WebAsse
text: ref.null
text: ref.func
text: ref.extern
text: ref.exn
text: function index; url: syntax/modules.html#syntax-funcidx
text: function instance; url: exec/runtime.html#function-instances
text: store_init; url: appendix/embedding.html#embed-store-init
Expand Down Expand Up @@ -101,6 +102,9 @@ urlPrefix: https://webassembly.github.io/exception-handling/core/; spec: WebAsse
text: global address; url: exec/runtime.html#syntax-globaladdr
text: extern address; url: exec/runtime.html#syntax-externaddr
text: tag address; url: exec/runtime.html#syntax-tagaddr
text: exception address; url: exec/runtime.html#syntax-exnaddr
text: exn_alloc; url: appendix/embedding.html#embed-exn-alloc
text: exn_read; url: appendix/embedding.html#embed-exn-read
url: syntax/types.html#syntax-numtype
text: i32
text: i64
Expand Down Expand Up @@ -238,6 +242,8 @@ Each [=agent=] is associated with the following [=ordered map=]s:
* The <dfn>Global object cache</dfn>, mapping [=global address=]es to {{Global}} objects.
* The <dfn>Extern value cache</dfn>, mapping [=extern address=]es to values.
* The <dfn>Tag object cache</dfn>, mapping [=tag addresses=] to {{Tag}} objects.
* The <dfn>Exception object cache</dfn>, mapping [=exception address=]es to {{Exception}} objects.


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

Expand Down Expand Up @@ -760,7 +766,7 @@ Each {{Table}} object has a \[[Table]] internal slot, which is a [=table address
The <dfn constructor for="Table">Table(|descriptor|, |value|)</dfn> constructor, when invoked, performs the following steps:
1. Let |elementType| be [=ToValueType=](|descriptor|["element"]).
1. If |elementType| is not a [=reftype=],
1. [=Throw=] a {{TypeError}} exception.
1. Throw a {{TypeError}} exception.
dschuff marked this conversation as resolved.
Show resolved Hide resolved
1. Let |initial| be |descriptor|["initial"].
1. If |descriptor|["maximum"] [=map/exists=], let |maximum| be |descriptor|["maximum"]; otherwise, let |maximum| be empty.
1. If |maximum| is not empty and |maximum| &lt; |initial|, throw a {{RangeError}} exception.
Expand Down Expand Up @@ -1011,14 +1017,10 @@ This slot holds a [=function address=] relative to the [=surrounding agent=]'s [
1. [=list/Append=] [=ToWebAssemblyValue=](|arg|, |t|) to |args|.
1. Set |i| to |i| + 1.
1. Let (|store|, |ret|) be the result of [=func_invoke=](|store|, |funcaddr|, |args|).
1. Note: The expectation is that [=func_invoke=] will be updated to return (|store|, <var ignore>val</var>* | [=error=] | (exception |exntag| |payload| |opaqueData|)).
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 <a href="#errors">the WebAssembly error mapping</a>.
1. If |ret| is exception |exntag| |payload| |opaqueData|, then
1. If |opaqueData| is not [=ref.null=] [=externref=],
1. Let « [=ref.extern=] |externaddr| » be |opaqueData|.
1. Throw the result of [=retrieving an extern value=] from |externaddr|.
1. Let |exception| be [=create an Exception object|a new Exception=] for |exntag| and |payload|.
1. If |ret| is [=THROW=] [=ref.exn=] |exnaddr|, then
1. Let |exception| be [=create an Exception object|a new Exception=] created from |exnaddr|.
1. Throw |exception|.
1. Let |outArity| be the [=list/size=] of |ret|.
1. If |outArity| is 0, return undefined.
Expand Down Expand Up @@ -1048,7 +1050,7 @@ Note: Exported Functions do not have a \[[Construct]] method and thus it is not
1. Otherwise, if |resultsSize| is 1, return « [=?=] [=ToWebAssemblyValue=](|ret|, |results|[0]) ».
1. Otherwise,
1. Let |method| be [=?=] [$GetMethod$](|ret|, {{@@iterator}}).
1. If |method| is undefined, [=throw=] a {{TypeError}}.
1. If |method| is undefined, throw a {{TypeError}}.
1. Let |values| be [=?=] [$IterableToList$](|ret|, |method|).
1. Let |wasmValues| be a new, empty [=list=].
1. If |values|'s [=list/size=] is not |resultsSize|, throw a {{TypeError}} exception.
Expand Down Expand Up @@ -1264,20 +1266,31 @@ interface Exception {
An {{Exception}} value represents an exception.

<div algorithm>
To <dfn>initialize an Exception object</dfn> |exn| from an [=Exception address=] |exnAddress|, perform the following steps:
dschuff marked this conversation as resolved.
Show resolved Hide resolved

To <dfn>create an Exception object</dfn> from a [=tag address=] |tagAddress| and a [=list=] of
WebAssembly values |payload|, perform the following steps:

1. Let |map| be the [=surrounding agent=]'s associated [=Exception object cache=].
1. Assert: |map|[|exnAddress|] doesn't [=map/exist=].
1. Set |exn|.\[[Address]] to |exnAddress|.
1. [=map/Set=] |map|[|exnAddress|] to |exn|.
1. Let |store| be the [=surrounding agent=]'s [=associated store=].
1. Let |types| be [=tag_parameters=](|store|, |tagAddress|).
1. Assert: |types|'s [=list/size=] is |payload|'s [=list/size=].
1. [=list/iterate|For each=] |value| and |resultType| of |payload| and |types|, paired linearly,
1. Assert: |value|'s type matches |resultType|.
1. Let |exception| be a [=new=] {{Exception}}.
1. Set |exception|.\[[Type]] to |tagAddress|.
1. Set |exception|.\[[Payload]] to |payload|.
1. Set |exception|.\[[Stack]] to undefined.
1. Return |exception|.
1. Let (|tagaddr|, |payload|) be [=exn_read=](|store|, |exnAddress|).
1. Set |exn|.\[[Type]] to |tagaddr|.
1. Set |exn|.\[[Payload]] to |payload|.
1. Set |exn|.\[[Stack]] to undefined.

</div>

<div algorithm>

To <dfn>create an Exception object</dfn> from a [=exception address=] |exnAddress|, perform the following steps:

1. Let |map| be the [=surrounding agent=]'s associated [=Exception object cache=].
1. If |map|[|exnAddress|] [=map/exists=],
1. Return |map|[|exnAddress|].
1. Let |exn| be a [=new=] {{Exception}}.
1. [=initialize an Exception object|Initialize=] |exn| from |exnAddress|.
1. Return |exn|.


</div>

Expand All @@ -1294,22 +1307,22 @@ constructor steps are:
1. Let |wasmPayload| be « ».
1. [=list/iterate|For each=] |value| and |resultType| of |payload| and |types|, paired linearly,
1. [=list/Append=] ? [=ToWebAssemblyValue=](|value|, |resultType|) to |wasmPayload|.
dschuff marked this conversation as resolved.
Show resolved Hide resolved
1. Set **this**.\[[Type]] to |exceptionTag|.\[[Address]].
1. Set **this**.\[[Payload]] to |wasmPayload|.
1. Let (|store|, |exceptionAddr|) be [=exn_alloc=](|store|, |exceptionTag|.\[[Address]], |wasmPayload|)
dschuff marked this conversation as resolved.
Show resolved Hide resolved
1. [=initialize an Exception object|Initialize=] **this** from |exceptionAddr|.
dschuff marked this conversation as resolved.
Show resolved Hide resolved
1. If |options|["traceStack"] is true,
1. Set **this**.\[[Stack]] to either a {{DOMString}} representation of the current call stack or undefined.
1. Otherwise,
1. Set **this**.\[[Stack]] to undefined.
dschuff marked this conversation as resolved.
Show resolved Hide resolved


</div>

<div algorithm>

The <dfn method for="Exception">getArg(|exceptionTag|, |index|)</dfn> method steps are:
The <dfn method for="Exception">getArg(|index|)</dfn> method steps are:
(XXX maybe rename this method? exns don't really have 'args' the way func types do and also for backward compatibility)

1. If **this**.\[[Type]] is not equal to |exceptionTag|.\[[Address]],
1. Throw a {{TypeError}}.
1. Let |payload| be **this**.\[[Payload]].
1. Let |store| be the [=surrounding agent=]'s [=associated store=].
1. Let (|tagaddr|, |payload|) be [=exn_read=](|store|, **this**.\[[Address]]).
1. Assert: |tagaddr| is equal to **this**.\[[Type]].
1. If |index| ≥ |payload|'s [=list/size=],
1. Throw a {{RangeError}}.
1. Return [=ToJSValue=](|payload|[|index|]).
Expand Down