From 12e9ce82971e96d0d7aaaa3df96cf56542524736 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Sat, 14 Oct 2023 17:45:50 +0200 Subject: [PATCH 1/2] [legacy] Create specification doc for legacy exception handling --- document/Makefile | 2 +- document/index.html | 17 +- document/legacy/exceptions/.gitignore | 3 + document/legacy/exceptions/LICENSE | 50 + document/legacy/exceptions/Makefile | 358 +++++ document/legacy/exceptions/README.md | 25 + .../exceptions/appendix/index-instructions.py | 116 ++ document/legacy/exceptions/binary.rst | 31 + document/legacy/exceptions/conf.py | 498 ++++++ document/legacy/exceptions/exec.rst | 351 +++++ document/legacy/exceptions/index.rst | 22 + document/legacy/exceptions/intro.rst | 8 + document/legacy/exceptions/static/custom.css | 78 + .../legacy/exceptions/static/webassembly.png | Bin 0 -> 43955 bytes document/legacy/exceptions/syntax.rst | 38 + document/legacy/exceptions/text.rst | 37 + document/legacy/exceptions/util/macros.def | 1342 +++++++++++++++++ document/legacy/exceptions/util/mathdef.py | 122 ++ .../legacy/exceptions/util/pseudo-lexer.py | 32 + document/legacy/exceptions/valid.rst | 150 ++ 20 files changed, 3277 insertions(+), 3 deletions(-) create mode 100644 document/legacy/exceptions/.gitignore create mode 100644 document/legacy/exceptions/LICENSE create mode 100644 document/legacy/exceptions/Makefile create mode 100644 document/legacy/exceptions/README.md create mode 100755 document/legacy/exceptions/appendix/index-instructions.py create mode 100644 document/legacy/exceptions/binary.rst create mode 100644 document/legacy/exceptions/conf.py create mode 100644 document/legacy/exceptions/exec.rst create mode 100644 document/legacy/exceptions/index.rst create mode 100644 document/legacy/exceptions/intro.rst create mode 100644 document/legacy/exceptions/static/custom.css create mode 100644 document/legacy/exceptions/static/webassembly.png create mode 100644 document/legacy/exceptions/syntax.rst create mode 100644 document/legacy/exceptions/text.rst create mode 100644 document/legacy/exceptions/util/macros.def create mode 100644 document/legacy/exceptions/util/mathdef.py create mode 100644 document/legacy/exceptions/util/pseudo-lexer.py create mode 100644 document/legacy/exceptions/valid.rst diff --git a/document/Makefile b/document/Makefile index 875efc72..629d5f51 100644 --- a/document/Makefile +++ b/document/Makefile @@ -1,4 +1,4 @@ -DIRS = core js-api web-api +DIRS = core js-api web-api legacy/exceptions FILES = index.html BUILDDIR = _build diff --git a/document/index.html b/document/index.html index 37eed976..79a2a0cf 100644 --- a/document/index.html +++ b/document/index.html @@ -49,19 +49,32 @@

Embedder specifications

+

Legacy Extensions

+ +

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

+ + + +

Source for these documents is available here. diff --git a/document/legacy/exceptions/.gitignore b/document/legacy/exceptions/.gitignore new file mode 100644 index 00000000..b932ec28 --- /dev/null +++ b/document/legacy/exceptions/.gitignore @@ -0,0 +1,3 @@ +_build +_static +document/*.pyc diff --git a/document/legacy/exceptions/LICENSE b/document/legacy/exceptions/LICENSE new file mode 100644 index 00000000..795b406e --- /dev/null +++ b/document/legacy/exceptions/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/Makefile b/document/legacy/exceptions/Makefile new file mode 100644 index 00000000..56b9560a --- /dev/null +++ b/document/legacy/exceptions/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 + +# 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/README.md b/document/legacy/exceptions/README.md new file mode 100644 index 00000000..06d07523 --- /dev/null +++ b/document/legacy/exceptions/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/appendix/index-instructions.py b/document/legacy/exceptions/appendix/index-instructions.py new file mode 100755 index 00000000..ea315469 --- /dev/null +++ b/document/legacy/exceptions/appendix/index-instructions.py @@ -0,0 +1,116 @@ +#!/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: + +Appendix +======== + +.. index:: instruction +.. _index-instr: + +Index of Instructions +--------------------- +""" + +FOOTER = """\ + +.. 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.\ +""" + +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/binary.rst b/document/legacy/exceptions/binary.rst new file mode 100644 index 00000000..68ea09df --- /dev/null +++ b/document/legacy/exceptions/binary.rst @@ -0,0 +1,31 @@ +.. _binary: + +Binary Format +============= + +.. index:: instruction +.. _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/conf.py b/document/legacy/exceptions/conf.py new file mode 100644 index 00000000..ebd159bd --- /dev/null +++ b/document/legacy/exceptions/conf.py @@ -0,0 +1,498 @@ +# -*- 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' +project = u'WebAssembly' +title = u'WebAssembly Specification 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 = u'0.1' +# 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': { + 'Index': 'BASEDIR/genindex.html', + '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 = project + u' ' + release + +# 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 = True + +# 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}', +} + +# 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, + 'manual' + ), +] + +# 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/exec.rst b/document/legacy/exceptions/exec.rst new file mode 100644 index 00000000..a935eaca --- /dev/null +++ b/document/legacy/exceptions/exec.rst @@ -0,0 +1,351 @@ +.. _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 \\ + (\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/index.rst b/document/legacy/exceptions/index.rst new file mode 100644 index 00000000..b6428fb7 --- /dev/null +++ b/document/legacy/exceptions/index.rst @@ -0,0 +1,22 @@ +WebAssembly Specification Addendum: Legacy Exception Handling +============================================================= + +.. only:: html + + | Release |release| + + | Editor: Andreas Rossberg + + | Latest Draft: |WasmDraft| + | Issue Tracker: |WasmIssues| + +.. toctree:: + :maxdepth: 1 + + intro + syntax + valid + exec + binary + text + appendix/index-instructions diff --git a/document/legacy/exceptions/intro.rst b/document/legacy/exceptions/intro.rst new file mode 100644 index 00000000..b8d8c57c --- /dev/null +++ b/document/legacy/exceptions/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/static/custom.css b/document/legacy/exceptions/static/custom.css new file mode 100644 index 00000000..33bb863d --- /dev/null +++ b/document/legacy/exceptions/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/static/webassembly.png b/document/legacy/exceptions/static/webassembly.png new file mode 100644 index 0000000000000000000000000000000000000000..f9edc61098a6f6957903d4e67d92c81269c22e49 GIT binary patch literal 43955 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 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/util/pseudo-lexer.py b/document/legacy/exceptions/util/pseudo-lexer.py new file mode 100644 index 00000000..fd3a251d --- /dev/null +++ b/document/legacy/exceptions/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. From 7ecd3873a3d8383adef08c09b9c7b24a1930f402 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Sat, 14 Oct 2023 17:51:50 +0200 Subject: [PATCH 2/2] [test] Create infra for legacy tests --- test/legacy/exceptions/rethrow.wast | 96 ++++++++ test/legacy/exceptions/throw.wast | 51 +++++ test/legacy/exceptions/try_catch.wast | 265 +++++++++++++++++++++++ test/legacy/exceptions/try_delegate.wast | 199 +++++++++++++++++ test/legacy/run.py | 117 ++++++++++ 5 files changed, 728 insertions(+) create mode 100644 test/legacy/exceptions/rethrow.wast create mode 100644 test/legacy/exceptions/throw.wast create mode 100644 test/legacy/exceptions/try_catch.wast create mode 100644 test/legacy/exceptions/try_delegate.wast create mode 100755 test/legacy/run.py diff --git a/test/legacy/exceptions/rethrow.wast b/test/legacy/exceptions/rethrow.wast new file mode 100644 index 00000000..e41d94b2 --- /dev/null +++ b/test/legacy/exceptions/rethrow.wast @@ -0,0 +1,96 @@ +;; Test rethrow instruction. + +(module + (tag $e0) + (tag $e1) + + (func (export "catch-rethrow-0") + (try + (do (throw $e0)) + (catch $e0 (rethrow 0)) + ) + ) + + (func (export "catch-rethrow-1") (param i32) (result i32) + (try (result i32) + (do (throw $e0)) + (catch $e0 + (if (i32.eqz (local.get 0)) (then (rethrow 1))) (i32.const 23) + ) + ) + ) + + (func (export "catchall-rethrow-0") + (try + (do (throw $e0)) + (catch_all (rethrow 0)) + ) + ) + + (func (export "catchall-rethrow-1") (param i32) (result i32) + (try (result i32) + (do (throw $e0)) + (catch_all + (if (i32.eqz (local.get 0)) (then (rethrow 1))) (i32.const 23) + ) + ) + ) + + (func (export "rethrow-nested") (param i32) (result i32) + (try (result i32) + (do (throw $e1)) + (catch $e1 + (try (result i32) + (do (throw $e0)) + (catch $e0 + (if (i32.eq (local.get 0) (i32.const 0)) (then (rethrow 1))) + (if (i32.eq (local.get 0) (i32.const 1)) (then (rethrow 2))) + (i32.const 23) + ) + ) + ) + ) + ) + + (func (export "rethrow-recatch") (param i32) (result i32) + (try (result i32) + (do (throw $e0)) + (catch $e0 + (try (result i32) + (do (if (i32.eqz (local.get 0)) (then (rethrow 2))) (i32.const 42)) + (catch $e0 (i32.const 23)) + ) + ) + ) + ) + + (func (export "rethrow-stack-polymorphism") + (try + (do (throw $e0)) + (catch $e0 (i32.const 1) (rethrow 0)) + ) + ) +) + +(assert_exception (invoke "catch-rethrow-0")) + +(assert_exception (invoke "catch-rethrow-1" (i32.const 0))) +(assert_return (invoke "catch-rethrow-1" (i32.const 1)) (i32.const 23)) + +(assert_exception (invoke "catchall-rethrow-0")) + +(assert_exception (invoke "catchall-rethrow-1" (i32.const 0))) +(assert_return (invoke "catchall-rethrow-1" (i32.const 1)) (i32.const 23)) +(assert_exception (invoke "rethrow-nested" (i32.const 0))) +(assert_exception (invoke "rethrow-nested" (i32.const 1))) +(assert_return (invoke "rethrow-nested" (i32.const 2)) (i32.const 23)) + +(assert_return (invoke "rethrow-recatch" (i32.const 0)) (i32.const 23)) +(assert_return (invoke "rethrow-recatch" (i32.const 1)) (i32.const 42)) + +(assert_exception (invoke "rethrow-stack-polymorphism")) + +(assert_invalid (module (func (rethrow 0))) "invalid rethrow label") +(assert_invalid (module (func (block (rethrow 0)))) "invalid rethrow label") +(assert_invalid (module (func (try (do (rethrow 0)) (delegate 0)))) + "invalid rethrow label") diff --git a/test/legacy/exceptions/throw.wast b/test/legacy/exceptions/throw.wast new file mode 100644 index 00000000..d53b5b55 --- /dev/null +++ b/test/legacy/exceptions/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/legacy/exceptions/try_catch.wast b/test/legacy/exceptions/try_catch.wast new file mode 100644 index 00000000..2a0e9ff6 --- /dev/null +++ b/test/legacy/exceptions/try_catch.wast @@ -0,0 +1,265 @@ +;; Test try-catch blocks. + +(module + (tag $e0 (export "e0")) + (func (export "throw") (throw $e0)) +) + +(register "test") + +(module + (tag $imported-e0 (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 "empty-catch") (try (do) (catch $e0))) + + (func (export "simple-throw-catch") (param i32) (result i32) + (try (result i32) + (do (local.get 0) (i32.eqz) (if (then (throw $e0)) (else)) (i32.const 42)) + (catch $e0 (i32.const 23)) + ) + ) + + (func (export "unreachable-not-caught") (try (do (unreachable)) (catch_all))) + + (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) + (try (result i32) + (do (local.get 0) (local.get 1) (call $div)) + (catch_all (i32.const 11)) + ) + ) + + (func (export "catch-complex-1") (param i32) (result i32) + (try (result i32) + (do + (try (result i32) + (do + (local.get 0) + (i32.eqz) + (if + (then (throw $e0)) + (else + (local.get 0) + (i32.const 1) + (i32.eq) + (if (then (throw $e1)) (else (throw $e2))) + ) + ) + (i32.const 2) + ) + (catch $e0 (i32.const 3)) + ) + ) + (catch $e1 (i32.const 4)) + ) + ) + + (func (export "catch-complex-2") (param i32) (result i32) + (try (result i32) + (do + (local.get 0) + (i32.eqz) + (if + (then (throw $e0)) + (else + (local.get 0) + (i32.const 1) + (i32.eq) + (if (then (throw $e1)) (else (throw $e2))) + ) + ) + (i32.const 2) + ) + (catch $e0 (i32.const 3)) + (catch $e1 (i32.const 4)) + ) + ) + + (func (export "throw-catch-param-i32") (param i32) (result i32) + (try (result i32) + (do (local.get 0) (throw $e-i32) (i32.const 2)) + (catch $e-i32 (return)) + ) + ) + + (func (export "throw-catch-param-f32") (param f32) (result f32) + (try (result f32) + (do (local.get 0) (throw $e-f32) (f32.const 0)) + (catch $e-f32 (return)) + ) + ) + + (func (export "throw-catch-param-i64") (param i64) (result i64) + (try (result i64) + (do (local.get 0) (throw $e-i64) (i64.const 2)) + (catch $e-i64 (return)) + ) + ) + + (func (export "throw-catch-param-f64") (param f64) (result f64) + (try (result f64) + (do (local.get 0) (throw $e-f64) (f64.const 0)) + (catch $e-f64 (return)) + ) + ) + + (func $throw-param-i32 (param i32) (local.get 0) (throw $e-i32)) + (func (export "catch-param-i32") (param i32) (result i32) + (try (result i32) + (do (i32.const 0) (local.get 0) (call $throw-param-i32)) + (catch $e-i32) + ) + ) + + (func (export "catch-imported") (result i32) + (try (result i32) + (do + (i32.const 1) + (call $imported-throw) + ) + (catch $imported-e0 (i32.const 2)) + ) + ) + + (func (export "catchless-try") (param i32) (result i32) + (try (result i32) + (do + (try (result i32) + (do (local.get 0) (call $throw-if)) + ) + ) + (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) + ) + ) +) + +(assert_return (invoke "empty-catch")) + +(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 "catch-param-i32" (i32.const 5)) (i32.const 5)) + +(assert_return (invoke "catch-imported") (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")) + +(module + (func $imported-throw (import "test" "throw")) + (tag $e0) + + (func (export "imported-mismatch") (result i32) + (try (result i32) + (do + (try (result i32) + (do + (i32.const 1) + (call $imported-throw) + ) + (catch $e0 (i32.const 2)) + ) + ) + (catch_all (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" +) + +(assert_malformed + (module quote + "(module (func (try (do) (catch_all) (catch_all))))" + ) + "unexpected token" +) + +(assert_invalid (module (func (result i32) (try (result i32) (do)))) + "type mismatch: instruction requires [i32] but stack has []") +(assert_invalid (module (func (result i32) (try (result i32) (do (i64.const 42))))) + "type mismatch: instruction requires [i32] but stack has [i64]") +(assert_invalid (module (tag) (func (try (do) (catch 0 (i32.const 42))))) + "type mismatch: block requires [] but stack has [i32]") +(assert_invalid (module + (tag (param i64)) + (func (result i32) + (try (result i32) (do (i32.const 42)) (catch 0)))) + "type mismatch: instruction requires [i32] but stack has [i64]") +(assert_invalid (module (func (try (do) (catch_all (i32.const 42))))) + "type mismatch: block requires [] but stack has [i32]") diff --git a/test/legacy/exceptions/try_delegate.wast b/test/legacy/exceptions/try_delegate.wast new file mode 100644 index 00000000..aae3a301 --- /dev/null +++ b/test/legacy/exceptions/try_delegate.wast @@ -0,0 +1,199 @@ +;; Test try-delegate blocks. + +(module + (tag $e0) + (tag $e1) + + (func (export "delegate-no-throw") (result i32) + (try $t (result i32) + (do (try (result i32) (do (i32.const 1)) (delegate $t))) + (catch $e0 (i32.const 2)) + ) + ) + + (func $throw-if (param i32) + (local.get 0) + (if (then (throw $e0)) (else)) + ) + + (func (export "delegate-throw") (param i32) (result i32) + (try $t (result i32) + (do + (try (result i32) + (do (local.get 0) (call $throw-if) (i32.const 1)) + (delegate $t) + ) + ) + (catch $e0 (i32.const 2)) + ) + ) + + (func (export "delegate-skip") (result i32) + (try $t (result i32) + (do + (try (result i32) + (do + (try (result i32) + (do (throw $e0) (i32.const 1)) + (delegate $t) + ) + ) + (catch $e0 (i32.const 2)) + ) + ) + (catch $e0 (i32.const 3)) + ) + ) + + (func (export "delegate-to-block") (result i32) + (try (result i32) + (do (block (try (do (throw $e0)) (delegate 0))) + (i32.const 0)) + (catch_all (i32.const 1))) + ) + + (func (export "delegate-to-catch") (result i32) + (try (result i32) + (do (try + (do (throw $e0)) + (catch $e0 + (try (do (rethrow 1)) (delegate 0)))) + (i32.const 0)) + (catch_all (i32.const 1))) + ) + + (func (export "delegate-to-caller-trivial") + (try + (do (throw $e0)) + (delegate 0))) + + (func (export "delegate-to-caller-skipping") + (try (do (try (do (throw $e0)) (delegate 1))) (catch_all)) + ) + + (func $select-tag (param i32) + (block (block (block (local.get 0) (br_table 0 1 2)) (return)) (throw $e0)) + (throw $e1) + ) + + (func (export "delegate-merge") (param i32 i32) (result i32) + (try $t (result i32) + (do + (local.get 0) + (call $select-tag) + (try + (result i32) + (do (local.get 1) (call $select-tag) (i32.const 1)) + (delegate $t) + ) + ) + (catch $e0 (i32.const 2)) + ) + ) + + (func (export "delegate-throw-no-catch") (result i32) + (try (result i32) + (do (try (result i32) (do (throw $e0) (i32.const 1)) (delegate 0))) + (catch $e1 (i32.const 2)) + ) + ) + + (func (export "delegate-correct-targets") (result i32) + (try (result i32) + (do (try $l3 + (do (try $l2 + (do (try $l1 + (do (try $l0 + (do (try + (do (throw $e0)) + (delegate $l1))) + (catch_all unreachable))) + (delegate $l3))) + (catch_all unreachable))) + (catch_all (try + (do (throw $e0)) + (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) + ) + ) +) + +(assert_return (invoke "delegate-no-throw") (i32.const 1)) + +(assert_return (invoke "delegate-throw" (i32.const 0)) (i32.const 1)) +(assert_return (invoke "delegate-throw" (i32.const 1)) (i32.const 2)) + +(assert_exception (invoke "delegate-throw-no-catch")) + +(assert_return (invoke "delegate-merge" (i32.const 1) (i32.const 0)) (i32.const 2)) +(assert_exception (invoke "delegate-merge" (i32.const 2) (i32.const 0))) +(assert_return (invoke "delegate-merge" (i32.const 0) (i32.const 1)) (i32.const 2)) +(assert_exception (invoke "delegate-merge" (i32.const 0) (i32.const 2))) +(assert_return (invoke "delegate-merge" (i32.const 0) (i32.const 0)) (i32.const 1)) + +(assert_return (invoke "delegate-skip") (i32.const 3)) + +(assert_return (invoke "delegate-to-block") (i32.const 1)) +(assert_return (invoke "delegate-to-catch") (i32.const 1)) + +(assert_exception (invoke "delegate-to-caller-trivial")) +(assert_exception (invoke "delegate-to-caller-skipping")) + +(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_malformed + (module quote "(module (func (delegate 0)))") + "unexpected token" +) + +(assert_malformed + (module quote "(module (tag $e) (func (try (do) (catch $e) (delegate 0))))") + "unexpected token" +) + +(assert_malformed + (module quote "(module (func (try (do) (catch_all) (delegate 0))))") + "unexpected token" +) + +(assert_malformed + (module quote "(module (func (try (do) (delegate) (delegate 0))))") + "unexpected token" +) + +(assert_invalid + (module (func (try (do) (delegate 1)))) + "unknown label" +) diff --git a/test/legacy/run.py b/test/legacy/run.py new file mode 100755 index 00000000..f727aeef --- /dev/null +++ b/test/legacy/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, "exceptions", "*.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()