diff --git a/.github/workflows/ci-interpreter.yml b/.github/workflows/ci-interpreter.yml new file mode 100644 index 000000000..22efa999e --- /dev/null +++ b/.github/workflows/ci-interpreter.yml @@ -0,0 +1,36 @@ +name: CI for interpreter & tests + +on: + push: + branches: [ main ] + paths: [ interpreter/**, test/** ] + + pull_request: + branches: [ main ] + paths: [ interpreter/**, test/** ] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +jobs: + interpreter: + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v2 + - name: Setup OCaml + uses: ocaml/setup-ocaml@v2 + with: + ocaml-compiler: 4.12.x + - name: Setup OCaml tools + run: opam install --yes ocamlbuild.0.14.0 ocamlfind.1.9.5 js_of_ocaml.4.0.0 js_of_ocaml-ppx.4.0.0 + - name: Setup Node.js + uses: actions/setup-node@v2 + with: + node-version: 19.x + - name: Build interpreter + run: cd interpreter && opam exec make + - name: Run tests + # Node can't handle the new instructions yet + # run: cd interpreter && opam exec make JS='node --experimental-wasm-return_call' ci + run: cd interpreter && opam exec make ci diff --git a/.github/workflows/ci-spec.yml b/.github/workflows/ci-spec.yml new file mode 100644 index 000000000..e24a3cb50 --- /dev/null +++ b/.github/workflows/ci-spec.yml @@ -0,0 +1,146 @@ +name: CI for specs + +on: + push: + branches: [ main ] + paths: [ document/** ] + + pull_request: + branches: [ main ] + paths: [ document/** ] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +jobs: + build-core-spec: + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v2 + with: + submodules: "recursive" + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: 16 + - name: Setup Bikeshed + run: pip install bikeshed && bikeshed update + - name: Setup TexLive + run: sudo apt-get update -y && sudo apt-get install -y latexmk texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended + - name: Setup Sphinx + run: pip install six && pip install sphinx==5.1.0 + - name: Build main spec + run: cd document/core && make main + # Deactivate broken Bikeshed build for the time being + #- name: Run Bikeshed + # run: cd document/core && make bikeshed + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: core-rendered + path: document/core/_build/html + + build-js-api-spec: + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v2 + - name: Setup Bikeshed + run: pip install bikeshed && bikeshed update + - name: Run Bikeshed + run: bikeshed spec "document/js-api/index.bs" "document/js-api/index.html" + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: js-api-rendered + path: document/js-api/index.html + + build-web-api-spec: + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v2 + - name: Setup Bikeshed + run: pip install bikeshed && bikeshed update + - name: Run Bikeshed + run: bikeshed spec "document/web-api/index.bs" "document/web-api/index.html" + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: web-api-rendered + path: document/web-api/index.html + + build-legacy-exceptions-core-spec: + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v2 + with: + submodules: "recursive" + - name: Setup TexLive + run: sudo apt-get update -y && sudo apt-get install -y latexmk texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended + - name: Setup Sphinx + run: pip install six && pip install sphinx==5.1.0 + - name: Build main spec + run: cd document/legacy/exceptions/core && make main + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: legacy-exceptions-core-rendered + path: document/legacy/exceptions/core/_build/html + + build-legacy-exceptions-js-api-spec: + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v2 + - name: Setup Bikeshed + run: pip install bikeshed && bikeshed update + - name: Run Bikeshed + run: bikeshed spec "document/legacy/exceptions/js-api/index.bs" "document/legacy/exceptions/js-api/index.html" + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: legacy-exceptions-js-api-rendered + path: document/legacy/exceptions/js-api/index.html + + publish-spec: + runs-on: ubuntu-latest + needs: [build-core-spec, build-js-api-spec, build-web-api-spec, build-legacy-exceptions-core-spec, build-legacy-exceptions-js-api-spec] + steps: + - name: Checkout repo + uses: actions/checkout@v2 + - name: Create output directory + run: mkdir _output && cp document/index.html _output/index.html + - name: Download core spec artifact + uses: actions/download-artifact@v4 + with: + name: core-rendered + path: _output/core + - name: Download JS API spec artifact + uses: actions/download-artifact@v4 + with: + name: js-api-rendered + path: _output/js-api + - name: Download Web API spec artifact + uses: actions/download-artifact@v4 + with: + name: web-api-rendered + path: _output/web-api + - name: Download legacy exceptions core spec artifact + uses: actions/download-artifact@v4 + with: + name: legacy-exceptions-core-rendered + path: _output/legacy/exceptions/core + - name: Download legacy exceptions JS API spec artifact + uses: actions/download-artifact@v4 + with: + name: legacy-exceptions-js-api-rendered + path: _output/legacy/exceptions/js-api + - name: Publish to GitHub Pages + if: github.ref == 'refs/heads/main' + uses: peaceiris/actions-gh-pages@v3 + with: + publish_dir: ./_output + github_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml deleted file mode 100644 index 00b70e8f0..000000000 --- a/.github/workflows/main.yml +++ /dev/null @@ -1,96 +0,0 @@ -name: CI - -on: - push: - branches: [ main ] - pull_request: - branches: [ main ] - - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - -jobs: - ref-interpreter: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Setup OCaml - uses: ocaml/setup-ocaml@v2 - with: - ocaml-compiler: 4.12.x - - run: opam install --yes ocamlbuild.0.14.0 - - run: cd interpreter && opam exec make all - - ref-interpreter-js-library: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Setup OCaml - uses: ocaml/setup-ocaml@v2 - with: - ocaml-compiler: 4.12.x - - run: opam install --yes ocamlbuild.0.14.0 ocamlfind.1.9.5 js_of_ocaml.4.0.0 js_of_ocaml-ppx.4.0.0 - - run: cd interpreter && opam exec make wast.js - - build-js-api-spec: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - run: pip install bikeshed && bikeshed update - - run: bikeshed spec "document/js-api/index.bs" "document/js-api/index.html" - - uses: actions/upload-artifact@v2 - with: - name: js-api-rendered - path: document/js-api/index.html - - build-web-api-spec: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - run: pip install bikeshed && bikeshed update - - run: bikeshed spec "document/web-api/index.bs" "document/web-api/index.html" - - uses: actions/upload-artifact@v2 - with: - name: web-api-rendered - path: document/web-api/index.html - - build-core-spec: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - with: - submodules: "recursive" - - run: pip install bikeshed && bikeshed update - - run: pip install six - - run: sudo apt-get update -y && sudo apt-get install -y latexmk texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended - - run: pip install sphinx==5.1.0 - - run: cd document/core && make all - - uses: actions/upload-artifact@v2 - with: - name: core-api-rendered - path: document/core/_build/html - - publish-spec: - runs-on: ubuntu-latest - needs: [build-core-spec, build-js-api-spec, build-web-api-spec] - steps: - - uses: actions/checkout@v2 - - run: mkdir _output && cp document/index.html _output/index.html - - uses: actions/download-artifact@v2 - with: - name: js-api-rendered - path: _output/js-api - - uses: actions/download-artifact@v2 - with: - name: web-api-rendered - path: _output/web-api - - uses: actions/download-artifact@v2 - with: - name: core-api-rendered - path: _output/core - - name: Publish HTML to GitHub Pages - if: github.ref == 'refs/heads/main' - uses: peaceiris/actions-gh-pages@v3 - with: - publish_dir: ./_output - github_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/mirror.yml b/.github/workflows/mirror-to-master.yml similarity index 81% rename from .github/workflows/mirror.yml rename to .github/workflows/mirror-to-master.yml index 5c4707573..7849af75b 100644 --- a/.github/workflows/mirror.yml +++ b/.github/workflows/mirror-to-master.yml @@ -1,3 +1,5 @@ +name: Mirror main branch to master branch + on: push: branches: @@ -8,8 +10,7 @@ jobs: runs-on: ubuntu-latest name: Mirror main branch to master branch steps: - - name: Mirror action step - id: mirror + - name: Mirror branch uses: google/mirror-branch-action@v1.0 with: github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/README.md b/README.md index f92fcb018..536375233 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ -![Build Status](https://github.com/WebAssembly/exception-handling/actions/workflows/main.yml/badge.svg) +[![CI for specs](https://github.com/WebAssembly/exception-handling/actions/workflows/ci-spec.yml/badge.svg)](https://github.com/WebAssembly/exception-handling/actions/workflows/ci-spec.yml) +[![CI for interpreter & tests](https://github.com/WebAssembly/exception-handling/actions/workflows/ci-interpreter.yml/badge.svg)](https://github.com/WebAssembly/exception-handling/actions/workflows/ci-interpreter.yml) # Exception Handling Proposal for WebAssembly @@ -11,7 +12,6 @@ summary of the proposal. [webassembly.github.io/exception-handling](https://webassembly.github.io/exception-handling/). Original README from upstream repository follows... -======= # spec diff --git a/document/Makefile b/document/Makefile index 875efc720..1a9625c14 100644 --- a/document/Makefile +++ b/document/Makefile @@ -1,4 +1,4 @@ -DIRS = core js-api web-api +DIRS = core js-api web-api legacy/exception-handling FILES = index.html BUILDDIR = _build diff --git a/document/core/Makefile b/document/core/Makefile index 3ff1a87cb..8a3650ec9 100644 --- a/document/core/Makefile +++ b/document/core/Makefile @@ -89,12 +89,14 @@ bikeshed-keep: echo Downloaded Bikeshed. -.PHONY: index -index: - (cd appendix; ./gen-index-instructions.py) +GENERATED = appendix/index-instructions.rst +.INTERMEDIATE: $(GENERATED) + +%.rst: %.py + (cd `dirname $@`; ./`basename $^`) .PHONY: pdf -pdf: index latexpdf +pdf: $(GENERATED) latexpdf mkdir -p $(BUILDDIR)/html/$(DOWNLOADDIR) ln -f $(BUILDDIR)/latex/$(NAME).pdf $(BUILDDIR)/html/$(DOWNLOADDIR)/$(NAME).pdf @@ -103,9 +105,10 @@ pdf: index latexpdf clean: rm -rf $(BUILDDIR) rm -rf $(STATICDIR) + rm -f $(GENERATED) .PHONY: html -html: index +html: $(GENERATED) $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html for file in `ls $(BUILDDIR)/html/*.html`; \ do \ @@ -121,28 +124,34 @@ html: index @echo "Build finished. The HTML pages are in `pwd`/$(BUILDDIR)/html/." .PHONY: dirhtml -dirhtml: +dirhtml: $(GENERATED) $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." .PHONY: singlehtml -singlehtml: +singlehtml: $(GENERATED) $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." .PHONY: bikeshed -bikeshed: +bikeshed: $(GENERATED) $(SPHINXBUILD) -b singlehtml -c util/bikeshed \ $(ALLSPHINXOPTS) $(BUILDDIR)/bikeshed_singlehtml - python util/bikeshed_fixup.py $(BUILDDIR)/bikeshed_singlehtml/index.html \ + python3 util/bikeshed_fixup.py $(BUILDDIR)/bikeshed_singlehtml/index.html \ >$(BUILDDIR)/bikeshed_singlehtml/index_fixed.html + @echo ==== Showing contents of _build/bikeshed_singlehtml/index_fixed.html ==== + @head -n10 _build/bikeshed_singlehtml/index_fixed.html + @echo ... skipping $$(expr `cat _build/bikeshed_singlehtml/index_fixed.html | wc -l` - 20) lines ... + @tail -n10 _build/bikeshed_singlehtml/index_fixed.html + @echo + @echo ========================================================================= mkdir -p $(BUILDDIR)/bikeshed_mathjax/ bikeshed spec index.bs $(BUILDDIR)/bikeshed_mathjax/index.html mkdir -p $(BUILDDIR)/html/bikeshed/ (cd util/katex/ && yarn && yarn build && npm install --only=prod) - python util/mathjax2katex.py $(BUILDDIR)/bikeshed_mathjax/index.html \ + python3 util/mathjax2katex.py $(BUILDDIR)/bikeshed_mathjax/index.html \ >$(BUILDDIR)/html/bikeshed/index.html mkdir -p $(BUILDDIR)/html/bikeshed/katex/dist/ cp -r util/katex/dist/* $(BUILDDIR)/html/bikeshed/katex/dist/ @@ -259,7 +268,7 @@ latex: "(use \`make latexpdf' here to do that automatically)." .PHONY: latexpdf -latexpdf: +latexpdf: $(GENERATED) $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex LATEXMKOPTS=" $(BUILDDIR)/latex/LOG 2>&1 || cat $(BUILDDIR)/latex/LOG diff --git a/document/core/appendix/algorithm.rst b/document/core/appendix/algorithm.rst index 941653f7f..6b6985e81 100644 --- a/document/core/appendix/algorithm.rst +++ b/document/core/appendix/algorithm.rst @@ -25,7 +25,7 @@ Types are representable as an enumeration. .. code-block:: pseudo - type val_type = I32 | I64 | F32 | F64 | V128 | Funcref | Externref + type val_type = I32 | I64 | F32 | F64 | V128 | Funcref | Exnref | Externref func is_num(t : val_type | Unknown) : bool = return t = I32 || t = I64 || t = F32 || t = F64 || t = Unknown @@ -34,7 +34,7 @@ Types are representable as an enumeration. return t = V128 || t = Unknown func is_ref(t : val_type | Unknown) : bool = - return t = Funcref || t = Externref || t = Unknown + return t = Funcref || t = Exnref || t = Externref || t = Unknown The algorithm uses two separate stacks: the *value stack* and the *control stack*. The former tracks the :ref:`types ` of operand values on the :ref:`stack `, @@ -212,20 +212,27 @@ Other instructions are checked in a similar manner. error_if(frame.opcode =/= if) push_ctrl(else, frame.start_types, frame.end_types) - case (try t1*->t2*) + case (try_table t1*->t2* handler*) pop_vals([t1*]) - push_ctrl(try, [t1*], [t2*]) - - case (catch) - let frame = pop_ctrl() - error_if(frame.opcode =/= try || frame.opcode =/= catch) - let params = tags[x].type.params - push_ctrl(catch, params , frame.end_types) - - case (catch_all) - let frame = pop_ctrl() - error_if(frame.opcode =/= try || frame.opcode =/= catch) - push_ctrl(catch_all, [], frame.end_types) + foreach (handler in handler*) + error_if(ctrls.size() < handler.label) + push_ctrl(catch, [], label_types(ctrls[handler.label])) + switch (handler.clause) + case (catch x) + push_vals(tags[x].type.params) + case (catch_ref x) + push_vals(tags[x].type.params) + push_val(Exnref) + case (catch_all) + skip + case (catch_all_ref) + push_val(Exnref) + pop_ctrl() + push_ctrl(try_table, [t1*], [t2*]) + + case (throw x) + pop_vals(tags[x].type.params) + unreachable() case (br n) error_if(ctrls.size() < n) @@ -249,8 +256,6 @@ Other instructions are checked in a similar manner. pop_vals(label_types(ctrls[m])) unreachable() -.. todo:: - Add a case for :code:`throw`. .. note:: It is an invariant under the current WebAssembly instruction set that an operand of :code:`Unknown` type is never duplicated on the stack. diff --git a/document/core/appendix/changes.rst b/document/core/appendix/changes.rst index 339cb25f9..db014c5f4 100644 --- a/document/core/appendix/changes.rst +++ b/document/core/appendix/changes.rst @@ -138,6 +138,22 @@ Added vector type and instructions that manipulate multiple numeric values in pa * New injection/projection :ref:`vector instructions `: :math:`\K{i}\!N\!\K{x}\!M\!\K{.splat}`, :math:`\K{f}\!N\!\K{x}\!M\!\K{.splat}`, :math:`\K{i}\!N\!\K{x}\!M\!\K{.bitmask}` +.. index:: instructions, exception, tag type, tag, handler + +Exception Handling +.................. + +Added tag definitions, imports, and exports, and instructions to throw and catch exceptions [#proposal-exceptions]_ + +* Modules may :ref:`define `, :ref:`import `, and :ref:`export ` tags. + +* New :ref:`reference type ` |EXNREF|. + +* New :ref:`control instructions `: |THROW|, |THROWREF|, and |TRYTABLE|. + +* New :ref:`tag section ` in binary format. + + .. [#proposal-signext] https://github.com/WebAssembly/spec/tree/main/proposals/sign-extension-ops/ @@ -155,3 +171,6 @@ Added vector type and instructions that manipulate multiple numeric values in pa .. [#proposal-vectype] https://github.com/WebAssembly/spec/tree/main/proposals/simd/ + +.. [#proposal-exceptions] + https://github.com/WebAssembly/spec/tree/main/proposals/exception-handling/ diff --git a/document/core/appendix/embedding.rst b/document/core/appendix/embedding.rst index b4ad120d7..173f60a22 100644 --- a/document/core/appendix/embedding.rst +++ b/document/core/appendix/embedding.rst @@ -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 address :math:`exnaddr` identifies the exception thrown. + +Failure of an interface operation is also indicated by an auxiliary syntactic class: .. math:: \begin{array}{llll} @@ -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 ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -293,14 +304,16 @@ 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 ` the function :math:`\funcaddr` in :math:`\store` with :ref:`values ` :math:`\val^\ast` as arguments: a. If it succeeds with :ref:`values ` :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 ` :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}`. @@ -308,6 +321,7 @@ Functions ~ \\ \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~a')~\THROWREF] \\ \F{func\_invoke}(S, a, v^\ast) &=& (S', \ERROR) && (\iff \invoke(S, a, v^\ast) \stepto^\ast S'; F; \TRAP) \\ \end{array} @@ -323,7 +337,7 @@ Tables .. _embed-table-alloc: -:math:`\F{table\_alloc}(\store, \tabletype) : (\store, \tableaddr, \reff)` +:math:`\F{table\_alloc}(\store, \tabletype, \reff) : (\store, \tableaddr)` .......................................................................... 1. Pre-condition: :math:`\tabletype` is :ref:`valid `. @@ -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 ` is :ref:`valid `. + +.. 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 `. + +2. Let :math:`\exnaddr` be the result of :ref:`allocating an exception ` in :math:`\store` with :ref:`tag address ` :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 ` :math:`\store.\SEXNS[\exnaddr]`. + +2. Return the :ref:`tag address ` :math:`\X{ei}.\EITAG~\tagaddr` paired with :ref:`values ` :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: diff --git a/document/core/appendix/implementation.rst b/document/core/appendix/implementation.rst index 4ffbe0e79..d96581652 100644 --- a/document/core/appendix/implementation.rst +++ b/document/core/appendix/implementation.rst @@ -46,6 +46,7 @@ An implementation may impose restrictions on the following dimensions of a modul * the number of results in a :ref:`function type ` * the number of parameters in a :ref:`block type ` * the number of results in a :ref:`block type ` +* the number of parameters in a :ref:`tag type ` * the number of :ref:`locals ` in a :ref:`function ` * the size of a :ref:`function ` body * the size of a :ref:`structured control instruction ` @@ -126,6 +127,7 @@ Restrictions on the following dimensions may be imposed during :ref:`execution < * the number of allocated :ref:`memory instances ` * the number of allocated :ref:`tag instances ` * the number of allocated :ref:`global instances ` +* the number of allocated :ref:`exception instances ` * the size of a :ref:`table instance ` * the size of a :ref:`memory instance ` * the number of :ref:`frames ` on the :ref:`stack ` diff --git a/document/core/appendix/gen-index-instructions.py b/document/core/appendix/index-instructions.py similarity index 97% rename from document/core/appendix/gen-index-instructions.py rename to document/core/appendix/index-instructions.py index 65a971715..75b9430c7 100755 --- a/document/core/appendix/gen-index-instructions.py +++ b/document/core/appendix/index-instructions.py @@ -12,7 +12,7 @@ INDEX_INSTRUCTIONS_RST = os.path.join(SCRIPT_DIR, 'index-instructions.rst') HEADER = """\ -.. DO NOT EDIT: This file is auto-generated by the gen-index-instructions.py script. +.. DO NOT EDIT: This file is auto-generated by the index-instructions.py script. .. index:: instruction .. _index-instr: @@ -52,18 +52,28 @@ def RefWrap(s, kind): return f':ref:`{kind} <{s}>`' -def Instruction(name, opcode, type=None, validation=None, execution=None, operator=None): +def Instruction(name, opcode, type=None, validation=None, execution=None, operator=None, validation2=None, execution2=None): if operator: execution_str = ', '.join([RefWrap(execution, 'execution'), RefWrap(operator, 'operator')]) + elif execution2: + execution_str = ', '.join([RefWrap(execution, 'execution'), + RefWrap(execution, 'execution')]) + else: execution_str = RefWrap(execution, 'execution') + if validation2: + validation_str = ', '.join([RefWrap(validation, 'validation'), + RefWrap(validation2, 'validation')]) + else: + validation_str = RefWrap(validation, 'validation') + return ( MathWrap(name, '(reserved)'), MathWrap(opcode), MathWrap(type), - RefWrap(validation, 'validation'), + validation_str, execution_str ) @@ -77,9 +87,9 @@ def Instruction(name, opcode, type=None, validation=None, execution=None, operat Instruction(r'\ELSE', r'\hex{05}'), Instruction(None, r'\hex{06}'), Instruction(None, r'\hex{07}'), - Instruction(None, r'\hex{08}'), + Instruction(r'\THROW~x', r'\hex{08}', r'[t_1^\ast~t_x^\ast] \to [t_2^\ast]', r'valid-throw', r'exec-throw'), Instruction(None, r'\hex{09}'), - Instruction(None, r'\hex{0A}'), + Instruction(r'\THROWREF', r'\hex{0A}', r'[t_1^\ast~\EXNREF] \to [t_2^\ast]', r'valid-throw_ref', r'exec-throw_ref'), Instruction(r'\END', r'\hex{0B}'), Instruction(r'\BR~l', r'\hex{0C}', r'[t_1^\ast~t^\ast] \to [t_2^\ast]', r'valid-br', r'exec-br'), Instruction(r'\BRIF~l', r'\hex{0D}', r'[t^\ast~\I32] \to [t^\ast]', r'valid-br_if', r'exec-br_if'), @@ -100,7 +110,7 @@ def Instruction(name, opcode, type=None, validation=None, execution=None, operat Instruction(r'\SELECT~t', r'\hex{1C}', r'[t~t~\I32] \to [t]', r'valid-select', r'exec-select'), Instruction(None, r'\hex{1D}'), Instruction(None, r'\hex{1E}'), - Instruction(None, r'\hex{1F}'), + Instruction(r'\TRYTABLE~\X{bt}', r'\hex{1F}', r'[t_1^\ast] \to [t_2^\ast]', r'valid-try_table', r'exec-try_table'), Instruction(r'\LOCALGET~x', r'\hex{20}', r'[] \to [t]', r'valid-local.get', r'exec-local.get'), Instruction(r'\LOCALSET~x', r'\hex{21}', r'[t] \to []', r'valid-local.set', r'exec-local.set'), Instruction(r'\LOCALTEE~x', r'\hex{22}', r'[t] \to [t]', r'valid-local.tee', r'exec-local.tee'), @@ -427,12 +437,12 @@ def Instruction(name, opcode, type=None, validation=None, execution=None, operat Instruction(r'\V128.\LOAD\K{16\_lane}~\memarg~\laneidx', r'\hex{FD}~~\hex{55}', r'[\I32~\V128] \to [\V128]', r'valid-load-lane', r'exec-load-lane'), Instruction(r'\V128.\LOAD\K{32\_lane}~\memarg~\laneidx', r'\hex{FD}~~\hex{56}', r'[\I32~\V128] \to [\V128]', r'valid-load-lane', r'exec-load-lane'), Instruction(r'\V128.\LOAD\K{64\_lane}~\memarg~\laneidx', r'\hex{FD}~~\hex{57}', r'[\I32~\V128] \to [\V128]', r'valid-load-lane', r'exec-load-lane'), - Instruction(r'\V128.\STORE\K{8\_lane}~\memarg~\laneidx', r'\hex{FD}~~\hex{58}', r'[\I32~\V128] \to [\V128]', r'valid-store-lane', r'exec-store-lane'), - Instruction(r'\V128.\STORE\K{16\_lane}~\memarg~\laneidx', r'\hex{FD}~~\hex{59}', r'[\I32~\V128] \to [\V128]', r'valid-store-lane', r'exec-store-lane'), - Instruction(r'\V128.\STORE\K{32\_lane}~\memarg~\laneidx', r'\hex{FD}~~\hex{5A}', r'[\I32~\V128] \to [\V128]', r'valid-store-lane', r'exec-store-lane'), - Instruction(r'\V128.\STORE\K{64\_lane}~\memarg~\laneidx', r'\hex{FD}~~\hex{5B}', r'[\I32~\V128] \to [\V128]', r'valid-store-lane', r'exec-store-lane'), - Instruction(r'\V128.\LOAD\K{32\_zero}~\memarg~\laneidx', r'\hex{FD}~~\hex{5C}', r'[\I32] \to [\V128]', r'valid-load-zero', r'exec-load-zero'), - Instruction(r'\V128.\LOAD\K{64\_zero}~\memarg~\laneidx', r'\hex{FD}~~\hex{5D}', r'[\I32] \to [\V128]', r'valid-load-zero', r'exec-load-zero'), + Instruction(r'\V128.\STORE\K{8\_lane}~\memarg~\laneidx', r'\hex{FD}~~\hex{58}', r'[\I32~\V128] \to []', r'valid-store-lane', r'exec-store-lane'), + Instruction(r'\V128.\STORE\K{16\_lane}~\memarg~\laneidx', r'\hex{FD}~~\hex{59}', r'[\I32~\V128] \to []', r'valid-store-lane', r'exec-store-lane'), + Instruction(r'\V128.\STORE\K{32\_lane}~\memarg~\laneidx', r'\hex{FD}~~\hex{5A}', r'[\I32~\V128] \to []', r'valid-store-lane', r'exec-store-lane'), + Instruction(r'\V128.\STORE\K{64\_lane}~\memarg~\laneidx', r'\hex{FD}~~\hex{5B}', r'[\I32~\V128] \to []', r'valid-store-lane', r'exec-store-lane'), + Instruction(r'\V128.\LOAD\K{32\_zero}~\memarg', r'\hex{FD}~~\hex{5C}', r'[\I32] \to [\V128]', r'valid-load-zero', r'exec-load-zero'), + Instruction(r'\V128.\LOAD\K{64\_zero}~\memarg', r'\hex{FD}~~\hex{5D}', r'[\I32] \to [\V128]', r'valid-load-zero', r'exec-load-zero'), Instruction(r'\F32X4.\VDEMOTE\K{\_f64x2\_zero}', r'\hex{FD}~~\hex{5E}', r'[\V128] \to [\V128]', r'valid-vcvtop', r'exec-vcvtop', r'op-demote'), Instruction(r'\F64X2.\VPROMOTE\K{\_low\_f32x4}', r'\hex{FD}~~\hex{5F}', r'[\V128] \to [\V128]', r'valid-vcvtop', r'exec-vcvtop', r'op-promote'), Instruction(r'\I8X16.\VABS', r'\hex{FD}~~\hex{60}', r'[\V128] \to [\V128]', r'valid-vunop', r'exec-vunop', r'op-iabs'), diff --git a/document/core/appendix/index-instructions.rst b/document/core/appendix/index-instructions.rst deleted file mode 100644 index 84055a9fa..000000000 --- a/document/core/appendix/index-instructions.rst +++ /dev/null @@ -1,523 +0,0 @@ -.. DO NOT EDIT: This file is auto-generated by the gen-index-instructions.py script. - -.. index:: instruction -.. _index-instr: - -Index of Instructions ---------------------- - -================================================= ==================================== ============================================= ============================================= ================================================================== -Instruction Binary Opcode Type Validation Execution -================================================= ==================================== ============================================= ============================================= ================================================================== -:math:`\UNREACHABLE` :math:`\hex{00}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\NOP` :math:`\hex{01}` :math:`[] \to []` :ref:`validation ` :ref:`execution ` -:math:`\BLOCK~\X{bt}` :math:`\hex{02}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\LOOP~\X{bt}` :math:`\hex{03}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\IF~\X{bt}` :math:`\hex{04}` :math:`[t_1^\ast~\I32] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\ELSE` :math:`\hex{05}` -(reserved) :math:`\hex{06}` -(reserved) :math:`\hex{07}` -(reserved) :math:`\hex{08}` -(reserved) :math:`\hex{09}` -(reserved) :math:`\hex{0A}` -:math:`\END` :math:`\hex{0B}` -:math:`\BR~l` :math:`\hex{0C}` :math:`[t_1^\ast~t^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\BRIF~l` :math:`\hex{0D}` :math:`[t^\ast~\I32] \to [t^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\BRTABLE~l^\ast~l` :math:`\hex{0E}` :math:`[t_1^\ast~t^\ast~\I32] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\RETURN` :math:`\hex{0F}` :math:`[t_1^\ast~t^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\CALL~x` :math:`\hex{10}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\CALLINDIRECT~x~y` :math:`\hex{11}` :math:`[t_1^\ast~\I32] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -(reserved) :math:`\hex{12}` -(reserved) :math:`\hex{13}` -(reserved) :math:`\hex{14}` -(reserved) :math:`\hex{15}` -(reserved) :math:`\hex{16}` -(reserved) :math:`\hex{17}` -(reserved) :math:`\hex{18}` -(reserved) :math:`\hex{19}` -:math:`\DROP` :math:`\hex{1A}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` -:math:`\SELECT` :math:`\hex{1B}` :math:`[t~t~\I32] \to [t]` :ref:`validation ` :ref:`execution ` -:math:`\SELECT~t` :math:`\hex{1C}` :math:`[t~t~\I32] \to [t]` :ref:`validation ` :ref:`execution ` -(reserved) :math:`\hex{1D}` -(reserved) :math:`\hex{1E}` -(reserved) :math:`\hex{1F}` -:math:`\LOCALGET~x` :math:`\hex{20}` :math:`[] \to [t]` :ref:`validation ` :ref:`execution ` -:math:`\LOCALSET~x` :math:`\hex{21}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` -:math:`\LOCALTEE~x` :math:`\hex{22}` :math:`[t] \to [t]` :ref:`validation ` :ref:`execution ` -:math:`\GLOBALGET~x` :math:`\hex{23}` :math:`[] \to [t]` :ref:`validation ` :ref:`execution ` -:math:`\GLOBALSET~x` :math:`\hex{24}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` -:math:`\TABLEGET~x` :math:`\hex{25}` :math:`[\I32] \to [t]` :ref:`validation ` :ref:`execution ` -:math:`\TABLESET~x` :math:`\hex{26}` :math:`[\I32~t] \to []` :ref:`validation ` :ref:`execution ` -(reserved) :math:`\hex{27}` -:math:`\I32.\LOAD~\memarg` :math:`\hex{28}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD~\memarg` :math:`\hex{29}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\F32.\LOAD~\memarg` :math:`\hex{2A}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution ` -:math:`\F64.\LOAD~\memarg` :math:`\hex{2B}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\LOAD\K{8\_s}~\memarg` :math:`\hex{2C}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\LOAD\K{8\_u}~\memarg` :math:`\hex{2D}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\LOAD\K{16\_s}~\memarg` :math:`\hex{2E}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\LOAD\K{16\_u}~\memarg` :math:`\hex{2F}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{8\_s}~\memarg` :math:`\hex{30}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{8\_u}~\memarg` :math:`\hex{31}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{16\_s}~\memarg` :math:`\hex{32}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{16\_u}~\memarg` :math:`\hex{33}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{32\_s}~\memarg` :math:`\hex{34}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{32\_u}~\memarg` :math:`\hex{35}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\STORE~\memarg` :math:`\hex{36}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I64.\STORE~\memarg` :math:`\hex{37}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` -:math:`\F32.\STORE~\memarg` :math:`\hex{38}` :math:`[\I32~\F32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\F64.\STORE~\memarg` :math:`\hex{39}` :math:`[\I32~\F64] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I32.\STORE\K{8}~\memarg` :math:`\hex{3A}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I32.\STORE\K{16}~\memarg` :math:`\hex{3B}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I64.\STORE\K{8}~\memarg` :math:`\hex{3C}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I64.\STORE\K{16}~\memarg` :math:`\hex{3D}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I64.\STORE\K{32}~\memarg` :math:`\hex{3E}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` -:math:`\MEMORYSIZE` :math:`\hex{3F}` :math:`[] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\MEMORYGROW` :math:`\hex{40}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\CONST~\i32` :math:`\hex{41}` :math:`[] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\CONST~\i64` :math:`\hex{42}` :math:`[] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\F32.\CONST~\f32` :math:`\hex{43}` :math:`[] \to [\F32]` :ref:`validation ` :ref:`execution ` -:math:`\F64.\CONST~\f64` :math:`\hex{44}` :math:`[] \to [\F64]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\EQZ` :math:`\hex{45}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\EQ` :math:`\hex{46}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\NE` :math:`\hex{47}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\LT\K{\_s}` :math:`\hex{48}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\LT\K{\_u}` :math:`\hex{49}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\GT\K{\_s}` :math:`\hex{4A}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\GT\K{\_u}` :math:`\hex{4B}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\LE\K{\_s}` :math:`\hex{4C}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\LE\K{\_u}` :math:`\hex{4D}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\GE\K{\_s}` :math:`\hex{4E}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\GE\K{\_u}` :math:`\hex{4F}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EQZ` :math:`\hex{50}` :math:`[\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EQ` :math:`\hex{51}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\NE` :math:`\hex{52}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\LT\K{\_s}` :math:`\hex{53}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\LT\K{\_u}` :math:`\hex{54}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\GT\K{\_s}` :math:`\hex{55}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\GT\K{\_u}` :math:`\hex{56}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\LE\K{\_s}` :math:`\hex{57}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\LE\K{\_u}` :math:`\hex{58}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\GE\K{\_s}` :math:`\hex{59}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\GE\K{\_u}` :math:`\hex{5A}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\EQ` :math:`\hex{5B}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\NE` :math:`\hex{5C}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\LT` :math:`\hex{5D}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\GT` :math:`\hex{5E}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\LE` :math:`\hex{5F}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\GE` :math:`\hex{60}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\EQ` :math:`\hex{61}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\NE` :math:`\hex{62}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\LT` :math:`\hex{63}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\GT` :math:`\hex{64}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\LE` :math:`\hex{65}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\GE` :math:`\hex{66}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\CLZ` :math:`\hex{67}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\CTZ` :math:`\hex{68}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\POPCNT` :math:`\hex{69}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\ADD` :math:`\hex{6A}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\SUB` :math:`\hex{6B}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\MUL` :math:`\hex{6C}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\DIV\K{\_s}` :math:`\hex{6D}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\DIV\K{\_u}` :math:`\hex{6E}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\REM\K{\_s}` :math:`\hex{6F}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\REM\K{\_u}` :math:`\hex{70}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\AND` :math:`\hex{71}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\OR` :math:`\hex{72}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\XOR` :math:`\hex{73}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\SHL` :math:`\hex{74}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\SHR\K{\_s}` :math:`\hex{75}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\SHR\K{\_u}` :math:`\hex{76}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\ROTL` :math:`\hex{77}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\ROTR` :math:`\hex{78}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\CLZ` :math:`\hex{79}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\CTZ` :math:`\hex{7A}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\POPCNT` :math:`\hex{7B}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\ADD` :math:`\hex{7C}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\SUB` :math:`\hex{7D}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\MUL` :math:`\hex{7E}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\DIV\K{\_s}` :math:`\hex{7F}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\DIV\K{\_u}` :math:`\hex{80}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\REM\K{\_s}` :math:`\hex{81}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\REM\K{\_u}` :math:`\hex{82}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\AND` :math:`\hex{83}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\OR` :math:`\hex{84}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\XOR` :math:`\hex{85}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\SHL` :math:`\hex{86}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\SHR\K{\_s}` :math:`\hex{87}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\SHR\K{\_u}` :math:`\hex{88}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\ROTL` :math:`\hex{89}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\ROTR` :math:`\hex{8A}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\ABS` :math:`\hex{8B}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\NEG` :math:`\hex{8C}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\CEIL` :math:`\hex{8D}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\FLOOR` :math:`\hex{8E}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\TRUNC` :math:`\hex{8F}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\NEAREST` :math:`\hex{90}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\SQRT` :math:`\hex{91}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\ADD` :math:`\hex{92}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\SUB` :math:`\hex{93}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\MUL` :math:`\hex{94}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\DIV` :math:`\hex{95}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\FMIN` :math:`\hex{96}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\FMAX` :math:`\hex{97}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\COPYSIGN` :math:`\hex{98}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\ABS` :math:`\hex{99}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\NEG` :math:`\hex{9A}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\CEIL` :math:`\hex{9B}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\FLOOR` :math:`\hex{9C}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\TRUNC` :math:`\hex{9D}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\NEAREST` :math:`\hex{9E}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\SQRT` :math:`\hex{9F}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\ADD` :math:`\hex{A0}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\SUB` :math:`\hex{A1}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\MUL` :math:`\hex{A2}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\DIV` :math:`\hex{A3}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\FMIN` :math:`\hex{A4}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\FMAX` :math:`\hex{A5}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\COPYSIGN` :math:`\hex{A6}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\WRAP\K{\_}\I64` :math:`\hex{A7}` :math:`[\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_}\F32\K{\_s}` :math:`\hex{A8}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_}\F32\K{\_u}` :math:`\hex{A9}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_}\F64\K{\_s}` :math:`\hex{AA}` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_}\F64\K{\_u}` :math:`\hex{AB}` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EXTEND\K{\_}\I32\K{\_s}` :math:`\hex{AC}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EXTEND\K{\_}\I32\K{\_u}` :math:`\hex{AD}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_}\F32\K{\_s}` :math:`\hex{AE}` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_}\F32\K{\_u}` :math:`\hex{AF}` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_}\F64\K{\_s}` :math:`\hex{B0}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_}\F64\K{\_u}` :math:`\hex{B1}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\CONVERT\K{\_}\I32\K{\_s}` :math:`\hex{B2}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\CONVERT\K{\_}\I32\K{\_u}` :math:`\hex{B3}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\CONVERT\K{\_}\I64\K{\_s}` :math:`\hex{B4}` :math:`[\I64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\CONVERT\K{\_}\I64\K{\_u}` :math:`\hex{B5}` :math:`[\I64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\DEMOTE\K{\_}\F64` :math:`\hex{B6}` :math:`[\F64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\CONVERT\K{\_}\I32\K{\_s}` :math:`\hex{B7}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\CONVERT\K{\_}\I32\K{\_u}` :math:`\hex{B8}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\CONVERT\K{\_}\I64\K{\_s}` :math:`\hex{B9}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\CONVERT\K{\_}\I64\K{\_u}` :math:`\hex{BA}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\PROMOTE\K{\_}\F32` :math:`\hex{BB}` :math:`[\F32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\REINTERPRET\K{\_}\F32` :math:`\hex{BC}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\REINTERPRET\K{\_}\F64` :math:`\hex{BD}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\REINTERPRET\K{\_}\I32` :math:`\hex{BE}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\REINTERPRET\K{\_}\I64` :math:`\hex{BF}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\EXTEND\K{8\_s}` :math:`\hex{C0}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\EXTEND\K{16\_s}` :math:`\hex{C1}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EXTEND\K{8\_s}` :math:`\hex{C2}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EXTEND\K{16\_s}` :math:`\hex{C3}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EXTEND\K{32\_s}` :math:`\hex{C4}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -(reserved) :math:`\hex{C5}` -(reserved) :math:`\hex{C6}` -(reserved) :math:`\hex{C7}` -(reserved) :math:`\hex{C8}` -(reserved) :math:`\hex{C9}` -(reserved) :math:`\hex{CA}` -(reserved) :math:`\hex{CB}` -(reserved) :math:`\hex{CC}` -(reserved) :math:`\hex{CD}` -(reserved) :math:`\hex{CE}` -(reserved) :math:`\hex{CF}` -:math:`\REFNULL~t` :math:`\hex{D0}` :math:`[] \to [t]` :ref:`validation ` :ref:`execution ` -:math:`\REFISNULL` :math:`\hex{D1}` :math:`[t] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\REFFUNC~x` :math:`\hex{D2}` :math:`[] \to [\FUNCREF]` :ref:`validation ` :ref:`execution ` -(reserved) :math:`\hex{D3}` -(reserved) :math:`\hex{D4}` -(reserved) :math:`\hex{D5}` -(reserved) :math:`\hex{D6}` -(reserved) :math:`\hex{D7}` -(reserved) :math:`\hex{D8}` -(reserved) :math:`\hex{D9}` -(reserved) :math:`\hex{DA}` -(reserved) :math:`\hex{DB}` -(reserved) :math:`\hex{DC}` -(reserved) :math:`\hex{DD}` -(reserved) :math:`\hex{DE}` -(reserved) :math:`\hex{DF}` -(reserved) :math:`\hex{E0}` -(reserved) :math:`\hex{E1}` -(reserved) :math:`\hex{E2}` -(reserved) :math:`\hex{E3}` -(reserved) :math:`\hex{E4}` -(reserved) :math:`\hex{E5}` -(reserved) :math:`\hex{E6}` -(reserved) :math:`\hex{E7}` -(reserved) :math:`\hex{E8}` -(reserved) :math:`\hex{E9}` -(reserved) :math:`\hex{EA}` -(reserved) :math:`\hex{EB}` -(reserved) :math:`\hex{EC}` -(reserved) :math:`\hex{ED}` -(reserved) :math:`\hex{EE}` -(reserved) :math:`\hex{EF}` -(reserved) :math:`\hex{F0}` -(reserved) :math:`\hex{F1}` -(reserved) :math:`\hex{F2}` -(reserved) :math:`\hex{F3}` -(reserved) :math:`\hex{F4}` -(reserved) :math:`\hex{F5}` -(reserved) :math:`\hex{F6}` -(reserved) :math:`\hex{F7}` -(reserved) :math:`\hex{F8}` -(reserved) :math:`\hex{F9}` -(reserved) :math:`\hex{FA}` -(reserved) :math:`\hex{FB}` -:math:`\I32.\TRUNC\K{\_sat\_}\F32\K{\_s}` :math:`\hex{FC}~\hex{00}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_sat\_}\F32\K{\_u}` :math:`\hex{FC}~\hex{01}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_sat\_}\F64\K{\_s}` :math:`\hex{FC}~\hex{02}` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_sat\_}\F64\K{\_u}` :math:`\hex{FC}~\hex{03}` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_sat\_}\F32\K{\_s}` :math:`\hex{FC}~\hex{04}` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_sat\_}\F32\K{\_u}` :math:`\hex{FC}~\hex{05}` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_sat\_}\F64\K{\_s}` :math:`\hex{FC}~\hex{06}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_sat\_}\F64\K{\_u}` :math:`\hex{FC}~\hex{07}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\MEMORYINIT~x` :math:`\hex{FC}~\hex{08}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\DATADROP~x` :math:`\hex{FC}~\hex{09}` :math:`[] \to []` :ref:`validation ` :ref:`execution ` -:math:`\MEMORYCOPY` :math:`\hex{FC}~\hex{0A}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\MEMORYFILL` :math:`\hex{FC}~\hex{0B}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\TABLEINIT~x~y` :math:`\hex{FC}~\hex{0C}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\ELEMDROP~x` :math:`\hex{FC}~\hex{0D}` :math:`[] \to []` :ref:`validation ` :ref:`execution ` -:math:`\TABLECOPY~x~y` :math:`\hex{FC}~\hex{0E}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\TABLEGROW~x` :math:`\hex{FC}~\hex{0F}` :math:`[t~\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\TABLESIZE~x` :math:`\hex{FC}~\hex{10}` :math:`[] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\TABLEFILL~x` :math:`\hex{FC}~\hex{11}` :math:`[\I32~t~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD~\memarg` :math:`\hex{FD}~~\hex{00}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{8x8\_s}~\memarg` :math:`\hex{FD}~~\hex{01}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{8x8\_u}~\memarg` :math:`\hex{FD}~~\hex{02}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{16x4\_s}~\memarg` :math:`\hex{FD}~~\hex{03}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{16x4\_u}~\memarg` :math:`\hex{FD}~~\hex{04}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{32x2\_s}~\memarg` :math:`\hex{FD}~~\hex{05}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{32x2\_u}~\memarg` :math:`\hex{FD}~~\hex{06}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{8\_splat}~\memarg` :math:`\hex{FD}~~\hex{07}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{16\_splat}~\memarg` :math:`\hex{FD}~~\hex{08}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{32\_splat}~\memarg` :math:`\hex{FD}~~\hex{09}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{64\_splat}~\memarg` :math:`\hex{FD}~~\hex{0A}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\STORE~\memarg` :math:`\hex{FD}~~\hex{0B}` :math:`[\I32~\V128] \to []` :ref:`validation ` :ref:`execution ` -:math:`\V128.\VCONST~\i128` :math:`\hex{FD}~~\hex{0C}` :math:`[] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I8X16.\SHUFFLE~\laneidx^{16}` :math:`\hex{FD}~~\hex{0D}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I8X16.\SWIZZLE` :math:`\hex{FD}~~\hex{0E}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I8X16.\SPLAT` :math:`\hex{FD}~~\hex{0F}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\SPLAT` :math:`\hex{FD}~~\hex{10}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\SPLAT` :math:`\hex{FD}~~\hex{11}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I64X2.\SPLAT` :math:`\hex{FD}~~\hex{12}` :math:`[\I64] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\F32X4.\SPLAT` :math:`\hex{FD}~~\hex{13}` :math:`[\F32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\F64X2.\SPLAT` :math:`\hex{FD}~~\hex{14}` :math:`[\F64] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I8X16.\EXTRACTLANE\K{\_s}~\laneidx` :math:`\hex{FD}~~\hex{15}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I8X16.\EXTRACTLANE\K{\_u}~\laneidx` :math:`\hex{FD}~~\hex{16}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I8X16.\REPLACELANE~\laneidx` :math:`\hex{FD}~~\hex{17}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\EXTRACTLANE\K{\_s}~\laneidx` :math:`\hex{FD}~~\hex{18}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\EXTRACTLANE\K{\_u}~\laneidx` :math:`\hex{FD}~~\hex{19}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\REPLACELANE~\laneidx` :math:`\hex{FD}~~\hex{1A}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\EXTRACTLANE~\laneidx` :math:`\hex{FD}~~\hex{1B}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\REPLACELANE~\laneidx` :math:`\hex{FD}~~\hex{1C}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I64X2.\EXTRACTLANE~\laneidx` :math:`\hex{FD}~~\hex{1D}` :math:`[\V128] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64X2.\REPLACELANE~\laneidx` :math:`\hex{FD}~~\hex{1E}` :math:`[\V128~\I64] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\F32X4.\EXTRACTLANE~\laneidx` :math:`\hex{FD}~~\hex{1F}` :math:`[\V128] \to [\F32]` :ref:`validation ` :ref:`execution ` -:math:`\F32X4.\REPLACELANE~\laneidx` :math:`\hex{FD}~~\hex{20}` :math:`[\V128~\F32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\F64X2.\EXTRACTLANE~\laneidx` :math:`\hex{FD}~~\hex{21}` :math:`[\V128] \to [\F64]` :ref:`validation ` :ref:`execution ` -:math:`\F64X2.\REPLACELANE~\laneidx` :math:`\hex{FD}~~\hex{22}` :math:`[\V128~\F64] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I8X16.\VEQ` :math:`\hex{FD}~~\hex{23}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VNE` :math:`\hex{FD}~~\hex{24}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VLT\K{\_s}` :math:`\hex{FD}~~\hex{25}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VLT\K{\_u}` :math:`\hex{FD}~~\hex{26}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VGT\K{\_s}` :math:`\hex{FD}~~\hex{27}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VGT\K{\_u}` :math:`\hex{FD}~~\hex{28}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VLE\K{\_s}` :math:`\hex{FD}~~\hex{29}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VLE\K{\_u}` :math:`\hex{FD}~~\hex{2A}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VGE\K{\_s}` :math:`\hex{FD}~~\hex{2B}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VGE\K{\_u}` :math:`\hex{FD}~~\hex{2C}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VEQ` :math:`\hex{FD}~~\hex{2D}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VNE` :math:`\hex{FD}~~\hex{2E}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VLT\K{\_s}` :math:`\hex{FD}~~\hex{2F}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VLT\K{\_u}` :math:`\hex{FD}~~\hex{30}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VGT\K{\_s}` :math:`\hex{FD}~~\hex{31}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VGT\K{\_u}` :math:`\hex{FD}~~\hex{32}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VLE\K{\_s}` :math:`\hex{FD}~~\hex{33}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VLE\K{\_u}` :math:`\hex{FD}~~\hex{34}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VGE\K{\_s}` :math:`\hex{FD}~~\hex{35}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VGE\K{\_u}` :math:`\hex{FD}~~\hex{36}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VEQ` :math:`\hex{FD}~~\hex{37}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VNE` :math:`\hex{FD}~~\hex{38}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VLT\K{\_s}` :math:`\hex{FD}~~\hex{39}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VLT\K{\_u}` :math:`\hex{FD}~~\hex{3A}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VGT\K{\_s}` :math:`\hex{FD}~~\hex{3B}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VGT\K{\_u}` :math:`\hex{FD}~~\hex{3C}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VLE\K{\_s}` :math:`\hex{FD}~~\hex{3D}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VLE\K{\_u}` :math:`\hex{FD}~~\hex{3E}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VGE\K{\_s}` :math:`\hex{FD}~~\hex{3F}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VGE\K{\_u}` :math:`\hex{FD}~~\hex{40}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VEQ` :math:`\hex{FD}~~\hex{41}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VNE` :math:`\hex{FD}~~\hex{42}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VLT` :math:`\hex{FD}~~\hex{43}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VGT` :math:`\hex{FD}~~\hex{44}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VLE` :math:`\hex{FD}~~\hex{45}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VGE` :math:`\hex{FD}~~\hex{46}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VEQ` :math:`\hex{FD}~~\hex{47}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VNE` :math:`\hex{FD}~~\hex{48}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VLT` :math:`\hex{FD}~~\hex{49}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VGT` :math:`\hex{FD}~~\hex{4A}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VLE` :math:`\hex{FD}~~\hex{4B}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VGE` :math:`\hex{FD}~~\hex{4C}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\V128.\VNOT` :math:`\hex{FD}~~\hex{4D}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\V128.\VAND` :math:`\hex{FD}~~\hex{4E}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\V128.\VANDNOT` :math:`\hex{FD}~~\hex{4F}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\V128.\VOR` :math:`\hex{FD}~~\hex{50}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\V128.\VXOR` :math:`\hex{FD}~~\hex{51}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\V128.\BITSELECT` :math:`\hex{FD}~~\hex{52}` :math:`[\V128~\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\V128.\ANYTRUE` :math:`\hex{FD}~~\hex{53}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{8\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{54}` :math:`[\I32~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{16\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{55}` :math:`[\I32~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{32\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{56}` :math:`[\I32~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{64\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{57}` :math:`[\I32~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\STORE\K{8\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{58}` :math:`[\I32~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\STORE\K{16\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{59}` :math:`[\I32~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\STORE\K{32\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{5A}` :math:`[\I32~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\STORE\K{64\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{5B}` :math:`[\I32~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{32\_zero}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{5C}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{64\_zero}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{5D}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\F32X4.\VDEMOTE\K{\_f64x2\_zero}` :math:`\hex{FD}~~\hex{5E}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VPROMOTE\K{\_low\_f32x4}` :math:`\hex{FD}~~\hex{5F}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VABS` :math:`\hex{FD}~~\hex{60}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VNEG` :math:`\hex{FD}~~\hex{61}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VPOPCNT` :math:`\hex{FD}~~\hex{62}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\ALLTRUE` :math:`\hex{FD}~~\hex{63}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I8X16.\BITMASK` :math:`\hex{FD}~~\hex{64}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I8X16.\NARROW\K{\_i16x8\_s}` :math:`\hex{FD}~~\hex{65}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I8X16.\NARROW\K{\_i16x8\_u}` :math:`\hex{FD}~~\hex{66}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\F32X4.\VCEIL` :math:`\hex{FD}~~\hex{67}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VFLOOR` :math:`\hex{FD}~~\hex{68}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VTRUNC` :math:`\hex{FD}~~\hex{69}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VNEAREST` :math:`\hex{FD}~~\hex{6A}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VSHL` :math:`\hex{FD}~~\hex{6B}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VSHR\K{\_s}` :math:`\hex{FD}~~\hex{6C}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VSHR\K{\_u}` :math:`\hex{FD}~~\hex{6D}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VADD` :math:`\hex{FD}~~\hex{6E}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VADD\K{\_sat\_s}` :math:`\hex{FD}~~\hex{6F}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VADD\K{\_sat\_u}` :math:`\hex{FD}~~\hex{70}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VSUB` :math:`\hex{FD}~~\hex{71}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VSUB\K{\_sat\_s}` :math:`\hex{FD}~~\hex{72}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VSUB\K{\_sat\_u}` :math:`\hex{FD}~~\hex{73}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VCEIL` :math:`\hex{FD}~~\hex{74}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VFLOOR` :math:`\hex{FD}~~\hex{75}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VMIN\K{\_s}` :math:`\hex{FD}~~\hex{76}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VMIN\K{\_u}` :math:`\hex{FD}~~\hex{77}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VMAX\K{\_s}` :math:`\hex{FD}~~\hex{78}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VMAX\K{\_u}` :math:`\hex{FD}~~\hex{79}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VTRUNC` :math:`\hex{FD}~~\hex{7A}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\AVGR\K{\_u}` :math:`\hex{FD}~~\hex{7B}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\EXTADDPAIRWISE\K{\_i8x16\_s}` :math:`\hex{FD}~~\hex{7C}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\EXTADDPAIRWISE\K{\_i8x16\_u}` :math:`\hex{FD}~~\hex{7D}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\EXTADDPAIRWISE\K{\_i16x8\_s}` :math:`\hex{FD}~~\hex{7E}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\EXTADDPAIRWISE\K{\_i16x8\_u}` :math:`\hex{FD}~~\hex{7F}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\VABS` :math:`\hex{FD}~~\hex{80}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VNEG` :math:`\hex{FD}~~\hex{81}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\Q15MULRSAT\K{\_s}` :math:`\hex{FD}~~\hex{82}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\ALLTRUE` :math:`\hex{FD}~~\hex{83}~~\hex{01}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\BITMASK` :math:`\hex{FD}~~\hex{84}~~\hex{01}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\NARROW\K{\_i32x4\_s}` :math:`\hex{FD}~~\hex{85}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\NARROW\K{\_i32x4\_u}` :math:`\hex{FD}~~\hex{86}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\VEXTEND\K{\_low\_i8x16\_s}` :math:`\hex{FD}~~\hex{87}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\VEXTEND\K{\_high\_i8x16\_s}` :math:`\hex{FD}~~\hex{88}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\VEXTEND\K{\_low\_i8x16\_u}` :math:`\hex{FD}~~\hex{89}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\VEXTEND\K{\_high\_i8x16\_u}` :math:`\hex{FD}~~\hex{8A}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\VSHL` :math:`\hex{FD}~~\hex{8B}~~\hex{01}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VSHR\K{\_s}` :math:`\hex{FD}~~\hex{8C}~~\hex{01}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VSHR\K{\_u}` :math:`\hex{FD}~~\hex{8D}~~\hex{01}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VADD` :math:`\hex{FD}~~\hex{8E}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VADD\K{\_sat\_s}` :math:`\hex{FD}~~\hex{8F}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VADD\K{\_sat\_u}` :math:`\hex{FD}~~\hex{90}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VSUB` :math:`\hex{FD}~~\hex{91}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VSUB\K{\_sat\_s}` :math:`\hex{FD}~~\hex{92}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VSUB\K{\_sat\_u}` :math:`\hex{FD}~~\hex{93}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VNEAREST` :math:`\hex{FD}~~\hex{94}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VMUL` :math:`\hex{FD}~~\hex{95}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VMIN\K{\_s}` :math:`\hex{FD}~~\hex{96}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VMIN\K{\_u}` :math:`\hex{FD}~~\hex{97}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VMAX\K{\_s}` :math:`\hex{FD}~~\hex{98}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VMAX\K{\_u}` :math:`\hex{FD}~~\hex{99}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\AVGR\K{\_u}` :math:`\hex{FD}~~\hex{9B}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\EXTMUL\K{\_low\_i8x16\_s}` :math:`\hex{FD}~~\hex{9C}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\EXTMUL\K{\_high\_i8x16\_s}` :math:`\hex{FD}~~\hex{9D}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\EXTMUL\K{\_low\_i8x16\_u}` :math:`\hex{FD}~~\hex{9E}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\EXTMUL\K{\_high\_i8x16\_u}` :math:`\hex{FD}~~\hex{9F}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\VABS` :math:`\hex{FD}~~\hex{A0}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VNEG` :math:`\hex{FD}~~\hex{A1}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\ALLTRUE` :math:`\hex{FD}~~\hex{A3}~~\hex{01}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\BITMASK` :math:`\hex{FD}~~\hex{A4}~~\hex{01}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\VEXTEND\K{\_low\_i16x8\_s}` :math:`\hex{FD}~~\hex{A7}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\VEXTEND\K{\_high\_i16x8\_s}` :math:`\hex{FD}~~\hex{A8}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\VEXTEND\K{\_low\_i16x8\_u}` :math:`\hex{FD}~~\hex{A9}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\VEXTEND\K{\_high\_i16x8\_u}` :math:`\hex{FD}~~\hex{AA}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\VSHL` :math:`\hex{FD}~~\hex{AB}~~\hex{01}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VSHR\K{\_s}` :math:`\hex{FD}~~\hex{AC}~~\hex{01}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VSHR\K{\_u}` :math:`\hex{FD}~~\hex{AD}~~\hex{01}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VADD` :math:`\hex{FD}~~\hex{AE}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VSUB` :math:`\hex{FD}~~\hex{B1}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VMUL` :math:`\hex{FD}~~\hex{B5}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VMIN\K{\_s}` :math:`\hex{FD}~~\hex{B6}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VMIN\K{\_u}` :math:`\hex{FD}~~\hex{B7}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VMAX\K{\_s}` :math:`\hex{FD}~~\hex{B8}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VMAX\K{\_u}` :math:`\hex{FD}~~\hex{B9}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\DOT\K{\_i16x8\_s}` :math:`\hex{FD}~~\hex{BA}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\EXTMUL\K{\_low\_i16x8\_s}` :math:`\hex{FD}~~\hex{BC}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\EXTMUL\K{\_high\_i16x8\_s}` :math:`\hex{FD}~~\hex{BD}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\EXTMUL\K{\_low\_i16x8\_u}` :math:`\hex{FD}~~\hex{BE}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\EXTMUL\K{\_high\_i16x8\_u}` :math:`\hex{FD}~~\hex{BF}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I64X2.\VABS` :math:`\hex{FD}~~\hex{C0}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64X2.\VNEG` :math:`\hex{FD}~~\hex{C1}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64X2.\ALLTRUE` :math:`\hex{FD}~~\hex{C3}~~\hex{01}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I64X2.\BITMASK` :math:`\hex{FD}~~\hex{C4}~~\hex{01}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I64X2.\VEXTEND\K{\_low\_i32x4\_s}` :math:`\hex{FD}~~\hex{C7}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I64X2.\VEXTEND\K{\_high\_i32x4\_s}` :math:`\hex{FD}~~\hex{C8}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I64X2.\VEXTEND\K{\_low\_i32x4\_u}` :math:`\hex{FD}~~\hex{C9}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I64X2.\VEXTEND\K{\_high\_i32x4\_u}` :math:`\hex{FD}~~\hex{CA}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I64X2.\VSHL` :math:`\hex{FD}~~\hex{CB}~~\hex{01}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64X2.\VSHR\K{\_s}` :math:`\hex{FD}~~\hex{CC}~~\hex{01}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64X2.\VSHR\K{\_u}` :math:`\hex{FD}~~\hex{CD}~~\hex{01}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64X2.\VADD` :math:`\hex{FD}~~\hex{CE}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64X2.\VSUB` :math:`\hex{FD}~~\hex{D1}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64X2.\VMUL` :math:`\hex{FD}~~\hex{D5}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64X2.\VEQ` :math:`\hex{FD}~~\hex{D6}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64X2.\VNE` :math:`\hex{FD}~~\hex{D7}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64X2.\VLT\K{\_s}` :math:`\hex{FD}~~\hex{D8}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64X2.\VGT\K{\_s}` :math:`\hex{FD}~~\hex{D9}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64X2.\VLE\K{\_s}` :math:`\hex{FD}~~\hex{DA}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64X2.\VGE\K{\_s}` :math:`\hex{FD}~~\hex{DB}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64X2.\EXTMUL\K{\_low\_i32x4\_s}` :math:`\hex{FD}~~\hex{DC}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I64X2.\EXTMUL\K{\_high\_i32x4\_s}` :math:`\hex{FD}~~\hex{DD}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I64X2.\EXTMUL\K{\_low\_i32x4\_u}` :math:`\hex{FD}~~\hex{DE}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I64X2.\EXTMUL\K{\_high\_i32x4\_u}` :math:`\hex{FD}~~\hex{DF}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\F32X4.\VABS` :math:`\hex{FD}~~\hex{E0}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VNEG` :math:`\hex{FD}~~\hex{E1}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VSQRT` :math:`\hex{FD}~~\hex{E3}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VADD` :math:`\hex{FD}~~\hex{E4}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VSUB` :math:`\hex{FD}~~\hex{E5}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VMUL` :math:`\hex{FD}~~\hex{E6}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VDIV` :math:`\hex{FD}~~\hex{E7}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VMIN` :math:`\hex{FD}~~\hex{E8}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VMAX` :math:`\hex{FD}~~\hex{E9}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VPMIN` :math:`\hex{FD}~~\hex{EA}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VPMAX` :math:`\hex{FD}~~\hex{EB}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VABS` :math:`\hex{FD}~~\hex{EC}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VNEG` :math:`\hex{FD}~~\hex{ED}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VSQRT` :math:`\hex{FD}~~\hex{EF}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VADD` :math:`\hex{FD}~~\hex{F0}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VSUB` :math:`\hex{FD}~~\hex{F1}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VMUL` :math:`\hex{FD}~~\hex{F2}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VDIV` :math:`\hex{FD}~~\hex{F3}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VMIN` :math:`\hex{FD}~~\hex{F4}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VMAX` :math:`\hex{FD}~~\hex{F5}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VPMIN` :math:`\hex{FD}~~\hex{F6}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VPMAX` :math:`\hex{FD}~~\hex{F7}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\TRUNC\K{\_sat\_f32x4\_s}` :math:`\hex{FD}~~\hex{F8}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\TRUNC\K{\_sat\_f32x4\_u}` :math:`\hex{FD}~~\hex{F9}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VCONVERT\K{\_i32x4\_s}` :math:`\hex{FD}~~\hex{FA}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VCONVERT\K{\_i32x4\_u}` :math:`\hex{FD}~~\hex{FB}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VTRUNC\K{\_sat\_f64x2\_s\_zero}` :math:`\hex{FD}~~\hex{FC}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VTRUNC\K{\_sat\_f64x2\_u\_zero}` :math:`\hex{FD}~~\hex{FD}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VCONVERT\K{\_low\_i32x4\_s}` :math:`\hex{FD}~~\hex{FE}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VCONVERT\K{\_low\_i32x4\_u}` :math:`\hex{FD}~~\hex{FF}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -================================================= ==================================== ============================================= ============================================= ================================================================== - -.. note:: - Multi-byte opcodes are given with the shortest possible encoding in the table. - However, what is following the first byte is actually a :ref:`u32 ` with variable-length encoding - and consequently has multiple possible representations. diff --git a/document/core/appendix/index-rules.rst b/document/core/appendix/index-rules.rst index 5092be632..1cb3607ee 100644 --- a/document/core/appendix/index-rules.rst +++ b/document/core/appendix/index-rules.rst @@ -23,6 +23,7 @@ Construct Judgement :ref:`External type ` :math:`\vdashexterntype \externtype \ok` :ref:`Instruction ` :math:`S;C \vdashinstr \instr : \stacktype` :ref:`Instruction sequence ` :math:`S;C \vdashinstrseq \instr^\ast : \stacktype` +:ref:`Catch clause ` :math:`C \vdashcatch \catch \ok` :ref:`Expression ` :math:`C \vdashexpr \expr : \resulttype` :ref:`Function ` :math:`C \vdashfunc \func : \functype` :ref:`Table ` :math:`C \vdashtable \table : \tabletype` diff --git a/document/core/appendix/index-types.rst b/document/core/appendix/index-types.rst index 5ec06bf4d..e560796b9 100644 --- a/document/core/appendix/index-types.rst +++ b/document/core/appendix/index-types.rst @@ -16,7 +16,9 @@ Category Constructor (reserved) :math:`\hex{7A}` .. :math:`\hex{71}` :ref:`Reference type ` |FUNCREF| :math:`\hex{70}` (-16 as |Bs7|) :ref:`Reference type ` |EXTERNREF| :math:`\hex{6F}` (-17 as |Bs7|) -(reserved) :math:`\hex{6E}` .. :math:`\hex{61}` +(reserved) :math:`\hex{6E}` .. :math:`\hex{6A}` +:ref:`Reference type ` |EXNREF| :math:`\hex{69}` (-23 as |Bs7|) +(reserved) :math:`\hex{68}` .. :math:`\hex{61}` :ref:`Function type ` :math:`[\valtype^\ast] \to [\valtype^\ast]` :math:`\hex{60}` (-32 as |Bs7|) (reserved) :math:`\hex{5F}` .. :math:`\hex{41}` :ref:`Result type ` :math:`[\epsilon]` :math:`\hex{40}` (-64 as |Bs7|) diff --git a/document/core/appendix/properties.rst b/document/core/appendix/properties.rst index 2c2c3eea3..de9faa46c 100644 --- a/document/core/appendix/properties.rst +++ b/document/core/appendix/properties.rst @@ -58,8 +58,23 @@ Results S \vdashresult \TRAP : [t^\ast] } -.. todo:: - Add validation for exception results. + +:ref:`Results ` :math:`\XT[(\REFEXNADDR~a)~\THROWREF]` +..................................................................... + +* The value :math:`\REFEXNADDR~a` must be :ref:`valid `. + +* Then the result is valid with :ref:`result type ` :math:`[t^\ast]`, for any sequence :math:`{t'}^\ast` of :ref:`value types `. + + +.. math:: + \frac{ + S \vdashexternval \EVTAG~\tagaddr : \ETTAG~[t^\ast] \to [] + \qquad + (S \vdashval \val : t)^\ast + }{ + S \vdashresult \XT[(\REFEXNADDR~a)~\THROWREF] : [{t'}^\ast] + } .. _module-context: @@ -96,6 +111,8 @@ Module instances are classified by *module contexts*, which are regular :ref:`co * Each :ref:`data instance ` :math:`\datainst_i` in :math:`S.\SDATAS` must be :ref:`valid `. +* Each :ref:`exception instance ` :math:`\exninst_i` in :math:`S.\SEXNS` must be :ref:`valid `. + * Then the store is valid. .. math:: @@ -115,6 +132,8 @@ Module instances are classified by *module contexts*, which are regular :ref:`co (S \vdasheleminst \eleminst : \reftype)^\ast \qquad (S \vdashdatainst \datainst \ok)^\ast + \qquad + (S \vdashexninst \exninst \ok)^\ast \\ S = \{ \SFUNCS~\funcinst^\ast, @@ -124,7 +143,8 @@ Module instances are classified by *module contexts*, which are regular :ref:`co \\ \SGLOBALS~\globalinst^\ast, \SELEMS~\eleminst^\ast, - \SDATAS~\datainst^\ast \} + \SDATAS~\datainst^\ast, + \SEXNS~\exninst^\ast \} \end{array} }{ \vdashstore S \ok @@ -337,6 +357,34 @@ Module instances are classified by *module contexts*, which are regular :ref:`co } +.. index:: exception instance, tag, tag address +.. _valid-exninst: + +:ref:`Exception Instances ` :math:`\{ \EITAG~a, \EIFIELDS~\val^\ast \}` +....................................................................................... + +* The store entry :math:`S.\STAGS[a]` must exist. + +* Let :math:`[t^\ast] \toF [{t'}^\ast]` be the :ref:`tag type ` :math:`S.\STAGS[a].\TAGITYPE`. + +* The :ref:`result type ` :math:`[{t'}^\ast]` must be empty. + +* The sequence :math:`\val^ast` of :ref:`values ` must have the same length as the sequence :math:`t^\ast` of :ref:`value types `. + +* For each value :math:`\val_i` in :math:`\val^ast` and corresponding value type :math:`t_i` in :math:`t^\ast`, the value :math:`\val_i` must be valid with type :math:`t_i`. + +* Then the exception instance is valid. + +.. math:: + \frac{ + S.\STAGS[a] = \{\TAGITYPE = [t^\ast] \toF []\} + \qquad + (S \vdashval \val : t)^\ast + }{ + S \vdashexninst \{ \EITAG~a, \EIFIELDS~\val^\ast \} \ok + } + + .. index:: external type, export instance, name, external value .. _valid-exportinst: @@ -564,146 +612,20 @@ To that end, all previous typing judgements :math:`C \vdash \X{prop}` are genera } -.. index:: extern address - -:math:`\REFEXTERNADDR~\externaddr` -.................................. - -* The instruction is valid with type :math:`[] \to [\EXTERNREF]`. - -.. math:: - \frac{ - }{ - S; C \vdashadmininstr \REFEXTERNADDR~\externaddr : [] \to [\EXTERNREF] - } - - -.. index:: function address, extern value, extern type, function type - -:math:`\REFFUNCADDR~\funcaddr` -.............................. - -* The :ref:`external function value ` :math:`\EVFUNC~\funcaddr` must be :ref:`valid ` with :ref:`external function type ` :math:`\ETFUNC~\functype`. - -* Then the instruction is valid with type :math:`[] \to [\FUNCREF]`. - -.. math:: - \frac{ - S \vdashexternval \EVFUNC~\funcaddr : \ETFUNC~\functype - }{ - S; C \vdashadmininstr \REFFUNCADDR~\funcaddr : [] \to [\FUNCREF] - } - - -.. index:: throw, throw context, tag address - -:math:`\THROWadm~\tagaddr` -.......................... - -* The :ref:`external tag value ` :math:`\EVTAG~\tagaddr` must be :ref:`valid ` with :ref:`external tag type ` :math:`\ETTAG~[t^\ast]\to[]`. - -* Then the instruction is valid with type :math:`[t_1^\ast t^\ast] \to [t_2^\ast]` for any sequences of :ref:`value types ` :math:`t_1^\ast` and :math:`t_2^\ast`. - -.. math:: - \frac{ - S \vdashexternval \EVTAG~\tagaddr : \ETTAG~[t^\ast]\to[] - }{ - S; C \vdashadmininstr \THROWadm~\tagaddr : [t_1^\ast t^\ast] \to [t_2^\ast] - } - - -.. index:: catch, throw context - -:math:`\CATCHadm\{\tagaddr^?~\instr_1^\ast\}^\ast~\instr_2^\ast~\END` -..................................................................... - -* Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with the :ref:`label type ` :math:`[t_2^\ast]` prepended to the |CLABELS| vector. - -* Under context :math:`C'`, - the instruction sequence :math:`\instr_2^\ast` must be :ref:`valid ` with type :math:`[] \to [t_2^\ast]`. - -* Let :math:`C''` be the same :ref:`context ` as :math:`C`, but with the :ref:`label type ` :math:`(\LCATCH~[t_2^\ast])` prepended to the |CLABELS| vector. +.. index:: value, reference -* Under context :math:`C''`, - for every :math:`\tagaddr^?` and associated instruction sequence :math:`\instr_1^\ast`: - - * If :math:`\tagaddr^? = \epsilon`, then :math:`\instr_1^\ast` must be :ref:`valid ` with type :math:`[] \to [t_2^\ast]`. - - * Else: - - * The :ref:`external tag value ` :math:`\EVTAG~\tagaddr` must be :ref:`valid ` with some :ref:`external tag type ` :math:`\ETTAG~[t_1^\ast] \to []`. - - * The instruction sequence :math:`\instr_1^\ast` must be :ref:`valid ` with type :math:`[t_1^\ast] \to [t_2^\ast]`. - -* Then the compound instruction is valid under context :math:`C'` with type :math:`[] \to [t_2^\ast]`. - -.. math:: - \frac{ - \begin{array}{@{}c@{}} - ((S \vdashexternval \EVTAG~\tagaddr : \ETTAG~[t_1^\ast]\to[])^? \\ - ~~S; C,\CLABELS\,(\LCATCH~[t_2^\ast]) \vdashinstrseq \instr_1^\ast : [(t_1^\ast)^?] \to [t_2^\ast])^\ast \\ - S; C,\CLABELS\,[t_2^\ast] \vdashinstrseq \instr_2^\ast : [] \to [t_2^\ast] \\ - \end{array} - }{ - S; C,\CLABELS\,[t_2^\ast] \vdashadmininstr \CATCHadm\{\tagaddr^?~{\instr_1}^\ast\}^\ast~\instr_2^\ast~\END : [] \to [t_2^\ast] - } - - -.. index:: delegate, throw context - -:math:`\DELEGATEadm\{l\}~\instr^\ast~\END` -.......................................... - -* The label :math:`C.\CLABELS[l]` must be defined in the context. - -* Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with the label :math:`[t^\ast]` prepended to the |CLABELS| vector. - -* Under context :math:`C'`, - the instruction sequence :math:`\instr^\ast` must be :ref:`valid ` with type :math:`[]\to[t^\ast]`. - -* Then the compound instruction is valid under context :math:`C'` with type :math:`[] \to [t^\ast]`. - -.. math:: - \frac{ - S; C,\CLABELS\,[t^\ast] \vdashinstrseq \instr^\ast : [] \to [t^\ast] - \qquad - C.\CLABELS[l] = \LCATCH^?~[t_0^\ast] - }{ - S; C,\CLABELS\,[t^\ast] \vdashadmininstr \DELEGATEadm\{l\}~\instr^\ast~\END : [] \to [t^\ast] - } - - -.. index:: caught, throw context - -:math:`\CAUGHTadm_n\{\tagaddr~\val^\ast\}~\instr^\ast~\END` -........................................................... - -* The :ref:`external tag value ` :math:`\EVTAG~\tagaddr` must be :ref:`valid ` with some :ref:`external tag type ` :math:`\ETTAG~[t_0^\ast] \to []`. - -* The :ref:`values ` :math:`\val^\ast` must be of type :math:`[t_0^\ast]`. - -* The label :math:`C.\CLABELS[0]` must be defined in the context. - -* Let :math:`(\LCATCH^?~[t^n])` be the :ref:`label type ` :math:`C.\CLABELS[0]`. - -* The |LCATCH| must not be present in the label type :math:`C.\CLABELS[0]`. - -* Let :math:`C''` be the same :ref:`context ` as :math:`C`, but with the label type :math:`(\LCATCH~[t^n])` replacing the first element of the |CLABELS| vector. +:math:`\reff` +............. -* Under context :math:`C''`, - the instruction sequence :math:`\instr^\ast` must be :ref:`valid ` with type :math:`[] \to [t^n]`. +* The reference :math:`\reff` must be :ref:`valid ` with some type :math:`t`. -* Then the compound instruction is valid with type :math:`[] \to [t^n]`. +* Then the instruction is valid with type :math:`[] \to [t]`. .. math:: \frac{ - S \vdashexternval \EVTAG~\tagaddr : \ETTAG~[t_0^\ast]\to[] - \qquad - (val : t_0)^\ast - \qquad - S; C',\CLABELS\,(\LCATCH~[t^n]) \vdashinstrseq \instr^\ast : [] \to [t^n] + S \vdashval \reff : t }{ - S; C',\CLABELS\,[t^n] \vdashadmininstr \CAUGHTadm_n\{\tagaddr~\val^\ast\}~\instr^\ast~\END : [] \to [t^n] + S; C \vdashadmininstr \reff : [] \to [t] } @@ -731,7 +653,7 @@ To that end, all previous typing judgements :math:`C \vdash \X{prop}` are genera * The instruction sequence :math:`\instr_0^\ast` must be :ref:`valid ` with some type :math:`[t_1^n] \to [t_2^*]`. -* Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with the :ref:`label type ` :math:`[t_1^n]` prepended to the |CLABELS| vector. +* Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with the :ref:`result type ` :math:`[t_1^n]` prepended to the |CLABELS| vector. * Under context :math:`C'`, the instruction sequence :math:`\instr^\ast` must be :ref:`valid ` with type :math:`[] \to [t_2^*]`. @@ -748,6 +670,29 @@ To that end, all previous typing judgements :math:`C \vdash \X{prop}` are genera } +.. index:: handler, throw context + +:math:`\HANDLER_n\{\catch^\ast\}~\instr^\ast~\END` +.................................................. + +* For every :ref:`catch clause ` :math:`\catch_i` in :math:`\catch^\ast`, :math:`\catch_i` must be :ref:`valid `. + +* The instruction sequence :math:`\instr^\ast` must be :ref:`valid ` with some type :math:`[t_1^\ast] \to [t_2^\ast]`. + +* Then the compound instruction is valid with type :math:`[t_1^\ast] \to [t_2^\ast]`. + +.. math:: + \frac{ + \begin{array}{c} + (C \vdashcatch \catch \ok)^\ast + \qquad + S; C \vdashinstrseq \instr^\ast : [t_1^\ast] \to [t_2^\ast] \\ + \end{array} + }{ + S; C \vdashadmininstr \HANDLER_n\{\catch^\ast\}~\instr^\ast~\END : [t_1^\ast] \to [t_2^\ast] + } + + .. index:: frame, instruction, result type :math:`\FRAME_n\{F\}~\instr^\ast~\END` @@ -805,6 +750,8 @@ a store state :math:`S'` extends state :math:`S`, written :math:`S \extendsto S' * The length of :math:`S.\SDATAS` must not shrink. +* The length of :math:`S.\SEXNS` must not shrink. + * For each :ref:`function instance ` :math:`\funcinst_i` in the original :math:`S.\SFUNCS`, the new function instance must be an :ref:`extension ` of the old. * For each :ref:`table instance ` :math:`\tableinst_i` in the original :math:`S.\STABLES`, the new table instance must be an :ref:`extension ` of the old. @@ -815,9 +762,11 @@ a store state :math:`S'` extends state :math:`S`, written :math:`S \extendsto S' * For each :ref:`global instance ` :math:`\globalinst_i` in the original :math:`S.\SGLOBALS`, the new global instance must be an :ref:`extension ` of the old. -* For each :ref:`element instance ` :math:`\eleminst_i` in the original :math:`S.\SELEMS`, the new global instance must be an :ref:`extension ` of the old. +* For each :ref:`element instance ` :math:`\eleminst_i` in the original :math:`S.\SELEMS`, the new element instance must be an :ref:`extension ` of the old. + +* For each :ref:`data instance ` :math:`\datainst_i` in the original :math:`S.\SDATAS`, the new data instance must be an :ref:`extension ` of the old. -* For each :ref:`data instance ` :math:`\datainst_i` in the original :math:`S.\SDATAS`, the new global instance must be an :ref:`extension ` of the old. +* For each :ref:`exception instance ` :math:`\exninst_i` in the original :math:`S.\SEXNS`, the new exception instance must be an :ref:`extension ` of the old. .. math:: \frac{ @@ -843,6 +792,9 @@ a store state :math:`S'` extends state :math:`S`, written :math:`S \extendsto S' S_1.\SDATAS = \datainst_1^\ast & S_2.\SDATAS = {\datainst'_1}^\ast~\datainst_2^\ast & (\vdashdatainstextends \datainst_1 \extendsto \datainst'_1)^\ast \\ + S_1.\SEXNS = \exninst_1^\ast & + S_2.\SEXNS = {\exninst'_1}^\ast~\exninst_2^\ast & + (\vdashexninstextends \exninst_1 \extendsto \exninst'_1)^\ast \\ \end{array} }{ \vdashstoreextends S_1 \extendsto S_2 @@ -967,6 +919,21 @@ a store state :math:`S'` extends state :math:`S`, written :math:`S \extendsto S' } +.. index:: exception instance +.. _extend-exninst: + +:ref:`Exception Instance ` :math:`\exninst` +........................................................... + +* An exception instance must remain unchanged. + +.. math:: + \frac{ + }{ + \vdashexninstextends \exninst \extendsto \exninst + } + + .. index:: ! preservation, ! progress, soundness, configuration, thread, terminal configuration, instantiation, invocation, validity, module .. _soundness-statement: diff --git a/document/core/binary/instructions.rst b/document/core/binary/instructions.rst index b8ac093f1..d26bfc481 100644 --- a/document/core/binary/instructions.rst +++ b/document/core/binary/instructions.rst @@ -21,7 +21,7 @@ The only exception are :ref:`structured control instructions ` have varying encodings. For structured instructions, the instruction sequences forming nested blocks are separated or terminated with explicit opcodes for |END|, |ELSE|, |CATCH|, |CATCHALL|, and |DELEGATE|. +:ref:`Control instructions ` have varying encodings. For structured instructions, the instruction sequences forming nested blocks are delimited with explicit opcodes for |END| and |ELSE|. :ref:`Block types ` are encoded in special compressed form, by either the byte :math:`\hex{40}` indicating the empty type, as a single :ref:`value type `, or as a :ref:`type index ` encoded as a positive :ref:`signed integer `. @@ -31,22 +31,23 @@ Control Instructions .. _binary-block: .. _binary-loop: .. _binary-if: -.. _binary-try: +.. _binary-try_table: .. _binary-throw: -.. _binary-rethrow: +.. _binary-throw_ref: .. _binary-br: .. _binary-br_if: .. _binary-br_table: .. _binary-return: .. _binary-call: .. _binary-call_indirect: +.. _binary-catch: .. math:: - \begin{array}{llcllll} + \begin{array}{@{}l@{}lclll@{}} \production{block type} & \Bblocktype &::=& \hex{40} &\Rightarrow& \epsilon \\ &&|& t{:}\Bvaltype &\Rightarrow& t \\ &&|& - x{:}\Bs33 &\Rightarrow& x & (\iff x \geq 0) \\ + x{:}\Bs33 &\Rightarrow& x \qquad\qquad (\iff x \geq 0) \\ \production{instruction} & \Binstr &::=& \hex{00} &\Rightarrow& \UNREACHABLE \\ &&|& \hex{01} &\Rightarrow& \NOP \\ &&|& @@ -59,22 +60,22 @@ Control Instructions \hex{04}~~\X{bt}{:}\Bblocktype~~(\X{in}_1{:}\Binstr)^\ast~~ \hex{05}~~(\X{in}_2{:}\Binstr)^\ast~~\hex{0B} &\Rightarrow& \IF~\X{bt}~\X{in}_1^\ast~\ELSE~\X{in}_2^\ast~\END \\ &&|& - \hex{06}~~\X{bt}{:}\Bblocktype~~(\X{in}_1{:}\Binstr)^\ast~~ - (\hex{07}~~x{:}\Btagidx~~(\X{in}_2{:}\Binstr)^\ast)^\ast~~ - (\hex{19}~~(\X{in}_3{:}\Binstr)^\ast)^?~~\hex{0B} - &\Rightarrow& \TRY~\X{bt}~\X{in}_1^\ast~(\CATCH~x~\X{in}_2^\ast)^\ast~ - (\CATCHALL~\X{in}_3^\ast)^?\END \\ &&|& - \hex{06}~~\X{bt}{:}\Bblocktype~~(\X{in}{:}\Binstr)^\ast~~\hex{18}~~l{:}\Blabelidx - &\Rightarrow& \TRY~\X{bt}~\X{in}^\ast~\DELEGATE~l \\ &&|& \hex{08}~~x{:}\Btagidx &\Rightarrow& \THROW~x \\ &&|& - \hex{09}~~l{:}\Blabelidx &\Rightarrow& \RETHROW~l \\ &&|& + \hex{0A} &\Rightarrow& \THROWREF \\ &&|& \hex{0C}~~l{:}\Blabelidx &\Rightarrow& \BR~l \\ &&|& \hex{0D}~~l{:}\Blabelidx &\Rightarrow& \BRIF~l \\ &&|& \hex{0E}~~l^\ast{:}\Bvec(\Blabelidx)~~l_N{:}\Blabelidx &\Rightarrow& \BRTABLE~l^\ast~l_N \\ &&|& \hex{0F} &\Rightarrow& \RETURN \\ &&|& \hex{10}~~x{:}\Bfuncidx &\Rightarrow& \CALL~x \\ &&|& - \hex{11}~~y{:}\Btypeidx~~x{:}\Btableidx &\Rightarrow& \CALLINDIRECT~x~y \\ + \hex{11}~~y{:}\Btypeidx~~x{:}\Btableidx &\Rightarrow& \CALLINDIRECT~x~y \\ &&|& + \hex{1F}~~\X{bt}{:}\Bblocktype~~c^\ast{:}\Bvec(\Bcatch)~~(\X{in}{:}\Binstr)^\ast~~\hex{0B} + &\Rightarrow& \TRYTABLE~\X{bt}~c^\ast~\X{in}^\ast~\END \\ + \production{catch clause} & \Bcatch &::=& + \hex{00}~~x{:}\Btagidx~~l{:}\Blabelidx &\Rightarrow& \CATCH~x~l \\ &&|& + \hex{01}~~x{:}\Btagidx~~l{:}\Blabelidx &\Rightarrow& \CATCHREF~x~l \\ &&|& + \hex{02}~~l{:}\Blabelidx &\Rightarrow& \CATCHALL~l \\ &&|& + \hex{03}~~l{:}\Blabelidx &\Rightarrow& \CATCHALLREF~l \\ \end{array} .. note:: diff --git a/document/core/binary/types.rst b/document/core/binary/types.rst index d9e1ca10a..2eef0bee1 100644 --- a/document/core/binary/types.rst +++ b/document/core/binary/types.rst @@ -58,7 +58,8 @@ Reference Types \begin{array}{llclll@{\qquad\qquad}l} \production{reference type} & \Breftype &::=& \hex{70} &\Rightarrow& \FUNCREF \\ &&|& - \hex{6F} &\Rightarrow& \EXTERNREF \\ + \hex{6F} &\Rightarrow& \EXTERNREF \\ &&|& + \hex{69} &\Rightarrow& \EXNREF \\ \end{array} diff --git a/document/core/conf.py b/document/core/conf.py index 22a578a2d..d6e5eb5a2 100644 --- a/document/core/conf.py +++ b/document/core/conf.py @@ -66,10 +66,10 @@ logo = 'static/webassembly.png' # The name of the GitHub repository this resides in -repo = 'spec' +repo = 'exception-handling' # The name of the proposal it represents, if any -proposal = '' +proposal = 'exception handling' # The draft version string (clear out for release cuts) draft = ' (Draft ' + date.today().strftime("%Y-%m-%d") + ')' @@ -297,7 +297,8 @@ 'pointsize': '10pt', # Additional stuff for the LaTeX preamble. - 'preamble': '', + # Don't type-set cross references with emphasis. + 'preamble': '\\renewcommand\\sphinxcrossref[1]{#1}\n', # Latex figure (float) alignment 'figure_align': 'htbp', diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index b61bbc2c6..0fa0e86fc 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -220,9 +220,9 @@ Reference Instructions .. math:: \begin{array}{lcl@{\qquad}l} - \val~\REFISNULL &\stepto& \I32.\CONST~1 + \val~\REFISNULL &\stepto& (\I32.\CONST~1) & (\iff \val = \REFNULL~t) \\ - \val~\REFISNULL &\stepto& \I32.\CONST~0 + \val~\REFISNULL &\stepto& (\I32.\CONST~0) & (\otherwise) \\ \end{array} @@ -242,7 +242,7 @@ Reference Instructions .. math:: \begin{array}{lcl@{\qquad}l} - F; \REFFUNC~x &\stepto& F; \REFFUNCADDR~a + F; (\REFFUNC~x) &\stepto& F; (\REFFUNCADDR~a) & (\iff a = F.\AMODULE.\MIFUNCS[x]) \\ \end{array} @@ -379,22 +379,22 @@ Most vector instructions are defined in terms of generic numeric operators appli 2. Pop the value :math:`\V128.\VCONST~c_2` from the stack. -3. Let :math:`i^\ast` be the sequence :math:`\lanes_{i8x16}(c_2)`. +3. Let :math:`i^\ast` be the result of computing :math:`\lanes_{i8x16}(c_2)`. 4. Pop the value :math:`\V128.\VCONST~c_1` from the stack. -5. Let :math:`j^\ast` be the sequence :math:`\lanes_{i8x16}(c_1)`. +5. Let :math:`j^\ast` be the result of computing :math:`\lanes_{i8x16}(c_1)`. -6. Let :math:`c^\ast` be the concatenation of the two sequences :math:`j^\ast~0^{240}` +6. Let :math:`c^\ast` be the concatenation of the two sequences :math:`j^\ast` and :math:`0^{240}`. -7. Let :math:`c'` be the result of :math:`\lanes^{-1}_{i8x16}(c^\ast[ i^\ast[0] ] \dots c^\ast[ i^\ast[15] ])`. +7. Let :math:`c'` be the result of computing :math:`\lanes^{-1}_{i8x16}(c^\ast[ i^\ast[0] ] \dots c^\ast[ i^\ast[15] ])`. 8. Push the value :math:`\V128.\VCONST~c'` onto the stack. .. math:: \begin{array}{l} \begin{array}{lcl@{\qquad}l} - (\V128\K{.}\VCONST~c_1)~(\V128\K{.}\VCONST~c_2)~\V128\K{.}\SWIZZLE &\stepto& (\V128\K{.}\VCONST~c') + (\V128\K{.}\VCONST~c_1)~(\V128\K{.}\VCONST~c_2)~\I8X16\K{.}\SWIZZLE &\stepto& (\V128\K{.}\VCONST~c') \end{array} \\ \qquad \begin{array}[t]{@{}r@{~}l@{}} @@ -416,22 +416,22 @@ Most vector instructions are defined in terms of generic numeric operators appli 3. Pop the value :math:`\V128.\VCONST~c_2` from the stack. -4. Let :math:`i_2^\ast` be the sequence :math:`\lanes_{i8x16}(c_2)`. +4. Let :math:`i_2^\ast` be the result of computing :math:`\lanes_{i8x16}(c_2)`. 5. Pop the value :math:`\V128.\VCONST~c_1` from the stack. -6. Let :math:`i_1^\ast` be the sequence :math:`\lanes_{i8x16}(c_1)`. +6. Let :math:`i_1^\ast` be the result of computing :math:`\lanes_{i8x16}(c_1)`. -7. Let :math:`i^\ast` be the concatenation of the two sequences :math:`i_1^\ast~i_2^\ast`. +7. Let :math:`i^\ast` be the concatenation of the two sequences :math:`i_1^\ast` and :math:`i_2^\ast`. -8. Let :math:`c` be the result of :math:`\lanes^{-1}_{i8x16}(i^\ast[x^\ast[0]] \dots i^\ast[x^\ast[15]])`. +8. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{i8x16}(i^\ast[x^\ast[0]] \dots i^\ast[x^\ast[15]])`. 9. Push the value :math:`\V128.\VCONST~c` onto the stack. .. math:: \begin{array}{l} \begin{array}{lcl@{\qquad}l} - (\V128\K{.}\VCONST~c_1)~(\V128\K{.}\VCONST~c_2)~\V128\K{.}\SHUFFLE~x^\ast &\stepto& (\V128\K{.}\VCONST~c) + (\V128\K{.}\VCONST~c_1)~(\V128\K{.}\VCONST~c_2)~(\I8X16\K{.}\SHUFFLE~x^\ast) &\stepto& (\V128\K{.}\VCONST~c) \end{array} \\ \qquad \begin{array}[t]{@{}r@{~}l@{}} @@ -454,7 +454,7 @@ Most vector instructions are defined in terms of generic numeric operators appli 4. Let :math:`N` be the integer :math:`\dim(\shape)`. -5. Let :math:`c` be the result of :math:`\lanes^{-1}_{\shape}(c_1^N)`. +5. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{\shape}(c_1^N)`. 6. Push the value :math:`\V128.\VCONST~c` to the stack. @@ -478,7 +478,7 @@ Most vector instructions are defined in terms of generic numeric operators appli 3. Pop the value :math:`\V128.\VCONST~c_1` from the stack. -4. Let :math:`i^\ast` be the sequence :math:`\lanes_{t_1\K{x}N}(c_1)`. +4. Let :math:`i^\ast` be the result of computing :math:`\lanes_{t_1\K{x}N}(c_1)`. 5. Let :math:`t_2` be the type :math:`\unpacked(t_1\K{x}N)`. @@ -489,7 +489,7 @@ Most vector instructions are defined in terms of generic numeric operators appli .. math:: \begin{array}{l} \begin{array}{lcl@{\qquad}l} - (\V128\K{.}\VCONST~c_1)~t_1\K{x}N\K{.}\EXTRACTLANE~x &\stepto& (t_2\K{.}\CONST~c_2) + (\V128\K{.}\VCONST~c_1)~(t_1\K{x}N\K{.}\EXTRACTLANE~x) &\stepto& (t_2\K{.}\CONST~c_2) \end{array} \\ \qquad \begin{array}[t]{@{}r@{~}l@{}} @@ -516,16 +516,16 @@ Most vector instructions are defined in terms of generic numeric operators appli 6. Pop the value :math:`\V128.\VCONST~c_2` from the stack. -7. Let :math:`i^\ast` be the sequence :math:`\lanes_{\shape}(c_2)`. +7. Let :math:`i^\ast` be the result of computing :math:`\lanes_{\shape}(c_2)`. -8. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{\shape}(i^\ast \with [x] = c_1)` +8. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{\shape}(i^\ast \with [x] = c_1)`. 9. Push :math:`\V128.\VCONST~c` on the stack. .. math:: \begin{array}{l} \begin{array}{lcl@{\qquad}l} - (t_1\K{.}\CONST~c_1)~(\V128\K{.}\VCONST~c_2)~\shape\K{.}\REPLACELANE~x &\stepto& (\V128\K{.}\VCONST~c) + (t_1\K{.}\CONST~c_1)~(\V128\K{.}\VCONST~c_2)~(\shape\K{.}\REPLACELANE~x) &\stepto& (\V128\K{.}\VCONST~c) \end{array} \\ \qquad \begin{array}[t]{@{}r@{~}l@{}} @@ -596,13 +596,17 @@ Most vector instructions are defined in terms of generic numeric operators appli 3. Pop the value :math:`\V128.\VCONST~c_1` from the stack. -4. Let :math:`i^\ast` be the sequence :math:`\lanes_{t\K{x}N}(c_1)`. +4. Let :math:`i_1^\ast` be the result of computing :math:`\lanes_{t\K{x}N}(c_1)`. -5. Let :math:`j^\ast` be the sequence :math:`\lanes_{t\K{x}N}(c_2)`. +5. Let :math:`i_2^\ast` be the result of computing :math:`\lanes_{t\K{x}N}(c_2)`. -6. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{t\K{x}N}(\extends_{1,|t|}(\vrelop_t(i^\ast, j^\ast)))`. +6. Let :math:`i^\ast` be the result of computing :math:`\vrelop_t(i_1^\ast, i_2^\ast)`. -7. Push the value :math:`\V128.\VCONST~c` to the stack. +7. Let :math:`j^\ast` be the result of computing :math:`\extends_{1,|t|}(i^\ast)`. + +8. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{t\K{x}N}(j^\ast)`. + +9. Push the value :math:`\V128.\VCONST~c` to the stack. .. math:: \begin{array}{l} @@ -629,11 +633,13 @@ Most vector instructions are defined in terms of generic numeric operators appli 4. Pop the value :math:`\V128.\VCONST~c_1` from the stack. -5. Let :math:`i^\ast` be the sequence :math:`\lanes_{t\K{x}N}(c_1)`. +5. Let :math:`i^\ast` be the result of computing :math:`\lanes_{t\K{x}N}(c_1)`. + +6. Let :math:`j^\ast` be the result of computing :math:`\vishiftop_{t}(i^\ast, s^N)`. -6. Let :math:`c` be :math:`\lanes^{-1}_{t\K{x}N}(\vishiftop_{t}(i^\ast, s^N))`. +7. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{t\K{x}N}(j^\ast)`. -7. Push the value :math:`\V128.\VCONST~c` to the stack. +8. Push the value :math:`\V128.\VCONST~c` to the stack. .. math:: \begin{array}{l} @@ -658,7 +664,7 @@ Most vector instructions are defined in terms of generic numeric operators appli 2. Pop the value :math:`\V128.\VCONST~c_1` from the stack. -3. Let :math:`i_1^\ast` be the sequence :math:`\lanes_{\shape}(c_1)` +3. Let :math:`i_1^\ast` be the result of computing :math:`\lanes_{\shape}(c_1)`. 4. Let :math:`i` be the result of computing :math:`\bool(\bigwedge(i_1 \neq 0)^\ast)`. @@ -687,15 +693,17 @@ Most vector instructions are defined in terms of generic numeric operators appli 2. Pop the value :math:`\V128.\VCONST~c_1` from the stack. -3. Let :math:`i_1^N` be the sequence :math:`\lanes_{t\K{x}N}(c)`. +3. Let :math:`i_1^N` be the result of computing :math:`\lanes_{t\K{x}N}(c)`. 4. Let :math:`B` be the :ref:`bit width ` :math:`|t|` of :ref:`value type ` :math:`t`. -5. Let :math:`i_2^N` be the sequence as a result of computing :math:`\ilts_{B}(i_1^N, 0^N)`. +5. Let :math:`i_2^N` be the result of computing :math:`\ilts_{B}(i_1^N, 0^N)`. -6. Let :math:`c` be the integer :math:`\ibits_{32}^{-1}(i_2^N~0^{32-N})`. +6. Let :math:`j^\ast` be the concatenation of the two sequences :math:`i_2^N` and :math:`0^{32-N}`. -7. Push the value :math:`\I32.\CONST~c` onto the stack. +7. Let :math:`c` be the result of computing :math:`\ibits_{32}^{-1}(j^\ast)`. + +8. Push the value :math:`\I32.\CONST~c` onto the stack. .. math:: \begin{array}{lcl@{\qquad}l} @@ -716,15 +724,21 @@ Most vector instructions are defined in terms of generic numeric operators appli 3. Pop the value :math:`\V128.\VCONST~c_2` from the stack. -4. Let :math:`d_2^M` be the result of computing :math:`\narrow^{\sx}_{|t_1|,|t_2|}(\lanes_{t_1\K{x}M}(c_2))`. +4. Let :math:`i_2^M` be the result of computing :math:`\lanes_{t_1\K{x}M}(c_2)`. -5. Pop the value :math:`\V128.\VCONST~c_1` from the stack. +5. Let :math:`d_2^M` be the result of computing :math:`\narrow^{\sx}_{|t_1|,|t_2|}(i_2^M)`. -6. Let :math:`d_1^M` be the result of computing :math:`\narrow^{\sx}_{|t_1|,|t_2|}(\lanes_{t_1\K{x}M}(c_1))`. +6. Pop the value :math:`\V128.\VCONST~c_1` from the stack. -7. Let :math:`c` be the result of :math:`\lanes^{-1}_{t_2\K{x}N}(d_1^M~d_2^M)`. +7. Let :math:`i_1^M` be the result of computing :math:`\lanes_{t_1\K{x}M}(c_1)`. -8. Push the value :math:`\V128.\VCONST~c` onto the stack. +8. Let :math:`d_1^M` be the result of computing :math:`\narrow^{\sx}_{|t_1|,|t_2|}(i_1^M)`. + +9. Let :math:`j^N` be the concatenation of the two sequences :math:`d_1^M` and :math:`d_2^M`. + +10. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{t_2\K{x}N}(j^N)`. + +11. Push the value :math:`\V128.\VCONST~c` onto the stack. .. math:: \begin{array}{l} @@ -745,15 +759,19 @@ Most vector instructions are defined in terms of generic numeric operators appli :math:`t_2\K{x}N\K{.}\vcvtop\K{\_}t_1\K{x}M\K{\_}\sx` ..................................................... -1. Assert: due to :ref:`validation `, a value of :ref:`value type ` |V128| is on the top of the stack. +1. Assert: due to :ref:`syntax `, :math:`N = M`. -2. Pop the value :math:`\V128.\VCONST~c_1` from the stack. +2. Assert: due to :ref:`validation `, a value of :ref:`value type ` |V128| is on the top of the stack. -3. Let :math:`i^\ast` be the sequence :math:`\lanes_{t_1\K{x}M}(c_1)`. +3. Pop the value :math:`\V128.\VCONST~c_1` from the stack. + +4. Let :math:`i^\ast` be the result of computing :math:`\lanes_{t_1\K{x}M}(c_1)`. -4. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{t_2\K{x}N}(\vcvtop^{\sx}_{|t_1|,|t_2|}(i^\ast))` +5. Let :math:`j^\ast` be the result of computing :math:`\vcvtop^{\sx}_{|t_1|,|t_2|}(i^\ast)`. -5. Push the value :math:`\V128.\VCONST~c` onto the stack. +6. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{t_2\K{x}N}(j^\ast)`. + +7. Push the value :math:`\V128.\VCONST~c` onto the stack. .. math:: \begin{array}{l} @@ -770,23 +788,27 @@ Most vector instructions are defined in terms of generic numeric operators appli :math:`t_2\K{x}N\K{.}\vcvtop\K{\_}\half\K{\_}t_1\K{x}M\K{\_}\sx^?` .................................................................. -1. Assert: due to :ref:`validation `, a value of :ref:`value type ` |V128| is on the top of the stack. +1. Assert: due to :ref:`syntax `, :math:`N = M / 2`. -2. Pop the value :math:`\V128.\VCONST~c_1` from the stack. +2. Assert: due to :ref:`validation `, a value of :ref:`value type ` |V128| is on the top of the stack. -3. If :math:`\half` is :math:`\K{low}`, then: +3. Pop the value :math:`\V128.\VCONST~c_1` from the stack. - a. Let :math:`i^\ast` be the sequence :math:`\lanes_{t_1\K{x}M}(c_1)[0 \slice N]`. +4. Let :math:`i^\ast` be the result of computing :math:`\lanes_{t_1\K{x}M}(c_1)`. -4. Else: +5. If :math:`\half` is :math:`\K{low}`, then: - a. Let :math:`i^\ast` be the sequence :math:`\lanes_{t_1\K{x}M}(c_1)[N \slice N]`. + a. Let :math:`j^\ast` be the sequence :math:`i^\ast[0 \slice N]`. -5. Let :math:`j^\ast` be the result of computing :math:`\vcvtop^{\sx^?}_{|t_1|,|t_2|}(i^\ast)`. +6. Else: -6. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{t_2\K{x}N}(j^\ast)`. + a. Let :math:`j^\ast` be the sequence :math:`i^\ast[N \slice N]`. -7. Push the value :math:`\V128.\VCONST~c` onto the stack. +7. Let :math:`k^\ast` be the result of computing :math:`\vcvtop^{\sx^?}_{|t_1|,|t_2|}(j^\ast)`. + +8. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{t_2\K{x}N}(k^\ast)`. + +9. Push the value :math:`\V128.\VCONST~c` onto the stack. .. math:: \begin{array}{l} @@ -811,17 +833,21 @@ where: :math:`t_2\K{x}N\K{.}\vcvtop\K{\_}t_1\K{x}M\K{\_}\sx\K{\_zero}` ............................................................... -1. Assert: due to :ref:`validation `, a value of :ref:`value type ` |V128| is on the top of the stack. +1. Assert: due to :ref:`syntax `, :math:`N = 2 \cdot M`. -2. Pop the value :math:`\V128.\VCONST~c_1` from the stack. +2. Assert: due to :ref:`validation `, a value of :ref:`value type ` |V128| is on the top of the stack. + +3. Pop the value :math:`\V128.\VCONST~c_1` from the stack. + +4. Let :math:`i^\ast` be the result of computing :math:`\lanes_{t_1\K{x}M}(c_1)`. -3. Let :math:`i^\ast` be the sequence :math:`\lanes_{t_1\K{x}M}(c_1)`. +5. Let :math:`j^\ast` be the result of computing :math:`\vcvtop^{\sx}_{|t_1|,|t_2|}(i^\ast)`. -4. Let :math:`j^\ast` be the result of computing :math:`\vcvtop^{\sx}_{|t_1|,|t_2|}(i^\ast)` concatenated with the vector :math:`0^M`. +6. Let :math:`k^\ast` be the concatenation of the two sequences :math:`j^\ast` and :math:`0^M`. -5. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{t_2\K{x}N}(j^\ast)`. +7. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{t_2\K{x}N}(k^\ast)`. -6. Push the value :math:`\V128.\VCONST~c` onto the stack. +8. Push the value :math:`\V128.\VCONST~c` onto the stack. .. math:: \begin{array}{l} @@ -846,13 +872,21 @@ where: 3. Pop the value :math:`\V128.\VCONST~c_1` from the stack. -4. Let :math:`(i_1~i_2)^\ast` be the result of computing :math:`\imul_{32}(\extends_{16,32}(\lanes_{\I16X8}(c_1)), \extends_{16,32}(\lanes_{\I16X8}(c_2)))` +4. Let :math:`i_1^\ast` be the result of computing :math:`\lanes_{\I16X8}(c_1)`. -5. Let :math:`j^\ast` be the result of computing :math:`\iadd_{32}(i_1, i_2)^\ast`. +5. Let :math:`j_1^\ast` be the result of computing :math:`\extends_{16,32}(i_1^\ast)`. -6. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{\I32X4}(j^\ast)`. +6. Let :math:`i_2^\ast` be the result of computing :math:`\lanes_{\I16X8}(c_2)`. -7. Push the value :math:`\V128.\VCONST~c` onto the stack. +7. Let :math:`j_2^\ast` be the result of computing :math:`\extends_{16,32}(i_2^\ast)`. + +8. Let :math:`(k_1~k_2)^\ast` be the result of computing :math:`\imul_{32}(j_1^\ast, j_2^\ast)`. + +9. Let :math:`k^\ast` be the result of computing :math:`\iadd_{32}(k_1, k_2)^\ast`. + +10. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{\I32X4}(k^\ast)`. + +11. Push the value :math:`\V128.\VCONST~c` onto the stack. .. math:: \begin{array}{l} @@ -873,27 +907,39 @@ where: :math:`t_2\K{x}N\K{.}\EXTMUL\K{\_}\half\K{\_}t_1\K{x}M\K{\_}\sx` ................................................................ -1. Assert: due to :ref:`validation `, two values of :ref:`value type ` |V128| are on the top of the stack. +1. Assert: due to :ref:`syntax `, :math:`N = M / 2`. -2. Pop the value :math:`\V128.\VCONST~c_2` from the stack. +2. Assert: due to :ref:`validation `, two values of :ref:`value type ` |V128| are on the top of the stack. -3. Pop the value :math:`\V128.\VCONST~c_1` from the stack. +3. Pop the value :math:`\V128.\VCONST~c_2` from the stack. -4. If :math:`\half` is :math:`\K{low}`, then: +4. Pop the value :math:`\V128.\VCONST~c_1` from the stack. - a. Let :math:`i^\ast` be the sequence :math:`\lanes_{t_1\K{x}M}(c_1)[0 \slice N]`. +5. Let :math:`i_1^\ast` be the result of computing :math:`\lanes_{t_1\K{x}M}(c_1)`. - b. Let :math:`j^\ast` be the sequence :math:`\lanes_{t_1\K{x}M}(c_2)[0 \slice N]`. +6. Let :math:`i_2^\ast` be the result of computing :math:`\lanes_{t_1\K{x}M}(c_2)`. -5. Else: +7. If :math:`\half` is :math:`\K{low}`, then: - a. Let :math:`i^\ast` be the sequence :math:`\lanes_{t_1\K{x}M}(c_1)[N \slice N]`. + a. Let :math:`j_1^\ast` be the sequence :math:`i_1^\ast[0 \slice N]`. - b. Let :math:`j^\ast` be the sequence :math:`\lanes_{t_1\K{x}M}(c_2)[N \slice N]`. + b. Let :math:`j_2^\ast` be the sequence :math:`i_2^\ast[0 \slice N]`. -6. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{t_2\K{x}N}(\imul_{t_2\K{x}N}(\extend^{\sx}_{|t_1|,|t_2|}(i^\ast), \extend^{\sx}_{|t_1|,|t_2|}(j^\ast)))` +8. Else: -7. Push the value :math:`\V128.\VCONST~c` onto the stack. + a. Let :math:`j_1^\ast` be the sequence :math:`i_1^\ast[N \slice N]`. + + b. Let :math:`j_2^\ast` be the sequence :math:`i_2^\ast[N \slice N]`. + +9. Let :math:`k_1^\ast` be the result of computing :math:`\extend^{\sx}_{|t_1|,|t_2|}(j_1^\ast)`. + +10. Let :math:`k_2^\ast` be the result of computing :math:`\extend^{\sx}_{|t_1|,|t_2|}(j_2^\ast)`. + +11. Let :math:`k^\ast` be the result of computing :math:`\imul_{t_2\K{x}N}(k_1^\ast, k_2^\ast)`. + +12. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{t_2\K{x}N}(k^\ast)`. + +13. Push the value :math:`\V128.\VCONST~c` onto the stack. .. math:: \begin{array}{lcl@{\qquad}l} @@ -920,17 +966,21 @@ where: :math:`t_2\K{x}N\K{.}\EXTADDPAIRWISE\_t_1\K{x}M\_\sx` ..................................................... -1. Assert: due to :ref:`validation `, a value of :ref:`value type ` |V128| is on the top of the stack. +1. Assert: due to :ref:`syntax `, :math:`N = M / 2`. -2. Pop the value :math:`\V128.\VCONST~c_1` from the stack. +2. Assert: due to :ref:`validation `, a value of :ref:`value type ` |V128| is on the top of the stack. -3. Let :math:`(i_1~i_2)^\ast` be the sequence :math:`\extend^{\sx}_{|t_1|,|t_2|}(\lanes_{t_1\K{x}M}(c_1))`. +3. Pop the value :math:`\V128.\VCONST~c_1` from the stack. -4. Let :math:`j^\ast` be the result of computing :math:`\iadd_{N}(i_1, i_2)^\ast`. +4. Let :math:`i^\ast` be the result of computing :math:`\lanes_{t_1\K{x}M}(c_1)`. -5. Let `c` be the result of computing :math:`\lanes^{-1}_{t_2\K{x}N}(j^\ast)`. +5. Let :math:`(j_1~j_2)^\ast` be the result of computing :math:`\extend^{\sx}_{|t_1|,|t_2|}(i^\ast)`. -6. Push the value :math:`\V128.\VCONST~c` to the stack. +6. Let :math:`k^\ast` be the result of computing :math:`\iadd_{N}(j_1, j_2)^\ast`. + +7. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{t_2\K{x}N}(k^\ast)`. + +8. Push the value :math:`\V128.\VCONST~c` to the stack. .. math:: \begin{array}{l} @@ -994,9 +1044,9 @@ Parametric Instructions .. math:: \begin{array}{lcl@{\qquad}l} - \val_1~\val_2~(\I32\K{.}\CONST~c)~\SELECT~t^? &\stepto& \val_1 + \val_1~\val_2~(\I32\K{.}\CONST~c)~(\SELECT~t^?) &\stepto& \val_1 & (\iff c \neq 0) \\ - \val_1~\val_2~(\I32\K{.}\CONST~c)~\SELECT~t^? &\stepto& \val_2 + \val_1~\val_2~(\I32\K{.}\CONST~c)~(\SELECT~t^?) &\stepto& \val_2 & (\iff c = 0) \\ \end{array} @@ -1067,7 +1117,7 @@ Variable Instructions 4. Push the value :math:`\val` to the stack. -5. :ref:`Execute ` the instruction :math:`(\LOCALSET~x)`. +5. :ref:`Execute ` the instruction :math:`\LOCALSET~x`. .. math:: \begin{array}{lcl@{\qquad}l} @@ -1290,13 +1340,19 @@ Table Instructions 11. Let :math:`\X{err}` be the |i32| value :math:`2^{32}-1`, for which :math:`\signed_{32}(\X{err})` is :math:`-1`. -12. Either, try :ref:`growing ` :math:`\X{table}` by :math:`n` entries with initialization value :math:`\val`: +12. Either: - a. If it succeeds, push the value :math:`\I32.\CONST~\X{sz}` to the stack. + a. If :ref:`growing ` :math:`\X{tab}` by :math:`n` entries with initialization value :math:`\val` succeeds, then: - b. Else, push the value :math:`\I32.\CONST~\X{err}` to the stack. + i. Push the value :math:`\I32.\CONST~\X{sz}` to the stack. -13. Or, push the value :math:`\I32.\CONST~\X{err}` to the stack. + b. Else: + + i. Push the value :math:`\I32.\CONST~\X{err}` to the stack. + +13. Or: + + a. push the value :math:`\I32.\CONST~\X{err}` to the stack. .. math:: ~\\[-1ex] @@ -1312,7 +1368,7 @@ Table Instructions \end{array} \\[1ex] \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~n)~(\TABLEGROW~x) &\stepto& S; F; (\I32.\CONST~\signed_{32}^{-1}(-1)) + S; F; \val~(\I32.\CONST~n)~(\TABLEGROW~x) &\stepto& S; F; (\I32.\CONST~\signed_{32}^{-1}(-1)) \end{array} \end{array} @@ -1762,7 +1818,7 @@ Memory Instructions 12. Let :math:`W` be the integer :math:`M \cdot 2`. -13. Let :math:`n_k` be the result of :math:`\extend^{\sx}_{M,W}(m_k)`. +13. Let :math:`n_k` be the result of computing :math:`\extend^{\sx}_{M,W}(m_k)`. 14. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{\X{i}W\K{x}N}(n_0 \dots n_{N-1})`. @@ -1878,7 +1934,7 @@ Memory Instructions 11. Let :math:`n` be the integer for which :math:`\bytes_{\iN}(n) = b^\ast`. -12. Let :math:`c` be the result of :math:`\extendu_{N,128}(n)`. +12. Let :math:`c` be the result of computing :math:`\extendu_{N,128}(n)`. 13. Push the value :math:`\V128.\CONST~c` to the stack. @@ -1939,9 +1995,11 @@ Memory Instructions 14. Let :math:`L` be :math:`128 / N`. -15. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{\K{i}N\K{x}L}(\lanes_{\K{i}N\K{x}L}(v) \with [x] = r)`. +15. Let :math:`j^\ast` be the result of computing :math:`\lanes_{\K{i}N\K{x}L}(v)`. -16. Push the value :math:`\V128.\CONST~c` to the stack. +16. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{\K{i}N\K{x}L}(j^\ast \with [x] = r)`. + +17. Push the value :math:`\V128.\CONST~c` to the stack. .. math:: ~\\[-1ex] @@ -2074,9 +2132,11 @@ Memory Instructions 12. Let :math:`L` be :math:`128/N`. -13. Let :math:`b^\ast` be the byte sequence :math:`\bytes_{\iN}(\lanes_{\K{i}N\K{x}L}(c)[x])`. +13. Let :math:`j^\ast` be the result of computing :math:`\lanes_{\K{i}N\K{x}L}(c)`. + +14. Let :math:`b^\ast` be the result of computing :math:`\bytes_{\iN}(j^\ast[x])`. -14. Replace the bytes :math:`\X{mem}.\MIDATA[\X{ea} \slice N/8]` with :math:`b^\ast`. +15. Replace the bytes :math:`\X{mem}.\MIDATA[\X{ea} \slice N/8]` with :math:`b^\ast`. .. math:: ~\\[-1ex] @@ -2152,13 +2212,19 @@ Memory Instructions 9. Let :math:`\X{err}` be the |i32| value :math:`2^{32}-1`, for which :math:`\signed_{32}(\X{err})` is :math:`-1`. -10. Either, try :ref:`growing ` :math:`\X{mem}` by :math:`n` :ref:`pages `: +10. Either: + + a. If :ref:`growing ` :math:`\X{mem}` by :math:`n` :ref:`pages ` succeeds, then: + + i. Push the value :math:`\I32.\CONST~\X{sz}` to the stack. - a. If it succeeds, push the value :math:`\I32.\CONST~\X{sz}` to the stack. + b. Else: - b. Else, push the value :math:`\I32.\CONST~\X{err}` to the stack. + i. Push the value :math:`\I32.\CONST~\X{err}` to the stack. -11. Or, push the value :math:`\I32.\CONST~\X{err}` to the stack. +11. Or: + + a. Push the value :math:`\I32.\CONST~\X{err}` to the stack. .. math:: ~\\[-1ex] @@ -2244,7 +2310,7 @@ Memory Instructions S; F; (\I32.\CONST~d)~\val~(\I32.\CONST~n)~\MEMORYFILL \quad\stepto\quad S; F; \TRAP \\ \qquad - (\iff d + n > |S.\SMEMS[F.\AMODULE.\MIMEMS[x]].\MIDATA|) + (\iff d + n > |S.\SMEMS[F.\AMODULE.\MIMEMS[0]].\MIDATA|) \\[1ex] S; F; (\I32.\CONST~d)~\val~(\I32.\CONST~0)~\MEMORYFILL \quad\stepto\quad S; F; \epsilon @@ -2451,7 +2517,7 @@ Memory Instructions \\ \qquad \begin{array}[t]{@{}r@{~}l@{}} (\iff & s + n > |S.\SDATAS[F.\AMODULE.\MIDATAS[x]].\DIDATA| \\ - \vee & d + n > |S.\SMEMS[F.\AMODULE.\MIMEMS[x]].\MIDATA|) \\[1ex] + \vee & d + n > |S.\SMEMS[F.\AMODULE.\MIMEMS[0]].\MIDATA|) \\[1ex] \end{array} \\[1ex] S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~0)~(\MEMORYINIT~x) @@ -2537,17 +2603,19 @@ Control Instructions :math:`\BLOCK~\blocktype~\instr^\ast~\END` .......................................... -1. Assert: due to :ref:`validation `, :math:`\expand_F(\blocktype)` is defined. +1. Let :math:`F` be the :ref:`current ` :ref:`frame `. -2. Let :math:`[t_1^m] \to [t_2^n]` be the :ref:`function type ` :math:`\expand_F(\blocktype)`. +2. Assert: due to :ref:`validation `, :math:`\expand_F(\blocktype)` is defined. -3. Let :math:`L` be the label whose arity is :math:`n` and whose continuation is the end of the block. +3. Let :math:`[t_1^m] \to [t_2^n]` be the :ref:`function type ` :math:`\expand_F(\blocktype)`. -4. Assert: due to :ref:`validation `, there are at least :math:`m` values on the top of the stack. +4. Let :math:`L` be the label whose arity is :math:`n` and whose continuation is the end of the block. -5. Pop the values :math:`\val^m` from the stack. +5. Assert: due to :ref:`validation `, there are at least :math:`m` values on the top of the stack. + +6. Pop the values :math:`\val^m` from the stack. -6. :ref:`Enter ` the block :math:`\val^m~\instr^\ast` with label :math:`L`. +7. :ref:`Enter ` the block :math:`\val^m~\instr^\ast` with label :math:`L`. .. math:: ~\\[-1ex] @@ -2563,17 +2631,19 @@ Control Instructions :math:`\LOOP~\blocktype~\instr^\ast~\END` ......................................... -1. Assert: due to :ref:`validation `, :math:`\expand_F(\blocktype)` is defined. +1. Let :math:`F` be the :ref:`current ` :ref:`frame `. -2. Let :math:`[t_1^m] \to [t_2^n]` be the :ref:`function type ` :math:`\expand_F(\blocktype)`. +2. Assert: due to :ref:`validation `, :math:`\expand_F(\blocktype)` is defined. -3. Let :math:`L` be the label whose arity is :math:`m` and whose continuation is the start of the loop. +3. Let :math:`[t_1^m] \to [t_2^n]` be the :ref:`function type ` :math:`\expand_F(\blocktype)`. -4. Assert: due to :ref:`validation `, there are at least :math:`m` values on the top of the stack. +4. Let :math:`L` be the label whose arity is :math:`m` and whose continuation is the start of the loop. -5. Pop the values :math:`\val^m` from the stack. +5. Assert: due to :ref:`validation `, there are at least :math:`m` values on the top of the stack. + +6. Pop the values :math:`\val^m` from the stack. -6. :ref:`Enter ` the block :math:`\val^m~\instr^\ast` with label :math:`L`. +7. :ref:`Enter ` the block :math:`\val^m~\instr^\ast` with label :math:`L`. .. math:: ~\\[-1ex] @@ -2595,143 +2665,200 @@ Control Instructions 3. If :math:`c` is non-zero, then: - a. Execute the block instruction :math:`\BLOCK~\X{bt}~\instr_1^\ast~\END`. + a. Execute the block instruction :math:`\BLOCK~\blocktype~\instr_1^\ast~\END`. 4. Else: - a. Execute the block instruction :math:`\BLOCK~\X{bt}~\instr_2^\ast~\END`. + a. Execute the block instruction :math:`\BLOCK~\blocktype~\instr_2^\ast~\END`. .. math:: ~\\[-1ex] \begin{array}{lcl} - F; (\I32.\CONST~c)~\IF~\X{bt}~\instr_1^\ast~\ELSE~\instr_2^\ast~\END &\stepto& - F; \BLOCK~\X{bt}~\instr_1^\ast~\END + (\I32.\CONST~c)~\IF~\X{bt}~\instr_1^\ast~\ELSE~\instr_2^\ast~\END &\stepto& + \BLOCK~\X{bt}~\instr_1^\ast~\END \\&&\quad (\iff c \neq 0) \\ - F; (\I32.\CONST~c)~\IF~\X{bt}~\instr_1^\ast~\ELSE~\instr_2^\ast~\END &\stepto& - F; \BLOCK~\X{bt}~\instr_2^\ast~\END + (\I32.\CONST~c)~\IF~\X{bt}~\instr_1^\ast~\ELSE~\instr_2^\ast~\END &\stepto& + \BLOCK~\X{bt}~\instr_2^\ast~\END \\&&\quad (\iff c = 0) \\ \end{array} -.. _exec-try-catch: +.. _exec-try_table: -:math:`\TRY~\blocktype~\instr_1^\ast~(\CATCH~x~\instr_2^\ast)^\ast~(\CATCHALL~\instr_3^\ast)^?~\END` -.................................................................................................... +:math:`\TRYTABLE~\blocktype~\catch^\ast~\instr^\ast~\END` +......................................................... 1. Assert: due to :ref:`validation `, :math:`\expand_F(\blocktype)` is defined. 2. Let :math:`[t_1^m] \to [t_2^n]` be the :ref:`function type ` :math:`\expand_F(\blocktype)`. -3. Let :math:`L` be the label whose arity is :math:`n` and whose continuation is the end of the |TRY| instruction. +3. Assert: due to :ref:`validation `, there are at least :math:`m` values on the top of the stack. -4. Assert: due to :ref:`validation `, there are at least :math:`m` values on the top of the stack. +4. Pop the values :math:`\val^m` from the stack. -5. Pop the values :math:`\val^m` from the stack. +5. Let :math:`L` be the label whose arity is :math:`n` and whose continuation is the end of the |TRYTABLE| instruction. -6. Let :math:`F` be the :ref:`current ` :ref:`frame `. +6. :ref:`Enter ` the block :math:`\val^m~\instr_1^\ast` with label :math:`L` and exception handler :math:`\HANDLER_n\{\catch^\ast\}`. -7. For each catch clause :math:`(\CATCH~x_i~\instr_{2i}^\ast)` do: +.. math:: + ~\\[-1ex] + \begin{array}{r} + F; \val^m~(\TRYTABLE~\X{bt}~\catch^\ast~\instr^\ast~\END + \quad \stepto \quad + F; \HANDLER_n\{\catch^\ast\}~(\LABEL_n\{\epsilon\}~\val^m~\instr^\ast~\END)~\END \\ \qquad\qquad + (\iff \expand_F(\X{bt}) = [t_1^m] \to [t_2^n] \land (F.\AMODULE.\MITAGS[x]=a_x)^\ast) + \end{array} - a. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MITAGS[x_i]` exists. - b. Let :math:`a_i` be the tag address :math:`F.\AMODULE.\MITAGS[x_i]`. +.. _exec-throw: - c. Let :math:`H_i` be the handler clause :math:`\{a_i~\instr_{2i}^\ast\}`. +:math:`\THROW~x` +................ -8. If there is a catch all clause :math:`(\CATCHALL~\instr_3^\ast)`, then: +1. Let :math:`F` be the :ref:`current ` :ref:`frame `. - a. Let :math:`H'^?` be the handler clause :math:`\{\epsilon~\instr_3^\ast\}`. +2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MITAGS[x]` exists. -9. Else: +3. Let :math:`ta` be the :ref:`tag address ` :math:`F.\AMODULE.\MITAGS[x]`. - a. Let :math:`H'^?` be the empty handler clause :math:`\epsilon`. +4. Assert: due to :ref:`validation `, :math:`S.\STAGS[ta]` exists. -10. Let :math:`H^\ast` be the :ref:`catching exception handler ` containing the concatenation of the handler clauses :math:`H_i` and :math:`H'^?`. +5. Let :math:`\X{ti}` be the :ref:`tag instance ` :math:`S.\STAGS[ta]`. -11. :ref:`Enter ` the block :math:`\val^m~\instr_1^\ast` with label :math:`L` and exception handler :math:`H`. +6. Let :math:`[t^n] \toF [{t'}^\ast]` be the :ref:`tag type ` :math:`\X{ti}.\TAGITYPE`. + +7. Assert: due to :ref:`validation `, 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{ea}` be the :ref:`exception address ` resulting from :ref:`allocating ` an exception instance with tag address :math:`ta` and initializer values :math:`\val^n`. + +10. Let :math:`\X{exn}` be :math:`S.\SEXNS[ea]` + +11. Push the value :math:`\REFEXNADDR~\X{ea}` to the stack. + +12. Execute the instruction |THROWREF|. .. math:: ~\\[-1ex] - \begin{array}{l} - F; \val^m~(\TRY~\X{bt}~\instr_1^\ast~(\CATCH~x~\instr_2^\ast)^\ast~(\CATCHALL~\instr_3^\ast)^?~\END - \quad \stepto \\ - \qquad F; \LABEL_n\{\epsilon\}~(\CATCHadm\{a_x~\instr_2^\ast\}^\ast\{\epsilon~\instr_3\ast\}^?~\val^m~\instr_1^\ast~\END)~\END \\ - (\iff \expand_F(\X{bt}) = [t_1^m] \to [t_2^n] \land (F.\AMODULE.\MITAGS[x]=a_x)^\ast) + \begin{array}{lclr@{\qquad}l} + S; F; \val^n~(\THROW~x) &\stepto& S'; F; (\REFEXNADDR~|S.\SEXNS|)~\THROWREF & + (\begin{array}[t]{@{}r@{~}l@{}} + \iff & F.\AMODULE.\MITAGS[x] = a \\ + \land & S.\STAGS[a].\TAGITYPE = [t^n] \toF [] \\ + \land & \X{exn} = \{ \EITAG~a, \EIFIELDS~\val^n \} \\ + \land & S' = S \with \SEXNS = S.\SEXNS~\X{exn} ) \\ + \end{array} \\ \end{array} -.. _exec-try-delegate: +.. _exec-throw_ref: -:math:`\TRY~\blocktype~\instr^\ast~\DELEGATE~l` -............................................... +:math:`\THROWREF` +................. -1. Assert: due to :ref:`validation `, :math:`\expand_F(\blocktype)` is defined. +1. Assert: due to :ref:`validation `, a :ref:`reference ` is on the top of the stack. -2. Let :math:`[t_1^m] \to [t_2^n]` be the :ref:`function type ` :math:`\expand_F(\blocktype)`. +2. Pop the reference :math:`\reff` from the stack. -3. Let :math:`L` be the label whose arity is :math:`n` and whose continuation is the end of the |TRY| instruction. +3. If :math:`\reff` is :math:`\REFNULL~\X{ht}`, then: -4. Let :math:`H` be the :ref:`delegating exception handler ` :math:`\DELEGATEadm\{l\}`, targeting the :math:`l`-th surrounding block. + a. Trap. -5. Assert: due to :ref:`validation `, there are at least :math:`m` values on the top of the stack. +4. Assert: due to :ref:`validation `, :math:`\reff` is an :ref:`exception reference `. -6. Pop the values :math:`\val^m` from the stack. +5. Let :math:`\REFEXNADDR~\X{ea}` be :math:`\reff`. -7. :ref:`Enter ` the block :math:`H~(\val^n~\instr^\ast)~\END` with label :math:`L`. +6. Assert: due to :ref:`validation `, :math:`S.\SEXNS[\X{ea}]` exists. -8. :ref:`Install ` the exception handler `H` containing :math:`\val^m~\instr^\ast`. +7. Let :math:`\X{exn}` be the :ref:`exception instance ` :math:`S.\SEXNS[\X{ea}]`. -.. math:: - ~\\[-1ex] - \begin{array}{lcl} - F; \val^m~(\TRY~\X{bt}~\instr^\ast~\DELEGATE~l) &\stepto& - F; \LABEL_n\{\epsilon\}~(\DELEGATEadm\{l\}~\val^m~\instr^\ast~\END)~\END \\ - && (\iff \expand_F(\X{bt}) = [t_1^m] \to [t_2^n]) - \end{array} +8. Let :math:`a` be the :ref:`tag address ` :math:`\X{exn}.\EITAG`. +9. While the stack is not empty and the top of the stack is not an :ref:`exception handler `, do: -.. _exec-throw: + a. Pop the top element from the stack. -:math:`\THROW~x` -................ +10. Assert: the stack is now either empty, or there is an exception handler on the top of the stack. -1. Let :math:`F` be the :ref:`current ` :ref:`frame `. +11. If the stack is empty, then: -2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MITAGS[x]` exists. + a. Return the exception :math:`(\REFEXNADDR~a)` as a :ref:`result `. -3. Let :math:`a` be the :ref:`tag address ` :math:`F.\AMODULE.\MITAGS[x]`. +12. Assert: there is an :ref:`exception handler ` on the top of the stack. -4. :ref:`Throw ` an exception with :ref:`tag address ` :math:`a`. +13. Pop the exception handler :math:`\HANDLER_n\{\catch^\ast\}` from the stack. -.. math:: - ~\\[-1ex] - \begin{array}{lclr@{\qquad}l} - \THROW~x &\stepto& \THROWadm~a & (\iff F.\AMODULE.\MITAGS[x] = a) \\ - \end{array} +14. If :math:`\catch^\ast` is empty, then: + a. Push the exception reference :math:`\REFEXNADDR~\X{ea}` back to the stack. -.. _exec-rethrow: + b. Execute the instruction |THROWREF| again. -:math:`\RETHROW~l` -.................. +15. Else: -1. Assert: due to :ref:`validation `, the stack contains at least :math:`l+1` labels. + a. Let :math:`F` be the :ref:`current ` :ref:`frame `. -2. Let :math:`L` be the :math:`l`-th label appearing on the stack, starting from the top and counting from zero. + b. Let :math:`\catch_1` be the first :ref:`catch clause ` in :math:`\catch^\ast` and :math:`{\catch'}^\ast` the remaining clauses. + + c. If :math:`\catch_1` is of the form :math:`\CATCH~x~l` and the :ref:`tag address ` :math:`a` equals :math:`F.\AMODULE.\MITAGS[x]`, then: + + i. Push the values :math:`\X{exn}.\EIFIELDS` to the stack. + + ii. Execute the instruction :math:`\BR~l`. + + d. Else if :math:`\catch_1` is of the form :math:`\CATCHREF~x~l` and the :ref:`tag address ` :math:`a` equals :math:`F.\AMODULE.\MITAGS[x]`, then: + + i. Push the values :math:`\X{exn}.\EIFIELDS` to the stack. + + ii. Push the exception reference :math:`\REFEXNADDR~\X{ea}` to the stack. + + iii. Execute the instruction :math:`\BR~l`. + + e. Else if :math:`\catch_1` is of the form :math:`\CATCHALL~l`, then: -3. Assert: due to :ref:`validation `, :math:`L` is a catch label, i.e., a label of the form :math:`(\LCATCH~[t^\ast])`, which is a label followed by a caught exception in an active catch clause. + i. Execute the instruction :math:`\BR~l`. -4. Let :math:`\{a~\val^\ast\}` be the caught exception. + f. Else if :math:`\catch_1` is of the form :math:`\CATCHALLREF~l`, then: -5. Push the values :math:`\val^\ast` onto the stack. + i. Push the exception reference :math:`\REFEXNADDR~\X{ea}` to the stack. -6. :ref:`Throw ` an exception with :ref:`tag address ` :math:`a`. + ii. Execute the instruction :math:`\BR~l`. + + g. Else: + + 1. Push the modified handler :math:`\HANDLER_n\{{\catch'}^\ast\}` back to the stack. + + 2. Push the exception reference :math:`\REFEXNADDR~\X{ea}` back to the stack. + + 3. Execute the instruction :math:`\THROWREF` again. .. math:: ~\\[-1ex] - \begin{array}{lclr@{\qquad}} - \CAUGHTadm\{a~\val^\ast\}~\XB^l[\RETHROW~l]~\END &\stepto& - \CAUGHTadm\{a~\val^\ast\}~\XB^l[\val^\ast~(\THROWadm~a)]~\END \\ + \begin{array}{rcl} + (\REFNULL~\X{ht})~\THROWREF &\stepto& + \TRAP \\ + \HANDLER_n\{\}~\XT[(\REFEXNADDR~a)~\THROWREF]~\END &\stepto& + (\REFEXNADDR~a)~\THROWREF \\ + S; F; \HANDLER_n\{(\CATCH~x~l)~\catch^\ast\}~\XT[(\REFEXNADDR~a)~\THROWREF]~\END &\stepto& + \X{exn}.\EIFIELDS~(\BR~l) \\ && + (\begin{array}[t]{@{}r@{~}l@{}} + \iff & \X{exn} = S.\SEXNS[a] \\ + \land & \X{exn}.\EITAG = F.\AMODULE.\MITAGS[x]) \\ + \end{array} \\ + S; F; \HANDLER_n\{(\CATCHREF~x~l)~\catch^\ast\}~\XT[(\REFEXNADDR~a)~\THROWREF]~\END &\stepto& + \X{exn}.\EIFIELDS~(\REFEXNADDR~a)~(\BR~l) \\ && + (\begin{array}[t]{@{}r@{~}l@{}} + \iff & \X{exn} = S.\SEXNS[a] \\ + \land & \X{exn}.\EITAG = F.\AMODULE.\MITAGS[x]) \\ + \end{array} \\ + \HANDLER_n\{(\CATCHALL~l)~\catch^\ast\}~\XT[(\REFEXNADDR~a)~\THROWREF]~\END &\stepto& + (\BR~l) \\ + \HANDLER_n\{(\CATCHALLREF~l)~\catch^\ast\}~\XT[(\REFEXNADDR~a)~\THROWREF]~\END &\stepto& + (\REFEXNADDR~a)~(\BR~l) \\ + \HANDLER_n\{\catch_1~\catch^\ast\}~\XT[(\REFEXNADDR~a)~\THROWREF]~\END &\stepto& + \HANDLER_n\{\catch^\ast\}~\XT[(\REFEXNADDR~a)~\THROWREF]~\END \\ && + (\otherwise) \\ \end{array} @@ -2752,9 +2879,9 @@ Control Instructions 6. Repeat :math:`l+1` times: - a. While the top of the stack is a value, a |handler|, or a |CAUGHTadm| instruction, do: + a. While the top of the stack is a value or a :ref:`handler `, do: - i. Pop the value from the stack. + i. Pop the value or handler from the stack. b. Assert: due to :ref:`validation `, the top of the stack now is a label. @@ -2782,7 +2909,7 @@ Control Instructions 3. If :math:`c` is non-zero, then: - a. :ref:`Execute ` the instruction :math:`(\BR~l)`. + a. :ref:`Execute ` the instruction :math:`\BR~l`. 4. Else: @@ -2811,11 +2938,11 @@ Control Instructions a. Let :math:`l_i` be the label :math:`l^\ast[i]`. - b. :ref:`Execute ` the instruction :math:`(\BR~l_i)`. + b. :ref:`Execute ` the instruction :math:`\BR~l_i`. 4. Else: - a. :ref:`Execute ` the instruction :math:`(\BR~l_N)`. + a. :ref:`Execute ` the instruction :math:`\BR~l_N`. .. math:: ~\\[-1ex] @@ -2982,22 +3109,20 @@ Exiting :math:`\instr^\ast` with label :math:`L` When the end of a block is reached without a jump, exception, or trap aborting it, then the following steps are performed. -1. Let :math:`n` be the number of values on the top of the stack. - -2. Pop the values :math:`\val^n` from the stack. +1. Pop all values :math:`\val^\ast` from the top of the stack. -3. Assert: due to :ref:`validation `, the label :math:`L` is now on the top of the stack and has arity :math:`n`. +2. Assert: due to :ref:`validation `, the label :math:`L` is now on the top of the stack. -4. Pop the label from the stack. +3. Pop the label from the stack. -5. Push :math:`\val^n` back to the stack. +4. Push :math:`\val^\ast` back to the stack. -6. Jump to the position after the |END| of the :ref:`structured control instruction ` associated with the label :math:`L`. +5. Jump to the position after the |END| of the :ref:`structured control instruction ` associated with the label :math:`L`. .. math:: ~\\[-1ex] \begin{array}{lcl@{\qquad}l} - \LABEL_n\{\instr^\ast\}~\val^n~\END &\stepto& \val^n + \LABEL_n\{\instr^\ast\}~\val^\ast~\END &\stepto& \val^\ast \end{array} .. note:: @@ -3008,22 +3133,21 @@ When the end of a block is reached without a jump, exception, or trap aborting i .. index:: exception handling, throw context, tag, exception tag pair: handling; exception -.. _exec-catchadm: -.. _exec-delegateadm: +.. _exec-handler: Exception Handling ~~~~~~~~~~~~~~~~~~ -The following auxiliary rules define the semantics of entering and exiting :ref:`exception handlers ` through :ref:`try ` instructions, and handling thrown exceptions. +The following auxiliary rules define the semantics of entering and exiting |TRYTABLE| blocks. .. _exec-handler-enter: Entering :math:`\instr^\ast` with label :math:`L` and exception handler :math:`H` ................................................................................. -1. Push :math:`L` to the stack. +1. Push :math:`H` to the stack. -2. Push :math:`H` onto the stack. +2. Push :math:`L` onto the stack. 3. Jump to the start of the instruction sequence :math:`\instr^\ast`. @@ -3031,89 +3155,36 @@ Entering :math:`\instr^\ast` with label :math:`L` and exception handler :math:`H .. note:: No formal reduction rule is needed for entering an exception :ref:`handler ` because it is an :ref:`administrative instruction ` - that the :ref:`try ` instruction reduces to directly. + that the |TRYTABLE| instruction reduces to directly. .. _exec-handler-exit: Exiting an exception handler ............................ -When the end of a :ref:`try ` instruction is reached without a jump, exception, or trap, then the following steps are performed. +When the end of a |TRYTABLE| block is reached without a jump, exception, or trap, then the following steps are performed. 1. Let :math:`m` be the number of values on the top of the stack. 2. Pop the values :math:`\val^m` from the stack. -3. Assert: due to :ref:`validation `, the handler :math:`H` is now on the top of the stack. +3. Assert: due to :ref:`validation `, a handler and a label are now on the top of the stack. + +4. Pop the label from the stack. -4. Pop the handler from the stack. +5. Pop the handler :math:`H` from the stack. -5. Push :math:`\val^m` back to the stack. +6. Push :math:`\val^m` back to the stack. -6. Jump to the position after the |END| of the administrative instruction associated with the handler :math:`H`. +7. Jump to the position after the |END| of the administrative instruction associated with the handler :math:`H`. .. math:: ~\\[-1ex] \begin{array}{lcl@{\qquad}l} - \CATCHadm\{a^?~\instr^\ast\}^\ast~\val^m~\END &\stepto& \val^m \\ - \DELEGATEadm\{l\}~\val^m~\END &\stepto& \val^m - \end{array} - - -.. _exec-throwadm: - -Throwing an exception with :ref:`tag address ` :math:`a` -........................................................................ - -.. todo:: - Add prose for the following execution steps. - - -.. math:: - \begin{array}{rcl} - \CATCHadm\{a_1^?~\instr^\ast\}\{a'^?~\instr'^\ast\}^\ast~\XT[(\THROWadm~a)]~\END &\stepto& - \CATCHadm\{a'^?~\instr'^\ast\}^\ast~\XT[(\THROWadm~a)]~\END \\ - && (\iff a_1^? \neq \epsilon \land a_1^? \neq a) \\ - S;~\CATCHadm\{a_1^?~\instr^\ast\}\{a'^?~\instr'^\ast\}^\ast~\XT[\val^n~(\THROWadm~a)]~\END &\stepto& - S;~\CAUGHTadm\{a~\val^n\}~(\val^n)?~\instr^\ast~\END \\ - && (\iff~(a_1^? = \epsilon \lor a_1^? = a)~\land\\ - && \ S.\STAGS[a].\TAGITYPE = [t^n]\to[]) \\ - \LABEL_n\{\}~\XB^l[\DELEGATEadm\{l\}~\XT[(\THROWadm~a)]~\END]~\END &\stepto& - \XT[(\THROWadm~a)] \\ + \HANDLER_m\{\catch^\ast\}~\val^m~\END &\stepto& \val^m \\ \end{array} -.. todo:: - Add explainer note. - -.. _exec-caughtadm: - -Exiting a catch clause -...................... - -When the |END| of a catch clause is reached without a jump, exception, or trap, then the following steps are performed. - -1. Let :math:`\val^\ast` be the values on the top of the stack. - -2. Pop the values :math:`\val^\ast` from the stack. - -3. Assert: due to :ref:`validation `, a caught exception :math:`\{a~\val_0^\ast\}` is now on the top of the stack. - -4. Pop the caught exception from the stack. - -5. Push :math:`\val^\ast` back to the stack. - -6. Jump to the position after the |END| of the administrative instruction associated with the catch clause. - -.. math:: - \begin{array}{rcl} - \CAUGHTadm\{a~\val_0^\ast\}~\val^\ast~\END &\stepto& \val^\ast - \end{array} - -.. note:: - An exception can only be rethrown from the scope of the |CAUGHTadm| administrative instruction holding it, i.e., from the scope of the |CATCH| or |CATCHALL| block of a :ref:`try-catch ` instruction that caught it. Upon exit from a |CAUGHTadm|, the exception it holds is discarded. - - .. index:: ! call, function, function instance, label, frame Function Calls @@ -3143,15 +3214,13 @@ Invocation of :ref:`function address ` :math:`a` 7. Pop the values :math:`\val^n` from the stack. -8. Let :math:`\val_0^\ast` be the list of zero values of types :math:`t^\ast`. - -9. Let :math:`F` be the :ref:`frame ` :math:`\{ \AMODULE~f.\FIMODULE, \ALOCALS~\val^n~(\default_t)^\ast \}`. +8. Let :math:`F` be the :ref:`frame ` :math:`\{ \AMODULE~f.\FIMODULE, \ALOCALS~\val^n~(\default_t)^\ast \}`. -10. Push the activation of :math:`F` with arity :math:`m` to the stack. +9. Push the activation of :math:`F` with arity :math:`m` to the stack. -11. Let :math:`L` be the :ref:`label ` whose arity is :math:`m` and whose continuation is the end of the function. +10. Let :math:`L` be the :ref:`label ` whose arity is :math:`m` and whose continuation is the end of the function. -12. :ref:`Enter ` the instruction sequence :math:`\instr^\ast` with label :math:`L`. +11. :ref:`Enter ` the instruction sequence :math:`\instr^\ast` with label :math:`L`. .. math:: ~\\[-1ex] diff --git a/document/core/exec/modules.rst b/document/core/exec/modules.rst index 0858f56a9..2a52bc96f 100644 --- a/document/core/exec/modules.rst +++ b/document/core/exec/modules.rst @@ -157,8 +157,23 @@ The following auxiliary typing rules specify this typing relation relative to a } -:ref:`External References ` :math:`\REFEXTERNADDR~a` -....................................................................... +:ref:`Exception References ` :math:`\REFEXNADDR~a` +.............................................................. + +* The store entry :math:`S.\SEXNS[a]` must exist. + +* Then the value is valid with :ref:`reference type ` :math:`\EXNREF`. + +.. math:: + \frac{ + S.\SEXNS[a] = \exninst + }{ + S \vdashval \REFEXNADDR : \EXNREF + } + + +:ref:`External References ` :math:`\REFEXTERNADDR~a` +............................................................................ * The value is valid with :ref:`reference type ` :math:`\EXTERNREF`. @@ -175,7 +190,7 @@ The following auxiliary typing rules specify this typing relation relative to a Allocation ~~~~~~~~~~ -New instances of :ref:`functions `, :ref:`tables `, :ref:`memories `, :ref:`tags `, and :ref:`globals ` are *allocated* in a :ref:`store ` :math:`S`, as defined by the following auxiliary functions. +New instances of :ref:`functions `, :ref:`tables `, :ref:`memories `, :ref:`tags `, :ref:`exceptions `, and :ref:`globals ` are *allocated* in a :ref:`store ` :math:`S`, as defined by the following auxiliary functions. .. index:: function, function instance, function address, module instance, function type @@ -323,6 +338,32 @@ New instances of :ref:`functions `, :ref:`tables ` +.................................. + +1. Let :math:`ta` be the :ref:`tag address ` 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 ` in :math:`S`. + +3. Let :math:`\exninst` be the :ref:`exception instance ` :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: @@ -381,11 +422,11 @@ New instances of :ref:`functions `, :ref:`tables ` ...................................... -1. Let :math:`\bytes` be the vector of :ref:`bytes ` to allocate. +1. Let :math:`b^\ast` be the vector of :ref:`bytes ` to allocate. 2. Let :math:`a` be the first free :ref:`data address ` in :math:`S`. -3. Let :math:`\datainst` be the :ref:`data instance ` :math:`\{ \DIDATA~\bytes \}`. +3. Let :math:`\datainst` be the :ref:`data instance ` :math:`\{ \DIDATA~b^\ast \}`. 4. Append :math:`\datainst` to the |SDATAS| of :math:`S`. @@ -393,10 +434,10 @@ New instances of :ref:`functions `, :ref:`tables ` vectors for the module's :ref:`element a. Let :math:`\limits_i~t_i` be the :ref:`table type ` :math:`\table_i.\TTYPE`. - b. Let :math:`\tableaddr_i` be the :ref:`table address ` resulting from :ref:`allocating ` :math:`\table_i.\TTYPE` - with initialization value :math:`\REFNULL~t_i`. + b. Let :math:`\tableaddr_i` be the :ref:`table address ` resulting from :ref:`allocating ` :math:`\table_i.\TTYPE` with initialization value :math:`\REFNULL~t_i`. 4. For each :ref:`memory ` :math:`\mem_i` in :math:`\module.\MMEMS`, do: @@ -785,20 +825,17 @@ It is up to the :ref:`embedder ` to define how such conditions are rep &\wedge& S', \moduleinst = \allocmodule(S, \module, \externval^k, \val^\ast, (\reff^\ast)^n) \\ &\wedge& F = \{ \AMODULE~\moduleinst, \ALOCALS~\epsilon \} \\[1ex] &\wedge& (S'; F; \expr_{\F{g}} \stepto^\ast S'; F; \val~\END)^\ast \\ - &\wedge& ((S'; F; \expr_{\F{e}} \stepto^\ast S'; F; \reff~\END)^\ast)^n \\ - &\wedge& (\tableaddr = \moduleinst.\MITABLES[\elem.\ETABLE])^\ast \\ - &\wedge& (\memaddr = \moduleinst.\MIMEMS[\data.\DMEM])^\ast \\ - &\wedge& (\funcaddr = \moduleinst.\MIFUNCS[\start.\SFUNC])^?) + &\wedge& ((S'; F; \expr_{\F{e}} \stepto^\ast S'; F; \reff~\END)^\ast)^n) \\ \end{array} where: .. math:: \begin{array}{@{}l} - \F{runelem}_i(\{\ETYPE~\X{et}, \EINIT~\reff^n, \EMODE~\EPASSIVE\}) \quad=\quad \epsilon \\ - \F{runelem}_i(\{\ETYPE~\X{et}, \EINIT~\reff^n, \EMODE~\EACTIVE \{\ETABLE~x, \EOFFSET~\instr^\ast~\END\}\}) \quad=\\ \qquad + \F{runelem}_i(\{\ETYPE~\X{et}, \EINIT~\expr^n, \EMODE~\EPASSIVE\}) \quad=\quad \epsilon \\ + \F{runelem}_i(\{\ETYPE~\X{et}, \EINIT~\expr^n, \EMODE~\EACTIVE \{\ETABLE~x, \EOFFSET~\instr^\ast~\END\}\}) \quad=\\ \qquad \instr^\ast~(\I32.\CONST~0)~(\I32.\CONST~n)~(\TABLEINIT~x~i)~(\ELEMDROP~i) \\ - \F{runelem}_i(\{\ETYPE~\X{et}, \EINIT~\reff^n, \EMODE~\EDECLARATIVE\}) \quad=\\ \qquad + \F{runelem}_i(\{\ETYPE~\X{et}, \EINIT~\expr^n, \EMODE~\EDECLARATIVE\}) \quad=\\ \qquad (\ELEMDROP~i) \\[1ex] \F{rundata}_i(\{\DINIT~b^n, \DMODE~\DPASSIVE\}) \quad=\quad \epsilon \\ \F{rundata}_i(\{\DINIT~b^n, \DMODE~\DACTIVE \{\DMEM~0, \DOFFSET~\instr^\ast~\END\}\}) \quad=\\ \qquad diff --git a/document/core/exec/runtime.rst b/document/core/exec/runtime.rst index a48cadabf..021a9dcdd 100644 --- a/document/core/exec/runtime.rst +++ b/document/core/exec/runtime.rst @@ -12,7 +12,9 @@ Runtime Structure .. _syntax-num: .. _syntax-vecc: .. _syntax-ref: -.. _syntax-ref.extern: +.. _syntax-ref.func-addr: +.. _syntax-ref.exn-addr: +.. _syntax-ref.extern-addr: .. _syntax-val: Values @@ -26,7 +28,8 @@ It is convenient to reuse the same notation as for the |CONST| :ref:`instruction References other than null are represented with additional :ref:`administrative instructions `. They either are *function references*, pointing to a specific :ref:`function address `, -or *external references* pointing to an uninterpreted form of :ref:`extern address ` that can be defined by the :ref:`embedder ` to represent its own objects. +*exception references*, pointing to a specific :ref:`exception address `, +or *external references* pointing to an uninterpreted form of :ref:`external address ` that can be defined by the :ref:`embedder ` to represent its own objects. .. math:: \begin{array}{llcl} @@ -40,6 +43,7 @@ or *external references* pointing to an uninterpreted form of :ref:`extern addre \production{reference} & \reff &::=& \REFNULL~t \\&&|& \REFFUNCADDR~\funcaddr \\&&|& + \REFEXNADDR~\exnaddr \\&&|& \REFEXTERNADDR~\externaddr \\ \production{value} & \val &::=& \num ~|~ \vecc ~|~ \reff \\ @@ -67,7 +71,7 @@ Convention * The meta variable :math:`r` ranges over reference values where clear from context. -.. index:: ! result, value, trap, exception +.. index:: ! result, value, trap, exception, exception address pair: abstract syntax; result .. _syntax-result: @@ -75,16 +79,17 @@ Results ~~~~~~~ A *result* is the outcome of a computation. -It is either a sequence of :ref:`values `, a :ref:`trap `, or an uncaught exception wrapped in its :ref:`throw context `. +It is either a sequence of :ref:`values `, a :ref:`trap `, or a thrown :ref:`exception `. .. math:: \begin{array}{llcl} \production{result} & \result &::=& \val^\ast \\&&|& \TRAP \\&&|& - \XT[\val^\ast~(\THROWadm~\tagaddr)] + \XT[(\REFEXNADDR~\exnaddr)~\THROWREF] \end{array} + .. index:: ! store, function instance, table instance, memory instance, tag instance, global instance, module, allocation pair: abstract syntax; store .. _syntax-store: @@ -94,7 +99,7 @@ Store ~~~~~ The *store* represents all global state that can be manipulated by WebAssembly programs. -It consists of the runtime representation of all *instances* of :ref:`functions `, :ref:`tables `, :ref:`memories `, :ref:`tags `, and :ref:`globals `, :ref:`element segments `, and :ref:`data segments ` that have been :ref:`allocated ` during the life time of the abstract machine. [#gc]_ +It consists of the runtime representation of all *instances* of :ref:`functions `, :ref:`tables `, :ref:`memories `, :ref:`tags `, and :ref:`globals `, :ref:`element segments `, :ref:`data segments `, and :ref:`exceptions ` that have been :ref:`allocated ` during the life time of the abstract machine. [#gc]_ It is an invariant of the semantics that no element or data instance is :ref:`addressed ` from anywhere else but the owning module instances. @@ -110,12 +115,13 @@ Syntactically, the store is defined as a :ref:`record ` listing \STAGS & \taginst^\ast, \\ \SGLOBALS & \globalinst^\ast, \\ \SELEMS & \eleminst^\ast, \\ - \SDATAS & \datainst^\ast ~\} \\ + \SDATAS & \datainst^\ast, \\ + \SEXNS & \exninst^\ast ~\} \\ \end{array} \end{array} .. [#gc] - In practice, implementations may apply techniques like garbage collection to remove objects from the store that are no longer referenced. + In practice, implementations may apply techniques like garbage collection or reference counting to remove objects from the store that are no longer referenced. However, such techniques are not semantically observable, and hence outside the scope of this specification. @@ -134,6 +140,7 @@ Convention pair: abstract syntax; global address pair: abstract syntax; element address pair: abstract syntax; data address + pair: abstract syntax; exception address pair: abstract syntax; host address pair: function; address pair: table; address @@ -142,6 +149,7 @@ Convention pair: global; address pair: element; address pair: data; address + pair: exception; address pair: host; address .. _syntax-funcaddr: .. _syntax-tableaddr: @@ -150,13 +158,14 @@ Convention .. _syntax-globaladdr: .. _syntax-elemaddr: .. _syntax-dataaddr: +.. _syntax-exnaddr: .. _syntax-externaddr: .. _syntax-addr: Addresses ~~~~~~~~~ -:ref:`Function instances `, :ref:`table instances `, :ref:`memory instances `, :ref:`tag instances `, :ref:`global instances `, :ref:`element instances `, and :ref:`data instances ` in the :ref:`store ` are referenced with abstract *addresses*. +:ref:`Function instances `, :ref:`table instances `, :ref:`memory instances `, :ref:`tag instances `, :ref:`global instances `, :ref:`element instances `, :ref:`data instances `, and :ref:`exception instances ` in the :ref:`store ` are referenced with abstract *addresses*. These are simply indices into the respective store component. In addition, an :ref:`embedder ` may supply an uninterpreted set of *host addresses*. @@ -178,6 +187,8 @@ In addition, an :ref:`embedder ` may supply an uninterpreted set of *h \addr \\ \production{data address} & \dataaddr &::=& \addr \\ + \production{exception address} & \exnaddr &::=& + \addr \\ \production{extern address} & \externaddr &::=& \addr \\ \end{array} @@ -444,13 +455,32 @@ It filters out entries of a specific kind in an order-preserving fashion: * :math:`\evglobals(\externval^\ast) = [\globaladdr ~|~ (\EVGLOBAL~\globaladdr) \in \externval^\ast]` +.. index:: ! exception instance, tag, tag address, + pair: abstract syntax; exception instance + pair: exception; instance +.. _syntax-exninst: + +Exception Instances +~~~~~~~~~~~~~~~~~~~ + +An *exception instance* is the runtime representation of an _exception_ produced by a |THROW| instruction. +It holds the :ref:`address ` of the respective :ref:`tag ` and the argument :ref:`values `. + +.. math:: + \begin{array}{llcl} + \production{exception instance} & \exninst &::=& + \{ \EITAG~\tagaddr, \EIFIELDS~\vec(\val) \} \\ + \end{array} + + -.. index:: ! stack, ! frame, ! label, ! handler, instruction, store, activation, function, call, local, module instance, exception handler +.. index:: ! stack, ! frame, ! label, ! handler, instruction, store, activation, function, call, local, module instance, exception handler, exception pair: abstract syntax; frame pair: abstract syntax; label pair: abstract syntax; handler .. _syntax-frame: .. _syntax-label: +.. _syntax-handler: .. _frame: .. _label: .. _handler: @@ -460,7 +490,7 @@ Stack ~~~~~ Besides the :ref:`store `, most :ref:`instructions ` interact with an implicit *stack*. -The stack contains three kinds of entries: +The stack contains the following kinds of entries: * *Values*: the *operands* of instructions. @@ -510,8 +540,8 @@ Intuitively, :math:`\instr^\ast` is the *continuation* to execute when the branc When branching, the empty continuation ends the targeted block, such that execution can proceed with consecutive instructions. -Activations and Frames -...................... +Activation Frames +................. Activation frames carry the return arity :math:`n` of the respective function, hold the values of its :ref:`locals ` (including arguments) in the order corresponding to their static :ref:`local indices `, @@ -519,41 +549,24 @@ and a reference to the function's own :ref:`module instance ` .. math:: \begin{array}{llll} - \production{activation} & \X{activation} &::=& - \FRAME_n\{\frame\} \\ \production{frame} & \frame &::=& \{ \ALOCALS~\val^\ast, \AMODULE~\moduleinst \} \\ \end{array} The values of the locals are mutated by respective :ref:`variable instructions `. -.. _syntax-handler: - -Exception handlers +Exception Handlers .................. -Exception handlers are installed by |TRY| instructions and are either *catching handlers* or *delegating handlers*. - -Catching handlers start with the identifier |CATCHadm| and contain handler clauses, which are mappings from :ref:`tag addresses ` -to their associated branch *targets*, each of which is expressed syntactically as a possibly empty sequence of -:ref:`instructions ` possibly following a :ref:`tag address `. -If there is no :ref:`tag address `, the instructions of that handler clause correspond to a |CATCHALL| clause. - -.. todo:: - Add prose for delegating handlers. +Exception handlers are installed by |TRYTABLE| instructions and record the corresponding list of :ref:`catch clauses `: .. math:: \begin{array}{llllll} - \production{handler} & \handler &::=& \CATCHadm\{\tagaddr^?~\instr^\ast\}^\ast &|& \DELEGATEadm\{l\} + \production{handler} & \handler &::=& + \HANDLER_n\{\catch^\ast\} \end{array} -Intuitively, for each handler clause :math:`\{\tagaddr^?~\instr^\ast\}` of a |CATCHadm|, :math:`\instr^\ast` is the *continuation* to execute -when the handler catches a thrown exception with tag |tagaddr|, or for any exception, when a handler clause specifies no tag address. -In that case, the exception is handled by the exception handler |CATCHadm|. -If this list of targets is empty, or if the tag address of the thrown exception is not in any of the handler's clauses and there is no |CATCHALL| clause, then the exception will be rethrown. - -.. todo:: - Add prose with intuition on delegating handlers. +The handlers on the stack are searched when an exception is :ref:`thrown `. .. _exec-expand: @@ -576,15 +589,10 @@ Conventions \end{array} -.. index:: ! administrative instructions, function, function instance, function address, label, frame, instruction, trap, call, memory, memory instance, table, table instance, element, data, segment, tag, tag instance, tag address, exceptions, reftype, catch, delegate, handler, caught +.. index:: ! administrative instructions, function, function instance, function address, label, frame, instruction, trap, call, memory, memory instance, table, table instance, element, data, segment, tag, tag instance, tag address, exception, reftype, handler, caught, caught exception pair:: abstract syntax; administrative instruction .. _syntax-trap: -.. _syntax-reffuncaddr: .. _syntax-invoke: -.. _syntax-throwadm: -.. _syntax-catchadm: -.. _syntax-delegateadm: -.. _syntax-caughtadm: .. _syntax-instr-admin: Administrative Instructions @@ -602,28 +610,24 @@ In order to express the reduction of :ref:`traps `, :ref:`calls `. Similarly, |REFEXTERNADDR| represents :ref:`external references `. +The |REFFUNCADDR| instruction represents :ref:`function reference values `. +Similarly, |REFEXTERNADDR| represents :ref:`external references `. +The |REFEXNADDR| instruction represents an :ref:`exception reference `. The |INVOKE| instruction represents the imminent invocation of a :ref:`function instance `, identified by its :ref:`address `. It unifies the handling of different forms of calls. -The |THROWadm| instruction represents the imminent throw of an exception based on a :ref:`tag instance `, identified by its :ref:`address `. -The values it will consume depend on its :ref:`tag type `. -It unifies the different forms of throwing exceptions. - -The |LABEL|, |FRAME|, |CATCHadm|, |DELEGATEadm|, and |CAUGHTadm| instructions model :ref:`labels `, :ref:`frames `, active :ref:`catching exception handlers `, active :ref:`delegating exception handlers `, and :ref:`caught exceptions `, respectively, :ref:`"on the stack" `. +The |LABEL|, |FRAME|, and |HANDLER| instructions model :ref:`labels `, :ref:`frames `, and active :ref:`exception handlers `, respectively, :ref:`"on the stack" `. Moreover, the administrative syntax maintains the nesting structure of the original :ref:`structured control instruction ` or :ref:`function body ` and their :ref:`instruction sequences ` with an |END| marker. That way, the end of the inner instruction sequence is known when part of an outer sequence. @@ -666,24 +670,16 @@ In order to specify the reduction of :ref:`branches `, the .. math:: \begin{array}{llll} - \production{block contexts} & \XB^0 &::=& - \val^\ast~[\_]~\instr^\ast \\ - \production{block contexts} & \XB^{k+1} &::=& - \val^\ast~\LABEL_n\{\instr^\ast\}~\XB^k~\END~\instr^\ast \\ + \production{block contexts} & \XB^k &::=& + \val~\XB^k ~|~ \XB^k~\instr ~|~ \HANDLER_n\{\catch^\ast\}~\XB^k~\END ~|~ \XC^k \\ + \production{label contexts} & \XC^0 &::=& + [\_] \\ + \production{label contexts} & \XC^{k+1} &::=& + \LABEL_n\{\instr^\ast\}~\XB^k~\END \\ \end{array} This definition allows to index active labels surrounding a :ref:`branch ` or :ref:`return ` instruction. -In order to be able to break jumping over exception handlers and caught exceptions, these new structured administrative control instructions are allowed to appear after labels in block contexts, by extending block context as follows. - -.. math:: - \begin{array}{llll} - \production{control contexts} & \XC^{k} &::=& \handler~\XB^k~\END \\ - & & | & \CAUGHTadm~\{\tagaddr~\val^\ast\}~\XB^k~\END \\ - \production{block contexts} & \XB^0 &::=& \dots ~|~ \val^\ast~\XC^0~\instr^\ast\\ - \production{block contexts} & \XB^{k+1} &::=& \dots ~|~ \val^\ast~\XC^{k+1}~\instr^\ast \\ - \end{array} - .. note:: For example, the :ref:`reduction ` of a simple branch can be defined as follows: @@ -692,18 +688,17 @@ In order to be able to break jumping over exception handlers and caught exceptio Here, the hole :math:`[\_]` of the context is instantiated with a branch instruction. When a branch occurs, - this rule replaces the targeted label and associated instruction sequence with the label's continuation. + this rule replaces the target label and associated instruction sequence with the label's continuation. The selected label is identified through the :ref:`label index ` :math:`l`, which corresponds to the number of surrounding |LABEL| instructions that must be hopped over -- which is exactly the count encoded in the index of a block context. -.. index:: ! throw context, tag, throw address, catch block, handler, exception +.. index:: ! throw context, tag, throw address, catch clause, handler, exception .. _syntax-ctxt-throw: Throw Contexts .............. -In order to specify the reduction of |TRY| blocks -with the help of the administrative instructions |THROWadm|, |CATCHadm|, |DELEGATEadm|, and |CAUGHTadm|, +In order to specify the reduction of |TRYTABLE| blocks, the following syntax of *throw contexts* is defined, as well as associated structural rules: .. math:: @@ -712,50 +707,13 @@ the following syntax of *throw contexts* is defined, as well as associated struc [\_] \\ &&|& \val^\ast~\XT~\instr^\ast \\ &&|& \LABEL_n\{\instr^\ast\}~\XT~\END \\ &&|& - \CAUGHTadm\{\tagaddr~\val^\ast\}~\XT~\END \\ &&|& \FRAME_n\{F\}~\XT~\END \\ \end{array} -Throw contexts allow matching the program context around a throw instruction up to the innermost enclosing |CATCHadm| or |DELEGATEadm|, thereby selecting the exception |handler| responsible for an exception, if one exists. -If no exception :ref:`handler that catches the exception ` is found, the computation :ref:`results ` in an uncaught exception result value, which contains the exception's entire throw context. +Throw contexts allow matching the program context around a throw instruction up to the innermost enclosing :ref:`exception handler `, if one exists. .. note:: - Contrary to block contexts, throw contexts don't skip over handlers. - - Since handlers are not included above, there is always a unique maximal throw context to match the reduction rules. - - |CAUGHTadm| blocks do not represent active handlers. Instead, they delimit the continuation of a handler that has already been selected. Their sole purpose is to record the exception that has been caught, such that |RETHROW| can access it inside such a block. - -.. note:: - For example, catching a simple :ref:`throw ` in a :ref:`try block ` would be as follows. - - Assume that :math:`\expand_F(bt) = [\I32~\F32~\I64] \to [\F32~\I64]`, - and that the tag address `a` of :math:`x` has tag type :math:`[\F32~\I64] \to []`. - Let :math:`\val_{i32}`, :math:`\val_{f32}`, and :math:`\val_{i64}` be values of type |I32|, |F32|, and |I64| respectively. - - .. math:: - \begin{array}{ll} - & \hspace{-5ex} F;~\val_{i32}~\val_{f32}~\val_{i64}~(\TRY~\X{bt}~(\THROW~x)~\CATCH~x~\END) \\ - \stepto & F;~\LABEL_2\{\} (\CATCHadm\{a~\epsilon\}~\val_{i32}~\val_{f32}~\val_{i64}~(\THROW~x)~\END)~\END \\ - \end{array} - - :ref:`Handling the thrown exception ` with tag address :math:`a` in the throw context - :math:`T=[\val_{i32}\_]`, with the exception handler :math:`H=\CATCHadm\{a~\epsilon\}` gives: - - .. math:: - \begin{array}{lll} - \stepto & F;~\LABEL_2\{\}~(\CAUGHTadm\{a~\val_{f32}~\val_{i64}\}~\val_{f32}~\val_{i64}~\END)~\END & \hspace{9ex}\ \\ - \stepto & F;~\LABEL_2\{\}~\val_{f32}~\val_{i64}~\END & \hspace{9ex}\ \\ - \stepto & \val_{f32}~\val_{i64} & \\ - \end{array} - - - When a throw of the form :math:`\val^m (\THROWadm~a)` occurs, search for the maximal surrounding throw context :math:`T` is performed, - which means any other values, labels, frames, and |CAUGHTadm| instructions surrounding the throw :math:`\val^m (\THROWadm~a)` are popped, - until a :ref:`handler ` for the exception is found. - Then a new |CAUGHTadm| instruction, containing the tag address :math:`a` and the values :math:`\val^m`, is pushed onto the stack. - - In this particular case, the exception is caught by the exception handler :math:`H` and its values are returned. + Contrary to block contexts, throw contexts do not skip over handlers. .. index:: ! configuration, ! thread, store, frame, instruction, module instruction diff --git a/document/core/index.rst b/document/core/index.rst index d8095d48a..0179df7be 100644 --- a/document/core/index.rst +++ b/document/core/index.rst @@ -3,7 +3,7 @@ WebAssembly Specification .. only:: html - | Release |release| + exception handling (Draft, |today|) + | Release |release| | Editor: Andreas Rossberg diff --git a/document/core/static/custom.css b/document/core/static/custom.css index 45838c1e3..33bb863d4 100644 --- a/document/core/static/custom.css +++ b/document/core/static/custom.css @@ -44,6 +44,8 @@ div.admonition p.admonition-title { div.math { background-color: #F0F0F0; padding: 3px 0 3px 0; + overflow-x: auto; + overflow-y: hidden; } div.relations { diff --git a/document/core/syntax/conventions.rst b/document/core/syntax/conventions.rst index 9e5dca182..5eeff48cd 100644 --- a/document/core/syntax/conventions.rst +++ b/document/core/syntax/conventions.rst @@ -20,7 +20,7 @@ Grammar Notation The following conventions are adopted in defining grammar rules for abstract syntax. -* Terminal symbols (atoms) are written in sans-serif font: :math:`\K{i32}, \K{end}`. +* Terminal symbols (atoms) are written in sans-serif font or in symbolic form: :math:`\K{i32}, \K{end}, {\to}, [, ]`. * Nonterminal symbols are written in italic font: :math:`\X{valtype}, \X{instr}`. diff --git a/document/core/syntax/instructions.rst b/document/core/syntax/instructions.rst index a79190a7f..2d58b6e2b 100644 --- a/document/core/syntax/instructions.rst +++ b/document/core/syntax/instructions.rst @@ -45,7 +45,7 @@ These operations closely match respective operations available in hardware. \production{signedness} & \sx &::=& \K{u} ~|~ \K{s} \\ \production{instruction} & \instr &::=& - \K{i}\X{nn}\K{.}\CONST~\xref{syntax/values}{syntax-int}{\iX{\X{nn}}} ~|~ + \K{i}\X{nn}\K{.}\CONST~\xref{syntax/values}{syntax-int}{\uX{\X{nn}}} ~|~ \K{f}\X{nn}\K{.}\CONST~\xref{syntax/values}{syntax-float}{\fX{\X{nn}}} \\&&|& \K{i}\X{nn}\K{.}\iunop ~|~ \K{f}\X{nn}\K{.}\funop \\&&|& @@ -621,11 +621,9 @@ The |DATADROP| instruction prevents further use of a passive data segment. This .. _syntax-block: .. _syntax-loop: .. _syntax-if: -.. _syntax-try: -.. _syntax-try-catch: -.. _syntax-try-delegate: +.. _syntax-try_table: .. _syntax-throw: -.. _syntax-rethrow: +.. _syntax-throw_ref: .. _syntax-br: .. _syntax-br_if: .. _syntax-br_table: @@ -634,6 +632,7 @@ The |DATADROP| instruction prevents further use of a passive data segment. This .. _syntax-call_indirect: .. _syntax-instr-seq: .. _syntax-instr-control: +.. _syntax-catch: Control Instructions ~~~~~~~~~~~~~~~~~~~~ @@ -651,32 +650,35 @@ Instructions in this group affect the flow of control. \BLOCK~\blocktype~\instr^\ast~\END \\&&|& \LOOP~\blocktype~\instr^\ast~\END \\&&|& \IF~\blocktype~\instr^\ast~\ELSE~\instr^\ast~\END \\&&|& - \TRY~\blocktype~\instr^\ast~(\CATCH~\tagidx~\instr^\ast)^\ast~(\CATCHALL~\instr^\ast)^?~\END \\ &&|& - \TRY~\blocktype~\instr^\ast~\DELEGATE~\labelidx \\ &&|& + \TRYTABLE~\blocktype~\catch^\ast~\instr^\ast~\END \\ &&|& \THROW~\tagidx \\&&|& - \RETHROW~\labelidx \\ &&|& + \THROWREF \\ &&|& \BR~\labelidx \\&&|& \BRIF~\labelidx \\&&|& \BRTABLE~\vec(\labelidx)~\labelidx \\&&|& \RETURN \\&&|& \CALL~\funcidx \\&&|& \CALLINDIRECT~\tableidx~\typeidx \\ + \production{catch clause} & \catch &::=& + \CATCH~\tagidx~\labelidx \\ &&|& + \CATCHREF~\tagidx~\labelidx \\ &&|& + \CATCHALL~\labelidx \\ &&|& + \CATCHALLREF~\labelidx \\ \end{array} The |NOP| instruction does nothing. The |UNREACHABLE| instruction causes an unconditional :ref:`trap `. -The |BLOCK|, |LOOP|, |IF|, and |TRY| instructions are *structured* instructions. +The |BLOCK|, |LOOP|, |IF|, and |TRYTABLE| instructions are *structured* instructions. They bracket nested sequences of instructions, called *blocks*, -separated by either |ELSE|, |CATCH|, or |CATCHALL| pseudo-instructions, -and terminated with either an |END| or a |DELEGATE| pseudo-instruction. +separated by the |ELSE| pseudo-instruction, +and terminated with an |END| pseudo-instruction. As the grammar prescribes, they must be well-nested. -The instructions |TRY|, |THROW|, and |RETHROW|, are concerned with handling exceptions. -The |TRY| instruction installs an exception handler, and may either handle exceptions in the case of |CATCH| and |CATCHALL|, -or rethrow them in an outer block in the case of |DELEGATE|. -The |THROW| and |RETHROW| instructions alter control flow by searching for a matching handler in one of the enclosing |TRY| blocks, if any. +The instructions |TRYTABLE|, |THROW|, and |THROWREF| are concerned with *exceptions*. +The |TRYTABLE| instruction installs an exception handler that handles exceptions as specified by its catch clauses.. +The |THROW| and |THROWREF| instructions raise and reraise an exception, repsectively, and transfers control to the innermost enclosing exception handler that has a matching catch clause. A structured instruction can consume *input* and produce *output* on the operand stack according to its annotated *block type*. It is given either as a :ref:`type index ` that refers to a suitable :ref:`function type `, or as an optional :ref:`value type ` inline, which is a shorthand for the function type :math:`[] \to [\valtype^?]`. @@ -694,9 +696,6 @@ In case of |BLOCK| or |IF| it is a *forward jump*, resuming execution after the matching |END|. In case of |LOOP| it is a *backward jump* to the beginning of the loop. -.. todo:: - Add prose for try-delegate's jump. - .. note:: This enforces *structured control flow*. Intuitively, a branch targeting a |BLOCK| or |IF| behaves like a :math:`\K{break}` statement in most C-like languages, diff --git a/document/core/syntax/modules.rst b/document/core/syntax/modules.rst index 256901681..b2d61a1c6 100644 --- a/document/core/syntax/modules.rst +++ b/document/core/syntax/modules.rst @@ -424,7 +424,7 @@ The |MIMPORTS| component of a module defines a set of *imports* that are require \IDFUNC~\typeidx \\&&|& \IDTABLE~\tabletype \\&&|& \IDMEM~\memtype \\&&|& - \IDTAG~\tagtype \\&&|& + \IDTAG~\typeidx \\&&|& \IDGLOBAL~\globaltype \\ \end{array} diff --git a/document/core/syntax/types.rst b/document/core/syntax/types.rst index b1c164ccb..9e0f8e40e 100644 --- a/document/core/syntax/types.rst +++ b/document/core/syntax/types.rst @@ -85,11 +85,13 @@ Reference Types .. math:: \begin{array}{llll} \production{reference type} & \reftype &::=& - \FUNCREF ~|~ \EXTERNREF \\ + \FUNCREF ~|~ \EXNREF ~|~ \EXTERNREF \\ \end{array} The type |FUNCREF| denotes the infinite union of all references to :ref:`functions `, regardless of their :ref:`function types `. +The type |EXNREF| denotes the infinite union of all references to :ref:`exceptions `, regardless of their associated :ref:`tag types `. + The type |EXTERNREF| denotes the infinite union of all references to objects owned by the :ref:`embedder ` and that can be passed into WebAssembly under this type. Reference types are *opaque*, meaning that neither their size nor their bit pattern can be observed. diff --git a/document/core/syntax/values.rst b/document/core/syntax/values.rst index 564ddc2d6..1b155df42 100644 --- a/document/core/syntax/values.rst +++ b/document/core/syntax/values.rst @@ -140,6 +140,8 @@ An *arithmetic NaN* is a floating-point value :math:`\pm\NAN(n)` with :math:`n .. note:: In the abstract syntax, subnormals are distinguished by the leading 0 of the significand. The exponent of subnormals has the same value as the smallest possible exponent of a normal number. Only in the :ref:`binary representation ` the exponent of a subnormal is encoded differently than the exponent of any normal number. + The notion of canonical NaN defined here is unrelated to the notion of canonical NaN that the |IEEE754|_ standard (Section 3.5.2) defines for decimal interchange formats. + Conventions ........... diff --git a/document/core/text/instructions.rst b/document/core/text/instructions.rst index bc5202ca6..d4f472535 100644 --- a/document/core/text/instructions.rst +++ b/document/core/text/instructions.rst @@ -34,6 +34,8 @@ The following grammar handles the corresponding update to the :ref:`identifier c \production{label} & \Tlabel_I &::=& v{:}\Tid &\Rightarrow& \{\ILABELS~v\} \compose I & (\iff v \notin I.\ILABELS) \\ &&|& + v{:}\Tid &\Rightarrow& \{\ILABELS~v\} \compose (I \with \ILABELS[i] = \epsilon) + & (\iff I.\ILABELS[i] = v) \\ &&|& \epsilon &\Rightarrow& \{\ILABELS~(\epsilon)\} \compose I \\ \end{array} @@ -42,6 +44,9 @@ The following grammar handles the corresponding update to the :ref:`identifier c This effectively shifts all existing labels up by one, mirroring the fact that control instructions are indexed relatively not absolutely. + If a label with the same name already exists, + then it is shadowed and the earlier label becomes inaccessible. + .. index:: control instructions, structured control, label, block, branch, result type, label index, function index, type index, vector, polymorphism, tag index, exception instructions pair: text format; instruction @@ -57,11 +62,11 @@ Control Instructions .. _text-loop: .. _text-if: .. _text-instr-block: -.. _text-try: +.. _text-try_table: +.. _text-catch: :ref:`Structured control instructions ` can bind an optional symbolic :ref:`label identifier `. -The same label identifier may optionally be repeated after the corresponding :math:`\T{end}`, :math:`\T{else}`, :math:`\T{catch}`, :math:`\T{catch\_all}`, and :math:`\T{delegate}` -pseudo instructions, to indicate the matching delimiters. +The same label identifier may optionally be repeated after the corresponding :math:`\T{end}` or :math:`\T{else}` keywords, to indicate the matching delimiters. Their :ref:`block type ` is given as a :ref:`type use `, analogous to the type of :ref:`functions `. However, the special case of a type use that is syntactically empty or consists of only a single :ref:`result ` is not regarded as an :ref:`abbreviation ` for an inline :ref:`function type `, but is parsed directly into an optional :ref:`value type `. @@ -86,15 +91,22 @@ However, the special case of a type use that is syntactically empty or consists \text{else}~~\Tid_1^?~~(\X{in}_2{:}\Tinstr_{I'})^\ast~~\text{end}~~\Tid_2^? \\ &&&\qquad \Rightarrow\quad \IF~\X{bt}~\X{in}_1^\ast~\ELSE~\X{in}_2^\ast~\END \qquad (\iff \Tid_1^? = \epsilon \vee \Tid_1^? = \Tlabel, \Tid_2^? = \epsilon \vee \Tid_2^? = \Tlabel) \\ &&|& - \text{try}~~I'{:}\Tlabel_I~~\X{bt}{:}\Tblocktype~~(\X{in}_1{:}\Tinstr_{I'})^\ast~~ - (\text{catch}~~\Tid_1^?~~x{:}\Ttagidx_I~~(\X{in}_2{:}\Tinstr_{I'})^\ast)^\ast~~ - \\ &&&\qquad\qquad (\text{catch\_all}~~\Tid_1^?~~(\X{in}_3{:}\Tinstr_{I'})^\ast)^?~~\text{end}~~\Tid_2^? - \\ &&&\qquad \Rightarrow\quad \TRY~\X{bt}~\X{in}_1^\ast~(\CATCH~x~\X{in}_2^\ast)^\ast~(\CATCHALL~\X{in}_3^\ast)^?~\END - \\ &&&\qquad\qquad (\iff \Tid_1^? = \epsilon \vee \Tid_1^? = \Tlabel, \Tid_2^? = \epsilon \vee \Tid_2^? = \Tlabel) \\ &&|& - \text{try}~~I'{:}\Tlabel_I~~\X{bt}{:}\Tblocktype~~(\X{in}_1{:}\Tinstr_{I'})^\ast - ~~\text{delegate}~~l{:}\Tlabelidx_I~~\X{l}{:}\Tlabelidx_I - \\ &&&\qquad \Rightarrow\quad \TRY~\X{bt}~\X{in}_1^\ast~\DELEGATE~l - \qquad\quad~~ (\iff \Tid^? = \epsilon \vee \Tid^? = \Tlabel) \\ + \text{try\_table}~~I'{:}\Tlabel_I~~\X{bt}{:}\Tblocktype~~(c{:}\Tcatch_I)^\ast~~(\X{in}{:}\Tinstr_{I'})^\ast~~\text{end}~~\Tid^? + \\ &&&\qquad \Rightarrow\quad \TRYTABLE~\X{bt}~c^\ast~\X{in}^\ast~~\END + \qquad\qquad (\iff \Tid^? = \epsilon \vee \Tid^? = \Tlabel) \\ + \production{catch clause} & \Tcatch_I & + \begin{array}[t]{@{}c@{}} ::= \\ | \\ | \\ | \\ \end{array} + & + \begin{array}[t]{@{}lcll@{}} + \text{(}~\text{catch}~~x{:}\Ttagidx_I~~l{:}\Tlabelidx_I~\text{)} + &\Rightarrow& \CATCH~x~l \\ + \text{(}~\text{catch\_ref}~~x{:}\Ttagidx_I~~l{:}\Tlabelidx_I~\text{)} + &\Rightarrow& \CATCHREF~x~l \\ + \text{(}~\text{catch\_all}~~l{:}\Tlabelidx_I~\text{)} + &\Rightarrow& \CATCHALL~l \\ + \text{(}~\text{catch\_all\_ref}~~l{:}\Tlabelidx_I~\text{)} + &\Rightarrow& \CATCHALLREF~l \\ + \end{array} \\ \end{array} .. note:: @@ -104,7 +116,7 @@ However, the special case of a type use that is syntactically empty or consists .. _text-nop: .. _text-unreachable: .. _text-throw: -.. _text-rethrow: +.. _text-throw_ref: .. _text-br: .. _text-br_if: .. _text-br_table: @@ -120,7 +132,7 @@ All other control instruction are represented verbatim. \text{unreachable} &\Rightarrow& \UNREACHABLE \\ &&|& \text{nop} &\Rightarrow& \NOP \\ &&|& \text{throw}~~x{:}\Ttagidx_I &\Rightarrow& \THROW~x \\ &&|& - \text{rethrow}~~l{:}\Tlabelidx_I &\Rightarrow& \RETHROW~l \\ &&|& + \text{throw\_ref} &\Rightarrow& \THROWREF \\ &&|& \text{br}~~l{:}\Tlabelidx_I &\Rightarrow& \BR~l \\ &&|& \text{br\_if}~~l{:}\Tlabelidx_I &\Rightarrow& \BRIF~l \\ &&|& \text{br\_table}~~l^\ast{:}\Tvec(\Tlabelidx_I)~~l_N{:}\Tlabelidx_I @@ -175,7 +187,7 @@ Reference Instructions \production{instruction} & \Tplaininstr_I &::=& \dots \\ &&|& \text{ref.null}~~t{:}\Theaptype &\Rightarrow& \REFNULL~t \\ &&|& \text{ref.is\_null} &\Rightarrow& \REFISNULL \\ &&|& - \text{ref.func}~~x{:}\Tfuncidx &\Rightarrow& \REFFUNC~x \\ &&|& + \text{ref.func}~~x{:}\Tfuncidx &\Rightarrow& \REFFUNC~x \\ \end{array} @@ -901,7 +913,7 @@ Vector constant instructions have a mandatory :ref:`shape ` de \text{f64x2.convert\_low\_i32x4\_s} &\Rightarrow& \F64X2.\VCONVERT\K{\_low\_i32x4\_s}\\ &&|& \text{f64x2.convert\_low\_i32x4\_u} &\Rightarrow& \F64X2.\VCONVERT\K{\_low\_i32x4\_u}\\ &&|& \text{f32x4.demote\_f64x2\_zero} &\Rightarrow& \F32X4.\VDEMOTE\K{\_f64x2\_zero}\\ &&|& - \text{f64x2.promote\_low\_f32x4} &\Rightarrow& \F64X2.\VPROMOTE\K{\_low\_f32x4}\\ &&|& + \text{f64x2.promote\_low\_f32x4} &\Rightarrow& \F64X2.\VPROMOTE\K{\_low\_f32x4}\\ \end{array} @@ -935,16 +947,9 @@ Such a folded instruction can appear anywhere a regular instruction can. \quad\equiv \\ &\qquad \Tfoldedinstr^\ast~~\text{if}~~\Tlabel &\hspace{-12ex} \Tblocktype~~\Tinstr_1^\ast~~\text{else}~~(\Tinstr_2^\ast)^?~\text{end} \\ & - \text{(}~\text{try}~~\Tlabel~~\Tblocktype~~\text{(}~\text{do} &\hspace{-8ex} \Tinstr_1^\ast~\text{)}~~ - (\text{(}~\text{catch}~~x{:}\Ttagidx_I~~\Tinstr_2^\ast~\text{)})^\ast \\ &\quad - (\text{(}~\text{catch\_all}~~\Tinstr_3^\ast~\text{)})^?~\text{)} - \quad\equiv \\ &\qquad - \text{try}~~\Tlabel~~\Tblocktype~~\Tinstr_1^\ast - &\hspace{-5ex} (\text{catch}~~x{:}\Ttagidx_I~~\Tinstr_2^\ast)^\ast~~(\text{catch\_all}~~\Tinstr_3^\ast)^?~~\text{end} \\ & - \text{(}~\text{try}~~\Tlabel~~\Tblocktype~~\text{(}~\text{do} &\hspace{-8ex} \Tinstr^\ast~\text{)}~~ - \text{(}~\text{delegate}~~l{:}\Tlabelidx~~\text{)}~\text{)} + \text{(}~\text{try\_table}~~\Tlabel~~\Tblocktype~~\Tcatch^\ast~~\Tinstr^\ast~\text{)} \quad\equiv \\ &\qquad - \text{try}~~\Tlabel~~\Tblocktype~~\Tinstr^\ast &\hspace{-5ex} \text{delegate}~~l{:}\Tlabelidx \\ + \text{try\_table}~~\Tlabel~~\Tblocktype~~\Tcatch^\ast~~\Tinstr^\ast~~\text{end} \\ \end{array} diff --git a/document/core/text/lexical.rst b/document/core/text/lexical.rst index f46646662..1dd34c863 100644 --- a/document/core/text/lexical.rst +++ b/document/core/text/lexical.rst @@ -48,7 +48,7 @@ The character stream in the source text is divided, from left to right, into a s \text{(} ~|~ \text{)} ~|~ \Treserved \\ \production{keyword} & \Tkeyword &::=& (\text{a} ~|~ \dots ~|~ \text{z})~\Tidchar^\ast - \qquad (\mbox{if occurring as a literal terminal in the grammar}) \\ + \qquad (\iff~\mbox{occurring as a literal terminal in the grammar}) \\ \production{reserved} & \Treserved &::=& (\Tidchar ~|~ \Tstring)^+ \\ \end{array} diff --git a/document/core/text/modules.rst b/document/core/text/modules.rst index 0ec6611d0..5bf0e2096 100644 --- a/document/core/text/modules.rst +++ b/document/core/text/modules.rst @@ -17,6 +17,7 @@ Modules .. _text-funcidx: .. _text-tableidx: .. _text-memidx: +.. _text-tagidx: .. _text-elemidx: .. _text-dataidx: .. _text-globalidx: @@ -112,7 +113,7 @@ If inline declarations are given, then their types must match the referenced :re \end{array} \\ \end{array} -The synthesized attribute of a |Ttypeuse| is a pair consisting of both the used :ref:`type index ` and the updated :ref:`identifier context ` including possible parameter identifiers. +The synthesized attribute of a |Ttypeuse| is a pair consisting of both the used :ref:`type index ` and the local :ref:`identifier context ` containing possible parameter identifiers. The following auxiliary function extracts optional identifiers from parameters: .. math:: @@ -206,7 +207,7 @@ Function definitions can bind a symbolic :ref:`function identifier `, a \text{(}~\text{func}~~\Tid^?~~x,I'{:}\Ttypeuse_I~~ (t{:}\Tlocal)^\ast~~(\X{in}{:}\Tinstr_{I''})^\ast~\text{)} \\ &&& \qquad \Rightarrow\quad \{ \FTYPE~x, \FLOCALS~t^\ast, \FBODY~\X{in}^\ast~\END \} \\ &&& \qquad\qquad\qquad - (\iff I'' = I' \compose \{\ILOCALS~\F{id}(\Tlocal)^\ast\} \idcwellformed) \\[1ex] + (\iff I'' = I \compose I' \compose \{\ILOCALS~\F{id}(\Tlocal)^\ast\} \idcwellformed) \\[1ex] \production{local} & \Tlocal &::=& \text{(}~\text{local}~~\Tid^?~~t{:}\Tvaltype~\text{)} \quad\Rightarrow\quad t \\ @@ -298,7 +299,7 @@ An :ref:`element segment ` can be given inline with a table definitio \production{module field} & \text{(}~\text{table}~~\Tid^?~~\Treftype~~\text{(}~\text{elem}~~\expr^n{:}\Tvec(\Telemexpr)~\text{)}~\text{)} \quad\equiv \\ & \qquad \text{(}~\text{table}~~\Tid'~~n~~n~~\Treftype~\text{)} \\ & \qquad - \text{(}~\text{elem}~~\text{(}~\text{table}~~\Tid'~\text{)}~~\text{(}~\text{i32.const}~~\text{0}~\text{)}~~\Tvec(\Telemexpr)~\text{)} + \text{(}~\text{elem}~~\text{(}~\text{table}~~\Tid'~\text{)}~~\text{(}~\text{i32.const}~~\text{0}~\text{)}~~\Treftype~~\Tvec(\Telemexpr)~\text{)} \\ & \qquad\qquad (\iff \Tid^? \neq \epsilon \wedge \Tid' = \Tid^? \vee \Tid^? = \epsilon \wedge \Tid' \idfresh) \\ \end{array} @@ -308,7 +309,7 @@ An :ref:`element segment ` can be given inline with a table definitio \production{module field} & \text{(}~\text{table}~~\Tid^?~~\Treftype~~\text{(}~\text{elem}~~x^n{:}\Tvec(\Tfuncidx)~\text{)}~\text{)} \quad\equiv \\ & \qquad \text{(}~\text{table}~~\Tid'~~n~~n~~\Treftype~\text{)} \\ & \qquad - \text{(}~\text{elem}~~\text{(}~\text{table}~~\Tid'~\text{)}~~\text{(}~\text{i32.const}~~\text{0}~\text{)}~~\Tvec(\Tfuncidx)~\text{)} + \text{(}~\text{elem}~~\text{(}~\text{table}~~\Tid'~\text{)}~~\text{(}~\text{i32.const}~~\text{0}~\text{)}~~\text{func}~~\Tvec(\Tfuncidx)~\text{)} \\ & \qquad\qquad (\iff \Tid^? \neq \epsilon \wedge \Tid' = \Tid^? \vee \Tid^? = \epsilon \wedge \Tid' \idfresh) \\ \end{array} diff --git a/document/core/text/types.rst b/document/core/text/types.rst index 7705cc575..685a36572 100644 --- a/document/core/text/types.rst +++ b/document/core/text/types.rst @@ -48,9 +48,11 @@ Reference Types \begin{array}{llcll@{\qquad\qquad}l} \production{reference type} & \Treftype &::=& \text{funcref} &\Rightarrow& \FUNCREF \\ &&|& + \text{exnref} &\Rightarrow& \EXNREF \\ &&|& \text{externref} &\Rightarrow& \EXTERNREF \\ \production{heap type} & \Theaptype &::=& \text{func} &\Rightarrow& \FUNCREF \\ &&|& + \text{exn} &\Rightarrow& \EXNREF \\ &&|& \text{extern} &\Rightarrow& \EXTERNREF \\ \end{array} diff --git a/document/core/util/bikeshed_fixup.py b/document/core/util/bikeshed_fixup.py index dcd4fd070..05439207f 100755 --- a/document/core/util/bikeshed_fixup.py +++ b/document/core/util/bikeshed_fixup.py @@ -11,6 +11,12 @@ def Main(): data = open(sys.argv[1]).read() + # Make bikeshed happy + # Apparently it can't handle empty line before DOCTYPE comment + data = data.replace('\n + data = data.replace('
', '\n
')
+
   # Don't add more than 3 levels to TOC.
   data = data.replace('
', '
') diff --git a/document/core/util/macros.def b/document/core/util/macros.def index b6ea41062..ed0da3328 100644 --- a/document/core/util/macros.def +++ b/document/core/util/macros.def @@ -9,7 +9,7 @@ .. |WasmIssues| replace:: |issuelink| .. _WasmIssues: |issuelink| -.. |IEEE754| replace:: IEEE 754-2019 +.. |IEEE754| replace:: IEEE 754 .. _IEEE754: https://ieeexplore.ieee.org/document/8766229 .. |Unicode| replace:: Unicode @@ -176,6 +176,7 @@ .. Types, terminals .. |to| mathdef:: \xref{syntax/types}{syntax-functype}{\rightarrow} +.. |toF| mathdef:: \xref{syntax/types}{syntax-functype}{\rightarrow} .. |I8| mathdef:: \xref{exec/runtime}{syntax-storagetype}{\K{i8}} .. |I16| mathdef:: \xref{exec/runtime}{syntax-storagetype}{\K{i16}} @@ -194,6 +195,7 @@ .. |FUNCREF| mathdef:: \xref{syntax/types}{syntax-reftype}{\K{funcref}} .. |EXTERNREF| mathdef:: \xref{syntax/types}{syntax-reftype}{\K{externref}} +.. |EXNREF| mathdef:: \xref{syntax/types}{syntax-reftype}{\K{exnref}} .. |MVAR| mathdef:: \xref{syntax/types}{syntax-mut}{\K{var}} .. |MCONST| mathdef:: \xref{syntax/types}{syntax-mut}{\K{const}} @@ -377,12 +379,13 @@ .. |RETURN| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{return}} .. |CALL| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{call}} .. |CALLINDIRECT| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{call\_indirect}} -.. |TRY| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{try}} +.. |TRYTABLE| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{try\_table}} .. |CATCH| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{catch}} +.. |CATCHREF| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{catch\_ref}} .. |CATCHALL| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{catch\_all}} -.. |DELEGATE| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{delegate}} +.. |CATCHALLREF| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{catch\_all\_ref}} .. |THROW| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{throw}} -.. |RETHROW| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{rethrow}} +.. |THROWREF| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{throw\_ref}} .. |DROP| mathdef:: \xref{syntax/instructions}{syntax-instr-parametric}{\K{drop}} .. |SELECT| mathdef:: \xref{syntax/instructions}{syntax-instr-parametric}{\K{select}} @@ -560,6 +563,7 @@ .. |blocktype| mathdef:: \xref{syntax/instructions}{syntax-blocktype}{\X{blocktype}} .. |instr| mathdef:: \xref{syntax/instructions}{syntax-instr}{\X{instr}} +.. |catch| mathdef:: \xref{syntax/instructions}{syntax-catch}{\X{catch}} .. |expr| mathdef:: \xref{syntax/instructions}{syntax-expr}{\X{expr}} @@ -689,6 +693,7 @@ .. |Bblocktype| mathdef:: \xref{binary/instructions}{binary-blocktype}{\B{blocktype}} .. |Binstr| mathdef:: \xref{binary/instructions}{binary-instr}{\B{instr}} +.. |Bcatch| mathdef:: \xref{binary/instructions}{binary-catch}{\B{catch}} .. |Bexpr| mathdef:: \xref{binary/instructions}{binary-expr}{\B{expr}} .. |Blaneidx| mathdef:: \xref{binary/instructions}{binary-laneidx}{\B{laneidx}} @@ -861,6 +866,7 @@ .. |Tplaininstr| mathdef:: \xref{text/instructions}{text-plaininstr}{\T{plaininstr}} .. |Tblockinstr| mathdef:: \xref{text/instructions}{text-blockinstr}{\T{blockinstr}} .. |Tfoldedinstr| mathdef:: \xref{text/instructions}{text-foldedinstr}{\T{foldedinstr}} +.. |Tcatch| mathdef:: \xref{text/instructions}{text-catch}{\T{catch}} .. |Texpr| mathdef:: \xref{text/instructions}{text-expr}{\T{expr}} @@ -913,7 +919,6 @@ .. |CLABELS| mathdef:: \xref{valid/conventions}{context}{\K{labels}} .. |CRETURN| mathdef:: \xref{valid/conventions}{context}{\K{return}} .. |CREFS| mathdef:: \xref{valid/conventions}{context}{\K{refs}} -.. |LCATCH| mathdef:: \xref{valid/conventions}{context}{\K{catch}} .. Contexts, non-terminals @@ -933,6 +938,7 @@ .. |vdashinstr| mathdef:: \xref{valid/instructions}{valid-instr}{\vdash} .. |vdashinstrseq| mathdef:: \xref{valid/instructions}{valid-instr-seq}{\vdash} +.. |vdashcatch| mathdef:: \xref{valid/instructions}{valid-catch}{\vdash} .. |vdashexpr| mathdef:: \xref{valid/instructions}{valid-expr}{\vdash} .. |vdashexprconst| mathdef:: \xref{valid/instructions}{valid-constant}{\vdash} .. |vdashinstrconst| mathdef:: \xref{valid/instructions}{valid-constant}{\vdash} @@ -975,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}} @@ -994,6 +1001,7 @@ .. |globaladdr| mathdef:: \xref{exec/runtime}{syntax-globaladdr}{\X{globaladdr}} .. |elemaddr| mathdef:: \xref{exec/runtime}{syntax-elemaddr}{\X{elemaddr}} .. |dataaddr| mathdef:: \xref{exec/runtime}{syntax-dataaddr}{\X{dataaddr}} +.. |exnaddr| mathdef:: \xref{exec/runtime}{syntax-exnaddr}{\X{exnaddr}} .. |externaddr| mathdef:: \xref{exec/runtime}{syntax-externaddr}{\X{externaddr}} .. Instances, terminals @@ -1022,6 +1030,9 @@ .. |EINAME| mathdef:: \xref{exec/runtime}{syntax-exportinst}{\K{name}} .. |EIVALUE| mathdef:: \xref{exec/runtime}{syntax-exportinst}{\K{value}} +.. |EITAG| mathdef:: \xref{exec/runtime}{syntax-exninst}{\K{tag}} +.. |EIFIELDS| mathdef:: \xref{exec/runtime}{syntax-exninst}{\K{fields}} + .. |EVFUNC| mathdef:: \xref{exec/runtime}{syntax-externval}{\K{func}} .. |EVTABLE| mathdef:: \xref{exec/runtime}{syntax-externval}{\K{table}} .. |EVMEM| mathdef:: \xref{exec/runtime}{syntax-externval}{\K{mem}} @@ -1052,6 +1063,7 @@ .. |eleminst| mathdef:: \xref{exec/runtime}{syntax-eleminst}{\X{eleminst}} .. |datainst| mathdef:: \xref{exec/runtime}{syntax-datainst}{\X{datainst}} .. |exportinst| mathdef:: \xref{exec/runtime}{syntax-exportinst}{\X{exportinst}} +.. |exninst| mathdef:: \xref{exec/runtime}{syntax-exninst}{\X{exninst}} .. |hostfunc| mathdef:: \xref{exec/runtime}{syntax-hostfunc}{\X{hostfunc}} @@ -1074,6 +1086,7 @@ .. |SGLOBALS| mathdef:: \xref{exec/runtime}{syntax-store}{\K{globals}} .. |SELEMS| mathdef:: \xref{exec/runtime}{syntax-store}{\K{elems}} .. |SDATAS| mathdef:: \xref{exec/runtime}{syntax-store}{\K{datas}} +.. |SEXNS| mathdef:: \xref{exec/runtime}{syntax-store}{\K{exns}} .. Store, non-terminals @@ -1102,14 +1115,12 @@ .. Administrative Instructions, terminals -.. |REFFUNCADDR| mathdef:: \xref{exec/runtime}{syntax-ref}{\K{ref}} -.. |REFEXTERNADDR| mathdef:: \xref{exec/runtime}{syntax-ref.extern}{\K{ref{.}extern}} +.. |REFFUNCADDR| mathdef:: \xref{exec/runtime}{syntax-ref.func-addr}{\K{ref}} +.. |REFEXTERNADDR| mathdef:: \xref{exec/runtime}{syntax-ref.extern-addr}{\K{ref{.}extern}} +.. |REFEXNADDR| mathdef:: \xref{exec/runtime}{syntax-ref.exn-addr}{\K{ref{.}exn}} .. |TRAP| mathdef:: \xref{exec/runtime}{syntax-trap}{\K{trap}} .. |INVOKE| mathdef:: \xref{exec/runtime}{syntax-invoke}{\K{invoke}} -.. |THROWadm| mathdef:: \xref{exec/runtime}{syntax-throwadm}{\K{throw}} -.. |CATCHadm| mathdef:: \xref{exec/runtime}{syntax-catchadm}{\K{catch}} -.. |DELEGATEadm| mathdef:: \xref{exec/runtime}{syntax-delegateadm}{\K{delegate}} -.. |CAUGHTadm| mathdef:: \xref{exec/runtime}{syntax-caughtadm}{\K{caught}} +.. |HANDLER| mathdef:: \xref{exec/runtime}{syntax-handler}{\K{handler}} .. Values & Results, non-terminals @@ -1270,7 +1281,7 @@ .. |vdashadmininstr| mathdef:: \xref{appendix/properties}{valid-instr-admin}{\vdash} -.. |vdashval| mathdef:: \xref{appendix/properties}{valid-val}{\vdash} +.. |vdashval| mathdef:: \xref{exec/modules}{valid-val}{\vdash} .. |vdashresult| mathdef:: \xref{appendix/properties}{valid-result}{\vdash} .. |vdashfuncinst| mathdef:: \xref{appendix/properties}{valid-funcinst}{\vdash} @@ -1280,6 +1291,7 @@ .. |vdashglobalinst| mathdef:: \xref{appendix/properties}{valid-globalinst}{\vdash} .. |vdasheleminst| mathdef:: \xref{appendix/properties}{valid-eleminst}{\vdash} .. |vdashdatainst| mathdef:: \xref{appendix/properties}{valid-datainst}{\vdash} +.. |vdashexninst| mathdef:: \xref{appendix/properties}{valid-exninst}{\vdash} .. |vdashexportinst| mathdef:: \xref{appendix/properties}{valid-exportinst}{\vdash} .. |vdashmoduleinst| mathdef:: \xref{appendix/properties}{valid-moduleinst}{\vdash} @@ -1295,6 +1307,7 @@ .. |vdashglobalinstextends| mathdef:: \xref{appendix/properties}{extend-globalinst}{\vdash} .. |vdasheleminstextends| mathdef:: \xref{appendix/properties}{extend-eleminst}{\vdash} .. |vdashdatainstextends| mathdef:: \xref{appendix/properties}{extend-datainst}{\vdash} +.. |vdashexninstextends| mathdef:: \xref{appendix/properties}{extend-exninst}{\vdash} .. |vdashstoreextends| mathdef:: \xref{appendix/properties}{extend-store}{\vdash} @@ -1323,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}} diff --git a/document/core/valid/conventions.rst b/document/core/valid/conventions.rst index fdcf5e961..544a8133d 100644 --- a/document/core/valid/conventions.rst +++ b/document/core/valid/conventions.rst @@ -26,7 +26,6 @@ The skeleton of a sound and complete algorithm for type-checking instruction seq .. index:: ! context, function type, table type, memory type, tag type, global type, value type, result type, index space, module, function, tag, label type .. _context: -.. _syntax-labeltype: Contexts ~~~~~~~~ @@ -43,7 +42,7 @@ which collects relevant information about the surrounding :ref:`module ` accessible from the current position, represented by their :ref:`result type `. * *Return*: the return type of the current function, represented as an optional result type that is absent when no return is allowed, as in free-standing expressions. * *References*: the list of :ref:`function indices ` that occur in the module outside functions and can hence be used to form references inside them. @@ -56,19 +55,18 @@ More concretely, contexts are defined as :ref:`records ` :math: .. math:: \begin{array}{llll} - \production{labeltype} & \labeltype & ::= & \LCATCH^?~\resulttype\\ \production{context} & C &::=& \begin{array}[t]{l@{~}ll} \{ & \CTYPES & \functype^\ast, \\ & \CFUNCS & \functype^\ast, \\ & \CTABLES & \tabletype^\ast, \\ & \CMEMS & \memtype^\ast, \\ - & \CTAGS & \tagtype^\ast, \\ + & \CTAGS & \tagtype^\ast, \\ & \CGLOBALS & \globaltype^\ast, \\ & \CELEMS & \reftype^\ast, \\ & \CDATAS & {\ok}^\ast, \\ & \CLOCALS & \valtype^\ast, \\ - & \CLABELS & \labeltype^\ast, \\ + & \CLABELS & \resulttype^\ast, \\ & \CRETURN & \resulttype^?, \\ & \CREFS & \funcidx^\ast ~\} \\ \end{array} diff --git a/document/core/valid/instructions.rst b/document/core/valid/instructions.rst index c6b83eee4..44c400877 100644 --- a/document/core/valid/instructions.rst +++ b/document/core/valid/instructions.rst @@ -1234,7 +1234,7 @@ Memory Instructions } -.. index:: control instructions, structured control, label, block, branch, block type, label index, label type, function index, type index, tag index, vector, polymorphism, context +.. index:: control instructions, structured control, label, block, branch, block type, label index, result type, function index, type index, tag index, vector, polymorphism, context pair: validation; instruction single: abstract syntax; instruction .. _valid-label: @@ -1281,7 +1281,7 @@ Control Instructions * The :ref:`block type ` must be :ref:`valid ` as some :ref:`function type ` :math:`[t_1^\ast] \to [t_2^\ast]`. -* Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with the :ref:`label type ` :math:`[t_2^\ast]` prepended to the |CLABELS| vector. +* Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with the :ref:`result type ` :math:`[t_2^\ast]` prepended to the |CLABELS| vector. * Under context :math:`C'`, the instruction sequence :math:`\instr^\ast` must be :ref:`valid ` with type :math:`[t_1^\ast] \to [t_2^\ast]`. @@ -1308,7 +1308,7 @@ Control Instructions * The :ref:`block type ` must be :ref:`valid ` as some :ref:`function type ` :math:`[t_1^\ast] \to [t_2^\ast]`. -* Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with the :ref:`label type ` :math:`[t_1^\ast]` prepended to the |CLABELS| vector. +* Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with the :ref:`result type ` :math:`[t_1^\ast]` prepended to the |CLABELS| vector. * Under context :math:`C'`, the instruction sequence :math:`\instr^\ast` must be :ref:`valid ` with type :math:`[t_1^\ast] \to [t_2^\ast]`. @@ -1335,7 +1335,7 @@ Control Instructions * The :ref:`block type ` must be :ref:`valid ` as some :ref:`function type ` :math:`[t_1^\ast] \to [t_2^\ast]`. -* Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with the :ref:`label type ` :math:`[t_2^\ast]` prepended to the |CLABELS| vector. +* Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with the :ref:`result type ` :math:`[t_2^\ast]` prepended to the |CLABELS| vector. * Under context :math:`C'`, the instruction sequence :math:`\instr_1^\ast` must be :ref:`valid ` with type :math:`[t_1^\ast] \to [t_2^\ast]`. @@ -1361,86 +1361,121 @@ Control Instructions -.. _valid-try-catch: +.. _valid-try_table: -:math:`\TRY~\blocktype~\instr_1^\ast~(\CATCH~x~\instr_2^\ast)^\ast~(\CATCHALL~\instr_3^\ast)^?~\END` -.................................................................................................... +:math:`\TRYTABLE~\blocktype~\catch^\ast~\instr^\ast~\END` +......................................................... * The :ref:`block type ` must be :ref:`valid ` as some :ref:`function type ` :math:`[t_1^\ast] \to [t_2^\ast]`. -* Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with the :ref:`label type ` :math:`[t_2^\ast]` prepended to the |CLABELS| vector. +* For every :ref:`catch clause ` :math:`\catch_i` in :math:`\catch^\ast`, :math:`\catch_i` must be :ref:`valid `. + +* Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with the :ref:`result type ` :math:`[t_2^\ast]` prepended to the |CLABELS| vector. * Under context :math:`C'`, - the instruction sequence :math:`\instr_1^\ast` must be :ref:`valid ` with type :math:`[t_1^\ast] \to [t_2^\ast]`. + the instruction sequence :math:`\instr^\ast` must be :ref:`valid ` with type :math:`[t_1^\ast] \to [t_2^\ast]`. -* Let :math:`C''` be the same :ref:`context ` as :math:`C`, but with the :ref:`label type ` :math:`\LCATCH~[t_2^\ast]` prepended to the |CLABELS| vector. +* Then the compound instruction is valid with type :math:`[t_1^\ast] \to [t_2^\ast]`. -* For every :math:`x_i` and :math:`\instr_{2i}^\ast` in :math:`(\CATCH~x~\instr_2^\ast)^\ast`: - * The tag :math:`C.\CTAGS[x_i]` must be defined in the context :math:`C`. +.. math:: + \frac{ + \begin{array}{c} + C \vdashblocktype \blocktype : [t_1^\ast] \to [t_2^\ast] + \qquad + (C \vdashcatch \catch \ok)^\ast + \qquad + C,\CLABELS\,[t_2^\ast] \vdashinstrseq \instr^\ast : [t_1^\ast] \to [t_2^\ast] \\ + \end{array} + }{ + C \vdashinstr \TRYTABLE~\blocktype~\catch^\ast~\instr^\ast~\END : [t_1^\ast] \to [t_2^\ast] + } - * Let :math:`[t_{3i}^\ast] \to [t_{4i}^\ast]` be the :ref:`tag type ` :math:`C.\CTAGS[x_i]`. +.. note:: + The :ref:`notation ` :math:`C,\CLABELS\,[t^\ast]` inserts the new label type at index :math:`0`, shifting all others. - * The :ref:`result type ` :math:`[t_{4i}^\ast]` must be empty. - * Under context :math:`C''`, - the instruction sequence :math:`\instr_{2i}^\ast` must be :ref:`valid ` with type :math:`[t_{3i}^\ast] \to [t_2^\ast]`. +.. _valid-catch: -* If :math:`(\CATCHALL~\instr_3^\ast)^?` is not empty, then: +:math:`\CATCH~x~l` +.................. - * Under context :math:`C''`, - the instruction sequence :math:`\instr_3^\ast` must be :ref:`valid ` with type :math:`[] \to [t_2^\ast]`. +* The tag :math:`C.\CTAGS[x]` must be defined in the context. -* Then the compound instruction is valid with type :math:`[t_1^\ast] \to [t_2^\ast]`. +* Let :math:`[t^\ast] \to [{t'}^\ast]` be the :ref:`tag type ` :math:`C.\CTAGS[x]`. + +* The :ref:`result type ` :math:`[{t'}^\ast]` must be empty. + +* The label :math:`C.\CLABELS[l]` must be defined in the context. + +* The :ref:`result type ` :math:`[t^\ast]` must be the same as :math:`C.\CLABELS[l]`. + +* Then the catch clause is valid. .. math:: \frac{ - \begin{array}{c} - C \vdashblocktype \blocktype : [t_1^\ast] \to [t_2^\ast] + C.\CTAGS[x] = [t^\ast] \toF [] \qquad - C,\CLABELS\,[t_2^\ast] \vdashinstrseq \instr_1^\ast : [t_1^\ast] \to [t_2^\ast] \\ - (C.\CTAGS[x] = [t^\ast] \to [] \\ - C,\CLABELS\,(\LCATCH~[t_2^\ast]) \vdashinstrseq \instr_2^\ast : [t^\ast] \to [t_2^\ast])^\ast \\ - (C,\CLABELS\,(\LCATCH~[t_2^\ast]) \vdashinstrseq \instr_3^\ast : [] \to [t_2^\ast])^? - \end{array} + C.\CLABELS[l] = [t^\ast] }{ - C \vdashinstr \TRY~\blocktype~\instr_1^\ast~(\CATCH~x~\instr_2^\ast)^\ast~(\CATCHALL~\instr_3^\ast)^?~\END : [t_1^\ast] \to [t_2^\ast] + C \vdashcatch \CATCH~x~l \ok } +:math:`\CATCHREF~x~l` +..................... -.. note:: - The :ref:`notation ` :math:`C,\CLABELS\,(\LCATCH^?~[t^\ast])` inserts the new label type at index :math:`0`, shifting all others. - +* The tag :math:`C.\CTAGS[x]` must be defined in the context. -.. _valid-try-delegate: +* Let :math:`[t^\ast] \to [{t'}^\ast]` be the :ref:`tag type ` :math:`C.\CTAGS[x]`. -:math:`\TRY~\blocktype~\instr^\ast~\DELEGATE~l` -............................................... +* The :ref:`result type ` :math:`[{t'}^\ast]` must be empty. * The label :math:`C.\CLABELS[l]` must be defined in the context. -* The :ref:`block type ` must be :ref:`valid ` as some :ref:`function type ` :math:`[t_1^\ast] \to [t_2^\ast]`. +* The :ref:`result type ` :math:`[t^\ast]` must be the same as :math:`C.\CLABELS[l]` with |EXNREF| appended. -* Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with the :ref:`result type ` :math:`[t_2^\ast]` prepended to the |CLABELS| vector. +* Then the catch clause is valid. -* Under context :math:`C'`, - the instruction sequence :math:`\instr^\ast` must be :ref:`valid ` with type :math:`[t_1^\ast] \to [t_2^\ast]`. +.. math:: + \frac{ + C.\CTAGS[x] = [t^\ast] \toF [] + \qquad + C.\CLABELS[l] = [t^\ast~\EXNREF] + }{ + C \vdashcatch \CATCHREF~x~l \ok + } -* Then the compound instruction is valid with type :math:`[t_1^\ast] \to [t_2^\ast]`. +:math:`\CATCHALL~l` +................... + +* The label :math:`C.\CLABELS[l]` must be defined in the context. + +* The :ref:`result type ` :math:`C.\CLABELS[l]` must be empty. + +* Then the catch clause is valid. .. math:: \frac{ - C \vdashblocktype \blocktype : [t_1^\ast] \to [t_2^\ast] - \qquad - C,\CLABELS\,[t_2^\ast] \vdashinstrseq \instr^\ast : [t_1^\ast]\to[t_2^\ast] - \qquad - C.\CLABELS[l] = [t_0^\ast] + C.\CLABELS[l] = [] }{ - C \vdashinstrseq \TRY~\blocktype~\instr^\ast~\DELEGATE~l : [t_1^\ast]\to[t_2^\ast] + C \vdashcatch \CATCHALL~l \ok } -.. note:: - The :ref:`label index ` space in the :ref:`context ` :math:`C` contains the most recent label first, so that :math:`C.\CLABELS[l]` performs a relative lookup as expected. +:math:`\CATCHALLREF~l` +...................... + +* The label :math:`C.\CLABELS[l]` must be defined in the context. + +* The :ref:`result type ` :math:`C.\CLABELS[l]` must be :math:`[\EXNREF]`. + +* Then the catch clause is valid. + +.. math:: + \frac{ + C.\CLABELS[l] = [\EXNREF] + }{ + C \vdashcatch \CATCHALLREF~l \ok + } .. _valid-throw: @@ -1450,7 +1485,9 @@ Control Instructions * The tag :math:`C.\CTAGS[x]` must be defined in the context. -* Let :math:`[t^\ast] \to []` be its :ref:`tag type `. +* Let :math:`[t^\ast] \to [{t'}^\ast]` be the :ref:`tag type ` :math:`C.\CTAGS[x]`. + +* The :ref:`result type ` :math:`[{t'}^\ast]` must be empty. * Then the instruction is valid with type :math:`[t_1^\ast t^\ast] \to [t_2^\ast]`, for any sequences of :ref:`value types ` :math:`t_1^\ast` and :math:`t_2^\ast`. @@ -1458,7 +1495,7 @@ Control Instructions \frac{ C.\CTAGS[x] = [t^\ast] \to [] }{ - C \vdashinstr \THROW~x : [t_1^\ast t^\ast] \to [t_2^\ast] + C \vdashinstr \THROW~x : [t_1^\ast~t^\ast] \to [t_2^\ast] } @@ -1466,30 +1503,23 @@ Control Instructions The |THROW| instruction is :ref:`stack-polymorphic `. -.. _valid-rethrow: - -:math:`\RETHROW~l` -.................. - -* The label :math:`C.\CLABELS[l]` must be defined in the context. - -* Let :math:`(\LCATCH^?~[t^\ast])` be the :ref:`label type ` :math:`C.\CLABELS[l]`. +.. _valid-throw_ref: -* The |LCATCH| must be present in the :ref:`label type ` :math:`C.\CLABELS[l]`. +:math:`\THROWREF` +................. -* Then the instruction is valid with type :math:`[t_1^\ast] \to [t_2^\ast]`, for any sequences of :ref:`value types ` :math:`t_1^\ast` and :math:`t_2^\ast`. +* The instruction is valid with type :math:`[t_1^\ast~\EXNREF] \to [t_2^\ast]`, for any sequences of :ref:`value types ` :math:`t_1^\ast` and :math:`t_2^\ast`. .. math:: \frac{ - C.\CLABELS[l] = \LCATCH~[t^\ast] }{ - C \vdashinstr \RETHROW~l : [t_1^\ast] \to [t_2^\ast] + C \vdashinstr \THROWREF : [t_1^\ast~\EXNREF] \to [t_2^\ast] } .. note:: - The |RETHROW| instruction is :ref:`stack-polymorphic `. + The |THROWREF| instruction is :ref:`stack-polymorphic `. @@ -1500,13 +1530,13 @@ Control Instructions * The label :math:`C.\CLABELS[l]` must be defined in the context. -* Let :math:`\LCATCH^?~[t^\ast]` be the :ref:`label type ` :math:`C.\CLABELS[l]`. +* Let :math:`[t^\ast]` be the :ref:`result type ` :math:`C.\CLABELS[l]`. * Then the instruction is valid with type :math:`[t_1^\ast~t^\ast] \to [t_2^\ast]`, for any sequences of :ref:`operand types ` :math:`t_1^\ast` and :math:`t_2^\ast`. .. math:: \frac{ - C.\CLABELS[l] = \LCATCH^?~[t^\ast] + C.\CLABELS[l] = [t^\ast] }{ C \vdashinstr \BR~l : [t_1^\ast~t^\ast] \to [t_2^\ast] } @@ -1524,13 +1554,13 @@ Control Instructions * The label :math:`C.\CLABELS[l]` must be defined in the context. -* Let :math:`\LCATCH^?~[t^\ast]` be the :ref:`label type ` :math:`C.\CLABELS[l]`. +* Let :math:`[t^\ast]` be the :ref:`result type ` :math:`C.\CLABELS[l]`. * Then the instruction is valid with type :math:`[t^\ast~\I32] \to [t^\ast]`. .. math:: \frac{ - C.\CLABELS[l] = \LCATCH^?~[t^\ast] + C.\CLABELS[l] = [t^\ast] }{ C \vdashinstr \BRIF~l : [t^\ast~\I32] \to [t^\ast] } diff --git a/document/core/valid/modules.rst b/document/core/valid/modules.rst index 7fcd70681..8404d2fda 100644 --- a/document/core/valid/modules.rst +++ b/document/core/valid/modules.rst @@ -29,7 +29,7 @@ Functions :math:`\func` are classified by :ref:`function types * |CLOCALS| set to the sequence of :ref:`value types ` :math:`t_1^\ast~t^\ast`, concatenating parameters and locals, - * |CLABELS| set to the singular sequence containing only :ref:`label type ` :math:`[t_2^\ast]`. + * |CLABELS| set to the singular sequence containing only :ref:`result type ` :math:`[t_2^\ast]`. * |CRETURN| set to the :ref:`result type ` :math:`[t_2^\ast]`. @@ -181,7 +181,7 @@ Element segments :math:`\elem` are classified by the :ref:`reference type ` with some :ref:`result type ` :math:`[t]`. - * The expression :math:`e_i` must be :ref:`constant `. + * The expression :math:`e_i` must be :ref:`constant `. * The element mode :math:`\elemmode` must be valid with :ref:`reference type ` :math:`t`. diff --git a/document/index.html b/document/index.html index 37eed9762..b23262bd6 100644 --- a/document/index.html +++ b/document/index.html @@ -49,19 +49,42 @@

Embedder specifications

  • JavaScript Embedding: defines JavaScript classes and objects for accessing WebAssembly from within JavaScript, including methods for validation, compilation, instantiation, and classes for representing and manipulating imports and exports as JavaScript objects.

  • Web Embedding: defines extensions to the JavaScript API made available specifically in web browsers, in particular, an interface for streaming compilation and instantiation from origin-bound Response types.

+

Legacy Extensions

+ +

Define extensions that are deprecated, but may still be in use.

+ +
    +
  • Legacy Exception Handling: defines additional instructions for exception handling that may still be available in some engines and tools, specifically web browsers.

    + +
  • +
+ +

Source for these documents is available here. diff --git a/document/js-api/index.bs b/document/js-api/index.bs index 3da64d69f..9586c48ee 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -37,64 +37,12 @@ urlPrefix: https://tc39.github.io/ecma262/; spec: ECMASCRIPT url: sec-returnifabrupt-shorthands text: ! text: ? - text: agent cluster; url: sec-agent-clusters - text: agent; url: agent - text: data block; url: sec-data-blocks - text: Bound Function; url: sec-bound-function-exotic-objects - text: NumericLiteral; url: sec-literals-numeric-literals - text: surrounding agent; url: surrounding-agent - text: ToNumber; url: sec-tonumber - text: ToInt32; url: sec-toint32 - text: ToString; url: sec-tostring - url: sec-ecmascript-data-types-and-values - text: Type - text: Type(x) - url: sec-iscallable - text: IsCallable - text: callable; for: ECMAScript - url: sec-well-known-intrinsic-objects - text: %ErrorPrototype% - text: %ObjectPrototype%; url: sec-properties-of-the-object-prototype-object - text: %Promise%; url: sec-promise-constructor - text: Property Descriptor; url: sec-property-descriptor-specification-type - text: array index; url: sec-array-exotic-objects - text: OrdinaryGetOwnProperty; url: sec-ordinarygetownproperty - text: OrdinaryDefineOwnProperty; url: sec-ordinarydefineownproperty - text: OrdinaryPreventExtensions; url: sec-ordinarypreventextensions - text: OrdinarySet; url: sec-ordinaryset - text: equally close values; url: sec-ecmascript-language-types-number-type - text: internal slot; url: sec-object-internal-methods-and-internal-slots - text: JavaScript execution context stack; url: execution-context-stack - text: running JavaScript execution context; url: running-execution-context - text: GetIterator; url: sec-getiterator - text: IteratorStep; url: sec-iteratorstep - text: NormalCompletion; url: sec-normalcompletion - text: IteratorValue; url: sec-iteratorvalue - url: sec-well-known-symbols - text: @@iterator - text: @@toStringTag - text: CreateDataProperty; url: sec-createdataproperty - text: DetachArrayBuffer; url: sec-detacharraybuffer - text: SetIntegrityLevel; url: sec-setintegritylevel - text: Call; url: sec-call - text: Get; url: sec-get-o-p - text: DefinePropertyOrThrow; url: sec-definepropertyorthrow + text: Type; url: sec-ecmascript-data-types-and-values text: current Realm; url: current-realm - text: ObjectCreate; url: sec-objectcreate - text: CreateBuiltinFunction; url: sec-createbuiltinfunction - text: SetFunctionName; url: sec-setfunctionname - text: SetFunctionLength; url: sec-setfunctionlength - text: the Number value; url: sec-ecmascript-language-types-number-type - text: NumberToRawBytes; url: sec-numbertorawbytes text: Built-in Function Objects; url: sec-built-in-function-objects text: NativeError Object Structure; url: sec-nativeerror-object-structure - text: CreateArrayFromList; url: sec-createarrayfromlist - text: GetMethod; url: sec-getmethod - text: IterableToList; url: sec-iterabletolist - text: ToBigInt64; url: #sec-tobigint64 - text: BigInt; url: #sec-ecmascript-language-types-bigint-type - type: abstract-op - text: CreateMethodProperty; url: sec-createmethodproperty + text: 𝔽; url: #𝔽 + text: ℤ; url: #ℤ urlPrefix: https://webassembly.github.io/exception-handling/core/; spec: WebAssembly; type: dfn url: valid/modules.html#valid-module text: valid @@ -116,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 @@ -153,6 +102,12 @@ 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: tag_alloc; url: appendix/embedding.html#embed-tag-alloc + text: tag_type; url: appendix/embedding.html#embed-tag-type + 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 + text: tag type; url: syntax/types.html#syntax-tagtype url: syntax/types.html#syntax-numtype text: i32 text: i64 @@ -163,7 +118,14 @@ urlPrefix: https://webassembly.github.io/exception-handling/core/; spec: WebAsse url: syntax/types.html#syntax-reftype text: reftype text: funcref + text: exnref text: externref + url: syntax/values.html#syntax-float + text: +∞ + text: −∞ + text: nan + text: canon + text: signif text: function element; url: exec/runtime.html#syntax-funcelem text: import component; url: syntax/modules.html#imports url: exec/runtime.html#syntax-externval @@ -190,6 +152,7 @@ urlPrefix: https://webassembly.github.io/exception-handling/core/; spec: WebAsse text: address; url: exec/runtime.html#addresses text: signed_32; url: exec/numerics.html#aux-signed text: memory.grow; url: exec/instructions.html#exec-memory-grow + text: throw_ref; url: exec/instructions.html#exec-throw-ref text: current frame; url: exec/conventions.html#exec-notation-textual text: module; for: frame; url: exec/runtime.html#syntax-frame text: memaddrs; for: moduleinst; url: exec/runtime.html#syntax-moduleinst @@ -283,6 +246,8 @@ Each [=agent=] is associated with the following [=ordered map=]s: * The Global object cache, mapping [=global address=]es to {{Global}} objects. * The Extern value cache, mapping [=extern address=]es to values. * The Tag object cache, mapping [=tag addresses=] to {{Tag}} objects. + * The Exception object cache, mapping [=exception address=]es to {{Exception}} objects. +

The WebAssembly Namespace

@@ -292,7 +257,7 @@ dictionary WebAssemblyInstantiatedSource { required Instance instance; }; -[Exposed=(Window,Worker,Worklet)] +[Exposed=*] namespace WebAssembly { boolean validate(BufferSource bytes); Promise<Module> compile(BufferSource bytes); @@ -302,6 +267,8 @@ namespace WebAssembly { Promise<Instance> instantiate( Module moduleObject, optional object importObject); + + readonly attribute Tag JSTag; };
@@ -369,11 +336,11 @@ A {{Module}} object represents a single WebAssembly module. Each {{Module}} obje 1. If |module|.[=imports=] [=list/is empty|is not empty=], and |importObject| is undefined, throw a {{TypeError}} exception. 1. Let |imports| be « ». 1. [=list/iterate|For each=] (|moduleName|, |componentName|, |externtype|) of [=module_imports=](|module|), - 1. Let |o| be [=?=] [=Get=](|importObject|, |moduleName|). + 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. Let |v| be [=?=] [$Get$](|o|, |componentName|). 1. If |externtype| is of the form [=func=] |functype|, - 1. If [=IsCallable=](|v|) is false, throw a {{LinkError}} exception. + 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, @@ -423,7 +390,7 @@ The verification of WebAssembly type requirements is deferred to the
To create an exports object from a WebAssembly module |module| and instance |instance|, perform the following steps: - 1. Let |exportsObject| be [=!=] [=ObjectCreate=](null). + 1. Let |exportsObject| be [=!=] [$OrdinaryObjectCreate$](null). 1. [=list/iterate|For each=] (|name|, |externtype|) of [=module_exports=](|module|), 1. Let |externval| be [=instance_export=](|instance|, |name|). 1. Assert: |externval| is not [=error=]. @@ -453,11 +420,11 @@ The verification of WebAssembly type requirements is deferred to the 1. Let [=external value/tag=] |tagaddr| be |externval|. 1. Let |tag| be [=create a Tag object|a new Tag object=] created from |tagaddr|. 1. Let |value| be |tag|. - 1. Let |status| be [=!=] [=CreateDataProperty=](|exportsObject|, |name|, |value|). + 1. Let |status| be [=!=] [$CreateDataProperty$](|exportsObject|, |name|, |value|). 1. Assert: |status| is true. Note: the validity and uniqueness checks performed during [=WebAssembly module validation=] ensure that each property name is valid and no properties are defined twice. - 1. Perform [=!=] [=SetIntegrityLevel=](|exportsObject|, `"frozen"`). + 1. Perform [=!=] [$SetIntegrityLevel$](|exportsObject|, `"frozen"`). 1. Return |exportsObject|.
@@ -488,18 +455,20 @@ The verification of WebAssembly type requirements is deferred to the 1. Let |module| be |moduleObject|.\[[Module]]. 1. [=Read the imports=] of |module| with imports |importObject|, and let |imports| be the result. If this operation throws an exception, catch it, [=reject=] |promise| with the exception, and return |promise|. - 1. [=Queue a task=] to perform the following steps: - 1. [=Instantiate the core of a WebAssembly module=] |module| with |imports|, and let |instance| be the result. - If this throws an exception, catch it, [=reject=] |promise| with the exception, and terminate these substeps. - 1. Let |instanceObject| be a [=/new=] {{Instance}}. - 1. [=initialize an instance object|Initialize=] |instanceObject| from |module| and |instance|. - If this throws an exception, catch it, [=reject=] |promise| with the exception, and terminate these substeps. - 1. [=Resolve=] |promise| with |instanceObject|. + 1. Run the following steps [=in parallel=]: + 1. [=Queue a task=] to perform the following steps: + Note: Implementation-specific work may be performed here. + 1. [=Instantiate the core of a WebAssembly module=] |module| with |imports|, and let |instance| be the result. + If this throws an exception, catch it, [=reject=] |promise| with the exception, and terminate these substeps. + 1. Let |instanceObject| be a [=/new=] {{Instance}}. + 1. [=initialize an instance object|Initialize=] |instanceObject| from |module| and |instance|. + If this throws an exception, catch it, [=reject=] |promise| with the exception, and terminate these substeps. + 1. [=Resolve=] |promise| with |instanceObject|. 1. Return |promise|.
- To instantiate a WebAssembly module from a {{Module}} |moduleObject| and imports |importObject|, perform the following steps: + To synchronously instantiate a WebAssembly module from a {{Module}} |moduleObject| and imports |importObject|, perform the following steps: 1. Let |module| be |moduleObject|.\[[Module]]. 1. [=Read the imports=] of |module| with imports |importObject|, and let |imports| be the result. 1. [=Instantiate the core of a WebAssembly module=] |module| with |imports|, and let |instance| be the result. @@ -513,14 +482,15 @@ The verification of WebAssembly type requirements is deferred to the 1. Let |promise| be [=a new promise=]. 1. [=Upon fulfillment=] of |promiseOfModule| with value |module|: - 1. [=instantiate a WebAssembly module|Instantiate the WebAssembly module=] |module| importing |importObject|, and let |instance| be the result. If this throws an exception, catch it, [=reject=] |promise| with the exception, and abort these substeps. - 1. Let |result| be the {{WebAssemblyInstantiatedSource}} value «[ "{{WebAssemblyInstantiatedSource/module}}" → |module|, "{{WebAssemblyInstantiatedSource/instance}}" → |instance| ]». - 1. [=Resolve=] |promise| with |result|. + 1. [=asynchronously instantiate a WebAssembly module|Instantiate the WebAssembly module=] |module| importing |importObject|, and let |innerPromise| be the result. + 1. [=Upon fulfillment=] of |innerPromise| with value |instance|. + 1. Let |result| be the {{WebAssemblyInstantiatedSource}} value «[ "{{WebAssemblyInstantiatedSource/module}}" → |module|, "{{WebAssemblyInstantiatedSource/instance}}" → |instance| ]». + 1. [=Resolve=] |promise| with |result|. + 1. [=Upon rejection=] of |innerPromise| with reason |reason|: + 1. [=Reject=] |promise| with |reason|. 1. [=Upon rejection=] of |promiseOfModule| with reason |reason|: 1. [=Reject=] |promise| with |reason|. 1. Return |promise|. - - Note: It would be valid to perform certain parts of the instantiation [=in parallel=], but several parts need to happen in the event loop, including JavaScript operations to access the |importObject| and execution of the start function.
@@ -537,6 +507,11 @@ The verification of WebAssembly type requirements is deferred to the Note: A follow-on streaming API is documented in the WebAssembly Web API. +The getter of the JSTag attribute of the {{WebAssembly}} Namespace, when invoked, performs the following steps: + 1. Let |JSTagAddr| be the result of [=get the JavaScript exception tag|getting the JavaScript exception tag=]. + 1. Let |JSTagObject| be the result of [=create a Tag object|creating a Tag object=] from |JSTagAddr|. + 1. Return |JSTagObject|. +

Modules

@@ -560,7 +535,7 @@ dictionary ModuleImportDescriptor {
   required ImportExportKind kind;
 };
 
-[LegacyNamespace=WebAssembly, Exposed=(Window,Worker,Worklet)]
+[LegacyNamespace=WebAssembly, Exposed=*]
 interface Module {
   constructor(BufferSource bytes);
   static sequence<ModuleExportDescriptor> exports(Module moduleObject);
@@ -620,12 +595,14 @@ interface Module {
     1. If |module| is [=error=], throw a {{CompileError}} exception.
     1. Set **this**.\[[Module]] to |module|.
     1. Set **this**.\[[Bytes]] to |stableBytes|.
+
+Note: Some implementations enforce a size limitation on |bytes|. Use of this API is discouraged, in favor of asynchronous APIs.
 

Instances

-[LegacyNamespace=WebAssembly, Exposed=(Window,Worker,Worklet)]
+[LegacyNamespace=WebAssembly, Exposed=*]
 interface Instance {
   constructor(Module module, optional object importObject);
   readonly attribute object exports;
@@ -638,6 +615,8 @@ interface Instance {
     1. [=Read the imports=] of |module| with imports |importObject|, and let |imports| be the result.
     1. [=Instantiate the core of a WebAssembly module=] |module| with |imports|, and let |instance| be the result.
     1. [=initialize an instance object|Initialize=] **this** from |module| and |instance|.
+
+Note: The use of this synchronous API is discouraged, as some implementations sometimes do long-running compilation work when instantiating.
 
 
 
@@ -652,7 +631,7 @@ dictionary MemoryDescriptor { [EnforceRange] unsigned long maximum; }; -[LegacyNamespace=WebAssembly, Exposed=(Window,Worker,Worklet)] +[LegacyNamespace=WebAssembly, Exposed=*] interface Memory { constructor(MemoryDescriptor descriptor); unsigned long grow([EnforceRange] unsigned long delta); @@ -715,7 +694,7 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each 1. Let |map| be the [=surrounding agent=]'s associated [=Memory object cache=]. 1. Assert: |map|[|memaddr|] [=map/exists=]. 1. Let |memory| be |map|[|memaddr|]. - 1. Perform [=!=] [=DetachArrayBuffer=](|memory|.\[[BufferObject]], "WebAssembly.Memory"). + 1. Perform [=!=] [$DetachArrayBuffer$](|memory|.\[[BufferObject]], "WebAssembly.Memory"). 1. Let |buffer| be the result of [=create a memory buffer|creating a memory buffer=] from |memaddr|. 1. Set |memory|.\[[BufferObject]] to |buffer|.
@@ -762,7 +741,7 @@ dictionary TableDescriptor { [EnforceRange] unsigned long maximum; }; -[LegacyNamespace=WebAssembly, Exposed=(Window,Worker,Worklet)] +[LegacyNamespace=WebAssembly, Exposed=*] interface Table { constructor(TableDescriptor descriptor, optional any value); unsigned long grow([EnforceRange] unsigned long delta, optional any value); @@ -798,7 +777,7 @@ Each {{Table}} object has a \[[Table]] internal slot, which is a [=table address The Table(|descriptor|, |value|) 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. 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| < |initial|, throw a {{RangeError}} exception. @@ -843,6 +822,9 @@ Each {{Table}} object has a \[[Table]] internal slot, which is a [=table address The get(|index|) method, when invoked, performs the following steps: 1. Let |tableaddr| be **this**.\[[Table]]. 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. + 1. Let (limits, |elementType|) be [=table_type=](|store|, |tableaddr|). + 1. If |elementType| is [=exnref=], + 1. Throw a {{TypeError}} exception. 1. Let |result| be [=table_read=](|store|, |tableaddr|, |index|). 1. If |result| is [=error=], throw a {{RangeError}} exception. 1. Return [=ToJSValue=](|result|). @@ -851,12 +833,14 @@ Each {{Table}} object has a \[[Table]] internal slot, which is a [=table address
The set(|index|, |value|) method, when invoked, performs the following steps: 1. Let |tableaddr| be **this**.\[[Table]]. - 1. Let (limits, |elementType|) be [=table_type=](|tableaddr|). + 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. + 1. Let (limits, |elementType|) be [=table_type=](|store|, |tableaddr|). + 1. If |elementType| is [=exnref=], + 1. Throw a {{TypeError}} exception. 1. If |value| is missing, 1. Let |ref| be [=DefaultValue=](|elementType|). 1. Otherwise, 1. Let |ref| be [=?=] [=ToWebAssemblyValue=](|value|, |elementType|). - 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. 1. Let |store| be [=table_write=](|store|, |tableaddr|, |index|, |ref|). 1. If |store| is [=error=], throw a {{RangeError}} exception. 1. Set the [=surrounding agent=]'s [=associated store=] to |store|. @@ -884,7 +868,7 @@ dictionary GlobalDescriptor { boolean mutable = false; }; -[LegacyNamespace=WebAssembly, Exposed=(Window,Worker,Worklet)] +[LegacyNamespace=WebAssembly, Exposed=*] interface Global { constructor(GlobalDescriptor descriptor, optional any v); any valueOf(); @@ -943,7 +927,7 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each The Global(|descriptor|, |v|) constructor, when invoked, performs the following steps: 1. Let |mutable| be |descriptor|["mutable"]. 1. Let |valuetype| be [=ToValueType=](|descriptor|["value"]). - 1. If |valuetype| is [=v128=], + 1. If |valuetype| is [=v128=] or [=exnref=], 1. Throw a {{TypeError}} exception. 1. If |v| is missing, 1. Let |value| be [=DefaultValue=](|valuetype|). @@ -961,7 +945,7 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each 1. Let |store| be the current agent's [=associated store=]. 1. Let |globaladdr| be |global|.\[[Global]]. 1. Let |globaltype| be [=global_type=](|store|, |globaladdr|). - 1. If |globaltype| is of the form mut [=v128=], throw a {{TypeError}}. + 1. If |globaltype| is of the form mut |valuetype| where |valuetype| is [=v128=] or [=exnref=], throw a {{TypeError}}. 1. Let |value| be [=global_read=](|store|, |globaladdr|). 1. Return [=ToJSValue=](|value|).
@@ -974,7 +958,7 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each 1. Let |store| be the current agent's [=associated store=]. 1. Let |globaladdr| be **this**.\[[Global]]. 1. Let |mut| |valuetype| be [=global_type=](|store|, |globaladdr|). - 1. If |valuetype| is [=v128=], throw a {{TypeError}}. + 1. If |valuetype| is [=v128=] or [=exnref=], throw a {{TypeError}}. 1. If |mut| is [=const=], throw a {{TypeError}}. 1. Let |value| be [=ToWebAssemblyValue=](**the given value**, |valuetype|). 1. Let |store| be [=global_write=](|store|, |globaladdr|, |value|). @@ -999,13 +983,13 @@ This slot holds a [=function address=] relative to the [=surrounding agent=]'s [ 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. 1. Let |funcinst| be |store|.funcs[|funcaddr|]. 1. If |funcinst| is of the form {type functype, hostcode |hostfunc|}, - 1. Assert: |hostfunc| is a JavaScript object and [=IsCallable=](|hostfunc|) is true. + 1. Assert: |hostfunc| is a JavaScript object and [$IsCallable$](|hostfunc|) is true. 1. Let |index| be the [=index of the host function=] |funcaddr|. 1. Otherwise, 1. Let |moduleinst| be |funcinst|.module. 1. Assert: |funcaddr| is contained in |moduleinst|.funcaddrs. 1. Let |index| be the index of |moduleinst|.funcaddrs where |funcaddr| is found. - 1. Return [=!=] [=ToString=](|index|). + 1. Return [=!=] [$ToString$](|index|).
@@ -1021,7 +1005,7 @@ This slot holds a [=function address=] relative to the [=surrounding agent=]'s [ 1. Let [|paramTypes|] → [resultTypes] be |functype|. 1. Let |arity| be |paramTypes|'s [=list/size=]. 1. Let |name| be the [=name of the WebAssembly function=] |funcaddr|. - 1. Let |function| be [=!=] [=CreateBuiltinFunction=](|steps|, |arity|, |name|, « \[[FunctionAddress]] », |realm|). + 1. Let |function| be [=!=] [$CreateBuiltinFunction$](|steps|, |arity|, |name|, « \[[FunctionAddress]] », |realm|). 1. Set |function|.\[[FunctionAddress]] to |funcaddr|. 1. [=map/Set=] |map|[|funcaddr|] to |function|. 1. Return |function|. @@ -1033,7 +1017,7 @@ This slot holds a [=function address=] relative to the [=surrounding agent=]'s [ 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. 1. Let |functype| be [=func_type=](|store|, |funcaddr|). 1. Let [|parameters|] → [|results|] be |functype|. - 1. If |parameters| or |results| contain [=v128=], throw a {{TypeError}}. + 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 « ». @@ -1044,15 +1028,16 @@ 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|, val* | [=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 the WebAssembly error mapping. - 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. Throw |exception|. + 1. If |ret| is [=THROW=] [=ref.exn=] |exnaddr|, then + 1. Let (|tagaddr|, |payload|) be [=exn_read=](|store|, |exnaddr|). + 1. Let |jsTagAddr| be the result of [=get the JavaScript exception tag |getting the JavaScript exception tag=]. + 1. If |tagaddr| is equal to |jsTagAddr|, + 1. Throw the result of [=retrieving an extern value=] from |payload|[0]. + 1. Otherwise, + 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. 1. Otherwise, if |outArity| is 1, return [=ToJSValue=](|ret|[0]). @@ -1060,7 +1045,7 @@ This slot holds a [=function address=] relative to the [=surrounding agent=]'s [ 1. Let |values| be « ». 1. [=list/iterate|For each=] |r| of |ret|, 1. [=list/Append=] [=ToJSValue=](|r|) to |values|. - 1. Return [=CreateArrayFromList=](|values|). + 1. Return [$CreateArrayFromList$](|values|).
Note: [=call an Exported Function|Calling an Exported Function=] executes in the \[[Realm]] of the callee Exported Function, as per the definition of [=built-in function objects=]. @@ -1071,18 +1056,18 @@ Note: Exported Functions do not have a \[[Construct]] method and thus it is not 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=], throw a {{TypeError}}. + 1. If |parameters| or |results| contain [=v128=] or [=exnref=], 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. Let |ret| be [=?=] [$Call$](|func|, undefined, |jsArguments|). 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]) ». 1. Otherwise, - 1. Let |method| be [=?=] [=GetMethod=](|ret|, [=@@iterator=]). - 1. If |method| is undefined, [=throw=] a {{TypeError}}. - 1. Let |values| be [=?=] [=IterableToList=](|ret|, |method|). + 1. Let |method| be [=?=] [$GetMethod$](|ret|, {{@@iterator}}). + 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. 1. For each |value| and |resultType| in |values| and |results|, paired linearly, @@ -1093,29 +1078,29 @@ Note: Exported Functions do not have a \[[Construct]] method and thus it is not
To create a host function from the JavaScript object |func| and type |functype|, perform the following steps: - 1. Assert: [=IsCallable=](|func|). + 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 |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. [=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 throw, then: 1. Let |v| be |result|.\[[Value]]. 1. If |v| [=implements=] {{Exception}}, - 1. Let |type| be |v|.\[[Type]]. - 1. Let |payload| be |v|.\[[Payload]]. + 1. Let |address| be |v|.\[[Address]]. 1. Otherwise, - 1. Let |type| be the [=JavaScript exception tag=]. - 1. Let |payload| be « ». - 1. Let |opaqueData| be [=ToWebAssemblyValue=](|v|, [=externref=]) - 1. [=WebAssembly/Throw=] with |type|, |payload| and |opaqueData|. + 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. 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|. @@ -1125,17 +1110,24 @@ Note: Exported Functions do not have a \[[Construct]] method and thus it is not The algorithm ToJSValue(|w|) coerces a [=WebAssembly value=] to a JavaScript value by performing the following steps: 1. Assert: |w| is not of the form [=v128.const=] v128. +1. Assert: |w| is not of the form [=ref.exn=] exnaddr. 1. If |w| is of the form [=i64.const=] |i64|, 1. Let |v| be [=signed_64=](|i64|). - 1. Return a [=BigInt=] representing the mathematical value |v|. -1. If |w| is of the form [=i32.const=] |i32|, return [=the Number value=] for [=signed_32=](|i32|). -1. If |w| is of the form [=f32.const=] |f32|, return [=the Number value=] for |f32|. -1. If |w| is of the form [=f64.const=] |f64|, return [=the Number value=] for |f64|. + 1. Return [=ℤ=](|v| interpreted as a mathematical value). +1. If |w| is of the form [=i32.const=] |i32|, return [=𝔽=]([=signed_32=](|i32| interpreted as a mathematical value)). +1. If |w| is of the form [=f32.const=] |f32|, + 1. If |f32| is [=+∞=] or [=−∞=], return **+∞**𝔽 or **-∞**𝔽, respectively. + 1. If |f32| is [=nan=], return **NaN**. + 1. Return [=𝔽=](|f32| interpreted as a mathematical value). +1. If |w| is of the form [=f64.const=] |f64|, + 1. If |f64| is [=+∞=] or [=−∞=], return **+∞**𝔽 or **-∞**𝔽, respectively. + 1. If |f64| is [=nan=], return **NaN**. + 1. Return [=𝔽=](|f64| interpreted as a mathematical value). 1. If |w| is of the form [=ref.null=] t, return null. 1. If |w| is of the form [=ref.func=] |funcaddr|, return the result of creating [=a new Exported Function=] from |funcaddr|. 1. If |w| is of the form [=ref.extern=] |externaddr|, return the result of [=retrieving an extern value=] from |externaddr|. -Note: Number values which are equal to NaN may have various observable NaN payloads; see [=NumberToRawBytes=] for details. +Note: Number values which are equal to NaN may have various observable NaN payloads; see [$NumericToRawBytes$] for details.
@@ -1152,17 +1144,28 @@ For retrieving an extern value from an [=extern address=] |externaddr The algorithm ToWebAssemblyValue(|v|, |type|) coerces a JavaScript value to a [=WebAssembly value=] by performing the following steps: 1. Assert: |type| is not [=v128=]. +1. Assert: |type| is not [=exnref=]. 1. If |type| is [=i64=], - 1. Let |i64| be [=?=] [=ToBigInt64=](|v|). + 1. Let |i64| be [=?=] [$ToBigInt64$](|v|). 1. Return [=i64.const=] |i64|. 1. If |type| is [=i32=], - 1. Let |i32| be [=?=] [=ToInt32=](|v|). + 1. Let |i32| be [=?=] [$ToInt32$](|v|). 1. Return [=i32.const=] |i32|. 1. If |type| is [=f32=], - 1. Let |f32| be [=?=] [=ToNumber=](|v|) rounded to the nearest representable value using IEEE 754-2008 round to nearest, ties to even mode. + 1. Let |number| be [=?=] [$ToNumber$](|v|). + 1. If |number| is **NaN**, + 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. Return [=f32.const=] |f32|. 1. If |type| is [=f64=], - 1. Let |f64| be [=?=] [=ToNumber=](|v|). + 1. Let |number| be [=?=] [$ToNumber$](|v|). + 1. If |number| is **NaN**, + 1. Let |n| be an implementation-defined integer such that [=canon=]64 ≤ |n| < 2[=signif=](64). + 1. Let |f64| be [=nan=](n). + 1. Otherwise, + 1. Let |f64| be |number|. 1. Return [=f64.const=] |f64|. 1. If |type| is [=funcref=], 1. If |v| is null, @@ -1184,11 +1187,7 @@ The algorithm ToWebAssemblyValue(|v|, |type|) coerces a JavaScript va
-

Tags

- -The tag_alloc(|store|, |parameters|) algorithm creates a new [=tag address=] for |parameters| in |store| and returns the updated store and the [=tag address=]. - -The tag_parameters(|store|, |tagAddress|) algorithm returns the [=list=] of types for |tagAddress| in |store|. +

Exceptions

Exception types

@@ -1200,7 +1199,6 @@ dictionary TagType { [LegacyNamespace=WebAssembly, Exposed=(Window,Worker,Worklet)] interface Tag { constructor(TagType type); - TagType type(); };
@@ -1245,21 +1243,6 @@ The new Tag(|type|) constructor -
- -The type() method steps are: - -1. Let |store| be the [=surrounding agent=]'s [=associated store=]. -1. Let |parameters| be [=tag_parameters=](|store|, **this**.\[[Address]]). -1. Let |idlParameters| be «». -1. [=list/iterate|For each=] |type| of |parameters|, - 1. [=list/Append=] [$FromValueType$](|type|) to |idlParameters|. -1. Return «[ "{{TagType/parameters}}" → |idlParameters| ]». - -Advisement: This method is only expected to be implemented or shipped when both this proposal and the Type Reflection proposal are implemented or shipped (respectively). - -
-

Runtime exceptions

@@ -1270,7 +1253,7 @@ dictionary ExceptionOptions {
 [LegacyNamespace=WebAssembly, Exposed=(Window,Worker,Worklet)]
 interface Exception {
   constructor(Tag exceptionTag, sequence<any> payload, optional ExceptionOptions options = {});
-  any getArg(Tag exceptionTag, unsigned long index);
+  any getArg([EnforceRange] unsigned long index);
   boolean is(Tag exceptionTag);
   readonly attribute (DOMString or undefined) stack;
 };
@@ -1280,19 +1263,31 @@ An {{Exception}} value represents an exception.
 
 
-To create an Exception object from a [=tag address=] |tagAddress| and a [=list=] of -WebAssembly values |payload|, perform the following steps: +To initialize an Exception object |exn| from an [=Exception address=] |exnAddress|, 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. + +
+ +
+ +To create an Exception object 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|. +
@@ -1302,31 +1297,39 @@ The new Exception(|exceptionTag|, |payload|, |options|) constructor steps are: +1. Let |JSTagAddr| be the result of [=get the JavaScript exception tag|getting the JavaScript exception tag=]. +1. If |exceptionTag|.\[[Address]] is equal to |JSTagAddr|, + 1. Throw a {{TypeError}}. 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. -1. Let |types| be [=tag_parameters=](|store|, |exceptionTag|.\[[Address]]). +1. Let [|types|] → [] be [=tag_type=](|store|, |exceptionTag|.\[[Address]]). 1. If |types|'s [=list/size=] is not |payload|'s [=list/size=], 1. Throw a {{TypeError}}. 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|. -1. Set **this**.\[[Type]] to |exceptionTag|.\[[Address]]. -1. Set **this**.\[[Payload]] to |wasmPayload|. + 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. Set the [=surrounding agent=]'s [=associated store=] to |store|. +1. [=initialize an Exception object|Initialize=] **this** from |exceptionAddr|. 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. +
-The getArg(|exceptionTag|, |index|) method steps are: +The getArg(|index|) method steps are: -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. Let [|types|] → [] be [=tag_type=](|store|, |tagaddr|). +1. If |types|[|index|] is [=v128=] or [=exnref=], + 1. Throw a {{TypeError}}. 1. Return [=ToJSValue=](|payload|[|index|]).
@@ -1351,20 +1354,22 @@ The stack getter steps are:

JavaScript exceptions

-The JavaScript exception tag is a [=tag address=] reserved by this -specification to distinguish exceptions originating from JavaScript. +The JavaScript exception tag is a [=tag address=] associated with +the surrounding agent. It is allocated in the agent's [=associated store=] on +first use and cached. It always has the [=tag type=] « [=externref=] » → « ». -For any [=associated store=] |store|, the result of -[=tag_parameters=](|store|, [=JavaScript exception tag=]) must be « ».
-To throw with a [=tag address=] |type|, a matching [=list=] of WebAssembly values |payload|, and an [=externref=] |opaqueData|, perform the following steps: +To get the JavaScript exception tag, perform the following steps: -1. Unwind the stack until reaching the *catching try block* given |type|. -1. Invoke the catch block with |payload| and |opaqueData|. - -Note: This algorithm is expected to be moved into the core specification. + 1. If the [=surrounding agent=]'s associated [=JavaScript exception tag=] has been initialized, + 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|. + 1. Set the current agent's associated [=JavaScript exception tag=] to |tagAddress|. + 1. return |tagAddress|.
@@ -1438,32 +1443,32 @@ An implementation must reject a module that exceeds one of the following limits In practice, an implementation may run out of resources for valid modules below these limits.
    -
  • The maximum size of a module is 1073741824 bytes (1 GiB).
  • -
  • The maximum number of types defined in the types section is 1000000.
  • -
  • The maximum number of functions defined in a module is 1000000.
  • -
  • The maximum number of imports declared in a module is 100000.
  • -
  • The maximum number of exports declared in a module is 100000.
  • -
  • The maximum number of globals defined in a module is 1000000.
  • -
  • The maximum number of tags defined in a module is 1000000.
  • -
  • The maximum number of data segments defined in a module is 100000.
  • - -
  • The maximum number of tables, including declared or imported tables, is 100000.
  • -
  • The maximum size of a table is 10000000.
  • -
  • The maximum number of table entries in any table initialization is 10000000.
  • +
  • The maximum size of a module is 1,073,741,824 bytes (1 GiB).
  • +
  • The maximum number of types defined in the types section is 1,000,000.
  • +
  • The maximum number of functions defined in a module is 1,000,000.
  • +
  • The maximum number of imports declared in a module is 100,000.
  • +
  • The maximum number of exports declared in a module is 100,000.
  • +
  • The maximum number of globals defined in a module is 1,000,000.
  • +
  • The maximum number of tags defined in a module is 1,000,000.
  • +
  • The maximum number of data segments defined in a module is 100,000.
  • + +
  • The maximum number of tables, including declared or imported tables, is 100,000.
  • +
  • The maximum size of a table is 10,000,000.
  • +
  • The maximum number of table entries in any table initialization is 10,000,000.
  • The maximum number of memories, including declared or imported memories, is 1.
  • -
  • The maximum number of parameters to any function or block is 1000.
  • -
  • The maximum number of return values for any function or block is 1000.
  • -
  • The maximum size of a function body, including locals declarations, is 7654321 bytes.
  • -
  • The maximum number of locals declared in a function, including implicitly declared as parameters, is 50000.
  • +
  • The maximum number of parameters to any function or block is 1,000.
  • +
  • The maximum number of return values for any function or block is 1,000.
  • +
  • The maximum size of a function body, including locals declarations, is 7,654,321 bytes.
  • +
  • The maximum number of locals declared in a function, including implicitly declared as parameters, is 50,000.
An implementation must throw a {{RuntimeError}} if one of the following limits is exceeded during runtime: In practice, an implementation may run out of resources for valid modules below these limits.
    -
  • The maximum size of a table is 10000000.
  • -
  • The maximum number of pages of a memory is 65536.
  • +
  • The maximum size of a table is 10,000,000.
  • +
  • The maximum number of pages of a memory is 65,536.

Security and Privacy Considerations

diff --git a/document/legacy/exceptions/.gitignore b/document/legacy/exceptions/.gitignore new file mode 100644 index 000000000..b932ec283 --- /dev/null +++ b/document/legacy/exceptions/.gitignore @@ -0,0 +1,3 @@ +_build +_static +document/*.pyc diff --git a/document/legacy/exceptions/core/LICENSE b/document/legacy/exceptions/core/LICENSE new file mode 100644 index 000000000..795b406e4 --- /dev/null +++ b/document/legacy/exceptions/core/LICENSE @@ -0,0 +1,50 @@ +W3C SOFTWARE AND DOCUMENT NOTICE AND LICENSE + +This work is being provided by the copyright holders under the following +license. + + +LICENSE + +By obtaining and/or copying this work, you (the licensee) agree that you have +read, understood, and will comply with the following terms and conditions. + +Permission to copy, modify, and distribute this work, with or without +modification, for any purpose and without fee or royalty is hereby granted, +provided that you include the following on ALL copies of the work or portions +thereof, including modifications: + +* The full text of this NOTICE in a location viewable to users of the + redistributed or derivative work. + +* Any pre-existing intellectual property disclaimers, notices, or terms and + conditions. If none exist, the W3C Software and Document Short Notice + (https://www.w3.org/Consortium/Legal/copyright-software-short-notice) should + be included. + +* Notice of any changes or modifications, through a copyright statement on the + new code or document such as "This software or document includes material + copied from or derived from [title and URI of the W3C document]. Copyright © [YEAR] W3C® (MIT, ERCIM, Keio, Beihang)." + + +DISCLAIMERS + +THIS WORK IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS +OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, WARRANTIES OF +MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE +SOFTWARE OR DOCUMENT WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, +TRADEMARKS OR OTHER RIGHTS. + +COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENT. + +The name and trademarks of copyright holders may NOT be used in advertising or +publicity pertaining to the work without specific, written prior permission. +Title to copyright in this work will at all times remain with copyright +holders. + + +NOTES + +This version: +http://www.w3.org/Consortium/Legal/2015/copyright-software-and-document diff --git a/document/legacy/exceptions/core/Makefile b/document/legacy/exceptions/core/Makefile new file mode 100644 index 000000000..eb2611acd --- /dev/null +++ b/document/legacy/exceptions/core/Makefile @@ -0,0 +1,358 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = a4 +BUILDDIR = _build +STATICDIR = _static +DOWNLOADDIR = _download +NAME = WebAssembly-Legacy-Exceptions + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: usage +usage: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " pdf to make standalone PDF file" + @echo " bikeshed to make a bikeshed wrapped single large HTML file" + @echo " diff to make a diff of the bikeshed HTML file with the latest TR" + @echo " WD-tar generate tar file for updating the Working Draft" + @echo " WD-echidna publish the Working Draft tar file via Echidna" + @echo " all to make all 3" + @echo " publish to make all and push to gh-pages" + @echo " help to see more options" + +.PHONY: help +help: + @echo "Usage: \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " pdf to make standalone PDF file" + @echo " bikeshed to make a bikeshed wrapped single large HTML file" + @echo " all to make all 3" + @echo " publish to make all and push to gh-pages" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " applehelp to make an Apple Help Book" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " epub3 to make an epub3" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + @echo " coverage to run coverage check of the documentation (if enabled)" + @echo " dummy to check syntax errors of document sources" + +.PHONY: deploy +deploy: + (cd ../..; make dir-core deploy-core) + +.PHONY: publish +publish: clean all deploy + +.PHONY: publish-main +publish-main: clean main bikeshed-keep deploy + +.PHONY: all +all: pdf html bikeshed + +.PHONY: main +main: pdf html + +# Dirty hack to avoid rebuilding the Bikeshed version for every push. +.PHONY: bikeshed-keep +bikeshed-keep: + test -e $(BUILDDIR)/html/bikeshed || \ + wget -r -nH --cut-dirs=2 -P $(BUILDDIR)/html --no-check-certificate \ + https://webassembly.github.io/spec/core/bikeshed || \ + echo Downloaded Bikeshed. + + +GENERATED = appendix/index-instructions.rst +.INTERMEDIATE: $(GENERATED) + +%.rst: %.py + (cd `dirname $@`; ./`basename $^`) + +.PHONY: pdf +pdf: $(GENERATED) latexpdf + mkdir -p $(BUILDDIR)/html/$(DOWNLOADDIR) + ln -f $(BUILDDIR)/latex/$(NAME).pdf $(BUILDDIR)/html/$(DOWNLOADDIR)/$(NAME).pdf + + +.PHONY: clean +clean: + rm -rf $(BUILDDIR) + rm -rf $(STATICDIR) + rm -f $(GENERATED) + +.PHONY: html +html: $(GENERATED) + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + for file in `ls $(BUILDDIR)/html/*.html`; \ + do \ + sed s:BASEDIR:.:g <$$file >$$file.out; \ + mv -f $$file.out $$file; \ + done + for file in `ls $(BUILDDIR)/html/*/*.html`; \ + do \ + sed s:BASEDIR:..:g <$$file >$$file.out; \ + mv -f $$file.out $$file; \ + done + @echo + @echo "Build finished. The HTML pages are in `pwd`/$(BUILDDIR)/html/." + +.PHONY: dirhtml +dirhtml: $(GENERATED) + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +.PHONY: singlehtml +singlehtml: $(GENERATED) + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +.PHONY: bikeshed +bikeshed: $(GENERATED) + $(SPHINXBUILD) -b singlehtml -c util/bikeshed \ + $(ALLSPHINXOPTS) $(BUILDDIR)/bikeshed_singlehtml + python3 util/bikeshed_fixup.py $(BUILDDIR)/bikeshed_singlehtml/index.html \ + >$(BUILDDIR)/bikeshed_singlehtml/index_fixed.html + @echo ==== Showing contents of _build/bikeshed_singlehtml/index_fixed.html ==== + @head -n10 _build/bikeshed_singlehtml/index_fixed.html + @echo ... skipping $$(expr `cat _build/bikeshed_singlehtml/index_fixed.html | wc -l` - 20) lines ... + @tail -n10 _build/bikeshed_singlehtml/index_fixed.html + @echo + @echo ========================================================================= + mkdir -p $(BUILDDIR)/bikeshed_mathjax/ + bikeshed spec index.bs $(BUILDDIR)/bikeshed_mathjax/index.html + mkdir -p $(BUILDDIR)/html/bikeshed/ + (cd util/katex/ && yarn && yarn build && npm install --only=prod) + python3 util/mathjax2katex.py $(BUILDDIR)/bikeshed_mathjax/index.html \ + >$(BUILDDIR)/html/bikeshed/index.html + mkdir -p $(BUILDDIR)/html/bikeshed/katex/dist/ + cp -r util/katex/dist/* $(BUILDDIR)/html/bikeshed/katex/dist/ + patch -p0 $(BUILDDIR)/html/bikeshed/katex/dist/katex.css \ + < util/katex_fix.patch + cp $(BUILDDIR)/bikeshed_singlehtml/_static/pygments.css \ + $(BUILDDIR)/html/bikeshed/ + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/html/bikeshed/." + +.PHONY: WD-tar +WD-tar: bikeshed + @echo "Building tar file..." + tar cvf \ + $(BUILDDIR)/WD.tar \ + --transform='s|$(BUILDDIR)/html/bikeshed/||' \ + --transform='s|index.html|Overview.html|' \ + $(BUILDDIR)/html/bikeshed/index.html \ + $(BUILDDIR)/html/bikeshed/pygments.css \ + $(BUILDDIR)/html/bikeshed/katex/dist/katex.css \ + $(BUILDDIR)/html/bikeshed/katex/dist/fonts + @echo "Built $(BUILDDIR)/WD.tar." + +.PHONY: WD-echidna +WD-echidna: WD-tar + @if [ -z $(W3C_USERNAME) ] || \ + [ -z $(W3C_PASSWORD) ] || \ + [ -z $(DECISION_URL) ] ; then \ + echo "Must provide W3C_USERNAME, W3C_PASSWORD, and DECISION_URL environment variables"; \ + exit 1; \ + fi + curl 'https://labs.w3.org/echidna/api/request' \ + --user '$(W3C_USERNAME):$(W3C_PASSWORD)' \ + -F "tar=@$(BUILDDIR)/WD.tar" \ + -F "decision=$(DECISION_URL)" | tee $(BUILDDIR)/WD-echidna-id.txt + @echo + @echo "Published working draft. Check its status at https://labs.w3.org/echidna/api/status?id=`cat $(BUILDDIR)/WD-echidna-id.txt`" + +.PHONY: diff +diff: bikeshed + @echo "Downloading the old single-file html spec..." + curl `grep "^TR" index.bs | cut -d' ' -f2` -o $(BUILDDIR)/html/bikeshed/old.html + @echo "Done." + @echo "Diffing new against old (go get a coffee)..." + perl ../util/htmldiff.pl $(BUILDDIR)/html/bikeshed/old.html $(BUILDDIR)/html/bikeshed/index.html $(BUILDDIR)/html/bikeshed/diff.html + @echo "Done. The diff is at $(BUILDDIR)/html/bikeshed/diff.html" + +.PHONY: pickle +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +.PHONY: json +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +.PHONY: htmlhelp +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +.PHONY: qthelp +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/WebAssembly.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/WebAssembly.qhc" + +.PHONY: applehelp +applehelp: + $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp + @echo + @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." + @echo "N.B. You won't be able to view it unless you put it in" \ + "~/Library/Documentation/Help or install it in your application" \ + "bundle." + +.PHONY: devhelp +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/WebAssembly" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/WebAssembly" + @echo "# devhelp" + +.PHONY: epub +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +.PHONY: epub3 +epub3: + $(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3 + @echo + @echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3." + +.PHONY: latex +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +.PHONY: latexpdf +latexpdf: $(GENERATED) + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex LATEXMKOPTS=" $(BUILDDIR)/latex/LOG 2>&1 || cat $(BUILDDIR)/latex/LOG + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +.PHONY: latexpdfja +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +.PHONY: text +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +.PHONY: man +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +.PHONY: texinfo +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +.PHONY: info +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +.PHONY: gettext +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +.PHONY: changes +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +.PHONY: linkcheck +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +.PHONY: doctest +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +.PHONY: coverage +coverage: + $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage + @echo "Testing of coverage in the sources finished, look at the " \ + "results in $(BUILDDIR)/coverage/python.txt." + +.PHONY: xml +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +.PHONY: pseudoxml +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." + +.PHONY: dummy +dummy: + $(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy + @echo + @echo "Build finished. Dummy builder generates no files." diff --git a/document/legacy/exceptions/core/README.md b/document/legacy/exceptions/core/README.md new file mode 100644 index 000000000..06d075235 --- /dev/null +++ b/document/legacy/exceptions/core/README.md @@ -0,0 +1,25 @@ +# WebAssembly Core Specification Addendum: Legacy Exception Handling + +This is the official WebAssembly "language" specification. + +It uses [Sphinx](http://www.sphinx-doc.org/). To install that: +``` +pip install sphinx +``` +To make HTML (result in `_build/html`): +``` +make html +``` +To make PDF (result in `_build/latex`, requires LaTeX): +``` +make pdf +``` +To make all: +``` +make all +``` +Finally, to make all and update webassembly.github.io/spec with it: +``` +make publish +``` +Please make sure to only use that once a change has approval. diff --git a/document/legacy/exceptions/core/appendix/index-instructions.py b/document/legacy/exceptions/core/appendix/index-instructions.py new file mode 100755 index 000000000..2c8d3407d --- /dev/null +++ b/document/legacy/exceptions/core/appendix/index-instructions.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python3 + +# This script generates the `index-instructions.rst` file. The table in that +# file is particularly annoying to update by hand, since the Restructured Text +# format requires the header and columns to line up properly. This is +# especially tedious when merging changes from the upstream spec, or merging a +# proposal back to the spec when it is standardized. + +import os + +SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) +INDEX_INSTRUCTIONS_RST = os.path.join(SCRIPT_DIR, 'index-instructions.rst') + +HEADER = """\ +.. DO NOT EDIT: This file is auto-generated by the index-instructions.py script. + +.. _appendix: +.. _index-instr: + +Index of Instructions +===================== +""" + +FOOTER = """\ +""" + +COLUMNS = [ + 'Instruction', + 'Binary Opcode', + 'Type', + 'Validation', + 'Execution', +] + + +def MathWrap(s, default=''): + if s is None: + return default + else: + return f':math:`{s}`' + + +def RefWrap(s, kind): + if s is None: + return '' + else: + return f':ref:`{kind} <{s}>`' + + +def Instruction(name, opcode, type=None, validation=None, execution=None, operator=None, validation2=None, execution2=None): + if operator: + execution_str = ', '.join([RefWrap(execution, 'execution'), + RefWrap(operator, 'operator')]) + elif execution2: + execution_str = ', '.join([RefWrap(execution, 'execution'), + RefWrap(execution, 'execution')]) + + else: + execution_str = RefWrap(execution, 'execution') + + if validation2: + validation_str = ', '.join([RefWrap(validation, 'validation'), + RefWrap(validation2, 'validation')]) + else: + validation_str = RefWrap(validation, 'validation') + + return ( + MathWrap(name, '(reserved)'), + MathWrap(opcode), + MathWrap(type), + validation_str, + execution_str + ) + + +INSTRUCTIONS = [ + Instruction(r'\TRY~\X{bt}', r'\hex{06}', r'[t_1^\ast] \to [t_2^\ast]', r'valid-try-catch', r'exec-try-catch', None, r'valid-try-delegate', r'exec-try-delegate'), + Instruction(r'\CATCH~x', r'\hex{07}', None, r'valid-try-catch', r'exec-try-catch'), + Instruction(r'\RETHROW~n', r'\hex{09}', r'[t_1^\ast] \to [t_2^\ast]', r'valid-rethrow', r'exec-rethrow'), + Instruction(r'\DELEGATE~l', r'\hex{18}', None, r'valid-try-delegate', r'exec-try-delegate'), + Instruction(r'\CATCHALL', r'\hex{19}', None, r'valid-try-catch', r'exec-try-catch'), +] + + +def ColumnWidth(n): + return max([len(instr[n]) for instr in INSTRUCTIONS]) + +COLUMN_WIDTHS = [ColumnWidth(i) for i in range(len(COLUMNS))] +DIVIDER = ' '.join('=' * width for width in COLUMN_WIDTHS) + +def Row(columns): + return ' '.join(('{:%d}' % COLUMN_WIDTHS[i]).format(column) + for i, column in enumerate(columns)) + +if __name__ == '__main__': + with open(INDEX_INSTRUCTIONS_RST, 'w') as f: + print(HEADER, file=f) + print(DIVIDER, file=f) + print(Row(COLUMNS), file=f) + print(DIVIDER, file=f) + + for instr in INSTRUCTIONS: + print(Row(instr), file=f) + + print(DIVIDER, file=f) + print(FOOTER, file=f) diff --git a/document/legacy/exceptions/core/binary.rst b/document/legacy/exceptions/core/binary.rst new file mode 100644 index 000000000..f5c95be2f --- /dev/null +++ b/document/legacy/exceptions/core/binary.rst @@ -0,0 +1,32 @@ +.. _binary: + +Binary Format +============= + +.. _binary-instr: + +Instructions +------------ + +.. _binary-instr-control: + +Control Instructions +~~~~~~~~~~~~~~~~~~~~ + +.. _binary-try: +.. _binary-rethrow: + +.. math:: + \begin{array}{@{}llcllll} + \production{instruction} & \Binstr &::=& \dots \\ &&|& + \hex{06}~~\X{bt}{:}\Bblocktype~~ + (\X{in}_1{:}\Binstr)^\ast~~ \\&&& + (\hex{07}~~x{:}\Btagidx~~(\X{in}_2{:}\Binstr)^\ast)^\ast~~ \\&&& + (\hex{19}~~(\X{in}_3{:}\Binstr)^\ast)^?~~\hex{0B} + &\Rightarrow& \TRY~\X{bt}~\X{in}_1^\ast~(\CATCH~x~\X{in}_2^\ast)^\ast~ + (\CATCHALL~\X{in}_3^\ast)^?\END \\ &&|& + \hex{06}~~\X{bt}{:}\Bblocktype~~(\X{in}{:}\Binstr)^\ast~~ \\&&& + \hex{18}~~l{:}\Blabelidx + &\Rightarrow& \TRY~\X{bt}~\X{in}^\ast~\DELEGATE~l \\ &&|& + \hex{09}~~l{:}\Blabelidx &\Rightarrow& \RETHROW~l \\ + \end{array} diff --git a/document/legacy/exceptions/core/conf.py b/document/legacy/exceptions/core/conf.py new file mode 100644 index 000000000..39b20491d --- /dev/null +++ b/document/legacy/exceptions/core/conf.py @@ -0,0 +1,500 @@ +# -*- coding: utf-8 -*- +# +# WebAssembly documentation build configuration file, created by +# sphinx-quickstart on Mon Nov 21 11:32:49 2016. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +import os +import sys +from datetime import date + +pwd = os.path.abspath('.') +sys.path.insert(0, pwd) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +# +needs_sphinx = '2.3' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.todo', + 'sphinx.ext.coverage', + 'sphinx.ext.mathjax', + 'sphinx.ext.ifconfig', + 'sphinx.ext.githubpages', + 'util.mathdef', + 'util.pseudo-lexer' +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +source_suffix = ['.rst'] + +# The encoding of source files. +# +# source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +name = 'WebAssembly-Legacy-Exceptions' +project = u'WebAssembly-Legacy-Exceptions' +title = u'WebAssembly Spec Addendum: Legacy Exception Handling' +copyright = u'2023, WebAssembly Community Group' +author = u'WebAssembly Community Group' +editor = u'Andreas Rossberg (editor)' +logo = 'static/webassembly.png' + +# The name of the GitHub repository this resides in +repo = 'spec' + +# The draft version string (clear out for release cuts) +draft = ' (Draft ' + date.today().strftime("%Y-%m-%d") + ')' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '' +# The full version, including alpha/beta/rc tags. +release = version + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = 'en' + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +# +# today = '' +# +# Else, today_fmt is used as the format for a strftime call. +# +# today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This patterns also effect to html_static_path and html_extra_path +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +# +# default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +# +# add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +# +# add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +# +# show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +# modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +# keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = True + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'alabaster' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +html_theme_options = { + 'logo': logo, + 'logo_name': 'WebAssembly', + 'description': 'WebAssembly Specification', + 'fixed_sidebar': True, + 'sidebar_width': '260px', + 'sidebar_collapse': True, + 'show_powered_by': False, + 'extra_nav_links': { + 'Download as PDF': 'BASEDIR/_download/' + name + '.pdf' + }, +} + +html_sidebars = { + '**': [ + # 'about.html', + 'navigation.html', + # 'relations.html', + 'searchbox.html', + ] +} + + +# Add any paths that contain custom themes here, relative to this directory. +# html_theme_path = [] + +# The name for this set of Sphinx documents. +# " v documentation" by default. +# +html_title = u'WebAssembly Legacy Exceptions' + +# A shorter title for the navigation bar. Default is the same as html_title. +# +# html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +# +html_logo = logo + +# The name of an image file (relative to this directory) to use as a favicon of +# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +# +# html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['static/custom.css'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +# +# html_extra_path = [] + +# If not None, a 'Last updated on:' timestamp is inserted at every page +# bottom, using the given strftime format. +# The empty string is equivalent to '%b %d, %Y'. +# +# html_last_updated_fmt = None + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +# +# html_use_smartypants = True + +# Additional templates that should be rendered to pages, maps page names to +# template names. +# +# html_additional_pages = {} + +# If false, no module index is generated. +# +html_domain_indices = False + +# If false, no index is generated. +# +html_use_index = False + +# If true, the index is split into individual pages for each letter. +# +html_split_index = False + +# If true, the reST sources are included in the HTML build as _sources/name. The default is True. +# +html_copy_source = False + +# If true, links to the reST sources are added to the pages. +# +html_show_sourcelink = False + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +# +html_show_sphinx = False + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +# +html_show_copyright = True + +# If this is not None, a ‘Last updated on:’ timestamp is inserted at every +# page bottom, using the given strftime() format. +# +html_last_updated_fmt = '%Y-%m-%d' + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +# +# html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +# +# html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr', 'zh' +# +# html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# 'ja' uses this config value. +# 'zh' user can custom change `jieba` dictionary path. +# +# html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +# +# html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +# +htmlhelp_basename = 'WebAssemblydoc' + + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { + # The paper size ('a4paper' or 'letterpaper'). + 'papersize': 'a4paper', + + # The font size ('10pt', '11pt' or '12pt'). + 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # Don't type-set cross references with emphasis. + 'preamble': '\\renewcommand\\sphinxcrossref[1]{#1}\n', + + # Latex figure (float) alignment + 'figure_align': 'htbp', + + # Fancy chapters [Bjarne, Sonny, Lenny, Glenn, Conny, Rejne] + 'fncychap': '\\usepackage[Sonny]{fncychap}', + + # Allow chapters to start on even pages + 'extraclassoptions': 'openany' +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + ( master_doc, + name + '.tex', + title, + author + '\\\\ \\hfill\\large ' + editor, + 'howto' + ), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +# +latex_logo = logo + +# For "manual" documents [part, chapter, or section]. +# +latex_toplevel_sectioning = 'section' + +# If true, show page references after internal links. +# +latex_show_pagerefs = False + +# How to show URL addresses after external links [no, footnote, inline]. +# +latex_show_urls = 'footnote' + +# Documents to append as an appendix to all manuals. +# +# latex_appendices = [] + +# It false, will not define \strong, \code, \titleref, \crossref ... but only +# \sphinxstrong, ..., \sphinxtitleref, ... To help avoid clash with user added +# packages. +# +# latex_keep_old_macro_names = True + +# If false, no module index is generated. +# +latex_domain_indices = False + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ( master_doc, + name, + title, + [author], + 1 + ) +] + +# If true, show URL addresses after external links. +# +# man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ( master_doc, + name, + title, + author, + name, + 'A portable low-level execution format.', + 'Virtual Machine' + ), +] + +# Documents to append as an appendix to all manuals. +# +# texinfo_appendices = [] + +# If false, no module index is generated. +# +texinfo_domain_indices = False + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +# +# texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +# +# texinfo_no_detailmenu = False + + +# -- Options for Epub output ---------------------------------------------- + +# Bibliographic Dublin Core info. +epub_title = project +epub_author = author +epub_publisher = author +epub_copyright = copyright + +# The basename for the epub file. It defaults to the project name. +# epub_basename = project + +# The HTML theme for the epub output. Since the default themes are not +# optimized for small screen space, using the same theme for HTML and epub +# output is usually not wise. This defaults to 'epub', a theme designed to save +# visual space. +# +# epub_theme = 'epub' + +# The language of the text. It defaults to the language option +# or 'en' if the language is not set. +# +# epub_language = '' + +# The scheme of the identifier. Typical schemes are ISBN or URL. +# epub_scheme = '' + +# The unique identifier of the text. This can be a ISBN number +# or the project homepage. +# +# epub_identifier = '' + +# A unique identification for the text. +# +# epub_uid = '' + +# A tuple containing the cover image and cover page html template filenames. +# +# epub_cover = () + +# A sequence of (type, uri, title) tuples for the guide element of content.opf. +# +# epub_guide = () + +# HTML files that should be inserted before the pages created by sphinx. +# The format is a list of tuples containing the path and title. +# +# epub_pre_files = [] + +# HTML files that should be inserted after the pages created by sphinx. +# The format is a list of tuples containing the path and title. +# +# epub_post_files = [] + +# A list of files that should not be packed into the epub file. +epub_exclude_files = ['search.html'] + +# The depth of the table of contents in toc.ncx. +# +# epub_tocdepth = 3 + +# Allow duplicate toc entries. +# +# epub_tocdup = True + +# Choose between 'default' and 'includehidden'. +# +# epub_tocscope = 'default' + +# Fix unsupported image types using the Pillow. +# +# epub_fix_images = False + +# Scale large images. +# +# epub_max_image_width = 0 + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +# +# epub_show_urls = 'inline' + +# If false, no index is generated. +# +# epub_use_index = True + +# Macros +rst_prolog = """ +.. |issuelink| replace:: https://github.com/webassembly/""" + repo + """/issues/ +.. |pagelink| replace:: https://webassembly.github.io/""" + repo + """/core/ +.. include:: /""" + pwd + """/util/macros.def +""" + +# https://www.sphinx-doc.org/en/master/usage/extensions/math.html#confval-mathjax3_config +# https://docs.mathjax.org/en/latest/web/configuration.html#configuration +# https://docs.mathjax.org/en/latest/options/input/tex.html#tex-maxbuffer +mathjax3_config = { + 'tex': { 'maxBuffer': 30*1024 }, +} diff --git a/document/legacy/exceptions/core/exec.rst b/document/legacy/exceptions/core/exec.rst new file mode 100644 index 000000000..15d30b1b6 --- /dev/null +++ b/document/legacy/exceptions/core/exec.rst @@ -0,0 +1,350 @@ +.. _exec: + +Execution +========= + +.. _syntax-runtime: + +Runtime Structure +----------------- + +.. _handler: +.. _stack: + +Stack +~~~~~ + +.. _syntax-handler: + +**Exception Handlers** + +Legacy exception handlers are installed by |TRY| instructions. +Instead of branch labels, their catch clauses have instruction blocks associated with them. +Furthermore, a |DELEGATE| handler is associated with a label index to implicitly rewthrow to: + +.. math:: + \begin{array}{llllll} + \production{catch} & \catch &::=& \dots \\ &&|& + \CATCH~\tagidx~\instr^\ast \\ &&|& + \CATCHALL~\tagidx~\instr^\ast \\ &&|& + \DELEGATE~\labelidx \\ + \end{array} + + +.. _syntax-caught: +.. _syntax-instr-admin: + +Administrative Instructions +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Administrative instructions are extended with the |CAUGHT| instruction that models exceptions caught by legacy exception handlers. + +.. math:: + \begin{array}{llcl} + \production{administrative instruction} & \instr &::=& \dots \\ &&|& + \CAUGHT_n\{\exnaddr\}~\instr^\ast~\END \\ + \end{array} + + +.. _syntax-ctxt-block: + +Block Contexts +.............. + +Block contexts are extended to include |CAUGHT| instructions: + +.. math:: + \begin{array}{llll} + \production{block contexts} & \XB^k &::=& \dots \\ &&|& + \CAUGHT_n~\{\exnaddr\}~\XB^k~\END \\ + \end{array} + + +.. _syntax-ctxt-throw: + +Throw Contexts +.............. + +Throw contexts are also extended to include |CAUGHT| instructions: + +.. math:: + \begin{array}{llll} + \production{throw contexts} & \XT &::=& \dots \\ &&|& + \CAUGHT_n\{\exnaddr\}~\XT~\END \\ + \end{array} + + +.. _exec-instr: + +Instructions +------------ + +.. _exec-instr-control: + +Control Instructions +~~~~~~~~~~~~~~~~~~~~ + +.. _exec-try-catch: + +:math:`\TRY~\blocktype~\instr_1^\ast~(\CATCH~x~\instr_2^\ast)^\ast~(\CATCHALL~\instr_3^\ast)^?~\END` +.................................................................................................... + +1. Assert: due to :ref:`validation `, :math:`\expand_F(\blocktype)` is defined. + +2. Let :math:`[t_1^m] \to [t_2^n]` be the :ref:`function type ` :math:`\expand_F(\blocktype)`. + +3. Let :math:`L` be the label whose arity is :math:`n` and whose continuation is the end of the |TRY| instruction. + +4. Assert: due to :ref:`validation `, there are at least :math:`m` values on the top of the stack. + +5. Pop the values :math:`\val^m` from the stack. + +6. Let :math:`F` be the :ref:`current ` :ref:`frame `. + +7. For each catch clause :math:`(\CATCH~x_i~\instr_{2i}^\ast)` do: + + a. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MITAGS[x_i]` exists. + + b. Let :math:`a_i` be the tag address :math:`F.\AMODULE.\MITAGS[x_i]`. + + c. Let :math:`\catch_i` be the catch clause :math:`(\CATCH~a_i~\instr_{2i}^\ast)`. + +8. If there is a catch-all clause :math:`(\CATCHALL~\instr_3^\ast)`, then: + + a. Let :math:`\catch'^?` be the handler :math:`(\CATCHALL~\instr_3^\ast)`. + +9. Else: + + a. Let :math:`\catch'^?` be empty. + +10. Let :math:`\catch^\ast` be the concatenation of :math:`\catch_i` and :math:`\catch'^?`. + +11. :ref:`Enter ` the block :math:`\val^m~\instr_1^\ast` with label :math:`L` and exception handler :math:`\HANDLER_n\{\catch^\ast\}^\ast`. + +.. math:: + ~\\[-1ex] + \begin{array}{l} + F; \val^m~(\TRY~\X{bt}~\instr_1^\ast~(\CATCH~x~\instr_2^\ast)^\ast~(\CATCHALL~\instr_3^\ast)^?~\END + \quad \stepto \\ + \qquad F; \LABEL_n\{\epsilon\}~(\HANDLER_n\{(\CATCH~a_x~\instr_2^\ast)^\ast~(\CATCHALL~\instr_3^\ast)^?\}~\val^m~\instr_1^\ast~\END)~\END \\ \qquad + (\iff \expand_F(\X{bt}) = [t_1^m] \to [t_2^n] \land (F.\AMODULE.\MITAGS[x]=a_x)^\ast) + \end{array} + + +.. _exec-try-delegate: + +:math:`\TRY~\blocktype~\instr^\ast~\DELEGATE~l` +............................................... + +1. Assert: due to :ref:`validation `, :math:`\expand_F(\blocktype)` is defined. + +2. Let :math:`[t_1^m] \to [t_2^n]` be the :ref:`function type ` :math:`\expand_F(\blocktype)`. + +3. Let :math:`L` be the label whose arity is :math:`n` and whose continuation is the end of the |TRY| instruction. + +4. Let :math:`H` be the :ref:`exception handler ` :math:`l`, targeting the :math:`l`-th surrounding block. + +5. Assert: due to :ref:`validation `, there are at least :math:`m` values on the top of the stack. + +6. Pop the values :math:`\val^m` from the stack. + +7. :ref:`Enter ` the block :math:`\val^m~\instr^\ast` with label :math:`L` and exception handler `\HANDLER_n\{\DELEGATE~l\}`. + +.. math:: + ~\\[-1ex] + \begin{array}{lcl} + F; \val^m~(\TRY~\X{bt}~\instr^\ast~\DELEGATE~l) &\stepto& + F; \LABEL_n\{\epsilon\}~(\HANDLER_n\{\DELEGATE~l\}~\val^m~\instr^\ast~\END)~\END \\ + && (\iff \expand_F(\X{bt}) = [t_1^m] \to [t_2^n]) + \end{array} + + +.. _exec-throw_ref: + +:math:`\THROWREF` +................. + +1. Let :math:`F` be the :ref:`current ` :ref:`frame `. + +2. Assert: due to :ref:`validation `, a :ref:`reference ` is on the top of the stack. + +3. Pop the reference :math:`\reff` from the stack. + +4. If :math:`\reff` is :math:`\REFNULL~\X{ht}`, then: + + a. Trap. + +5. Assert: due to :ref:`validation `, :math:`\reff` is an :ref:`exception reference `. + +6. Let :math:`\REFEXNADDR~\X{ea}` be :math:`\reff`. + +7. Assert: due to :ref:`validation `, :math:`S.\SEXNS[\X{ea}]` exists. + +8. Let :math:`\X{exn}` be the :ref:`exception instance ` :math:`S.\SEXNS[\X{ea}]`. + +9. Let :math:`a` be the :ref:`tag address ` :math:`\X{exn}.\EITAG`. + +10. While the stack is not empty and the top of the stack is not an :ref:`exception handler `, do: + + a. Pop the top element from the stack. + +11. Assert: the stack is now either empty, or there is an exception handler on the top of the stack. + +12. If the stack is empty, then: + + a. Return the exception :math:`(\REFEXNADDR~a)` as a :ref:`result `. + +13. Assert: there is an :ref:`exception handler ` on the top of the stack. + +14. Pop the exception handler :math:`\HANDLER_n\{\catch^\ast\}` from the stack. + +15. If :math:`\catch^\ast` is empty, then: + + a. Push the exception reference :math:`\REFEXNADDR~\X{ea}` back to the stack. + + b. Execute the instruction |THROWREF| again. + +16. Else: + + a. Let :math:`\catch_1` be the first :ref:`catch clause ` in :math:`\catch^\ast` and :math:`{\catch'}^\ast` the remaining clauses. + + b. If :math:`\catch_1` is of the form :math:`\CATCH~x~l` and the :ref:`exception address ` :math:`a` equals :math:`F.\AMODULE.\MITAGS[x]`, then: + + i. Push the values :math:`\X{exn}.\EIFIELDS` to the stack. + + ii. Execute the instruction :math:`\BR~l`. + + c. Else if :math:`\catch_1` is of the form :math:`\CATCHREF~x~l` and the :ref:`exception address ` :math:`a` equals :math:`F.\AMODULE.\MITAGS[x]`, then: + + i. Push the values :math:`\X{exn}.\EIFIELDS` to the stack. + + ii. Push the exception reference :math:`\REFEXNADDR~\X{ea}` to the stack. + + iii. Execute the instruction :math:`\BR~l`. + + d. Else if :math:`\catch_1` is of the form :math:`\CATCHALL~l`, then: + + i. Execute the instruction :math:`\BR~l`. + + e. Else if :math:`\catch_1` is of the form :math:`\CATCHALLREF~l`, then: + + i. Push the exception reference :math:`\REFEXNADDR~\X{ea}` to the stack. + + ii. Execute the instruction :math:`\BR~l`. + + f. Else if :math:`\catch_1` is of the form :math:`\CATCH~x~\instr^\ast` and the :ref:`exception address ` :math:`a` equals :math:`F.\AMODULE.\MITAGS[x]`, then: + + i. Push the caught exception :math:`\CAUGHT_n\{\X{ea}\}` to the stack. + + ii. Push the values :math:`\X{exn}.\EIFIELDS` to the stack. + + iii. :ref:`Enter ` the catch block :math:`\instr^\ast`. + + g. Else if :math:`\catch_1` is of the form :math:`\CATCHALL~\instr^\ast`, then: + + i. Push the caught exception :math:`\CAUGHT_n\{\X{ea}\}` to the stack. + + ii. :ref:`Enter ` the catch block :math:`\instr^\ast`. + + h. Else if :math:`\catch_1` is of the form :math:`\DELEGATE~l`, then: + + i. Assert: due to :ref:`validation `, the stack contains at least :math:`l` labels. + + ii. Repeat :math:`l` times: + + * While the top of the stack is not a label, do: + + - Pop the top element from the stack. + + iii. Assert: due to :ref:`validation `, the top of the stack now is a label. + + iv. Pop the label from the stack. + + v. Push the exception reference :math:`\REFEXNADDR~\X{ea}` back to the stack. + + vi. Execute the instruction :math:`\THROWREF` again. + + i. Else: + + 1. Push the modified handler :math:`\HANDLER_n\{{\catch'}^\ast\}` back to the stack. + + 2. Push the exception reference :math:`\REFEXNADDR~\X{ea}` back to the stack. + + 3. Execute the instruction :math:`\THROWREF` again. + +.. math:: + ~\\[-1ex] + \begin{array}{rcl} + \dots \\ + \HANDLER_n\{(\CATCH~x~\instr^\ast)~\catch^\ast\}~\XT[(\REFEXNADDR~a)~\THROWREF]~\END &\stepto& + \CAUGHT_n\{a\}~\X{exn}.\EIFIELDS~\instr^\ast~\END \\ && + (\begin{array}[t]{@{}r@{~}l@{}} + \iff & \X{exn} = S.\SEXNS[a] \\ + \land & \X{exn}.\EITAG = F.\AMODULE.\MITAGS[x]) \\ + \end{array} \\ + \HANDLER_n\{(\CATCHALL~\instr^\ast)~\catch^\ast\}~\XT[(\REFEXNADDR~a)~\THROWREF]~\END &\stepto& + \CAUGHT_n\{a\}~\instr^\ast~\END \\ + \XB^l[\HANDLER_n\{(\DELEGATE~l)~\catch^\ast\}~\XT[(\REFEXNADDR~a)~\THROWREF]~\END] &\stepto& + (\REFEXNADDR~a)~\THROWREF \\ + \end{array} + + +.. _exec-rethrow: + +:math:`\RETHROW~l` +.................. + +1. Assert: due to :ref:`validation `, the stack contains at least :math:`l+1` labels. + +2. Let :math:`L` be the :math:`l`-th label appearing on the stack, starting from the top and counting from zero. + +3. Assert: due to :ref:`validation `, :math:`L` is a catch label, i.e., a label of the form :math:`(\LCATCH~[t^\ast])`, which is a label followed by a caught exception in an active catch clause. + +4. Let :math:`a` be the caught exception address. + +5. Push the value :math:`\REFEXNADDR~a` onto the stack. + +6. Execute the instruction |THROWREF|. + +.. math:: + ~\\[-1ex] + \begin{array}{lclr@{\qquad}} + \CAUGHT_n\{a\}~\XB^l[\RETHROW~l]~\END &\stepto& + \CAUGHT_n\{a\}~\XB^l[(\REFEXNADDR~a)~\THROWREF]~\END \\ + \end{array} + + +.. _exec-caught-enter: + +Entering a catch block +...................... + +1. Jump to the start of the instruction sequence :math:`\instr^\ast`. + + +.. _exec-caught-exit: + +Exiting a catch block +..................... + +When the |END| of a catch block is reached without a jump, thrown exception, or trap, then the following steps are performed. + +1. Let :math:`\val^m` be the values on the top of the stack. + +2. Pop the values :math:`\val^m` from the stack. + +3. Assert: due to :ref:`validation `, a caught exception is now on the top of the stack. + +4. Pop the caught exception from the stack. + +5. Push :math:`\val^m` back to the stack. + +6. Jump to the position after the |END| of the administrative instruction associated with the caught exception. + +.. math:: + \begin{array}{rcl} + \CAUGHT_n\{a\}~\val^m~\END &\stepto& \val^m + \end{array} + +.. note:: + A caught exception can only be rethrown from the scope of the administrative instruction associated with it, i.e., from the scope of the |CATCH| or |CATCHALL| block of a legacy |TRY| instruction. Upon exit from that block, the caught exception is discarded. diff --git a/document/legacy/exceptions/core/index.rst b/document/legacy/exceptions/core/index.rst new file mode 100644 index 000000000..a83254bb5 --- /dev/null +++ b/document/legacy/exceptions/core/index.rst @@ -0,0 +1,19 @@ +WebAssembly Addendum: Legacy Exception Handling +=============================================== + +.. only:: html + + | Editor: Andreas Rossberg + + | Issue Tracker: |WasmIssues| + +.. toctree:: + :maxdepth: 1 + + intro + syntax + valid + exec + binary + text + appendix/index-instructions diff --git a/document/legacy/exceptions/core/intro.rst b/document/legacy/exceptions/core/intro.rst new file mode 100644 index 000000000..b8d8c57c3 --- /dev/null +++ b/document/legacy/exceptions/core/intro.rst @@ -0,0 +1,8 @@ +.. _intro: + +Introduction +============ + +This document describes an extension of the official WebAssembly standard +developed by its `W3C Community Group `_ with additional instructions for exception handling. +These instructions were never standardized and are deprecated, but they may still be available in some engines, especially in web browsers. diff --git a/document/legacy/exceptions/core/static/custom.css b/document/legacy/exceptions/core/static/custom.css new file mode 100644 index 000000000..33bb863d4 --- /dev/null +++ b/document/legacy/exceptions/core/static/custom.css @@ -0,0 +1,78 @@ +a { + color: #004BAB; + text-decoration: none; +} + +a.reference { + border-bottom: none; +} + +a.reference:hover { + border-bottom: 1px dotted #004BAB; +} + +body { + font-size: 15px; +} + +div.document { width: 1000px; } +div.bodywrapper { margin: 0 0 0 200px; } +div.body { padding: 0 10px 0 10px; } +div.footer { width: 1000px; } + +div.body h1 { font-size: 200%; } +div.body h2 { font-size: 150%; } +div.body h3 { font-size: 120%; } +div.body h4 { font-size: 110%; } + +div.note { + border: 0px; + font-size: 90%; + background-color: #F6F8FF; +} + +div.admonition { + padding: 10px; +} + +div.admonition p.admonition-title { + margin: 0px 0px 0px 0px; + font-size: 100%; + font-weight: bold; +} + +div.math { + background-color: #F0F0F0; + padding: 3px 0 3px 0; + overflow-x: auto; + overflow-y: hidden; +} + +div.relations { + display: block; +} + +div.sphinxsidebar { + z-index: 1; + background: #FFF; + margin-top: -30px; + font-size: 13px; + width: 200px; + height: 100%; +} + +div.sphinxsidebarwrapper p.logo { + padding: 30px 40px 10px 0px; +} + +div.sphinxsidebar h3 { + font-size: 0px; +} + +div.sphinxsidebar a { + border-bottom: 0px; +} + +div.sphinxsidebar a:hover { + border-bottom: 1px dotted; +} diff --git a/document/legacy/exceptions/core/static/webassembly.png b/document/legacy/exceptions/core/static/webassembly.png new file mode 100644 index 000000000..f9edc6109 Binary files /dev/null and b/document/legacy/exceptions/core/static/webassembly.png differ diff --git a/document/legacy/exceptions/core/syntax.rst b/document/legacy/exceptions/core/syntax.rst new file mode 100644 index 000000000..3dc50dfe6 --- /dev/null +++ b/document/legacy/exceptions/core/syntax.rst @@ -0,0 +1,38 @@ +.. _syntax: + +Structure +========= + +.. _syntax-instr: + +Instructions +------------ + +.. _syntax-try: +.. _syntax-try-catch: +.. _syntax-try-delegate: +.. _syntax-rethrow: +.. _syntax-instr-control: + +Control Instructions +~~~~~~~~~~~~~~~~~~~~ + +The set of recognised instructions is extended with the following: + +.. math:: + \begin{array}{llcl} + \production{instruction} & \instr &::=& + \dots \\&&|& + \TRY~\blocktype~\instr^\ast~(\CATCH~\tagidx~\instr^\ast)^\ast~(\CATCHALL~\instr^\ast)^?~\END \\ &&|& + \TRY~\blocktype~\instr^\ast~\DELEGATE~\labelidx \\ &&|& + \RETHROW~\labelidx \\ + \end{array} + +The instructions |TRY| and |RETHROW|, are concerned with exceptions. +The |TRY| instruction installs an exception handler, and may either handle exceptions in the case of |CATCH| and |CATCHALL|, +or rethrow them in an outer block in the case of |DELEGATE|. + +The |RETHROW| instruction is only allowed inside a |CATCH| or |CATCHALL| clause and allows rethrowing the caught exception by lexically referring to a the corresponding |TRY|. + +When |TRY|-|DELEGATE| handles an exception, it also behaves similar to a forward jump, +effectively rethrowing the caught exception right before the matching |END|. diff --git a/document/legacy/exceptions/core/text.rst b/document/legacy/exceptions/core/text.rst new file mode 100644 index 000000000..1968c1120 --- /dev/null +++ b/document/legacy/exceptions/core/text.rst @@ -0,0 +1,38 @@ +.. _text: + +Text Format +=========== + +.. _text-instr: + +Instructions +------------ + +.. _text-blockinstr: +.. _text-plaininstr: +.. _text-instr-control: + +Control Instructions +~~~~~~~~~~~~~~~~~~~~ + +.. _text-try: + +The label identifier on a structured control instruction may optionally be repeated after the corresponding :math:`\T{end}`, :math:`\T{else}`, :math:`\T{catch}`, :math:`\T{catch\_all}`, and :math:`\T{delegate}` +pseudo instructions, to indicate the matching delimiters. + +.. math:: + \begin{array}{@{}llclll} + \production{block instruction} & \Tblockinstr_I &::=& \dots \\ &&|& + \text{try}~~I'{:}\Tlabel_I~~\X{bt}{:}\Tblocktype~~(\X{in}_1{:}\Tinstr_{I'})^\ast~~\\&&& + (\text{catch}~~\Tid_1^?~~x{:}\Ttagidx_I~~(\X{in}_2{:}\Tinstr_{I'})^\ast)^\ast~~ \\&&& + (\text{catch\_all}~~\Tid_1^?~~(\X{in}_3{:}\Tinstr_{I'})^\ast)^?~~ \\&&& + \text{end}~~\Tid_2^? + \\ &&&\qquad \Rightarrow\quad \TRY~\X{bt}~\X{in}_1^\ast~(\CATCH~x~\X{in}_2^\ast)^\ast~(\CATCHALL~\X{in}_3^\ast)^?~\END + \\ &&&\qquad\qquad (\iff \Tid_1^? = \epsilon \vee \Tid_1^? = \Tlabel, \Tid_2^? = \epsilon \vee \Tid_2^? = \Tlabel) \\ &&|& + \text{try}~~I'{:}\Tlabel_I~~\X{bt}{:}\Tblocktype~~(\X{in}_1{:}\Tinstr_{I'})^\ast~~ \\&&& + \text{delegate}~~l{:}\Tlabelidx_I~~\X{l}{:}\Tlabelidx_I + \\ &&&\qquad \Rightarrow\quad \TRY~\X{bt}~\X{in}_1^\ast~\DELEGATE~l + \qquad\quad~~ (\iff \Tid^? = \epsilon \vee \Tid^? = \Tlabel) \\ + \production{plain instruction} & \Tplaininstr_I &::=& \dots \\ &&|& + \text{rethrow}~~l{:}\Tlabelidx_I \quad\Rightarrow\quad \RETHROW~l \\ + \end{array} diff --git a/document/legacy/exceptions/core/util/macros.def b/document/legacy/exceptions/core/util/macros.def new file mode 100644 index 000000000..e1c289100 --- /dev/null +++ b/document/legacy/exceptions/core/util/macros.def @@ -0,0 +1,1342 @@ +.. LINK MACROS + +.. External Standards +.. ------------------ + +.. |WasmDraft| replace:: |pagelink| +.. _WasmDraft: |pagelink| + +.. |WasmIssues| replace:: |issuelink| +.. _WasmIssues: |issuelink| + +.. |IEEE754| replace:: IEEE 754 +.. _IEEE754: https://ieeexplore.ieee.org/document/8766229 + +.. |Unicode| replace:: Unicode +.. _Unicode: https://www.unicode.org/versions/latest/ + +.. |ASCII| replace:: ASCII +.. _ASCII: https://webstore.ansi.org/RecordDetail.aspx?sku=INCITS+4-1986%5bR2012%5d + + +.. External Definitions +.. -------------------- + +.. |LittleEndian| replace:: little endian +.. _LittleEndian: https://en.wikipedia.org/wiki/Endianness#Little-endian + +.. |LEB128| replace:: LEB128 +.. _LEB128: https://en.wikipedia.org/wiki/LEB128 +.. |UnsignedLEB128| replace:: unsigned LEB128 +.. _UnsignedLEB128: https://en.wikipedia.org/wiki/LEB128#Unsigned_LEB128 +.. |SignedLEB128| replace:: signed LEB128 +.. _SignedLEB128: https://en.wikipedia.org/wiki/LEB128#Signed_LEB128 + +.. |SExpressions| replace:: S-expressions +.. _SExpressions: https://en.wikipedia.org/wiki/S-expression + +.. |MediaType| replace:: Media Type +.. _MediaType: https://www.iana.org/assignments/media-types/media-types.xhtml + + +.. Literature +.. ---------- + +.. |PLDI2017| replace:: Bringing the Web up to Speed with WebAssembly +.. _PLDI2017: https://dl.acm.org/citation.cfm?doid=3062341.3062363 + +.. |CPP2018| replace:: Mechanising and Verifying the WebAssembly Specification +.. _CPP2018: https://dl.acm.org/citation.cfm?id=3167082 + +.. |FM2021| replace:: Two Mechanisations of WebAssembly 1.0 +.. _FM2021: https://link.springer.com/chapter/10.1007/978-3-030-90870-6_4 + +.. |TAPL| replace:: Types and Programming Languages +.. _TAPL: https://www.cis.upenn.edu/~bcpierce/tapl/ + + + +.. MATH MACROS + + +.. Generic Stuff +.. ------------- + +.. To comment out stuff + +.. |void#1| mathdef:: {} + + +.. Type-setting of names +.. X - (multi-letter) variables / non-terminals +.. F - functions +.. K - keywords / terminals +.. B - binary grammar non-terminals +.. T - textual grammar non-terminals + +.. |X| mathdef:: \mathit +.. |F| mathdef:: \mathrm +.. |K| mathdef:: \mathsf +.. |B| mathdef:: \mathtt +.. |T| mathdef:: \mathtt + + +.. Notation + +.. |mod| mathdef:: \mathbin{\F{mod}} + +.. |iff| mathdef:: \mathrel{\mbox{if}} +.. |otherwise| mathdef:: \mathrel{\mbox{otherwise}} +.. |where| mathdef:: \mathrel{\mbox{where}} + + + +.. Grammar & Syntax Notation +.. ------------------------- + +.. Notation for grammars + +.. |production| mathdef:: \void + + +.. Notation for Sequences & Records + +.. |slice| mathdef:: \xref{syntax/conventions}{notation-slice}{\mathrel{\mathbf{:}}} +.. |with| mathdef:: \xref{syntax/conventions}{notation-replace}{\mathrel{\mbox{with}}} +.. |concat| mathdef:: \xref{syntax/conventions}{notation-concat}{\F{concat}} +.. |compose| mathdef:: \xref{syntax/conventions}{notation-compose}{\oplus} +.. |bigcompose| mathdef:: \xref{syntax/conventions}{notation-compose}{\bigoplus} + + + +.. Abstract Syntax +.. --------------- + +.. Auxiliary productions + +.. |vec| mathdef:: \xref{syntax/conventions}{syntax-vec}{\X{vec}} + + +.. Values, terminals + +.. |hex#1| mathdef:: \mathtt{0x#1} +.. |unicode#1| mathdef:: \mathrm{U{+}#1} + +.. |NAN| mathdef:: \xref{syntax/values}{syntax-float}{\K{nan}} + + +.. Values, non-terminals + +.. |byte| mathdef:: \xref{syntax/values}{syntax-byte}{\X{byte}} + +.. |uX#1| mathdef:: {\X{u#1}} +.. |sX#1| mathdef:: {\X{s#1}} +.. |iX#1| mathdef:: {\X{i#1}} +.. |fX#1| mathdef:: {\X{f#1}} +.. |vX#1| mathdef:: {\X{v#1}} + +.. |uN| mathdef:: \xref{syntax/values}{syntax-int}{\X{u}N} +.. |uM| mathdef:: \xref{syntax/values}{syntax-int}{\X{u}M} +.. |u1| mathdef:: \xref{syntax/values}{syntax-int}{\X{u1}} +.. |u8| mathdef:: \xref{syntax/values}{syntax-int}{\X{u8}} +.. |u16| mathdef:: \xref{syntax/values}{syntax-int}{\X{u16}} +.. |u32| mathdef:: \xref{syntax/values}{syntax-int}{\X{u32}} +.. |u64| mathdef:: \xref{syntax/values}{syntax-int}{\X{u64}} + +.. |sN| mathdef:: \xref{syntax/values}{syntax-int}{\X{s}N} +.. |s8| mathdef:: \xref{syntax/values}{syntax-int}{\X{s8}} +.. |s16| mathdef:: \xref{syntax/values}{syntax-int}{\X{s16}} +.. |s32| mathdef:: \xref{syntax/values}{syntax-int}{\X{s32}} +.. |s64| mathdef:: \xref{syntax/values}{syntax-int}{\X{s64}} + +.. |iM| mathdef:: \xref{syntax/values}{syntax-int}{\X{i}M} +.. |iN| mathdef:: \xref{syntax/values}{syntax-int}{\X{i}N} +.. |i8| mathdef:: \xref{syntax/values}{syntax-int}{\X{i8}} +.. |i16| mathdef:: \xref{syntax/values}{syntax-int}{\X{i16}} +.. |i32| mathdef:: \xref{syntax/values}{syntax-int}{\X{i32}} +.. |i64| mathdef:: \xref{syntax/values}{syntax-int}{\X{i64}} +.. |i128| mathdef:: \xref{syntax/values}{syntax-int}{\X{i128}} + +.. |fN| mathdef:: \xref{syntax/values}{syntax-float}{\X{f}N} +.. |fNmag| mathdef:: \xref{syntax/values}{syntax-float}{\X{f}\X{Nmag}} +.. |f32| mathdef:: \xref{syntax/values}{syntax-float}{\X{f32}} +.. |f64| mathdef:: \xref{syntax/values}{syntax-float}{\X{f64}} + +.. |name| mathdef:: \xref{syntax/values}{syntax-name}{\X{name}} +.. |char| mathdef:: \xref{syntax/values}{syntax-name}{\X{char}} + + +.. Values, meta functions + +.. |canon| mathdef:: \xref{syntax/values}{aux-canon}{\F{canon}} +.. |significand| mathdef:: \xref{syntax/values}{aux-significand}{\F{signif}} +.. |exponent| mathdef:: \xref{syntax/values}{aux-exponent}{\F{expon}} + + +.. Types, terminals + +.. |to| mathdef:: \xref{syntax/types}{syntax-functype}{\rightarrow} +.. |toF| mathdef:: \xref{syntax/types}{syntax-functype}{\rightarrow} + +.. |I8| mathdef:: \xref{exec/runtime}{syntax-storagetype}{\K{i8}} +.. |I16| mathdef:: \xref{exec/runtime}{syntax-storagetype}{\K{i16}} +.. |I32| mathdef:: \xref{syntax/types}{syntax-valtype}{\K{i32}} +.. |I64| mathdef:: \xref{syntax/types}{syntax-valtype}{\K{i64}} +.. |F32| mathdef:: \xref{syntax/types}{syntax-valtype}{\K{f32}} +.. |F64| mathdef:: \xref{syntax/types}{syntax-valtype}{\K{f64}} +.. |V128| mathdef:: \xref{syntax/types}{syntax-valtype}{\K{v128}} +.. |I8X16| mathdef:: \xref{syntax/types}{syntax-valtype}{\K{i8x16}} +.. |I16X8| mathdef:: \xref{syntax/types}{syntax-valtype}{\K{i16x8}} +.. |I32X4| mathdef:: \xref{syntax/types}{syntax-valtype}{\K{i32x4}} +.. |I64X2| mathdef:: \xref{syntax/types}{syntax-valtype}{\K{i64x2}} +.. |F32X4| mathdef:: \xref{syntax/types}{syntax-valtype}{\K{f32x4}} +.. |F64X2| mathdef:: \xref{syntax/types}{syntax-valtype}{\K{f64x2}} +.. |I128| mathdef:: \K{i128} + +.. |FUNCREF| mathdef:: \xref{syntax/types}{syntax-reftype}{\K{funcref}} +.. |EXTERNREF| mathdef:: \xref{syntax/types}{syntax-reftype}{\K{externref}} +.. |EXNREF| mathdef:: \xref{syntax/types}{syntax-reftype}{\K{exnref}} + +.. |MVAR| mathdef:: \xref{syntax/types}{syntax-mut}{\K{var}} +.. |MCONST| mathdef:: \xref{syntax/types}{syntax-mut}{\K{const}} + +.. |LMIN| mathdef:: \xref{syntax/types}{syntax-limits}{\K{min}} +.. |LMAX| mathdef:: \xref{syntax/types}{syntax-limits}{\K{max}} + +.. |ETFUNC| mathdef:: \xref{syntax/types}{syntax-externtype}{\K{func}} +.. |ETTABLE| mathdef:: \xref{syntax/types}{syntax-externtype}{\K{table}} +.. |ETMEM| mathdef:: \xref{syntax/types}{syntax-externtype}{\K{mem}} +.. |ETGLOBAL| mathdef:: \xref{syntax/types}{syntax-externtype}{\K{global}} +.. |ETTAG| mathdef:: \xref{syntax/types}{syntax-tagtype}{\K{tag}} + + +.. Types, non-terminals + +.. |numtype| mathdef:: \xref{syntax/types}{syntax-numtype}{\X{numtype}} +.. |vectype| mathdef:: \xref{syntax/types}{syntax-vectype}{\X{vectype}} +.. |reftype| mathdef:: \xref{syntax/types}{syntax-reftype}{\X{reftype}} +.. |valtype| mathdef:: \xref{syntax/types}{syntax-valtype}{\X{valtype}} +.. |resulttype| mathdef:: \xref{syntax/types}{syntax-resulttype}{\X{resulttype}} +.. |functype| mathdef:: \xref{syntax/types}{syntax-functype}{\X{functype}} +.. |tagtype| mathdef:: \xref{syntax/types}{syntax-tagtype}{\X{tagtype}} + +.. |globaltype| mathdef:: \xref{syntax/types}{syntax-globaltype}{\X{globaltype}} +.. |tabletype| mathdef:: \xref{syntax/types}{syntax-tabletype}{\X{tabletype}} +.. |memtype| mathdef:: \xref{syntax/types}{syntax-memtype}{\X{memtype}} + +.. |limits| mathdef:: \xref{syntax/types}{syntax-limits}{\X{limits}} +.. |mut| mathdef:: \xref{syntax/types}{syntax-mut}{\X{mut}} + +.. |externtype| mathdef:: \xref{syntax/types}{syntax-externtype}{\X{externtype}} + +.. |stacktype| mathdef:: \xref{syntax/types}{syntax-stacktype}{\X{stacktype}} +.. |opdtype| mathdef:: \xref{syntax/types}{syntax-opdtype}{\X{opdtype}} + + +.. Types, meta functions + +.. |etfuncs| mathdef:: \xref{syntax/types}{syntax-externtype}{\F{funcs}} +.. |ettables| mathdef:: \xref{syntax/types}{syntax-externtype}{\F{tables}} +.. |etmems| mathdef:: \xref{syntax/types}{syntax-externtype}{\F{mems}} +.. |etglobals| mathdef:: \xref{syntax/types}{syntax-externtype}{\F{globals}} +.. |ettags| mathdef:: \xref{syntax/types}{syntax-externtype}{\F{tags}} + + +.. Indices, non-terminals + +.. |typeidx| mathdef:: \xref{syntax/modules}{syntax-typeidx}{\X{typeidx}} +.. |funcidx| mathdef:: \xref{syntax/modules}{syntax-funcidx}{\X{funcidx}} +.. |tableidx| mathdef:: \xref{syntax/modules}{syntax-tableidx}{\X{tableidx}} +.. |memidx| mathdef:: \xref{syntax/modules}{syntax-memidx}{\X{memidx}} +.. |globalidx| mathdef:: \xref{syntax/modules}{syntax-globalidx}{\X{globalidx}} +.. |elemidx| mathdef:: \xref{syntax/modules}{syntax-elemidx}{\X{elemidx}} +.. |dataidx| mathdef:: \xref{syntax/modules}{syntax-dataidx}{\X{dataidx}} +.. |localidx| mathdef:: \xref{syntax/modules}{syntax-localidx}{\X{localidx}} +.. |labelidx| mathdef:: \xref{syntax/modules}{syntax-labelidx}{\X{labelidx}} +.. |tagidx| mathdef:: \xref{syntax/modules}{syntax-tagidx}{\X{tagidx}} + + +.. Indices, meta functions + +.. |freetypeidx| mathdef:: \xref{syntax/modules}{syntax-typeidx}{\F{typeidx}} +.. |freefuncidx| mathdef:: \xref{syntax/modules}{syntax-funcidx}{\F{funcidx}} +.. |freetableidx| mathdef:: \xref{syntax/modules}{syntax-tableidx}{\F{tableidx}} +.. |freememidx| mathdef:: \xref{syntax/modules}{syntax-memidx}{\F{memidx}} +.. |freeglobalidx| mathdef:: \xref{syntax/modules}{syntax-globalidx}{\F{globalidx}} +.. |freeelemidx| mathdef:: \xref{syntax/modules}{syntax-elemidx}{\F{elemidx}} +.. |freedataidx| mathdef:: \xref{syntax/modules}{syntax-dataidx}{\F{dataidx}} +.. |freelocalidx| mathdef:: \xref{syntax/modules}{syntax-localidx}{\F{localidx}} +.. |freelabelidx| mathdef:: \xref{syntax/modules}{syntax-labelidx}{\F{labelidx}} + + +.. Modules, terminals + +.. |MTYPES| mathdef:: \xref{syntax/modules}{syntax-module}{\K{types}} +.. |MFUNCS| mathdef:: \xref{syntax/modules}{syntax-module}{\K{funcs}} +.. |MTABLES| mathdef:: \xref{syntax/modules}{syntax-module}{\K{tables}} +.. |MMEMS| mathdef:: \xref{syntax/modules}{syntax-module}{\K{mems}} +.. |MGLOBALS| mathdef:: \xref{syntax/modules}{syntax-module}{\K{globals}} +.. |MTAGS| mathdef:: \xref{syntax/modules}{syntax-module}{\K{tags}} +.. |MIMPORTS| mathdef:: \xref{syntax/modules}{syntax-module}{\K{imports}} +.. |MEXPORTS| mathdef:: \xref{syntax/modules}{syntax-module}{\K{exports}} +.. |MDATAS| mathdef:: \xref{syntax/modules}{syntax-module}{\K{datas}} +.. |MELEMS| mathdef:: \xref{syntax/modules}{syntax-module}{\K{elems}} +.. |MSTART| mathdef:: \xref{syntax/modules}{syntax-module}{\K{start}} + +.. |FTYPE| mathdef:: \xref{syntax/modules}{syntax-func}{\K{type}} +.. |FLOCALS| mathdef:: \xref{syntax/modules}{syntax-func}{\K{locals}} +.. |FBODY| mathdef:: \xref{syntax/modules}{syntax-func}{\K{body}} + +.. |TTYPE| mathdef:: \xref{syntax/modules}{syntax-table}{\K{type}} + +.. |MTYPE| mathdef:: \xref{syntax/modules}{syntax-mem}{\K{type}} + +.. |TAGTYPE| mathdef:: \xref{syntax/modules}{syntax-tag}{\K{type}} + +.. |GTYPE| mathdef:: \xref{syntax/modules}{syntax-global}{\K{type}} +.. |GINIT| mathdef:: \xref{syntax/modules}{syntax-global}{\K{init}} + +.. |ETYPE| mathdef:: \xref{syntax/modules}{syntax-elem}{\K{type}} +.. |EINIT| mathdef:: \xref{syntax/modules}{syntax-elem}{\K{init}} +.. |EMODE| mathdef:: \xref{syntax/modules}{syntax-elem}{\K{mode}} +.. |EPASSIVE| mathdef:: \xref{syntax/modules}{syntax-elemmode}{\K{passive}} +.. |EACTIVE| mathdef:: \xref{syntax/modules}{syntax-elemmode}{\K{active}} +.. |EDECLARATIVE| mathdef:: \xref{syntax/modules}{syntax-elemmode}{\K{declarative}} +.. |ETABLE| mathdef:: \xref{syntax/modules}{syntax-elem}{\K{table}} +.. |EOFFSET| mathdef:: \xref{syntax/modules}{syntax-elem}{\K{offset}} + +.. |DINIT| mathdef:: \xref{syntax/modules}{syntax-data}{\K{init}} +.. |DMODE| mathdef:: \xref{syntax/modules}{syntax-data}{\K{mode}} +.. |DPASSIVE| mathdef:: \xref{syntax/modules}{syntax-datamode}{\K{passive}} +.. |DACTIVE| mathdef:: \xref{syntax/modules}{syntax-datamode}{\K{active}} +.. |DMEM| mathdef:: \xref{syntax/modules}{syntax-data}{\K{memory}} +.. |DOFFSET| mathdef:: \xref{syntax/modules}{syntax-data}{\K{offset}} + +.. |SFUNC| mathdef:: \xref{syntax/modules}{syntax-start}{\K{func}} + +.. |ENAME| mathdef:: \xref{syntax/modules}{syntax-export}{\K{name}} +.. |EDESC| mathdef:: \xref{syntax/modules}{syntax-export}{\K{desc}} +.. |EDFUNC| mathdef:: \xref{syntax/modules}{syntax-exportdesc}{\K{func}} +.. |EDTABLE| mathdef:: \xref{syntax/modules}{syntax-exportdesc}{\K{table}} +.. |EDMEM| mathdef:: \xref{syntax/modules}{syntax-exportdesc}{\K{mem}} +.. |EDGLOBAL| mathdef:: \xref{syntax/modules}{syntax-exportdesc}{\K{global}} +.. |EDTAG| mathdef:: \xref{syntax/modules}{syntax-exportdesc}{\K{tag}} + +.. |IMODULE| mathdef:: \xref{syntax/modules}{syntax-import}{\K{module}} +.. |INAME| mathdef:: \xref{syntax/modules}{syntax-import}{\K{name}} +.. |IDESC| mathdef:: \xref{syntax/modules}{syntax-import}{\K{desc}} +.. |IDFUNC| mathdef:: \xref{syntax/modules}{syntax-importdesc}{\K{func}} +.. |IDTABLE| mathdef:: \xref{syntax/modules}{syntax-importdesc}{\K{table}} +.. |IDMEM| mathdef:: \xref{syntax/modules}{syntax-importdesc}{\K{mem}} +.. |IDTAG| mathdef:: \xref{syntax/modules}{syntax-importdesc}{\K{tag}} +.. |IDGLOBAL| mathdef:: \xref{syntax/modules}{syntax-importdesc}{\K{global}} + + +.. Modules, non-terminals + +.. |module| mathdef:: \xref{syntax/modules}{syntax-module}{\X{module}} +.. |type| mathdef:: \xref{syntax/types}{syntax-functype}{\X{type}} +.. |func| mathdef:: \xref{syntax/modules}{syntax-func}{\X{func}} +.. |table| mathdef:: \xref{syntax/modules}{syntax-table}{\X{table}} +.. |mem| mathdef:: \xref{syntax/modules}{syntax-mem}{\X{mem}} +.. |tag| mathdef:: \xref{syntax/modules}{syntax-tag}{\X{tag}} +.. |global| mathdef:: \xref{syntax/modules}{syntax-global}{\X{global}} +.. |import| mathdef:: \xref{syntax/modules}{syntax-import}{\X{import}} +.. |export| mathdef:: \xref{syntax/modules}{syntax-export}{\X{export}} +.. |importdesc| mathdef:: \xref{syntax/modules}{syntax-importdesc}{\X{importdesc}} +.. |exportdesc| mathdef:: \xref{syntax/modules}{syntax-exportdesc}{\X{exportdesc}} +.. |elem| mathdef:: \xref{syntax/modules}{syntax-elem}{\X{elem}} +.. |elemmode| mathdef:: \xref{syntax/modules}{syntax-elemmode}{\X{elemmode}} +.. |data| mathdef:: \xref{syntax/modules}{syntax-data}{\X{data}} +.. |datamode| mathdef:: \xref{syntax/modules}{syntax-datamode}{\X{datamode}} +.. |start| mathdef:: \xref{syntax/modules}{syntax-start}{\X{start}} + + +.. Modules, meta functions + +.. |edfuncs| mathdef:: \xref{syntax/modules}{syntax-exportdesc}{\F{funcs}} +.. |edtables| mathdef:: \xref{syntax/modules}{syntax-exportdesc}{\F{tables}} +.. |edmems| mathdef:: \xref{syntax/modules}{syntax-exportdesc}{\F{mems}} +.. |edtags| mathdef:: \xref{syntax/modules}{syntax-exportdesc}{\F{tags}} +.. |edglobals| mathdef:: \xref{syntax/modules}{syntax-exportdesc}{\F{globals}} + + +.. Instructions, terminals + +.. |OFFSET| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{offset}} +.. |ALIGN| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{align}} + +.. |UNREACHABLE| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{unreachable}} +.. |NOP| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{nop}} +.. |BLOCK| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{block}} +.. |LOOP| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{loop}} +.. |IF| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{if}} +.. |ELSE| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{else}} +.. |END| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{end}} +.. |BR| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{br}} +.. |BRIF| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{br\_if}} +.. |BRTABLE| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{br\_table}} +.. |RETURN| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{return}} +.. |CALL| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{call}} +.. |CALLINDIRECT| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{call\_indirect}} +.. |TRYTABLE| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{try\_table}} +.. |TRY| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{try}} +.. |CATCH| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{catch}} +.. |CATCHREF| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{catch\_ref}} +.. |CATCHALL| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{catch\_all}} +.. |CATCHALLREF| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{catch\_all\_ref}} +.. |DELEGATE| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{delegate}} +.. |THROW| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{throw}} +.. |THROWREF| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{throw\_ref}} +.. |RETHROW| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{rethrow}} + +.. |DROP| mathdef:: \xref{syntax/instructions}{syntax-instr-parametric}{\K{drop}} +.. |SELECT| mathdef:: \xref{syntax/instructions}{syntax-instr-parametric}{\K{select}} + +.. |LOCALGET| mathdef:: \xref{syntax/instructions}{syntax-instr-variable}{\K{local.get}} +.. |LOCALSET| mathdef:: \xref{syntax/instructions}{syntax-instr-variable}{\K{local.set}} +.. |LOCALTEE| mathdef:: \xref{syntax/instructions}{syntax-instr-variable}{\K{local.tee}} +.. |GLOBALGET| mathdef:: \xref{syntax/instructions}{syntax-instr-variable}{\K{global.get}} +.. |GLOBALSET| mathdef:: \xref{syntax/instructions}{syntax-instr-variable}{\K{global.set}} + +.. |TABLEGET| mathdef:: \xref{syntax/instructions}{syntax-instr-table}{\K{table.get}} +.. |TABLESET| mathdef:: \xref{syntax/instructions}{syntax-instr-table}{\K{table.set}} +.. |TABLESIZE| mathdef:: \xref{syntax/instructions}{syntax-instr-table}{\K{table.size}} +.. |TABLEGROW| mathdef:: \xref{syntax/instructions}{syntax-instr-table}{\K{table.grow}} +.. |TABLEFILL| mathdef:: \xref{syntax/instructions}{syntax-instr-table}{\K{table.fill}} +.. |TABLECOPY| mathdef:: \xref{syntax/instructions}{syntax-instr-table}{\K{table.copy}} +.. |TABLEINIT| mathdef:: \xref{syntax/instructions}{syntax-instr-table}{\K{table.init}} +.. |ELEMDROP| mathdef:: \xref{syntax/instructions}{syntax-instr-table}{\K{elem.drop}} + +.. |LOAD| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{load}} +.. |STORE| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{store}} +.. |MEMORYSIZE| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{memory.size}} +.. |MEMORYGROW| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{memory.grow}} +.. |MEMORYFILL| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{memory.fill}} +.. |MEMORYCOPY| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{memory.copy}} +.. |MEMORYINIT| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{memory.init}} +.. |DATADROP| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{data.drop}} + +.. |REFNULL| mathdef:: \xref{syntax/instructions}{syntax-instr-ref}{\K{ref{.}null}} +.. |REFISNULL| mathdef:: \xref{syntax/instructions}{syntax-instr-ref}{\K{ref{.}is\_null}} +.. |REFFUNC| mathdef:: \xref{syntax/instructions}{syntax-instr-ref}{\K{ref{.}func}} + +.. |CONST| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{const}} +.. |EQZ| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{eqz}} +.. |EQ| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{eq}} +.. |NE| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{ne}} +.. |LT| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{lt}} +.. |GT| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{gt}} +.. |LE| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{le}} +.. |GE| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{ge}} +.. |CLZ| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{clz}} +.. |CTZ| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{ctz}} +.. |POPCNT| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{popcnt}} +.. |ABS| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{abs}} +.. |NEG| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{neg}} +.. |CEIL| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{ceil}} +.. |FLOOR| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{floor}} +.. |TRUNC| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{trunc}} +.. |NEAREST| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{nearest}} +.. |SQRT| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{sqrt}} +.. |ADD| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{add}} +.. |SUB| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{sub}} +.. |MUL| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{mul}} +.. |DIV| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{div}} +.. |REM| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{rem}} +.. |FMIN| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{min}} +.. |FMAX| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{max}} +.. |AND| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{and}} +.. |OR| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{or}} +.. |XOR| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{xor}} +.. |SHL| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{shl}} +.. |SHR| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{shr}} +.. |ROTL| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{rotl}} +.. |ROTR| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{rotr}} +.. |COPYSIGN| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{copysign}} + +.. |CONVERT| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{convert}} +.. |EXTEND| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{extend}} +.. |WRAP| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{wrap}} +.. |PROMOTE| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{promote}} +.. |DEMOTE| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{demote}} +.. |REINTERPRET| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{reinterpret}} + +.. |VCONST| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{const}} +.. |SHUFFLE| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{shuffle}} +.. |SWIZZLE| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{swizzle}} +.. |SPLAT| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{splat}} +.. |EXTRACTLANE| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{extract\_lane}} +.. |REPLACELANE| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{replace\_lane}} +.. |VNOT| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{not}} +.. |VAND| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{and}} +.. |VANDNOT| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{andnot}} +.. |VOR| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{or}} +.. |VXOR| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{xor}} +.. |BITSELECT| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{bitselect}} +.. |VEQ| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{eq}} +.. |VNE| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{ne}} +.. |VLT| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{lt}} +.. |VGT| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{gt}} +.. |VLE| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{le}} +.. |VGE| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{ge}} +.. |VABS| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{abs}} +.. |VNEG| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{neg}} +.. |VCEIL| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{ceil}} +.. |VFLOOR| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{floor}} +.. |VTRUNC| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{trunc}} +.. |VNEAREST| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{nearest}} +.. |VPOPCNT| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{popcnt}} +.. |ANYTRUE| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{any\_true}} +.. |ALLTRUE| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{all\_true}} +.. |BITMASK| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{bitmask}} +.. |VSHL| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{shl}} +.. |VSHR| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{shr}} +.. |VSQRT| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{sqrt}} +.. |VADD| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{add}} +.. |VSUB| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{sub}} +.. |VMUL| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{mul}} +.. |VDIV| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{div}} +.. |VMIN| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{min}} +.. |VMAX| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{max}} +.. |VPMIN| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{pmin}} +.. |VPMAX| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{pmax}} +.. |NARROW| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{narrow}} +.. |VEXTEND| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{extend}} +.. |AVGR| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{avgr}} +.. |DOT| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{dot}} +.. |EXTMUL| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{extmul}} +.. |VCONVERT| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{convert}} +.. |Q15MULRSAT| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{q15mulr\_sat}} +.. |EXTADDPAIRWISE| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{extadd\_pairwise}} +.. |VDEMOTE| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{demote}} +.. |VPROMOTE| mathdef:: \xref{syntax/instructions}{syntax-instr-vec}{\K{promote}} + + +.. Instructions, non-terminals + +.. |unop| mathdef:: \xref{syntax/instructions}{syntax-unop}{\X{unop}} +.. |binop| mathdef:: \xref{syntax/instructions}{syntax-binop}{\X{binop}} +.. |testop| mathdef:: \xref{syntax/instructions}{syntax-testop}{\X{testop}} +.. |relop| mathdef:: \xref{syntax/instructions}{syntax-relop}{\X{relop}} +.. |cvtop| mathdef:: \xref{syntax/instructions}{syntax-cvtop}{\X{cvtop}} + +.. |iunop| mathdef:: \xref{syntax/instructions}{syntax-iunop}{\X{iunop}} +.. |ibinop| mathdef:: \xref{syntax/instructions}{syntax-ibinop}{\X{ibinop}} +.. |itestop| mathdef:: \xref{syntax/instructions}{syntax-itestop}{\X{itestop}} +.. |irelop| mathdef:: \xref{syntax/instructions}{syntax-irelop}{\X{irelop}} + +.. |funop| mathdef:: \xref{syntax/instructions}{syntax-funop}{\X{funop}} +.. |fbinop| mathdef:: \xref{syntax/instructions}{syntax-fbinop}{\X{fbinop}} +.. |ftestop| mathdef:: \xref{syntax/instructions}{syntax-ftestop}{\X{ftestop}} +.. |frelop| mathdef:: \xref{syntax/instructions}{syntax-frelop}{\X{frelop}} + +.. |ishape| mathdef:: \xref{syntax/instructions}{syntax-shape}{\X{ishape}} +.. |fshape| mathdef:: \xref{syntax/instructions}{syntax-shape}{\X{fshape}} +.. |shape| mathdef:: \xref{syntax/instructions}{syntax-shape}{\X{shape}} + +.. |vunop| mathdef:: \xref{syntax/instructions}{syntax-vunop}{\X{vunop}} +.. |vbinop| mathdef:: \xref{syntax/instructions}{syntax-vbinop}{\X{vbinop}} +.. |vrelop| mathdef:: \xref{syntax/instructions}{syntax-vrelop}{\X{vrelop}} +.. |vternop| mathdef:: \xref{syntax/instructions}{syntax-vternop}{\X{vternop}} +.. |vcvtop| mathdef:: \xref{syntax/instructions}{syntax-vcvtop}{\X{vcvtop}} +.. |vextmul| mathdef:: \xref{syntax/instructions}{syntax-vextmul}{\X{vextmul}} + +.. |laneidx| mathdef:: \xref{syntax/instructions}{syntax-laneidx}{\X{laneidx}} +.. |vvunop| mathdef:: \xref{syntax/instructions}{syntax-vvunop}{\X{vvunop}} +.. |vvbinop| mathdef:: \xref{syntax/instructions}{syntax-vvbinop}{\X{vvbinop}} +.. |vvternop| mathdef:: \xref{syntax/instructions}{syntax-vvternop}{\X{vvternop}} +.. |vvtestop| mathdef:: \xref{syntax/instructions}{syntax-vvtestop}{\X{vvtestop}} +.. |vishiftop| mathdef:: \xref{syntax/instructions}{syntax-vishiftop}{\X{vishiftop}} +.. |viunop| mathdef:: \xref{syntax/instructions}{syntax-viunop}{\X{viunop}} +.. |vibinop| mathdef:: \xref{syntax/instructions}{syntax-vibinop}{\X{vibinop}} +.. |viminmaxop| mathdef:: \xref{syntax/instructions}{syntax-viminmaxop}{\X{viminmaxop}} +.. |visatbinop| mathdef:: \xref{syntax/instructions}{syntax-visatbinop}{\X{visatbinop}} +.. |vfunop| mathdef:: \xref{syntax/instructions}{syntax-vfunop}{\X{vfunop}} +.. |vfbinop| mathdef:: \xref{syntax/instructions}{syntax-vfbinop}{\X{vfbinop}} +.. |virelop| mathdef:: \xref{syntax/instructions}{syntax-virelop}{\X{virelop}} +.. |vfrelop| mathdef:: \xref{syntax/instructions}{syntax-vfrelop}{\X{vfrelop}} +.. |vitestop| mathdef:: \xref{syntax/instructions}{syntax-vitestop}{\X{vitestop}} +.. |vtestop| mathdef:: \xref{syntax/instructions}{syntax-vtestop}{\X{vtestop}} + +.. |sx| mathdef:: \xref{syntax/instructions}{syntax-sx}{\X{sx}} +.. |half| mathdef:: \xref{syntax/instructions}{syntax-half}{\X{half}} +.. |memarg| mathdef:: \xref{syntax/instructions}{syntax-memarg}{\X{memarg}} + +.. |blocktype| mathdef:: \xref{syntax/instructions}{syntax-blocktype}{\X{blocktype}} + +.. |instr| mathdef:: \xref{syntax/instructions}{syntax-instr}{\X{instr}} +.. |catch| mathdef:: \xref{syntax/instructions}{syntax-catch}{\X{catch}} +.. |expr| mathdef:: \xref{syntax/instructions}{syntax-expr}{\X{expr}} + + + +.. Binary Format +.. ------------- + +.. Auxiliary productions + +.. |Bvec| mathdef:: \xref{binary/conventions}{binary-vec}{\B{vec}} + + +.. Values, non-terminals + +.. |Bbyte| mathdef:: \xref{binary/values}{binary-byte}{\B{byte}} + +.. |BuX#1| mathdef:: {\B{u}#1} +.. |BsX#1| mathdef:: {\B{s}#1} +.. |BiX#1| mathdef:: {\B{i}#1} +.. |BfX#1| mathdef:: {\B{f}#1} + +.. |BuN| mathdef:: \xref{binary/values}{binary-int}{\BuX{N}} +.. |Bu1| mathdef:: \xref{binary/values}{binary-int}{\BuX{\B{1}}} +.. |Bu8| mathdef:: \xref{binary/values}{binary-int}{\BuX{\B{8}}} +.. |Bu16| mathdef:: \xref{binary/values}{binary-int}{\BuX{\B{16}}} +.. |Bu32| mathdef:: \xref{binary/values}{binary-int}{\BuX{\B{32}}} +.. |Bu64| mathdef:: \xref{binary/values}{binary-int}{\BuX{\B{64}}} + +.. |BsN| mathdef:: \xref{binary/values}{binary-int}{\BsX{N}} +.. |Bs7| mathdef:: \xref{binary/values}{binary-int}{\BsX{\B{7}}} +.. |Bs32| mathdef:: \xref{binary/values}{binary-int}{\BsX{\B{32}}} +.. |Bs33| mathdef:: \xref{binary/values}{binary-int}{\BsX{\B{33}}} +.. |Bs64| mathdef:: \xref{binary/values}{binary-int}{\BsX{\B{64}}} + +.. |BiN| mathdef:: \xref{binary/values}{binary-int}{\BiX{N}} +.. |Bi32| mathdef:: \xref{binary/values}{binary-int}{\BiX{\B{32}}} +.. |Bi64| mathdef:: \xref{binary/values}{binary-int}{\BiX{\B{64}}} + +.. |BfN| mathdef:: \xref{binary/values}{binary-float}{\BfX{N}} +.. |Bf32| mathdef:: \xref{binary/values}{binary-float}{\BfX{\B{32}}} +.. |Bf64| mathdef:: \xref{binary/values}{binary-float}{\BfX{\B{64}}} + +.. |Bname| mathdef:: \xref{binary/values}{binary-name}{\B{name}} + + +.. Values, meta functions + +.. |utf8| mathdef:: \xref{binary/values}{binary-utf8}{\F{utf8}} + + +.. Types, non-terminals + +.. |Bnumtype| mathdef:: \xref{binary/types}{binary-numtype}{\B{numtype}} +.. |Bvectype| mathdef:: \xref{binary/types}{binary-vectype}{\B{vectype}} +.. |Breftype| mathdef:: \xref{binary/types}{binary-reftype}{\B{reftype}} +.. |Bvaltype| mathdef:: \xref{binary/types}{binary-valtype}{\B{valtype}} +.. |Bresulttype| mathdef:: \xref{binary/types}{binary-resulttype}{\B{resulttype}} +.. |Bfunctype| mathdef:: \xref{binary/types}{binary-functype}{\B{functype}} +.. |Bglobaltype| mathdef:: \xref{binary/types}{binary-globaltype}{\B{globaltype}} +.. |Btagtype| mathdef:: \xref{binary/types}{binary-tagtype}{\B{tagtype}} +.. |Btabletype| mathdef:: \xref{binary/types}{binary-tabletype}{\B{tabletype}} +.. |Bmemtype| mathdef:: \xref{binary/types}{binary-memtype}{\B{memtype}} +.. |Blimits| mathdef:: \xref{binary/types}{binary-limits}{\B{limits}} +.. |Bmut| mathdef:: \xref{binary/types}{binary-mut}{\B{mut}} + + +.. Indices, non-terminals + +.. |Bidx| mathdef:: \xref{binary/modules}{binary-index}{\B{idx}} +.. |Btypeidx| mathdef:: \xref{binary/modules}{binary-typeidx}{\B{typeidx}} +.. |Bfuncidx| mathdef:: \xref{binary/modules}{binary-funcidx}{\B{funcidx}} +.. |Btableidx| mathdef:: \xref{binary/modules}{binary-tableidx}{\B{tableidx}} +.. |Bmemidx| mathdef:: \xref{binary/modules}{binary-memidx}{\B{memidx}} +.. |Btagidx| mathdef:: \xref{binary/modules}{binary-tagidx}{\B{tagidx}} +.. |Bglobalidx| mathdef:: \xref{binary/modules}{binary-globalidx}{\B{globalidx}} +.. |Belemidx| mathdef:: \xref{binary/modules}{binary-elemidx}{\B{elemidx}} +.. |Bdataidx| mathdef:: \xref{binary/modules}{binary-dataidx}{\B{dataidx}} +.. |Blocalidx| mathdef:: \xref{binary/modules}{binary-localidx}{\B{localidx}} +.. |Blabelidx| mathdef:: \xref{binary/modules}{binary-labelidx}{\B{labelidx}} + + +.. Modules, non-terminals + +.. |Bmagic| mathdef:: \xref{binary/modules}{binary-magic}{\B{magic}} +.. |Bversion| mathdef:: \xref{binary/modules}{binary-version}{\B{version}} +.. |Bmodule| mathdef:: \xref{binary/modules}{binary-module}{\B{module}} + +.. |Bsection| mathdef:: \xref{binary/modules}{binary-section}{\B{section}} +.. |Bcustomsec| mathdef:: \xref{binary/modules}{binary-customsec}{\B{customsec}} +.. |Btypesec| mathdef:: \xref{binary/modules}{binary-typesec}{\B{typesec}} +.. |Bfuncsec| mathdef:: \xref{binary/modules}{binary-funcsec}{\B{funcsec}} +.. |Bcodesec| mathdef:: \xref{binary/modules}{binary-codesec}{\B{codesec}} +.. |Btablesec| mathdef:: \xref{binary/modules}{binary-tablesec}{\B{tablesec}} +.. |Bmemsec| mathdef:: \xref{binary/modules}{binary-memsec}{\B{memsec}} +.. |Btagsec| mathdef:: \xref{binary/modules}{binary-tagsec}{\B{tagsec}} +.. |Bglobalsec| mathdef:: \xref{binary/modules}{binary-globalsec}{\B{globalsec}} +.. |Bimportsec| mathdef:: \xref{binary/modules}{binary-importsec}{\B{importsec}} +.. |Bexportsec| mathdef:: \xref{binary/modules}{binary-exportsec}{\B{exportsec}} +.. |Belemsec| mathdef:: \xref{binary/modules}{binary-elemsec}{\B{elemsec}} +.. |Bdatasec| mathdef:: \xref{binary/modules}{binary-datasec}{\B{datasec}} +.. |Bstartsec| mathdef:: \xref{binary/modules}{binary-startsec}{\B{startsec}} +.. |Bdatacountsec| mathdef:: \xref{binary/modules}{binary-datacountsec}{\B{datacountsec}} + +.. |Bcustom| mathdef:: \xref{binary/modules}{binary-customsec}{\B{custom}} +.. |Btype| mathdef:: \xref{binary/modules}{binary-typedef}{\B{type}} +.. |Bfunc| mathdef:: \xref{binary/modules}{binary-func}{\B{func}} +.. |Btable| mathdef:: \xref{binary/modules}{binary-table}{\B{table}} +.. |Bmem| mathdef:: \xref{binary/modules}{binary-mem}{\B{mem}} +.. |Btag| mathdef:: \xref{binary/modules}{binary-tag}{\B{tag}} +.. |Bglobal| mathdef:: \xref{binary/modules}{binary-global}{\B{global}} +.. |Bimport| mathdef:: \xref{binary/modules}{binary-import}{\B{import}} +.. |Bexport| mathdef:: \xref{binary/modules}{binary-export}{\B{export}} +.. |Bimportdesc| mathdef:: \xref{binary/modules}{binary-importdesc}{\B{importdesc}} +.. |Bexportdesc| mathdef:: \xref{binary/modules}{binary-exportdesc}{\B{exportdesc}} +.. |Belem| mathdef:: \xref{binary/modules}{binary-elem}{\B{elem}} +.. |Belemkind| mathdef:: \xref{binary/modules}{binary-elemkind}{\B{elemkind}} +.. |Bcode| mathdef:: \xref{binary/modules}{binary-code}{\B{code}} +.. |Blocal| mathdef:: \xref{binary/modules}{binary-local}{\B{local}} +.. |Blocals| mathdef:: \xref{binary/modules}{binary-local}{\B{locals}} +.. |Bdata| mathdef:: \xref{binary/modules}{binary-data}{\B{data}} +.. |Bstart| mathdef:: \xref{binary/modules}{binary-start}{\B{start}} + + +.. Instructions, non-terminals + +.. |Bmemarg| mathdef:: \xref{binary/instructions}{binary-memarg}{\B{memarg}} +.. |Bblocktype| mathdef:: \xref{binary/instructions}{binary-blocktype}{\B{blocktype}} + +.. |Binstr| mathdef:: \xref{binary/instructions}{binary-instr}{\B{instr}} +.. |Bcatch| mathdef:: \xref{binary/instructions}{binary-catch}{\B{catch}} +.. |Bexpr| mathdef:: \xref{binary/instructions}{binary-expr}{\B{expr}} + +.. |Blaneidx| mathdef:: \xref{binary/instructions}{binary-laneidx}{\B{laneidx}} + + +.. Text Format +.. ----------- + +.. Auxiliary productions + +.. |Tvec| mathdef:: \xref{text/conventions}{text-vec}{\T{vec}} + + +.. Lexical grammar, terminals + +.. |textl| mathdef:: \mbox{‘} +.. |textr| mathdef:: \mbox{’} +.. |text#1| mathdef:: \textl\mathtt{#1}\textr + +.. |Tcommentl| mathdef:: \text{{(}{;}} +.. |Tcommentr| mathdef:: \text{{;}{)}} +.. |Tcommentd| mathdef:: \text{{;}{;}} + + +.. Lexical grammar, non-terminals + +.. |Tsource| mathdef:: \xref{text/lexical}{text-source}{\T{source}} +.. |Tchar| mathdef:: \xref{text/lexical}{text-char}{\T{char}} +.. |Tspace| mathdef:: \xref{text/lexical}{text-space}{\T{space}} +.. |Tformat| mathdef:: \xref{text/lexical}{text-format}{\T{format}} + +.. |Ttoken| mathdef:: \xref{text/lexical}{text-token}{\T{token}} +.. |Tkeyword| mathdef:: \xref{text/lexical}{text-keyword}{\T{keyword}} +.. |Treserved| mathdef:: \xref{text/lexical}{text-reserved}{\T{reserved}} + +.. |Tcomment| mathdef:: \xref{text/lexical}{text-comment}{\T{comment}} +.. |Tlinecomment| mathdef:: \xref{text/lexical}{text-comment}{\T{linecomment}} +.. |Tblockcomment| mathdef:: \xref{text/lexical}{text-comment}{\T{blockcomment}} +.. |Tlinechar| mathdef:: \xref{text/lexical}{text-comment}{\T{linechar}} +.. |Tblockchar| mathdef:: \xref{text/lexical}{text-comment}{\T{blockchar}} + + +.. Values, non-terminals + +.. |Tsign| mathdef:: \xref{text/values}{text-sign}{\T{sign}} +.. |Tdigit| mathdef:: \xref{text/values}{text-digit}{\T{digit}} +.. |Thexdigit| mathdef:: \xref{text/values}{text-hexdigit}{\T{hexdigit}} +.. |Tnum| mathdef:: \xref{text/values}{text-num}{\T{num}} +.. |Thexnum| mathdef:: \xref{text/values}{text-hexnum}{\T{hexnum}} +.. |Tfrac| mathdef:: \xref{text/values}{text-frac}{\T{frac}} +.. |Thexfrac| mathdef:: \xref{text/values}{text-hexfrac}{\T{hexfrac}} +.. |Tfloat| mathdef:: \xref{text/values}{text-float}{\T{float}} +.. |Thexfloat| mathdef:: \xref{text/values}{text-hexfloat}{\T{hexfloat}} + +.. |TuX#1| mathdef:: {\T{u}#1} +.. |TsX#1| mathdef:: {\T{s}#1} +.. |TiX#1| mathdef:: {\T{i}#1} +.. |TfX#1| mathdef:: {\T{f}#1} + +.. |TuN| mathdef:: \xref{text/values}{text-int}{\TuX{N}} +.. |Tu1| mathdef:: \xref{text/values}{text-int}{\TuX{\T{1}}} +.. |Tu8| mathdef:: \xref{text/values}{text-int}{\TuX{\T{8}}} +.. |Tu16| mathdef:: \xref{text/values}{text-int}{\TuX{\T{16}}} +.. |Tu32| mathdef:: \xref{text/values}{text-int}{\TuX{\T{32}}} +.. |Tu64| mathdef:: \xref{text/values}{text-int}{\TuX{\T{64}}} + +.. |TsN| mathdef:: \xref{text/values}{text-int}{\TsX{N}} +.. |Ts32| mathdef:: \xref{text/values}{text-int}{\TsX{\T{32}}} +.. |Ts64| mathdef:: \xref{text/values}{text-int}{\TsX{\T{64}}} + +.. |TiN| mathdef:: \xref{text/values}{text-int}{\TiX{N}} +.. |Ti8| mathdef:: \xref{text/values}{text-int}{\TiX{\T{8}}} +.. |Ti16| mathdef:: \xref{text/values}{text-int}{\TiX{\T{16}}} +.. |Ti32| mathdef:: \xref{text/values}{text-int}{\TiX{\T{32}}} +.. |Ti64| mathdef:: \xref{text/values}{text-int}{\TiX{\T{64}}} + +.. |TfN| mathdef:: \xref{text/values}{text-float}{\TfX{N}} +.. |TfNmag| mathdef:: \xref{text/values}{text-float}{\TfX{N}\T{mag}} +.. |Tf32| mathdef:: \xref{text/values}{text-float}{\TfX{\T{32}}} +.. |Tf64| mathdef:: \xref{text/values}{text-float}{\TfX{\T{64}}} + +.. |Tstring| mathdef:: \xref{text/values}{text-string}{\T{string}} +.. |Tstringelem| mathdef:: \xref{text/values}{text-string}{\T{stringelem}} +.. |Tstringchar| mathdef:: \xref{text/values}{text-string}{\T{stringchar}} +.. |Tname| mathdef:: \xref{text/values}{text-name}{\T{name}} + +.. |Tid| mathdef:: \xref{text/values}{text-id}{\T{id}} +.. |Tidchar| mathdef:: \xref{text/values}{text-idchar}{\T{idchar}} + + +.. Types, non-terminals + +.. |Tnumtype| mathdef:: \xref{text/types}{text-numtype}{\T{numtype}} +.. |Tvectype| mathdef:: \xref{text/types}{text-vectype}{\T{vectype}} +.. |Treftype| mathdef:: \xref{text/types}{text-reftype}{\T{reftype}} +.. |Theaptype| mathdef:: \xref{text/types}{text-heaptype}{\T{heaptype}} +.. |Tvaltype| mathdef:: \xref{text/types}{text-valtype}{\T{valtype}} +.. |Tfunctype| mathdef:: \xref{text/types}{text-functype}{\T{functype}} + +.. |Tglobaltype| mathdef:: \xref{text/types}{text-globaltype}{\T{globaltype}} +.. |Ttabletype| mathdef:: \xref{text/types}{text-tabletype}{\T{tabletype}} +.. |Tmemtype| mathdef:: \xref{text/types}{text-memtype}{\T{memtype}} +.. |Tlimits| mathdef:: \xref{text/types}{text-limits}{\T{limits}} + +.. |Tparam| mathdef:: \xref{text/types}{text-functype}{\T{param}} +.. |Tresult| mathdef:: \xref{text/types}{text-functype}{\T{result}} + + +.. Indices, non-terminals + +.. |Ttypeidx| mathdef:: \xref{text/modules}{text-typeidx}{\T{typeidx}} +.. |Tfuncidx| mathdef:: \xref{text/modules}{text-funcidx}{\T{funcidx}} +.. |Ttableidx| mathdef:: \xref{text/modules}{text-tableidx}{\T{tableidx}} +.. |Tmemidx| mathdef:: \xref{text/modules}{text-memidx}{\T{memidx}} +.. |Ttagidx| mathdef:: \xref{text/modules}{text-tagidx}{\T{tagidx}} +.. |Tglobalidx| mathdef:: \xref{text/modules}{text-globalidx}{\T{globalidx}} +.. |Telemidx| mathdef:: \xref{text/modules}{text-elemidx}{\T{elemidx}} +.. |Tdataidx| mathdef:: \xref{text/modules}{text-dataidx}{\T{dataidx}} +.. |Tlocalidx| mathdef:: \xref{text/modules}{text-localidx}{\T{localidx}} +.. |Tlabelidx| mathdef:: \xref{text/modules}{text-labelidx}{\T{labelidx}} + +.. |Ttypebind| mathdef:: \xref{text/modules}{text-typebind}{\T{typebind}} +.. |Tfuncbind| mathdef:: \xref{text/modules}{text-funcbind}{\T{funcbind}} +.. |Ttablebind| mathdef:: \xref{text/modules}{text-tablebind}{\T{tablebind}} +.. |Tmembind| mathdef:: \xref{text/modules}{text-membind}{\T{membind}} +.. |Tglobalbind| mathdef:: \xref{text/modules}{text-globalbind}{\T{globalbind}} +.. |Tlocalbind| mathdef:: \xref{text/modules}{text-localbind}{\T{localbind}} +.. |Tlabelbind| mathdef:: \xref{text/modules}{text-labelbind}{\T{labelbind}} + + +.. Modules, non-terminals + +.. |Tmodule| mathdef:: \xref{text/modules}{text-module}{\T{module}} +.. |Tmodulebody| mathdef:: \xref{text/modules}{text-modulebody}{\T{modulebody}} +.. |Tmodulefield| mathdef:: \xref{text/modules}{text-modulefield}{\T{modulefield}} +.. |Ttype| mathdef:: \xref{text/modules}{text-typedef}{\T{type}} +.. |Ttypeuse| mathdef:: \xref{text/modules}{text-typeuse}{\T{typeuse}} +.. |Tfunc| mathdef:: \xref{text/modules}{text-func}{\T{func}} +.. |Ttable| mathdef:: \xref{text/modules}{text-table}{\T{table}} +.. |Tmem| mathdef:: \xref{text/modules}{text-mem}{\T{mem}} +.. |Ttag| mathdef:: \xref{text/modules}{text-tag}{\T{tag}} +.. |Tglobal| mathdef:: \xref{text/modules}{text-global}{\T{global}} +.. |Timport| mathdef:: \xref{text/modules}{text-import}{\T{import}} +.. |Texport| mathdef:: \xref{text/modules}{text-export}{\T{export}} +.. |Timportdesc| mathdef:: \xref{text/modules}{text-importdesc}{\T{importdesc}} +.. |Texportdesc| mathdef:: \xref{text/modules}{text-exportdesc}{\T{exportdesc}} +.. |Telem| mathdef:: \xref{text/modules}{text-elem}{\T{elem}} +.. |Telemlist| mathdef:: \xref{text/modules}{text-elemlist}{\T{elemlist}} +.. |Telemexpr| mathdef:: \xref{text/modules}{text-elemexpr}{\T{elemexpr}} +.. |Ttableuse| mathdef:: \xref{text/modules}{text-tableuse}{\T{tableuse}} +.. |Tcode| mathdef:: \xref{text/modules}{text-code}{\T{code}} +.. |Tlocal| mathdef:: \xref{text/modules}{text-local}{\T{local}} +.. |Tlocals| mathdef:: \xref{text/modules}{text-local}{\T{locals}} +.. |Tdata| mathdef:: \xref{text/modules}{text-data}{\T{data}} +.. |Tdatastring| mathdef:: \xref{text/modules}{text-datastring}{\T{datastring}} +.. |Tmemuse| mathdef:: \xref{text/modules}{text-memuse}{\T{memuse}} +.. |Tstart| mathdef:: \xref{text/modules}{text-start}{\T{start}} + + +.. Instructions, non-terminals + +.. |Tmemarg| mathdef:: \xref{text/instructions}{text-memarg}{\T{memarg}} +.. |Talign| mathdef:: \xref{text/instructions}{text-memarg}{\T{align}} +.. |Toffset| mathdef:: \xref{text/instructions}{text-memarg}{\T{offset}} + +.. |Tblocktype| mathdef:: \xref{text/instructions}{text-blocktype}{\T{blocktype}} + +.. |Tlabel| mathdef:: \xref{text/instructions}{text-label}{\T{label}} +.. |Tinstr| mathdef:: \xref{text/instructions}{text-instr}{\T{instr}} +.. |Tplaininstr| mathdef:: \xref{text/instructions}{text-plaininstr}{\T{plaininstr}} +.. |Tblockinstr| mathdef:: \xref{text/instructions}{text-blockinstr}{\T{blockinstr}} +.. |Tfoldedinstr| mathdef:: \xref{text/instructions}{text-foldedinstr}{\T{foldedinstr}} +.. |Tcatch| mathdef:: \xref{text/instructions}{text-catch}{\T{catch}} +.. |Texpr| mathdef:: \xref{text/instructions}{text-expr}{\T{expr}} + + + +.. Parsing +.. ------- + +.. Contexts + +.. |ITYPEDEFS| mathdef:: \xref{text/conventions}{text-context}{\K{typedefs}} +.. |ITYPES| mathdef:: \xref{text/conventions}{text-context}{\K{types}} +.. |IFUNCS| mathdef:: \xref{text/conventions}{text-context}{\K{funcs}} +.. |ITABLES| mathdef:: \xref{text/conventions}{text-context}{\K{tables}} +.. |IMEMS| mathdef:: \xref{text/conventions}{text-context}{\K{mems}} +.. |ITAGS| mathdef:: \xref{text/conventions}{text-context}{\K{tags}} +.. |IGLOBALS| mathdef:: \xref{text/conventions}{text-context}{\K{globals}} +.. |IELEM| mathdef:: \xref{text/conventions}{text-context}{\K{elem}} +.. |IDATA| mathdef:: \xref{text/conventions}{text-context}{\K{data}} +.. |ILOCALS| mathdef:: \xref{text/conventions}{text-context}{\K{locals}} +.. |ILABELS| mathdef:: \xref{text/conventions}{text-context}{\K{labels}} + + +.. Meta Functions + +.. |idfresh| mathdef:: ~\xref{text/values}{text-id-fresh}{\mbox{fresh}} +.. |idcwellformed| mathdef:: ~\xref{text/conventions}{text-context-wf}{\mbox{well-formed}} + + + + +.. Validation +.. ---------- + +.. Notation + +.. |ok| mathdef:: \mathrel{\mbox{ok}} +.. |const| mathdef:: \xref{valid/instructions}{valid-constant}{\mathrel{\mbox{const}}} + +.. Contexts, terminals + +.. |CTYPES| mathdef:: \xref{valid/conventions}{context}{\K{types}} +.. |CFUNCS| mathdef:: \xref{valid/conventions}{context}{\K{funcs}} +.. |CTABLES| mathdef:: \xref{valid/conventions}{context}{\K{tables}} +.. |CMEMS| mathdef:: \xref{valid/conventions}{context}{\K{mems}} +.. |CTAGS| mathdef:: \xref{valid/conventions}{context}{\K{tags}} +.. |CGLOBALS| mathdef:: \xref{valid/conventions}{context}{\K{globals}} +.. |CELEMS| mathdef:: \xref{valid/conventions}{context}{\K{elems}} +.. |CDATAS| mathdef:: \xref{valid/conventions}{context}{\K{datas}} +.. |CLOCALS| mathdef:: \xref{valid/conventions}{context}{\K{locals}} +.. |CLABELS| mathdef:: \xref{valid/conventions}{context}{\K{labels}} +.. |CRETURN| mathdef:: \xref{valid/conventions}{context}{\K{return}} +.. |CREFS| mathdef:: \xref{valid/conventions}{context}{\K{refs}} +.. |LCATCH| mathdef:: \xref{valid/conventions}{context}{\K{catch}} + +.. Contexts, non-terminals + +.. |labeltype| mathdef:: \xref{valid/conventions}{context}{\X{labeltype}} + + +.. Judgments + +.. |vdashlimits| mathdef:: \xref{valid/types}{valid-limits}{\vdash} +.. |vdashblocktype| mathdef:: \xref{valid/types}{valid-blocktype}{\vdash} +.. |vdashfunctype| mathdef:: \xref{valid/types}{valid-functype}{\vdash} +.. |vdashtabletype| mathdef:: \xref{valid/types}{valid-tabletype}{\vdash} +.. |vdashmemtype| mathdef:: \xref{valid/types}{valid-memtype}{\vdash} +.. |vdashtagtype| mathdef:: \xref{valid/types}{valid-tagtype}{\vdash} +.. |vdashglobaltype| mathdef:: \xref{valid/types}{valid-globaltype}{\vdash} +.. |vdashexterntype| mathdef:: \xref{valid/types}{valid-externtype}{\vdash} + +.. |vdashinstr| mathdef:: \xref{valid/instructions}{valid-instr}{\vdash} +.. |vdashinstrseq| mathdef:: \xref{valid/instructions}{valid-instr-seq}{\vdash} +.. |vdashcatch| mathdef:: \xref{valid/instructions}{valid-catch}{\vdash} +.. |vdashexpr| mathdef:: \xref{valid/instructions}{valid-expr}{\vdash} +.. |vdashexprconst| mathdef:: \xref{valid/instructions}{valid-constant}{\vdash} +.. |vdashinstrconst| mathdef:: \xref{valid/instructions}{valid-constant}{\vdash} + +.. |vdashfunc| mathdef:: \xref{valid/modules}{valid-func}{\vdash} +.. |vdashtable| mathdef:: \xref{valid/modules}{valid-table}{\vdash} +.. |vdashmem| mathdef:: \xref{valid/modules}{valid-mem}{\vdash} +.. |vdashtag| mathdef:: \xref{valid/modules}{valid-tag}{\vdash} +.. |vdashglobal| mathdef:: \xref{valid/modules}{valid-global}{\vdash} +.. |vdashelem| mathdef:: \xref{valid/modules}{valid-elem}{\vdash} +.. |vdashelemmode| mathdef:: \xref{valid/modules}{valid-elemmode}{\vdash} +.. |vdashdata| mathdef:: \xref{valid/modules}{valid-data}{\vdash} +.. |vdashdatamode| mathdef:: \xref{valid/modules}{valid-datamode}{\vdash} +.. |vdashstart| mathdef:: \xref{valid/modules}{valid-start}{\vdash} +.. |vdashexport| mathdef:: \xref{valid/modules}{valid-export}{\vdash} +.. |vdashexportdesc| mathdef:: \xref{valid/modules}{valid-exportdesc}{\vdash} +.. |vdashimport| mathdef:: \xref{valid/modules}{valid-import}{\vdash} +.. |vdashimportdesc| mathdef:: \xref{valid/modules}{valid-importdesc}{\vdash} +.. |vdashmodule| mathdef:: \xref{valid/modules}{valid-module}{\vdash} + +.. |unpacked| mathdef:: \xref{valid/instructions}{aux-unpacked}{\F{unpacked}} +.. |dim| mathdef:: \xref{valid/instructions}{aux-dim}{\F{dim}} + + +.. Execution +.. --------- + +.. Notation + +.. |stepto| mathdef:: \xref{exec/conventions}{formal-notation}{\hookrightarrow} +.. |extendsto| mathdef:: \xref{appendix/properties}{extend}{\preceq} +.. |matchesexterntype| mathdef:: \xref{exec/modules}{match-externtype}{\leq} +.. |matcheslimits| mathdef:: \xref{exec/modules}{match-limits}{\leq} + + +.. Allocation + +.. |allocfunc| mathdef:: \xref{exec/modules}{alloc-func}{\F{allocfunc}} +.. |allochostfunc| mathdef:: \xref{exec/modules}{alloc-hostfunc}{\F{allochostfunc}} +.. |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}} +.. |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}} +.. |allocmodule| mathdef:: \xref{exec/modules}{alloc-module}{\F{allocmodule}} + +.. |growtable| mathdef:: \xref{exec/modules}{grow-table}{\F{growtable}} +.. |growmem| mathdef:: \xref{exec/modules}{grow-mem}{\F{growmem}} + + +.. Addresses, non-terminals + +.. |addr| mathdef:: \xref{exec/runtime}{syntax-addr}{\X{addr}} +.. |funcaddr| mathdef:: \xref{exec/runtime}{syntax-funcaddr}{\X{funcaddr}} +.. |tableaddr| mathdef:: \xref{exec/runtime}{syntax-tableaddr}{\X{tableaddr}} +.. |memaddr| mathdef:: \xref{exec/runtime}{syntax-memaddr}{\X{memaddr}} +.. |tagaddr| mathdef:: \xref{exec/runtime}{syntax-tagaddr}{\X{tagaddr}} +.. |globaladdr| mathdef:: \xref{exec/runtime}{syntax-globaladdr}{\X{globaladdr}} +.. |elemaddr| mathdef:: \xref{exec/runtime}{syntax-elemaddr}{\X{elemaddr}} +.. |dataaddr| mathdef:: \xref{exec/runtime}{syntax-dataaddr}{\X{dataaddr}} +.. |exnaddr| mathdef:: \xref{exec/runtime}{syntax-exnaddr}{\X{exnaddr}} +.. |externaddr| mathdef:: \xref{exec/runtime}{syntax-externaddr}{\X{externaddr}} + +.. Instances, terminals + +.. |FITYPE| mathdef:: \xref{exec/runtime}{syntax-funcinst}{\K{type}} +.. |FIMODULE| mathdef:: \xref{exec/runtime}{syntax-funcinst}{\K{module}} +.. |FICODE| mathdef:: \xref{exec/runtime}{syntax-funcinst}{\K{code}} +.. |FIHOSTCODE| mathdef:: \xref{exec/runtime}{syntax-funcinst}{\K{hostcode}} + +.. |TITYPE| mathdef:: \xref{exec/runtime}{syntax-tableinst}{\K{type}} +.. |TIELEM| mathdef:: \xref{exec/runtime}{syntax-tableinst}{\K{elem}} + +.. |MITYPE| mathdef:: \xref{exec/runtime}{syntax-meminst}{\K{type}} +.. |MIDATA| mathdef:: \xref{exec/runtime}{syntax-meminst}{\K{data}} + +.. |TAGITYPE| mathdef:: \xref{exec/runtime}{syntax-taginst}{\K{type}} + +.. |GITYPE| mathdef:: \xref{exec/runtime}{syntax-globalinst}{\K{type}} +.. |GIVALUE| mathdef:: \xref{exec/runtime}{syntax-globalinst}{\K{value}} + +.. |EITYPE| mathdef:: \xref{exec/runtime}{syntax-eleminst}{\K{type}} +.. |EIELEM| mathdef:: \xref{exec/runtime}{syntax-eleminst}{\K{elem}} + +.. |DIDATA| mathdef:: \xref{exec/runtime}{syntax-datainst}{\K{data}} + +.. |EITAG| mathdef:: \xref{exec/runtime}{syntax-exninst}{\K{tag}} +.. |EIFIELDS| mathdef:: \xref{exec/runtime}{syntax-exninst}{\K{fields}} + +.. |EINAME| mathdef:: \xref{exec/runtime}{syntax-exportinst}{\K{name}} +.. |EIVALUE| mathdef:: \xref{exec/runtime}{syntax-exportinst}{\K{value}} + +.. |EVFUNC| mathdef:: \xref{exec/runtime}{syntax-externval}{\K{func}} +.. |EVTABLE| mathdef:: \xref{exec/runtime}{syntax-externval}{\K{table}} +.. |EVMEM| mathdef:: \xref{exec/runtime}{syntax-externval}{\K{mem}} +.. |EVTAG| mathdef:: \xref{exec/runtime}{syntax-externval}{\K{tag}} +.. |EVGLOBAL| mathdef:: \xref{exec/runtime}{syntax-externval}{\K{global}} + +.. |MITYPES| mathdef:: \xref{exec/runtime}{syntax-moduleinst}{\K{types}} +.. |MIFUNCS| mathdef:: \xref{exec/runtime}{syntax-moduleinst}{\K{funcaddrs}} +.. |MITABLES| mathdef:: \xref{exec/runtime}{syntax-moduleinst}{\K{tableaddrs}} +.. |MIMEMS| mathdef:: \xref{exec/runtime}{syntax-moduleinst}{\K{memaddrs}} +.. |MITAGS| mathdef:: \xref{exec/runtime}{syntax-moduleinst}{\K{tagaddrs}} +.. |MIGLOBALS| mathdef:: \xref{exec/runtime}{syntax-moduleinst}{\K{globaladdrs}} +.. |MIELEMS| mathdef:: \xref{exec/runtime}{syntax-moduleinst}{\K{elemaddrs}} +.. |MIDATAS| mathdef:: \xref{exec/runtime}{syntax-moduleinst}{\K{dataaddrs}} +.. |MIEXPORTS| mathdef:: \xref{exec/runtime}{syntax-moduleinst}{\K{exports}} + + +.. Instances, non-terminals + +.. |externval| mathdef:: \xref{exec/runtime}{syntax-externval}{\X{externval}} + +.. |moduleinst| mathdef:: \xref{exec/runtime}{syntax-moduleinst}{\X{moduleinst}} +.. |funcinst| mathdef:: \xref{exec/runtime}{syntax-funcinst}{\X{funcinst}} +.. |tableinst| mathdef:: \xref{exec/runtime}{syntax-tableinst}{\X{tableinst}} +.. |meminst| mathdef:: \xref{exec/runtime}{syntax-meminst}{\X{meminst}} +.. |taginst| mathdef:: \xref{exec/runtime}{syntax-taginst}{\X{taginst}} +.. |globalinst| mathdef:: \xref{exec/runtime}{syntax-globalinst}{\X{globalinst}} +.. |eleminst| mathdef:: \xref{exec/runtime}{syntax-eleminst}{\X{eleminst}} +.. |datainst| mathdef:: \xref{exec/runtime}{syntax-datainst}{\X{datainst}} +.. |exninst| mathdef:: \xref{exec/runtime}{syntax-exninst}{\X{exninst}} +.. |exportinst| mathdef:: \xref{exec/runtime}{syntax-exportinst}{\X{exportinst}} + +.. |hostfunc| mathdef:: \xref{exec/runtime}{syntax-hostfunc}{\X{hostfunc}} + + +.. Instances, meta functions + +.. |evfuncs| mathdef:: \xref{exec/runtime}{syntax-externval}{\F{funcs}} +.. |evtables| mathdef:: \xref{exec/runtime}{syntax-externval}{\F{tables}} +.. |evmems| mathdef:: \xref{exec/runtime}{syntax-externval}{\F{mems}} +.. |evtags| mathdef:: \xref{exec/runtime}{syntax-externval}{\F{tags}} +.. |evglobals| mathdef:: \xref{exec/runtime}{syntax-externval}{\F{globals}} + + +.. Store, terminals + +.. |SFUNCS| mathdef:: \xref{exec/runtime}{syntax-store}{\K{funcs}} +.. |STABLES| mathdef:: \xref{exec/runtime}{syntax-store}{\K{tables}} +.. |SMEMS| mathdef:: \xref{exec/runtime}{syntax-store}{\K{mems}} +.. |STAGS| mathdef:: \xref{exec/runtime}{syntax-store}{\K{tags}} +.. |SGLOBALS| mathdef:: \xref{exec/runtime}{syntax-store}{\K{globals}} +.. |SELEMS| mathdef:: \xref{exec/runtime}{syntax-store}{\K{elems}} +.. |SDATAS| mathdef:: \xref{exec/runtime}{syntax-store}{\K{datas}} +.. |SEXNS| mathdef:: \xref{exec/runtime}{syntax-store}{\K{exns}} + +.. Store, non-terminals + +.. |store| mathdef:: \xref{exec/runtime}{syntax-store}{\X{store}} + + +.. Stack, terminals + +.. |LABEL| mathdef:: \xref{exec/runtime}{syntax-label}{\K{label}} +.. |FRAME| mathdef:: \xref{exec/runtime}{syntax-frame}{\K{frame}} + +.. |ALOCALS| mathdef:: \xref{exec/runtime}{syntax-frame}{\K{locals}} +.. |AMODULE| mathdef:: \xref{exec/runtime}{syntax-frame}{\K{module}} + + +.. Stack, non-terminals + +.. |label| mathdef:: \xref{exec/runtime}{syntax-label}{\X{label}} +.. |frame| mathdef:: \xref{exec/runtime}{syntax-frame}{\X{frame}} +.. |handler| mathdef:: \xref{exec/runtime}{syntax-handler}{\X{handler}} + +.. Stack, meta functions + +.. |expand| mathdef:: \xref{exec/runtime}{exec-expand}{\F{expand}} + + +.. Administrative Instructions, terminals + +.. |REFFUNCADDR| mathdef:: \xref{exec/runtime}{syntax-ref}{\K{ref}} +.. |REFEXNADDR| mathdef:: \xref{exec/runtime}{syntax-ref.exn-addr}{\K{ref{.}exn}} +.. |REFEXTERNADDR| mathdef:: \xref{exec/runtime}{syntax-ref.extern-addr}{\K{ref{.}extern}} +.. |TRAP| mathdef:: \xref{exec/runtime}{syntax-trap}{\K{trap}} +.. |INVOKE| mathdef:: \xref{exec/runtime}{syntax-invoke}{\K{invoke}} +.. |HANDLER| mathdef:: \xref{exec/runtime}{syntax-handler}{\K{handler}} +.. |CAUGHT| mathdef:: \xref{exec/runtime}{syntax-caught}{\K{caught}} + + +.. Values & Results, non-terminals + +.. |num| mathdef:: \xref{exec/runtime}{syntax-num}{\X{num}} +.. |vecc| mathdef:: \xref{exec/runtime}{syntax-vec}{\X{vec}} +.. |reff| mathdef:: \xref{exec/runtime}{syntax-ref}{\X{ref}} +.. |val| mathdef:: \xref{exec/runtime}{syntax-val}{\X{val}} +.. |result| mathdef:: \xref{exec/runtime}{syntax-result}{\X{result}} + + +.. Values, meta-functions + +.. |default| mathdef:: \xref{exec/runtime}{default-val}{\F{default}} + + +.. Administrative Instructions, non-terminals + +.. |XB| mathdef:: \xref{exec/runtime}{syntax-ctxt-block}{B} +.. |XC| mathdef:: \xref{exec/runtime}{syntax-ctxt-block}{C} +.. |XT| mathdef:: \xref{exec/runtime}{syntax-ctxt-throw}{T} + + +.. Configurations, non-terminals + +.. |config| mathdef:: \xref{exec/runtime}{syntax-config}{\X{config}} +.. |thread| mathdef:: \xref{exec/runtime}{syntax-thread}{\X{thread}} + + +.. Numerics, operators + +.. |iadd| mathdef:: \xref{exec/numerics}{op-iadd}{\F{iadd}} +.. |isub| mathdef:: \xref{exec/numerics}{op-isub}{\F{isub}} +.. |imul| mathdef:: \xref{exec/numerics}{op-imul}{\F{imul}} +.. |idivu| mathdef:: \xref{exec/numerics}{op-idiv_u}{\F{idiv\_u}} +.. |idivs| mathdef:: \xref{exec/numerics}{op-idiv_s}{\F{idiv\_s}} +.. |iremu| mathdef:: \xref{exec/numerics}{op-irem_u}{\F{irem\_u}} +.. |irems| mathdef:: \xref{exec/numerics}{op-irem_s}{\F{irem\_s}} +.. |inot| mathdef:: \xref{exec/numerics}{op-inot}{\F{inot}} +.. |iand| mathdef:: \xref{exec/numerics}{op-iand}{\F{iand}} +.. |iandnot| mathdef:: \xref{exec/numerics}{op-iandnot}{\F{iandnot}} +.. |ior| mathdef:: \xref{exec/numerics}{op-ior}{\F{ior}} +.. |ixor| mathdef:: \xref{exec/numerics}{op-ixor}{\F{ixor}} +.. |ishl| mathdef:: \xref{exec/numerics}{op-ishl}{\F{ishl}} +.. |ishru| mathdef:: \xref{exec/numerics}{op-ishr_u}{\F{ishr\_u}} +.. |ishrs| mathdef:: \xref{exec/numerics}{op-ishr_s}{\F{ishr\_s}} +.. |irotl| mathdef:: \xref{exec/numerics}{op-irotl}{\F{irotl}} +.. |irotr| mathdef:: \xref{exec/numerics}{op-irotr}{\F{irotr}} +.. |iclz| mathdef:: \xref{exec/numerics}{op-iclz}{\F{iclz}} +.. |ictz| mathdef:: \xref{exec/numerics}{op-ictz}{\F{ictz}} +.. |ipopcnt| mathdef:: \xref{exec/numerics}{op-ipopcnt}{\F{ipopcnt}} +.. |ieqz| mathdef:: \xref{exec/numerics}{op-ieqz}{\F{ieqz}} +.. |ieq| mathdef:: \xref{exec/numerics}{op-ieq}{\F{ieq}} +.. |ine| mathdef:: \xref{exec/numerics}{op-ine}{\F{ine}} +.. |iltu| mathdef:: \xref{exec/numerics}{op-ilt_u}{\F{ilt\_u}} +.. |ilts| mathdef:: \xref{exec/numerics}{op-ilt_s}{\F{ilt\_s}} +.. |igtu| mathdef:: \xref{exec/numerics}{op-igt_u}{\F{igt\_u}} +.. |igts| mathdef:: \xref{exec/numerics}{op-igt_s}{\F{igt\_s}} +.. |ileu| mathdef:: \xref{exec/numerics}{op-ile_u}{\F{ile\_u}} +.. |iles| mathdef:: \xref{exec/numerics}{op-ile_s}{\F{ile\_s}} +.. |igeu| mathdef:: \xref{exec/numerics}{op-ige_u}{\F{ige\_u}} +.. |iges| mathdef:: \xref{exec/numerics}{op-ige_s}{\F{ige\_s}} +.. |iextendMs| mathdef:: \xref{exec/numerics}{op-iextendn_s}{\F{iextend}M\F{\_s}} +.. |ibitselect| mathdef:: \xref{exec/numerics}{op-ibitselect}{\F{ibitselect}} +.. |iabs| mathdef:: \xref{exec/numerics}{op-iabs}{\F{iabs}} +.. |ineg| mathdef:: \xref{exec/numerics}{op-ineg}{\F{ineg}} +.. |iminu| mathdef:: \xref{exec/numerics}{op-imin_u}{\F{imin\_u}} +.. |imins| mathdef:: \xref{exec/numerics}{op-imin_s}{\F{imin\_s}} +.. |imaxu| mathdef:: \xref{exec/numerics}{op-imax_u}{\F{imax\_u}} +.. |imaxs| mathdef:: \xref{exec/numerics}{op-imax_s}{\F{imax\_s}} +.. |iaddsatu| mathdef:: \xref{exec/numerics}{op-iaddsat_u}{\F{iaddsat\_u}} +.. |iaddsats| mathdef:: \xref{exec/numerics}{op-iaddsat_s}{\F{iaddsat\_s}} +.. |isubsatu| mathdef:: \xref{exec/numerics}{op-isubsat_u}{\F{isubsat\_u}} +.. |isubsats| mathdef:: \xref{exec/numerics}{op-isubsat_s}{\F{isubsat\_s}} +.. |iavgru| mathdef:: \xref{exec/numerics}{op-iavgr_u}{\F{iavgr\_u}} +.. |iq15mulrsats| mathdef:: \xref{exec/numerics}{op-iq15mulrsat_s}{\F{iq15mulrsat\_s}} + +.. |fadd| mathdef:: \xref{exec/numerics}{op-fadd}{\F{fadd}} +.. |fsub| mathdef:: \xref{exec/numerics}{op-fsub}{\F{fsub}} +.. |fmul| mathdef:: \xref{exec/numerics}{op-fmul}{\F{fmul}} +.. |fdiv| mathdef:: \xref{exec/numerics}{op-fdiv}{\F{fdiv}} +.. |fmin| mathdef:: \xref{exec/numerics}{op-fmin}{\F{fmin}} +.. |fmax| mathdef:: \xref{exec/numerics}{op-fmax}{\F{fmax}} +.. |fcopysign| mathdef:: \xref{exec/numerics}{op-fcopysign}{\F{fcopysign}} +.. |fabs| mathdef:: \xref{exec/numerics}{op-fabs}{\F{fabs}} +.. |fneg| mathdef:: \xref{exec/numerics}{op-fneg}{\F{fneg}} +.. |fsqrt| mathdef:: \xref{exec/numerics}{op-fsqrt}{\F{fsqrt}} +.. |fceil| mathdef:: \xref{exec/numerics}{op-fceil}{\F{fceil}} +.. |ffloor| mathdef:: \xref{exec/numerics}{op-ffloor}{\F{ffloor}} +.. |ftrunc| mathdef:: \xref{exec/numerics}{op-ftrunc}{\F{ftrunc}} +.. |fnearest| mathdef:: \xref{exec/numerics}{op-fnearest}{\F{fnearest}} +.. |feq| mathdef:: \xref{exec/numerics}{op-feq}{\F{feq}} +.. |fne| mathdef:: \xref{exec/numerics}{op-fne}{\F{fne}} +.. |flt| mathdef:: \xref{exec/numerics}{op-flt}{\F{flt}} +.. |fgt| mathdef:: \xref{exec/numerics}{op-fgt}{\F{fgt}} +.. |fle| mathdef:: \xref{exec/numerics}{op-fle}{\F{fle}} +.. |fge| mathdef:: \xref{exec/numerics}{op-fge}{\F{fge}} +.. |fpmin| mathdef:: \xref{exec/numerics}{op-fpmin}{\F{fpmin}} +.. |fpmax| mathdef:: \xref{exec/numerics}{op-fpmax}{\F{fpmax}} + +.. |extend| mathdef:: \xref{exec/numerics}{op-extend_u}{\F{extend}} +.. |extendu| mathdef:: \xref{exec/numerics}{op-extend_u}{\F{extend}^{\K{u}}} +.. |extends| mathdef:: \xref{exec/numerics}{op-extend_s}{\F{extend}^{\K{s}}} +.. |wrap| mathdef:: \xref{exec/numerics}{op-wrap}{\F{wrap}} +.. |truncu| mathdef:: \xref{exec/numerics}{op-trunc_u}{\F{trunc}^{\K{u}}} +.. |truncs| mathdef:: \xref{exec/numerics}{op-trunc_s}{\F{trunc}^{\K{s}}} +.. |truncsatu| mathdef:: \xref{exec/numerics}{op-trunc_sat_u}{\F{trunc\_sat\_u}} +.. |truncsats| mathdef:: \xref{exec/numerics}{op-trunc_sat_s}{\F{trunc\_sat\_s}} +.. |promote| mathdef:: \xref{exec/numerics}{op-promote}{\F{promote}} +.. |demote| mathdef:: \xref{exec/numerics}{op-demote}{\F{demote}} +.. |convertu| mathdef:: \xref{exec/numerics}{op-convert_u}{\F{convert}^{\K{u}}} +.. |converts| mathdef:: \xref{exec/numerics}{op-convert_s}{\F{convert}^{\K{s}}} +.. |reinterpret| mathdef:: \xref{exec/numerics}{op-reinterpret}{\F{reinterpret}} +.. |narrow| mathdef:: \xref{exec/numerics}{op-narrow_u}{\F{narrow}} +.. |narrowu| mathdef:: \xref{exec/numerics}{op-narrow_u}{\F{narrow}^{\K{u}}} +.. |narrows| mathdef:: \xref{exec/numerics}{op-narrow_s}{\F{narrow}^{\K{s}}} + + +.. Numerics, meta functions + +.. |bits| mathdef:: \xref{exec/numerics}{aux-bits}{\F{bits}} +.. |ibits| mathdef:: \xref{exec/numerics}{aux-ibits}{\F{ibits}} +.. |fbits| mathdef:: \xref{exec/numerics}{aux-fbits}{\F{fbits}} +.. |fsign| mathdef:: \xref{exec/numerics}{aux-fsign}{\F{fsign}} +.. |fbias| mathdef:: \xref{exec/numerics}{aux-fbias}{\F{fbias}} +.. |bytes| mathdef:: \xref{exec/numerics}{aux-bytes}{\F{bytes}} +.. |littleendian| mathdef:: \xref{exec/numerics}{aux-littleendian}{\F{littleendian}} +.. |signed| mathdef:: \xref{exec/numerics}{aux-signed}{\F{signed}} +.. |bool| mathdef:: \xref{exec/numerics}{aux-bool}{\F{bool}} + +.. |ieee| mathdef:: \xref{exec/numerics}{aux-ieee}{\F{float}} +.. |nans| mathdef:: \xref{exec/numerics}{aux-nans}{\F{nans}} +.. |trunc| mathdef:: \xref{exec/numerics}{aux-trunc}{\F{trunc}} +.. |satu| mathdef:: \xref{exec/numerics}{aux-sat_u}{\F{sat}^{\K{u}}} +.. |sats| mathdef:: \xref{exec/numerics}{aux-sat_s}{\F{sat}^{\K{s}}} + +.. |lanes| mathdef:: \xref{exec/numerics}{aux-lanes}{\F{lanes}} + + +.. Other meta functions + +.. |instantiate| mathdef:: \xref{exec/modules}{exec-instantiation}{\F{instantiate}} +.. |invoke| mathdef:: \xref{exec/modules}{exec-invocation}{\F{invoke}} + + +.. Judgements + +.. |vdashexternval| mathdef:: \xref{exec/modules}{valid-externval}{\vdash} + +.. |vdashlimitsmatch| mathdef:: \xref{exec/modules}{match-limits}{\vdash} +.. |vdashexterntypematch| mathdef:: \xref{exec/modules}{match-externtype}{\vdash} + + +.. Soundness +.. --------- + +.. Judgements + +.. |vdashadmininstr| mathdef:: \xref{appendix/properties}{valid-instr-admin}{\vdash} + +.. |vdashval| mathdef:: \xref{appendix/properties}{valid-val}{\vdash} +.. |vdashresult| mathdef:: \xref{appendix/properties}{valid-result}{\vdash} + +.. |vdashfuncinst| mathdef:: \xref{appendix/properties}{valid-funcinst}{\vdash} +.. |vdashtableinst| mathdef:: \xref{appendix/properties}{valid-tableinst}{\vdash} +.. |vdashmeminst| mathdef:: \xref{appendix/properties}{valid-meminst}{\vdash} +.. |vdashtaginst| mathdef:: \xref{appendix/properties}{valid-taginst}{\vdash} +.. |vdashglobalinst| mathdef:: \xref{appendix/properties}{valid-globalinst}{\vdash} +.. |vdasheleminst| mathdef:: \xref{appendix/properties}{valid-eleminst}{\vdash} +.. |vdashdatainst| mathdef:: \xref{appendix/properties}{valid-datainst}{\vdash} +.. |vdashexninst| mathdef:: \xref{appendix/properties}{valid-exninst}{\vdash} +.. |vdashexportinst| mathdef:: \xref{appendix/properties}{valid-exportinst}{\vdash} +.. |vdashmoduleinst| mathdef:: \xref{appendix/properties}{valid-moduleinst}{\vdash} + +.. |vdashstore| mathdef:: \xref{appendix/properties}{valid-store}{\vdash} +.. |vdashconfig| mathdef:: \xref{appendix/properties}{valid-config}{\vdash} +.. |vdashthread| mathdef:: \xref{appendix/properties}{valid-thread}{\vdash} +.. |vdashframe| mathdef:: \xref{appendix/properties}{valid-frame}{\vdash} + +.. |vdashfuncinstextends| mathdef:: \xref{appendix/properties}{extend-funcinst}{\vdash} +.. |vdashtableinstextends| mathdef:: \xref{appendix/properties}{extend-tableinst}{\vdash} +.. |vdashmeminstextends| mathdef:: \xref{appendix/properties}{extend-meminst}{\vdash} +.. |vdashtaginstextends| mathdef:: \xref{appendix/properties}{extend-taginst}{\vdash} +.. |vdashglobalinstextends| mathdef:: \xref{appendix/properties}{extend-globalinst}{\vdash} +.. |vdasheleminstextends| mathdef:: \xref{appendix/properties}{extend-eleminst}{\vdash} +.. |vdashdatainstextends| mathdef:: \xref{appendix/properties}{extend-datainst}{\vdash} +.. |vdashexninstextends| mathdef:: \xref{appendix/properties}{extend-exninst}{\vdash} +.. |vdashstoreextends| mathdef:: \xref{appendix/properties}{extend-store}{\vdash} + + +.. Custom Sections +.. --------------- + +.. Name section, non-terminals + +.. |Bnamesec| mathdef:: \xref{appendix/custom}{binary-namesubsection}{\B{namesec}} +.. |Bnamedata| mathdef:: \xref{appendix/custom}{binary-namesubsection}{\B{namedata}} +.. |Bnamesubsection| mathdef:: \xref{appendix/custom}{binary-namesubsection}{\B{namesubsection}} + +.. |Bnamemap| mathdef:: \xref{appendix/custom}{binary-namemap}{\B{namemap}} +.. |Bnameassoc| mathdef:: \xref{appendix/custom}{binary-namemap}{\B{nameassoc}} +.. |Bindirectnamemap| mathdef:: \xref{appendix/custom}{binary-indirectnamemap}{\B{indirectnamemap}} +.. |Bindirectnameassoc| mathdef:: \xref{appendix/custom}{binary-indirectnamemap}{\B{indirectnameassoc}} + +.. |Bmodulenamesubsec| mathdef:: \xref{appendix/custom}{binary-modulenamesec}{\B{modulenamesubsec}} +.. |Bfuncnamesubsec| mathdef:: \xref{appendix/custom}{binary-funcnamesec}{\B{funcnamesubsec}} +.. |Blocalnamesubsec| mathdef:: \xref{appendix/custom}{binary-localnamesec}{\B{localnamesubsec}} +.. |Btagnamesubsec| mathdef:: \xref{appendix/custom}{binary-tagnamesec}{\B{tagnamesubsec}} + + +.. Embedding +.. --------- + +.. |error| mathdef:: \xref{appendix/embedding}{embed-error}{\X{error}} +.. |ERROR| mathdef:: \xref{appendix/embedding}{embed-error}{\K{error}} diff --git a/document/legacy/exceptions/core/util/mathdef.py b/document/legacy/exceptions/core/util/mathdef.py new file mode 100644 index 000000000..a10fc458f --- /dev/null +++ b/document/legacy/exceptions/core/util/mathdef.py @@ -0,0 +1,122 @@ +from sphinx.directives.patches import MathDirective +from sphinx.util.texescape import tex_replace_map +from sphinx.writers.html5 import HTML5Translator +from sphinx.writers.latex import LaTeXTranslator +from docutils import nodes +from docutils.nodes import math +from docutils.parsers.rst.directives.misc import Replace +from six import text_type +import re + + +# Transform \xref in math nodes + +xref_re = re.compile('\\\\xref\{([^}]*)\}\{([^}]*)\}', re.M) + +def html_hyperlink(file, id): + return '\\href{../%s.html#%s}' % (file, id.replace('_', '-')) + +def html_transform_math_xref(node): + new_text = xref_re.sub(lambda m: html_hyperlink(m.group(1), m.group(2)), node.astext()) + node.children[0] = nodes.Text(new_text) + +# Mirrors sphinx/writers/latex +def latex_hyperlink(file, id): + id = text_type(id).translate(tex_replace_map).\ + encode('ascii', 'backslashreplace').decode('ascii').\ + replace('_', '-').replace('\\', '_') + return '\\hyperref[%s:%s]' % (file, id) + +def latex_transform_math_xref(node): + new_text = xref_re.sub(lambda m: latex_hyperlink(m.group(1), m.group(2)), node.astext()) + node.children[0] = nodes.Text(new_text) + +# Expand mathdef names in math roles and directives + +def_re = re.compile('\\\\[A-Za-z][0-9A-Za-z]*', re.M) + +auxcounter = 0 + +def lookup_mathdef(defs, name): + if name in defs: + [arity, s] = defs[name] + if arity > 0: + global auxcounter + auxcounter = auxcounter + 1 + name = "\\mathdef%d" % auxcounter + s = "\\def%s#%d{%s}%s" % (name, arity, s, name) + return s + return name + +def replace_mathdefs(doc, s): + if not hasattr(doc, 'mathdefs'): + return s + return def_re.sub(lambda m: lookup_mathdef(doc.mathdefs, m.group(0)), s) + +def ext_math_role(role, raw, text, line, inliner, options = {}, content = []): + text = replace_mathdefs(inliner.document, raw.split('`')[1]) + return [math(raw, text)], [] + +class ExtMathDirective(MathDirective): + def run(self): + doc = self.state.document + for i, s in enumerate(self.content): + self.content[i] = replace_mathdefs(doc, s) + for i, s in enumerate(self.arguments): + self.arguments[i] = replace_mathdefs(doc, s) + return super().run() + +class MathdefDirective(Replace): + def run(self): + name = '\\' + self.state.parent.rawsource.split('|')[1] + name = name.split('#') + if len(name) > 1: + arity = int(name[1]) + else: + arity = 0 + name = name[0] + doc = self.state.document + if not hasattr(doc, 'mathdefs'): + doc.mathdefs = {} + # TODO: we don't ever hit the case where len(self.content) > 1 + for i, s in enumerate(self.content): + self.content[i] = replace_mathdefs(doc, s) + doc.mathdefs[name] = [arity, ''.join(self.content)] + self.content[0] = ':math:`' + self.content[0] + self.content[-1] = self.content[-1] + '`' + return super().run() + +class WebAssemblyHTML5Translator(HTML5Translator): + """ + Customize HTML5Translator. + Convert xref in math and math block nodes to hrefs. + """ + def visit_math(self, node, math_env = ''): + html_transform_math_xref(node) + super().visit_math(node, math_env) + + def visit_math_block(self, node, math_env = ''): + html_transform_math_xref(node) + super().visit_math_block(node, math_env) + +class WebAssemblyLaTeXTranslator(LaTeXTranslator): + """ + Customize LaTeXTranslator. + Convert xref in math and math block nodes to hyperrefs. + """ + def visit_math(self, node): + latex_transform_math_xref(node) + super().visit_math(node) + + def visit_math_block(self, node): + latex_transform_math_xref(node) + super().visit_math_block(node) + +# Setup + +def setup(app): + app.set_translator('html', WebAssemblyHTML5Translator) + app.set_translator('latex', WebAssemblyLaTeXTranslator) + app.add_role('math', ext_math_role) + app.add_directive('math', ExtMathDirective, override = True) + app.add_directive('mathdef', MathdefDirective) diff --git a/document/legacy/exceptions/core/util/pseudo-lexer.py b/document/legacy/exceptions/core/util/pseudo-lexer.py new file mode 100644 index 000000000..fd3a251d5 --- /dev/null +++ b/document/legacy/exceptions/core/util/pseudo-lexer.py @@ -0,0 +1,32 @@ +from pygments.lexer import RegexLexer +from pygments.token import * +from sphinx.highlighting import lexers + +class PseudoLexer(RegexLexer): + name = 'Pseudo' + aliases = ['pseudo'] + filenames = ['*.pseudo'] + + tokens = { + 'root': [ + (r"(?` must be :ref:`valid ` as some :ref:`function type ` :math:`[t_1^\ast] \to [t_2^\ast]`. + +* Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with the :ref:`label type ` :math:`[t_2^\ast]` prepended to the |CLABELS| vector. + +* Under context :math:`C'`, + the instruction sequence :math:`\instr_1^\ast` must be :ref:`valid ` with type :math:`[t_1^\ast] \to [t_2^\ast]`. + +* Let :math:`C''` be the same :ref:`context ` as :math:`C`, but with the :ref:`label type ` :math:`\LCATCH~[t_2^\ast]` prepended to the |CLABELS| vector. + +* For every :math:`x_i` and :math:`\instr_{2i}^\ast` in :math:`(\CATCH~x~\instr_2^\ast)^\ast`: + + * The tag :math:`C.\CTAGS[x_i]` must be defined in the context :math:`C`. + + * Let :math:`[t_{3i}^\ast] \to [t_{4i}^\ast]` be the :ref:`tag type ` :math:`C.\CTAGS[x_i]`. + + * The :ref:`result type ` :math:`[t_{4i}^\ast]` must be empty. + + * Under context :math:`C''`, + the instruction sequence :math:`\instr_{2i}^\ast` must be :ref:`valid ` with type :math:`[t_{3i}^\ast] \to [t_2^\ast]`. + +* If :math:`(\CATCHALL~\instr_3^\ast)^?` is not empty, then: + + * Under context :math:`C''`, + the instruction sequence :math:`\instr_3^\ast` must be :ref:`valid ` with type :math:`[] \to [t_2^\ast]`. + +* Then the compound instruction is valid with type :math:`[t_1^\ast] \to [t_2^\ast]`. + +.. math:: + ~\\ + \frac{ + \begin{array}{c} + C \vdashblocktype \blocktype : [t_1^\ast] \to [t_2^\ast] + \qquad + C,\CLABELS\,[t_2^\ast] \vdashinstrseq \instr_1^\ast : [t_1^\ast] \to [t_2^\ast] \\ + (C.\CTAGS[x] = [t^\ast] \to [])^\ast \\ + C,\CLABELS\,(\LCATCH~[t_2^\ast]) \vdashinstrseq \instr_2^\ast : [t^\ast] \to [t_2^\ast])^\ast \\ + (C,\CLABELS\,(\LCATCH~[t_2^\ast]) \vdashinstrseq \instr_3^\ast : [] \to [t_2^\ast])^? + \end{array} + }{ + C \vdashinstr \TRY~\blocktype~\instr_1^\ast~(\CATCH~x~\instr_2^\ast)^\ast~(\CATCHALL~\instr_3^\ast)^?~\END : [t_1^\ast] \to [t_2^\ast] + } + + +.. note:: + The :ref:`notation ` :math:`C,\CLABELS\,(\LCATCH~[t^\ast])` inserts the new label type at index :math:`0`, shifting all others. + + +.. _valid-try-delegate: + +:math:`\TRY~\blocktype~\instr^\ast~\DELEGATE~l` +............................................... + +* The label :math:`C.\CLABELS[l]` must be defined in the context. + +* The :ref:`block type ` must be :ref:`valid ` as some :ref:`function type ` :math:`[t_1^\ast] \to [t_2^\ast]`. + +* Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with the :ref:`result type ` :math:`[t_2^\ast]` prepended to the |CLABELS| vector. + +* Under context :math:`C'`, + the instruction sequence :math:`\instr^\ast` must be :ref:`valid ` with type :math:`[t_1^\ast] \to [t_2^\ast]`. + +* Then the compound instruction is valid with type :math:`[t_1^\ast] \to [t_2^\ast]`. + +.. math:: + ~\\ + \frac{ + C \vdashblocktype \blocktype : [t_1^\ast] \to [t_2^\ast] + \qquad + C,\CLABELS\,[t_2^\ast] \vdashinstrseq \instr^\ast : [t_1^\ast]\to[t_2^\ast] + \qquad + C.\CLABELS[l] = [t_0^\ast] + }{ + C \vdashinstrseq \TRY~\blocktype~\instr^\ast~\DELEGATE~l : [t_1^\ast]\to[t_2^\ast] + } + +.. note:: + The :ref:`label index ` space in the :ref:`context ` :math:`C` contains the most recent label first, so that :math:`C.\CLABELS[l]` performs a relative lookup as expected. + + +.. _valid-rethrow: + +:math:`\RETHROW~l` +.................. + +* The label :math:`C.\CLABELS[l]` must be defined in the context. + +* Let :math:`(\LCATCH^?~[t^\ast])` be the :ref:`label type ` :math:`C.\CLABELS[l]`. + +* The |LCATCH| must be present in the :ref:`label type ` :math:`C.\CLABELS[l]`. + +* Then the instruction is valid with type :math:`[t_1^\ast] \to [t_2^\ast]`, for any sequences of :ref:`value types ` :math:`t_1^\ast` and :math:`t_2^\ast`. + + +.. math:: + ~\\ + \frac{ + C.\CLABELS[l] = \LCATCH~[t^\ast] + }{ + C \vdashinstr \RETHROW~l : [t_1^\ast] \to [t_2^\ast] + } + + +.. note:: + The |RETHROW| instruction is stack-polymorphic. diff --git a/document/legacy/exceptions/js-api/Makefile b/document/legacy/exceptions/js-api/Makefile new file mode 100644 index 000000000..84ba5d3ab --- /dev/null +++ b/document/legacy/exceptions/js-api/Makefile @@ -0,0 +1,44 @@ +BUILDDIR = _build +STATICDIR = _static +DOWNLOADDIR = _download +NAME = WebAssembly + +.PHONY: all +all: + mkdir -p $(BUILDDIR)/html + bikeshed spec index.bs $(BUILDDIR)/html/index.html + @echo "Build finished. The HTML pages are in `pwd`/$(BUILDDIR)/html." + +.PHONY: publish +publish: + (cd ..; make publish-js-api) + +.PHONY: clean +clean: + rm -rf $(BUILDDIR) + rm -rf $(STATICDIR) + +.PHONY: diff +diff: all + @echo "Downloading the old single-file html spec..." + curl `grep "^TR" index.bs | cut -d' ' -f2` -o $(BUILDDIR)/html/old.html + @echo "Done." + @echo "Diffing new against old..." + perl ../util/htmldiff.pl $(BUILDDIR)/html/old.html $(BUILDDIR)/html/index.html $(BUILDDIR)/html/diff.html + @echo "Done. The diff is at $(BUILDDIR)/html/diff.html" + +.PHONY: WD-tar +WD-tar: + bikeshed echidna --just-tar index.bs $(BUILDDIR)/html/index.html + mv test.tar $(BUILDDIR)/WD.tar + @echo "Built $(BUILDDIR)/WD.tar." + +.PHONY: WD-echidna +WD-echidna: + @if [ -z $(W3C_USERNAME) ] || \ + [ -z $(W3C_PASSWORD) ] || \ + [ -z $(DECISION_URL) ] ; then \ + echo "Must provide W3C_USERNAME, W3C_PASSWORD, and DECISION_URL environment variables"; \ + exit 1; \ + fi + bikeshed echidna index.bs --u $(W3C_USERNAME) --p $(W3C_PASSWORD) --d $(DECISION_URL) diff --git a/document/legacy/exceptions/js-api/index.bs b/document/legacy/exceptions/js-api/index.bs new file mode 100644 index 000000000..e7db14074 --- /dev/null +++ b/document/legacy/exceptions/js-api/index.bs @@ -0,0 +1,1450 @@ + + +
+{
+  "WEBASSEMBLY": {
+    "href": "https://webassembly.github.io/spec/core/",
+    "title": "WebAssembly Core Specification",
+    "publisher": "W3C WebAssembly Community Group",
+    "status": "Draft"
+  }
+}
+
+ +
+urlPrefix: https://tc39.github.io/ecma262/; spec: ECMASCRIPT
+    type: interface; for: ECMAScript
+        text: ArrayBuffer; url: sec-arraybuffer-objects
+    type: exception; for: ECMAScript
+        text: Error; url: sec-error-objects
+        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
+        url: sec-returnifabrupt-shorthands
+            text: !
+            text: ?
+        text: Type; url: sec-ecmascript-data-types-and-values
+        text: current Realm; url: current-realm
+        text: Built-in Function Objects; url: sec-built-in-function-objects
+        text: NativeError Object Structure; url: sec-nativeerror-object-structure
+        text: 𝔽; url: #𝔽
+        text: ℤ; url: #ℤ
+urlPrefix: https://webassembly.github.io/exception-handling/core/; spec: WebAssembly; type: dfn
+    url: valid/modules.html#valid-module
+        text: valid
+        text: WebAssembly module validation
+    text: module grammar; url: binary/modules.html#binary-module
+    text: custom section; url: binary/modules.html#custom-section
+    text: customsec; url: binary/modules.html#binary-customsec
+    text: memory instance; url: exec/runtime.html#memory-instances
+    text: table instance; url: exec/runtime.html#table-instances
+    text: global instance; url: exec/runtime.html#global-instances
+    text: trap; url: exec/runtime.html#syntax-trap
+    url: exec/runtime.html#values
+        text: WebAssembly value
+        text: i64.const
+        text: i32.const
+        text: f32.const
+        text: f64.const
+        text: v128.const
+        text: ref.null
+        text: ref.func
+        text: ref.extern
+    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
+    text: module_decode; url: appendix/embedding.html#embed-module-decode
+    text: module_validate; url: appendix/embedding.html#embed-module-validate
+    text: module_instantiate; url: appendix/embedding.html#embed-module-instantiate
+    text: module_imports; url: appendix/embedding.html#embed-module-imports
+    text: module_exports; url: appendix/embedding.html#embed-module-exports
+    text: instance_export; url: appendix/embedding.html#embed-instance-export
+    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: 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
+    text: table_write; url: appendix/embedding.html#embed-table-write
+    text: table_size; url: appendix/embedding.html#embed-table-size
+    text: table_grow; url: appendix/embedding.html#embed-table-grow
+    text: mem_alloc; url: appendix/embedding.html#embed-mem-alloc
+    text: mem_type; url: appendix/embedding.html#embed-mem-type
+    text: mem_read; url: appendix/embedding.html#embed-mem-read
+    text: mem_write; url: appendix/embedding.html#embed-mem-write
+    text: mem_size; url: appendix/embedding.html#embed-mem-size
+    text: mem_grow; url: appendix/embedding.html#embed-mem-grow
+    text: global_alloc; url: appendix/embedding.html#embed-global-alloc
+    text: global_type; url: appendix/embedding.html#embed-global-type
+    text: global_read; url: appendix/embedding.html#embed-global-read
+    text: global_write; url: appendix/embedding.html#embed-global-write
+    text: error; url: appendix/embedding.html#embed-error
+    text: store; url: exec/runtime.html#syntax-store
+    text: table type; url: syntax/types.html#syntax-tabletype
+    text: table address; url: exec/runtime.html#syntax-tableaddr
+    text: function address; url: exec/runtime.html#syntax-funcaddr
+    text: memory address; url: exec/runtime.html#syntax-memaddr
+    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
+    url: syntax/types.html#syntax-numtype
+        text: i32
+        text: i64
+        text: f32
+        text: f64
+    url: syntax/types.html#vector-types
+        text: v128
+    url: syntax/types.html#syntax-reftype
+        text: reftype
+        text: funcref
+        text: externref
+    url: syntax/values.html#syntax-float
+        text: +∞
+        text: −∞
+        text: nan
+        text: canon
+        text: signif
+    text: function element; url: exec/runtime.html#syntax-funcelem
+    text: import component; url: syntax/modules.html#imports
+    url: exec/runtime.html#syntax-externval
+        text: external value
+        for: external value
+            text: tag
+    text: host function; url: exec/runtime.html#syntax-hostfunc
+    text: the instantiation algorithm; url: exec/modules.html#instantiation
+    text: module; url: syntax/modules.html#syntax-module
+    text: imports; url: syntax/modules.html#syntax-module
+    text: import; url: syntax/modules.html#syntax-import
+    url: syntax/types.html#external-types
+        text: external type
+        text: func
+        text: table
+        text: mem
+        text: global
+        for: externtype
+            text: tag
+    text: global type; url: syntax/types.html#syntax-globaltype
+    url: syntax/types.html#syntax-mut
+        text: var
+        text: const
+    text: address; url: exec/runtime.html#addresses
+    text: signed_32; url: exec/numerics.html#aux-signed
+    text: memory.grow; url: exec/instructions.html#exec-memory-grow
+    text: current frame; url: exec/conventions.html#exec-notation-textual
+    text: module; for: frame; url: exec/runtime.html#syntax-frame
+    text: memaddrs; for: moduleinst; url: exec/runtime.html#syntax-moduleinst
+    text: signed_64; url: exec/numerics.html#aux-signed
+    text: sequence; url: syntax/conventions.html#grammar-notation
+    text: exception; for: tagtype/attribute; url: syntax/types.html#syntax-tagtype
+urlPrefix: https://heycam.github.io/webidl/; spec: WebIDL
+    type: dfn
+        text: create a namespace object; url: create-a-namespace-object
+urlPrefix: https://webassembly.github.io/js-types/js-api/; spec: WebAssembly JS API (JS Type Reflection)
+    type: abstract-op; text: FromValueType; url: abstract-opdef-fromvaluetype
+
+ + + + + +This API provides a way to access WebAssembly [[WEBASSEMBLY]] through a bridge to explicitly construct modules from JavaScript [[ECMASCRIPT]]. + +

Sample API Usage

+ +

This section is non-normative.

+ +Given `demo.wat` (encoded to `demo.wasm`): + +```lisp +(module + (import "js" "import1" (func $i1)) + (import "js" "import2" (func $i2)) + (func $main (call $i1)) + (start $main) + (func (export "f") (call $i2)) +) +``` + +and the following JavaScript, run in a browser: + +```javascript +var importObj = {js: { + import1: () => console.log("hello,"), + import2: () => console.log("world!") +}}; +fetch('demo.wasm').then(response => + response.arrayBuffer() +).then(buffer => + WebAssembly.instantiate(buffer, importObj) +).then(({module, instance}) => + instance.exports.f() +); +``` + +

Notation

+ +This specification depends on the Infra Standard. [[INFRA]] + +The WebAssembly [=sequence=] type is equivalent to the [=list=] type defined there; values of one +are treated as values of the other transparently. + +

Internal storage

+ +

Interaction of the WebAssembly Store with JavaScript

+ +Note: WebAssembly semantics are defined in terms of an abstract [=store=], representing the state of the WebAssembly abstract machine. WebAssembly operations take a store and return an updated store. + +Each [=agent=] has an associated store. When a new agent is created, its associated store is set to the result of [=store_init=](). + +Note: In this specification, no WebAssembly-related objects, memory or addresses can be shared among agents in an [=agent cluster=]. In a future version of WebAssembly, this may change. + +Elements of the WebAssembly store may be identified with JavaScript values. In particular, each WebAssembly [=memory instance=] with a corresponding {{Memory}} object is identified with a JavaScript [=Data Block=]; modifications to this Data Block are identified to updating the agent's store to a store which reflects those changes, and vice versa. + +

WebAssembly JS Object Caches

+ +Note: There are several WebAssembly objects that may have a corresponding JavaScript object. The correspondence is stored in a per-agent mapping from WebAssembly [=address=]es to JavaScript objects. +This mapping is used to ensure that, for a given [=agent=], there exists at most one JavaScript object for a particular WebAssembly address. However, this property does not hold for shared objects. + +Each [=agent=] is associated with the following [=ordered map=]s: + * The Memory object cache, mapping [=memory address=]es to {{Memory}} objects. + * The Table object cache, mapping [=table address=]es to {{Table}} objects. + * The Exported Function cache, mapping [=function address=]es to [=Exported Function=] objects. + * The Global object cache, mapping [=global address=]es to {{Global}} objects. + * The Extern value cache, mapping [=extern address=]es to values. + * The Tag object cache, mapping [=tag addresses=] to {{Tag}} objects. + +

The WebAssembly Namespace

+ +
+dictionary WebAssemblyInstantiatedSource {
+    required Module module;
+    required Instance instance;
+};
+
+[Exposed=*]
+namespace WebAssembly {
+    boolean validate(BufferSource bytes);
+    Promise<Module> compile(BufferSource bytes);
+
+    Promise<WebAssemblyInstantiatedSource> instantiate(
+        BufferSource bytes, optional object importObject);
+
+    Promise<Instance> instantiate(
+        Module moduleObject, optional object importObject);
+};
+
+ + + +
+ To compile a WebAssembly module from source bytes |bytes|, perform the following steps: + 1. Let |module| be [=module_decode=](|bytes|). If |module| is [=error=], return [=error=]. + 1. If [=module_validate=](|module|) is [=error=], return [=error=]. + 1. Return |module|. +
+ +
+ The validate(|bytes|) method, when invoked, performs the following steps: + 1. Let |stableBytes| be a [=get a copy of the buffer source|copy of the bytes held by the buffer=] |bytes|. + 1. [=Compile a WebAssembly module|Compile=] |stableBytes| as a WebAssembly module and store the results as |module|. + 1. If |module| is [=error=], return false. + 1. Return true. +
+ +A {{Module}} object represents a single WebAssembly module. Each {{Module}} object has the following internal slots: + + * \[[Module]] : a WebAssembly [=/module=] + * \[[Bytes]] : the source bytes of \[[Module]]. + +
+ To construct a WebAssembly module object from a module |module| and source bytes |bytes|, perform the following steps: + + 1. Let |moduleObject| be a new {{Module}} object. + 1. Set |moduleObject|.\[[Module]] to |module|. + 1. Set |moduleObject|.\[[Bytes]] to |bytes|. + 1. Return |moduleObject|. +
+ +
+ To asynchronously compile a WebAssembly module from source bytes |bytes|, using optional [=task source=] |taskSource|, perform the following steps: + + 1. Let |promise| be [=a new promise=]. + 1. Run the following steps [=in parallel=]: + 1. [=compile a WebAssembly module|Compile the WebAssembly module=] |bytes| and store the result as |module|. + 1. [=Queue a task=] to perform the following steps. If |taskSource| was provided, queue the task on that task source. + 1. If |module| is [=error=], reject |promise| with a {{CompileError}} exception. + 1. Otherwise, + 1. [=Construct a WebAssembly module object=] from |module| and |bytes|, and let |moduleObject| be the result. + 1. [=Resolve=] |promise| with |moduleObject|. + 1. Return |promise|. +
+ +
+ The compile(|bytes|) method, when invoked, performs the following steps: + 1. Let |stableBytes| be a [=get a copy of the buffer source|copy of the bytes held by the buffer=] |bytes|. + 1. [=Asynchronously compile a WebAssembly module=] from |stableBytes| and return the result. +
+ +
+ To read the imports from a WebAssembly module |module| from imports object |importObject|, perform the following steps: + 1. If |module|.[=imports=] [=list/is empty|is not empty=], and |importObject| is undefined, throw a {{TypeError}} exception. + 1. Let |imports| be « ». + 1. [=list/iterate|For each=] (|moduleName|, |componentName|, |externtype|) of [=module_imports=](|module|), + 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 [=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. Let |externfunc| be the [=external value=] [=external value|func=] |funcaddr|. + 1. [=list/Append=] |externfunc| to |imports|. + 1. If |externtype| is of the form [=global=] mut |valtype|, + 1. If [=Type=](|v|) is Number or BigInt, + 1. If |valtype| is [=i64=] and [=Type=](|v|) is Number, + 1. Throw a {{LinkError}} exception. + 1. If |valtype| is not [=i64=] and [=Type=](|v|) is BigInt, + 1. Throw a {{LinkError}} exception. + 1. If |valtype| is [=v128=], + 1. Throw a {{LinkError}} exception. + 1. Let |value| be [=ToWebAssemblyValue=](|v|, |valtype|). + 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. + 1. Let (|store|, |globaladdr|) be [=global_alloc=](|store|, [=const=] |valtype|, |value|). + 1. Set the [=surrounding agent=]'s [=associated store=] to |store|. + 1. Otherwise, if |v| [=implements=] {{Global}}, + 1. Let |globaladdr| be |v|.\[[Global]]. + 1. Otherwise, + 1. Throw a {{LinkError}} exception. + 1. Let |externglobal| be [=external value|global=] |globaladdr|. + 1. [=list/Append=] |externglobal| to |imports|. + 1. If |externtype| is of the form [=mem=] memtype, + 1. If |v| does not [=implement=] {{Memory}}, throw a {{LinkError}} exception. + 1. Let |externmem| be the [=external value=] [=external value|mem=] |v|.\[[Memory]]. + 1. [=list/Append=] |externmem| to |imports|. + 1. If |externtype| is of the form [=table=] tabletype, + 1. If |v| does not [=implement=] {{Table}}, throw a {{LinkError}} exception. + 1. Let |tableaddr| be |v|.\[[Table]]. + 1. Let |externtable| be the [=external value=] [=external value|table=] |tableaddr|. + 1. [=list/Append=] |externtable| to |imports|. + 1. If |externtype| is of the form [=externtype/tag=] |attribute| functype, + 1. Assert: |attribute| is [=tagtype/attribute/exception=]. + 1. If |v| does not [=implement=] {{Tag}}, throw a {{LinkError}} exception. + 1. Let |tagaddr| be |v|.\[[Address]]. + 1. Let |externtag| be the [=external value=] [=external value/tag=] |tagaddr|. + 1. [=list/Append=] |externtag| to |imports|. + 1. Return |imports|. + +Note: This algorithm only verifies the right kind of JavaScript values are passed. +The verification of WebAssembly type requirements is deferred to the +"[=instantiate the core of a WebAssembly module=]" algorithm. +
+ +
+ To create an exports object from a WebAssembly module |module| and instance |instance|, perform the following steps: + 1. Let |exportsObject| be [=!=] [$OrdinaryObjectCreate$](null). + 1. [=list/iterate|For each=] (|name|, |externtype|) of [=module_exports=](|module|), + 1. Let |externval| be [=instance_export=](|instance|, |name|). + 1. Assert: |externval| is not [=error=]. + 1. If |externtype| is of the form [=func=] functype, + 1. Assert: |externval| is of the form [=external value|func=] |funcaddr|. + 1. Let [=external value|func=] |funcaddr| be |externval|. + 1. Let |func| be the result of creating [=a new Exported Function=] from |funcaddr|. + 1. Let |value| be |func|. + 1. If |externtype| is of the form [=global=] mut globaltype, + 1. Assert: |externval| is of the form [=external value|global=] |globaladdr|. + 1. Let [=external value|global=] |globaladdr| be |externval|. + 1. Let |global| be [=create a global object|a new Global object=] created from |globaladdr|. + 1. Let |value| be |global|. + 1. If |externtype| is of the form [=mem=] memtype, + 1. Assert: |externval| is of the form [=external value|mem=] |memaddr|. + 1. Let [=external value|mem=] |memaddr| be |externval|. + 1. Let |memory| be [=create a memory object|a new Memory object=] created from |memaddr|. + 1. Let |value| be |memory|. + 1. If |externtype| is of the form [=table=] tabletype, + 1. Assert: |externval| is of the form [=external value|table=] |tableaddr|. + 1. Let [=external value|table=] |tableaddr| be |externval|. + 1. Let |table| be [=create a Table object|a new Table object=] created from |tableaddr|. + 1. Let |value| be |table|. + 1. If |externtype| is of the form [=externtype/tag=] |attribute| functype, + 1. Assert: |attribute| is [=tagtype/attribute/exception=]. + 1. Assert: |externval| is of the form [=external value/tag=] |tagaddr|. + 1. Let [=external value/tag=] |tagaddr| be |externval|. + 1. Let |tag| be [=create a Tag object|a new Tag object=] created from |tagaddr|. + 1. Let |value| be |tag|. + 1. Let |status| be [=!=] [$CreateDataProperty$](|exportsObject|, |name|, |value|). + 1. Assert: |status| is true. + + Note: the validity and uniqueness checks performed during [=WebAssembly module validation=] ensure that each property name is valid and no properties are defined twice. + 1. Perform [=!=] [$SetIntegrityLevel$](|exportsObject|, `"frozen"`). + 1. Return |exportsObject|. +
+ +
+ To initialize an instance object |instanceObject| from a WebAssembly module |module| and instance |instance|, perform the following steps: + + 1. [=Create an exports object=] from |module| and |instance| and let |exportsObject| be the result. + 1. Set |instanceObject|.\[[Instance]] to |instance|. + 1. Set |instanceObject|.\[[Exports]] to |exportsObject|. +
+ +
+ To instantiate the core of a WebAssembly module from a module |module| and imports |imports|, perform the following steps: + 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. + 1. Let |result| be [=module_instantiate=](|store|, |module|, |imports|). + 1. If |result| is [=error=], throw an appropriate exception type: + * A {{LinkError}} exception for most cases which occur during linking. + * If the error came when running the start function, throw a {{RuntimeError}} for most errors which occur from WebAssembly, or the error object propagated from inner ECMAScript code. + * Another error type if appropriate, for example an out-of-memory exception, as documented in the WebAssembly error mapping. + 1. Let (|store|, |instance|) be |result|. + 1. Set the [=surrounding agent=]'s [=associated store=] to |store|. + 1. Return |instance|. +
+ +
+ To asynchronously instantiate a WebAssembly module from a {{Module}} |moduleObject| and imports |importObject|, perform the following steps: + 1. Let |promise| be [=a new promise=]. + 1. Let |module| be |moduleObject|.\[[Module]]. + 1. [=Read the imports=] of |module| with imports |importObject|, and let |imports| be the result. + If this operation throws an exception, catch it, [=reject=] |promise| with the exception, and return |promise|. + 1. Run the following steps [=in parallel=]: + 1. [=Queue a task=] to perform the following steps: + Note: Implementation-specific work may be performed here. + 1. [=Instantiate the core of a WebAssembly module=] |module| with |imports|, and let |instance| be the result. + If this throws an exception, catch it, [=reject=] |promise| with the exception, and terminate these substeps. + 1. Let |instanceObject| be a [=/new=] {{Instance}}. + 1. [=initialize an instance object|Initialize=] |instanceObject| from |module| and |instance|. + If this throws an exception, catch it, [=reject=] |promise| with the exception, and terminate these substeps. + 1. [=Resolve=] |promise| with |instanceObject|. + 1. Return |promise|. +
+ +
+ To synchronously instantiate a WebAssembly module from a {{Module}} |moduleObject| and imports |importObject|, perform the following steps: + 1. Let |module| be |moduleObject|.\[[Module]]. + 1. [=Read the imports=] of |module| with imports |importObject|, and let |imports| be the result. + 1. [=Instantiate the core of a WebAssembly module=] |module| with |imports|, and let |instance| be the result. + 1. Let |instanceObject| be a [=/new=] {{Instance}}. + 1. [=initialize an instance object|Initialize=] |instanceObject| from |module| and |instance|. + 1. Return |instanceObject|. +
+ +
+ To instantiate a promise of a module |promiseOfModule| with imports |importObject|, perform the following steps: + + 1. Let |promise| be [=a new promise=]. + 1. [=Upon fulfillment=] of |promiseOfModule| with value |module|: + 1. [=asynchronously instantiate a WebAssembly module|Instantiate the WebAssembly module=] |module| importing |importObject|, and let |innerPromise| be the result. + 1. [=Upon fulfillment=] of |innerPromise| with value |instance|. + 1. Let |result| be the {{WebAssemblyInstantiatedSource}} value «[ "{{WebAssemblyInstantiatedSource/module}}" → |module|, "{{WebAssemblyInstantiatedSource/instance}}" → |instance| ]». + 1. [=Resolve=] |promise| with |result|. + 1. [=Upon rejection=] of |innerPromise| with reason |reason|: + 1. [=Reject=] |promise| with |reason|. + 1. [=Upon rejection=] of |promiseOfModule| with reason |reason|: + 1. [=Reject=] |promise| with |reason|. + 1. Return |promise|. +
+ +
+ The instantiate(|bytes|, |importObject|) method, when invoked, performs the following steps: + 1. Let |stableBytes| be a [=get a copy of the buffer source|copy of the bytes held by the buffer=] |bytes|. + 1. [=Asynchronously compile a WebAssembly module=] from |stableBytes| and let |promiseOfModule| be the result. + 1. [=Instantiate a promise of a module|Instantiate=] |promiseOfModule| with imports |importObject| and return the result. +
+ +
+ The instantiate(|moduleObject|, |importObject|) method, when invoked, performs the following steps: + 1. [=asynchronously instantiate a WebAssembly module|Asynchronously instantiate the WebAssembly module=] |moduleObject| importing |importObject|, and return the result. +
+ +Note: A follow-on streaming API is documented in the WebAssembly Web API. + +

Modules

+ +
+enum ImportExportKind {
+  "function",
+  "table",
+  "memory",
+  "global",
+  "tag"
+};
+
+dictionary ModuleExportDescriptor {
+  required USVString name;
+  required ImportExportKind kind;
+  // Note: Other fields such as signature may be added in the future.
+};
+
+dictionary ModuleImportDescriptor {
+  required USVString module;
+  required USVString name;
+  required ImportExportKind kind;
+};
+
+[LegacyNamespace=WebAssembly, Exposed=*]
+interface Module {
+  constructor(BufferSource bytes);
+  static sequence<ModuleExportDescriptor> exports(Module moduleObject);
+  static sequence<ModuleImportDescriptor> imports(Module moduleObject);
+  static sequence<ArrayBuffer> customSections(Module moduleObject, DOMString sectionName);
+};
+
+ +
+ The string value of the extern type |type| is + * "function" if |type| is of the form [=func=] functype + * "table" if |type| is of the form [=table=] tabletype + * "memory" if |type| is of the form [=mem=] memtype + * "global" if |type| is of the form [=global=] globaltype + * "tag" if |type| is of the form [=externtype/tag=] tag +
+ +
+ The exports(|moduleObject|) method, when invoked, performs the following steps: + 1. Let |module| be |moduleObject|.\[[Module]]. + 1. Let |exports| be « ». + 1. [=list/iterate|For each=] (|name|, |type|) of [=module_exports=](|module|), + 1. Let |kind| be the [=string value of the extern type=] |type|. + 1. Let |obj| be «[ "{{ModuleExportDescriptor/name}}" → |name|, "{{ModuleExportDescriptor/kind}}" → |kind| ]». + 1. [=list/Append=] |obj| to |exports|. + 1. Return |exports|. +
+ +
+ The imports(|moduleObject|) method, when invoked, performs the following steps: + 1. Let |module| be |moduleObject|.\[[Module]]. + 1. Let |imports| be « ». + 1. [=list/iterate|For each=] (|moduleName|, |name|, |type|) of [=module_imports=](|module|), + 1. Let |kind| be the [=string value of the extern type=] |type|. + 1. Let |obj| be «[ "{{ModuleImportDescriptor/module}}" → |moduleName|, "{{ModuleImportDescriptor/name}}" → |name|, "{{ModuleImportDescriptor/kind}}" → |kind| ]». + 1. [=list/Append=] |obj| to |imports|. + 1. Return |imports|. +
+ +
+ The customSections(|moduleObject|, |sectionName|) method, when invoked, performs the following steps: + 1. Let |bytes| be |moduleObject|.\[[Bytes]]. + 1. Let |customSections| be « ». + 1. [=list/iterate|For each=] [=custom section=] |customSection| of |bytes|, interpreted according to the [=module grammar=], + 1. Let |name| be the name of |customSection|, [=UTF-8 decode without BOM or fail|decoded as UTF-8=]. + 1. Assert: |name| is not failure (|moduleObject|.\[[Module]] is [=valid=]). + 1. If |name| equals |sectionName| as string values, + 1. [=list/Append=] a new {{ArrayBuffer}} containing a copy of the bytes in |bytes| for the range matched by this [=customsec=] production to |customSections|. + 1. Return |customSections|. +
+ +
+ The Module(|bytes|) constructor, when invoked, performs the following steps: + + 1. Let |stableBytes| be a [=get a copy of the buffer source|copy of the bytes held by the buffer=] |bytes|. + 1. [=Compile a WebAssembly module|Compile the WebAssembly module=] |stableBytes| and store the result as |module|. + 1. If |module| is [=error=], throw a {{CompileError}} exception. + 1. Set **this**.\[[Module]] to |module|. + 1. Set **this**.\[[Bytes]] to |stableBytes|. + +Note: Some implementations enforce a size limitation on |bytes|. Use of this API is discouraged, in favor of asynchronous APIs. +
+ +

Instances

+ +
+[LegacyNamespace=WebAssembly, Exposed=*]
+interface Instance {
+  constructor(Module module, optional object importObject);
+  readonly attribute object exports;
+};
+
+ +
+ The Instance(|module|, |importObject|) constructor, when invoked, runs the following steps: + 1. Let |module| be |module|.\[[Module]]. + 1. [=Read the imports=] of |module| with imports |importObject|, and let |imports| be the result. + 1. [=Instantiate the core of a WebAssembly module=] |module| with |imports|, and let |instance| be the result. + 1. [=initialize an instance object|Initialize=] **this** from |module| and |instance|. + +Note: The use of this synchronous API is discouraged, as some implementations sometimes do long-running compilation work when instantiating. +
+ +
+ The getter of the exports attribute of {{Instance}} returns **this**.\[[Exports]]. +
+ +

Memories

+ +
+dictionary MemoryDescriptor {
+  required [EnforceRange] unsigned long initial;
+  [EnforceRange] unsigned long maximum;
+};
+
+[LegacyNamespace=WebAssembly, Exposed=*]
+interface Memory {
+  constructor(MemoryDescriptor descriptor);
+  unsigned long grow([EnforceRange] unsigned long delta);
+  readonly attribute ArrayBuffer buffer;
+};
+
+ +A {{Memory}} object represents a single [=memory instance=] +which can be simultaneously referenced by multiple {{Instance}} objects. Each +{{Memory}} object has the following internal slots: + + * \[[Memory]] : a [=memory address=] + * \[[BufferObject]] : an {{ArrayBuffer}} whose [=Data Block=] is [=identified with=] the above memory address + +
+ To create a memory buffer from a [=memory address=] |memaddr|, perform the following steps: + + 1. Let |block| be a [=Data Block=] which is [=identified with=] the underlying memory of |memaddr|. + 1. Let |buffer| be a new {{ArrayBuffer}} whose \[[ArrayBufferData]] is |block| and \[[ArrayBufferByteLength]] is set to the length of |block|. + 1. Set |buffer|.\[[ArrayBufferDetachKey]] to "WebAssembly.Memory". + 1. Return |buffer|. +
+ +
+ To initialize a memory object |memory| from a [=memory address=] |memaddr|, perform the following steps: + 1. Let |map| be the [=surrounding agent=]'s associated [=Memory object cache=]. + 1. Assert: |map|[|memaddr|] doesn't [=map/exist=]. + 1. Let |buffer| be the result of [=create a memory buffer|creating a memory buffer=] from |memaddr|. + 1. Set |memory|.\[[Memory]] to |memaddr|. + 1. Set |memory|.\[[BufferObject]] to |buffer|. + 1. [=map/Set=] |map|[|memaddr|] to |memory|. +
+ +
+ To create a memory object from a [=memory address=] |memaddr|, perform the following steps: + + 1. Let |map| be the [=surrounding agent=]'s associated [=Memory object cache=]. + 1. If |map|[|memaddr|] [=map/exists=], + 1. Return |map|[|memaddr|]. + 1. Let |memory| be a [=/new=] {{Memory}}. + 1. [=initialize a memory object|Initialize=] |memory| from |memaddr|. + 1. Return |memory|. +
+ +
+ The Memory(|descriptor|) constructor, when invoked, performs the following steps: + 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| < |initial|, throw a {{RangeError}} exception. + 1. Let |memtype| be { min |initial|, max |maximum| }. + 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. + 1. Let (|store|, |memaddr|) be [=mem_alloc=](|store|, |memtype|). If allocation fails, throw a {{RangeError}} exception. + 1. Set the [=surrounding agent=]'s [=associated store=] to |store|. + 1. [=initialize a memory object|Initialize=] **this** from |memaddr|. +
+ +
+ To reset the Memory buffer of |memaddr|, perform the following steps: + + 1. Let |map| be the [=surrounding agent=]'s associated [=Memory object cache=]. + 1. Assert: |map|[|memaddr|] [=map/exists=]. + 1. Let |memory| be |map|[|memaddr|]. + 1. Perform [=!=] [$DetachArrayBuffer$](|memory|.\[[BufferObject]], "WebAssembly.Memory"). + 1. Let |buffer| be the result of [=create a memory buffer|creating a memory buffer=] from |memaddr|. + 1. Set |memory|.\[[BufferObject]] to |buffer|. +
+ +
+ The grow(|delta|) method, when invoked, performs the following steps: + 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. + 1. Let |memaddr| be **this**.\[[Memory]]. + 1. Let |ret| be the [=mem_size=](|store|, |memaddr|). + 1. Let |store| be [=mem_grow=](|store|, |memaddr|, |delta|). + 1. If |store| is [=error=], throw a {{RangeError}} exception. + 1. Set the [=surrounding agent=]'s [=associated store=] to |store|. + 1. [=Reset the memory buffer=] of |memaddr|. + 1. Return |ret|. +
+ +Immediately after a WebAssembly [=memory.grow=] instruction executes, perform the following steps: + +
+ 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. Let |memaddr| be the memory address |frame|.[=frame/module=].[=moduleinst/memaddrs=][0]. + 1. [=Reset the memory buffer=] of |memaddr|. +
+ +
+ The getter of the buffer attribute of {{Memory}} returns **this**.\[[BufferObject]]. +
+ +

Tables

+ +
+enum TableKind {
+  "externref",
+  "anyfunc",
+  // Note: More values may be added in future iterations,
+  // e.g., typed function references, typed GC references
+};
+
+dictionary TableDescriptor {
+  required TableKind element;
+  required [EnforceRange] unsigned long initial;
+  [EnforceRange] unsigned long maximum;
+};
+
+[LegacyNamespace=WebAssembly, Exposed=*]
+interface Table {
+  constructor(TableDescriptor descriptor, optional any value);
+  unsigned long grow([EnforceRange] unsigned long delta, optional any value);
+  any get([EnforceRange] unsigned long index);
+  undefined set([EnforceRange] unsigned long index, optional any value);
+  readonly attribute unsigned long length;
+};
+
+ +A {{Table}} object represents a single [=table instance=] which can be simultaneously referenced by +multiple {{Instance}} objects. +Each {{Table}} object has a \[[Table]] internal slot, which is a [=table address=]. + +
+ To initialize a table object |table| from a [=table address=] |tableaddr|, perform the following steps: + 1. Let |map| be the [=surrounding agent=]'s associated [=Table object cache=]. + 1. Assert: |map|[|tableaddr|] doesn't [=map/exist=]. + 1. Set |table|.\[[Table]] to |tableaddr|. + 1. [=map/Set=] |map|[|tableaddr|] to |table|. +
+ +
+ To create a table object from a [=table address=] |tableaddr|, perform the following steps: + 1. Let |map| be the [=surrounding agent=]'s associated [=Table object cache=]. + 1. If |map|[|tableaddr|] [=map/exists=], + 1. Return |map|[|tableaddr|]. + 1. Let |table| be a [=/new=] {{Table}}. + 1. [=initialize a table object|Initialize=] |table| from |tableaddr|. + 1. Return |table|. +
+ +
+ The Table(|descriptor|, |value|) 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. 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| < |initial|, throw a {{RangeError}} exception. + 1. If |value| is missing, + 1. Let |ref| be [=DefaultValue=](|elementType|). + 1. Otherwise, + 1. Let |ref| be [=?=] [=ToWebAssemblyValue=](|value|, |elementType|). + 1. Let |type| be the [=table type=] {[=table type|min=] |initial|, [=table type|max=] |maximum|} |elementType|. + 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. + 1. Let (|store|, |tableaddr|) be [=table_alloc=](|store|, |type|, |ref|). + 1. Set the [=surrounding agent=]'s [=associated store=] to |store|. + 1. [=initialize a table object|Initialize=] **this** from |tableaddr|. +
+ +
+ The grow(|delta|, |value|) method, when invoked, performs the following steps: + 1. Let |tableaddr| be **this**.\[[Table]]. + 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. + 1. Let |initialSize| be [=table_size=](|store|, |tableaddr|). + 1. Let (limits, |elementType|) be [=table_type=](|tableaddr|). + 1. If |value| is missing, + 1. Let |ref| be [=DefaultValue=](|elementType|). + 1. Otherwise, + 1. Let |ref| be [=?=] [=ToWebAssemblyValue=](|value|, |elementType|). + 1. Let |result| be [=table_grow=](|store|, |tableaddr|, |delta|, |ref|). + 1. If |result| is [=error=], throw a {{RangeError}} exception. + + Note: The above exception can happen due to either insufficient memory or an invalid size parameter. + + 1. Set the [=surrounding agent=]'s [=associated store=] to |result|. + 1. Return |initialSize|. +
+ +
+ The getter of the length attribute of {{Table}}, when invoked, performs the following steps: + 1. Let |tableaddr| be **this**.\[[Table]]. + 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. + 1. Return [=table_size=](|store|, |tableaddr|). +
+ +
+ The get(|index|) method, when invoked, performs the following steps: + 1. Let |tableaddr| be **this**.\[[Table]]. + 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. + 1. Let |result| be [=table_read=](|store|, |tableaddr|, |index|). + 1. If |result| is [=error=], throw a {{RangeError}} exception. + 1. Return [=ToJSValue=](|result|). +
+ +
+ The set(|index|, |value|) method, when invoked, performs the following steps: + 1. Let |tableaddr| be **this**.\[[Table]]. + 1. Let (limits, |elementType|) be [=table_type=](|tableaddr|). + 1. If |value| is missing, + 1. Let |ref| be [=DefaultValue=](|elementType|). + 1. Otherwise, + 1. Let |ref| be [=?=] [=ToWebAssemblyValue=](|value|, |elementType|). + 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. + 1. Let |store| be [=table_write=](|store|, |tableaddr|, |index|, |ref|). + 1. If |store| is [=error=], throw a {{RangeError}} exception. + 1. Set the [=surrounding agent=]'s [=associated store=] to |store|. +
+ +

Globals

+ +
+enum ValueType {
+  "i32",
+  "i64",
+  "f32",
+  "f64",
+  "v128",
+  "externref",
+  "anyfunc",
+};
+
+ +Note: this type may be extended with additional cases in future versions of WebAssembly. + +
+dictionary GlobalDescriptor {
+  required ValueType value;
+  boolean mutable = false;
+};
+
+[LegacyNamespace=WebAssembly, Exposed=*]
+interface Global {
+  constructor(GlobalDescriptor descriptor, optional any v);
+  any valueOf();
+  attribute any value;
+};
+
+ +A {{Global}} object represents a single [=global instance=] +which can be simultaneously referenced by multiple {{Instance}} objects. Each +{{Global}} object has one internal slot: + + * \[[Global]] : a [=global address=] + +
+ To initialize a global object |global| from a [=global address=] |globaladdr|, perform the following steps: + 1. Let |map| be the [=surrounding agent=]'s associated [=Global object cache=]. + 1. Assert: |map|[|globaladdr|] doesn't [=map/exist=]. + 1. Set |global|.\[[Global]] to |globaladdr|. + 1. [=map/Set=] |map|[|globaladdr|] to |global|. +
+ +
+ To create a global object from a [=global address=] |globaladdr|, perform the following steps: + 1. Let |map| be the current [=agent=]'s associated [=Global object cache=]. + 1. If |map|[|globaladdr|] [=map/exists=], + 1. Return |map|[|globaladdr|]. + 1. Let |global| be a [=/new=] {{Global}}. + 1. [=initialize a global object|Initialize=] |global| from |globaladdr|. + 1. Return |global|. +
+ +
+ The algorithm ToValueType(|s|) performs the following steps: + 1. If |s| equals "i32", return [=i32=]. + 1. If |s| equals "i64", return [=i64=]. + 1. If |s| equals "f32", return [=f32=]. + 1. If |s| equals "f64", return [=f64=]. + 1. If |s| equals "v128", return [=v128=]. + 1. If |s| equals "anyfunc", return [=funcref=]. + 1. If |s| equals "externref", return [=externref=]. + 1. Assert: This step is not reached. +
+ +
+ The algorithm DefaultValue(|valuetype|) performs the following steps: + 1. If |valuetype| equals [=i32=], return [=i32.const=] 0. + 1. If |valuetype| equals [=i64=], return [=i64.const=] 0. + 1. If |valuetype| equals [=f32=], return [=f32.const=] 0. + 1. If |valuetype| equals [=f64=], return [=f64.const=] 0. + 1. If |valuetype| equals [=funcref=], return [=ref.null=] [=funcref=]. + 1. If |valuetype| equals [=externref=], return [=ToWebAssemblyValue=](undefined, |valuetype|). + 1. Assert: This step is not reached. +
+ +
+ The Global(|descriptor|, |v|) constructor, when invoked, performs the following steps: + 1. Let |mutable| be |descriptor|["mutable"]. + 1. Let |valuetype| be [=ToValueType=](|descriptor|["value"]). + 1. If |valuetype| is [=v128=], + 1. Throw a {{TypeError}} exception. + 1. If |v| is missing, + 1. Let |value| be [=DefaultValue=](|valuetype|). + 1. Otherwise, + 1. Let |value| be [=ToWebAssemblyValue=](|v|, |valuetype|). + 1. If |mutable| is true, let |globaltype| be [=var=] |valuetype|; otherwise, let |globaltype| be [=const=] |valuetype|. + 1. Let |store| be the current agent's [=associated store=]. + 1. Let (|store|, |globaladdr|) be [=global_alloc=](|store|, |globaltype|, |value|). + 1. Set the current agent's [=associated store=] to |store|. + 1. [=initialize a global object|Initialize=] **this** from |globaladdr|. +
+ +
+ The algorithm GetGlobalValue({{Global}} |global|) performs the following steps: + 1. Let |store| be the current agent's [=associated store=]. + 1. Let |globaladdr| be |global|.\[[Global]]. + 1. Let |globaltype| be [=global_type=](|store|, |globaladdr|). + 1. If |globaltype| is of the form mut [=v128=], throw a {{TypeError}}. + 1. Let |value| be [=global_read=](|store|, |globaladdr|). + 1. Return [=ToJSValue=](|value|). +
+ +
+ The getter of the value attribute of {{Global}}, when invoked, performs the following steps: + 1. Return [=GetGlobalValue=](**this**). + + The setter of the value attribute of {{Global}}, when invoked, performs the following steps: + 1. Let |store| be the current agent's [=associated store=]. + 1. Let |globaladdr| be **this**.\[[Global]]. + 1. Let |mut| |valuetype| be [=global_type=](|store|, |globaladdr|). + 1. If |valuetype| is [=v128=], throw a {{TypeError}}. + 1. If |mut| is [=const=], throw a {{TypeError}}. + 1. Let |value| be [=ToWebAssemblyValue=](**the given value**, |valuetype|). + 1. Let |store| be [=global_write=](|store|, |globaladdr|, |value|). + 1. If |store| is [=error=], throw a {{RangeError}} exception. + 1. Set the current agent's [=associated store=] to |store|. +
+ +
+ The valueOf() method, when invoked, performs the following steps: + 1. Return [=GetGlobalValue=](**this**). +
+ +

Exported Functions

+ +A WebAssembly function is made available in JavaScript as an Exported Function. +Exported Functions are [=Built-in Function Objects=] which are not constructors, and which have a \[[FunctionAddress]] internal slot. +This slot holds a [=function address=] relative to the [=surrounding agent=]'s [=associated store=]. + +
+ The name of the WebAssembly function |funcaddr| is found by performing the following steps: + + 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. + 1. Let |funcinst| be |store|.funcs[|funcaddr|]. + 1. If |funcinst| is of the form {type functype, hostcode |hostfunc|}, + 1. Assert: |hostfunc| is a JavaScript object and [$IsCallable$](|hostfunc|) is true. + 1. Let |index| be the [=index of the host function=] |funcaddr|. + 1. Otherwise, + 1. Let |moduleinst| be |funcinst|.module. + 1. Assert: |funcaddr| is contained in |moduleinst|.funcaddrs. + 1. Let |index| be the index of |moduleinst|.funcaddrs where |funcaddr| is found. + 1. Return [=!=] [$ToString$](|index|). +
+ +
+ To create a new Exported Function from a WebAssembly [=function address=] |funcaddr|, perform the following steps: + + 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 |realm| be the [=current Realm=]. + 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. + 1. Let |functype| be [=func_type=](|store|, |funcaddr|). + 1. Let [|paramTypes|] → [resultTypes] be |functype|. + 1. Let |arity| be |paramTypes|'s [=list/size=]. + 1. Let |name| be the [=name of the WebAssembly function=] |funcaddr|. + 1. Let |function| be [=!=] [$CreateBuiltinFunction$](|steps|, |arity|, |name|, « \[[FunctionAddress]] », |realm|). + 1. Set |function|.\[[FunctionAddress]] to |funcaddr|. + 1. [=map/Set=] |map|[|funcaddr|] to |function|. + 1. Return |function|. +
+ +
+ 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 [|parameters|] → [|results|] be |functype|. + 1. If |parameters| or |results| contain [=v128=], 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. + 1. [=list/iterate|For each=] |t| of |parameters|, + 1. If |argValues|'s [=list/size=] > |i|, let |arg| be |argValues|[|i|]. + 1. Otherwise, let |arg| be undefined. + 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|, val* | [=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 the WebAssembly error mapping. + 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. Throw |exception|. + 1. Let |outArity| be the [=list/size=] of |ret|. + 1. If |outArity| is 0, return undefined. + 1. Otherwise, if |outArity| is 1, return [=ToJSValue=](|ret|[0]). + 1. Otherwise, + 1. Let |values| be « ». + 1. [=list/iterate|For each=] |r| of |ret|, + 1. [=list/Append=] [=ToJSValue=](|r|) to |values|. + 1. Return [$CreateArrayFromList$](|values|). +
+ +Note: [=call an Exported Function|Calling an Exported Function=] executes in the \[[Realm]] of the callee Exported Function, as per the definition of [=built-in function objects=]. + +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=], 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. Let |resultsSize| be |results|'s [=list/size=]. + 1. If |resultsSize| is 0, return « ». + 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. 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. + 1. For each |value| and |resultType| in |values| and |results|, paired linearly, + 1. [=list/Append=] [=ToWebAssemblyValue=](|value|, |resultType|) to |wasmValues|. + 1. Return |wasmValues|. +
+ +
+ To create a host function from the JavaScript object |func| and 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. [=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. [=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. If |result|.\[[Type]] is throw, then: + 1. Let |v| be |result|.\[[Value]]. + 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. [=WebAssembly/Throw=] with |type|, |payload| and |opaqueData|. + 1. Otherwise, return |result|.\[[Value]]. + 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|. +
+ +
+The algorithm ToJSValue(|w|) coerces a [=WebAssembly value=] to a JavaScript value by performing the following steps: + +1. Assert: |w| is not of the form [=v128.const=] v128. +1. If |w| is of the form [=i64.const=] |i64|, + 1. Let |v| be [=signed_64=](|i64|). + 1. Return [=ℤ=](|v| interpreted as a mathematical value). +1. If |w| is of the form [=i32.const=] |i32|, return [=𝔽=]([=signed_32=](|i32| interpreted as a mathematical value)). +1. If |w| is of the form [=f32.const=] |f32|, + 1. If |f32| is [=+∞=] or [=−∞=], return **+∞**𝔽 or **-∞**𝔽, respectively. + 1. If |f32| is [=nan=], return **NaN**. + 1. Return [=𝔽=](|f32| interpreted as a mathematical value). +1. If |w| is of the form [=f64.const=] |f64|, + 1. If |f64| is [=+∞=] or [=−∞=], return **+∞**𝔽 or **-∞**𝔽, respectively. + 1. If |f64| is [=nan=], return **NaN**. + 1. Return [=𝔽=](|f64| interpreted as a mathematical value). +1. If |w| is of the form [=ref.null=] t, return null. +1. If |w| is of the form [=ref.func=] |funcaddr|, return the result of creating [=a new Exported Function=] from |funcaddr|. +1. If |w| is of the form [=ref.extern=] |externaddr|, return the result of [=retrieving an extern value=] from |externaddr|. + +Note: Number values which are equal to NaN may have various observable NaN payloads; see [$NumericToRawBytes$] for details. +
+ +
+ +For retrieving an extern value from an [=extern address=] |externaddr|, perform the following steps: + +1. Let |map| be the [=surrounding agent=]'s associated [=extern value cache=]. +1. Assert: |map|[|externaddr|] [=map/exists=]. +1. Return |map|[|externaddr|]. + +
+ +
+The algorithm ToWebAssemblyValue(|v|, |type|) coerces a JavaScript value to a [=WebAssembly value=] by performing the following steps: + +1. Assert: |type| is not [=v128=]. +1. If |type| is [=i64=], + 1. Let |i64| be [=?=] [$ToBigInt64$](|v|). + 1. Return [=i64.const=] |i64|. +1. If |type| is [=i32=], + 1. Let |i32| be [=?=] [$ToInt32$](|v|). + 1. Return [=i32.const=] |i32|. +1. If |type| is [=f32=], + 1. Let |number| be [=?=] [$ToNumber$](|v|). + 1. If |number| is **NaN**, + 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. Return [=f32.const=] |f32|. +1. If |type| is [=f64=], + 1. Let |number| be [=?=] [$ToNumber$](|v|). + 1. If |number| is **NaN**, + 1. Let |n| be an implementation-defined integer such that [=canon=]64 ≤ |n| < 2[=signif=](64). + 1. Let |f64| be [=nan=](n). + 1. Otherwise, + 1. Let |f64| be |number|. + 1. Return [=f64.const=] |f64|. +1. If |type| is [=funcref=], + 1. If |v| is null, + 1. Return [=ref.null=] [=funcref=]. + 1. If |v| is an [=Exported Function=], + 1. Let |funcaddr| be the value of |v|'s \[[FunctionAddress]] internal slot. + 1. Return [=ref.func=] |funcaddr|. + 1. Throw a {{TypeError}}. +1. If |type| is [=externref=], + 1. If |v| is null, + 1. Return [=ref.null=] [=externref=]. + 1. Let |map| be the [=surrounding agent=]'s associated [=extern value cache=]. + 1. If a [=extern address=] |externaddr| exists such that |map|[|externaddr|] is the same as |v|, + 1. Return [=ref.extern=] |externaddr|. + 1. Let [=extern address=] |externaddr| be the smallest address such that |map|[|externaddr|] [=map/exists=] is false. + 1. [=map/Set=] |map|[|externaddr|] to |v|. + 1. Return [=ref.extern=] |externaddr|. +1. Assert: This step is not reached. + +
+ +

Tags

+ +The tag_alloc(|store|, |parameters|) algorithm creates a new [=tag address=] for |parameters| in |store| and returns the updated store and the [=tag address=]. + +The tag_parameters(|store|, |tagAddress|) algorithm returns the [=list=] of types for |tagAddress| in |store|. + +

Exception types

+ +
+dictionary TagType {
+  required sequence<ValueType> parameters;
+};
+
+[LegacyNamespace=WebAssembly, Exposed=(Window,Worker,Worklet)]
+interface Tag {
+  constructor(TagType type);
+  TagType type();
+};
+
+ +A {{Tag}} value represents a type of exception. + +
+ +To initialize a Tag object |tag| from a [=tag address=] |tagAddress|, perform the following steps: + +1. Let |map| be the [=surrounding agent=]'s associated [=Tag object cache=]. +1. Assert: |map|[|tagAddress|] doesn't [=map/exist=]. +1. Set |tag|.\[[Address]] to |tagAddress|. +1. [=map/Set=] |map|[|tagAddress|] to |tag|. + +
+ +
+ +To create a Tag object from a [=tag address=] |tagAddress|, perform the following steps: + +1. Let |map| be the [=surrounding agent=]'s associated [=Tag object cache=]. +1. If |map|[|tagAddress|] [=map/exists=], + 1. Return |map|[|tagAddress|]. +1. Let |tag| be a [=new=] {{Tag}}. +1. [=initialize a Tag object|Initialize=] |tag| from |tagAddress|. +1. Return |tag|. + +
+ +
+ +The new Tag(|type|) constructor steps are: + +1. Let |parameters| be |type|["parameters"]. +1. Let |wasmParameters| be «». +1. [=list/iterate|For each=] |type| of |parameters|, + 1. [=list/Append=] [=ToValueType=](|type|) to |wasmParameters|. +1. Let |store| be the current agent's [=associated store=]. +1. Let (|store|, |tagAddress|) be [=tag_alloc=](|store|, |wasmParameters|). +1. Set the current agent's [=associated store=] to |store|. +1. [=initialize a Tag object|Initialize=] **this** from |tagAddress|. + +
+ +
+ +The type() method steps are: + +1. Let |store| be the [=surrounding agent=]'s [=associated store=]. +1. Let |parameters| be [=tag_parameters=](|store|, **this**.\[[Address]]). +1. Let |idlParameters| be «». +1. [=list/iterate|For each=] |type| of |parameters|, + 1. [=list/Append=] [$FromValueType$](|type|) to |idlParameters|. +1. Return «[ "{{TagType/parameters}}" → |idlParameters| ]». + +Advisement: This method is only expected to be implemented or shipped when both this proposal and the Type Reflection proposal are implemented or shipped (respectively). + +
+ +

Runtime exceptions

+ +
+dictionary ExceptionOptions {
+  boolean traceStack = false;
+};
+
+[LegacyNamespace=WebAssembly, Exposed=(Window,Worker,Worklet)]
+interface Exception {
+  constructor(Tag exceptionTag, sequence<any> payload, optional ExceptionOptions options = {});
+  any getArg(Tag exceptionTag, [EnforceRange] unsigned long index);
+  boolean is(Tag exceptionTag);
+  readonly attribute (DOMString or undefined) stack;
+};
+
+ +An {{Exception}} value represents an exception. + +
+ +To create an Exception object from a [=tag address=] |tagAddress| and a [=list=] of +WebAssembly values |payload|, perform the following steps: + +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|. + +
+ +
+ +The new Exception(|exceptionTag|, |payload|, |options|) +constructor steps are: + +1. Let |store| be the [=surrounding agent=]'s [=associated store=]. +1. Let |types| be [=tag_parameters=](|store|, |exceptionTag|.\[[Address]]). +1. If |types|'s [=list/size=] is not |payload|'s [=list/size=], + 1. Throw a {{TypeError}}. +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|. +1. Set **this**.\[[Type]] to |exceptionTag|.\[[Address]]. +1. Set **this**.\[[Payload]] to |wasmPayload|. +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. + +
+ +
+ +The getArg(|exceptionTag|, |index|) method steps are: + +1. If **this**.\[[Type]] is not equal to |exceptionTag|.\[[Address]], + 1. Throw a {{TypeError}}. +1. Let |payload| be **this**.\[[Payload]]. +1. If |index| ≥ |payload|'s [=list/size=], + 1. Throw a {{RangeError}}. +1. Return [=ToJSValue=](|payload|[|index|]). + +
+ +
+ +The is(|exceptionTag|) method steps are: + +1. If **this**.\[[Type]] is not equal to |exceptionTag|.\[[Address]], + 1. Return false. +1. Return true. + +
+ +
+ +The stack getter steps are: + +1. Return **this**.\[[Stack]]. + +
+ +

JavaScript exceptions

+ +The JavaScript exception tag is a [=tag address=] reserved by this +specification to distinguish exceptions originating from JavaScript. + +For any [=associated store=] |store|, the result of +[=tag_parameters=](|store|, [=JavaScript exception tag=]) must be « ». + +
+ +To throw with a [=tag address=] |type|, a matching [=list=] of WebAssembly values |payload|, and an [=externref=] |opaqueData|, perform the following steps: + +1. Unwind the stack until reaching the *catching try block* given |type|. +1. Invoke the catch block with |payload| and |opaqueData|. + +Note: This algorithm is expected to be moved into the core specification. + +
+ +

Error Objects

+ +WebAssembly defines the following Error classes: CompileError, LinkError, and RuntimeError. + +
+When the [=namespace object=] for the {{WebAssembly}} namespace is [=create a namespace object|created=], the following steps must be run: + +1. Let |namespaceObject| be the [=namespace object=]. +1. [=list/iterate|For each=] |error| of « "CompileError", "LinkError", "RuntimeError" », + 1. Let |constructor| be a new object, implementing the [=NativeError Object Structure=], with NativeError set to |error|. + 1. [=!=] [$CreateMethodProperty$](|namespaceObject|, |error|, |constructor|). + +
+ +Note: This defines {{CompileError}}, {{LinkError}}, and {{RuntimeError}} classes on the {{WebAssembly}} namespace, which are produced by the APIs defined in this specification. +They expose the same interface as native JavaScript errors like {{TypeError}} and {{RangeError}}. + +Note: It is not currently possible to define this behavior using Web IDL. + + +

Error Condition Mappings to JavaScript

+ +Running WebAssembly programs encounter certain events which halt execution of the WebAssembly code. +WebAssembly code (currently) +has no way to catch these conditions and thus an exception will necessarily +propagate to the enclosing non-WebAssembly caller (whether it is a browser, +JavaScript or another runtime system) where it is handled like a normal JavaScript exception. + +If WebAssembly calls JavaScript via import and the JavaScript throws an +exception, the exception is propagated through the WebAssembly activation to the +enclosing caller. + +Because JavaScript exceptions can be handled, and JavaScript can continue to +call WebAssembly exports after a trap has been handled, traps do not, in +general, prevent future execution. + +

Stack Overflow

+ +Whenever a stack overflow occurs in +WebAssembly code, the same class of exception is thrown as for a stack overflow in +JavaScript. The particular exception here is implementation-defined in both cases. + +Note: ECMAScript doesn't specify any sort of behavior on stack overflow; implementations have been observed to throw {{RangeError}}, InternalError or Error. Any is valid here. + +

Out of Memory

+ +Whenever validation, compilation or instantiation run out of memory, the +same class of exception is thrown as for out of memory conditions in JavaScript. +The particular exception here is implementation-defined in both cases. + +Note: ECMAScript doesn't specify any sort of behavior on out-of-memory conditions; implementations have been observed to throw OOMError and to crash. Either is valid here. + +
+ A failed allocation of a large table or memory may either result in + - a {{RangeError}}, as specified in the {{Memory}} {{Memory/grow()}} and {{Table}} {{Table/grow()}} operations + - returning -1 as the [=memory.grow=] instruction + - UA-specific OOM behavior as described in this section. + In a future revision, we may reconsider more reliable and recoverable errors for allocations of large amounts of memory. + + See [Issue 879](https://github.com/WebAssembly/spec/issues/879) for further discussion. +
+ +

Implementation-defined Limits

+ +The WebAssembly core specification allows an implementation to define limits on the syntactic structure of the module. +While each embedding of WebAssembly may choose to define its own limits, for predictability the standard WebAssembly JavaScript Interface described in this document defines the following exact limits. +An implementation must reject a module that exceeds one of the following limits with a {{CompileError}}: +In practice, an implementation may run out of resources for valid modules below these limits. + +
    +
  • The maximum size of a module is 1,073,741,824 bytes (1 GiB).
  • +
  • The maximum number of types defined in the types section is 1,000,000.
  • +
  • The maximum number of functions defined in a module is 1,000,000.
  • +
  • The maximum number of imports declared in a module is 100,000.
  • +
  • The maximum number of exports declared in a module is 100,000.
  • +
  • The maximum number of globals defined in a module is 1,000,000.
  • +
  • The maximum number of tags defined in a module is 1,000,000.
  • +
  • The maximum number of data segments defined in a module is 100,000.
  • + +
  • The maximum number of tables, including declared or imported tables, is 100,000.
  • +
  • The maximum size of a table is 10,000,000.
  • +
  • The maximum number of table entries in any table initialization is 10,000,000.
  • +
  • The maximum number of memories, including declared or imported memories, is 1.
  • + +
  • The maximum number of parameters to any function or block is 1,000.
  • +
  • The maximum number of return values for any function or block is 1,000.
  • +
  • The maximum size of a function body, including locals declarations, is 7,654,321 bytes.
  • +
  • The maximum number of locals declared in a function, including implicitly declared as parameters, is 50,000.
  • +
+ +An implementation must throw a {{RuntimeError}} if one of the following limits is exceeded during runtime: +In practice, an implementation may run out of resources for valid modules below these limits. + +
    +
  • The maximum size of a table is 10,000,000.
  • +
  • The maximum number of pages of a memory is 65,536.
  • +
+ +

Security and Privacy Considerations

+ +

This section is non-normative.

+ +This document defines a host environment for WebAssembly. It enables a WebAssembly instance to [=import=] JavaScript objects and functions from an [=read the imports|import object=], but otherwise provides no access to the embedding environment. Thus a WebAssembly instance is bound to the same constraints as JavaScript. diff --git a/document/web-api/index.bs b/document/web-api/index.bs index efeb3bb95..5edd4e8a9 100644 --- a/document/web-api/index.bs +++ b/document/web-api/index.bs @@ -76,6 +76,7 @@ url:https://w3c.github.io/webappsec-secure-contexts/#environment-settings-object @@ -118,8 +119,10 @@ Note: This algorithm accepts a {{Response}} object, or a 1. Let |returnValue| be [=a new promise=] 1. [=Upon fulfillment=] of |source| with value |unwrappedSource|: 1. Let |response| be |unwrappedSource|'s [=Response/response=]. - 1. Let |mimeType| be the result of [=extracting a MIME type=] from |response|'s [=response/header list=]. - 1. If |mimeType| is not `` `application/wasm` ``, reject |returnValue| with a {{TypeError}} and abort these substeps. + 1. Let |mimeType| be the result of [=header list/getting=] `` `Content-Type` `` from |response|'s [=response/header list=]. + 1. If |mimeType| is null, reject |returnValue| with a {{TypeError}} and abort these substeps. + 1. Remove all [=HTTP tab or space byte=] from the start and end of |mimeType|. + 1. If |mimeType| is not a [=byte-case-insensitive=] match for `` `application/wasm` ``, reject |returnValue| with a {{TypeError}} and abort these substeps. Note: extra parameters are not allowed, including the empty `` `application/wasm;` ``. diff --git a/interpreter/Makefile b/interpreter/Makefile index 7820e6428..3294e2682 100644 --- a/interpreter/Makefile +++ b/interpreter/Makefile @@ -18,12 +18,12 @@ JSLIB = wast WINMAKE = winmake.bat DIRS = util syntax binary text valid runtime exec script host main tests -LIBS = bigarray +LIBS = FLAGS = -lexflags -ml -cflags '-w +a-4-27-42-44-45-70 -warn-error +a-3' OCBA = ocamlbuild $(FLAGS) $(DIRS:%=-I %) OCB = $(OCBA) $(LIBS:%=-libs %) JSO = js_of_ocaml -q --opt 3 -JS = # set to JS shell command to run JS tests +JS = # set to JS shell command to run JS tests, empty to skip # Main targets @@ -41,10 +41,12 @@ all: unopt opt libunopt libopt test land: $(WINMAKE) all zip: $(ZIP) smallint: smallint.native +ci: land wast.js dunebuild dunebuild: dune build + # Building executable empty = @@ -175,6 +177,7 @@ smallinttest: smallint dunetest: dune test + # Miscellaneous targets .PHONY: clean diff --git a/interpreter/README.md b/interpreter/README.md index 418b84501..e79998965 100644 --- a/interpreter/README.md +++ b/interpreter/README.md @@ -1,6 +1,6 @@ # WebAssembly Reference Interpreter -This repository implements a interpreter for WebAssembly. It is written for clarity and simplicity, _not_ speed. It is intended as a playground for trying out ideas and a device for nailing down the exact semantics, and as a proxy for the (yet to be produced) formal specification of WebAssembly. For that purpose, the code is written in a fairly declarative, "speccy" way. +This repository implements an interpreter for WebAssembly. It is written for clarity and simplicity, _not_ speed. It is intended as a playground for trying out ideas and a device for nailing down their exact semantics. For that purpose, the code is written in a fairly declarative, "speccy" way. The interpreter can @@ -15,7 +15,7 @@ The text format defines modules in S-expression syntax. Moreover, it is generali ## Building -You'll need OCaml 4.08 or higher. Instructions for installing a recent version of OCaml on multiple platforms are available [here](https://ocaml.org/docs/install.html). On most platforms, the recommended way is through [OPAM](https://ocaml.org/docs/install.html#OPAM). +You'll need OCaml 4.12 or higher. Instructions for installing a recent version of OCaml on multiple platforms are available [here](https://ocaml.org/docs/install.html). On most platforms, the recommended way is through [OPAM](https://ocaml.org/docs/install.html#OPAM). Once you have OCaml, simply do @@ -203,6 +203,7 @@ func_type: ( type )? * * global_type: | ( mut ) table_type: ? memory_type: ? +tag_type: ( type )? * num: | var: | @@ -231,6 +232,7 @@ expr: ( loop ? * ) ( if ? ( then * ) ( else * )? ) ( if ? + ( then * ) ( else * )? ) ;; = + (if ? (then *) (else *)?) + ( try_table ? * * ) instr: @@ -239,6 +241,7 @@ instr: loop ? * end ? ;; = (loop ? *) if ? * end ? ;; = (if ? (then *)) if ? * else ? * end ? ;; = (if ? (then *) (else *)) + try_table ? * * end ? ;; = (try_table ? * *) op: unreachable @@ -279,6 +282,8 @@ op: ref.null ref.is_null ref.func + throw + throw_ref .const . . @@ -298,6 +303,12 @@ op: .extract_lane(_)? .replace_lane +catch: + catch + catch_ref + catch_all + catch_all_ref + func: ( func ? * * ) ( func ? ( export ) <...> ) ;; = (export (func )) (func ? <...>) ( func ? ( import ) ) ;; = (import (func ? )) @@ -404,6 +415,7 @@ assertion: ( assert_return * ) ;; assert action has expected results ( assert_trap ) ;; assert action traps with given failure string ( assert_exhaustion ) ;; assert action exhausts system resources + ( assert_exception ) ;; assert action throws an exception ( assert_malformed ) ;; assert module cannot be decoded with given failure string ( assert_invalid ) ;; assert module is invalid with given failure string ( assert_unlinkable ) ;; assert module fails to link @@ -495,6 +507,7 @@ assertion: ( assert_return * ) ;; assert action has expected results ( assert_trap ) ;; assert action traps with given failure string ( assert_exhaustion ) ;; assert action exhausts system resources + ( assert_exception ) ;; assert action throws an exception ( assert_malformed ) ;; assert module cannot be decoded with given failure string ( assert_invalid ) ;; assert module is invalid with given failure string ( assert_unlinkable ) ;; assert module fails to link diff --git a/interpreter/binary/decode.ml b/interpreter/binary/decode.ml index f5e4edf9b..8a805bd6e 100644 --- a/interpreter/binary/decode.ml +++ b/interpreter/binary/decode.ml @@ -164,6 +164,7 @@ let ref_type s = match s7 s with | -0x10 -> FuncRefType | -0x11 -> ExternRefType + | -0x17 -> ExnRefType | _ -> error s (pos s - 1) "malformed reference type" let value_type s = @@ -212,6 +213,7 @@ let global_type s = let tag_type s = zero s; at var s + (* Instructions *) open Ast @@ -264,30 +266,10 @@ let rec instr s = end | 0x05 -> error s pos "misplaced ELSE opcode" - | 0x06 -> - let bt = block_type s in - let es = instr_block s in - let ct = catch_list s in - let ca = - if peek s = Some 0x19 then begin - ignore (byte s); - Some (instr_block s) - end else - None - in - if ct <> [] || ca <> None then begin - end_ s; - try_catch bt es ct ca - end else begin - match op s with - | 0x0b -> try_catch bt es [] None - | 0x18 -> try_delegate bt es (at var s) - | b -> illegal s pos b - end - | 0x07 -> error s pos "misplaced CATCH opcode" + | 0x06 | 0x07 as b -> illegal s pos b | 0x08 -> throw (at var s) - | 0x09 -> rethrow (at var s) - | 0x0a as b -> illegal s pos b + | 0x09 as b -> illegal s pos b + | 0x0a -> throw_ref | 0x0b -> error s pos "misplaced END opcode" | 0x0c -> br (at var s) @@ -303,17 +285,26 @@ let rec instr s = let y = at var s in let x = at var s in call_indirect x y + | 0x12 -> return_call (at var s) + | 0x13 -> + let y = at var s in + let x = at var s in + return_call_indirect x y - | 0x12 | 0x13 | 0x14 | 0x15 | 0x16 | 0x17 as b -> illegal s pos b - - | 0x18 -> error s pos "misplaced DELEGATE opcode" - | 0x19 -> error s pos "misplaced CATCH_ALL opcode" + | 0x14 | 0x15 | 0x16 | 0x17 | 0x18 | 0x19 as b -> illegal s pos b | 0x1a -> drop | 0x1b -> select None | 0x1c -> select (Some (vec value_type s)) - | 0x1d | 0x1e | 0x1f as b -> illegal s pos b + | 0x1d | 0x1e as b -> illegal s pos b + + | 0x1f -> + let bt = block_type s in + let cs = vec (at catch) s in + let es = instr_block s in + end_ s; + try_table bt cs es | 0x20 -> local_get (at var s) | 0x21 -> local_set (at var s) @@ -808,19 +799,25 @@ let rec instr s = and instr_block s = List.rev (instr_block' s []) and instr_block' s es = match peek s with - | None | Some (0x05 | 0x07 | 0x0a | 0x0b | 0x18 | 0x19) -> es + | None | Some (0x05 | 0x0b) -> es | _ -> let pos = pos s in let e' = instr s in instr_block' s ((e' @@ region s pos pos) :: es) -and catch_list s = - if peek s = Some 0x07 then begin - ignore (byte s); - let tag = at var s in - let instrs = instr_block s in - (tag, instrs) :: catch_list s - end else - [] + +and catch s = + match byte s with + | 0x00 -> + let x1 = at var s in + let x2 = at var s in + Operators.catch x1 x2 + | 0x01 -> + let x1 = at var s in + let x2 = at var s in + catch_ref x1 x2 + | 0x02 -> catch_all (at var s) + | 0x03 -> catch_all_ref (at var s) + | _ -> error s (pos s - 1) "malformed catch clause" let const s = let c = at instr_block s in diff --git a/interpreter/binary/encode.ml b/interpreter/binary/encode.ml index 7e59a2f18..fb93d7430 100644 --- a/interpreter/binary/encode.ml +++ b/interpreter/binary/encode.ml @@ -77,7 +77,7 @@ struct let string bs = len (String.length bs); put_string s bs let name n = string (Utf8.encode n) let list f xs = List.iter f xs - let opt f xo = Lib.Option.app f xo + let opt f xo = Option.iter f xo let vec f xs = len (List.length xs); list f xs let gap32 () = let p = pos s in word32 0l; byte 0; p @@ -109,6 +109,7 @@ struct let ref_type = function | FuncRefType -> s7 (-0x10) + | ExnRefType -> s7 (-0x17) | ExternRefType -> s7 (-0x11) let value_type = function @@ -167,28 +168,18 @@ struct op 0x04; block_type bt; list instr es1; if es2 <> [] then op 0x05; list instr es2; end_ () - | TryCatch (bt, es, ct, ca) -> - op 0x06; block_type bt; list instr es; - let catch (tag, es) = - op 0x07; var tag; list instr es - in - list catch ct; - begin match ca with - | None -> () - | Some es -> op 0x19; list instr es - end; - end_ () - | TryDelegate (bt, es, x) -> - op 0x06; block_type bt; list instr es; - op 0x18; var x + | TryTable (bt, cs, es) -> + op 0x1f; block_type bt; vec catch cs; list instr es; end_ () | Br x -> op 0x0c; var x | BrIf x -> op 0x0d; var x | BrTable (xs, x) -> op 0x0e; vec var xs; var x | Return -> op 0x0f | Call x -> op 0x10; var x | CallIndirect (x, y) -> op 0x11; var y; var x + | ReturnCall x -> op 0x12; var x + | ReturnCallIndirect (x, y) -> op 0x13; var y; var x | Throw x -> op 0x08; var x - | Rethrow x -> op 0x09; var x + | ThrowRef -> op 0x0a | Drop -> op 0x1a | Select None -> op 0x1b @@ -744,6 +735,13 @@ struct | VecReplace (V128 (F32x4 (V128Op.Replace i))) -> vecop 0x20l; byte i | VecReplace (V128 (F64x2 (V128Op.Replace i))) -> vecop 0x22l; byte i + and catch c = + match c.it with + | Catch (x1, x2) -> byte 0x00; var x1; var x2 + | CatchRef (x1, x2) -> byte 0x01; var x1; var x2 + | CatchAll x -> byte 0x02; var x + | CatchAllRef x -> byte 0x03; var x + let const c = list instr c.it; end_ () diff --git a/dune-project b/interpreter/dune-project similarity index 100% rename from dune-project rename to interpreter/dune-project diff --git a/interpreter/exec/eval.ml b/interpreter/exec/eval.ml index 97b11362c..17baad842 100644 --- a/interpreter/exec/eval.ml +++ b/interpreter/exec/eval.ml @@ -63,15 +63,12 @@ and admin_instr' = | Invoke of func_inst | Trapping of string | Returning of value stack + | ReturningInvoke of value stack * func_inst | Breaking of int32 * value stack | Throwing of Tag.t * value stack - | Rethrowing of int32 * (admin_instr -> admin_instr) | Label of int32 * instr list * code | Frame of int32 * frame * code - | Catch of int32 * (Tag.t * instr list) list * instr list option * code - | Caught of int32 * Tag.t * value stack * code - | Delegate of int32 * code - | Delegating of int32 * Tag.t * value stack + | Handler of int32 * catch list * code type config = { @@ -214,6 +211,21 @@ let rec step (c : config) : config = else vs, [Invoke func @@ e.at] + | ReturnCall x, vs -> + (match (step {c with code = (vs, [Plain (Call x) @@ e.at])}).code with + | vs', [{it = Invoke a; at}] -> vs', [ReturningInvoke (vs', a) @@ at] + | _ -> assert false + ) + + | ReturnCallIndirect (x, y), vs -> + (match + (step {c with code = (vs, [Plain (CallIndirect (x, y)) @@ e.at])}).code + with + | vs', [{it = Invoke a; at}] -> vs', [ReturningInvoke (vs', a) @@ at] + | vs', [{it = Trapping s; at}] -> vs', [Trapping s @@ at] + | _ -> assert false + ) + | Throw x, vs -> let t = tag frame.inst x in let FuncType (ts, _) = Tag.type_of t in @@ -221,23 +233,18 @@ let rec step (c : config) : config = let args, vs' = take n vs e.at, drop n vs e.at in vs', [Throwing (t, args) @@ e.at] - | Rethrow x, vs -> - vs, [Rethrowing (x.it, fun e -> e) @@ e.at] + | ThrowRef, Ref (NullRef _) :: vs -> + vs, [Trapping "null exception reference" @@ e.at] - | TryCatch (bt, es', cts, ca), vs -> - let FuncType (ts1, ts2) = block_type frame.inst bt in - let n1 = Lib.List32.length ts1 in - let n2 = Lib.List32.length ts2 in - let args, vs' = take n1 vs e.at, drop n1 vs e.at in - let cts' = List.map (fun (x, es'') -> ((tag frame.inst x), es'')) cts in - vs', [Label (n2, [], ([], [Catch (n2, cts', ca, (args, List.map plain es')) @@ e.at])) @@ e.at] + | ThrowRef, Ref (ExnRef (t, args)) :: vs -> + vs, [Throwing (t, args) @@ e.at] - | TryDelegate (bt, es', x), vs -> + | TryTable (bt, cs, es'), vs -> let FuncType (ts1, ts2) = block_type frame.inst bt in let n1 = Lib.List32.length ts1 in let n2 = Lib.List32.length ts2 in let args, vs' = take n1 vs e.at, drop n1 vs e.at in - vs', [Label (n2, [], ([], [Delegate (x.it, (args, List.map plain es')) @@ e.at])) @@ e.at] + vs', [Handler (n2, cs, ([], [Label (n2, [], (args, List.map plain es')) @@ e.at])) @@ e.at] | Drop, v :: vs' -> vs', [] @@ -629,7 +636,8 @@ let rec step (c : config) : config = | Trapping msg, vs -> assert false - | Returning vs', vs -> + | Returning _, vs + | ReturningInvoke _, vs -> Crash.error e.at "undefined frame" | Breaking (k, vs'), vs -> @@ -638,12 +646,6 @@ let rec step (c : config) : config = | Throwing _, _ -> assert false - | Rethrowing _, _ -> - Crash.error e.at "undefined catch label" - - | Delegating _, _ -> - Crash.error e.at "undefined delegate label" - | Label (n, es0, (vs', [])), vs -> vs' @ vs, [] @@ -653,6 +655,9 @@ let rec step (c : config) : config = | Label (n, es0, (vs', {it = Returning vs0; at} :: es')), vs -> vs, [Returning vs0 @@ at] + | Label (n, es0, (vs', {it = ReturningInvoke (vs0, f); at} :: es')), vs -> + vs, [ReturningInvoke (vs0, f) @@ at] + | Label (n, es0, (vs', {it = Breaking (0l, vs0); at} :: es')), vs -> take n vs0 e.at @ vs, List.map plain es0 @@ -662,15 +667,6 @@ let rec step (c : config) : config = | Label (n, es0, (vs', {it = Throwing (a, vs0); at} :: es')), vs -> vs, [Throwing (a, vs0) @@ at] - | Label (n, es0, (vs', {it = Delegating (0l, a, vs0); at} :: es')), vs -> - vs, [Throwing (a, vs0) @@ at] - - | Label (n, es0, (vs', {it = Delegating (k, a, vs0); at} :: es')), vs -> - vs, [Delegating (Int32.sub k 1l, a, vs0) @@ at] - - | Label (n, es0, (vs', {it = Rethrowing (k, cont); at} :: es')), vs -> - vs, [Rethrowing (Int32.sub k 1l, (fun e -> Label (n, es0, (vs', cont e :: es')) @@ e.at)) @@ at] - | Label (n, es0, code'), vs -> let c' = step {c with code = code'} in vs, [Label (n, es0, c'.code) @@ e.at] @@ -684,6 +680,10 @@ let rec step (c : config) : config = | Frame (n, frame', (vs', {it = Returning vs0; at} :: es')), vs -> take n vs0 e.at @ vs, [] + | Frame (n, frame', (vs', {it = ReturningInvoke (vs0, f); at} :: es')), vs -> + let FuncType (ins, out) = Func.type_of f in + take (Lib.List32.length ins) vs0 e.at @ vs, [Invoke f @@ at] + | Frame (n, frame', (vs', {it = Throwing (a, vs0); at} :: es')), vs -> vs, [Throwing (a, vs0) @@ at] @@ -691,59 +691,36 @@ let rec step (c : config) : config = let c' = step {frame = frame'; code = code'; budget = c.budget - 1} in vs, [Frame (n, c'.frame, c'.code) @@ e.at] - | Catch (n, cts, ca, (vs', [])), vs -> + | Handler (n, cs, (vs', [])), vs -> vs' @ vs, [] - | Catch (n, cts, ca, (vs', ({it = Trapping _ | Breaking _ | Returning _ | Delegating _; at} as e) :: es')), vs -> + | Handler (n, cs, (vs', ({it = Trapping _ | Breaking _ | Returning _ | ReturningInvoke _; at} as e) :: es')), vs -> vs, [e] - | Catch (n, cts, ca, (vs', {it = Rethrowing (k, cont); at} :: es')), vs -> - vs, [Rethrowing (k, (fun e -> Catch (n, cts, ca, (vs', (cont e) :: es')) @@ e.at)) @@ at] - - | Catch (n, (a', es'') :: cts, ca, (vs', {it = Throwing (a, vs0); at} :: es')), vs -> - if a == a' then - vs, [Caught (n, a, vs0, (vs0, List.map plain es'')) @@ at] + | Handler (n, {it = Catch (x1, x2); _} :: cs, (vs', {it = Throwing (a, vs0); at} :: es')), vs -> + if a == tag frame.inst x1 then + vs0 @ vs, [Plain (Br x2) @@ e.at] else - vs, [Catch (n, cts, ca, (vs', {it = Throwing (a, vs0); at} :: es')) @@ e.at] + vs, [Handler (n, cs, (vs', {it = Throwing (a, vs0); at} :: es')) @@ e.at] - | Catch (n, [], Some es'', (vs', {it = Throwing (a, vs0); at} :: es')), vs -> - vs, [Caught (n, a, vs0, (vs0, List.map plain es'')) @@ at] - - | Catch (n, [], None, (vs', {it = Throwing (a, vs0); at} :: es')), vs -> - vs, [Throwing (a, vs0) @@ at] - - | Catch (n, cts, ca, code'), vs -> - let c' = step {c with code = code'} in - vs, [Catch (n, cts, ca, c'.code) @@ e.at] - - | Caught (n, a, vs0, (vs', [])), vs -> - vs' @ vs, [] - - | Caught (n, a, vs0, (vs', ({it = Trapping _ | Breaking _ | Returning _ | Throwing _ | Delegating _; at} as e) :: es')), vs -> - vs, [e] - - | Caught (n, a, vs0, (vs', {it = Rethrowing (0l, cont); at} :: es')), vs -> - vs, [Caught (n, a, vs0, (vs', (cont (Throwing (a, vs0) @@ at)) :: es')) @@ e.at] - - | Caught (n, a, vs0, (vs', {it = Rethrowing (k, cont); at} :: es')), vs -> - vs, [Rethrowing (k, (fun e -> Caught (n, a, vs0, (vs', (cont e) :: es')) @@ e.at)) @@ at] - - | Caught (n, a, vs0, code'), vs -> - let c' = step {c with code = code'} in - vs, [Caught (n, a, vs0, c'.code) @@ e.at] + | Handler (n, {it = CatchRef (x1, x2); _} :: cs, (vs', {it = Throwing (a, vs0); at} :: es')), vs -> + if a == tag frame.inst x1 then + Ref (ExnRef (a, vs0)) :: vs0 @ vs, [Plain (Br x2) @@ e.at] + else + vs, [Handler (n, cs, (vs', {it = Throwing (a, vs0); at} :: es')) @@ e.at] - | Delegate (l, (vs', [])), vs -> - vs' @ vs, [] + | Handler (n, {it = CatchAll x; _} :: cs, (vs', {it = Throwing (a, vs0); at} :: es')), vs -> + vs, [Plain (Br x) @@ e.at] - | Delegate (l, (vs', ({it = Trapping _ | Breaking _ | Returning _ | Rethrowing _ | Delegating _; at} as e) :: es')), vs -> - vs, [e] + | Handler (n, {it = CatchAllRef x; _} :: cs, (vs', {it = Throwing (a, vs0); at} :: es')), vs -> + Ref (ExnRef (a, vs0)) :: vs, [Plain (Br x) @@ e.at] - | Delegate (l, (vs', {it = Throwing (a, vs0); at} :: es')), vs -> - vs, [Delegating (l, a, vs0) @@ e.at] + | Handler (n, [], (vs', {it = Throwing (a, vs0); at} :: es')), vs -> + vs, [Throwing (a, vs0) @@ at] - | Delegate (l, code'), vs -> + | Handler (n, cs, code'), vs -> let c' = step {c with code = code'} in - vs, [Delegate (l, c'.code) @@ e.at] + vs, [Handler (n, cs, c'.code) @@ e.at] | Invoke func, vs when c.budget = 0 -> Exhaustion.error e.at "call stack exhausted" diff --git a/interpreter/script/js.ml b/interpreter/script/js.ml index a1f27d03a..3bcfeb12b 100644 --- a/interpreter/script/js.ml +++ b/interpreter/script/js.ml @@ -375,6 +375,7 @@ let assert_return ress ts at = let is_ref_idx = match t with | FuncRefType -> is_funcref_idx + | ExnRefType -> assert false | ExternRefType -> is_externref_idx in [ Call (is_ref_idx @@ at) @@ at; diff --git a/interpreter/script/run.ml b/interpreter/script/run.ml index bb92d0b86..8ca9b7a82 100644 --- a/interpreter/script/run.ml +++ b/interpreter/script/run.ml @@ -409,6 +409,7 @@ let assert_ref_pat r p = match r, p with | r, RefPat r' -> r = r'.it | Instance.FuncRef _, RefTypePat Types.FuncRefType + | Values.ExnRef _, RefTypePat Types.ExnRefType | ExternRef _, RefTypePat Types.ExternRefType -> true | _ -> false diff --git a/interpreter/syntax/ast.ml b/interpreter/syntax/ast.ml index b1750ee34..1ba2c2f57 100644 --- a/interpreter/syntax/ast.ml +++ b/interpreter/syntax/ast.ml @@ -149,6 +149,8 @@ and instr' = | Return (* break from function body *) | Call of var (* call function *) | CallIndirect of var * var (* call function through table *) + | ReturnCall of var (* tail-call function *) + | ReturnCallIndirect of var * var (* tail-call function through table *) | LocalGet of var (* read local variable *) | LocalSet of var (* write local variable *) | LocalTee of var (* write local variable and keep value *) @@ -183,13 +185,9 @@ and instr' = | Unary of unop (* unary numeric operator *) | Binary of binop (* binary numeric operator *) | Convert of cvtop (* conversion *) - | TryCatch of block_type * instr list * (* try *) - (var * instr list) list * (* catch exception with tag *) - instr list option (* catch_all *) - | TryDelegate of block_type * instr list * (* try *) - var (* delegate to outer handler *) + | TryTable of block_type * catch list * instr list (* handle exceptions *) | Throw of var (* throw exception *) - | Rethrow of var (* rethrow exception *) + | ThrowRef (* rethrow exception *) | VecConst of vec (* constant *) | VecTest of vec_testop (* vector test *) | VecCompare of vec_relop (* vector comparison *) @@ -206,6 +204,13 @@ and instr' = | VecExtract of vec_extractop (* extract lane from vector *) | VecReplace of vec_replaceop (* replace lane in vector *) +and catch = catch' Source.phrase +and catch' = + | Catch of var * var + | CatchRef of var * var + | CatchAll of var + | CatchAllRef of var + (* Globals & Functions *) diff --git a/interpreter/syntax/free.ml b/interpreter/syntax/free.ml index 774b2d032..650fca1c7 100644 --- a/interpreter/syntax/free.ml +++ b/interpreter/syntax/free.ml @@ -79,8 +79,13 @@ let rec instr (e : instr) = | Br x | BrIf x -> labels (var x) | BrTable (xs, x) -> list (fun x -> labels (var x)) (x::xs) | Return -> empty - | Call x -> funcs (var x) - | CallIndirect (x, y) -> tables (var x) ++ types (var y) + | Call x | ReturnCall x -> funcs (var x) + | CallIndirect (x, y) | ReturnCallIndirect (x, y) -> + tables (var x) ++ types (var y) + | Throw x -> tags (var x) + | ThrowRef -> empty + | TryTable (bt, cs, es) -> + block_type bt ++ list catch cs ++ block es | LocalGet x | LocalSet x | LocalTee x -> locals (var x) | GlobalGet x | GlobalSet x -> globals (var x) | TableGet x | TableSet x | TableSize x | TableGrow x | TableFill x -> @@ -99,19 +104,15 @@ let rec instr (e : instr) = memories zero | MemoryInit x -> memories zero ++ datas (var x) | DataDrop x -> datas (var x) - | TryCatch (bt, es, ct, ca) -> - let catch (tag, es) = tags (var tag) ++ block es in - let catch_all = function - | None -> empty - | Some es -> block es in - block es ++ (list catch ct) ++ catch_all ca - | TryDelegate (bt, es, x) -> block es ++ tags (var x) - | Throw x -> tags (var x) - | Rethrow x -> labels (var x) and block (es : instr list) = let free = list instr es in {free with labels = shift free.labels} +and catch (c : catch) = + match c.it with + | Catch (x1, x2) | CatchRef (x1, x2) -> tags (var x1) ++ labels (var x2) + | CatchAll x | CatchAllRef x -> labels (var x) + let const (c : const) = block c.it let global (g : global) = const g.it.ginit diff --git a/interpreter/syntax/operators.ml b/interpreter/syntax/operators.ml index bb44e4f9b..348207df6 100644 --- a/interpreter/syntax/operators.ml +++ b/interpreter/syntax/operators.ml @@ -20,17 +20,23 @@ let select t = Select t let block bt es = Block (bt, es) let loop bt es = Loop (bt, es) let if_ bt es1 es2 = If (bt, es1, es2) -let try_catch bt es ct ca = TryCatch (bt, es, ct, ca) -let try_delegate bt es x = TryDelegate (bt, es, x) +let try_table bt cs es = TryTable (bt, cs, es) let br x = Br x let br_if x = BrIf x let br_table xs x = BrTable (xs, x) +let catch x1 x2 = Catch (x1, x2) +let catch_ref x1 x2 = CatchRef (x1, x2) +let catch_all x = CatchAll x +let catch_all_ref x = CatchAllRef x + let return = Return let call x = Call x let call_indirect x y = CallIndirect (x, y) +let return_call x = ReturnCall x +let return_call_indirect x y = ReturnCallIndirect (x, y) let throw x = Throw x -let rethrow x = Rethrow x +let throw_ref = ThrowRef let local_get x = LocalGet x let local_set x = LocalSet x diff --git a/interpreter/syntax/types.ml b/interpreter/syntax/types.ml index 5b40d8c3b..cb153df9b 100644 --- a/interpreter/syntax/types.ml +++ b/interpreter/syntax/types.ml @@ -2,7 +2,7 @@ type num_type = I32Type | I64Type | F32Type | F64Type type vec_type = V128Type -type ref_type = FuncRefType | ExternRefType +type ref_type = FuncRefType | ExnRefType | ExternRefType type value_type = NumType of num_type | VecType of vec_type | RefType of ref_type type result_type = value_type list type func_type = FuncType of result_type * result_type @@ -119,10 +119,12 @@ let string_of_vec_type = function let string_of_ref_type = function | FuncRefType -> "funcref" + | ExnRefType -> "exnref" | ExternRefType -> "externref" let string_of_refed_type = function | FuncRefType -> "func" + | ExnRefType -> "exn" | ExternRefType -> "extern" let string_of_value_type = function diff --git a/interpreter/syntax/values.ml b/interpreter/syntax/values.ml index eefe37d5d..d4238a117 100644 --- a/interpreter/syntax/values.ml +++ b/interpreter/syntax/values.ml @@ -13,10 +13,12 @@ type num = (I32.t, I64.t, F32.t, F64.t) op type vec = (V128.t) vecop type ref_ = .. -type ref_ += NullRef of ref_type type value = Num of num | Vec of vec | Ref of ref_ +type ref_ += NullRef of ref_type +type ref_ += ExnRef of Tag.t * value list + (* Injection & projection *) @@ -96,7 +98,8 @@ let type_of_num = function let type_of_vec = function | V128 _ -> V128Type -let type_of_ref' = ref (function NullRef t -> t | _ -> assert false) +let type_of_ref' = + ref (function NullRef t -> t | ExnRef _ -> ExnRefType | _ -> assert false) let type_of_ref r = !type_of_ref' r let type_of_value = function @@ -114,6 +117,7 @@ let eq_vec v1 v2 = v1 = v2 let eq_ref' = ref (fun r1 r2 -> match r1, r2 with | NullRef _, NullRef _ -> true + | ExnRef _, ExnRef _ -> r1 == r2 | _, _ -> false ) @@ -169,7 +173,8 @@ let string_of_vec = function let hex_string_of_vec = function | V128 v -> V128.to_hex_string v -let string_of_ref' = ref (function NullRef t -> "null" | _ -> "ref") +let string_of_ref' = + ref (function NullRef t -> "null" | ExnRef _ -> "exn" | _ -> "ref") let string_of_ref r = !string_of_ref' r let string_of_value = function diff --git a/interpreter/text/arrange.ml b/interpreter/text/arrange.ml index 76e14bba2..53c463f1d 100644 --- a/interpreter/text/arrange.ml +++ b/interpreter/text/arrange.ml @@ -453,6 +453,13 @@ let rec instr e = | Call x -> "call " ^ var x, [] | CallIndirect (x, y) -> "call_indirect " ^ var x, [Node ("type " ^ var y, [])] + | ReturnCall x -> "return_call " ^ var x, [] + | ReturnCallIndirect (x, y) -> + "return_call_indirect " ^ var x, [Node ("type " ^ var y, [])] + | Throw x -> "throw " ^ var x, [] + | ThrowRef -> "throw_ref", [] + | TryTable (bt, cs, es) -> + "try_table", block_type bt @ list catch cs @ list instr es | LocalGet x -> "local.get " ^ var x, [] | LocalSet x -> "local.set " ^ var x, [] | LocalTee x -> "local.tee " ^ var x, [] @@ -487,18 +494,6 @@ let rec instr e = | Unary op -> unop op, [] | Binary op -> binop op, [] | Convert op -> cvtop op, [] - | TryCatch (bt, es, ct, ca) -> - let catch (tag, es) = Node ("catch " ^ var tag, list instr es) in - let catch_all = match ca with - | Some es -> [Node ("catch_all", list instr es)] - | None -> [] in - let handler = list catch ct @ catch_all in - "try", block_type bt @ [Node ("do", list instr es)] @ handler - | TryDelegate (bt, es, x) -> - let delegate = [Node ("delegate " ^ var x, [])] in - "try", block_type bt @ [Node ("do", list instr es)] @ delegate - | Throw x -> "throw " ^ var x, [] - | Rethrow x -> "rethrow " ^ var x, [] | VecConst v -> vec_constop v.it ^ " " ^ vec v, [] | VecTest op -> vec_testop op, [] | VecUnary op -> vec_unop op, [] @@ -516,6 +511,13 @@ let rec instr e = | VecReplace op -> vec_replaceop op, [] in Node (head, inner) +and catch c = + match c.it with + | Catch (x1, x2) -> Node ("catch " ^ var x1 ^ " " ^ var x2, []) + | CatchRef (x1, x2) -> Node ("catch_ref " ^ var x1 ^ " " ^ var x2, []) + | CatchAll x -> Node ("catch_all " ^ var x, []) + | CatchAllRef x -> Node ("catch_all_ref " ^ var x, []) + let const head c = match c.it with | [e] -> instr e diff --git a/interpreter/text/lexer.mll b/interpreter/text/lexer.mll index 9c709b130..f7d091443 100644 --- a/interpreter/text/lexer.mll +++ b/interpreter/text/lexer.mll @@ -147,7 +147,9 @@ rule token = parse | "f32x4" -> VEC_SHAPE (V128.F32x4 ()) | "f64x2" -> VEC_SHAPE (V128.F64x2 ()) + | "exn" -> EXN | "extern" -> EXTERN + | "exnref" -> EXNREF | "externref" -> EXTERNREF | "funcref" -> FUNCREF | "mut" -> MUT @@ -168,6 +170,15 @@ rule token = parse | "select" -> SELECT | "call" -> CALL | "call_indirect" -> CALL_INDIRECT + | "return_call" -> RETURN_CALL + | "return_call_indirect" -> RETURN_CALL_INDIRECT + | "try_table" -> TRY_TABLE + | "catch" -> CATCH + | "catch_ref" -> CATCH_REF + | "catch_all" -> CATCH_ALL + | "catch_all_ref" -> CATCH_ALL_REF + | "throw" -> THROW + | "throw_ref" -> THROW_REF | "local.get" -> LOCAL_GET | "local.set" -> LOCAL_SET @@ -274,6 +285,7 @@ rule token = parse | "ref.null" -> REF_NULL | "ref.func" -> REF_FUNC + | "ref.exn" -> REF_EXN | "ref.extern" -> REF_EXTERN | "ref.is_null" -> REF_IS_NULL @@ -653,14 +665,6 @@ rule token = parse | "f32x4.replace_lane" -> VEC_REPLACE f32x4_replace_lane | "f64x2.replace_lane" -> VEC_REPLACE f64x2_replace_lane - | "try" -> TRY - | "do" -> DO - | "catch" -> CATCH - | "catch_all" -> CATCH_ALL - | "delegate" -> DELEGATE - | "throw" -> THROW - | "rethrow" -> RETHROW - | "type" -> TYPE | "func" -> FUNC | "param" -> PARAM diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly index 13617b063..be41cd7ae 100644 --- a/interpreter/text/parser.mly +++ b/interpreter/text/parser.mly @@ -144,9 +144,6 @@ let func_type (c : context) x = try (Lib.List32.nth c.types.list x.it).it with Failure _ -> error x.at ("unknown type " ^ Int32.to_string x.it) -let handlers (c : context) h = - List.map (fun (l, i) -> (l c tag, i c)) h - let anon category space n = let i = space.count in space.count <- Int32.add i n; @@ -214,11 +211,11 @@ let inline_type_explicit (c : context) x ft at = %token NUM_TYPE %token VEC_TYPE %token VEC_SHAPE -%token FUNCREF EXTERNREF EXTERN MUT +%token FUNCREF EXNREF EXTERNREF EXN EXTERN MUT %token UNREACHABLE NOP DROP SELECT -%token BLOCK END IF THEN ELSE LOOP BR BR_IF BR_TABLE TRY DO CATCH CATCH_ALL -%token DELEGATE -%token CALL CALL_INDIRECT RETURN +%token BLOCK END IF THEN ELSE LOOP BR BR_IF BR_TABLE +%token TRY_TABLE CATCH CATCH_REF CATCH_ALL CATCH_ALL_REF THROW THROW_REF +%token CALL CALL_INDIRECT RETURN RETURN_CALL RETURN_CALL_INDIRECT %token LOCAL_GET LOCAL_SET LOCAL_TEE GLOBAL_GET GLOBAL_SET %token TABLE_GET TABLE_SET %token TABLE_SIZE TABLE_GROW TABLE_FILL TABLE_COPY TABLE_INIT ELEM_DROP @@ -227,8 +224,7 @@ let inline_type_explicit (c : context) x ft at = %token OFFSET_EQ_NAT ALIGN_EQ_NAT %token Ast.instr' * Values.num> CONST %token UNARY BINARY TEST COMPARE CONVERT -%token REF_NULL REF_FUNC REF_EXTERN REF_IS_NULL -%token THROW RETHROW +%token REF_NULL REF_FUNC REF_EXN REF_EXTERN REF_IS_NULL %token Memory.offset -> Ast.instr'> VEC_LOAD VEC_STORE %token Memory.offset -> int -> Ast.instr'> VEC_LOAD_LANE VEC_STORE_LANE %token string Source.phrase list -> Source.region -> Ast.instr' * Values.vec> VEC_CONST @@ -267,10 +263,12 @@ string_list : ref_kind : | FUNC { FuncRefType } + | EXN { ExnRefType } | EXTERN { ExternRefType } ref_type : | FUNCREF { FuncRefType } + | EXNREF { ExnRefType } | EXTERNREF { ExternRefType } value_type : @@ -373,12 +371,16 @@ align_opt : /* Instructions & Expressions */ -instr : +instr_list : + | /* empty */ { fun c -> [] } + | instr1 instr_list { fun c -> $1 c @ $2 c } + | select_instr_instr_list { $1 } + | call_instr_instr_list { $1 } + +instr1 : | plain_instr { let at = at () in fun c -> [$1 c @@ at] } - | select_instr_instr { fun c -> let e, es = $1 c in e :: es } - | call_instr_instr { fun c -> let e, es = $1 c in e :: es } | block_instr { let at = at () in fun c -> [$1 c @@ at] } - | expr { $1 } /* Sugar */ + | expr { $1 } /* Sugar */ plain_instr : | UNREACHABLE { fun c -> unreachable } @@ -391,8 +393,9 @@ plain_instr : br_table xs x } | RETURN { fun c -> return } | CALL var { fun c -> call ($2 c func) } + | RETURN_CALL var { fun c -> return_call ($2 c func) } | THROW var { fun c -> throw ($2 c tag) } - | RETHROW var { fun c -> rethrow ($2 c label) } + | THROW_REF { fun c -> throw_ref } | LOCAL_GET var { fun c -> local_get ($2 c local) } | LOCAL_SET var { fun c -> local_set ($2 c local) } | LOCAL_TEE var { fun c -> local_tee ($2 c local) } @@ -451,89 +454,59 @@ plain_instr : | VEC_REPLACE NAT { let at = at () in fun c -> $1 (vec_lane_index $2 at) } -select_instr : - | SELECT select_instr_results - { let at = at () in fun c -> let b, ts = $2 in - select (if b then (Some ts) else None) @@ at } - -select_instr_results : - | LPAR RESULT value_type_list RPAR select_instr_results - { let _, ts = $5 in true, $3 @ ts } - | /* empty */ - { false, [] } - -select_instr_instr : - | SELECT select_instr_results_instr +select_instr_instr_list : + | SELECT select_instr_results_instr_list { let at1 = ati 1 in fun c -> let b, ts, es = $2 c in - select (if b then (Some ts) else None) @@ at1, es } + (select (if b then (Some ts) else None) @@ at1) :: es } -select_instr_results_instr : - | LPAR RESULT value_type_list RPAR select_instr_results_instr +select_instr_results_instr_list : + | LPAR RESULT value_type_list RPAR select_instr_results_instr_list { fun c -> let _, ts, es = $5 c in true, $3 @ ts, es } - | instr + | instr_list { fun c -> false, [], $1 c } -call_instr : - | CALL_INDIRECT var call_instr_type - { let at = at () in fun c -> call_indirect ($2 c table) ($3 c) @@ at } - | CALL_INDIRECT call_instr_type /* Sugar */ - { let at = at () in fun c -> call_indirect (0l @@ at) ($2 c) @@ at } - -call_instr_type : - | type_use call_instr_params +call_instr_instr_list : + | CALL_INDIRECT var call_instr_type_instr_list { let at1 = ati 1 in - fun c -> - match $2 c with - | FuncType ([], []) -> $1 c type_ - | ft -> inline_type_explicit c ($1 c type_) ft at1 } - | call_instr_params - { let at = at () in fun c -> inline_type c ($1 c) at } - -call_instr_params : - | LPAR PARAM value_type_list RPAR call_instr_params - { fun c -> let FuncType (ts1, ts2) = $5 c in FuncType ($3 @ ts1, ts2) } - | call_instr_results - { fun c -> FuncType ([], $1 c) } - -call_instr_results : - | LPAR RESULT value_type_list RPAR call_instr_results - { fun c -> $3 @ $5 c } - | /* empty */ - { fun c -> [] } - - -call_instr_instr : - | CALL_INDIRECT var call_instr_type_instr + fun c -> let x, es = $3 c in + (call_indirect ($2 c table) x @@ at1) :: es } + | CALL_INDIRECT call_instr_type_instr_list /* Sugar */ + { let at1 = ati 1 in + fun c -> let x, es = $2 c in + (call_indirect (0l @@ at1) x @@ at1) :: es } + | RETURN_CALL_INDIRECT var call_instr_type_instr_list { let at1 = ati 1 in - fun c -> let x, es = $3 c in call_indirect ($2 c table) x @@ at1, es } - | CALL_INDIRECT call_instr_type_instr /* Sugar */ + fun c -> let x, es = $3 c in + (return_call_indirect ($2 c table) x @@ at1) :: es } + | RETURN_CALL_INDIRECT call_instr_type_instr_list /* Sugar */ { let at1 = ati 1 in - fun c -> let x, es = $2 c in call_indirect (0l @@ at1) x @@ at1, es } + fun c -> let x, es = $2 c in + (return_call_indirect (0l @@ at1) x @@ at1) :: es } -call_instr_type_instr : - | type_use call_instr_params_instr +call_instr_type_instr_list : + | type_use call_instr_params_instr_list { let at1 = ati 1 in fun c -> match $2 c with | FuncType ([], []), es -> $1 c type_, es | ft, es -> inline_type_explicit c ($1 c type_) ft at1, es } - | call_instr_params_instr + | call_instr_params_instr_list { let at = at () in fun c -> let ft, es = $1 c in inline_type c ft at, es } -call_instr_params_instr : - | LPAR PARAM value_type_list RPAR call_instr_params_instr +call_instr_params_instr_list : + | LPAR PARAM value_type_list RPAR call_instr_params_instr_list { fun c -> let FuncType (ts1, ts2), es = $5 c in FuncType ($3 @ ts1, ts2), es } - | call_instr_results_instr + | call_instr_results_instr_list { fun c -> let ts, es = $1 c in FuncType ([], ts), es } -call_instr_results_instr : - | LPAR RESULT value_type_list RPAR call_instr_results_instr +call_instr_results_instr_list : + | LPAR RESULT value_type_list RPAR call_instr_results_instr_list { fun c -> let ts, es = $5 c in $3 @ ts, es } - | instr + | instr_list { fun c -> [], $1 c } @@ -547,12 +520,9 @@ block_instr : | IF labeling_opt block ELSE labeling_end_opt instr_list END labeling_end_opt { fun c -> let c' = $2 c ($5 @ $8) in let ts, es1 = $3 c' in if_ ts es1 ($6 c') } - | TRY labeling_opt block handler_instr - { fun c -> let c' = $2 c [] in - let ts, es = $3 c' in $4 ts es c' } - | TRY labeling_opt block DELEGATE var - { fun c -> let c' = $2 c [] in - let ts, es = $3 c' in try_delegate ts es ($5 c label) } + | TRY_TABLE labeling_opt handler_block END labeling_end_opt + { fun c -> let c' = $2 c $5 in + let bt, (cs, es) = $3 c c' in try_table bt cs es } block : | type_use block_param_body @@ -582,43 +552,49 @@ block_result_body : { let FuncType (ins, out) = fst $5 in FuncType (ins, $3 @ out), snd $5 } -handler_instr : - | catch_list_instr END - { fun bt es c -> try_catch bt es (handlers c $1) None } - | catch_list_instr catch_all END - { fun bt es c -> try_catch bt es (handlers c $1) (Some ($2 c)) } - | catch_all END - { fun bt es c -> try_catch bt es [] (Some ($1 c)) } - | END { fun bt es c -> try_catch bt es [] None } - -catch_list_instr : - | catch catch_list_instr { $1 :: $2 } - | catch { [$1] } - -handler : - | catch_list - { fun bt es _ c' -> - let cs = (List.map (fun (l, i) -> (l c' tag, i c')) $1) in - try_catch bt es cs None } - | catch_list LPAR catch_all RPAR - { fun bt es _ c' -> - let cs = (List.map (fun (l, i) -> (l c' tag, i c')) $1) in - try_catch bt es cs (Some ($3 c')) } - | LPAR catch_all RPAR - { fun bt es _ c' -> try_catch bt es [] (Some ($2 c')) } - | LPAR DELEGATE var RPAR - { fun bt es c _ -> try_delegate bt es ($3 c label) } - | /* empty */ { fun bt es c _ -> try_catch bt es [] None } - -catch_list : - | catch_list LPAR catch RPAR { $1 @ [$3] } - | LPAR catch RPAR { [$2] } - -catch : - | CATCH var instr_list { ($2, $3) } - -catch_all : - | CATCH_ALL instr_list { $2 } + +handler_block : + | type_use handler_block_param_body + { let at1 = ati 1 in + fun c c' -> let ft, esh = $2 c c' in + VarBlockType (inline_type_explicit c ($1 c type_) ft at1), esh } + | handler_block_param_body /* Sugar */ + { let at = at () in + fun c c' -> let ft, esh = $1 c c' in + let bt = + match ft with + | FuncType ([], []) -> ValBlockType None + | FuncType ([], [t]) -> ValBlockType (Some t) + | ft -> VarBlockType (inline_type c ft at) + in bt, esh } + +handler_block_param_body : + | handler_block_result_body { $1 } + | LPAR PARAM value_type_list RPAR handler_block_param_body + { fun c c' -> let FuncType (ins, out), esh = $5 c c' in + FuncType ($3 @ ins, out), esh } + +handler_block_result_body : + | handler_block_body { fun c c' -> FuncType ([], []), $1 c c' } + | LPAR RESULT value_type_list RPAR handler_block_result_body + { fun c c' -> let FuncType (ins, out), esh = $5 c c' in + FuncType (ins, $3 @ out), esh } + +handler_block_body : + | instr_list + { fun c c' -> [], $1 c' } + | LPAR CATCH var var RPAR handler_block_body + { fun c c' -> let cs, es = $6 c c' in + (catch ($3 c tag) ($4 c label) @@ ati 2) :: cs, es } + | LPAR CATCH_REF var var RPAR handler_block_body + { fun c c' -> let cs, es = $6 c c' in + (catch_ref ($3 c tag) ($4 c label) @@ ati 2) :: cs, es } + | LPAR CATCH_ALL var RPAR handler_block_body + { fun c c' -> let cs, es = $5 c c' in + (catch_all ($3 c label) @@ ati 2) :: cs, es } + | LPAR CATCH_ALL_REF var RPAR handler_block_body + { fun c c' -> let cs, es = $5 c c' in + (catch_all_ref ($3 c label) @@ ati 2) :: cs, es } expr : /* Sugar */ @@ -634,6 +610,11 @@ expr1 : /* Sugar */ | CALL_INDIRECT call_expr_type /* Sugar */ { let at1 = ati 1 in fun c -> let x, es = $2 c in es, call_indirect (0l @@ at1) x } + | RETURN_CALL_INDIRECT var call_expr_type + { fun c -> let x, es = $3 c in es, return_call_indirect ($2 c table) x } + | RETURN_CALL_INDIRECT call_expr_type /* Sugar */ + { let at1 = ati 1 in + fun c -> let x, es = $2 c in es, return_call_indirect (0l @@ at1) x } | BLOCK labeling_opt block { fun c -> let c' = $2 c [] in let bt, es = $3 c' in [], block bt es } | LOOP labeling_opt block @@ -641,8 +622,9 @@ expr1 : /* Sugar */ | IF labeling_opt if_block { fun c -> let c' = $2 c [] in let bt, (es, es1, es2) = $3 c c' in es, if_ bt es1 es2 } - | TRY labeling_opt try_block - { fun c -> let c' = $2 c [] in [], $3 c c' } + | TRY_TABLE labeling_opt try_block + { fun c -> let c' = $2 c [] in + let bt, (cs, es) = $3 c c' in [], try_table bt cs es } select_expr_results : | LPAR RESULT value_type_list RPAR select_expr_results @@ -712,43 +694,53 @@ if_ : | LPAR THEN instr_list RPAR /* Sugar */ { fun c c' -> [], $3 c', [] } + try_block : | type_use try_block_param_body { let at = at () in fun c c' -> - let bt = VarBlockType (inline_type_explicit c' ($1 c' type_) (fst $2) at) in - snd $2 bt c c' } + let ft, esh = $2 c c' in + let bt = VarBlockType (inline_type_explicit c' ($1 c' type_) ft at) in + bt, esh } | try_block_param_body /* Sugar */ { let at = at () in fun c c' -> + let ft, esh = $1 c c' in let bt = - match fst $1 with + match ft with | FuncType ([], []) -> ValBlockType None | FuncType ([], [t]) -> ValBlockType (Some t) - | ft -> VarBlockType (inline_type c' ft at) - in snd $1 bt c c' } + | _ -> VarBlockType (inline_type c' ft at) + in bt, esh } try_block_param_body : | try_block_result_body { $1 } | LPAR PARAM value_type_list RPAR try_block_param_body - { let FuncType (ins, out) = fst $5 in - FuncType ($3 @ ins, out), snd $5 } + { fun c c' -> let FuncType (ins, out), esh = $5 c c' in + FuncType ($3 @ ins, out), esh } try_block_result_body : - | try_ { FuncType ([], []), $1 } + | try_block_handler_body { fun c c' -> FuncType ([], []), $1 c c' } | LPAR RESULT value_type_list RPAR try_block_result_body - { let FuncType (ins, out) = fst $5 in - FuncType (ins, $3 @ out), snd $5 } + { fun c c' -> let FuncType (ins, out), esh = $5 c c' in + FuncType (ins, $3 @ out), esh } -try_ : - | LPAR DO instr_list RPAR handler - { fun bt c c' -> $5 bt ($3 c') c c' } +try_block_handler_body : + | instr_list + { fun c c' -> [], $1 c' } + | LPAR CATCH var var RPAR try_block_handler_body + { fun c c' -> let cs, es = $6 c c' in + (catch ($3 c tag) ($4 c label) @@ ati 2) :: cs, es } + | LPAR CATCH_REF var var RPAR try_block_handler_body + { fun c c' -> let cs, es = $6 c c' in + (catch_ref ($3 c tag) ($4 c label) @@ ati 2) :: cs, es } + | LPAR CATCH_ALL var RPAR try_block_handler_body + { fun c c' -> let cs, es = $5 c c' in + (catch_all ($3 c label) @@ ati 2) :: cs, es } + | LPAR CATCH_ALL_REF var RPAR try_block_handler_body + { fun c c' -> let cs, es = $5 c c' in + (catch_all_ref ($3 c label) @@ ati 2) :: cs, es } -instr_list : - | /* empty */ { fun c -> [] } - | select_instr { fun c -> [$1 c] } - | call_instr { fun c -> [$1 c] } - | instr instr_list { fun c -> $1 c @ $2 c } expr_list : | /* empty */ { fun c -> [] } @@ -859,11 +851,11 @@ elem_expr_list : elem_var_list : | var_list { let f = function {at; _} as x -> [ref_func x @@ at] @@ at in - fun c lookup -> List.map f ($1 c lookup) } + fun c -> List.map f ($1 c func) } elem_list : | elem_kind elem_var_list - { ($1, fun c -> $2 c func) } + { ($1, fun c -> $2 c) } | ref_type elem_expr_list { ($1, fun c -> $2 c) } @@ -895,7 +887,7 @@ elem : { let at = at () in fun c -> ignore ($3 c anon_elem bind_elem); fun () -> - { etype = FuncRefType; einit = $5 c func; + { etype = FuncRefType; einit = $5 c; emode = Active {index = 0l @@ at; offset = $4 c} @@ at } @@ at } table : @@ -915,19 +907,19 @@ table_fields : | inline_export table_fields /* Sugar */ { fun c x at -> let tabs, elems, ims, exs = $2 c x at in tabs, elems, ims, $1 (TableExport x) c :: exs } - | ref_type LPAR ELEM elem_var_list RPAR /* Sugar */ + | ref_type LPAR ELEM elem_expr elem_expr_list RPAR /* Sugar */ { fun c x at -> let offset = [i32_const (0l @@ at) @@ at] @@ at in - let einit = $4 c func in + let einit = $4 c :: $5 c in let size = Lib.List32.length einit in let emode = Active {index = x; offset} @@ at in [{ttype = TableType ({min = size; max = Some size}, $1)} @@ at], - [{etype = FuncRefType; einit; emode} @@ at], + [{etype = $1; einit; emode} @@ at], [], [] } - | ref_type LPAR ELEM elem_expr elem_expr_list RPAR /* Sugar */ + | ref_type LPAR ELEM elem_var_list RPAR /* Sugar */ { fun c x at -> let offset = [i32_const (0l @@ at) @@ at] @@ at in - let einit = (fun c -> $4 c :: $5 c) c in + let einit = $4 c in let size = Lib.List32.length einit in let emode = Active {index = x; offset} @@ at in [{ttype = TableType ({min = size; max = Some size}, $1)} @@ at], @@ -1268,6 +1260,7 @@ result : | LPAR CONST NAN RPAR { NumResult (NanPat (nanop $2 ($3 @@ ati 3))) @@ at () } | literal_ref { RefResult (RefPat ($1 @@ at ())) @@ at () } | LPAR REF_FUNC RPAR { RefResult (RefTypePat FuncRefType) @@ at () } +/*| LPAR REF_EXN RPAR { RefResult (RefTypePat ExnRefType) @@ at () }*/ | LPAR REF_EXTERN RPAR { RefResult (RefTypePat ExternRefType) @@ at () } | LPAR VEC_CONST VEC_SHAPE numpat_list RPAR { if V128.num_lanes $3 <> List.length $4 then diff --git a/interpreter/valid/valid.ml b/interpreter/valid/valid.ml index 34707dbdf..1f177519f 100644 --- a/interpreter/valid/valid.ml +++ b/interpreter/valid/valid.ml @@ -14,8 +14,6 @@ let require b at s = if not b then error at s (* Context *) -type label_kind = BlockLabel | CatchLabel - type context = { types : func_type list; @@ -28,7 +26,7 @@ type context = datas : unit list; locals : value_type list; results : value_type list; - labels : (label_kind * result_type) list; + labels : result_type list; refs : Free.t; } @@ -257,34 +255,34 @@ let rec check_instr (c : context) (e : instr) (s : infer_result_type) : op_type | Block (bt, es) -> let FuncType (ts1, ts2) as ft = check_block_type c bt in - check_block {c with labels = (BlockLabel, ts2) :: c.labels} es ft e.at; + check_block {c with labels = ts2 :: c.labels} es ft e.at; ts1 --> ts2 | Loop (bt, es) -> let FuncType (ts1, ts2) as ft = check_block_type c bt in - check_block {c with labels = (BlockLabel, ts1) :: c.labels} es ft e.at; + check_block {c with labels = ts1 :: c.labels} es ft e.at; ts1 --> ts2 | If (bt, es1, es2) -> let FuncType (ts1, ts2) as ft = check_block_type c bt in - check_block {c with labels = (BlockLabel, ts2) :: c.labels} es1 ft e.at; - check_block {c with labels = (BlockLabel, ts2) :: c.labels} es2 ft e.at; + check_block {c with labels = ts2 :: c.labels} es1 ft e.at; + check_block {c with labels = ts2 :: c.labels} es2 ft e.at; (ts1 @ [NumType I32Type]) --> ts2 | Br x -> - let (_, ts) = label c x in + let ts = label c x in ts -->... [] | BrIf x -> - let (_, ts) = label c x in + let ts = label c x in (ts @ [NumType I32Type]) --> ts | BrTable (xs, x) -> - let (_, ts) = label c x in + let ts = label c x in let n = List.length ts in let ts' = Lib.List.table n (fun i -> peek (n - i) s) in check_stack ts' (known ts) x.at; - List.iter (fun x' -> check_stack ts' (known (snd (label c x'))) x'.at) xs; + List.iter (fun x' -> check_stack ts' (known (label c x')) x'.at) xs; (ts' @ [Some (NumType I32Type)]) -~>... [] | Return -> @@ -302,29 +300,30 @@ let rec check_instr (c : context) (e : instr) (s : infer_result_type) : op_type " but table has " ^ string_of_ref_type t); (ts1 @ [NumType I32Type]) --> ts2 + | ReturnCall x -> + let FuncType (ins, out) = func c x in + require (out = c.results) e.at "type mismatch in function result"; + ins -->... [] + + | ReturnCallIndirect (x, y) -> + let TableType (lim, t) = table c x in + let FuncType (ins, out) = type_ c y in + require (out = c.results) e.at "type mismatch in function result"; + (ins @ [NumType I32Type]) -->... [] + | Throw x -> let TagType y = tag c x in let FuncType (ts1, _) = type_ c (y @@ e.at) in ts1 -->... [] - | Rethrow x -> - let (kind, _) = label c x in - require (kind = CatchLabel) e.at "invalid rethrow label"; - [] -->... [] - - | TryCatch (bt, es, cts, ca) -> - let FuncType (ts1, ts2) as ft = check_block_type c bt in - let c_try = {c with labels = (BlockLabel, ts2) :: c.labels} in - let c_catch = {c with labels = (CatchLabel, ts2) :: c.labels} in - check_block c_try es ft e.at; - List.iter (fun ct -> check_catch ct c_catch ft e.at) cts; - Lib.Option.app (fun es -> check_block c_catch es ft e.at) ca; - ts1 --> ts2 + | ThrowRef -> + [RefType ExnRefType] -->... [] - | TryDelegate (bt, es, x) -> + | TryTable (bt, cs, es) -> let FuncType (ts1, ts2) as ft = check_block_type c bt in - ignore (label c x); - check_block {c with labels = (BlockLabel, ts2) :: c.labels} es ft e.at; + let c' = {c with labels = ts2 :: c.labels} in + List.iter (fun ct -> check_catch c ct ts2 e.at) cs; + check_block c' es ft e.at; ts1 --> ts2 | LocalGet x -> @@ -566,12 +565,30 @@ and check_block (c : context) (es : instr list) (ft : func_type) at = ("type mismatch: block requires " ^ string_of_result_type ts2 ^ " but stack has " ^ string_of_infer_types (snd s)) -and check_catch (ct : var * instr list) (c : context) (ft : func_type) at = - let (x, es) = ct in - let TagType y = tag c x in - let FuncType (ts1, _) = type_ c (y @@ at) in - let FuncType (_, ts2) = ft in - check_block c es (FuncType (ts1, ts2)) at +and check_catch (c : context) (cc : catch) (ts : value_type list) at = + match cc.it with + | Catch (x1, x2) -> + let TagType y = tag c x1 in + let FuncType (ts1, _) = type_ c (y @@ at) in + require (label c x2 = ts1) at + ("type mismatch: catch handler requires " ^ string_of_result_type ts1 ^ + " but label has " ^ string_of_result_type (label c x2)) + | CatchRef (x1, x2) -> + let TagType y = tag c x1 in + let FuncType (ts1, _) = type_ c (y @@ at) in + require (label c x2 = ts1 @ [RefType ExnRefType]) at + ("type mismatch: catch handler requires " ^ + string_of_result_type (ts1 @ [RefType ExnRefType]) ^ + " but label has " ^ string_of_result_type (label c x2)) + | CatchAll x -> + require (label c x = []) at + ("type mismatch: catch handler requires " ^ string_of_result_type [] ^ + " but label has " ^ string_of_result_type (label c x)) + | CatchAllRef x -> + require (label c x = [RefType ExnRefType]) at + ("type mismatch: catch handler requires " ^ + string_of_result_type [RefType ExnRefType] ^ + " but label has " ^ string_of_result_type (label c x)) (* Types *) @@ -641,7 +658,7 @@ let check_type (t : type_) = let check_func (c : context) (f : func) = let {ftype; locals; body} = f.it in let FuncType (ts1, ts2) = type_ c ftype in - let c' = {c with locals = ts1 @ locals; results = ts2; labels = [(BlockLabel, ts2)]} in + let c' = {c with locals = ts1 @ locals; results = ts2; labels = [ts2]} in check_block c' body (FuncType ([], ts2)) f.at let check_tag (c : context) (t : tag) = diff --git a/proposals/exception-handling/Exceptions.md b/proposals/exception-handling/Exceptions.md index a8f2f11df..47d8ae554 100644 --- a/proposals/exception-handling/Exceptions.md +++ b/proposals/exception-handling/Exceptions.md @@ -1,8 +1,12 @@ # Exception handling This explainer reflects the up-to-date version of the exception handling -proposal agreed on [the CG meeting on -09-15-2020](https://github.com/WebAssembly/meetings/blob/master/main/2020/CG-09-15.md). +proposal agreed on [Oct 2023 CG +meeting](https://github.com/WebAssembly/meetings/blob/main/main/2023/CG-10.md#exception-handling-vote-on-proposal-to-re-introduce-exnref). +See the [legacy +proposal](https://github.com/WebAssembly/exception-handling/blob/main/proposals/exception-handling/legacy/Exceptions.md) +for the previous version of the proposal that is still supported in several +browsers. --- @@ -36,8 +40,8 @@ succeeding instructions to process the data. A WebAssembly exception is created when you throw it with the `throw` instruction. Thrown exceptions are handled as follows: -1. They can be caught by one of `catch`/`catch_all` blocks in an enclosing try - block of a function body. +1. They can be caught by one of the *catch clauses* in an enclosing try block of + a function body. 1. Throws not caught within a function body continue up the call stack, popping call frames, until an enclosing try block is found. @@ -86,63 +90,53 @@ Exception tag indices are used by: 1. The `throw` instruction which creates a WebAssembly exception with the corresponding exception tag, and then throws it. -2. The `catch` clause uses the tag to identify if the thrown exception is one it - can catch. If true it pushes the corresponding argument values of the - exception onto the stack. +2. Catch clauses use a tag to identify the thrown exception it can catch. If it + matches, it pushes the corresponding argument values of the exception onto + the stack. -### Try-catch blocks +### Exception references + +When caught, an exception is reified into an _exception reference_, a value of +the new type `exnref`. Exception references can be used to rethrow the caught +exception. + +### Try blocks A _try block_ defines a list of instructions that may need to process exceptions and/or clean up state when an exception is thrown. Like other higher-level -constructs, a try block begins with a `try` instruction, and ends with an `end` -instruction. That is, a try-catch block is sequence of instructions having the +constructs, a try block begins with a `try_table` instruction, and ends with an +`end` instruction. That is, a try block is sequence of instructions having the following form: ``` -try blocktype - instruction* -catch i - instruction* -catch j - instruction* -... -catch_all +try_table blocktype catch* instruction* end ``` -A try-catch block contains zero or more `catch` blocks and zero or one -`catch_all` block. All `catch` blocks must precede the `catch_all` block, if -any. The `catch`/`catch_all` instructions (within the try construct) are called -the _catching_ instructions. There may not be any `catch` or `catch_all` blocks -after a `try`, in which case the `try` block does not catch any exceptions. - -The _body_ of the try block is the list of instructions before the first -catching instruction. The _body_ of each catch block is the sequence of -instructions following the corresponding catching instruction before the next -catching instruction (or the `end` instruction if it is the last catching -block). - -The `catch` instruction has an exception tag associated with it. The tag -identifies what exceptions it can catch. That is, any exception created with the -corresponding exception tag. Catch blocks that begin with a `catch` instruction -are considered _tagged_ catch blocks. - -The last catching instruction of a try-catch block can be the `catch_all` -instruction. If it begins with the `catch_all` instruction, it defines the -_default_ catch block. The default catch block has no tag index, and is used to -catch all exceptions not caught by any of the tagged catch blocks. The term -'catch block' refers to both `catch` and `catch_all` blocks. - -When the program runs `br` within `catch` or `catch_all` blocks, the rest of -the catching blocks will not run and the program control will branch to the -destination, as in normal blocks. +A try block contains zero or more _catch clauses_. If there are no catch +clauses, then the try block does not catch any exceptions. + +The _body_ of the try block is the list of instructions after the last catch +clause, if any. + +Each `catch` clause can be in one of 4 forms: +``` +catch tag label +catch_ref tag label +catch_all label +catch_all_ref label +``` +All forms have a label which is branched to when an exception is caught (see +below). The former two forms have an exception tag associated with it that +identifies what exceptions it will catch. The latter two forms catch any +exception, so that they can be used to define a _default_ handler. Try blocks, like control-flow blocks, have a _block type_. The block type of a try block defines the values yielded by evaluating the try block when either no -exception is thrown, or the exception is successfully caught by the catch block. -Because `try` and `end` instructions define a control-flow block, they can be -targets for branches (`br` and `br_if`) as well. +exception is thrown, or the exception is successfully caught by the catch +clause. Because `try_table` defines a control-flow block, it can be targets for +branches (`br` and `br_if`) as well. ### Throwing an exception @@ -168,246 +162,42 @@ an an enclosing try block, or the call stack is flushed. If the call stack is flushed, the embedder defines how to handle uncaught exceptions. Otherwise, the found enclosing try block is the catching try block. -A throw inside the body of a catch block is never caught by the corresponding -try block of the catch block, since instructions in the body of the catch block -are not in the body of the try block. - Once a catching try block is found for the thrown exception, the operand stack is popped back to the size the operand stack had when the try block was entered after possible block parameters were popped. -Then in case of a try-catch block, tagged catch blocks are tried in the order -they appear in the catching try block, until one matches. If a matched tagged -catch block is found, control is transferred to the body of the catch block, and -the arguments of the exception are pushed back onto the stack. +Then catch clauses are tried in the order they appear in the catching try block, +until one matches. If a matching catch clause is found, control is transferred +to the label of that catch clause. In case of `catch` or `catch_ref`, the +arguments of the exception are pushed back onto the stack. For `catch_ref` and +`catch_all_ref`, an exception reference is then pushed to the stack, which +represents the caught exception. -Otherwise, control is transferred to the body of the `catch_all` block, if any. -However, unlike tagged catch blocks, the constructor arguments are not copied -back onto the operand stack. +If no catch clauses were matched, the exception is implicitly rethrown. -If no tagged catch blocks were matched, and the catching try block doesn't have -a `catch_all` block, the exception is rethrown. - -If control is transferred to the body of a catch block, and the last instruction -in the body is executed, control then exits the try block. - -If the selected catch block does not throw an exception, it must yield the -value(s) specified by the type annotation on the corresponding catching try -block. - -Note that a caught exception can be rethrown using the `rethrow` instruction. +Note that a caught exception can be rethrown explicitly using the `exnref` and +the `throw_ref` instruction. ### Rethrowing an exception -The `rethrow` instruction can only appear in the body of a catch/catch_all -block. It always re-throws the exception caught by an enclosing catch block. - -Associated with the `rethrow` instruction is a _label_. The label is used to -disambiguate which exception is to be rethrown, when inside nested catch blocks. -The label is the relative block depth to the corresponding try block for which -the catching block appears. - -For example consider the following: - -``` -try $l1 - ... -catch ;; $l1 - ... - block - ... - try $l2 - ... - catch ;; $l2 - ... - try $l3 - ... - catch ;; $l3 - ... - rethrow N ;; (or label) - end - end - end - ... -end -``` - -In this example, `N` is used to disambiguate which caught exception is being -rethrown. It could rethrow any of the three caught expceptions. Hence, `rethrow -0` corresponds to the exception caught by `catch 3`, `rethrow 1` corresponds to -the exception caught by `catch 2`, and `rethrow 3` corresponds to the exception -caught by `catch 1`. In wat format, the argument for the `rethrow` instructions -can also be written as a label, like branches. So `rethrow 0` in the example -above can also be written as `rethrow $l3`. - -Note that `rethrow 2` is not allowed because it does not refer to a `try` label -from within its catch block. Rather, it references a `block` instruction, so it -will result in a validation failure. - -Note that the example below is a validation failure: -``` -try $l1 - try $l2 - rethrow $l2 ;; (= rethrow 0) - catch - end -catch -end -``` -The `rethrow` here references `try $l2`, but the `rethrow` is not within its -`catch` block. - -### Try-delegate blocks - -Try blocks can also be used with the `delegate` instruction. A try-delegate -block contains a `delegate` instruction with the following form: - -``` -try blocktype - instruction* -delegate label -``` - -The `delegate` clause does not have an associated body, so try-delegate blocks -don't have an `end` instruction at the end. The `delegate` instruction takes a -try label and delegates exception handling to a `catch`/`catch_all`/`delegate` -specified by the `try` label. For example, consider this code: - -``` -try $l0 - try - call $foo - delegate $l0 ;; (= delegate 0) -catch - ... -catch_all - ... -end -``` - -If `call $foo` throws, searching for a catching block first finds `delegate`, -and because it delegates exception handling to catching instructions associated -with `$l1`, it will be next checked by the outer `catch` and then `catch_all` -instructions. - -`delegate` can also target `catch`-less `try`s or non-`try` block constructs -like `block`s or `loop`s, in which case the delegated exception is assumed to -propagate to the outer scope and will be caught by the next matching -try-catches, or rethrown to the caller if there is no outer try block. In the -examples, catches are annotated with `($label_name)` to clarify which `try` it -belongs to for clarification; it is not the official syntax. -``` -try $l0 - block $l1 - try - call $foo - delegate $l1 ;; delegates to 'catch ($l0)' - end -catch ($l0) -end -``` - -Like branches, `delegate` can only target outer blocks, and effectively -rethrows the exception in that block. Consequently, delegating to a specific -`catch` or `catch_all` handler requires targeting the respective label from -within the associated `try` block. Delegating to a label from within a `catch` -block does delegate the exception to the next enclosing handler -- analogous to -performing a `throw` within a `catch` block, that handler is no longer active -at that point. Here is another example: - -``` -try $l0 - try $l1 - catch ($l1) - try - call $foo - delegate $l1 ;; delegates to 'catch ($l0)' - catch_all - ... - end -catch ($l0) -``` - -Here the `delegate` is targeting `catch ($l1)`, which exists before the -`delegate`. So in case an exception occurs, it propagates out and ends up -targetting `catch ($l0)`, if the catch has a matching tag. If not, it will -propagate further out. Even if the `catch_all` is below the `delegate`, -`delegate` targets catches of a `try` as a whole and does not target an -individual `catch`/`catch_all`, so it doesn't apply. - -If `delegate` targets the implicit function body block, then in effect it -delegates the exception to the caller of the current function. For example: -``` -(func $test - try - try - call $foo - delegate 1 ;; delegates to the caller - catch - ... - catch_all - ... - end -) -``` -In case `foo` throws, `delegate 1` here delegates the exception handling to the -caller, i.e., the exception escapes the current function. If the immediate is -greater than or equal to the number of block nesting including the implicit -function-level block, it is a validation failure. In this example, any number -equal to or greater than 2 is not allowed. - -The below is an example that includes all the cases explained. The numbers -within `()` after `delegate`s are the label operands in immediate values. -``` -(func $test - try $lA - block $lB - try $lC - try - delegate $lC (0) ;; delegates to 'catch ($lC)' - try - delegate $lB (1) ;; $lB is a block, so delegates to 'catch ($lA)' - try - delegate $lA (2) ;; delegates to 'catch ($lA)' - try - delegate 3 ;; propagates to the caller - try - delegate 4 ;; validation failure - catch ($lC) - try - delegate $lC (0) ;; 'catch ($lC)' is above this instruction, - ;; so delegates to 'catch ($lA)' - try - delegate $lB (1) ;; $lB is a block, so delegates to 'catch ($lA)' - try - delegate $lA (2) ;; delegates to 'catch ($lA)' - try - delegate 3 ;; propagates to the caller - try - delegate 4 ;; validation failure - end ;; try $lC - end ;; block $lB - catch ($lA) - end ;; try $lA -) -``` +The `throw_ref` takes an operand of type `exnref` and re-throws the +corresponding caught exception. If the operand is null, a trap occurs. ### JS API #### Traps -The `catch`/`catch_all` instruction catches exceptions generated by the `throw` -instruction, but does not catch traps. The rationale for this is that in general -traps are not locally recoverable and are not needed to be handled in local -scopes like try-catch. +Catch clauses handle exceptions generated by the `throw` instruction, but do not +catch traps. The rationale for this is that in general traps are not locally +recoverable and are not needed to be handled in local scopes like try blocks. -The `catch` instruction catches foreign exceptions generated from calls to +The `try_table` instruction catches foreign exceptions generated from calls to function imports as well, including JavaScript exceptions, with a few exceptions: 1. In order to be consistent before and after a trap reaches a JavaScript frame, - the `catch` instruction does not catch exceptions generated from traps. -1. The `catch` instruction does not catch JavaScript exceptions generated from - stack overflow and out of memory. + the `try_table` instruction does not catch exceptions generated from traps. +1. The `try_table` instruction does not catch JavaScript exceptions generated + from stack overflow and out of memory. Filtering these exceptions should be based on a predicate that is not observable by JavaScript. Traps currently generate instances of @@ -449,22 +239,22 @@ check ensures that without access to a WebAssembly module's exported exception tag, the associated data fields cannot be read. The `Exception` constructor can take an optional `ExceptionOptions` argument, -which can optionally contain `traceStack` entry. When `traceStack` is -`true`, JavaScript VMs are permitted to attach a stack trace string to -`Exception.stack` field, as in JavaScript's `Error` class. `traceStack` -serves as a request to the WebAssembly engine to attach a stack trace; it -is not necessary to honour if `true`, but `trace` may not be populated if -`traceStack` is `false`. While `Exception` is not a subclass of JavaScript's -`Error` and it can be used to represent normal control flow constructs, -`traceStack` field can be set when we use it to represent errors. The -format of stack trace strings conform to the [WebAssembly stack trace +which can optionally contain `traceStack` entry. When `traceStack` is `true`, +JavaScript VMs are permitted to attach a stack trace string to `Exception.stack` +field, as in JavaScript's `Error` class. `traceStack` serves as a request to the +WebAssembly engine to attach a stack trace; it is not necessary to honour if +`true`, but `trace` may not be populated if `traceStack` is `false`. While +`Exception` is not a subclass of JavaScript's `Error` and it can be used to +represent normal control flow constructs, `traceStack` field can be set when we +use it to represent errors. The format of stack trace strings conform to the +[WebAssembly stack trace conventions](https://webassembly.github.io/spec/web-api/index.html#conventions). When `ExceptionOption` is not provided or it does not contain `traceStack` entry, `traceStack` is considered `false` by default. To preserve stack trace info when crossing the JS to Wasm boundary, exceptions -can internally contain a stack trace, which is propagated when caught by `catch` -and rethrown by `rethrow`. +can internally contain a stack trace, which is propagated when caught by a +`catch[_all]_ref` clause and rethrown by `throw_ref`. More formally, the added interfaces look like the following: @@ -507,17 +297,16 @@ document](https://github.com/WebAssembly/spec/blob/master/document/core/text/ins The following rules are added to *instructions*: ``` - try blocktype instruction* (catch tag_index instruction*)* (catch_all instruction*)? end | - try blocktype instruction* delegate label | - throw tag_index argument* | - rethrow label | + try_table blocktype catch* instruction* end | + throw tag_index | + throw_ref | ``` -Like the `block`, `loop`, and `if` instructions, the `try` instruction is +Like the `block`, `loop`, and `if` instructions, the `try_table` instruction is *structured* control flow instruction, and can be labeled. This allows branch instructions to exit try blocks. -The `tag_index` of the `throw` and `catch` instructions denotes the exception +The `tag_index` of the `throw` and `catch[_ref]` clauses denotes the exception tag to use when creating/extract from an exception. See [tag index space](#tag-index-space) for further clarification of exception tags. @@ -545,6 +334,23 @@ document](https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md). #### Other Types +##### exnref + +The type `exnref` is represented by the type opcode `-0x17`. + +When combined with the [GC +proposal](https://github.com/WebAssembly/gc/blob/main/proposals/gc/MVP.md), +there also is a value type `nullexnref` with opcode `-0x0c`. Furthermore, these +opcodes also function as heap type, i.e., `exn` is a new heap type with opcode +`-0x17`, and `noexn` is a new heap type with opcode `-0x0c`; `exnref` and +`nullexnref` are shorthands for `(ref null exn)` and `(ref null noexn)`, +respectively. + +The heap type `noexn` is a subtype of `exn`. They are not in a subtype relation +with any other type (except bottom), such that they form a new disjoint +hierarchy of heap types. + + ##### tag_type We reserve a bit to denote the exception attribute: @@ -641,22 +447,28 @@ follows: ###### Tag names -The tag names subsection is a `name_map` which assigns names to a subset of -the tag indices (Used for both imports and module-defined). +The tag names subsection is a `name_map` which assigns names to a subset of the +tag indices (Used for both imports and module-defined). -### Control flow operators +### Control flow instructions -The control flow operators are extended to define try blocks, catch blocks, -throws, and rethrows as follows: +The control flow instructions are extended to define try blocks and throws as +follows: | Name | Opcode | Immediates | Description | | ---- | ---- | ---- | ---- | -| `try` | `0x06` | sig : `blocktype` | begins a block which can handle thrown exceptions | -| `catch` | `0x07` | index : `varint32` | begins the catch block of the try block | -| `catch_all` | `0x19` | | begins the catch_all block of the try block | -| `delegate` | `0x18` | relative_depth : `varuint32` | begins the delegate block of the try block | -| `throw` | `0x08` | index : `varint32` | Creates an exception defined by the tag and then throws it | -| `rethrow` | `0x09` | relative_depth : `varuint32` | Pops the `exnref` on top of the stack and throws it | - -The *sig* fields of `block`, `if`, and `try` operators are block signatures +| `try_table` | `0x1f` | sig : `blocktype`, n : `varuint32`, catch : `catch^n` | begins a block which can handle thrown exceptions | +| `throw` | `0x08` | index : `varuint32` | Creates an exception defined by the tag and then throws it | +| `throw_ref` | `0x0a` | | Pops an `exnref` from the stack and throws it | + +The *sig* fields of `block`, `if`, and `try_table` instructions are block types which describe their use of the operand stack. + +A `catch` handler is a pair of tag and label index: + +| Name | Opcode | Immediates | +| ------- | ------ | ----------- | +| `catch` | `0x00` | tag : `varuint32`, label : `varuint32` | +| `catch_ref` | `0x01` | tag : `varuint32`, label : `varuint32` | +| `catch_all` | `0x02` | label : `varuint32` | +| `catch_all_ref` | `0x03` | label : `varuint32` | diff --git a/proposals/exception-handling/Exceptions-formal-examples.md b/proposals/exception-handling/legacy/Exceptions-formal-examples.md similarity index 77% rename from proposals/exception-handling/Exceptions-formal-examples.md rename to proposals/exception-handling/legacy/Exceptions-formal-examples.md index 10571d855..5beb6d9aa 100644 --- a/proposals/exception-handling/Exceptions-formal-examples.md +++ b/proposals/exception-handling/legacy/Exceptions-formal-examples.md @@ -63,11 +63,11 @@ Take the frame `F = (locals i32.const 0, module m)`. We have: ``` ↪ ↪ ↪ ↪ F; (label_1{} - (catch{ a_x (local.get 0) } + (handler_1{ (a_x (local.get 0)) } (label_0{} - (delegate{ 0 } + (handler_0{ 0 } (label_0{} - (catch{ ε (local.set 0 (i32.const 27)) (rethrow 0) } + (handler_0{ (ε (local.set 0 (i32.const 27)) (rethrow 0)) } (throw a_x) end) end) end) end) end) end) ``` @@ -75,19 +75,19 @@ For the trivial throw context `T = [_]` the above is the same as ``` ↪ F; (label_1{} - (catch{ a_x (local.get 0) } + (handler_1{ (a_x (local.get 0)) } (label_0{} - (delegate{ 0 } + (handler_0{ 0 } (label_0{} - (catch{ ε (local.set 0 (i32.const 27)) (rethrow 0) } + (handler_0{ (ε (local.set 0 (i32.const 27)) (rethrow 0)) } T[(throw a_x)]) end) end) end) end) end) ↪ F; (label_1{} - (catch{ a_x (local.get 0) } + (handler_1{ (a_x (local.get 0)) } (label_0{} - (delegate{ 0 } + (handler_0{ 0 } (label_0{} - (caught{ a_x ε } + (caught_0{ a_x ε } (local.set 0 (i32.const 27)) (rethrow 0) end) end) end) end) end) end) ``` @@ -96,48 +96,48 @@ Let `F'` be the frame `{locals i32.const 27, module m}`, and let `B^0 = [_]` to ``` ↪ F'; (label_1{} - (catch{ a_x (local.get 0) } + (handler_1{ (a_x (local.get 0)) } (label_0{} - (delegate{ 0 } + (handler_0{ 0 } (label_0{} - (caught{ a_x ε } + (caught_0{ a_x ε } B^0[ (rethrow 0) ] end) end) end) end) end) end) ↪ F'; (label_1{} - (catch{ a_x (local.get 0) } + (handler_1{ (a_x (local.get 0)) } (label_0{} - (delegate{ 0 } + (handler_0{ 0 } (label_0{} - (caught{ a_x ε } + (caught_0{ a_x ε } (throw a_x) end) end) end) end) end) end) ``` -Let `T' = (label_0{} (caught{ a_x ε } [_] end) end)` and use the same `B^0` as above to reduce the throw with the delegate. +Let `T' = (label_0{} (caught_0{ a_x ε } [_] end) end)` and use the same `B^0` as above to reduce the throw with the delegate. ``` ↪ F'; (label_1{} - (catch{ a_x (local.get 0) } + (handler_1{ (a_x (local.get 0)) } (label_0{} - B^0[ (delegate{ 0 } T'[ (throw a_x) ] end) ] end) end) end) + B^0[ (handler_0{ 0 } T'[ (throw a_x) ] end) ] end) end) end) ↪ F'; (label_1{} - (catch{ a_x (local.get 0) } + (handler_1{ (a_x (local.get 0)) } (throw a_x) end) end) ``` -Use the trivial throw context `T` again, this time to match the throw to the `catch`. +Use the trivial throw context `T` again, this time to match the throw to the `handler_1{(...)}`. ``` ↪ F'; (label_1{} - (catch{ a_x (local.get 0) } + (handler_1{ (a_x (local.get 0)) } T[ (throw a_x) ] end) end) ↪ F'; (label_1{} - (caught{ a_x ε } + (caught_0{ a_x ε } (local.get 0) end) end) ↪ F'; (label_1{} - (caught{ a_x ε } + (caught_0{ a_x ε } (i32.const 27) end) end) ↪ F'; (label_1{} @@ -196,13 +196,13 @@ In the above example, all thrown exceptions get caught and the first one gets re ``` (label_0{} - (caught{ a_x val_x } ;; <---- The exception rethrown by `rethrow 2` below. + (caught_0{ a_x val_x } ;; <---- The exception rethrown by `rethrow 2` below. val_x (label_0{} - (caught{ a_y val_y } + (caught_0{ a_y val_y } ;; The catch_all does not leave val_y here. (label_0{} - (caught{ a_z val_z } + (caught_0{ a_z val_z } val_z ;; (rethrow 2) puts val_x and the throw below. val_x @@ -266,40 +266,40 @@ In folded form and reduced to the point `throw $x` is called, this is: ``` (label_0{} - (catch{ a_x instr* } + (handler_0{ (a_x instr*) } (label_0{} - (catch{ ε ε } + (handler_0{ (ε ε) } (label_0{} - (delegate{ 1 } + (handler_0{ 1 } (label_0{} - (delegate{ 0 } + (handler_0{ 0 } (throw a_x) end) end) end) end) end) end) end) end) ``` -The `delegate{ 0 }` reduces using the trivial throw and block contexts to: +The `handler_0{ 0 }` reduces using the trivial throw and block contexts to: ``` (label_0{} - (catch{ a_x instr* } + (handler_0{ (a_x instr*) } (label_0{} - (catch{ ε ε } + (handler_0{ (ε ε) } (label_0{} - (delegate{ 1 } + (handler_0{ 1 } (throw a_x) end) end) end) end) end) end) ``` -The `delegate{ 1 }` reduces using the trivial throw context and the block context `B^1 := (catch{ ε ε } (label_0{} [_] end) end)` to the following: +The `handler_0{ 1 }` reduces using the trivial throw context and the block context `B^1 := (handler_0{ (ε ε) } (label_0{} [_] end) end)` to the following: ``` (label_0{} - (catch{ a_x instr* } + (handler_0{ (a_x instr*) } (throw a_x) end) end) ``` The thrown exception is (eventually) caught by the outer try's `catch $x`, so the above reduces to the following. ``` (label_0 {} - (caught{a_x} + (caught_0{a_x} instr* end) end) ``` @@ -342,11 +342,11 @@ When it's time to reduce `(throw y)`, the reduction looks as follows. ``` (label_1{} - (catch{ ε (i32.const 4) } + (handler_1{ (ε (i32.const 4)) } (label_0{} - (caught{ a_x ε } + (caught_0{ a_x ε } (label_0{} - (delegate{ 0 } + (handler_0{ 0 } (throw a_y) end) end) end) end) end) end) ``` @@ -354,17 +354,17 @@ For `B^0 := [_] := T`, the above is the same as the following. ``` (label_1{} - (catch{ ε (i32.const 4) } + (handler_1{ (ε (i32.const 4)) } (label_0{} - (caught{ a_x ε } + (caught_0{ a_x ε } (label_0{} - B^0 [(delegate{ 0 } T[ (throw a_y) ] end)] end) end) end) end) end) + B^0 [(handler_0{ 0 } T[ (throw a_y) ] end)] end) end) end) end) end) ↪ (label_1{} - (catch{ ε (i32.const 4) } + (handler_1{ (ε (i32.const 4)) } (label_0{} - (caught{ a_x ε } + (caught_0{ a_x ε } (throw a_y) end) end) end) end) ``` -So `throw a_y` gets correctly caught by `catch{ ε (i32.const 4) }` and this example reduces to `(i32.const 4)`. +So `throw a_y` gets correctly caught by `handler_1{ (ε (i32.const 4)) }` and this example reduces to `(i32.const 4)`. diff --git a/proposals/exception-handling/Exceptions-formal-overview.md b/proposals/exception-handling/legacy/Exceptions-formal-overview.md similarity index 67% rename from proposals/exception-handling/Exceptions-formal-overview.md rename to proposals/exception-handling/legacy/Exceptions-formal-overview.md index c5d349cf5..d7e1ed518 100644 --- a/proposals/exception-handling/Exceptions-formal-overview.md +++ b/proposals/exception-handling/legacy/Exceptions-formal-overview.md @@ -110,12 +110,18 @@ taginst ::= {'type' tagtype} ``` m ::= {..., 'tags' tagaddr*} ``` +#### Stack + +``` +handler ::= (tagaddr? instr*)* | labelidx +exn ::= tagaddr val* +``` #### Administrative Instructions ``` -instr ::= ... | 'throw' tagaddr | 'catch'{ tagaddr? instr* }* instr* 'end' - | 'delegate'{ labelidx } instr* 'end' | 'caught'{ tagaddr val* } instr* 'end' +instr ::= ... | 'throw' tagaddr | 'handler'_n{handler} instr* 'end' + | 'handler'_n{ labelidx } instr* 'end' | 'caught'_n{exn} instr* 'end' ``` #### Block Contexts and Label Kinds @@ -125,73 +131,72 @@ So far block contexts are only used in the reduction of `br l` and `return`, and ``` B^0 ::= val* '[_]' instr* | val* C^0 instr* B^{k+1} ::= val* ('label'_n{instr*} B^k 'end') instr* | val* C^{k+1} instr* -C^k ::= 'catch'{ tagaddr? instr* }* B^k 'end' - | 'caught'{ tagaddr val* } B^k 'end' - | 'delegate'{ labelidx } B^k 'end' +C^k ::= 'handler'_n{ handler } B^k 'end' + | 'caught'_n{ exn } B^k 'end' ``` Note the `C` in `C^k` above stands for `control`, because the related administrative instructions are in some ways modeling [control frame opcodes](https://webassembly.github.io/spec/core/appendix/algorithm.html?highlight=control#data-structures) "on the stack". #### Throw Contexts -Throw contexts don't skip over handlers (administrative `catch` or `delegate` instructions). +Throw contexts don't skip over handlers. Throw contexts are used to match a thrown exception with the innermost handler. ``` T ::= '[_]' | val* T instr* | 'label'_n{instr*} T 'end' - | 'caught'{ tagaddr val* } T 'end' + | 'caught'_n{exn} T 'end' | 'frame'_n{F} T 'end' ``` -Note that because `catch` and `delegate` instructions are not included above, there is always a unique maximal throw context to match the reduction rules. Note that this basically means that `caught{..} instr* end` is not a potential catching block for exceptions thrown by `instr*`. The instruction sequence `instr*` is inside a `catch` or `catch_all` block. +Note that because handlers are not included above, popping the throw context stops when the innermost handler is found, if any. Note that this also means that `caught_n{exn} instr* end` is not a potential catching block for exceptions thrown by `instr*`. The instruction sequence `instr*` is inside a `catch` or `catch_all` block. ### Reduction of Instructions Reduction steps for the new instructions or administrative instructions. -An absent tag address in a `catch` administrative instruction (i.e., `a? = ε`) represents a `catch_all`. +An absent tag address in a handler (i.e., `a? = ε`) represents a `catch_all`. ``` F; throw x ↪ F; throw a (if F.module.tagaddrs[x]=a) -caught{a val*} B^l[rethrow l] end - ↪ caught{a val*} B^l[val* (throw a)] end +caught_n{a val*} B^l[rethrow l] end + ↪ caught_n{a val*} B^l[val* (throw a)] end -caught{a val0*} val* end ↪ val* +caught_n{a val0*} val^n end ↪ val^n F; val^n (try bt instr1* (catch x instr2*)* (catch_all instr3*)? end) - ↪ F; label_m{} (catch{a instr2*}*{ε instr3*}? val^n instr1* end) end + ↪ F; label_m{} (handler_m{(a instr2*)*(ε instr3*)?} val^n instr1* end) end (if expand_F(bt) = [t1^n]→[t2^m] ∧ (F.module.tagaddrs[x]=a)*) -catch{a? instr*}* val* end ↪ val* +handler_m{(a? instr*)*} val^m end ↪ val^m -S; F; catch{a1? instr1*}{a0? instr0*}* T[val^n (throw a)] end - ↪ S; F; caught{a val^n} (val^n)? instr1* end +S; F; handler_m{(a1? instr1*)(a0? instr0*)*} T[val^n (throw a)] end + ↪ S; F; caught_m{a val^n} (val^n)? instr1* end (if (a1? = ε ∨ a1? = a) ∧ S.tags(a).type = [t^n]→[]) -catch{a1? instr*}{a0? instr0*}* T[val^n (throw a)] end - ↪ catch{a0? instr0*}* T[val^n (throw a)] end +handler_m{(a1? instr*)(a0? instr0*)*} T[(throw a)] end + ↪ handler_m{(a0? instr0*)*} T[(throw a)] end (if a1? ≠ ε ∧ a1? ≠ a) -catch T[val^n (throw a)] end ↪ val^n (throw a) +handler_m{} T[(throw a)] end ↪ T[(throw a)] (if S.tags(a).type = [t^n]→[]) F; val^n (try bt instr* delegate l) - ↪ F; label_m{} (delegate{l} val^n instr* end) end + ↪ F; label_m{} (handler_m{l} val^n instr* end) end (if expand_F(bt) = [t1^n]→[t2^m]) -delegate{l} val* end ↪ val* +handler_m{l} val^m end ↪ val^m -label_m{} B^l[ delegate{l} T[val^n (throw a)] end ] end - ↪ val^n (throw a) +label_m{} B^l[ handler_m{l} T[(throw a)] end ] end + ↪ T[(throw a)] ``` -Note that the last reduction step above is similar to the reduction of `br l` [1], the entire `delegate{l}...end` is seen as a `br l` immediately followed by a throw. +Note that the last reduction step above is similar to the reduction of `br l` [1], the entire `handler_m{l}...end` is seen as a `br l` immediately followed by a throw. -There is a subtle difference though. The instruction `br l` searches for the `l+1`th surrounding block and breaks out after that block. Because `delegate{l}` is always wrapped in its own `label_n{} ... end` [2], with the same lookup as for `br l` the instruction ends up breaking inside the `l+1`th surrounding block, and throwing there. So if that `l+1`th surrounding block is a try, the exception is thrown in the "try code", and thus correctly getting delegated to that try's catches. +There is a subtle difference though. The instruction `br l` searches for the `l+1`th surrounding block and breaks out after that block. Because `handler_m{l}` is always wrapped in its own `label_m{} ... end` [2], with the same lookup as for `br l` the instruction ends up breaking inside the `l+1`th surrounding block, and throwing there. So if that `l+1`th surrounding block is a try, the exception is thrown in the "try code", and thus correctly getting delegated to that try's catches. - [1] [The execution step for `br l`](https://webassembly.github.io/spec/core/exec/instructions.html#xref-syntax-instructions-syntax-instr-control-mathsf-br-l) - [2] The label that always wraps `delegate{l}...end` can be thought of as "level -1" and cannot be referred to by the delegate's label index `l`. @@ -205,21 +210,21 @@ S ⊢ tag a : tag [t*]→[] S;C ⊢ throw a : [t1* t*]→[t2*] ((S ⊢ tag a : tag [t1*]→[])? - S;C, labels (catch [t2*]) ⊢ instr2* : [t1*?]→[t2*])* -S;C, labels [t2*] ⊢ instr1* : []→[t2*] + S;C, labels (catch [t2^m]) ⊢ instr2* : [t1*?]→[t2^m])* +S;C, labels [t2^m] ⊢ instr1* : []→[t2^m] ----------------------------------------------------------- -S;C, labels [t2*] ⊢ catch{a? instr2*}* instr1* end : []→[t2*] +S;C, labels [t2^m] ⊢ handler_m{(a? instr2*)*} instr1* end : []→[t2^m] -S;C ⊢ instr* : []→[t*] +S;C ⊢ instr* : []→[t^m] C.labels[l+1] = [t0*] ------------------------------------------------------ -S;C ⊢ delegate{l} instr* end : []→[t*] +S;C ⊢ handler_m{l} instr* end : []→[t^m] S ⊢ tag a : tag [t0*]→[] (val:t0)* -S;C, labels (catch [t*]) ⊢ instr* : []→[t*] ----------------------------------------------------------- -S;C, labels [t*] ⊢ caught{a val^*} instr* end : []→[t*] +S;C, labels (catch [t^n]) ⊢ instr* : []→[t^n] +------------------------------------------------------------ +S;C, labels [t^n] ⊢ caught_n{a val^*} instr* end : []→[t^n] ``` ## Uncaught Exceptions @@ -228,6 +233,6 @@ A new [result](https://webassembly.github.io/spec/core/exec/runtime.html#syntax- ``` result ::= val* | trap - | T[val* (throw tagaddr)] + | val* (throw tagaddr) ``` diff --git a/proposals/exception-handling/legacy/Exceptions.md b/proposals/exception-handling/legacy/Exceptions.md new file mode 100644 index 000000000..a214ee21f --- /dev/null +++ b/proposals/exception-handling/legacy/Exceptions.md @@ -0,0 +1,711 @@ +# Exception handling + +This explainer reflects the third version of the proposal adopted in the [CG +meeting on +09-15-2020](https://github.com/WebAssembly/meetings/blob/main/main/2020/CG-09-15.md#proposal-for-changes-in-eh-proposal-for-two-phase-unwinding-support-part-2--discussions-heejin-ahn-30-min), +which removed `exnref`. The rational then was the old proposal having a +first-class exception reference type was not easily extensible to a future +proposal that supports two-phase unwinding. + +This proposal was superseded by the [current +proposal](https://github.com/WebAssembly/exception-handling/blob/main/proposals/exception-handling/Exceptions.md) +in [Oct 2023 CG +meeting](https://github.com/WebAssembly/meetings/blob/main/main/2023/CG-10.md#exception-handling-vote-on-proposal-to-re-introduce-exnref), +recognizing that after all `exnref` provided important functionalities for the +spec and engine/toolchain implementations. + +This proposal is currently also known as the "legacy proposal" and still +supported in the web, but can be deprecated in future and the use of this +proposal is discouraged. + +--- + +## Overview + +Exception handling allows code to break control flow when an exception is +thrown. The exception can be any exception known by the WebAssembly module, or +it may an unknown exception that was thrown by a called imported function. + +One of the problems with exception handling is that both WebAssembly and an +embedder have different notions of what exceptions are, but both must be aware +of the other. + +It is difficult to define exceptions in WebAssembly because (in general) it +doesn't have knowledge of any embedder. Further, adding such knowledge to +WebAssembly would limit the ability for other embedders to support WebAssembly +exceptions. + +One issue is that both sides need to know if an exception was thrown by the +other, because cleanup may need to be performed. + +Another problem is that WebAssembly doesn't have direct access to an embedder's +memory. As a result, WebAssembly defers the handling of exceptions to the host +VM. + +To access exceptions, WebAssembly provides instructions to check if the +exception is one that WebAssembly understands. If so, the data of the +WebAssembly exception is extracted and copied onto the stack, allowing +succeeding instructions to process the data. + +A WebAssembly exception is created when you throw it with the `throw` +instruction. Thrown exceptions are handled as follows: + +1. They can be caught by one of `catch`/`catch_all` blocks in an enclosing try + block of a function body. + +1. Throws not caught within a function body continue up the call stack, popping + call frames, until an enclosing try block is found. + +1. If the call stack is exhausted without any enclosing try blocks, the embedder + defines how to handle the uncaught exception. + +### Exception handling + +This proposal adds exception handling to WebAssembly. Part of this proposal is +to define a new section to declare exceptions. However, rather than limiting +this new section to just defining exceptions, it defines a more general format +`tag` that allows the declaration of other forms of typed tags in future. + +WebAssembly tags are defined in a new `tag` section of a WebAssembly module. The +tag section is a list of declared tags that are created fresh each time the +module is instantiated. + +Each tag has an `attribute` and a `type`. Currently, the attribute can only +specify that the tag is for an exception. In the future, additional attribute +values may be added when other kinds of tags are added to WebAssembly. + +To allow for such a future extension possibility, we reserve a byte in the +binary format of an exception definition, set to 0 to denote an exception +attribute. + +### Exceptions + +An `exception tag` is a value to distinguish different exceptions, while an +`exception tag index` is a numeric name to refer to an (imported or defined) +exception tag within a module (see [tag index space](#tag-index-space) for +details). Exception tags are declared in the tag and import sections of a +module. + +An `exception` is an internal construct in WebAssembly that represents a runtime +object that can be thrown. A WebAssembly exception consists of an exception tag +and its runtime arguments. + +The type of an exception tag is denoted by an index to a function signature +defined in the `type` section. The parameters of the function signature define +the list of argument values associated with the tag. The result type must be +empty. + +Exception tag indices are used by: + +1. The `throw` instruction which creates a WebAssembly exception with the + corresponding exception tag, and then throws it. + +2. The `catch` clause uses the tag to identify if the thrown exception is one it + can catch. If true it pushes the corresponding argument values of the + exception onto the stack. + +### Try-catch blocks + +A _try block_ defines a list of instructions that may need to process exceptions +and/or clean up state when an exception is thrown. Like other higher-level +constructs, a try block begins with a `try` instruction, and ends with an `end` +instruction. That is, a try-catch block is sequence of instructions having the +following form: + +``` +try blocktype + instruction* +catch i + instruction* +catch j + instruction* +... +catch_all + instruction* +end +``` + +A try-catch block contains zero or more `catch` blocks and zero or one +`catch_all` block. All `catch` blocks must precede the `catch_all` block, if +any. The `catch`/`catch_all` instructions (within the try construct) are called +the _catching_ instructions. There may not be any `catch` or `catch_all` blocks +after a `try`, in which case the `try` block does not catch any exceptions. + +The _body_ of the try block is the list of instructions before the first +catching instruction. The _body_ of each catch block is the sequence of +instructions following the corresponding catching instruction before the next +catching instruction (or the `end` instruction if it is the last catching +block). + +The `catch` instruction has an exception tag associated with it. The tag +identifies what exceptions it can catch. That is, any exception created with the +corresponding exception tag. Catch blocks that begin with a `catch` instruction +are considered _tagged_ catch blocks. + +The last catching instruction of a try-catch block can be the `catch_all` +instruction. If it begins with the `catch_all` instruction, it defines the +_default_ catch block. The default catch block has no tag index, and is used to +catch all exceptions not caught by any of the tagged catch blocks. The term +'catch block' refers to both `catch` and `catch_all` blocks. + +When the program runs `br` within `catch` or `catch_all` blocks, the rest of +the catching blocks will not run and the program control will branch to the +destination, as in normal blocks. + +Try blocks, like control-flow blocks, have a _block type_. The block type of a +try block defines the values yielded by evaluating the try block when either no +exception is thrown, or the exception is successfully caught by the catch block. +Because `try` and `end` instructions define a control-flow block, they can be +targets for branches (`br` and `br_if`) as well. + +### Throwing an exception + +The `throw` instruction takes an exception tag index as an immediate argument. +That index is used to identify the exception tag to use to create and throw the +corresponding exception. + +The values on top of the stack must correspond to the type associated with the +exception tag. These values are popped off the stack and are used (along with +the corresponding exception tag) to create the corresponding exception. That +exception is then thrown. + +When an exception is thrown, the embedder searches for the nearest enclosing try +block body that execution is in. That try block is called the _catching_ try +block. + +If the throw appears within the body of a try block, it is the catching try +block. + +If a throw occurs within a function body, and it doesn't appear inside the body +of a try block, the throw continues up the call stack until it is in the body of +an an enclosing try block, or the call stack is flushed. If the call stack is +flushed, the embedder defines how to handle uncaught exceptions. Otherwise, the +found enclosing try block is the catching try block. + +A throw inside the body of a catch block is never caught by the corresponding +try block of the catch block, since instructions in the body of the catch block +are not in the body of the try block. + +Once a catching try block is found for the thrown exception, the operand stack +is popped back to the size the operand stack had when the try block was entered +after possible block parameters were popped. + +Then in case of a try-catch block, tagged catch blocks are tried in the order +they appear in the catching try block, until one matches. If a matched tagged +catch block is found, control is transferred to the body of the catch block, and +the arguments of the exception are pushed back onto the stack. + +Otherwise, control is transferred to the body of the `catch_all` block, if any. +However, unlike tagged catch blocks, the constructor arguments are not copied +back onto the operand stack. + +If no tagged catch blocks were matched, and the catching try block doesn't have +a `catch_all` block, the exception is rethrown. + +If control is transferred to the body of a catch block, and the last instruction +in the body is executed, control then exits the try block. + +If the selected catch block does not throw an exception, it must yield the +value(s) specified by the type annotation on the corresponding catching try +block. + +Note that a caught exception can be rethrown using the `rethrow` instruction. + +### Rethrowing an exception + +The `rethrow` instruction can only appear in the body of a catch/catch_all +block. It always re-throws the exception caught by an enclosing catch block. + +Associated with the `rethrow` instruction is a _label_. The label is used to +disambiguate which exception is to be rethrown, when inside nested catch blocks. +The label is the relative block depth to the corresponding try block for which +the catching block appears. + +For example consider the following: + +``` +try $l1 + ... +catch ;; $l1 + ... + block + ... + try $l2 + ... + catch ;; $l2 + ... + try $l3 + ... + catch ;; $l3 + ... + rethrow N ;; (or label) + end + end + end + ... +end +``` + +In this example, `N` is used to disambiguate which caught exception is being +rethrown. It could rethrow any of the three caught expceptions. Hence, `rethrow +0` corresponds to the exception caught by `catch 3`, `rethrow 1` corresponds to +the exception caught by `catch 2`, and `rethrow 3` corresponds to the exception +caught by `catch 1`. In wat format, the argument for the `rethrow` instructions +can also be written as a label, like branches. So `rethrow 0` in the example +above can also be written as `rethrow $l3`. + +Note that `rethrow 2` is not allowed because it does not refer to a `try` label +from within its catch block. Rather, it references a `block` instruction, so it +will result in a validation failure. + +Note that the example below is a validation failure: +``` +try $l1 + try $l2 + rethrow $l2 ;; (= rethrow 0) + catch + end +catch +end +``` +The `rethrow` here references `try $l2`, but the `rethrow` is not within its +`catch` block. + +The example below includes all of the cases explained above. The numbers +within `()` after `rethrow`s are the label operands in immediate values. +``` +(func $test + try $lA + ... + catch ($lA) + ... + block $lB + ... + try $lC + ... + catch ($lC) + ... + try $lD + ... + rethrow $lD (0) ;; refers to 'catch ($lD)', but it is not within 'catch ($lD)', so validation failure + rethrow $lC (1) ;; rethrows the exception caught by catch ($lC) + rethrow $lB (2) ;; refers to 'block $lB', so validation failure + rethrow $lA (3) ;; rethrows the exception caught by catch ($lA) + rethrow 4 ;; validation failure + catch ($lD) + ... + rethrow $lD (0) ;; rethrows the exception caught by catch ($lD) + rethrow $lC (1) ;; rethrows the exception caught by catch ($lC) + rethrow $lB (2) ;; refers to 'block $lB', so validation failure + rethrow $lA (3) ;; rethrows the exception caught by catch ($lA) + rethrow 4 ;; validation failure + end + end + end + ... + end +``` + +### Try-delegate blocks + +Try blocks can also be used with the `delegate` instruction. A try-delegate +block contains a `delegate` instruction with the following form: + +``` +try blocktype + instruction* +delegate label +``` + +The `delegate` clause does not have an associated body, so try-delegate blocks +don't have an `end` instruction at the end. The `delegate` instruction takes a +try label and delegates exception handling to a `catch`/`catch_all`/`delegate` +specified by the `try` label. For example, consider this code: + +``` +try $l0 + try + call $foo + delegate $l0 ;; (= delegate 0) +catch + ... +catch_all + ... +end +``` + +If `call $foo` throws, searching for a catching block first finds `delegate`, +and because it delegates exception handling to catching instructions associated +with `$l1`, it will be next checked by the outer `catch` and then `catch_all` +instructions. + +`delegate` can also target `catch`-less `try`s or non-`try` block constructs +like `block`s or `loop`s, in which case the delegated exception is assumed to +propagate to the outer scope and will be caught by the next matching +try-catches, or rethrown to the caller if there is no outer try block. In the +examples, catches are annotated with `($label_name)` to clarify which `try` it +belongs to for clarification; it is not the official syntax. +``` +try $l0 + block $l1 + try + call $foo + delegate $l1 ;; delegates to 'catch ($l0)' + end +catch ($l0) +end +``` + +Like branches, `delegate` can only target outer blocks, and effectively +rethrows the exception in that block. Consequently, delegating to a specific +`catch` or `catch_all` handler requires targeting the respective label from +within the associated `try` block. Delegating to a label from within a `catch` +block does delegate the exception to the next enclosing handler -- analogous to +performing a `throw` within a `catch` block, that handler is no longer active +at that point. Here is another example: + +``` +try $l0 + try $l1 + catch ($l1) + try + call $foo + delegate $l1 ;; delegates to 'catch ($l0)' + catch_all + ... + end +catch ($l0) +``` + +Here the `delegate` is targeting `catch ($l1)`, which exists before the +`delegate`. So in case an exception occurs, it propagates out and ends up +targetting `catch ($l0)`, if the catch has a matching tag. If not, it will +propagate further out. Even if the `catch_all` is below the `delegate`, +`delegate` targets catches of a `try` as a whole and does not target an +individual `catch`/`catch_all`, so it doesn't apply. + +If `delegate` targets the implicit function body block, then in effect it +delegates the exception to the caller of the current function. For example: +``` +(func $test + try + try + call $foo + delegate 1 ;; delegates to the caller + catch + ... + catch_all + ... + end +) +``` +In case `foo` throws, `delegate 1` here delegates the exception handling to the +caller, i.e., the exception escapes the current function. If the immediate is +greater than or equal to the number of block nesting including the implicit +function-level block, it is a validation failure. In this example, any number +equal to or greater than 2 is not allowed. + +The below is an example that includes all the cases explained. The numbers +within `()` after `delegate`s are the label operands in immediate values. +``` +(func $test + try $lA + block $lB + try $lC + try + delegate $lC (0) ;; delegates to 'catch ($lC)' + try + delegate $lB (1) ;; $lB is a block, so delegates to 'catch ($lA)' + try + delegate $lA (2) ;; delegates to 'catch ($lA)' + try + delegate 3 ;; propagates to the caller + try + delegate 4 ;; validation failure + catch ($lC) + try + delegate $lC (0) ;; 'catch ($lC)' is above this instruction, + ;; so delegates to 'catch ($lA)' + try + delegate $lB (1) ;; $lB is a block, so delegates to 'catch ($lA)' + try + delegate $lA (2) ;; delegates to 'catch ($lA)' + try + delegate 3 ;; propagates to the caller + try + delegate 4 ;; validation failure + end ;; try $lC + end ;; block $lB + catch ($lA) + end ;; try $lA +) +``` + +### JS API + +#### Traps + +The `catch`/`catch_all` instruction catches exceptions generated by the `throw` +instruction, but does not catch traps. The rationale for this is that in general +traps are not locally recoverable and are not needed to be handled in local +scopes like try-catch. + +The `catch` instruction catches foreign exceptions generated from calls to +function imports as well, including JavaScript exceptions, with a few +exceptions: +1. In order to be consistent before and after a trap reaches a JavaScript frame, + the `catch` instruction does not catch exceptions generated from traps. +1. The `catch` instruction does not catch JavaScript exceptions generated from + stack overflow and out of memory. + +Filtering these exceptions should be based on a predicate that is not observable +by JavaScript. Traps currently generate instances of +[`WebAssembly.RuntimeError`](https://webassembly.github.io/reference-types/js-api/#exceptiondef-runtimeerror), +but this detail is not used to decide type. Implementations are supposed to +specially mark non-catchable exceptions. +([`instanceof`](https://tc39.es/ecma262/#sec-instanceofoperator) predicate can +be intercepted in JS, and types of exceptions generated from stack overflow and +out of memory are implementation-defined.) + +#### API additions + +The following additional classes are added to the JS API in order to allow +JavaScript to interact with WebAssembly exceptions: + + * `WebAssembly.Tag` + * `WebAssembly.Exception` + +The `WebAssembly.Tag` class represents a typed tag defined in the tag section +and exported from a WebAssembly module. It allows querying the type of a tag +following the [JS type reflection +proposal](https://github.com/WebAssembly/js-types/blob/master/proposals/js-types/Overview.md). +Constructing an instance of `Tag` creates a fresh tag, and the new tag can be +passed to a WebAssembly module as a tag import. + +In the future, `WebAssembly.Tag` may be used for other proposals that require a +typed tag and its constructor may be extended to accept other types and/or a tag +attribute to differentiate them from tags used for exceptions. + +The `WebAssembly.Exception` class represents an exception thrown from +WebAssembly, or an exception that is constructed in JavaScript and is to be +thrown to a WebAssembly exception handler. The `Exception` constructor accepts a +`Tag` argument and a sequence of arguments for the exception's data fields. The +`Tag` argument determines the exception tag to use. The data field arguments +must match the types specified by the `Tag`'s type. The `is` method can be used +to query if the `Exception` matches a given tag. The `getArg` method allows +access to the data fields of a `Exception` if a matching tag is given. This last +check ensures that without access to a WebAssembly module's exported exception +tag, the associated data fields cannot be read. + +The `Exception` constructor can take an optional `ExceptionOptions` argument, +which can optionally contain `traceStack` entry. When `traceStack` is +`true`, JavaScript VMs are permitted to attach a stack trace string to +`Exception.stack` field, as in JavaScript's `Error` class. `traceStack` +serves as a request to the WebAssembly engine to attach a stack trace; it +is not necessary to honour if `true`, but `trace` may not be populated if +`traceStack` is `false`. While `Exception` is not a subclass of JavaScript's +`Error` and it can be used to represent normal control flow constructs, +`traceStack` field can be set when we use it to represent errors. The +format of stack trace strings conform to the [WebAssembly stack trace +conventions](https://webassembly.github.io/spec/web-api/index.html#conventions). +When `ExceptionOption` is not provided or it does not contain `traceStack` +entry, `traceStack` is considered `false` by default. + +To preserve stack trace info when crossing the JS to Wasm boundary, exceptions +can internally contain a stack trace, which is propagated when caught by `catch` +and rethrown by `rethrow`. + +More formally, the added interfaces look like the following: + +```WebIDL +dictionary TagType { + required sequence parameters; +}; + +[LegacyNamespace=WebAssembly, Exposed=(Window,Worker,Worklet)] +interface Tag { + constructor(TagType type); + TagType type(); +}; + +dictionary ExceptionOptions { + boolean traceStack = false; +}; + +[LegacyNamespace=WebAssembly, Exposed=(Window,Worker,Worklet)] +interface Exception { + constructor(Tag tag, sequence payload, optional ExceptionOptions options); + any getArg(Tag tag, unsigned long index); + boolean is(Tag tag); + readonly attribute (DOMString or undefined) stack; +}; +``` + +`TagType` corresponds to a `FunctionType` in [the type reflection +proposal](https://github.com/WebAssembly/js-types/blob/main/proposals/js-types/Overview.md), +without a `results` property). `TagType` could be extended in the future for +other proposals that require a richer type specification. + +## Changes to the text format + +This section describes change in the [instruction syntax +document](https://github.com/WebAssembly/spec/blob/master/document/core/text/instructions.rst). + +### New instructions + +The following rules are added to *instructions*: + +``` + try blocktype instruction* (catch tag_index instruction*)* (catch_all instruction*)? end | + try blocktype instruction* delegate label | + throw tag_index argument* | + rethrow label | +``` + +Like the `block`, `loop`, and `if` instructions, the `try` instruction is +*structured* control flow instruction, and can be labeled. This allows branch +instructions to exit try blocks. + +The `tag_index` of the `throw` and `catch` instructions denotes the exception +tag to use when creating/extract from an exception. See [tag index +space](#tag-index-space) for further clarification of exception tags. + +## Changes to Modules document + +This section describes change in the [Modules +document](https://github.com/WebAssembly/design/blob/master/Modules.md). + +### Tag index space + +The `tag index space` indexes all imported and internally-defined exception +tags, assigning monotonically-increasing indices based on the order defined in +the import and tag sections. Thus, the index space starts at zero with imported +tags, followed by internally-defined tags in the [tag section](#tag-section). + +For tag indices that are not imported/exported, the corresponding exception tag +is guaranteed to be unique over all loaded modules. Exceptions that are imported +or exported alias the respective exceptions defined elsewhere, and use the same +tag. + +## Changes to the binary model + +This section describes changes in the [binary encoding design +document](https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md). + +#### Other Types + +##### tag_type + +We reserve a bit to denote the exception attribute: + +| Name | Value | +|-----------|-------| +| Exception | 0 | + +Each tag type has the fields: + +| Field | Type | Description | +|-------|------|-------------| +| `attribute` | `uint8` | The attribute of a tag. | +| `type` | `varuint32` | The type index for its corresponding type signature | + +##### external_kind + +A single-byte unsigned integer indicating the kind of definition being imported +or defined: + +* `4` indicating a `Tag` +[import](https://github.com/WebAssembly/design/blob/main/BinaryEncoding.md#import-section) or +[definition](#tag-section) + +### Module structure + +#### High-level structure + +A new `tag` section is introduced. + +##### Tag section + +The `tag` section comes after the [memory +section](https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md#memory-section) +and before the [global +section](https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md#global-section). +So the list of all sections will be: + +| Section Name | Code | Description | +| ------------ | ---- | ----------- | +| Type | `1` | Function signature declarations | +| Import | `2` | Import declarations | +| Function | `3` | Function declarations | +| Table | `4` | Indirect function table and other tables | +| Memory | `5` | Memory attributes | +| Tag | `13` | Tag declarations | +| Global | `6` | Global declarations | +| Export | `7` | Exports | +| Start | `8` | Start function declaration | +| Element | `9` | Elements section | +| Data count | `12` | Data count section | +| Code | `10` | Function bodies (code) | +| Data | `11` | Data segments | + +The tag section declares a list of tag types as follows: + +| Field | Type | Description | +|-------|------|-------------| +| count | `varuint32` | count of the number of tags to follow | +| type | `tag_type*` | The definitions of the tag types | + +##### Import section + +The import section is extended to include tag definitions by extending an +`import_entry` as follows: + +If the `kind` is `Tag`: + +| Field | Type | Description | +|-------|------|-------------| +| `type` | `tag_type` | the tag being imported | + +##### Export section + +The export section is extended to reference tag types by extending an +`export_entry` as follows: + +If the `kind` is `Tag`: + +| Field | Type | Description | +|-------|------|-------------| +| `index` | `varuint32` | the index into the corresponding tag index space | + +##### Name section + +The set of known values for `name_type` of a name section is extended as +follows: + +| Name Type | Code | Description | +| --------- | ---- | ----------- | +| [Function](#function-names) | `1` | Assigns names to functions | +| [Local](#local-names) | `2` | Assigns names to locals in functions | +| [Tag](#tag-names) | `11` | Assigns names to tags | + +###### Tag names + +The tag names subsection is a `name_map` which assigns names to a subset of +the tag indices (Used for both imports and module-defined). + +### Control flow operators + +The control flow operators are extended to define try blocks, catch blocks, +throws, and rethrows as follows: + +| Name | Opcode | Immediates | Description | +| ---- | ---- | ---- | ---- | +| `try` | `0x06` | sig : `blocktype` | begins a block which can handle thrown exceptions | +| `catch` | `0x07` | index : `varint32` | begins the catch block of the try block | +| `catch_all` | `0x19` | | begins the catch_all block of the try block | +| `delegate` | `0x18` | relative_depth : `varuint32` | ends the current try block and delegates any exceptions to the block at `relative_depth` | +| `throw` | `0x08` | index : `varint32` | creates an exception defined by the tag and then throws it | +| `rethrow` | `0x09` | relative_depth : `varuint32` | throws the exception caught by the catch block at `relative_depth` | + +The *sig* fields of `block`, `if`, and `try` operators are block signatures +which describe their use of the operand stack. diff --git a/proposals/exception-handling/old/Exceptions-v1.md b/proposals/exception-handling/pre-legacy/Exceptions-v1.md similarity index 98% rename from proposals/exception-handling/old/Exceptions-v1.md rename to proposals/exception-handling/pre-legacy/Exceptions-v1.md index a5ca40df8..c48fa64ed 100644 --- a/proposals/exception-handling/old/Exceptions-v1.md +++ b/proposals/exception-handling/pre-legacy/Exceptions-v1.md @@ -1,10 +1,8 @@ -THIS DOCUMENT IS OBSOLETE! +This is the first version of the exception handling proposal, active from 2017 +to 2018 and superseded by [V2 proposal](Exceptions-v2.md) in [Oct 2018 CG +meeting](https://github.com/WebAssembly/meetings/blob/main/main/2018/TPAC.md#exception-handling-ben-titzer). -Please see The new [Level 1 MVP Proposal] instead. - -[Level 1 MVP Proposal]: Exceptions-v2-Level-1.md - -The original proposal is preserved here for reference. +--- # Exception handling diff --git a/proposals/exception-handling/old/Exceptions-v2-Level-1+N.md b/proposals/exception-handling/pre-legacy/Exceptions-v2-Level-1+N.md similarity index 97% rename from proposals/exception-handling/old/Exceptions-v2-Level-1+N.md rename to proposals/exception-handling/pre-legacy/Exceptions-v2-Level-1+N.md index 7372ef029..08a1a5e0e 100644 --- a/proposals/exception-handling/old/Exceptions-v2-Level-1+N.md +++ b/proposals/exception-handling/pre-legacy/Exceptions-v2-Level-1+N.md @@ -1,3 +1,8 @@ +This was written along with [Level 1 Proposal](Exceptions-v2-Level-1.md) in the +beginning of 2018 for collecting ideas for future work. + +--- + # Exception Handling Level 1+N Extensions While the Level 1 Proposal establishes the minimum viable product (MVP) for diff --git a/proposals/exception-handling/old/Exceptions-v2-Level-1.md b/proposals/exception-handling/pre-legacy/Exceptions-v2-Level-1.md similarity index 97% rename from proposals/exception-handling/old/Exceptions-v2-Level-1.md rename to proposals/exception-handling/pre-legacy/Exceptions-v2-Level-1.md index 8c9ce8eda..32400e9a9 100644 --- a/proposals/exception-handling/old/Exceptions-v2-Level-1.md +++ b/proposals/exception-handling/pre-legacy/Exceptions-v2-Level-1.md @@ -1,3 +1,11 @@ +This is written as an alternative to [V1 Proposal](Exceptions-v1.md) in the +beginning of 2018 as the need for the first-class exception reference type was +suggested. This was later slightly modified and became the basis of [V2 +Proposal](Exceptions-v2.md), which replaced the V1 Proposal in [Oct 2018 CG +meeting](https://github.com/WebAssembly/meetings/blob/main/main/2018/TPAC.md#exception-handling-ben-titzer). + +--- + # Level 1 exception handling Level 1 of exception handling is the MVP (minimal viable proposal) for @@ -10,10 +18,6 @@ levels, and either: 2. Allow performance improvements in the VM. 3. Introduce additional new functionality not available in Level 1. -This document supersedes the original [Exceptions Proposal]. - -[Exceptions Proposal]: Exceptions-v1.md - ## Overview Exception handling allows code to break control flow when an exception is diff --git a/proposals/exception-handling/old/Exceptions-v2.md b/proposals/exception-handling/pre-legacy/Exceptions-v2.md similarity index 96% rename from proposals/exception-handling/old/Exceptions-v2.md rename to proposals/exception-handling/pre-legacy/Exceptions-v2.md index 233f28529..4ab9eb5f6 100644 --- a/proposals/exception-handling/old/Exceptions-v2.md +++ b/proposals/exception-handling/pre-legacy/Exceptions-v2.md @@ -1,11 +1,16 @@ -# Exception handling +This V2 proposal was developed from [Level 1 Proposal](Exceptions-v2-Level-1.md) +and superseded [V1 proposal](Exceptions-v1.md). We decided to adopt this +proposal in [Oct 2018 CG +meeting](https://github.com/WebAssembly/meetings/blob/main/main/2018/TPAC.md#exception-handling-ben-titzer), +recognizing the need for a first-class exception type, based on the reasoning +that it is more expressive and also more extendible to other kinds of events. + +This proposal was active from Oct 2018 to Sep 2020 and superseded by [V3 +proposal](https://github.com/WebAssembly/exception-handling/blob/main/proposals/exception-handling/legacy/Exceptions.md). -There were two alternative proposals ([1st](Exceptions-v1.md) and -[2nd](Exceptions-v2-Level-1.md)) for the design of exception handling and we -[decided](https://github.com/WebAssembly/meetings/blob/master/2018/TPAC.md#exception-handling-ben-titzer) -on the second proposal, which uses first-class exception types, mainly based on -the reasoning that it is more expressive and also more extendible to other kinds -of events. +--- + +# Exception handling This proposal requires the following proposals as prerequisites. diff --git a/test/core/binary-leb128.wast b/test/core/binary-leb128.wast index 1b642261a..335496f08 100644 --- a/test/core/binary-leb128.wast +++ b/test/core/binary-leb128.wast @@ -404,19 +404,19 @@ (assert_malformed (module binary "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\11\01" ;; Code section + "\01\04\01\60\00\00" ;; Type section + "\03\02\01\00" ;; Function section + "\05\03\01\00\01" ;; Memory section + "\0a\11\01" ;; Code section ;; function 0 - "\0f\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\28" ;; i32.load - "\02" ;; alignment 2 - "\82\80\80\80\80\00" ;; offset 2 with one byte too many - "\1a" ;; drop - "\0b" ;; end + "\0f\01\01" ;; local type count + "\7f" ;; i32 + "\41\00" ;; i32.const 0 + "\28" ;; i32.load + "\02" ;; alignment 2 + "\82\80\80\80\80\80\80\80\80\80\00" ;; offset 2 with one byte too many + "\1a" ;; drop + "\0b" ;; end ) "integer representation too long" ) @@ -461,19 +461,19 @@ (assert_malformed (module binary "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\12\01" ;; Code section + "\01\04\01\60\00\00" ;; Type section + "\03\02\01\00" ;; Function section + "\05\03\01\00\01" ;; Memory section + "\0a\12\01" ;; Code section ;; function 0 - "\10\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\41\03" ;; i32.const 3 - "\36" ;; i32.store - "\02" ;; alignment 2 - "\82\80\80\80\80\00" ;; offset 2 with one byte too many - "\0b" ;; end + "\10\01\01" ;; local type count + "\7f" ;; i32 + "\41\00" ;; i32.const 0 + "\41\03" ;; i32.const 3 + "\36" ;; i32.store + "\02" ;; alignment 2 + "\82\80\80\80\80\80\80\80\80\80\00" ;; offset 2 with one byte too many + "\0b" ;; end ) "integer representation too long" ) @@ -730,40 +730,42 @@ (assert_malformed (module binary "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\10\01" ;; Code section + "\01\04\01\60\00\00" ;; Type section + "\03\02\01\00" ;; Function section + "\05\03\01\00\01" ;; Memory section + "\0a\10\01" ;; Code section ;; function 0 - "\0e\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\28" ;; i32.load - "\02" ;; alignment 2 - "\82\80\80\80\10" ;; offset 2 with unused bits set - "\1a" ;; drop - "\0b" ;; end + "\0e\01\01" ;; local type count + "\7f" ;; i32 + "\41\00" ;; i32.const 0 + "\28" ;; i32.load + "\02" ;; alignment 2 + "\82\80\80\80\80\80\80\80\80\10" ;; offset 2 with unused bits set + "\1a" ;; drop + "\0b" ;; end ) - "integer too large" + ;; TODO: This changes to "integer too large" with memory64. + "integer representation too long" ) (assert_malformed (module binary "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\10\01" ;; Code section + "\01\04\01\60\00\00" ;; Type section + "\03\02\01\00" ;; Function section + "\05\03\01\00\01" ;; Memory section + "\0a\10\01" ;; Code section ;; function 0 - "\0e\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\28" ;; i32.load - "\02" ;; alignment 2 - "\82\80\80\80\40" ;; offset 2 with some unused bits set - "\1a" ;; drop - "\0b" ;; end + "\0e\01\01" ;; local type count + "\7f" ;; i32 + "\41\00" ;; i32.const 0 + "\28" ;; i32.load + "\02" ;; alignment 2 + "\82\80\80\80\80\80\80\80\80\40" ;; offset 2 with some unused bits set + "\1a" ;; drop + "\0b" ;; end ) - "integer too large" + ;; TODO: This changes to "integer too large" with memory64. + "integer representation too long" ) (assert_malformed (module binary @@ -843,41 +845,42 @@ (assert_malformed (module binary "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\11\01" ;; Code section + "\01\04\01\60\00\00" ;; Type section + "\03\02\01\00" ;; Function section + "\05\03\01\00\01" ;; Memory section + "\0a\11\01" ;; Code section ;; function 0 - "\0f\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\41\03" ;; i32.const 3 - "\36" ;; i32.store - "\02" ;; alignment 2 - "\82\80\80\80\10" ;; offset 2 with unused bits set - "\0b" ;; end + "\0f\01\01" ;; local type count + "\7f" ;; i32 + "\41\00" ;; i32.const 0 + "\41\03" ;; i32.const 3 + "\36" ;; i32.store + "\02" ;; alignment 2 + "\82\80\80\80\80\80\80\80\80\10" ;; offset 2 with unused bits set + "\0b" ;; end ) - "integer too large" + ;; TODO: This changes to "integer too large" with memory64. + "integer representation too long" ) (assert_malformed (module binary "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\11\01" ;; Code section - + "\01\04\01\60\00\00" ;; Type section + "\03\02\01\00" ;; Function section + "\05\03\01\00\01" ;; Memory section + "\0a\11\01" ;; Code section ;; function 0 - "\0f\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\41\03" ;; i32.const 3 - "\36" ;; i32.store - "\02" ;; alignment 2 - "\82\80\80\80\40" ;; offset 2 with some unused bits set - "\0b" ;; end + "\0f\01\01" ;; local type count + "\7f" ;; i32 + "\41\00" ;; i32.const 0 + "\41\03" ;; i32.const 3 + "\36" ;; i32.store + "\02" ;; alignment 2 + "\82\80\80\80\80\80\80\80\80\40" ;; offset 2 with some unused bits set + "\0b" ;; end ) - "integer too large" + ;; TODO: This changes to "integer too large" with memory64. + "integer representation too long" ) ;; Signed LEB128s sign-extend @@ -963,7 +966,6 @@ "integer too large" ) - (module binary "\00asm" "\01\00\00\00" "\01\04\01" ;; type section @@ -1000,3 +1002,81 @@ ) "integer representation too long" ) + +;; Data segment tags and memory index can have non-minimal length +(module binary + "\00asm" "\01\00\00\00" + "\05\03\01" ;; Memory section with 1 entry + "\00\00" ;; no max, minimum 0 + "\0b\07\01" ;; Data section with 1 entry + "\80\00" ;; Active segment, encoded with 2 bytes + "\41\00\0b\00" ;; (i32.const 0) with contents "" +) +(module binary + "\00asm" "\01\00\00\00" + "\05\03\01" ;; Memory section with 1 entry + "\00\00" ;; no max, minimum 0 + "\0b\08\01" ;; Data section with 1 entry + "\82\00" ;; Active segment, encoded with 2 bytes + "\00" ;; explicit memory index + "\41\00\0b\00" ;; (i32.const 0) with contents "" +) +(module binary + "\00asm" "\01\00\00\00" + "\05\03\01" ;; Memory section with 1 entry + "\00\00" ;; no max, minimum 0 + "\0b\09\01" ;; Data section with 1 entry + "\82\00" ;; Active segment, encoded with 2 bytes + "\80\00" ;; explicit memory index, encoded with 2 bytes + "\41\00\0b\00" ;; (i32.const 0) with contents "" +) + +;; Element segment tags and table index can have non-minimal length +(module binary + "\00asm" "\01\00\00\00" + "\04\04\01" ;; Table section with 1 entry + "\70\00\00" ;; no max, minimum 0, funcref + "\09\07\01" ;; Element section with 1 entry + "\80\00" ;; Active segment + "\41\00\0b\00" ;; (i32.const 0) with no elements +) +(module binary + "\00asm" "\01\00\00\00" + "\04\04\01" ;; Table section with 1 entry + "\70\00\00" ;; no max, minimum 0, funcref + "\09\09\01" ;; Element section with 1 entry + "\02" ;; Active segment + "\80\00" ;; explicit table index, encoded with 2 bytes + "\41\00\0b\00\00" ;; (i32.const 0) with no elements +) +(module binary + "\00asm" "\01\00\00\00" + "\04\04\01" ;; Table section with 1 entry + "\70\00\00" ;; no max, minimum 0, funcref + "\09\09\01" ;; Element section with 1 entry + "\82\00" ;; Active segment, encoded with 2 bytes + "\00" ;; explicit table index + "\41\00\0b\00\00" ;; (i32.const 0) with no elements +) +(module binary + "\00asm" "\01\00\00\00" + "\04\04\01" ;; Table section with 1 entry + "\70\00\00" ;; no max, minimum 0, funcref + "\09\0a\01" ;; Element section with 1 entry + "\82\00" ;; Active segment, encoded with 2 bytes + "\80\00" ;; explicit table index, encoded with 2 bytes + "\41\00\0b\00\00" ;; (i32.const 0) with no elements +) + +;; Type section with signed LEB128 encoded type +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\01" ;; Type section id + "\05" ;; Type section length + "\01" ;; Types vector length + "\e0\7f" ;; Malformed functype, -0x20 in signed LEB128 encoding + "\00\00" + ) + "integer representation too long" +) diff --git a/test/core/binary.wast b/test/core/binary.wast index 387b2b7b9..7e4373171 100644 --- a/test/core/binary.wast +++ b/test/core/binary.wast @@ -45,373 +45,11 @@ (assert_malformed (module binary "\00asm\00\00\00\01") "unknown binary version") ;; Invalid section id. -(assert_malformed (module binary "\00asm" "\01\00\00\00" "\0e\00") "malformed section id") -(assert_malformed (module binary "\00asm" "\01\00\00\00" "\7f\00") "malformed section id") -(assert_malformed (module binary "\00asm" "\01\00\00\00" "\80\00\01\00") "malformed section id") -(assert_malformed (module binary "\00asm" "\01\00\00\00" "\81\00\01\00") "malformed section id") -(assert_malformed (module binary "\00asm" "\01\00\00\00" "\ff\00\01\00") "malformed section id") - -;; Unsigned LEB128 can have non-minimal length -(module binary - "\00asm" "\01\00\00\00" - "\05\04\01" ;; Memory section with 1 entry - "\00\82\00" ;; no max, minimum 2 -) -(module binary - "\00asm" "\01\00\00\00" - "\05\07\01" ;; Memory section with 1 entry - "\00\82\80\80\80\00" ;; no max, minimum 2 -) - -;; Signed LEB128 can have non-minimal length -(module binary - "\00asm" "\01\00\00\00" - "\06\07\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\80\00" ;; i32.const 0 - "\0b" ;; end -) -(module binary - "\00asm" "\01\00\00\00" - "\06\07\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\ff\7f" ;; i32.const -1 - "\0b" ;; end -) -(module binary - "\00asm" "\01\00\00\00" - "\06\0a\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\80\80\80\80\00" ;; i32.const 0 - "\0b" ;; end -) -(module binary - "\00asm" "\01\00\00\00" - "\06\0a\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\ff\ff\ff\ff\7f" ;; i32.const -1 - "\0b" ;; end -) - -(module binary - "\00asm" "\01\00\00\00" - "\06\07\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\80\00" ;; i64.const 0 with unused bits set - "\0b" ;; end -) -(module binary - "\00asm" "\01\00\00\00" - "\06\07\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\ff\7f" ;; i64.const -1 with unused bits unset - "\0b" ;; end -) -(module binary - "\00asm" "\01\00\00\00" - "\06\0f\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\80\80\80\80\80\80\80\80\80\00" ;; i64.const 0 with unused bits set - "\0b" ;; end -) -(module binary - "\00asm" "\01\00\00\00" - "\06\0f\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\ff\ff\ff\ff\ff\ff\ff\ff\ff\7f" ;; i64.const -1 with unused bits unset - "\0b" ;; end -) - -(module binary - "\00asm" "\01\00\00\00" - "\05\03\01" ;; Memory section with 1 entry - "\00\00" ;; no max, minimum 0 - "\0b\06\01" ;; Data section with 1 entry - "\00" ;; Memory index 0 - "\41\00\0b\00" ;; (i32.const 0) with contents "" -) - -(module binary - "\00asm" "\01\00\00\00" - "\04\04\01" ;; Table section with 1 entry - "\70\00\00" ;; no max, minimum 0, funcref - "\09\06\01" ;; Element section with 1 entry - "\00" ;; Table index 0 - "\41\00\0b\00" ;; (i32.const 0) with no elements -) - -;; Data segment tags and memory index can have non-minimal length -(module binary - "\00asm" "\01\00\00\00" - "\05\03\01" ;; Memory section with 1 entry - "\00\00" ;; no max, minimum 0 - "\0b\07\01" ;; Data section with 1 entry - "\80\00" ;; Active segment, encoded with 2 bytes - "\41\00\0b\00" ;; (i32.const 0) with contents "" -) -(module binary - "\00asm" "\01\00\00\00" - "\05\03\01" ;; Memory section with 1 entry - "\00\00" ;; no max, minimum 0 - "\0b\08\01" ;; Data section with 1 entry - "\82\00" ;; Active segment, encoded with 2 bytes - "\00" ;; explicit memory index - "\41\00\0b\00" ;; (i32.const 0) with contents "" -) -(module binary - "\00asm" "\01\00\00\00" - "\05\03\01" ;; Memory section with 1 entry - "\00\00" ;; no max, minimum 0 - "\0b\09\01" ;; Data section with 1 entry - "\82\00" ;; Active segment, encoded with 2 bytes - "\80\00" ;; explicit memory index, encoded with 2 bytes - "\41\00\0b\00" ;; (i32.const 0) with contents "" -) - -;; Element segment tags and table index can have non-minimal length -(module binary - "\00asm" "\01\00\00\00" - "\04\04\01" ;; Table section with 1 entry - "\70\00\00" ;; no max, minimum 0, funcref - "\09\07\01" ;; Element section with 1 entry - "\80\00" ;; Active segment - "\41\00\0b\00" ;; (i32.const 0) with no elements -) -(module binary - "\00asm" "\01\00\00\00" - "\04\04\01" ;; Table section with 1 entry - "\70\00\00" ;; no max, minimum 0, funcref - "\09\09\01" ;; Element section with 1 entry - "\02" ;; Active segment - "\80\00" ;; explicit table index, encoded with 2 bytes - "\41\00\0b\00\00" ;; (i32.const 0) with no elements -) -(module binary - "\00asm" "\01\00\00\00" - "\04\04\01" ;; Table section with 1 entry - "\70\00\00" ;; no max, minimum 0, funcref - "\09\09\01" ;; Element section with 1 entry - "\82\00" ;; Active segment, encoded with 2 bytes - "\00" ;; explicit table index - "\41\00\0b\00\00" ;; (i32.const 0) with no elements -) -(module binary - "\00asm" "\01\00\00\00" - "\04\04\01" ;; Table section with 1 entry - "\70\00\00" ;; no max, minimum 0, funcref - "\09\0a\01" ;; Element section with 1 entry - "\82\00" ;; Active segment, encoded with 2 bytes - "\80\00" ;; explicit table index, encoded with 2 bytes - "\41\00\0b\00\00" ;; (i32.const 0) with no elements -) - -;; Type section with signed LEB128 encoded type -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\01" ;; Type section id - "\05" ;; Type section length - "\01" ;; Types vector length - "\e0\7f" ;; Malformed functype, -0x20 in signed LEB128 encoding - "\00\00" - ) - "integer representation too long" -) - -;; Unsigned LEB128 must not be overlong -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\05\08\01" ;; Memory section with 1 entry - "\00\82\80\80\80\80\00" ;; no max, minimum 2 with one byte too many - ) - "integer representation too long" -) - -;; Signed LEB128 must not be overlong -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0b\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\80\80\80\80\80\00" ;; i32.const 0 with one byte too many - "\0b" ;; end - ) - "integer representation too long" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0b\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\ff\ff\ff\ff\ff\7f" ;; i32.const -1 with one byte too many - "\0b" ;; end - ) - "integer representation too long" -) - -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\10\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\80\80\80\80\80\80\80\80\80\80\00" ;; i64.const 0 with one byte too many - "\0b" ;; end - ) - "integer representation too long" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\10\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\ff\ff\ff\ff\ff\ff\ff\ff\ff\ff\7f" ;; i64.const -1 with one byte too many - "\0b" ;; end - ) - "integer representation too long" -) - -;; Unsigned LEB128s zero-extend -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\05\07\01" ;; Memory section with 1 entry - "\00\82\80\80\80\70" ;; no max, minimum 2 with unused bits set - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\05\07\01" ;; Memory section with 1 entry - "\00\82\80\80\80\40" ;; no max, minimum 2 with some unused bits set - ) - "integer too large" -) - -;; Signed LEB128s sign-extend -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0a\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\80\80\80\80\70" ;; i32.const 0 with unused bits set - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0a\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\ff\ff\ff\ff\0f" ;; i32.const -1 with unused bits unset - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0a\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\80\80\80\80\1f" ;; i32.const 0 with some unused bits set - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0a\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\ff\ff\ff\ff\4f" ;; i32.const -1 with some unused bits unset - "\0b" ;; end - ) - "integer too large" -) - -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0f\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\80\80\80\80\80\80\80\80\80\7e" ;; i64.const 0 with unused bits set - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0f\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\ff\ff\ff\ff\ff\ff\ff\ff\ff\01" ;; i64.const -1 with unused bits unset - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0f\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\80\80\80\80\80\80\80\80\80\02" ;; i64.const 0 with some unused bits set - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0f\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\ff\ff\ff\ff\ff\ff\ff\ff\ff\41" ;; i64.const -1 with some unused bits unset - "\0b" ;; end - ) - "integer too large" -) - -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0f\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\80\80\80\80\80\80\80\80\80\7e" ;; i64.const 0 with unused bits set - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0f\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\ff\ff\ff\ff\ff\ff\ff\ff\ff\01" ;; i64.const -1 with unused bits unset - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0f\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\80\80\80\80\80\80\80\80\80\02" ;; i64.const 0 with some unused bits set - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0f\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\ff\ff\ff\ff\ff\ff\ff\ff\ff\41" ;; i64.const -1 with some unused bits unset - "\0b" ;; end - ) - "integer too large" -) +(assert_malformed (module binary "\00asm" "\01\00\00\00" "\0e\01\00") "malformed section id") +(assert_malformed (module binary "\00asm" "\01\00\00\00" "\7f\01\00") "malformed section id") +(assert_malformed (module binary "\00asm" "\01\00\00\00" "\80\01\00\01\01\00") "malformed section id") +(assert_malformed (module binary "\00asm" "\01\00\00\00" "\81\01\00\01\01\00") "malformed section id") +(assert_malformed (module binary "\00asm" "\01\00\00\00" "\ff\01\00\01\01\00") "malformed section id") ;; Function with missing end marker (between two functions) (assert_malformed @@ -470,386 +108,17 @@ "section size mismatch" ) -;; Unsigned LEB128 must not be overlong -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\05\08\01" ;; Memory section with 1 entry - "\00\82\80\80\80\80\00" ;; no max, minimum 2 with one byte too many - ) - "integer representation too long" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\11\01" ;; Code section - ;; function 0 - "\0f\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\28" ;; i32.load - "\02" ;; alignment 2 - "\82\80\80\80\80\00" ;; offset 2 with one byte too many - "\1a" ;; drop - "\0b" ;; end - ) - "integer representation too long" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\11\01" ;; Code section - ;; function 0 - "\0f\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\28" ;; i32.load - "\82\80\80\80\80\00" ;; alignment 2 with one byte too many - "\00" ;; offset 0 - "\1a" ;; drop - "\0b" ;; end - ) - "integer representation too long" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\12\01" ;; Code section - ;; function 0 - "\10\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\41\03" ;; i32.const 3 - "\36" ;; i32.store - "\82\80\80\80\80\00" ;; alignment 2 with one byte too many - "\03" ;; offset 3 - "\0b" ;; end - ) - "integer representation too long" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\12\01" ;; Code section - ;; function 0 - "\10\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\41\03" ;; i32.const 3 - "\36" ;; i32.store - "\02" ;; alignment 2 - "\82\80\80\80\80\00" ;; offset 2 with one byte too many - "\0b" ;; end - ) - "integer representation too long" -) - -;; Signed LEB128 must not be overlong -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0b\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\80\80\80\80\80\00" ;; i32.const 0 with one byte too many - "\0b" ;; end - ) - "integer representation too long" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0b\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\ff\ff\ff\ff\ff\7f" ;; i32.const -1 with one byte too many - "\0b" ;; end - ) - "integer representation too long" -) - -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\10\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\80\80\80\80\80\80\80\80\80\80\00" ;; i64.const 0 with one byte too many - "\0b" ;; end - ) - "integer representation too long" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\10\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\ff\ff\ff\ff\ff\ff\ff\ff\ff\ff\7f" ;; i64.const -1 with one byte too many - "\0b" ;; end - ) - "integer representation too long" -) - -;; Unsigned LEB128s zero-extend -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\05\07\01" ;; Memory section with 1 entry - "\00\82\80\80\80\70" ;; no max, minimum 2 with unused bits set - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\05\07\01" ;; Memory section with 1 entry - "\00\82\80\80\80\40" ;; no max, minimum 2 with some unused bits set - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\10\01" ;; Code section - ;; function 0 - "\0e\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\28" ;; i32.load - "\02" ;; alignment 2 - "\82\80\80\80\10" ;; offset 2 with unused bits set - "\1a" ;; drop - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\10\01" ;; Code section - ;; function 0 - "\0e\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\28" ;; i32.load - "\02" ;; alignment 2 - "\82\80\80\80\40" ;; offset 2 with some unused bits set - "\1a" ;; drop - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\10\01" ;; Code section - "\0e\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\28" ;; i32.load - "\82\80\80\80\10" ;; alignment 2 with unused bits set - "\00" ;; offset 0 - "\1a" ;; drop - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\10\01" ;; Code section - ;; function 0 - "\0e\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\28" ;; i32.load - "\82\80\80\80\40" ;; alignment 2 with some unused bits set - "\00" ;; offset 0 - "\1a" ;; drop - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\11\01" ;; Code section - ;; function 0 - "\0f\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\41\03" ;; i32.const 3 - "\36" ;; i32.store - "\82\80\80\80\10" ;; alignment 2 with unused bits set - "\03" ;; offset 3 - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\11\01" ;; Code section - ;; function 0 - "\0f\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\41\03" ;; i32.const 3 - "\36" ;; i32.store - "\82\80\80\80\40" ;; alignment 2 with some unused bits set - "\03" ;; offset 3 - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\11\01" ;; Code section - ;; function 0 - "\0f\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\41\03" ;; i32.const 3 - "\36" ;; i32.store - "\02" ;; alignment 2 - "\82\80\80\80\10" ;; offset 2 with unused bits set - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\11\01" ;; Code section - - ;; function 0 - "\0f\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\41\03" ;; i32.const 3 - "\36" ;; i32.store - "\02" ;; alignment 2 - "\82\80\80\80\40" ;; offset 2 with some unused bits set - "\0b" ;; end - ) - "integer too large" -) - -;; Signed LEB128s sign-extend -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0a\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\80\80\80\80\70" ;; i32.const 0 with unused bits set - "\0b" ;; end - ) - "integer too large" -) +;; Init expression with missing end marker (assert_malformed (module binary "\00asm" "\01\00\00\00" - "\06\0a\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\ff\ff\ff\ff\0f" ;; i32.const -1 with unused bits unset - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0a\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\80\80\80\80\1f" ;; i32.const 0 with some unused bits set - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0a\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\ff\ff\ff\ff\4f" ;; i32.const -1 with some unused bits unset - "\0b" ;; end - ) - "integer too large" -) - -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0f\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\80\80\80\80\80\80\80\80\80\7e" ;; i64.const 0 with unused bits set - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0f\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\ff\ff\ff\ff\ff\ff\ff\ff\ff\01" ;; i64.const -1 with unused bits unset - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0f\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\80\80\80\80\80\80\80\80\80\02" ;; i64.const 0 with some unused bits set - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0f\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\ff\ff\ff\ff\ff\ff\ff\ff\ff\41" ;; i64.const -1 with some unused bits unset - "\0b" ;; end + "\01\04\01\60\00\00" ;; Type section: 1 type + "\03\02\01\00" ;; Function section: 1 function + "\06\05\01\7f\00\41\00" ;; Global section: 1 entry with missing end marker + ;; Missing end marker here + "\0a\04\01\02\00\0b" ;; Code section: 1 function ) - "integer too large" + "unexpected end of section or function" ) ;; memory.grow reserved byte equal to zero. diff --git a/test/core/br_table.wast b/test/core/br_table.wast index 5c1aa50c9..3fc533d56 100644 --- a/test/core/br_table.wast +++ b/test/core/br_table.wast @@ -583,255 +583,6 @@ 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 (local.get 0) ) (return (i32.const -1)) diff --git a/test/core/call_indirect.wast b/test/core/call_indirect.wast index 1ecd9b7ba..79b8dc393 100644 --- a/test/core/call_indirect.wast +++ b/test/core/call_indirect.wast @@ -1015,3 +1015,23 @@ (module (table funcref (elem 0 0))) "unknown function" ) + + + + +;; Flat syntax + +(module + (table 1 funcref) + (func unreachable call_indirect) + (func unreachable call_indirect nop) + (func unreachable call_indirect call_indirect) + (func unreachable call_indirect (call_indirect)) + (func unreachable call_indirect call_indirect call_indirect) + (func unreachable call_indirect (result)) + (func unreachable call_indirect (result) (result)) + (func unreachable call_indirect (result) (result) call_indirect) + (func unreachable call_indirect (result) (result) call_indirect (result)) + (func (result i32) unreachable call_indirect select) + (func (result i32) unreachable call_indirect select call_indirect) +) diff --git a/test/core/elem.wast b/test/core/elem.wast index 8dc04e6e4..4a399ecae 100644 --- a/test/core/elem.wast +++ b/test/core/elem.wast @@ -148,6 +148,25 @@ (assert_return (invoke "call-7") (i32.const 65)) (assert_return (invoke "call-9") (i32.const 66)) +;; Same as the above, but use ref.null to ensure the elements use exprs. +;; Note: some tools like wast2json avoid using exprs when possible. +(module + (type $out-i32 (func (result i32))) + (table 11 funcref) + (elem (i32.const 6) funcref (ref.null func) (ref.func $const-i32-a)) + (elem (i32.const 9) funcref (ref.func $const-i32-b) (ref.null func)) + (func $const-i32-a (type $out-i32) (i32.const 65)) + (func $const-i32-b (type $out-i32) (i32.const 66)) + (func (export "call-7") (type $out-i32) + (call_indirect (type $out-i32) (i32.const 7)) + ) + (func (export "call-9") (type $out-i32) + (call_indirect (type $out-i32) (i32.const 9)) + ) +) +(assert_return (invoke "call-7") (i32.const 65)) +(assert_return (invoke "call-9") (i32.const 66)) + (assert_invalid (module (table 1 funcref) (global i32 (i32.const 0)) (elem (global.get 0) $f) (func $f)) "unknown global" @@ -656,3 +675,26 @@ (assert_return (invoke $m "get" (i32.const 0)) (ref.null extern)) (assert_return (invoke $m "get" (i32.const 1)) (ref.extern 137)) + +;; Initializing a table with imported funcref global + +(module $module4 + (func (result i32) + i32.const 42 + ) + (global (export "f") funcref (ref.func 0)) +) + +(register "module4" $module4) + +(module + (import "module4" "f" (global funcref)) + (type $out-i32 (func (result i32))) + (table 10 funcref) + (elem (offset (i32.const 0)) funcref (global.get 0)) + (func (export "call_imported_elem") (type $out-i32) + (call_indirect (type $out-i32) (i32.const 0)) + ) +) + +(assert_return (invoke "call_imported_elem") (i32.const 42)) diff --git a/test/core/ref_null.wast b/test/core/ref_null.wast index b88b0888f..eb4a31633 100644 --- a/test/core/ref_null.wast +++ b/test/core/ref_null.wast @@ -1,10 +1,13 @@ (module (func (export "externref") (result externref) (ref.null extern)) + (func (export "exnref") (result exnref) (ref.null exn)) (func (export "funcref") (result funcref) (ref.null func)) (global externref (ref.null extern)) + (global exnref (ref.null exn)) (global funcref (ref.null func)) ) (assert_return (invoke "externref") (ref.null extern)) +(assert_return (invoke "exnref") (ref.null exn)) (assert_return (invoke "funcref") (ref.null func)) diff --git a/test/core/select.wast b/test/core/select.wast index 046e6fe2c..673dcf478 100644 --- a/test/core/select.wast +++ b/test/core/select.wast @@ -512,3 +512,20 @@ "type mismatch" ) + +;; Flat syntax + +(module + (table 1 funcref) + (func (result i32) unreachable select) + (func (result i32) unreachable select nop) + (func (result i32) unreachable select (select)) + (func (result i32) unreachable select select) + (func (result i32) unreachable select select select) + (func (result i32) unreachable select (result i32)) + (func (result i32) unreachable select (result i32) (result)) + (func (result i32) unreachable select (result i32) (result) select) + (func (result i32) unreachable select (result) (result i32) select (result i32)) + (func (result i32) unreachable select call_indirect) + (func (result i32) unreachable select call_indirect select) +) diff --git a/test/core/simd/simd_linking.wast b/test/core/simd/simd_linking.wast new file mode 100644 index 000000000..1a1d16355 --- /dev/null +++ b/test/core/simd/simd_linking.wast @@ -0,0 +1,12 @@ +(module + (global (export "g-v128") v128 (v128.const i64x2 0 0)) + (global (export "mg-v128") (mut v128) (v128.const i64x2 0 0)) +) +(register "Mv128") + +(module + ;; TODO: Reactivate once the fix for https://bugs.chromium.org/p/v8/issues/detail?id=13732 + ;; has made it to the downstream node.js that we use on CI. + ;; (import "Mv128" "g-v128" (global v128)) + (import "Mv128" "mg-v128" (global (mut v128))) +) diff --git a/test/core/table_fill.wast b/test/core/table_fill.wast index 3df64da1a..a8e222552 100644 --- a/test/core/table_fill.wast +++ b/test/core/table_fill.wast @@ -5,6 +5,10 @@ (table.fill $t (local.get $i) (local.get $r) (local.get $n)) ) + (func (export "fill-abbrev") (param $i i32) (param $r externref) (param $n i32) + (table.fill (local.get $i) (local.get $r) (local.get $n)) + ) + (func (export "get") (param $i i32) (result externref) (table.get $t (local.get $i)) ) @@ -39,7 +43,7 @@ (assert_return (invoke "get" (i32.const 8)) (ref.extern 4)) (assert_return (invoke "get" (i32.const 9)) (ref.extern 4)) -(assert_return (invoke "fill" (i32.const 9) (ref.null extern) (i32.const 1))) +(assert_return (invoke "fill-abbrev" (i32.const 9) (ref.null extern) (i32.const 1))) (assert_return (invoke "get" (i32.const 8)) (ref.extern 4)) (assert_return (invoke "get" (i32.const 9)) (ref.null extern)) diff --git a/test/core/table_get.wast b/test/core/table_get.wast index 5d57c3198..0dedb19f5 100644 --- a/test/core/table_get.wast +++ b/test/core/table_get.wast @@ -10,7 +10,7 @@ ) (func (export "get-externref") (param $i i32) (result externref) - (table.get $t2 (local.get $i)) + (table.get (local.get $i)) ) (func $f3 (export "get-funcref") (param $i i32) (result funcref) (table.get $t3 (local.get $i)) diff --git a/test/core/table_grow.wast b/test/core/table_grow.wast index 7d5b5630f..9a931a7fa 100644 --- a/test/core/table_grow.wast +++ b/test/core/table_grow.wast @@ -7,6 +7,9 @@ (func (export "grow") (param $sz i32) (param $init externref) (result i32) (table.grow $t (local.get $init) (local.get $sz)) ) + (func (export "grow-abbrev") (param $sz i32) (param $init externref) (result i32) + (table.grow (local.get $init) (local.get $sz)) + ) (func (export "size") (result i32) (table.size $t)) ) @@ -22,7 +25,7 @@ (assert_trap (invoke "set" (i32.const 1) (ref.extern 2)) "out of bounds table access") (assert_trap (invoke "get" (i32.const 1)) "out of bounds table access") -(assert_return (invoke "grow" (i32.const 4) (ref.extern 3)) (i32.const 1)) +(assert_return (invoke "grow-abbrev" (i32.const 4) (ref.extern 3)) (i32.const 1)) (assert_return (invoke "size") (i32.const 5)) (assert_return (invoke "get" (i32.const 0)) (ref.extern 2)) (assert_return (invoke "set" (i32.const 0) (ref.extern 2))) diff --git a/test/core/table_set.wast b/test/core/table_set.wast index 5a9cfa371..3362f9567 100644 --- a/test/core/table_set.wast +++ b/test/core/table_set.wast @@ -12,7 +12,7 @@ ) (func (export "set-externref") (param $i i32) (param $r externref) - (table.set $t2 (local.get $i) (local.get $r)) + (table.set (local.get $i) (local.get $r)) ) (func (export "set-funcref") (param $i i32) (param $r funcref) (table.set $t3 (local.get $i) (local.get $r)) diff --git a/test/core/table_size.wast b/test/core/table_size.wast index ad293b5ee..83fef02b3 100644 --- a/test/core/table_size.wast +++ b/test/core/table_size.wast @@ -4,7 +4,7 @@ (table $t2 0 2 externref) (table $t3 3 8 externref) - (func (export "size-t0") (result i32) (table.size $t0)) + (func (export "size-t0") (result i32) table.size) (func (export "size-t1") (result i32) (table.size $t1)) (func (export "size-t2") (result i32) (table.size $t2)) (func (export "size-t3") (result i32) (table.size $t3)) diff --git a/test/core/throw.wast b/test/core/throw.wast index d53b5b550..dc1aa4a98 100644 --- a/test/core/throw.wast +++ b/test/core/throw.wast @@ -20,17 +20,18 @@ (func (export "throw-param-f64") (param f64) (local.get 0) (throw $e-f64)) + (func (export "throw-polymorphic") (throw $e0) (throw $e-i32)) + + (func (export "throw-polymorphic-block") (block (result i32) (throw $e0)) (throw $e-i32)) + (func $throw-1-2 (i32.const 1) (i32.const 2) (throw $e-i32-i32)) (func (export "test-throw-1-2") - (try - (do (call $throw-1-2)) - (catch $e-i32-i32 - (i32.const 2) - (if (i32.ne) (then (unreachable))) - (i32.const 1) - (if (i32.ne) (then (unreachable))) - ) + (block $h (result i32 i32) + (try_table (catch $e-i32-i32 $h) (call $throw-1-2)) + (return) ) + (if (i32.ne (i32.const 2)) (then (unreachable))) + (if (i32.ne (i32.const 1)) (then (unreachable))) ) ) @@ -42,6 +43,9 @@ (assert_exception (invoke "throw-param-i64" (i64.const 5))) (assert_exception (invoke "throw-param-f64" (f64.const 5.0))) +(assert_exception (invoke "throw-polymorphic")) +(assert_exception (invoke "throw-polymorphic-block")) + (assert_return (invoke "test-throw-1-2")) (assert_invalid (module (func (throw 0))) "unknown tag 0") diff --git a/test/core/throw_ref.wast b/test/core/throw_ref.wast new file mode 100644 index 000000000..f59710a1f --- /dev/null +++ b/test/core/throw_ref.wast @@ -0,0 +1,118 @@ +;; Test throw_ref instruction. + +(module + (tag $e0) + (tag $e1) + + (func (export "catch-throw_ref-0") + (block $h (result exnref) + (try_table (catch_ref $e0 $h) (throw $e0)) + (unreachable) + ) + (throw_ref) + ) + + (func (export "catch-throw_ref-1") (param i32) (result i32) + (block $h (result exnref) + (try_table (result i32) (catch_ref $e0 $h) (throw $e0)) + (return) + ) + (if (param exnref) (i32.eqz (local.get 0)) + (then (throw_ref)) + (else (drop)) + ) + (i32.const 23) + ) + + (func (export "catchall-throw_ref-0") + (block $h (result exnref) + (try_table (result exnref) (catch_all_ref $h) (throw $e0)) + ) + (throw_ref) + ) + + (func (export "catchall-throw_ref-1") (param i32) (result i32) + (block $h (result exnref) + (try_table (result i32) (catch_all_ref $h) (throw $e0)) + (return) + ) + (if (param exnref) (i32.eqz (local.get 0)) + (then (throw_ref)) + (else (drop)) + ) + (i32.const 23) + ) + + (func (export "throw_ref-nested") (param i32) (result i32) + (local $exn1 exnref) + (local $exn2 exnref) + (block $h1 (result exnref) + (try_table (result i32) (catch_ref $e1 $h1) (throw $e1)) + (return) + ) + (local.set $exn1) + (block $h2 (result exnref) + (try_table (result i32) (catch_ref $e0 $h2) (throw $e0)) + (return) + ) + (local.set $exn2) + (if (i32.eq (local.get 0) (i32.const 0)) + (then (throw_ref (local.get $exn1))) + ) + (if (i32.eq (local.get 0) (i32.const 1)) + (then (throw_ref (local.get $exn2))) + ) + (i32.const 23) + ) + + (func (export "throw_ref-recatch") (param i32) (result i32) + (local $e exnref) + (block $h1 (result exnref) + (try_table (result i32) (catch_ref $e0 $h1) (throw $e0)) + (return) + ) + (local.set $e) + (block $h2 (result exnref) + (try_table (result i32) (catch_ref $e0 $h2) + (if (i32.eqz (local.get 0)) + (then (throw_ref (local.get $e))) + ) + (i32.const 42) + ) + (return) + ) + (drop) (i32.const 23) + ) + + (func (export "throw_ref-stack-polymorphism") + (local $e exnref) + (block $h (result exnref) + (try_table (result f64) (catch_ref $e0 $h) (throw $e0)) + (unreachable) + ) + (local.set $e) + (i32.const 1) + (throw_ref (local.get $e)) + ) +) + +(assert_exception (invoke "catch-throw_ref-0")) + +(assert_exception (invoke "catch-throw_ref-1" (i32.const 0))) +(assert_return (invoke "catch-throw_ref-1" (i32.const 1)) (i32.const 23)) + +(assert_exception (invoke "catchall-throw_ref-0")) + +(assert_exception (invoke "catchall-throw_ref-1" (i32.const 0))) +(assert_return (invoke "catchall-throw_ref-1" (i32.const 1)) (i32.const 23)) +(assert_exception (invoke "throw_ref-nested" (i32.const 0))) +(assert_exception (invoke "throw_ref-nested" (i32.const 1))) +(assert_return (invoke "throw_ref-nested" (i32.const 2)) (i32.const 23)) + +(assert_return (invoke "throw_ref-recatch" (i32.const 0)) (i32.const 23)) +(assert_return (invoke "throw_ref-recatch" (i32.const 1)) (i32.const 42)) + +(assert_exception (invoke "throw_ref-stack-polymorphism")) + +(assert_invalid (module (func (throw_ref))) "type mismatch") +(assert_invalid (module (func (block (throw_ref)))) "type mismatch") diff --git a/test/core/try_table.wast b/test/core/try_table.wast new file mode 100644 index 000000000..e94a3b27d --- /dev/null +++ b/test/core/try_table.wast @@ -0,0 +1,390 @@ +;; Test try-catch blocks. + +(module + (tag $e0 (export "e0")) + (func (export "throw") (throw $e0)) +) + +(register "test") + +(module + (tag $imported-e0 (import "test" "e0")) + (tag $imported-e0-alias (import "test" "e0")) + (func $imported-throw (import "test" "throw")) + (tag $e0) + (tag $e1) + (tag $e2) + (tag $e-i32 (param i32)) + (tag $e-f32 (param f32)) + (tag $e-i64 (param i64)) + (tag $e-f64 (param f64)) + + (func $throw-if (param i32) (result i32) + (local.get 0) + (i32.const 0) (if (i32.ne) (then (throw $e0))) + (i32.const 0) + ) + + (func (export "simple-throw-catch") (param i32) (result i32) + (block $h + (try_table (result i32) (catch $e0 $h) + (if (i32.eqz (local.get 0)) (then (throw $e0)) (else)) + (i32.const 42) + ) + (return) + ) + (i32.const 23) + ) + + (func (export "unreachable-not-caught") + (block $h + (try_table (catch_all $h) (unreachable)) + (return) + ) + ) + + (func $div (param i32 i32) (result i32) + (local.get 0) (local.get 1) (i32.div_u) + ) + (func (export "trap-in-callee") (param i32 i32) (result i32) + (block $h + (try_table (result i32) (catch_all $h) + (call $div (local.get 0) (local.get 1)) + ) + (return) + ) + (i32.const 11) + ) + + (func (export "catch-complex-1") (param i32) (result i32) + (block $h1 + (try_table (result i32) (catch $e1 $h1) + (block $h0 + (try_table (result i32) (catch $e0 $h0) + (if (i32.eqz (local.get 0)) + (then (throw $e0)) + (else + (if (i32.eq (local.get 0) (i32.const 1)) + (then (throw $e1)) + (else (throw $e2)) + ) + ) + ) + (i32.const 2) + ) + (br 1) + ) + (i32.const 3) + ) + (return) + ) + (i32.const 4) + ) + + (func (export "catch-complex-2") (param i32) (result i32) + (block $h0 + (block $h1 + (try_table (result i32) (catch $e0 $h0) (catch $e1 $h1) + (if (i32.eqz (local.get 0)) + (then (throw $e0)) + (else + (if (i32.eq (local.get 0) (i32.const 1)) + (then (throw $e1)) + (else (throw $e2)) + ) + ) + ) + (i32.const 2) + ) + (return) + ) + (return (i32.const 4)) + ) + (i32.const 3) + ) + + (func (export "throw-catch-param-i32") (param i32) (result i32) + (block $h (result i32) + (try_table (result i32) (catch $e-i32 $h) + (throw $e-i32 (local.get 0)) + (i32.const 2) + ) + (return) + ) + (return) + ) + + (func (export "throw-catch-param-f32") (param f32) (result f32) + (block $h (result f32) + (try_table (result f32) (catch $e-f32 $h) + (throw $e-f32 (local.get 0)) + (f32.const 0) + ) + (return) + ) + (return) + ) + + (func (export "throw-catch-param-i64") (param i64) (result i64) + (block $h (result i64) + (try_table (result i64) (catch $e-i64 $h) + (throw $e-i64 (local.get 0)) + (i64.const 2) + ) + (return) + ) + (return) + ) + + (func (export "throw-catch-param-f64") (param f64) (result f64) + (block $h (result f64) + (try_table (result f64) (catch $e-f64 $h) + (throw $e-f64 (local.get 0)) + (f64.const 0) + ) + (return) + ) + (return) + ) + + (func (export "throw-catch_ref-param-i32") (param i32) (result i32) + (block $h (result i32 exnref) + (try_table (result i32) (catch_ref $e-i32 $h) + (throw $e-i32 (local.get 0)) + (i32.const 2) + ) + (return) + ) + (drop) (return) + ) + + (func (export "throw-catch_ref-param-f32") (param f32) (result f32) + (block $h (result f32 exnref) + (try_table (result f32) (catch_ref $e-f32 $h) + (throw $e-f32 (local.get 0)) + (f32.const 0) + ) + (return) + ) + (drop) (return) + ) + + (func (export "throw-catch_ref-param-i64") (param i64) (result i64) + (block $h (result i64 exnref) + (try_table (result i64) (catch_ref $e-i64 $h) + (throw $e-i64 (local.get 0)) + (i64.const 2) + ) + (return) + ) + (drop) (return) + ) + + (func (export "throw-catch_ref-param-f64") (param f64) (result f64) + (block $h (result f64 exnref) + (try_table (result f64) (catch_ref $e-f64 $h) + (throw $e-f64 (local.get 0)) + (f64.const 0) + ) + (return) + ) + (drop) (return) + ) + + (func $throw-param-i32 (param i32) (throw $e-i32 (local.get 0))) + (func (export "catch-param-i32") (param i32) (result i32) + (block $h (result i32) + (try_table (result i32) (catch $e-i32 $h) + (i32.const 0) + (call $throw-param-i32 (local.get 0)) + ) + (return) + ) + ) + + (func (export "catch-imported") (result i32) + (block $h + (try_table (result i32) (catch $imported-e0 $h) + (call $imported-throw (i32.const 1)) + ) + (return) + ) + (i32.const 2) + ) + + (func (export "catch-imported-alias") (result i32) + (block $h + (try_table (result i32) (catch $imported-e0 $h) + (throw $imported-e0-alias (i32.const 1)) + ) + (return) + ) + (i32.const 2) + ) + + (func (export "catchless-try") (param i32) (result i32) + (block $h + (try_table (result i32) (catch $e0 $h) + (try_table (result i32) (call $throw-if (local.get 0))) + ) + (return) + ) + (i32.const 1) + ) + + (func $throw-void (throw $e0)) + (func (export "return-call-in-try-catch") + (block $h + (try_table (catch $e0 $h) + (return_call $throw-void) + ) + ) + ) + + (table funcref (elem $throw-void)) + (func (export "return-call-indirect-in-try-catch") + (block $h + (try_table (catch $e0 $h) + (return_call_indirect (i32.const 0)) + ) + ) + ) + + (func (export "try-with-param") + (i32.const 0) (try_table (param i32) (drop)) + ) +) + +(assert_return (invoke "simple-throw-catch" (i32.const 0)) (i32.const 23)) +(assert_return (invoke "simple-throw-catch" (i32.const 1)) (i32.const 42)) + +(assert_trap (invoke "unreachable-not-caught") "unreachable") + +(assert_return (invoke "trap-in-callee" (i32.const 7) (i32.const 2)) (i32.const 3)) +(assert_trap (invoke "trap-in-callee" (i32.const 1) (i32.const 0)) "integer divide by zero") + +(assert_return (invoke "catch-complex-1" (i32.const 0)) (i32.const 3)) +(assert_return (invoke "catch-complex-1" (i32.const 1)) (i32.const 4)) +(assert_exception (invoke "catch-complex-1" (i32.const 2))) + +(assert_return (invoke "catch-complex-2" (i32.const 0)) (i32.const 3)) +(assert_return (invoke "catch-complex-2" (i32.const 1)) (i32.const 4)) +(assert_exception (invoke "catch-complex-2" (i32.const 2))) + +(assert_return (invoke "throw-catch-param-i32" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "throw-catch-param-i32" (i32.const 1)) (i32.const 1)) +(assert_return (invoke "throw-catch-param-i32" (i32.const 10)) (i32.const 10)) + +(assert_return (invoke "throw-catch-param-f32" (f32.const 5.0)) (f32.const 5.0)) +(assert_return (invoke "throw-catch-param-f32" (f32.const 10.5)) (f32.const 10.5)) + +(assert_return (invoke "throw-catch-param-i64" (i64.const 5)) (i64.const 5)) +(assert_return (invoke "throw-catch-param-i64" (i64.const 0)) (i64.const 0)) +(assert_return (invoke "throw-catch-param-i64" (i64.const -1)) (i64.const -1)) + +(assert_return (invoke "throw-catch-param-f64" (f64.const 5.0)) (f64.const 5.0)) +(assert_return (invoke "throw-catch-param-f64" (f64.const 10.5)) (f64.const 10.5)) + +(assert_return (invoke "throw-catch_ref-param-i32" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "throw-catch_ref-param-i32" (i32.const 1)) (i32.const 1)) +(assert_return (invoke "throw-catch_ref-param-i32" (i32.const 10)) (i32.const 10)) + +(assert_return (invoke "throw-catch_ref-param-f32" (f32.const 5.0)) (f32.const 5.0)) +(assert_return (invoke "throw-catch_ref-param-f32" (f32.const 10.5)) (f32.const 10.5)) + +(assert_return (invoke "throw-catch_ref-param-i64" (i64.const 5)) (i64.const 5)) +(assert_return (invoke "throw-catch_ref-param-i64" (i64.const 0)) (i64.const 0)) +(assert_return (invoke "throw-catch_ref-param-i64" (i64.const -1)) (i64.const -1)) + +(assert_return (invoke "throw-catch_ref-param-f64" (f64.const 5.0)) (f64.const 5.0)) +(assert_return (invoke "throw-catch_ref-param-f64" (f64.const 10.5)) (f64.const 10.5)) + +(assert_return (invoke "catch-param-i32" (i32.const 5)) (i32.const 5)) + +(assert_return (invoke "catch-imported") (i32.const 2)) +(assert_return (invoke "catch-imported-alias") (i32.const 2)) + +(assert_return (invoke "catchless-try" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "catchless-try" (i32.const 1)) (i32.const 1)) + +(assert_exception (invoke "return-call-in-try-catch")) +(assert_exception (invoke "return-call-indirect-in-try-catch")) + +(assert_return (invoke "try-with-param")) + +(module + (func $imported-throw (import "test" "throw")) + (tag $e0) + + (func (export "imported-mismatch") (result i32) + (block $h + (try_table (result i32) (catch_all $h) + (block $h0 + (try_table (result i32) (catch $e0 $h0) + (i32.const 1) + (call $imported-throw) + ) + (return) + ) + (i32.const 2) + ) + (return) + ) + (i32.const 3) + ) +) + +(assert_return (invoke "imported-mismatch") (i32.const 3)) + +(assert_malformed + (module quote "(module (func (catch_all)))") + "unexpected token" +) + +(assert_malformed + (module quote "(module (tag $e) (func (catch $e)))") + "unexpected token" +) + +(module + (tag $e) + (func (try_table (catch $e 0) (catch $e 0))) + (func (try_table (catch_all 0) (catch $e 0))) + (func (try_table (catch_all 0) (catch_all 0))) + (func (result exnref) (try_table (catch_ref $e 0) (catch_ref $e 0)) (unreachable)) + (func (result exnref) (try_table (catch_all_ref 0) (catch_ref $e 0)) (unreachable)) + (func (result exnref) (try_table (catch_all_ref 0) (catch_all_ref 0)) (unreachable)) +) + +(assert_invalid + (module (func (result i32) (try_table (result i32)))) + "type mismatch" +) +(assert_invalid + (module (func (result i32) (try_table (result i32) (i64.const 42)))) + "type mismatch" +) + +(assert_invalid + (module (tag) (func (try_table (catch_ref 0 0)))) + "type mismatch" +) +(assert_invalid + (module (tag) (func (result exnref) (try_table (catch 0 0)) (unreachable))) + "type mismatch" +) +(assert_invalid + (module (func (try_table (catch_all_ref 0)))) + "type mismatch" +) +(assert_invalid + (module (func (result exnref) (try_table (catch_all 0)) (unreachable))) + "type mismatch" +) +(assert_invalid + (module + (tag (param i64)) + (func (result i32 exnref) (try_table (result i32) (catch_ref 0 0) (i32.const 42))) + ) + "type mismatch" +) diff --git a/test/js-api/exception/basic.tentative.any.js b/test/js-api/exception/basic.tentative.any.js new file mode 100644 index 000000000..09f8479aa --- /dev/null +++ b/test/js-api/exception/basic.tentative.any.js @@ -0,0 +1,182 @@ +// META: global=window,dedicatedworker,jsshell,shadowrealm +// META: script=/wasm/jsapi/wasm-module-builder.js + +function assert_throws_wasm(fn, message) { + try { + fn(); + assert_not_reached(`expected to throw with ${message}`); + } catch (e) { + assert_true(e instanceof WebAssembly.Exception, `Error should be a WebAssembly.Exception with ${message}`); + } +} + +promise_test(async () => { + const kSig_v_r = makeSig([kWasmExternRef], []); + const builder = new WasmModuleBuilder(); + const tagIndexExternref = builder.addTag(kSig_v_r); + builder.addFunction("throw_param", kSig_v_r) + .addBody([ + kExprLocalGet, 0, + kExprThrow, tagIndexExternref, + ]) + .exportFunc(); + const buffer = builder.toBuffer(); + const {instance} = await WebAssembly.instantiate(buffer, {}); + const values = [ + undefined, + null, + true, + false, + "test", + Symbol(), + 0, + 1, + 4.2, + NaN, + Infinity, + {}, + () => {}, + ]; + for (const v of values) { + assert_throws_wasm(() => instance.exports.throw_param(v), String(v)); + } +}, "Wasm function throws argument"); + +promise_test(async () => { + const builder = new WasmModuleBuilder(); + const tagIndexAnyref = builder.addTag(kSig_v_a); + builder.addFunction("throw_null", kSig_v_v) + .addBody([ + kExprRefNull, kAnyFuncCode, + kExprThrow, tagIndexAnyref, + ]) + .exportFunc(); + const buffer = builder.toBuffer(); + const {instance} = await WebAssembly.instantiate(buffer, {}); + assert_throws_wasm(() => instance.exports.throw_null()); +}, "Wasm function throws null"); + +promise_test(async () => { + const builder = new WasmModuleBuilder(); + const tagIndexI32 = builder.addTag(kSig_v_i); + builder.addFunction("throw_int", kSig_v_v) + .addBody([ + ...wasmI32Const(7), + kExprThrow, tagIndexI32, + ]) + .exportFunc(); + const buffer = builder.toBuffer(); + const {instance} = await WebAssembly.instantiate(buffer, {}); + assert_throws_wasm(() => instance.exports.throw_int()); +}, "Wasm function throws integer"); + +promise_test(async () => { + const builder = new WasmModuleBuilder(); + const fnIndex = builder.addImport("module", "fn", kSig_v_v); + const tagIndexExternref = builder.addTag(kSig_v_r); + + builder.addFunction("catch_exception", kSig_r_v) + .addBody([ + kExprBlock, kWasmVoid, + kExprBlock, kExternRefCode, + kExprTryTable, kWasmVoid, 1, + kCatchNoRef, tagIndexExternref, 0, + kExprCallFunction, fnIndex, + kExprEnd, + kExprBr, 1, + kExprEnd, + kExprReturn, + kExprEnd, + kExprRefNull, kExternRefCode, + ]) + .exportFunc(); + + const buffer = builder.toBuffer(); + + const error = new Error(); + const fn = () => { throw error }; + const {instance} = await WebAssembly.instantiate(buffer, { + module: { fn } + }); + assert_throws_exactly(error, () => instance.exports.catch_exception()); +}, "Imported JS function throws"); + +promise_test(async () => { + const builder = new WasmModuleBuilder(); + const fnIndex = builder.addImport("module", "fn", kSig_v_v); + builder.addFunction("catch_and_rethrow", kSig_r_v) + .addBody([ + kExprBlock, kWasmVoid, + kExprBlock, kExnRefCode, + kExprTryTable, kWasmVoid, 1, + kCatchAllRef, 0, + kExprCallFunction, fnIndex, + kExprEnd, + kExprBr, 1, + kExprEnd, + kExprThrowRef, + kExprEnd, + kExprRefNull, kExternRefCode, + ]) + .exportFunc(); + + const buffer = builder.toBuffer(); + + const error = new Error(); + const fn = () => { throw error }; + const {instance} = await WebAssembly.instantiate(buffer, { + module: { fn } + }); + assert_throws_exactly(error, () => instance.exports.catch_and_rethrow()); +}, "Imported JS function throws, Wasm catches and rethrows"); + +promise_test(async () => { + const builder = new WasmModuleBuilder(); + const fnIndex = builder.addImport("module", "fn", kSig_v_v); + const tagI32 = new WebAssembly.Tag({ parameters: ["i32"] }); + const tagIndexI32 = builder.addImportedTag("module", "tagI32", kSig_v_i); + const exn = new WebAssembly.Exception(tagI32, [42]); + const kSig_ie_v = makeSig([], [kWasmI32, kExnRefCode]); + const sig_ie_v = builder.addType(kSig_ie_v); + + builder.addFunction("all_catch_clauses", kSig_i_v) + .addBody([ + kExprBlock, kWasmVoid, + kExprBlock, kExnRefCode, + kExprBlock, sig_ie_v, + kExprBlock, kWasmVoid, + kExprBlock, kWasmI32, + kExprTryTable, kWasmVoid, 4, + kCatchNoRef, tagIndexI32, 0, + kCatchAllNoRef, 1, + kCatchRef, tagIndexI32, 2, + kCatchAllRef, 3, + kExprCallFunction, fnIndex, + kExprEnd, + kExprBr, 4, + kExprEnd, + kExprReturn, + kExprEnd, + kExprBr, 2, + kExprEnd, + kExprDrop, + kExprDrop, + kExprBr, 1, + kExprEnd, + kExprDrop, + kExprEnd, + kExprI32Const, 0, + ]) + .exportFunc(); + + const buffer = builder.toBuffer(); + + const fn = () => { + throw exn; + }; + const {instance} = await WebAssembly.instantiate(buffer, { + module: { fn, tagI32: tagI32 } + }); + const result = instance.exports.all_catch_clauses(); + assert_equals(result, 42); +}, "try-table uses all four kinds of catch clauses, one of which catches an exception"); diff --git a/test/js-api/exception/constructor.tentative.any.js b/test/js-api/exception/constructor.tentative.any.js index 7ad08e188..a46d1816c 100644 --- a/test/js-api/exception/constructor.tentative.any.js +++ b/test/js-api/exception/constructor.tentative.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/assertions.js test(() => { diff --git a/test/js-api/exception/getArg.tentative.any.js b/test/js-api/exception/getArg.tentative.any.js index f0a568a85..6d56ac8c6 100644 --- a/test/js-api/exception/getArg.tentative.any.js +++ b/test/js-api/exception/getArg.tentative.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/memory/assertions.js test(() => { @@ -43,7 +43,7 @@ test(() => { const tag = new WebAssembly.Tag({ parameters: [] }); const exn = new WebAssembly.Exception(tag, []); for (const value of outOfRangeValues) { - assert_throws_js(RangeError, () => exn.getArg(tag, value)); + assert_throws_js(TypeError, () => exn.getArg(tag, value)); } }, "Getting out-of-range argument"); diff --git a/test/js-api/exception/identity.tentative.any.js b/test/js-api/exception/identity.tentative.any.js index 65787c107..802e7053a 100644 --- a/test/js-api/exception/identity.tentative.any.js +++ b/test/js-api/exception/identity.tentative.any.js @@ -1,61 +1,201 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/assertions.js // META: script=/wasm/jsapi/wasm-module-builder.js test(() => { - const tag = new WebAssembly.Tag({ parameters: ["i32"] }); - const exn = new WebAssembly.Exception(tag, [42]); - const exn_same_payload = new WebAssembly.Exception(tag, [42]); - const exn_diff_payload = new WebAssembly.Exception(tag, [53]); - const builder = new WasmModuleBuilder(); - const jsfuncIndex = builder.addImport("module", "jsfunc", kSig_v_v); - const tagIndex = builder.addImportedTag("module", "tag", kSig_v_i); + + // Tag defined in JavaScript and imported into Wasm + const jsTag = new WebAssembly.Tag({ parameters: ["i32"] }); + const jsTagIndex = builder.addImportedTag("module", "jsTag", kSig_v_i); + const jsTagExn = new WebAssembly.Exception(jsTag, [42]); + const jsTagExnSamePayload = new WebAssembly.Exception(jsTag, [42]); + const jsTagExnDiffPayload = new WebAssembly.Exception(jsTag, [53]); + const throwJSTagExnIndex = builder.addImport("module", "throwJSTagExn", kSig_v_v); + + // Tag defined in Wasm and exported to JS + const wasmTagIndex = builder.addTag(kSig_v_i); + builder.addExportOfKind("wasmTag", kExternalTag, wasmTagIndex); + const throwWasmTagExnIndex = builder.addImport("module", "throwWasmTagExn", kSig_v_v); + // Will be assigned after an instance is created + let wasmTagExn = null; + let wasmTagExnSamePayload = null; + let wasmTagExnDiffPayload = null; + + const kSig_ie_v = makeSig([], [kWasmI32, kExnRefCode]); + const sig_ie_v = builder.addType(kSig_ie_v); + const imports = { module: { - jsfunc: function() { throw exn; }, - tag: tag + throwJSTagExn: function() { throw jsTagExn; }, + throwWasmTagExn: function() { throw wasmTagExn; }, + jsTag: jsTag } }; + // Call a JS function that throws an exception using a JS-defined tag, catches + // it with a 'catch_ref' instruction, and rethrows it. + builder + .addFunction("catch_ref_js_tag_throw_ref", kSig_v_v) + .addBody([ + kExprBlock, kWasmVoid, + kExprBlock, sig_ie_v, + kExprTryTable, kWasmVoid, 1, + kCatchRef, jsTagIndex, 0, + kExprCallFunction, throwJSTagExnIndex, + kExprEnd, + kExprBr, 1, + kExprEnd, + kExprThrowRef, + kExprEnd + ]) + .exportFunc(); + + // Call a JS function that throws an exception using a Wasm-defined tag, + // catches it with a 'catch_ref' instruction, and rethrows it. builder - .addFunction("catch_rethrow", kSig_v_v) + .addFunction("catch_ref_wasm_tag_throw_ref", kSig_v_v) .addBody([ - kExprTry, kWasmStmt, - kExprCallFunction, jsfuncIndex, - kExprCatch, tagIndex, - kExprDrop, - kExprRethrow, 0x00, + kExprBlock, kWasmVoid, + kExprBlock, sig_ie_v, + kExprTryTable, kWasmVoid, 1, + kCatchRef, wasmTagIndex, 0, + kExprCallFunction, throwWasmTagExnIndex, + kExprEnd, + kExprBr, 1, + kExprEnd, + kExprThrowRef, kExprEnd ]) .exportFunc(); + // Call a JS function that throws an exception using a JS-defined tag, catches + // it with a 'catch_all_ref' instruction, and rethrows it. builder - .addFunction("catch_all_rethrow", kSig_v_v) + .addFunction("catch_all_ref_js_tag_throw_ref", kSig_v_v) .addBody([ - kExprTry, kWasmStmt, - kExprCallFunction, jsfuncIndex, - kExprCatchAll, - kExprRethrow, 0x00, + kExprBlock, kWasmVoid, + kExprBlock, kExnRefCode, + kExprTryTable, kWasmVoid, 1, + kCatchAllRef, 0, + kExprCallFunction, throwJSTagExnIndex, + kExprEnd, + kExprBr, 1, + kExprEnd, + kExprThrowRef, + kExprEnd + ]) + .exportFunc(); + + // Call a JS function that throws an exception using a Wasm-defined tag, + // catches it with a 'catch_all_ref' instruction, and rethrows it. + builder + .addFunction("catch_all_ref_wasm_tag_throw_ref", kSig_v_v) + .addBody([ + kExprBlock, kWasmVoid, + kExprBlock, kExnRefCode, + kExprTryTable, kWasmVoid, 1, + kCatchAllRef, 0, + kExprCallFunction, throwWasmTagExnIndex, + kExprEnd, + kExprBr, 1, + kExprEnd, + kExprThrowRef, + kExprEnd + ]) + .exportFunc(); + + // Call a JS function that throws an exception, catches it with a 'catch' + // instruction, and returns its i32 payload. + builder + .addFunction("catch_js_tag_return_payload", kSig_i_v) + .addBody([ + kExprBlock, kWasmVoid, + kExprBlock, kWasmI32, + kExprTryTable, kWasmVoid, 1, + kCatchNoRef, jsTagIndex, 0, + kExprCallFunction, throwJSTagExnIndex, + kExprEnd, + kExprBr, 1, + kExprEnd, + kExprReturn, + kExprEnd, + kExprI32Const, 0 + ]) + .exportFunc(); + + // Call a JS function that throws an exception, catches it with a 'catch' + // instruction, and throws a new exception using that payload. + builder + .addFunction("catch_js_tag_throw_payload", kSig_v_v) + .addBody([ + kExprBlock, kWasmVoid, + kExprBlock, kWasmI32, + kExprTryTable, kWasmVoid, 1, + kCatchNoRef, jsTagIndex, 0, + kExprCallFunction, throwJSTagExnIndex, + kExprEnd, + kExprBr, 1, + kExprEnd, + kExprThrow, jsTagIndex, kExprEnd ]) .exportFunc(); const buffer = builder.toBuffer(); + WebAssembly.instantiate(buffer, imports).then(result => { + // The exception object's identity should be preserved across 'rethrow's in + // Wasm code. Do tests with a tag defined in JS. + try { + result.instance.exports.catch_ref_js_tag_throw_ref(); + } catch (e) { + assert_equals(e, jsTagExn); + // Even if they have the same payload, they are different objects, so they + // shouldn't compare equal. + assert_not_equals(e, jsTagExnSamePayload); + assert_not_equals(e, jsTagExnDiffPayload); + } + try { + result.instance.exports.catch_all_ref_js_tag_throw_ref(); + } catch (e) { + assert_equals(e, jsTagExn); + assert_not_equals(e, jsTagExnSamePayload); + assert_not_equals(e, jsTagExnDiffPayload); + } + + // Do the same tests with a tag defined in Wasm. + const wasmTag = result.instance.exports.wasmTag; + wasmTagExn = new WebAssembly.Exception(wasmTag, [42]); + wasmTagExnSamePayload = new WebAssembly.Exception(wasmTag, [42]); + wasmTagExnDiffPayload = new WebAssembly.Exception(wasmTag, [53]); try { - result.instance.exports.catch_rethrow(); + result.instance.exports.catch_ref_wasm_tag_throw_ref(); } catch (e) { - assert_equals(e, exn); - assert_not_equals(e, exn_same_payload); - assert_not_equals(e, exn_diff_payload); + assert_equals(e, wasmTagExn); + assert_not_equals(e, wasmTagExnSamePayload); + assert_not_equals(e, wasmTagExnDiffPayload); } try { - result.instance.exports.catch_all_rethrow(); + result.instance.exports.catch_all_ref_wasm_tag_throw_ref(); + } catch (e) { + assert_equals(e, wasmTagExn); + assert_not_equals(e, wasmTagExnSamePayload); + assert_not_equals(e, wasmTagExnDiffPayload); + } + + // This function catches the exception and returns its i32 payload, which + // should match the original payload. + assert_equals(result.instance.exports.catch_js_tag_return_payload(), 42); + + // This function catches the exception and throws a new exception using the + // its payload. Even if the payload is reused, the exception objects should + // not compare equal. + try { + result.instance.exports.catch_js_tag_throw_payload(); } catch (e) { - assert_equals(e, exn); - assert_not_equals(e, exn_same_payload); - assert_not_equals(e, exn_diff_payload); + assert_equals(e.getArg(jsTag, 0), 42); + assert_not_equals(e, jsTagExn); } }); }, "Identity check"); diff --git a/test/js-api/exception/is.tentative.any.js b/test/js-api/exception/is.tentative.any.js index e28a88a3c..840d00bf0 100644 --- a/test/js-api/exception/is.tentative.any.js +++ b/test/js-api/exception/is.tentative.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/memory/assertions.js test(() => { diff --git a/test/js-api/exception/jsTag.tentative.any.js b/test/js-api/exception/jsTag.tentative.any.js new file mode 100644 index 000000000..c5db55370 --- /dev/null +++ b/test/js-api/exception/jsTag.tentative.any.js @@ -0,0 +1,121 @@ +// META: global=window,dedicatedworker,jsshell,shadowrealm +// META: script=/wasm/jsapi/assertions.js +// META: script=/wasm/jsapi/wasm-module-builder.js + +test(() => { + assert_throws_js(TypeError, () => new WebAssembly.Exception(WebAssembly.JSTag, [{}])) +}, "Creating a WebAssembly.Exception with JSTag explicitly is not allowed"); + +promise_test(async () => { + const builder = new WasmModuleBuilder(); + const jsTag = builder.addImportedTag("module", "JSTag", kSig_v_r); + + const throwRefFn = builder.addImport("module", "throw_ref", kSig_r_r); + const sig_r_v = builder.addType(kSig_r_v); + const kSig_re_v = makeSig([], [kExternRefCode, kExnRefCode]); + const sig_re_v = builder.addType(kSig_re_v); + + // Calls throw_ref, catches an exception with 'try_table - catch JSTag', and + // returns it + builder.addFunction("catch_js_tag_and_return", kSig_r_r) + .addBody([ + kExprBlock, sig_r_v, + kExprTryTable, sig_r_v, 1, + kCatchNoRef, jsTag, 0, + kExprLocalGet, 0, + kExprCallFunction, throwRefFn, + kExprEnd, + kExprEnd, + ]) + .exportFunc(); + + // Calls throw_ref, catches an exception with 'try_table - catch_ref JSTag', + // and returns it + builder.addFunction("catch_ref_js_tag_and_return", kSig_r_r) + .addBody([ + kExprBlock, sig_re_v, + kExprTryTable, sig_r_v, 1, + kCatchRef, jsTag, 0, + kExprLocalGet, 0, + kExprCallFunction, throwRefFn, + kExprEnd, + kExprReturn, + kExprEnd, + kExprDrop, + ]) + .exportFunc(); + + // Calls throw_ref, catches an exception with 'try_table - catch_ref JSTag', + // and rethrows it (with throw_ref) + builder.addFunction("catch_ref_js_tag_and_throw_ref", kSig_r_r) + .addBody([ + kExprBlock, sig_re_v, + kExprTryTable, sig_r_v, 1, + kCatchRef, jsTag, 0, + kExprLocalGet, 0, + kExprCallFunction, throwRefFn, + kExprEnd, + kExprReturn, + kExprEnd, + kExprThrowRef, + ]) + .exportFunc(); + + function throw_ref(x) { + throw x; + } + const buffer = builder.toBuffer(); + const {instance} = await WebAssembly.instantiate(buffer, { + module: { throw_ref, JSTag: WebAssembly.JSTag } + }); + + const obj = {}; + const wasmTag = new WebAssembly.Tag({parameters:['externref']}); + const exn = new WebAssembly.Exception(wasmTag, [obj]); + + // Test catch w/ return: + // This throws obj as a JS exception so it should be caught by the program and + // be returned as the original obj. + assert_equals(obj, instance.exports.catch_js_tag_and_return(obj)); + // This is a WebAssembly.Exception, so the exception should just pass through + // the program without being caught. + assert_throws_exactly(exn, () => instance.exports.catch_js_tag_and_return(exn)); + + // Test catch_ref w/ return: + // This throws obj as a JS exception so it should be caught by the program and + // be returned as the original obj. + assert_equals(obj, instance.exports.catch_ref_js_tag_and_return(obj)); + // This is a WebAssembly.Exception, so the exception should just pass through + // the program without being caught. + assert_throws_exactly(exn, () => instance.exports.catch_ref_js_tag_and_return(exn)); + + // Test catch_ref w/ throw_ref: + // This throws obj as a JS exception so it should be caught by the program and + // be rethrown. + assert_throws_exactly(obj, () => instance.exports.catch_ref_js_tag_and_throw_ref(obj)); + // This is a WebAssembly.Exception, so the exception should just pass through + // the program without being caught. + assert_throws_exactly(exn, () => instance.exports.catch_ref_js_tag_and_throw_ref(exn)); +}, "JS tag catching tests"); + +promise_test(async () => { + const builder = new WasmModuleBuilder(); + const jsTag = builder.addImportedTag("module", "JSTag", kSig_v_r); + + // Throw a JS object with WebAssembly.JSTag and check that we can catch it + // as-is from JavaScript. + builder.addFunction("throw_js_tag", kSig_v_r) + .addBody([ + kExprLocalGet, 0, + kExprThrow, jsTag, + ]) + .exportFunc(); + + const buffer = builder.toBuffer(); + const {instance} = await WebAssembly.instantiate(buffer, { + module: { JSTag: WebAssembly.JSTag } + }); + + const obj = {}; + assert_throws_exactly(obj, () => instance.exports.throw_js_tag(obj)); +}, "JS tag throwing test"); diff --git a/test/js-api/exception/toString.tentative.any.js b/test/js-api/exception/toString.tentative.any.js index 00e801a6f..6885cf0de 100644 --- a/test/js-api/exception/toString.tentative.any.js +++ b/test/js-api/exception/toString.tentative.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm test(() => { const argument = { parameters: [] }; diff --git a/test/js-api/instanceTestFactory.js b/test/js-api/instanceTestFactory.js index ac468947e..7936810a5 100644 --- a/test/js-api/instanceTestFactory.js +++ b/test/js-api/instanceTestFactory.js @@ -237,7 +237,7 @@ const instanceTestFactory = [ builder.addGlobal(kWasmI32, true) .exportAs("") - .init = 7; + .init = wasmI32Const(7); const buffer = builder.toBuffer(); @@ -273,10 +273,10 @@ const instanceTestFactory = [ builder.addGlobal(kWasmI32, true) .exportAs("global") - .init = 7; + .init = wasmI32Const(7); builder.addGlobal(kWasmF64, true) .exportAs("global2") - .init = 1.2; + .init = wasmF64Const(1.2); builder.addMemory(4, 8, true); diff --git a/test/js-api/limits.any.js b/test/js-api/limits.any.js index 7e690cad9..d913c6c7a 100644 --- a/test/js-api/limits.any.js +++ b/test/js-api/limits.any.js @@ -244,3 +244,62 @@ test(() => { () => memory.grow(kJSEmbeddingMaxTableSize)); }, `Grow WebAssembly.Table object beyond the embedder-defined limit`); +function testModuleSizeLimit(size, expectPass) { + // We do not use `testLimit` here to avoid OOMs due to having multiple big + // modules alive at the same time. + + // Define a WebAssembly module that consists of a single custom section which + // has an empty name. The module size will be `size`. + let buffer; + try { + buffer = new Uint8Array(size); + } catch (e) { + if (e instanceof RangeError) { + // Allocation of a big TypedArray may fail. + return; + } + throw e; + } + const header = [ + kWasmH0, kWasmH1, kWasmH2, kWasmH3, // magic word + kWasmV0, kWasmV1, kWasmV2, kWasmV3, // version + 0 // custom section + ]; + // We calculate the section length so that the total module size is `size`. + // For that we have to calculate the length of the leb encoding of the section + // length. + const sectionLength = size - header.length - + wasmSignedLeb(size).length; + const lengthBytes = wasmSignedLeb(sectionLength); + buffer.set(header); + buffer.set(lengthBytes, header.length); + + if (expectPass) { + test(() => { + assert_true(WebAssembly.validate(buffer)); + }, `Validate module size limit`); + test(() => { + new WebAssembly.Module(buffer); + }, `Compile module size limit`); + promise_test(t => { + return WebAssembly.compile(buffer); + }, `Async compile module size limit`); + } else { + test(() => { + assert_false(WebAssembly.validate(buffer)); + }, `Validate module size over limit`); + test(() => { + assert_throws( + new WebAssembly.CompileError(), + () => new WebAssembly.Module(buffer)); + }, `Compile module size over limit`); + promise_test(t => { + return promise_rejects( + t, new WebAssembly.CompileError(), + WebAssembly.compile(buffer)); + }, `Async compile module size over limit`); + } +} + +testModuleSizeLimit(kJSEmbeddingMaxModuleSize, true); +testModuleSizeLimit(kJSEmbeddingMaxModuleSize + 1, false); diff --git a/test/js-api/module/exports.any.js b/test/js-api/module/exports.any.js index 40a3935a4..0d62725ae 100644 --- a/test/js-api/module/exports.any.js +++ b/test/js-api/module/exports.any.js @@ -109,10 +109,10 @@ test(() => { builder.addGlobal(kWasmI32, true) .exportAs("global") - .init = 7; + .init = wasmI32Const(7); builder.addGlobal(kWasmF64, true) .exportAs("global2") - .init = 1.2; + .init = wasmF64Const(1.2); builder.addMemory(0, 256, true); @@ -167,7 +167,7 @@ test(() => { builder.addGlobal(kWasmI32, true) .exportAs("") - .init = 7; + .init = wasmI32Const(7); const buffer = builder.toBuffer() const module = new WebAssembly.Module(buffer); diff --git a/test/js-api/tag/constructor.tentative.any.js b/test/js-api/tag/constructor.tentative.any.js index de63e7bf4..54edf8c8f 100644 --- a/test/js-api/tag/constructor.tentative.any.js +++ b/test/js-api/tag/constructor.tentative.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/assertions.js test(() => { diff --git a/test/js-api/tag/toString.tentative.any.js b/test/js-api/tag/toString.tentative.any.js index ad9a4ba15..76fff0fee 100644 --- a/test/js-api/tag/toString.tentative.any.js +++ b/test/js-api/tag/toString.tentative.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm test(() => { const argument = { parameters: [] }; diff --git a/test/js-api/tag/type.tentative.any.js b/test/js-api/tag/type.tentative.any.js deleted file mode 100644 index 9d2f0de1a..000000000 --- a/test/js-api/tag/type.tentative.any.js +++ /dev/null @@ -1,21 +0,0 @@ -// META: global=window,dedicatedworker,jsshell -// META: script=/wasm/jsapi/assertions.js - -function assert_type(argument) { - const tag = new WebAssembly.Tag(argument); - const tagtype = tag.type(); - - assert_array_equals(tagtype.parameters, argument.parameters); -} - -test(() => { - assert_type({ parameters: [] }); -}, "[]"); - -test(() => { - assert_type({ parameters: ["i32", "i64"] }); -}, "[i32 i64]"); - -test(() => { - assert_type({ parameters: ["i32", "i64", "f32", "f64"] }); -}, "[i32 i64 f32 f64]"); diff --git a/test/js-api/wasm-module-builder.js b/test/js-api/wasm-module-builder.js index 86d836a5a..1f6c91900 100644 --- a/test/js-api/wasm-module-builder.js +++ b/test/js-api/wasm-module-builder.js @@ -90,15 +90,46 @@ let kDeclFunctionImport = 0x02; let kDeclFunctionLocals = 0x04; let kDeclFunctionExport = 0x08; -// Local types -let kWasmStmt = 0x40; +// Value types and related +let kWasmVoid = 0x40; let kWasmI32 = 0x7f; let kWasmI64 = 0x7e; let kWasmF32 = 0x7d; let kWasmF64 = 0x7c; let kWasmS128 = 0x7b; -let kWasmAnyRef = 0x6f; -let kWasmAnyFunc = 0x70; + +// These are defined as negative integers to distinguish them from positive type +// indices. +let kWasmNullFuncRef = -0x0d; +let kWasmNullExternRef = -0x0e; +let kWasmNullRef = -0x0f; +let kWasmFuncRef = -0x10; +let kWasmAnyFunc = kWasmFuncRef; // Alias named as in the JS API spec +let kWasmExternRef = -0x11; +let kWasmAnyRef = -0x12; +let kWasmExnRef = -0x17; +let kWasmNullExnRef = -0x0c; + +// Use the positive-byte versions inside function bodies. +let kLeb128Mask = 0x7f; +let kFuncRefCode = kWasmFuncRef & kLeb128Mask; +let kAnyFuncCode = kFuncRefCode; // Alias named as in the JS API spec +let kExternRefCode = kWasmExternRef & kLeb128Mask; +let kAnyRefCode = kWasmAnyRef & kLeb128Mask; +let kNullExternRefCode = kWasmNullExternRef & kLeb128Mask; +let kNullFuncRefCode = kWasmNullFuncRef & kLeb128Mask; +let kExnRefCode = kWasmExnRef & kLeb128Mask; +let kNullExnRefCode = kWasmNullExnRef & kLeb128Mask; +let kNullRefCode = kWasmNullRef & kLeb128Mask; + +let kWasmRefNull = 0x63; +let kWasmRef = 0x64; +function wasmRefNullType(heap_type, is_shared = false) { + return {opcode: kWasmRefNull, heap_type: heap_type, is_shared: is_shared}; +} +function wasmRefType(heap_type, is_shared = false) { + return {opcode: kWasmRef, heap_type: heap_type, is_shared: is_shared}; +} let kExternalFunction = 0; let kExternalTable = 1; @@ -110,7 +141,7 @@ let kTableZero = 0; let kMemoryZero = 0; let kSegmentZero = 0; -let kTagAttribute = 0; +let kExceptionAttribute = 0; // Useful signatures let kSig_i_i = makeSig([kWasmI32], [kWasmI32]); @@ -146,14 +177,14 @@ let kSig_v_f = makeSig([kWasmF32], []); let kSig_f_f = makeSig([kWasmF32], [kWasmF32]); let kSig_f_d = makeSig([kWasmF64], [kWasmF32]); let kSig_d_d = makeSig([kWasmF64], [kWasmF64]); -let kSig_r_r = makeSig([kWasmAnyRef], [kWasmAnyRef]); +let kSig_r_r = makeSig([kWasmExternRef], [kWasmExternRef]); let kSig_a_a = makeSig([kWasmAnyFunc], [kWasmAnyFunc]); -let kSig_i_r = makeSig([kWasmAnyRef], [kWasmI32]); -let kSig_v_r = makeSig([kWasmAnyRef], []); +let kSig_i_r = makeSig([kWasmExternRef], [kWasmI32]); +let kSig_v_r = makeSig([kWasmExternRef], []); let kSig_v_a = makeSig([kWasmAnyFunc], []); -let kSig_v_rr = makeSig([kWasmAnyRef, kWasmAnyRef], []); +let kSig_v_rr = makeSig([kWasmExternRef, kWasmExternRef], []); let kSig_v_aa = makeSig([kWasmAnyFunc, kWasmAnyFunc], []); -let kSig_r_v = makeSig([], [kWasmAnyRef]); +let kSig_r_v = makeSig([], [kWasmExternRef]); let kSig_a_v = makeSig([], [kWasmAnyFunc]); let kSig_a_i = makeSig([kWasmI32], [kWasmAnyFunc]); @@ -190,10 +221,9 @@ let kExprIf = 0x04; let kExprElse = 0x05; let kExprTry = 0x06; let kExprCatch = 0x07; -let kExprCatchAll = 0x19; let kExprThrow = 0x08; let kExprRethrow = 0x09; -let kExprBrOnExn = 0x0a; +let kExprThrowRef = 0x0a; let kExprEnd = 0x0b; let kExprBr = 0x0c; let kExprBrIf = 0x0d; @@ -203,8 +233,10 @@ let kExprCallFunction = 0x10; let kExprCallIndirect = 0x11; let kExprReturnCall = 0x12; let kExprReturnCallIndirect = 0x13; +let kExprCatchAll = 0x19; let kExprDrop = 0x1a; let kExprSelect = 0x1b; +let kExprTryTable = 0x1f; let kExprLocalGet = 0x20; let kExprLocalSet = 0x21; let kExprLocalTee = 0x22; @@ -467,6 +499,12 @@ let kExprI32x4Eq = 0x2c; let kExprS1x4AllTrue = 0x75; let kExprF32x4Min = 0x9e; +// Exception handling with exnref. +let kCatchNoRef = 0x0; +let kCatchRef = 0x1; +let kCatchAllNoRef = 0x2; +let kCatchAllRef = 0x3; + class Binary { constructor() { this.length = 0; @@ -554,6 +592,16 @@ class Binary { } } + emit_type(type) { + if ((typeof type) == 'number') { + this.emit_u8(type >= 0 ? type : type & kLeb128Mask); + } else { + this.emit_u8(type.opcode); + if ('depth' in type) this.emit_u8(type.depth); + this.emit_heap_type(type.heap_type); + } + } + emit_header() { this.emit_bytes([ kWasmH0, kWasmH1, kWasmH2, kWasmH3, kWasmV0, kWasmV1, kWasmV2, kWasmV3 @@ -754,9 +802,9 @@ class WasmModuleBuilder { addTag(type) { let type_index = (typeof type) == "number" ? type : this.addType(type); - let except_index = this.tags.length + this.num_imported_tags; + let tag_index = this.tags.length + this.num_imported_tags; this.tags.push(type_index); - return except_index; + return tag_index; } addFunction(name, type) { @@ -898,11 +946,11 @@ class WasmModuleBuilder { section.emit_u8(kWasmFunctionTypeForm); section.emit_u32v(type.params.length); for (let param of type.params) { - section.emit_u8(param); + section.emit_type(param); } section.emit_u32v(type.results.length); for (let result of type.results) { - section.emit_u8(result); + section.emit_type(result); } } }); @@ -933,13 +981,13 @@ class WasmModuleBuilder { section.emit_u32v(imp.initial); // initial if (has_max) section.emit_u32v(imp.maximum); // maximum } else if (imp.kind == kExternalTable) { - section.emit_u8(imp.type); + section.emit_type(imp.type); var has_max = (typeof imp.maximum) != "undefined"; section.emit_u8(has_max ? 1 : 0); // flags section.emit_u32v(imp.initial); // initial if (has_max) section.emit_u32v(imp.maximum); // maximum } else if (imp.kind == kExternalTag) { - section.emit_u32v(kTagAttribute); + section.emit_u32v(kExceptionAttribute); section.emit_u32v(imp.type); } else { throw new Error("unknown/unsupported import kind " + imp.kind); @@ -965,7 +1013,7 @@ class WasmModuleBuilder { binary.emit_section(kTableSectionCode, section => { section.emit_u32v(wasm.tables.length); for (let table of wasm.tables) { - section.emit_u8(table.type); + section.emit_type(table.type); section.emit_u8(table.has_max); section.emit_u32v(table.initial_size); if (table.has_max) section.emit_u32v(table.max_size); @@ -997,7 +1045,7 @@ class WasmModuleBuilder { binary.emit_section(kGlobalSectionCode, section => { section.emit_u32v(wasm.globals.length); for (let global of wasm.globals) { - section.emit_u8(global.type); + section.emit_type(global.type); section.emit_u8(global.mutable); if ((typeof global.init_index) == "undefined") { // Emit a constant initializer. @@ -1042,7 +1090,7 @@ class WasmModuleBuilder { binary.emit_section(kTagSectionCode, section => { section.emit_u32v(wasm.tags.length); for (let type of wasm.tags) { - section.emit_u32v(kTagAttribute); + section.emit_u32v(kExceptionAttribute); section.emit_u32v(type); } }); @@ -1161,7 +1209,7 @@ class WasmModuleBuilder { local_decls.push({count: l.s128_count, type: kWasmS128}); } if (l.anyref_count > 0) { - local_decls.push({count: l.anyref_count, type: kWasmAnyRef}); + local_decls.push({count: l.anyref_count, type: kWasmExternRef}); } if (l.anyfunc_count > 0) { local_decls.push({count: l.anyfunc_count, type: kWasmAnyFunc}); @@ -1171,7 +1219,7 @@ class WasmModuleBuilder { header.emit_u32v(local_decls.length); for (let decl of local_decls) { header.emit_u32v(decl.count); - header.emit_u8(decl.type); + header.emit_type(decl.type); } section.emit_u32v(header.length + func.body.length); diff --git a/test/core/rethrow.wast b/test/legacy/exceptions/core/rethrow.wast similarity index 100% rename from test/core/rethrow.wast rename to test/legacy/exceptions/core/rethrow.wast diff --git a/test/legacy/exceptions/core/run.py b/test/legacy/exceptions/core/run.py new file mode 100755 index 000000000..b2f6c314b --- /dev/null +++ b/test/legacy/exceptions/core/run.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python3 + +from __future__ import print_function +import argparse +import os +import os.path +import unittest +import subprocess +import glob +import sys + + +ownDir = os.path.dirname(os.path.abspath(sys.argv[0])) +inputDir = ownDir +outputDir = os.path.join(inputDir, "_output") + +parser = argparse.ArgumentParser() +parser.add_argument("--wasm", metavar="", default=os.path.join(os.getcwd(), "wasm")) +parser.add_argument("--js", metavar="") +parser.add_argument("--generate-js-only", action='store_true') +parser.add_argument("--out", metavar="", default=outputDir) +parser.add_argument("file", nargs='*') +arguments = parser.parse_args() +sys.argv = sys.argv[:1] + +exceptions_test_files = glob.glob(os.path.join(inputDir, "*.wast")) + +wasmCommand = arguments.wasm +jsCommand = arguments.js +generateJsOnly = arguments.generate_js_only +outputDir = arguments.out +inputFiles = arguments.file if arguments.file else exceptions_test_files + +if not os.path.exists(wasmCommand): + sys.stderr.write("""\ +Error: The executable '%s' does not exist. +Provide the correct path with the '--wasm' flag. + +""" % (wasmCommand)) + parser.print_help() + sys.exit(1) + + +class RunTests(unittest.TestCase): + def _runCommand(self, command, logPath, expectedExitCode = 0): + with open(logPath, 'w+') as out: + exitCode = subprocess.call(command, shell=True, stdout=out, stderr=subprocess.STDOUT) + self.assertEqual(expectedExitCode, exitCode, "failed with exit code %i (expected %i) for %s" % (exitCode, expectedExitCode, command)) + + def _auxFile(self, path): + if os.path.exists(path): + os.remove(path) + return path + + def _compareFile(self, expectFile, actualFile): + if os.path.exists(expectFile): + with open(expectFile) as expect: + with open(actualFile) as actual: + expectText = expect.read() + actualText = actual.read() + self.assertEqual(expectText, actualText) + + def _runTestFile(self, inputPath): + dir, inputFile = os.path.split(inputPath) + outputPath = os.path.join(outputDir, inputFile) + + # Generate JS first, then return early if we are only generating JS. + jsPath = self._auxFile(outputPath.replace(".wast", ".js")) + logPath = self._auxFile(jsPath + ".log") + self._runCommand(('%s -d "%s" -o "%s"') % (wasmCommand, inputPath, jsPath), logPath) + + if generateJsOnly: + return + + # Run original file + expectedExitCode = 1 if ".fail." in inputFile else 0 + logPath = self._auxFile(outputPath + ".log") + self._runCommand(('%s "%s"') % (wasmCommand, inputPath), logPath, expectedExitCode) + + if expectedExitCode != 0: + return + + # Convert to binary and run again + wasmPath = self._auxFile(outputPath + ".bin.wast") + logPath = self._auxFile(wasmPath + ".log") + self._runCommand(('%s -d "%s" -o "%s"') % (wasmCommand, inputPath, wasmPath), logPath) + self._runCommand(('%s "%s"') % (wasmCommand, wasmPath), logPath) + + # Convert back to text and run again + wastPath = self._auxFile(wasmPath + ".wast") + logPath = self._auxFile(wastPath + ".log") + self._runCommand(('%s -d "%s" -o "%s"') % (wasmCommand, wasmPath, wastPath), logPath) + self._runCommand(('%s "%s"') % (wasmCommand, wastPath), logPath) + + # Convert back to binary once more and compare + wasm2Path = self._auxFile(wastPath + ".bin.wast") + logPath = self._auxFile(wasm2Path + ".log") + self._runCommand(('%s -d "%s" -o "%s"') % (wasmCommand, wastPath, wasm2Path), logPath) + self._compareFile(wasmPath, wasm2Path) + + # Convert back to text once more and compare + wast2Path = self._auxFile(wasm2Path + ".wast") + logPath = self._auxFile(wast2Path + ".log") + self._runCommand(('%s -d "%s" -o "%s"') % (wasmCommand, wasm2Path, wast2Path), logPath) + self._compareFile(wastPath, wast2Path) + + if jsCommand != None: + self._runCommand(('%s "%s"') % (jsCommand, jsPath), logPath) + + +if __name__ == "__main__": + if not os.path.exists(outputDir): + os.makedirs(outputDir) + for fileName in inputFiles: + testName = 'test ' + os.path.basename(fileName) + setattr(RunTests, testName, lambda self, file=fileName: self._runTestFile(file)) + unittest.main() diff --git a/test/legacy/exceptions/core/throw.wast b/test/legacy/exceptions/core/throw.wast new file mode 100644 index 000000000..d53b5b550 --- /dev/null +++ b/test/legacy/exceptions/core/throw.wast @@ -0,0 +1,51 @@ +;; Test throw instruction. + +(module + (tag $e0) + (tag $e-i32 (param i32)) + (tag $e-f32 (param f32)) + (tag $e-i64 (param i64)) + (tag $e-f64 (param f64)) + (tag $e-i32-i32 (param i32 i32)) + + (func $throw-if (export "throw-if") (param i32) (result i32) + (local.get 0) + (i32.const 0) (if (i32.ne) (then (throw $e0))) + (i32.const 0) + ) + + (func (export "throw-param-f32") (param f32) (local.get 0) (throw $e-f32)) + + (func (export "throw-param-i64") (param i64) (local.get 0) (throw $e-i64)) + + (func (export "throw-param-f64") (param f64) (local.get 0) (throw $e-f64)) + + (func $throw-1-2 (i32.const 1) (i32.const 2) (throw $e-i32-i32)) + (func (export "test-throw-1-2") + (try + (do (call $throw-1-2)) + (catch $e-i32-i32 + (i32.const 2) + (if (i32.ne) (then (unreachable))) + (i32.const 1) + (if (i32.ne) (then (unreachable))) + ) + ) + ) +) + +(assert_return (invoke "throw-if" (i32.const 0)) (i32.const 0)) +(assert_exception (invoke "throw-if" (i32.const 10))) +(assert_exception (invoke "throw-if" (i32.const -1))) + +(assert_exception (invoke "throw-param-f32" (f32.const 5.0))) +(assert_exception (invoke "throw-param-i64" (i64.const 5))) +(assert_exception (invoke "throw-param-f64" (f64.const 5.0))) + +(assert_return (invoke "test-throw-1-2")) + +(assert_invalid (module (func (throw 0))) "unknown tag 0") +(assert_invalid (module (tag (param i32)) (func (throw 0))) + "type mismatch: instruction requires [i32] but stack has []") +(assert_invalid (module (tag (param i32)) (func (i64.const 5) (throw 0))) + "type mismatch: instruction requires [i32] but stack has [i64]") diff --git a/test/core/try_catch.wast b/test/legacy/exceptions/core/try_catch.wast similarity index 90% rename from test/core/try_catch.wast rename to test/legacy/exceptions/core/try_catch.wast index 6564e201b..07399f3a5 100644 --- a/test/core/try_catch.wast +++ b/test/legacy/exceptions/core/try_catch.wast @@ -147,6 +147,34 @@ (catch $e0 (i32.const 1)) ) ) + + (func $throw-void (throw $e0)) + (func (export "return-call-in-try-catch") + (try + (do + (return_call $throw-void) + ) + (catch $e0) + ) + ) + + (table funcref (elem $throw-void)) + (func (export "return-call-indirect-in-try-catch") + (try + (do + (return_call_indirect (param) (i32.const 0)) + ) + (catch $e0) + ) + ) + + (func (export "break-try-catch") + (try (do (br 0)) (catch $e0)) + ) + + (func (export "break-try-catch_all") + (try (do (br 0)) (catch_all)) + ) ) (assert_return (invoke "empty-catch")) @@ -188,6 +216,12 @@ (assert_return (invoke "catchless-try" (i32.const 0)) (i32.const 0)) (assert_return (invoke "catchless-try" (i32.const 1)) (i32.const 1)) +(assert_exception (invoke "return-call-in-try-catch")) +(assert_exception (invoke "return-call-indirect-in-try-catch")) + +(assert_return (invoke "break-try-catch")) +(assert_return (invoke "break-try-catch_all")) + (module (func $imported-throw (import "test" "throw")) (tag $e0) diff --git a/test/core/try_delegate.wast b/test/legacy/exceptions/core/try_delegate.wast similarity index 72% rename from test/core/try_delegate.wast rename to test/legacy/exceptions/core/try_delegate.wast index 8ee864eba..39ee09a2b 100644 --- a/test/core/try_delegate.wast +++ b/test/legacy/exceptions/core/try_delegate.wast @@ -115,6 +115,76 @@ (delegate $l3)))) unreachable) (catch_all (i32.const 1)))) + + (func $throw-void (throw $e0)) + (func (export "return-call-in-try-delegate") + (try $l + (do + (try + (do + (return_call $throw-void) + ) + (delegate $l) + ) + ) + (catch $e0) + ) + ) + + (table funcref (elem $throw-void)) + (func (export "return-call-indirect-in-try-delegate") + (try $l + (do + (try + (do + (return_call_indirect (param) (i32.const 0)) + ) + (delegate $l) + ) + ) + (catch $e0) + ) + ) + + (func (export "break-try-delegate") + (try (do (br 0)) (delegate 0)) + ) + + (func (export "break-and-call-throw") (result i32) + (try $outer (result i32) + (do + (try (result i32) + (do + (block $a + (try (do (br $a)) (delegate $outer)) + ) + (call $throw-void) + (i32.const 0) + ) + (catch $e0 (i32.const 1)) + ) + ) + (catch $e0 (i32.const 2)) + ) + ) + + (func (export "break-and-throw") (result i32) + (try $outer (result i32) + (do + (try (result i32) + (do + (block $a + (try (do (br $a)) (delegate $outer)) + ) + (throw $e0) + (i32.const 0) + ) + (catch $e0 (i32.const 1)) + ) + ) + (catch $e0 (i32.const 2)) + ) + ) ) (assert_return (invoke "delegate-no-throw") (i32.const 1)) @@ -140,6 +210,14 @@ (assert_return (invoke "delegate-correct-targets") (i32.const 1)) +(assert_exception (invoke "return-call-in-try-delegate")) +(assert_exception (invoke "return-call-indirect-in-try-delegate")) + +(assert_return (invoke "break-try-delegate")) + +(assert_return (invoke "break-and-call-throw") (i32.const 1)) +(assert_return (invoke "break-and-throw") (i32.const 1)) + (assert_malformed (module quote "(module (func (delegate 0)))") "unexpected token" diff --git a/test/legacy/exceptions/js-api/basic.tentative.any.js b/test/legacy/exceptions/js-api/basic.tentative.any.js new file mode 100644 index 000000000..81478529a --- /dev/null +++ b/test/legacy/exceptions/js-api/basic.tentative.any.js @@ -0,0 +1,120 @@ +// META: global=window,dedicatedworker,jsshell,shadowrealm +// META: script=/wasm/jsapi/wasm-module-builder.js + +function assert_throws_wasm(fn, message) { + try { + fn(); + assert_not_reached(`expected to throw with ${message}`); + } catch (e) { + assert_true(e instanceof WebAssembly.Exception, `Error should be a WebAssembly.Exception with ${message}`); + } +} + +promise_test(async () => { + const kSig_v_r = makeSig([kWasmExternRef], []); + const builder = new WasmModuleBuilder(); + const tagIndex = builder.addTag(kSig_v_r); + builder.addFunction("throw_param", kSig_v_r) + .addBody([ + kExprLocalGet, 0, + kExprThrow, tagIndex, + ]) + .exportFunc(); + const buffer = builder.toBuffer(); + const {instance} = await WebAssembly.instantiate(buffer, {}); + const values = [ + undefined, + null, + true, + false, + "test", + Symbol(), + 0, + 1, + 4.2, + NaN, + Infinity, + {}, + () => {}, + ]; + for (const v of values) { + assert_throws_wasm(() => instance.exports.throw_param(v), String(v)); + } +}, "Wasm function throws argument"); + +promise_test(async () => { + const builder = new WasmModuleBuilder(); + const tagIndex = builder.addTag(kSig_v_a); + builder.addFunction("throw_null", kSig_v_v) + .addBody([ + kExprRefNull, kAnyFuncCode, + kExprThrow, tagIndex, + ]) + .exportFunc(); + const buffer = builder.toBuffer(); + const {instance} = await WebAssembly.instantiate(buffer, {}); + assert_throws_wasm(() => instance.exports.throw_null()); +}, "Wasm function throws null"); + +promise_test(async () => { + const builder = new WasmModuleBuilder(); + const tagIndex = builder.addTag(kSig_v_i); + builder.addFunction("throw_int", kSig_v_v) + .addBody([ + ...wasmI32Const(7), + kExprThrow, tagIndex, + ]) + .exportFunc(); + const buffer = builder.toBuffer(); + const {instance} = await WebAssembly.instantiate(buffer, {}); + assert_throws_wasm(() => instance.exports.throw_int()); +}, "Wasm function throws integer"); + +promise_test(async () => { + const builder = new WasmModuleBuilder(); + const fnIndex = builder.addImport("module", "fn", kSig_v_v); + const tagIndex = builder.addTag(kSig_v_r); + builder.addFunction("catch_exception", kSig_r_v) + .addBody([ + kExprTry, kWasmVoid, + kExprCallFunction, fnIndex, + kExprCatch, tagIndex, + kExprReturn, + kExprEnd, + kExprRefNull, kExternRefCode, + ]) + .exportFunc(); + + const buffer = builder.toBuffer(); + + const error = new Error(); + const fn = () => { throw error }; + const {instance} = await WebAssembly.instantiate(buffer, { + module: { fn } + }); + assert_throws_exactly(error, () => instance.exports.catch_exception()); +}, "Imported JS function throws"); + +promise_test(async () => { + const builder = new WasmModuleBuilder(); + const fnIndex = builder.addImport("module", "fn", kSig_v_v); + builder.addFunction("catch_and_rethrow", kSig_r_v) + .addBody([ + kExprTry, kWasmVoid, + kExprCallFunction, fnIndex, + kExprCatchAll, + kExprRethrow, 0x00, + kExprEnd, + kExprRefNull, kExternRefCode, + ]) + .exportFunc(); + + const buffer = builder.toBuffer(); + + const error = new Error(); + const fn = () => { throw error }; + const {instance} = await WebAssembly.instantiate(buffer, { + module: { fn } + }); + assert_throws_exactly(error, () => instance.exports.catch_and_rethrow()); +}, "Imported JS function throws, Wasm catches and rethrows"); diff --git a/test/legacy/exceptions/js-api/identity.tentative.any.js b/test/legacy/exceptions/js-api/identity.tentative.any.js new file mode 100644 index 000000000..36651c7d5 --- /dev/null +++ b/test/legacy/exceptions/js-api/identity.tentative.any.js @@ -0,0 +1,170 @@ +// META: global=window,dedicatedworker,jsshell,shadowrealm +// META: script=/wasm/jsapi/assertions.js +// META: script=/wasm/jsapi/wasm-module-builder.js + +test(() => { + const builder = new WasmModuleBuilder(); + + // Tag defined in JavaScript and imported into Wasm + const jsTag = new WebAssembly.Tag({ parameters: ["i32"] }); + const jsTagIndex = builder.addImportedTag("module", "jsTag", kSig_v_i); + const jsTagExn = new WebAssembly.Exception(jsTag, [42]); + const jsTagExnSamePayload = new WebAssembly.Exception(jsTag, [42]); + const jsTagExnDiffPayload = new WebAssembly.Exception(jsTag, [53]); + const throwJSTagExnIndex = builder.addImport("module", "throwJSTagExn", kSig_v_v); + + // Tag defined in Wasm and exported to JS + const wasmTagIndex = builder.addTag(kSig_v_i); + builder.addExportOfKind("wasmTag", kExternalTag, wasmTagIndex); + const throwWasmTagExnIndex = builder.addImport("module", "throwWasmTagExn", kSig_v_v); + // Will be assigned after an instance is created + let wasmTagExn = null; + let wasmTagExnSamePayload = null; + let wasmTagExnDiffPayload = null; + + const imports = { + module: { + throwJSTagExn: function() { throw jsTagExn; }, + throwWasmTagExn: function() { throw wasmTagExn; }, + jsTag: jsTag + } + }; + + // Call a JS function that throws an exception using a JS-defined tag, catches + // it with a 'catch' instruction, and rethrows it. + builder + .addFunction("catch_js_tag_rethrow", kSig_v_v) + .addBody([ + kExprTry, kWasmVoid, + kExprCallFunction, throwJSTagExnIndex, + kExprCatch, jsTagIndex, + kExprDrop, + kExprRethrow, 0x00, + kExprEnd + ]) + .exportFunc(); + + // Call a JS function that throws an exception using a Wasm-defined tag, + // catches it with a 'catch' instruction, and rethrows it. + builder + .addFunction("catch_wasm_tag_rethrow", kSig_v_v) + .addBody([ + kExprTry, kWasmVoid, + kExprCallFunction, throwWasmTagExnIndex, + kExprCatch, wasmTagIndex, + kExprDrop, + kExprRethrow, 0x00, + kExprEnd + ]) + .exportFunc(); + + // Call a JS function that throws an exception using a JS-defined tag, catches + // it with a 'catch_all' instruction, and rethrows it. + builder + .addFunction("catch_all_js_tag_rethrow", kSig_v_v) + .addBody([ + kExprTry, kWasmVoid, + kExprCallFunction, throwJSTagExnIndex, + kExprCatchAll, + kExprRethrow, 0x00, + kExprEnd + ]) + .exportFunc(); + + // Call a JS function that throws an exception using a Wasm-defined tag, + // catches it with a 'catch_all' instruction, and rethrows it. + builder + .addFunction("catch_all_wasm_tag_rethrow", kSig_v_v) + .addBody([ + kExprTry, kWasmVoid, + kExprCallFunction, throwWasmTagExnIndex, + kExprCatchAll, + kExprRethrow, 0x00, + kExprEnd + ]) + .exportFunc(); + + // Call a JS function that throws an exception, catches it with a 'catch' + // instruction, and returns its i32 payload. + builder + .addFunction("catch_js_tag_return_payload", kSig_i_v) + .addBody([ + kExprTry, kWasmI32, + kExprCallFunction, throwJSTagExnIndex, + kExprI32Const, 0x00, + kExprCatch, jsTagIndex, + kExprReturn, + kExprEnd + ]) + .exportFunc(); + + // Call a JS function that throws an exception, catches it with a 'catch' + // instruction, and throws a new exception using that payload. + builder + .addFunction("catch_js_tag_throw_payload", kSig_v_v) + .addBody([ + kExprTry, kWasmVoid, + kExprCallFunction, throwJSTagExnIndex, + kExprCatch, jsTagIndex, + kExprThrow, jsTagIndex, + kExprEnd + ]) + .exportFunc(); + + const buffer = builder.toBuffer(); + + WebAssembly.instantiate(buffer, imports).then(result => { + // The exception object's identity should be preserved across 'rethrow's in + // Wasm code. Do tests with a tag defined in JS. + try { + result.instance.exports.catch_js_tag_rethrow(); + } catch (e) { + assert_equals(e, jsTagExn); + // Even if they have the same payload, they are different objects, so they + // shouldn't compare equal. + assert_not_equals(e, jsTagExnSamePayload); + assert_not_equals(e, jsTagExnDiffPayload); + } + try { + result.instance.exports.catch_all_js_tag_rethrow(); + } catch (e) { + assert_equals(e, jsTagExn); + assert_not_equals(e, jsTagExnSamePayload); + assert_not_equals(e, jsTagExnDiffPayload); + } + + // Do the same tests with a tag defined in Wasm. + const wasmTag = result.instance.exports.wasmTag; + wasmTagExn = new WebAssembly.Exception(wasmTag, [42]); + wasmTagExnSamePayload = new WebAssembly.Exception(wasmTag, [42]); + wasmTagExnDiffPayload = new WebAssembly.Exception(wasmTag, [53]); + try { + result.instance.exports.catch_wasm_tag_rethrow(); + } catch (e) { + assert_equals(e, wasmTagExn); + assert_not_equals(e, wasmTagExnSamePayload); + assert_not_equals(e, wasmTagExnDiffPayload); + } + try { + result.instance.exports.catch_all_wasm_tag_rethrow(); + } catch (e) { + assert_equals(e, wasmTagExn); + assert_not_equals(e, wasmTagExnSamePayload); + assert_not_equals(e, wasmTagExnDiffPayload); + } + + // This function catches the exception and returns its i32 payload, which + // should match the original payload. + assert_equals(result.instance.exports.catch_js_tag_return_payload(), 42); + + // This function catches the exception and throws a new exception using the + // its payload. Even if the payload is reused, the exception objects should + // not compare equal. + try { + result.instance.exports.catch_js_tag_throw_payload(); + } catch (e) { + assert_equals(e.getArg(jsTag, 0), 42); + assert_not_equals(e, jsTagExn); + } + }); +}, "Identity check");