From 68d81c90d0a47010601a0fe673e27231468b99a2 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Mon, 12 Mar 2018 12:23:31 +0100 Subject: [PATCH 001/130] Overview --- README.md | 28 +++++++++---- proposals/annotations/Overview.md | 70 +++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 7 deletions(-) create mode 100644 proposals/annotations/Overview.md diff --git a/README.md b/README.md index 26d58a3a5c..f3f6b4fb4c 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,28 @@ -[![Build Status](https://travis-ci.org/WebAssembly/spec.svg?branch=master)](https://travis-ci.org/WebAssembly/spec) +[![Build Status](https://travis-ci.org/WebAssembly/multi-value.svg?branch=master)](https://travis-ci.org/WebAssembly/annotations) + +# Custom Annotations Proposal for WebAssembly + +This repository is a clone of [github.com/WebAssembly/spec/](https://github.com/WebAssembly/spec/). +It is meant for discussion, prototype specification and implementation of a proposal to add support for custom annotations to the WebAssembly text format. + +See the [overview](proposals/annotations/Overview.md) for a summary of the proposal. + +Original `README` from upstream repository follows... # spec -This repository holds the sources for the WebAssembly draft specification -(to seed a future -[WebAssembly Working Group](https://lists.w3.org/Archives/Public/public-new-work/2017Jun/0005.html)), -a reference implementation, and the official testsuite. +This repository holds a prototypical reference implementation for WebAssembly, +which is currently serving as the official specification. Eventually, we expect +to produce a specification either written in human-readable prose or in a formal +specification language. + +It also holds the WebAssembly testsuite, which tests numerous aspects of +conformance to the spec. + +View the work-in-progress spec at [webassembly.github.io/spec](https://webassembly.github.io/spec/). -A formatted version of the spec is available here: -[webassembly.github.io/spec](https://webassembly.github.io/spec/), +At this time, the contents of this repository are under development and known +to be "incomplet and inkorrect". Participation is welcome. Discussions about new features, significant semantic changes, or any specification change likely to generate substantial discussion diff --git a/proposals/annotations/Overview.md b/proposals/annotations/Overview.md new file mode 100644 index 0000000000..75f6a9c747 --- /dev/null +++ b/proposals/annotations/Overview.md @@ -0,0 +1,70 @@ +# Custom Annotation Syntax for the Wasm Text Format + +## Motivation + +Problem + +* The Wasm binary format supports custom sections to enable associating arbitrary meta data with a Wasm module. + +* No equivalent exists for the text format. In particular, there is no way to + - represent custom sections themselves in the text format, cf. WebAssembly/design#1153 and https://gist.github.com/binji/d1cfff7faaebb2aa4f8b1c995234e5a0 + - reflect arbitrary names in the text format, cf. WebAssembly/spec#617 + - express information like for host bindings, cf. https://github.com/WebAssembly/host-bindings/blob/master/proposals/host-bindings/Overview.md + +Solution + +* This proposal adds the ability to decorate a module in textual notarion with arbitrary annotations of the form `(@id ...)`. + +* Neither the syntactic shape nor the semantics is prescribed by the Wasm specification, though the Appendix might include a description of optional support for name section annotations and generic custom sections. + +* This proposal only affects the text format, nothing else. + + +## Details + +Extend the Text Format as follows: + +* Anywhere where white space is allowed, allow *annotations* of the following form: + ``` + annot ::= "(@"idchar+ annotelem* ")" + annotelem ::= keyword | reserved | uN | sN | fN | string | id | "(" annotelem* ")" | "(@"idchar+ annotelem* ")" + ``` + In other words, an annotation can contain any sequence of tokens, as long as it is well-bracketed. + No white space is allowed as part of the initial `(@idchar+` delimiter. + +* The initial `idchar+` is meant to be an identifier categorising the extension, and plays a role similar to the name of a custom section. + By convention, annotations corresponding to a custom section should use the same id. + +Extend the Appendix on the Custom Sections: + +* Define annotations reflecting the Name section, which take the form of annotations `(@name "name")`. + They may be placed after the binder for any construct that can be named by the name section. + +* Define annotation syntax expressing arbitrary custom sections; cf. https://gist.github.com/binji/d1cfff7faaebb2aa4f8b1c995234e5a0 + As with any matter concerning annotations, it is up to implementations how they handle the case where an explicit custom section overlaps with individual annotations that are associated with the same custom section. + + +## Examples + +Expressing generic custom sections (cf. https://gist.github.com/binji/d1cfff7faaebb2aa4f8b1c995234e5a0) +``` +(module + (@custom "my-fancy-section" (after function) "contents-bytes") +) +``` + +Expressing names +``` +(module (@name "Gümüsü") + (func $lambda (@name "λ") (param $x (@name "α βγ δ") i32) (result i32) (get_local $x)) +) +``` + +Host bindings (cf. https://github.com/WebAssembly/host-bindings/blob/master/proposals/host-bindings/Overview.md) +``` +(module + (func (export "f") (param i32 (@js unsigned)) ...) ;; argument converted as unsigned + (func (export "method") (param $x anyref (@js this)) (param $y i32) ...) ;; maps this to first arg + (func (import "m" "constructor") (@js new) (param i32) (result anyref) ;; is called as a constructor +) +``` From 8c3fda549889ec7f4b4e9bfbe99f96c7080ca58d Mon Sep 17 00:00:00 2001 From: Sergey Rubanov Date: Fri, 5 Apr 2019 19:44:40 +0300 Subject: [PATCH 002/130] Replace Host Bindings proposal by Web IDL proposal --- proposals/annotations/Overview.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/proposals/annotations/Overview.md b/proposals/annotations/Overview.md index 75f6a9c747..b1d2e8817f 100644 --- a/proposals/annotations/Overview.md +++ b/proposals/annotations/Overview.md @@ -9,7 +9,7 @@ Problem * No equivalent exists for the text format. In particular, there is no way to - represent custom sections themselves in the text format, cf. WebAssembly/design#1153 and https://gist.github.com/binji/d1cfff7faaebb2aa4f8b1c995234e5a0 - reflect arbitrary names in the text format, cf. WebAssembly/spec#617 - - express information like for host bindings, cf. https://github.com/WebAssembly/host-bindings/blob/master/proposals/host-bindings/Overview.md + - express information like for host bindings, cf. https://github.com/WebAssembly/webidl-bindings/blob/master/proposals/webidl-bindings/Explainer.md Solution @@ -47,21 +47,21 @@ Extend the Appendix on the Custom Sections: ## Examples Expressing generic custom sections (cf. https://gist.github.com/binji/d1cfff7faaebb2aa4f8b1c995234e5a0) -``` +```wasm (module (@custom "my-fancy-section" (after function) "contents-bytes") ) ``` Expressing names -``` +```wasm (module (@name "Gümüsü") (func $lambda (@name "λ") (param $x (@name "α βγ δ") i32) (result i32) (get_local $x)) ) ``` -Host bindings (cf. https://github.com/WebAssembly/host-bindings/blob/master/proposals/host-bindings/Overview.md) -``` +Web IDL bindings (cf. https://github.com/WebAssembly/webidl-bindings/blob/master/proposals/webidl-bindings/Explainer.md) +```wasm (module (func (export "f") (param i32 (@js unsigned)) ...) ;; argument converted as unsigned (func (export "method") (param $x anyref (@js this)) (param $y i32) ...) ;; maps this to first arg From f12488239fb89bc7324ce0762425886c4ad46876 Mon Sep 17 00:00:00 2001 From: Sergey Rubanov Date: Fri, 5 Apr 2019 19:45:39 +0300 Subject: [PATCH 003/130] Update Overview.md --- proposals/annotations/Overview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/annotations/Overview.md b/proposals/annotations/Overview.md index b1d2e8817f..590d6030e9 100644 --- a/proposals/annotations/Overview.md +++ b/proposals/annotations/Overview.md @@ -9,7 +9,7 @@ Problem * No equivalent exists for the text format. In particular, there is no way to - represent custom sections themselves in the text format, cf. WebAssembly/design#1153 and https://gist.github.com/binji/d1cfff7faaebb2aa4f8b1c995234e5a0 - reflect arbitrary names in the text format, cf. WebAssembly/spec#617 - - express information like for host bindings, cf. https://github.com/WebAssembly/webidl-bindings/blob/master/proposals/webidl-bindings/Explainer.md + - express information like for Web IDL bindings, cf. https://github.com/WebAssembly/webidl-bindings/blob/master/proposals/webidl-bindings/Explainer.md Solution From ab6b2215ceec630442d07b0ab10a4e18b649acb8 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Sat, 27 Apr 2019 23:37:42 +0200 Subject: [PATCH 004/130] [spec/interpreter/test] Spec and implement proposal --- document/core/appendix/custom.rst | 206 +++++++++++++++++++++++++++++- document/core/text/lexical.rst | 34 ++++- document/core/util/macros.def | 22 ++++ interpreter/text/lexer.mll | 36 +++++- test/core/annotations.wast | 146 +++++++++++++++++++++ 5 files changed, 434 insertions(+), 10 deletions(-) create mode 100644 test/core/annotations.wast diff --git a/document/core/appendix/custom.rst b/document/core/appendix/custom.rst index afd2b1a0e6..ed64593366 100644 --- a/document/core/appendix/custom.rst +++ b/document/core/appendix/custom.rst @@ -1,13 +1,12 @@ -.. index:: custom section, section, binary format +.. index:: custom section, section, binary format, annotation, text format -Custom Sections ---------------- +Custom Sections and Annotations +------------------------------- -This appendix defines dedicated :ref:`custom sections ` for WebAssembly's :ref:`binary format `. -Such sections do not contribute to, or otherwise affect, the WebAssembly semantics, and like any custom section they may be ignored by an implementation. +This appendix defines dedicated :ref:`custom sections ` for WebAssembly's :ref:`binary format ` and :ref:`annotations ` for the text format. +Such sections or annotations do not contribute to, or otherwise affect, the WebAssembly semantics, and may be ignored by an implementation. However, they provide useful meta data that implementations can make use of to improve user experience or take compilation hints. -Currently, only one dedicated custom section is defined, the :ref:`name section`. .. index:: ! name section, name, Unicode UTF-8 @@ -138,3 +137,198 @@ It consists of an :ref:`indirect name map ` assigning lo \production{local name subsection} & \Blocalnamesubsec &::=& \Bnamesubsection_2(\Bindirectnamemap) \\ \end{array} + + +.. index:: ! name annotation, name, Unicode UTF-8 +.. _text-nameannot: + +Name Annotations +~~~~~~~~~~~~~~~~ + +*Name annotations* are the textual analogue to the :ref:`name section ` and provide a textual representation for it. +Consequently, their id is :math:`\T{@name}`. + +Analogous to the name section, name annotations are allowed on :ref:`modules `, :ref:`functions `, and :ref:`locals ` (including :ref:`parameters `). +They can be placed where the text format allows binding occurrences of respective :ref:`identifiers `. +If both an identifier and a name annotation are given, the annotation is expected *after* the identifier. +In that case, the annotation takes precedence over the identifier as a textual representation of the binding's name. +At most one name annotation may be given per binding. + +All name annotations have the following format: + +.. math:: + \begin{array}{llclll} + \production{name annotation} & \Tnameannot &::=& + \text{(@name}~\Tstring~\text{)} \\ + \end{array} + + +.. note:: + All name annotations can be arbitrary UTF-8 :ref:`strings `. + Names need not be unique. + + +.. index:: module +.. _text-modulenameannot: + +Module Names +............ + +A *module name annotation* must be placed on a :ref:`module ` definition, +directly after the :math:`\text{module}` keyword, or if present, after the following module :ref:`identifier `. + +.. math:: + \begin{array}{llclll} + \production{module name annotation} & \Tmodulenameannot &::=& + \Tnameannot \\ + \end{array} + + +.. index:: function +.. _binary-funcnameannot: + +Function Names +.............. + +A *function name annotation* must be placed on a :ref:`function ` definition or function :ref:`import `, +directly after the :math:`\text{func}` keyword, or if present, after the following function :ref:`identifier ` or. + +.. math:: + \begin{array}{llclll} + \production{function name annotation} & \Tfuncnameannot &::=& + \Tnameannot \\ + \end{array} + + +.. index:: function, parameter +.. _binary-paramnameannot: + +Parameter Names +............... + +A *parameter name annotation* must be placed on a :ref:`parameter ` declaration, +directly after the :math:`\text{param}` keyword, or if present, after the following parameter :ref:`identifier `. +It may only be placed on a declaration that declares exactly one parameter. + +.. math:: + \begin{array}{llclll} + \production{parameter name annotation} & \Tparamnameannot &::=& + \Tnameannot \\ + \end{array} + + +.. index:: function, local +.. _binary-localnameannot: + +Local Names +........... + +A *local name annotation* must be placed on a :ref:`local ` declaration, +directly after the :math:`\text{local}` keyword, or if present, after the following local :ref:`identifier `. +It may only be placed on a declaration that declares exactly one local. + +.. math:: + \begin{array}{llclll} + \production{local name annotation} & \Tlocalnameannot &::=& + \Tnameannot \\ + \end{array} + + +.. index:: ! custom annotation, custom section +.. _text-customannot: + +Custom Annotations +~~~~~~~~~~~~~~~~~~ + +*Custom annotations* are a generic textual representation for any :ref:`custom section `. +Their id is :math:`\T{@custom}`. +By generating custom annotations, tools converting between :ref:`binary format ` and :ref:`text format ` can maintain and round-trip the content of custom sections even when they do not recognize them. + +Custom annotations must be placed inside a :ref:`module ` definition. +They must occur anywhere after the :math:`\text{module}` keyword, or if present, after the following module :ref:`identifier `. +They must not be nested into other constructs. + +.. math:: + \begin{array}{llclll} + \production{custom annotation} & \Tcustomannot &::=& + \text{(@custom}~~\Tstring~~\Tcustomplace^?~~\Tdatastring~~\text{)} \\ + \production{custom placement} & \Tcustomplace &::=& + \text{(}~\text{before}~~\text{first}~\text{)} \\ &&|& + \text{(}~\text{before}~~\Tsec~\text{)} \\ &&|& + \text{(}~\text{after}~~\Tsec~\text{)} \\ &&|& + \text{(}~\text{after}~~\text{last}~\text{)} \\ + \production{section} & \Tsec &::=& + \text{type} \\ &&|& + \text{import} \\ &&|& + \text{func} \\ &&|& + \text{table} \\ &&|& + \text{memory} \\ &&|& + \text{global} \\ &&|& + \text{export} \\ &&|& + \text{start} \\ &&|& + \text{elem} \\ &&|& + \text{code} \\ &&|& + \text{data} \\ + \end{array} + +The first :ref:`string ` in a custom annotation denotes the name of the custom section it represents. +The remaining strings collectively represent the section's payload data, written as a :ref:`data string `, which can be split up into a possibly empty sequence of individual string literals (similar to :ref:`data segments `). + +An arbitrary number of custom annotations (even of the same name) may occur in a module, +each defining a separate custom section when converting to :ref:`binary format `. +Placement of the sections in the binary can be customized via explicit *placement* directives, that position them either directly before or directly after a known section. +The placements :math:`\T{(before~first)}` and :math:`\T{(after~last)}` denote virtual sections before the first and after the last known section, respectively. +When the placement directive is omitted, it defaults to :math:`\T{(after~last)}`. + +If multiple placement directives appear for the same position, then the sections are all placed there, in order of their appearance in the text. +For this purpose, the position :math:`\T{after}` a section is considered different from the position :math:`\T{before}` the consecutive section, and the former occurs before the latter. + +.. note:: + Future versions of WebAssembly may introduce additional sections between others or at the beginning or end of a module. + Using :math:`\T{first}` and :math:`\T{last}` guarantees that placement will still go before or after any future section, respectively. + +If a custom section with a specific section id is given as well as annotations representing the same custom section (e.g., :math:`\T{@name}` :ref:`annotations ` as well as a :math:`\T{@custom}` annotation for a :math:`\T{name}` :ref:`section `), then two sections are assumed to be created. +Their relative placement will depend on the placement directive given for the :math:`\T{@custom}` annotation as well as the implicit placement requirements of the custom section, which are applied to the other annotation. + +.. note:: + + For example, the following module, + + .. code-block:: none + + (module + (@custom "A" "aaa") + (type $t (func)) + (@custom "B" (after func) "bbb") + (@custom "C" (before func) "ccc") + (@custom "D" (after last) "ddd") + (table 10 funcref) + (func (type $t)) + (@custom "E" (after import) "eee") + (@custom "F" (before type) "fff") + (@custom "G" (after data) "ggg") + (@custom "H" (after code) "hhh") + (@custom "I" (after func) "iii") + (@custom "J" (before func) "jjj") + (@custom "K" (before first) "kkk") + ) + + will result in the following section ordering: + + .. code-block:: none + + custom section "K" + custom section "F" + type section + custom section "E" + custom section "C" + custom section "J" + function section + custom section "B" + custom section "I" + table section + code section + custom section "H" + custom section "G" + custom section "A" + custom section "D" diff --git a/document/core/text/lexical.rst b/document/core/text/lexical.rst index a3b4529d35..4c3ee4d362 100644 --- a/document/core/text/lexical.rst +++ b/document/core/text/lexical.rst @@ -50,7 +50,7 @@ The character stream in the source text is divided, from left to right, into a s (\text{a} ~|~ \dots ~|~ \text{z})~\Tidchar^\ast \qquad (\mbox{if occurring as a literal terminal in the grammar}) \\ \production{reserved} & \Treserved &::=& - \Tidchar^+ \\ + \Tidchar^+ ~|~ \text{;} ~|~ \text{[} ~|~ \text{]} ~|~ \text{\{} ~|~ \text{\}} \\ \end{array} Tokens are formed from the input character stream according to the *longest match* rule. @@ -77,7 +77,7 @@ Any token that does not fall into any of the other categories is considered *res White Space ~~~~~~~~~~~ -*White space* is any sequence of literal space characters, formatting characters, or :ref:`comments `. +*White space* is any sequence of literal space characters, formatting characters, :ref:`comments `, or :ref:`annotations `. The allowed formatting characters correspond to a subset of the |ASCII|_ *format effectors*, namely, *horizontal tabulation* (:math:`\unicode{09}`), *line feed* (:math:`\unicode{0A}`), and *carriage return* (:math:`\unicode{0D}`). .. math:: @@ -124,3 +124,33 @@ The *look-ahead* restrictions on the productions for |Tblockchar| disambiguate t .. note:: Any formatting and control characters are allowed inside comments. + + +.. index:: ! annotation + single: text format; annotation +.. _text-annot: + +Annotations +~~~~~~~~~~~ + +An *annotation* is a bracketed token sequence headed by an *annotation id* of the form :math:`\T{@id}`. +No :ref:`space ` is allowed between the opening parenthesis and this id. +Annotations are intended to be used for third-party extensions; +they can appear anywhere in a program but are ignored by the WebAssembly semantics itself, which treats them as :ref:`white space `. + +Annotations can contain other parenthesized token sequences (including nested annotations), as long as they are well-nested. +:ref:`String literals ` and :ref:`comments ` occurring in an annotation must also be properly nested and closed. + +.. math:: + \begin{array}{llclll@{\qquad\qquad}l} + \production{annot} & \Tannot &::=& + \text{(}~\text{@}~\Tidchar^+ ~\Tspace^+ ~(\Tspace ~|~ \Ttoken)^\ast~\text{)} \\ + \end{array} + +.. note:: + The annotation id is meant to be an identifier categorising the extension, and plays a role similar to the name of a :ref:`custom section `. + By convention, annotations corresponding to a custom section should use the custom section's name as an id. + + Implementations are expected to ignore annotations with ids that they do not recognize. + On the other hand, they may impose restrictions on annotations that they do recognize, e.g., requiring a specific structure by superimposing a more concrete grammar. + It is up to an implementation how it deals with errors in such annotations. diff --git a/document/core/util/macros.def b/document/core/util/macros.def index 081e9a209c..529d6b247a 100644 --- a/document/core/util/macros.def +++ b/document/core/util/macros.def @@ -550,6 +550,9 @@ .. |Tlinechar| mathdef:: \xref{text/lexical}{text-comment}{\T{linechar}} .. |Tblockchar| mathdef:: \xref{text/lexical}{text-comment}{\T{blockchar}} +.. |Tannot| mathdef:: \xref{text/lexical}{text-annot}{\T{annot}} +.. |Tannottoken| mathdef:: \xref{text/lexical}{text-annot}{\T{annottoken}} + .. Values, non-terminals @@ -1028,6 +1031,25 @@ .. |Blocalnamesubsec| mathdef:: \xref{appendix/custom}{binary-localnamesec}{\B{localnamesubsec}} +.. Annotations +.. ----------- + +.. Custom annotations, non-terminals + +.. |Tcustomannot| mathdef:: \xref{appendix/custom}{text-customannot}{\T{customannot}} +.. |Tcustomplace| mathdef:: \xref{appendix/custom}{text-customannot}{\T{customplace}} +.. |Tsec| mathdef:: \xref{appendix/custom}{text-customannot}{\T{sec}} + + +.. Name annotations, non-terminals + +.. |Tnameannot| mathdef:: \xref{appendix/custom}{text-nameannot}{\T{nameannot}} +.. |Tmodulenameannot| mathdef:: \xref{appendix/custom}{text-modulenameannot}{\T{modulenameannot}} +.. |Tfuncnameannot| mathdef:: \xref{appendix/custom}{text-funcnameannot}{\T{funcnameannot}} +.. |Tparamnameannot| mathdef:: \xref{appendix/custom}{text-paramnameannot}{\T{paramnameannot}} +.. |Tlocalnameannot| mathdef:: \xref{appendix/custom}{text-localnameannot}{\T{localnameannot}} + + .. Embedding .. --------- diff --git a/interpreter/text/lexer.mll b/interpreter/text/lexer.mll index dab48e0453..6aa5abb698 100644 --- a/interpreter/text/lexer.mll +++ b/interpreter/text/lexer.mll @@ -134,8 +134,11 @@ let float = | sign? "nan" | sign? "nan:" "0x" hexnum let string = '"' character* '"' -let name = '$' (letter | digit | '_' | symbol)+ -let reserved = ([^'\"''('')'';'] # space)+ (* hack for table size *) + +let id = (letter | digit | '_' | symbol)+ +let name = '$' id + +let reserved = ';' | ([^'\"''('')'';'] # space)+ (* hack for table size *) let ixx = "i" ("32" | "64") let fxx = "f" ("32" | "64") @@ -353,6 +356,9 @@ rule token = parse | name as s { VAR s } + | "(@"id { annot (Lexing.lexeme_start_p lexbuf) lexbuf; token lexbuf } + | "(@" { error lexbuf "malformed annotation id" } + | ";;"utf8_no_nl*eof { EOF } | ";;"utf8_no_nl*'\n' { Lexing.new_line lexbuf; token lexbuf } | ";;"utf8_no_nl* { token lexbuf (* causes error on following position *) } @@ -365,6 +371,32 @@ rule token = parse | utf8 { error lexbuf "malformed operator" } | _ { error lexbuf "malformed UTF-8 encoding" } +and annot start = parse + | ")" { () } + | "(" { annot (Lexing.lexeme_start_p lexbuf) lexbuf; annot start lexbuf } + + | reserved { annot start lexbuf } + | nat { annot start lexbuf } + | int { annot start lexbuf } + | float { annot start lexbuf } + | id { annot start lexbuf } + | name { annot start lexbuf } + | string { annot start lexbuf } + | '"'character*('\n'|eof) { error lexbuf "unclosed string literal" } + | '"'character*['\x00'-'\x09''\x0b'-'\x1f''\x7f'] + { error lexbuf "illegal control character in string literal" } + | '"'character*'\\'_ + { error_nest (Lexing.lexeme_end_p lexbuf) lexbuf "illegal escape" } + + | (";;"utf8_no_nl*)? eof { error_nest start lexbuf "unclosed annotation" } + | ";;"utf8_no_nl*'\n' { Lexing.new_line lexbuf; annot start lexbuf } + | ";;"utf8_no_nl* { annot start lexbuf (* error on following position *) } + | "(;" { comment (Lexing.lexeme_start_p lexbuf) lexbuf; annot start lexbuf } + | space#'\n' { annot start lexbuf } + | '\n' { Lexing.new_line lexbuf; annot start lexbuf } + | eof { error_nest start lexbuf "unclosed annotation" } + | _ { error lexbuf "malformed UTF-8 encoding" } + and comment start = parse | ";)" { () } | "(;" { comment (Lexing.lexeme_start_p lexbuf) lexbuf; comment start lexbuf } diff --git a/test/core/annotations.wast b/test/core/annotations.wast new file mode 100644 index 0000000000..5ede9004dc --- /dev/null +++ b/test/core/annotations.wast @@ -0,0 +1,146 @@ +(@a) +(@aas-3!@$d-@#4) +(@@) +(@a x y z) +(@a x-y $yz "aa" -2 0.3 0x3) +(@a x-y$yz"aa"-2) +(@a block func module i32.add) +(@a 0x 8q 0xfa #4g0-.@f#^&@#$*0sf -- @#) +(@a ; ] [ }} }x{ ({) {{};}] ;) +(@a (bla) () (5-g) ("aa" a) ($x) (bla bla) (x (y)) ")" "(" x")"y) +(@a @ @x (@x) (@x y) (@) (@ x) (@(@(@(@))))) +(@a Heiße Würstchen   + +) +(@a (;bla;) (; ) ;) + ;; bla) + ;; bla (@x +) + +(assert_malformed (module quote "(@)") "malformed annotation id") +(assert_malformed (module quote "(@ )") "malformed annotation id") +(assert_malformed (module quote "(@ x)") "malformed annotation id") + +(assert_malformed (module quote "(@x ") "unclosed annotation") +(assert_malformed (module quote "(@x ()") "unclosed annotation") +(assert_malformed (module quote "(@x (y (z))") "unclosed annotation") +(assert_malformed (module quote "(@x (@y )") "unclosed annotation") + +(assert_malformed (module quote "(@x))") "unexpected token") +(assert_malformed (module quote "(@x ()))") "unexpected token") +(assert_malformed (module quote "(@x (y (z))))") "unexpected token") +(assert_malformed (module quote "(@x (@y )))") "unexpected token") + +(assert_malformed (module quote "(@x \"") "unclosed string") + +(assert_malformed (module quote "((@a)@b)") "unknown operator") +(assert_malformed (module quote "(func $(@a))") "unknown operator") +(assert_malformed (module quote "(func $(@a)f)") "unknown operator") + +((@a) module (@a) $m (@a) (@a) + ((@a) import (@a) "spectest" (@a) "global_i32" (@a) + ((@a) global (@a) $g (@a) i32 (@a)) (@a) + ) (@a) + ((@a) import (@a) "spectest" (@a) "table" (@a) + ((@a) table (@a) $t (@a) 10 (@a) 20 (@a) funcref (@a)) (@a) + ) (@a) + ((@a) import (@a) "spectest" (@a) "memory" (@a) + ((@a) memory (@a) $m (@a) 1 (@a) 2 (@a)) (@a) + ) (@a) + ((@a) import (@a) "spectest" (@a) "print_i32_f32" (@a) + ((@a) func (@a) $f (@a) + ((@a) param (@a) i32 (@a) f32 (@a)) (@a) + ((@a) result (@a)) (@a) + ) (@a) + ) (@a) + + ((@a) export (@a) "g" (@a) + ((@a) global (@a) $g (@a)) (@a) + ) (@a) + ((@a) export (@a) "t" (@a) + ((@a) table (@a) $t (@a)) (@a) + ) (@a) + ((@a) export (@a) "m" (@a) + ((@a) memory (@a) $m (@a)) (@a) + ) (@a) + ((@a) export (@a) "f" (@a) + ((@a) func (@a) $f (@a)) (@a) + ) (@a) +) (@a) + +((@a) module (@a) $m (@a) (@a) + ((@a) global (@a) $g (@a) + ((@a) export (@a) "g" (@a)) (@a) + ((@a) import (@a) "spectest" (@a) "global_i32" (@a)) (@a) + i32 (@a) + ) (@a) + ((@a) table (@a) $t (@a) + ((@a) export (@a) "t" (@a)) (@a) + ((@a) import (@a) "spectest" (@a) "table" (@a)) (@a) + 10 (@a) 20 (@a) + funcref (@a) + ) (@a) + ((@a) memory (@a) $m (@a) + ((@a) export (@a) "m" (@a)) (@a) + ((@a) import (@a) "spectest" (@a) "memory" (@a)) (@a) + 1 (@a) 2 (@a) + ) (@a) + ((@a) func (@a) $f (@a) + ((@a) export (@a) "f" (@a)) (@a) + ((@a) import (@a) "spectest" (@a) "print_i32_f32" (@a)) (@a) + ((@a) param (@a) i32 (@a) f32 (@a)) (@a) + ((@a) result (@a)) (@a) + ) (@a) +) (@a) + +((@a) module (@a) $m (@a) (@a) + ((@a) type (@a) $T (@a) + ((@a) func (@a) + ((@a) param (@a) i32 (@a) i64 (@a)) (@a) + ((@a) param (@a) $x (@a) i32 (@a)) (@a) + ((@a) result (@a) i32 (@a)) (@a) + ) (@a) + ) (@a) + + ((@a) global (@a) $g (@a) + ((@a) export (@a) "g" (@a)) (@a) + i32 (@a) + ((@a) i32.const (@a) 42 (@a)) (@a) + ) (@a) + ((@a) table (@a) $t (@a) + ((@a) export (@a) "t" (@a)) (@a) + 10 (@a) 20 (@a) + funcref (@a) + ) (@a) + ((@a) memory (@a) $m (@a) + ((@a) export (@a) "m" (@a)) (@a) + 1 (@a) 2 (@a) + ) (@a) + ((@a) func (@a) $f (@a) + ((@a) export (@a) "f" (@a)) (@a) + ((@a) param (@a) i32 (@a) i64 (@a)) (@a) + ((@a) param (@a) $x (@a) i32 (@a)) (@a) + ((@a) result (@a) i32 (@a)) (@a) + ((@a) local (@a) i32 (@a) i32 (@a)) (@a) + ((@a) local (@a) $y (@a) i32 (@a)) (@a) + ((@a) block (@a) + ((@a) result (@a) i32 (@a)) (@a) + ((@a) i32.add (@a) + ((@a) local.get (@a) $x (@a)) (@a) + ((@a) local.get (@a) 0 (@a)) (@a) + ) + ) + ) (@a) + + ((@a) elem (@a) + ((@a) offset (@a) ((@a) i32.const (@a) 0 (@a)) (@a)) (@a) + $f (@a) $f (@a) (@a) $f (@a) + ) (@a) + ((@a) data (@a) + ((@a) offset (@a) ((@a) i32.const (@a) 0 (@a)) (@a)) (@a) + "bla" (@a) "\43" (@a) (@a) "" (@a) + ) (@a) + + (func $s) + ((@a) start (@a) $s (@a)) (@a) +) (@a) From a4c9207b69eac2beb386e59ae78fa7826efbf1c9 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Sun, 28 Apr 2019 00:09:45 +0200 Subject: [PATCH 005/130] Small fix --- document/core/text/lexical.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/document/core/text/lexical.rst b/document/core/text/lexical.rst index 4c3ee4d362..ffb297554d 100644 --- a/document/core/text/lexical.rst +++ b/document/core/text/lexical.rst @@ -144,7 +144,7 @@ Annotations can contain other parenthesized token sequences (including nested an .. math:: \begin{array}{llclll@{\qquad\qquad}l} \production{annot} & \Tannot &::=& - \text{(}~\text{@}~\Tidchar^+ ~\Tspace^+ ~(\Tspace ~|~ \Ttoken)^\ast~\text{)} \\ + \text{(}~\text{@}~\Tidchar^+ ~(\Tspace ~|~ \Ttoken)^\ast~\text{)} \\ \end{array} .. note:: From 2722b578be5a75278fe4f8def98688b9a85da7dc Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Sun, 28 Apr 2019 00:12:39 +0200 Subject: [PATCH 006/130] Tweak --- document/core/text/lexical.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/document/core/text/lexical.rst b/document/core/text/lexical.rst index ffb297554d..c008b87939 100644 --- a/document/core/text/lexical.rst +++ b/document/core/text/lexical.rst @@ -144,7 +144,7 @@ Annotations can contain other parenthesized token sequences (including nested an .. math:: \begin{array}{llclll@{\qquad\qquad}l} \production{annot} & \Tannot &::=& - \text{(}~\text{@}~\Tidchar^+ ~(\Tspace ~|~ \Ttoken)^\ast~\text{)} \\ + \text{(@}~\Tidchar^+ ~(\Tspace ~|~ \Ttoken)^\ast~\text{)} \\ \end{array} .. note:: From 5c4533534e4851aec59247951f9d828ec469c42b Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Sun, 28 Apr 2019 00:15:20 +0200 Subject: [PATCH 007/130] A couple more tests --- test/core/annotations.wast | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/core/annotations.wast b/test/core/annotations.wast index 5ede9004dc..3015afc059 100644 --- a/test/core/annotations.wast +++ b/test/core/annotations.wast @@ -1,6 +1,6 @@ (@a) (@aas-3!@$d-@#4) -(@@) +(@@) (@$) (@+) (@0) (@.) (@!$@#$23414@#$) (@a x y z) (@a x-y $yz "aa" -2 0.3 0x3) (@a x-y$yz"aa"-2) From 7c4ec86bcc6721b1a115df289f4c78b0470d89b0 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Sun, 28 Apr 2019 00:17:48 +0200 Subject: [PATCH 008/130] A couple more tests --- test/core/annotations.wast | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/core/annotations.wast b/test/core/annotations.wast index 3015afc059..e8562ad2fa 100644 --- a/test/core/annotations.wast +++ b/test/core/annotations.wast @@ -17,9 +17,12 @@ ;; bla (@x ) +(assert_malformed (module quote "( @a)") "unknown operator") + (assert_malformed (module quote "(@)") "malformed annotation id") (assert_malformed (module quote "(@ )") "malformed annotation id") (assert_malformed (module quote "(@ x)") "malformed annotation id") +(assert_malformed (module quote "(@(@a)x)") "malformed annotation id") (assert_malformed (module quote "(@x ") "unclosed annotation") (assert_malformed (module quote "(@x ()") "unclosed annotation") @@ -32,6 +35,7 @@ (assert_malformed (module quote "(@x (@y )))") "unexpected token") (assert_malformed (module quote "(@x \"") "unclosed string") +(assert_malformed (module quote "(@x \")") "unclosed string") (assert_malformed (module quote "((@a)@b)") "unknown operator") (assert_malformed (module quote "(func $(@a))") "unknown operator") From f11bb0b2a96c0425b849525ff3f01557ff5af8f8 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Sun, 28 Apr 2019 08:03:40 +0200 Subject: [PATCH 009/130] Allow comma --- document/core/text/lexical.rst | 2 +- test/core/annotations.wast | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/document/core/text/lexical.rst b/document/core/text/lexical.rst index c008b87939..bf7210c822 100644 --- a/document/core/text/lexical.rst +++ b/document/core/text/lexical.rst @@ -50,7 +50,7 @@ The character stream in the source text is divided, from left to right, into a s (\text{a} ~|~ \dots ~|~ \text{z})~\Tidchar^\ast \qquad (\mbox{if occurring as a literal terminal in the grammar}) \\ \production{reserved} & \Treserved &::=& - \Tidchar^+ ~|~ \text{;} ~|~ \text{[} ~|~ \text{]} ~|~ \text{\{} ~|~ \text{\}} \\ + \Tidchar^+ ~|~ \text{,} ~|~ \text{;} ~|~ \text{[} ~|~ \text{]} ~|~ \text{\{} ~|~ \text{\}} \\ \end{array} Tokens are formed from the input character stream according to the *longest match* rule. diff --git a/test/core/annotations.wast b/test/core/annotations.wast index e8562ad2fa..ca778285be 100644 --- a/test/core/annotations.wast +++ b/test/core/annotations.wast @@ -6,7 +6,7 @@ (@a x-y$yz"aa"-2) (@a block func module i32.add) (@a 0x 8q 0xfa #4g0-.@f#^&@#$*0sf -- @#) -(@a ; ] [ }} }x{ ({) {{};}] ;) +(@a , ; ] [ }} }x{ ({) ,{{};}] ;) (@a (bla) () (5-g) ("aa" a) ($x) (bla bla) (x (y)) ")" "(" x")"y) (@a @ @x (@x) (@x y) (@) (@ x) (@(@(@(@))))) (@a Heiße Würstchen   From 33f8dab29762d3f9664229f5d3e719dff8096b33 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Mon, 24 Feb 2020 14:04:12 +0100 Subject: [PATCH 010/130] [test] Remove bogus test (#7) --- test/core/annotations.wast | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/core/annotations.wast b/test/core/annotations.wast index ca778285be..0d19d21301 100644 --- a/test/core/annotations.wast +++ b/test/core/annotations.wast @@ -9,9 +9,6 @@ (@a , ; ] [ }} }x{ ({) ,{{};}] ;) (@a (bla) () (5-g) ("aa" a) ($x) (bla bla) (x (y)) ")" "(" x")"y) (@a @ @x (@x) (@x y) (@) (@ x) (@(@(@(@))))) -(@a Heiße Würstchen   - -) (@a (;bla;) (; ) ;) ;; bla) ;; bla (@x From 45539165cb66db5ed360fb70c7ae1a7363e7cf4a Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Thu, 19 Mar 2020 13:23:24 +0100 Subject: [PATCH 011/130] [interpreter] Simplify keyword lexing (#8) --- interpreter/Makefile | 2 +- interpreter/text/lexer.mll | 493 +++++++++++++++++++------------------ test/core/annotations.wast | 4 + 3 files changed, 260 insertions(+), 239 deletions(-) diff --git a/interpreter/Makefile b/interpreter/Makefile index 7b44c1199b..5bb3ea39c1 100644 --- a/interpreter/Makefile +++ b/interpreter/Makefile @@ -19,7 +19,7 @@ WINMAKE = winmake.bat DIRS = util syntax binary text valid runtime exec script host main LIBS = bigarray -FLAGS = -cflags '-w +a-4-27-42-44-45 -warn-error +a' +FLAGS = -cflags '-w +a-4-27-42-44-45 -warn-error +a-3' OCB = ocamlbuild $(FLAGS) $(DIRS:%=-I %) $(LIBS:%=-libs %) JS = # set to JS shell command to run JS tests diff --git a/interpreter/text/lexer.mll b/interpreter/text/lexer.mll index 6aa5abb698..25d6c16d02 100644 --- a/interpreter/text/lexer.mll +++ b/interpreter/text/lexer.mll @@ -1,17 +1,18 @@ { open Parser open Operators +open Source let convert_pos pos = - { Source.file = pos.Lexing.pos_fname; - Source.line = pos.Lexing.pos_lnum; - Source.column = pos.Lexing.pos_cnum - pos.Lexing.pos_bol + { file = pos.Lexing.pos_fname; + line = pos.Lexing.pos_lnum; + column = pos.Lexing.pos_cnum - pos.Lexing.pos_bol } let region lexbuf = let left = convert_pos (Lexing.lexeme_start_p lexbuf) in let right = convert_pos (Lexing.lexeme_end_p lexbuf) in - {Source.left = left; Source.right = right} + {left = left; right = right} let error lexbuf msg = raise (Script.Syntax (region lexbuf, msg)) let error_nest start lexbuf msg = @@ -45,46 +46,6 @@ let string s = done; Buffer.contents b -let value_type = function - | "i32" -> Types.I32Type - | "i64" -> Types.I64Type - | "f32" -> Types.F32Type - | "f64" -> Types.F64Type - | _ -> assert false - -let intop t i32 i64 = - match t with - | "i32" -> i32 - | "i64" -> i64 - | _ -> assert false - -let floatop t f32 f64 = - match t with - | "f32" -> f32 - | "f64" -> f64 - | _ -> assert false - -let numop t i32 i64 f32 f64 = - match t with - | "i32" -> i32 - | "i64" -> i64 - | "f32" -> f32 - | "f64" -> f64 - | _ -> assert false - -let memsz sz m8 m16 m32 = - match sz with - | "8" -> m8 - | "16" -> m16 - | "32" -> m32 - | _ -> assert false - -let ext e s u = - match e with - | 's' -> s - | 'u' -> u - | _ -> assert false - let opt = Lib.Option.get } @@ -135,10 +96,12 @@ let float = | sign? "nan:" "0x" hexnum let string = '"' character* '"' -let id = (letter | digit | '_' | symbol)+ -let name = '$' id +let idchar = letter | digit | '_' | symbol +let name = idchar+ +let id = '$' name -let reserved = ';' | ([^'\"''('')'';'] # space)+ (* hack for table size *) +let keyword = ['a'-'z'] (letter | digit | '_' | '.')+ +let reserved = name | ',' | ';' | '[' | ']' | '{' | '}' let ixx = "i" ("32" | "64") let fxx = "f" ("32" | "64") @@ -163,200 +126,254 @@ rule token = parse | '"'character*'\\'_ { error_nest (Lexing.lexeme_end_p lexbuf) lexbuf "illegal escape" } - | (nxx as t) { VALUE_TYPE (value_type t) } - | (nxx as t)".const" - { let open Source in - CONST (numop t - (fun s -> let n = I32.of_string s.it in - i32_const (n @@ s.at), Values.I32 n) - (fun s -> let n = I64.of_string s.it in - i64_const (n @@ s.at), Values.I64 n) - (fun s -> let n = F32.of_string s.it in - f32_const (n @@ s.at), Values.F32 n) - (fun s -> let n = F64.of_string s.it in - f64_const (n @@ s.at), Values.F64 n)) + | keyword as s + { match s with + | "i32" -> VALUE_TYPE Types.I32Type + | "i64" -> VALUE_TYPE Types.I64Type + | "f32" -> VALUE_TYPE Types.F32Type + | "f64" -> VALUE_TYPE Types.F64Type + | "funcref" -> FUNCREF + | "mut" -> MUT + + | "nop" -> NOP + | "unreachable" -> UNREACHABLE + | "drop" -> DROP + | "block" -> BLOCK + | "loop" -> LOOP + | "end" -> END + | "br" -> BR + | "br_if" -> BR_IF + | "br_table" -> BR_TABLE + | "return" -> RETURN + | "if" -> IF + | "then" -> THEN + | "else" -> ELSE + | "select" -> SELECT + | "call" -> CALL + | "call_indirect" -> CALL_INDIRECT + + | "local.get" -> LOCAL_GET + | "local.set" -> LOCAL_SET + | "local.tee" -> LOCAL_TEE + | "global.get" -> GLOBAL_GET + | "global.set" -> GLOBAL_SET + + | "i32.load" -> LOAD (fun a o -> i32_load (opt a 2) o) + | "i64.load" -> LOAD (fun a o -> i64_load (opt a 3) o) + | "f32.load" -> LOAD (fun a o -> f32_load (opt a 2) o) + | "f64.load" -> LOAD (fun a o -> f64_load (opt a 3) o) + | "i32.store" -> STORE (fun a o -> i32_store (opt a 2) o) + | "i64.store" -> STORE (fun a o -> i64_store (opt a 3) o) + | "f32.store" -> STORE (fun a o -> f32_store (opt a 2) o) + | "f64.store" -> STORE (fun a o -> f64_store (opt a 3) o) + + | "i32.load8_u" -> LOAD (fun a o -> i32_load8_u (opt a 0) o) + | "i32.load8_s" -> LOAD (fun a o -> i32_load8_s (opt a 0) o) + | "i32.load16_u" -> LOAD (fun a o -> i32_load16_u (opt a 1) o) + | "i32.load16_s" -> LOAD (fun a o -> i32_load16_s (opt a 1) o) + | "i64.load8_u" -> LOAD (fun a o -> i64_load8_u (opt a 0) o) + | "i64.load8_s" -> LOAD (fun a o -> i64_load8_s (opt a 0) o) + | "i64.load16_u" -> LOAD (fun a o -> i64_load16_u (opt a 1) o) + | "i64.load16_s" -> LOAD (fun a o -> i64_load16_s (opt a 1) o) + | "i64.load32_u" -> LOAD (fun a o -> i64_load32_u (opt a 2) o) + | "i64.load32_s" -> LOAD (fun a o -> i64_load32_s (opt a 2) o) + + | "i32.store8" -> LOAD (fun a o -> i32_store8 (opt a 0) o) + | "i32.store16" -> LOAD (fun a o -> i32_store16 (opt a 1) o) + | "i64.store8" -> LOAD (fun a o -> i64_store8 (opt a 0) o) + | "i64.store16" -> LOAD (fun a o -> i64_store16 (opt a 1) o) + | "i64.store32" -> LOAD (fun a o -> i64_store32 (opt a 2) o) + + | "i32.const" -> + CONST (fun s -> + let n = I32.of_string s.it in i32_const (n @@ s.at), Values.I32 n) + | "i64.const" -> + CONST (fun s -> + let n = I64.of_string s.it in i64_const (n @@ s.at), Values.I64 n) + | "f32.const" -> + CONST (fun s -> + let n = F32.of_string s.it in f32_const (n @@ s.at), Values.F32 n) + | "f64.const" -> + CONST (fun s -> + let n = F64.of_string s.it in f64_const (n @@ s.at), Values.F64 n) + + | "i32.clz" -> UNARY i32_clz + | "i32.ctz" -> UNARY i32_ctz + | "i32.popcnt" -> UNARY i32_popcnt + | "i64.clz" -> UNARY i64_clz + | "i64.ctz" -> UNARY i64_ctz + | "i64.popcnt" -> UNARY i64_popcnt + + | "f32.neg" -> UNARY f32_neg + | "f32.abs" -> UNARY f32_abs + | "f32.sqrt" -> UNARY f32_sqrt + | "f32.ceil" -> UNARY f32_ceil + | "f32.floor" -> UNARY f32_floor + | "f32.trunc" -> UNARY f32_trunc + | "f32.nearest" -> UNARY f32_nearest + | "f64.neg" -> UNARY f64_neg + | "f64.abs" -> UNARY f64_abs + | "f64.sqrt" -> UNARY f64_sqrt + | "f64.ceil" -> UNARY f64_ceil + | "f64.floor" -> UNARY f64_floor + | "f64.trunc" -> UNARY f64_trunc + | "f64.nearest" -> UNARY f64_nearest + + | "i32.add" -> BINARY i32_add + | "i32.sub" -> BINARY i32_sub + | "i32.mul" -> BINARY i32_mul + | "i32.div_u" -> BINARY i32_div_u + | "i32.div_s" -> BINARY i32_div_s + | "i32.rem_u" -> BINARY i32_rem_u + | "i32.rem_s" -> BINARY i32_rem_s + | "i32.and" -> BINARY i32_and + | "i32.or" -> BINARY i32_or + | "i32.xor" -> BINARY i32_xor + | "i32.shl" -> BINARY i32_shl + | "i32.shr_u" -> BINARY i32_shr_u + | "i32.shr_s" -> BINARY i32_shr_s + | "i32.rotl" -> BINARY i32_rotl + | "i32.rotr" -> BINARY i32_rotr + | "i64.add" -> BINARY i64_add + | "i64.sub" -> BINARY i64_sub + | "i64.mul" -> BINARY i64_mul + | "i64.div_u" -> BINARY i64_div_u + | "i64.div_s" -> BINARY i64_div_s + | "i64.rem_u" -> BINARY i64_rem_u + | "i64.rem_s" -> BINARY i64_rem_s + | "i64.and" -> BINARY i64_and + | "i64.or" -> BINARY i64_or + | "i64.xor" -> BINARY i64_xor + | "i64.shl" -> BINARY i64_shl + | "i64.shr_u" -> BINARY i64_shr_u + | "i64.shr_s" -> BINARY i64_shr_s + | "i64.rotl" -> BINARY i64_rotl + | "i64.rotr" -> BINARY i64_rotr + + | "f32.add" -> BINARY f32_add + | "f32.sub" -> BINARY f32_sub + | "f32.mul" -> BINARY f32_mul + | "f32.div" -> BINARY f32_div + | "f32.min" -> BINARY f32_min + | "f32.max" -> BINARY f32_max + | "f32.copysign" -> BINARY f32_copysign + | "f64.add" -> BINARY f64_add + | "f64.sub" -> BINARY f64_sub + | "f64.mul" -> BINARY f64_mul + | "f64.div" -> BINARY f64_div + | "f64.min" -> BINARY f64_min + | "f64.max" -> BINARY f64_max + | "f64.copysign" -> BINARY f64_copysign + + | "i32.eqz" -> TEST i32_eqz + | "i64.eqz" -> TEST i64_eqz + + | "i32.eq" -> COMPARE i32_eq + | "i32.ne" -> COMPARE i32_ne + | "i32.lt_u" -> COMPARE i32_lt_u + | "i32.lt_s" -> COMPARE i32_lt_s + | "i32.le_u" -> COMPARE i32_le_u + | "i32.le_s" -> COMPARE i32_le_s + | "i32.gt_u" -> COMPARE i32_gt_u + | "i32.gt_s" -> COMPARE i32_gt_s + | "i32.ge_u" -> COMPARE i32_ge_u + | "i32.ge_s" -> COMPARE i32_ge_s + | "i64.eq" -> COMPARE i64_eq + | "i64.ne" -> COMPARE i64_ne + | "i64.lt_u" -> COMPARE i64_lt_u + | "i64.lt_s" -> COMPARE i64_lt_s + | "i64.le_u" -> COMPARE i64_le_u + | "i64.le_s" -> COMPARE i64_le_s + | "i64.gt_u" -> COMPARE i64_gt_u + | "i64.gt_s" -> COMPARE i64_gt_s + | "i64.ge_u" -> COMPARE i64_ge_u + | "i64.ge_s" -> COMPARE i64_ge_s + + | "f32.eq" -> COMPARE f32_eq + | "f32.ne" -> COMPARE f32_ne + | "f32.lt" -> COMPARE f32_lt + | "f32.le" -> COMPARE f32_le + | "f32.gt" -> COMPARE f32_gt + | "f32.ge" -> COMPARE f32_ge + | "f64.eq" -> COMPARE f64_eq + | "f64.ne" -> COMPARE f64_ne + | "f64.lt" -> COMPARE f64_lt + | "f64.le" -> COMPARE f64_le + | "f64.gt" -> COMPARE f64_gt + | "f64.ge" -> COMPARE f64_ge + + | "i32.wrap_i64" -> CONVERT i32_wrap_i64 + | "i64.extend_i32_s" -> CONVERT i64_extend_i32_s + | "i64.extend_i32_u" -> CONVERT i64_extend_i32_u + | "f32.demote_f64" -> CONVERT f32_demote_f64 + | "f64.promote_f32" -> CONVERT f64_promote_f32 + | "i32.trunc_f32_u" -> CONVERT i32_trunc_f32_u + | "i32.trunc_f32_s" -> CONVERT i32_trunc_f32_s + | "i64.trunc_f32_u" -> CONVERT i64_trunc_f32_u + | "i64.trunc_f32_s" -> CONVERT i64_trunc_f32_s + | "i32.trunc_f64_u" -> CONVERT i32_trunc_f64_u + | "i32.trunc_f64_s" -> CONVERT i32_trunc_f64_s + | "i64.trunc_f64_u" -> CONVERT i64_trunc_f64_u + | "i64.trunc_f64_s" -> CONVERT i64_trunc_f64_s + | "f32.convert_i32_u" -> CONVERT f32_convert_i32_u + | "f32.convert_i32_s" -> CONVERT f32_convert_i32_s + | "f64.convert_i32_u" -> CONVERT f64_convert_i32_u + | "f64.convert_i32_s" -> CONVERT f64_convert_i32_s + | "f32.convert_i64_u" -> CONVERT f32_convert_i64_u + | "f32.convert_i64_s" -> CONVERT f32_convert_i64_s + | "f64.convert_i64_u" -> CONVERT f64_convert_i64_u + | "f64.convert_i64_s" -> CONVERT f64_convert_i64_s + | "f32.reinterpret_i32" -> CONVERT f32_reinterpret_i32 + | "f64.reinterpret_i64" -> CONVERT f64_reinterpret_i64 + | "i32.reinterpret_f32" -> CONVERT i32_reinterpret_f32 + | "i64.reinterpret_f64" -> CONVERT i64_reinterpret_f64 + + | "memory.size" -> MEMORY_SIZE + | "memory.grow" -> MEMORY_GROW + + | "type" -> TYPE + | "func" -> FUNC + | "param" -> PARAM + | "result" -> RESULT + | "start" -> START + | "local" -> LOCAL + | "global" -> GLOBAL + | "table" -> TABLE + | "memory" -> MEMORY + | "elem" -> ELEM + | "data" -> DATA + | "offset" -> OFFSET + | "import" -> IMPORT + | "export" -> EXPORT + + | "module" -> MODULE + | "binary" -> BIN + | "quote" -> QUOTE + + | "script" -> SCRIPT + | "register" -> REGISTER + | "invoke" -> INVOKE + | "get" -> GET + | "assert_malformed" -> ASSERT_MALFORMED + | "assert_invalid" -> ASSERT_INVALID + | "assert_unlinkable" -> ASSERT_UNLINKABLE + | "assert_return" -> ASSERT_RETURN + | "assert_return_canonical_nan" -> ASSERT_RETURN_CANONICAL_NAN + | "assert_return_arithmetic_nan" -> ASSERT_RETURN_ARITHMETIC_NAN + | "assert_trap" -> ASSERT_TRAP + | "assert_exhaustion" -> ASSERT_EXHAUSTION + | "input" -> INPUT + | "output" -> OUTPUT + + | _ -> error lexbuf "unknown operator" } - | "funcref" { FUNCREF } - | "mut" { MUT } - - | "nop" { NOP } - | "unreachable" { UNREACHABLE } - | "drop" { DROP } - | "block" { BLOCK } - | "loop" { LOOP } - | "end" { END } - | "br" { BR } - | "br_if" { BR_IF } - | "br_table" { BR_TABLE } - | "return" { RETURN } - | "if" { IF } - | "then" { THEN } - | "else" { ELSE } - | "select" { SELECT } - | "call" { CALL } - | "call_indirect" { CALL_INDIRECT } - - | "local.get" { LOCAL_GET } - | "local.set" { LOCAL_SET } - | "local.tee" { LOCAL_TEE } - | "global.get" { GLOBAL_GET } - | "global.set" { GLOBAL_SET } - - | (nxx as t)".load" - { LOAD (fun a o -> - numop t (i32_load (opt a 2)) (i64_load (opt a 3)) - (f32_load (opt a 2)) (f64_load (opt a 3)) o) } - | (nxx as t)".store" - { STORE (fun a o -> - numop t (i32_store (opt a 2)) (i64_store (opt a 3)) - (f32_store (opt a 2)) (f64_store (opt a 3)) o) } - | (ixx as t)".load"(mem_size as sz)"_"(sign as s) - { if t = "i32" && sz = "32" then error lexbuf "unknown operator"; - LOAD (fun a o -> - intop t - (memsz sz - (ext s i32_load8_s i32_load8_u (opt a 0)) - (ext s i32_load16_s i32_load16_u (opt a 1)) - (fun _ -> unreachable) o) - (memsz sz - (ext s i64_load8_s i64_load8_u (opt a 0)) - (ext s i64_load16_s i64_load16_u (opt a 1)) - (ext s i64_load32_s i64_load32_u (opt a 2)) o)) } - | (ixx as t)".store"(mem_size as sz) - { if t = "i32" && sz = "32" then error lexbuf "unknown operator"; - STORE (fun a o -> - intop t - (memsz sz - (i32_store8 (opt a 0)) - (i32_store16 (opt a 1)) - (fun _ -> unreachable) o) - (memsz sz - (i64_store8 (opt a 0)) - (i64_store16 (opt a 1)) - (i64_store32 (opt a 2)) o)) } | "offset="(nat as s) { OFFSET_EQ_NAT s } | "align="(nat as s) { ALIGN_EQ_NAT s } - | (ixx as t)".clz" { UNARY (intop t i32_clz i64_clz) } - | (ixx as t)".ctz" { UNARY (intop t i32_ctz i64_ctz) } - | (ixx as t)".popcnt" { UNARY (intop t i32_popcnt i64_popcnt) } - | (fxx as t)".neg" { UNARY (floatop t f32_neg f64_neg) } - | (fxx as t)".abs" { UNARY (floatop t f32_abs f64_abs) } - | (fxx as t)".sqrt" { UNARY (floatop t f32_sqrt f64_sqrt) } - | (fxx as t)".ceil" { UNARY (floatop t f32_ceil f64_ceil) } - | (fxx as t)".floor" { UNARY (floatop t f32_floor f64_floor) } - | (fxx as t)".trunc" { UNARY (floatop t f32_trunc f64_trunc) } - | (fxx as t)".nearest" { UNARY (floatop t f32_nearest f64_nearest) } - - | (ixx as t)".add" { BINARY (intop t i32_add i64_add) } - | (ixx as t)".sub" { BINARY (intop t i32_sub i64_sub) } - | (ixx as t)".mul" { BINARY (intop t i32_mul i64_mul) } - | (ixx as t)".div_s" { BINARY (intop t i32_div_s i64_div_s) } - | (ixx as t)".div_u" { BINARY (intop t i32_div_u i64_div_u) } - | (ixx as t)".rem_s" { BINARY (intop t i32_rem_s i64_rem_s) } - | (ixx as t)".rem_u" { BINARY (intop t i32_rem_u i64_rem_u) } - | (ixx as t)".and" { BINARY (intop t i32_and i64_and) } - | (ixx as t)".or" { BINARY (intop t i32_or i64_or) } - | (ixx as t)".xor" { BINARY (intop t i32_xor i64_xor) } - | (ixx as t)".shl" { BINARY (intop t i32_shl i64_shl) } - | (ixx as t)".shr_s" { BINARY (intop t i32_shr_s i64_shr_s) } - | (ixx as t)".shr_u" { BINARY (intop t i32_shr_u i64_shr_u) } - | (ixx as t)".rotl" { BINARY (intop t i32_rotl i64_rotl) } - | (ixx as t)".rotr" { BINARY (intop t i32_rotr i64_rotr) } - | (fxx as t)".add" { BINARY (floatop t f32_add f64_add) } - | (fxx as t)".sub" { BINARY (floatop t f32_sub f64_sub) } - | (fxx as t)".mul" { BINARY (floatop t f32_mul f64_mul) } - | (fxx as t)".div" { BINARY (floatop t f32_div f64_div) } - | (fxx as t)".min" { BINARY (floatop t f32_min f64_min) } - | (fxx as t)".max" { BINARY (floatop t f32_max f64_max) } - | (fxx as t)".copysign" { BINARY (floatop t f32_copysign f64_copysign) } - - | (ixx as t)".eqz" { TEST (intop t i32_eqz i64_eqz) } - - | (ixx as t)".eq" { COMPARE (intop t i32_eq i64_eq) } - | (ixx as t)".ne" { COMPARE (intop t i32_ne i64_ne) } - | (ixx as t)".lt_s" { COMPARE (intop t i32_lt_s i64_lt_s) } - | (ixx as t)".lt_u" { COMPARE (intop t i32_lt_u i64_lt_u) } - | (ixx as t)".le_s" { COMPARE (intop t i32_le_s i64_le_s) } - | (ixx as t)".le_u" { COMPARE (intop t i32_le_u i64_le_u) } - | (ixx as t)".gt_s" { COMPARE (intop t i32_gt_s i64_gt_s) } - | (ixx as t)".gt_u" { COMPARE (intop t i32_gt_u i64_gt_u) } - | (ixx as t)".ge_s" { COMPARE (intop t i32_ge_s i64_ge_s) } - | (ixx as t)".ge_u" { COMPARE (intop t i32_ge_u i64_ge_u) } - | (fxx as t)".eq" { COMPARE (floatop t f32_eq f64_eq) } - | (fxx as t)".ne" { COMPARE (floatop t f32_ne f64_ne) } - | (fxx as t)".lt" { COMPARE (floatop t f32_lt f64_lt) } - | (fxx as t)".le" { COMPARE (floatop t f32_le f64_le) } - | (fxx as t)".gt" { COMPARE (floatop t f32_gt f64_gt) } - | (fxx as t)".ge" { COMPARE (floatop t f32_ge f64_ge) } - - | "i32.wrap_i64" { CONVERT i32_wrap_i64 } - | "i64.extend_i32_s" { CONVERT i64_extend_i32_s } - | "i64.extend_i32_u" { CONVERT i64_extend_i32_u } - | "f32.demote_f64" { CONVERT f32_demote_f64 } - | "f64.promote_f32" { CONVERT f64_promote_f32 } - | (ixx as t)".trunc_f32_s" - { CONVERT (intop t i32_trunc_f32_s i64_trunc_f32_s) } - | (ixx as t)".trunc_f32_u" - { CONVERT (intop t i32_trunc_f32_u i64_trunc_f32_u) } - | (ixx as t)".trunc_f64_s" - { CONVERT (intop t i32_trunc_f64_s i64_trunc_f64_s) } - | (ixx as t)".trunc_f64_u" - { CONVERT (intop t i32_trunc_f64_u i64_trunc_f64_u) } - | (fxx as t)".convert_i32_s" - { CONVERT (floatop t f32_convert_i32_s f64_convert_i32_s) } - | (fxx as t)".convert_i32_u" - { CONVERT (floatop t f32_convert_i32_u f64_convert_i32_u) } - | (fxx as t)".convert_i64_s" - { CONVERT (floatop t f32_convert_i64_s f64_convert_i64_s) } - | (fxx as t)".convert_i64_u" - { CONVERT (floatop t f32_convert_i64_u f64_convert_i64_u) } - | "f32.reinterpret_i32" { CONVERT f32_reinterpret_i32 } - | "f64.reinterpret_i64" { CONVERT f64_reinterpret_i64 } - | "i32.reinterpret_f32" { CONVERT i32_reinterpret_f32 } - | "i64.reinterpret_f64" { CONVERT i64_reinterpret_f64 } - - | "memory.size" { MEMORY_SIZE } - | "memory.grow" { MEMORY_GROW } - - | "type" { TYPE } - | "func" { FUNC } - | "start" { START } - | "param" { PARAM } - | "result" { RESULT } - | "local" { LOCAL } - | "global" { GLOBAL } - | "table" { TABLE } - | "memory" { MEMORY } - | "elem" { ELEM } - | "data" { DATA } - | "offset" { OFFSET } - | "import" { IMPORT } - | "export" { EXPORT } - - | "module" { MODULE } - | "binary" { BIN } - | "quote" { QUOTE } - - | "script" { SCRIPT } - | "register" { REGISTER } - | "invoke" { INVOKE } - | "get" { GET } - | "assert_malformed" { ASSERT_MALFORMED } - | "assert_invalid" { ASSERT_INVALID } - | "assert_unlinkable" { ASSERT_UNLINKABLE } - | "assert_return" { ASSERT_RETURN } - | "assert_return_canonical_nan" { ASSERT_RETURN_CANONICAL_NAN } - | "assert_return_arithmetic_nan" { ASSERT_RETURN_ARITHMETIC_NAN } - | "assert_trap" { ASSERT_TRAP } - | "assert_exhaustion" { ASSERT_EXHAUSTION } - | "input" { INPUT } - | "output" { OUTPUT } - - | name as s { VAR s } - - | "(@"id { annot (Lexing.lexeme_start_p lexbuf) lexbuf; token lexbuf } + | id as s { VAR s } + + | "(@"name { annot (Lexing.lexeme_start_p lexbuf) lexbuf; token lexbuf } | "(@" { error lexbuf "malformed annotation id" } | ";;"utf8_no_nl*eof { EOF } @@ -368,7 +385,7 @@ rule token = parse | eof { EOF } | reserved { error lexbuf "unknown operator" } - | utf8 { error lexbuf "malformed operator" } + | utf8 { error lexbuf "illegal character" } | _ { error lexbuf "malformed UTF-8 encoding" } and annot start = parse @@ -380,7 +397,6 @@ and annot start = parse | int { annot start lexbuf } | float { annot start lexbuf } | id { annot start lexbuf } - | name { annot start lexbuf } | string { annot start lexbuf } | '"'character*('\n'|eof) { error lexbuf "unclosed string literal" } | '"'character*['\x00'-'\x09''\x0b'-'\x1f''\x7f'] @@ -395,6 +411,7 @@ and annot start = parse | space#'\n' { annot start lexbuf } | '\n' { Lexing.new_line lexbuf; annot start lexbuf } | eof { error_nest start lexbuf "unclosed annotation" } + | utf8 { error lexbuf "illegal character" } | _ { error lexbuf "malformed UTF-8 encoding" } and comment start = parse diff --git a/test/core/annotations.wast b/test/core/annotations.wast index 0d19d21301..ad97389537 100644 --- a/test/core/annotations.wast +++ b/test/core/annotations.wast @@ -1,4 +1,5 @@ (@a) + (@aas-3!@$d-@#4) (@@) (@$) (@+) (@0) (@.) (@!$@#$23414@#$) (@a x y z) @@ -14,6 +15,9 @@ ;; bla (@x ) +(assert_malformed (module quote "(@a Heiße Würstchen)") "illegal character") +(assert_malformed (module quote "(@a )") "illegal character") + (assert_malformed (module quote "( @a)") "unknown operator") (assert_malformed (module quote "(@)") "malformed annotation id") From 318622f0b1edd6377d937172ed9b221dda346959 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Thu, 19 Mar 2020 17:32:32 +0100 Subject: [PATCH 012/130] [test] Add more lexing tests (#9) --- test/core/annotations.wast | 44 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/test/core/annotations.wast b/test/core/annotations.wast index ad97389537..ce538d9371 100644 --- a/test/core/annotations.wast +++ b/test/core/annotations.wast @@ -15,6 +15,50 @@ ;; bla (@x ) +(assert_malformed (module quote "(@a \00)") "illegal character") +(assert_malformed (module quote "(@a \01)") "illegal character") +(assert_malformed (module quote "(@a \02)") "illegal character") +(assert_malformed (module quote "(@a \03)") "illegal character") +(assert_malformed (module quote "(@a \04)") "illegal character") +(assert_malformed (module quote "(@a \05)") "illegal character") +(assert_malformed (module quote "(@a \06)") "illegal character") +(assert_malformed (module quote "(@a \07)") "illegal character") +(assert_malformed (module quote "(@a \08)") "illegal character") +(module quote "(@a \09)") ;; \t +(module quote "(@a \0a)") ;; \n +(assert_malformed (module quote "(@a \0b)") "illegal character") +(assert_malformed (module quote "(@a \0c)") "illegal character") +(module quote "(@a \0d)") ;; \r +(assert_malformed (module quote "(@a \0e)") "illegal character") +(assert_malformed (module quote "(@a \0f)") "illegal character") +(assert_malformed (module quote "(@a \10)") "illegal character") +(assert_malformed (module quote "(@a \11)") "illegal character") +(assert_malformed (module quote "(@a \12)") "illegal character") +(assert_malformed (module quote "(@a \13)") "illegal character") +(assert_malformed (module quote "(@a \14)") "illegal character") +(assert_malformed (module quote "(@a \15)") "illegal character") +(assert_malformed (module quote "(@a \16)") "illegal character") +(assert_malformed (module quote "(@a \17)") "illegal character") +(assert_malformed (module quote "(@a \18)") "illegal character") +(assert_malformed (module quote "(@a \19)") "illegal character") +(assert_malformed (module quote "(@a \1a)") "illegal character") +(assert_malformed (module quote "(@a \1b)") "illegal character") +(assert_malformed (module quote "(@a \1c)") "illegal character") +(assert_malformed (module quote "(@a \1d)") "illegal character") +(assert_malformed (module quote "(@a \1e)") "illegal character") +(assert_malformed (module quote "(@a \1f)") "illegal character") +(module quote "(@a \20)") ;; space +(assert_malformed (module quote "(@a \7f)") "illegal character") +(assert_malformed (module quote "(@a \80)") "malformed UTF-8 encoding") +(assert_malformed (module quote "(@a \81)") "malformed UTF-8 encoding") +(assert_malformed (module quote "(@a \90)") "malformed UTF-8 encoding") +(assert_malformed (module quote "(@a \a0)") "malformed UTF-8 encoding") +(assert_malformed (module quote "(@a \b0)") "malformed UTF-8 encoding") +(assert_malformed (module quote "(@a \c0)") "malformed UTF-8 encoding") +(assert_malformed (module quote "(@a \d0)") "malformed UTF-8 encoding") +(assert_malformed (module quote "(@a \e0)") "malformed UTF-8 encoding") +(assert_malformed (module quote "(@a \f0)") "malformed UTF-8 encoding") +(assert_malformed (module quote "(@a \ff)") "malformed UTF-8 encoding") (assert_malformed (module quote "(@a Heiße Würstchen)") "illegal character") (assert_malformed (module quote "(@a )") "illegal character") From 7f3a876b1b807a9f032650c04cb2a8ae7c5bfed6 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Tue, 9 Nov 2021 09:36:14 +0100 Subject: [PATCH 013/130] Fix function keyword --- proposals/annotations/Overview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/annotations/Overview.md b/proposals/annotations/Overview.md index 590d6030e9..47d1a58a79 100644 --- a/proposals/annotations/Overview.md +++ b/proposals/annotations/Overview.md @@ -49,7 +49,7 @@ Extend the Appendix on the Custom Sections: Expressing generic custom sections (cf. https://gist.github.com/binji/d1cfff7faaebb2aa4f8b1c995234e5a0) ```wasm (module - (@custom "my-fancy-section" (after function) "contents-bytes") + (@custom "my-fancy-section" (after func) "contents-bytes") ) ``` From 88a0fbb45cd8692533fcd3af7ed630f7e7b66f2c Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Tue, 9 Nov 2021 16:25:55 +0100 Subject: [PATCH 014/130] Clarify @custom (#16) --- document/core/appendix/custom.rst | 4 +++- proposals/annotations/Overview.md | 25 +++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/document/core/appendix/custom.rst b/document/core/appendix/custom.rst index 79dceb15a0..034779d29e 100644 --- a/document/core/appendix/custom.rst +++ b/document/core/appendix/custom.rst @@ -273,7 +273,8 @@ They must not be nested into other constructs. \text{start} \\ &&|& \text{elem} \\ &&|& \text{code} \\ &&|& - \text{data} \\ + \text{data} \\ &&|& + \text{datacount} \\ \end{array} The first :ref:`string ` in a custom annotation denotes the name of the custom section it represents. @@ -282,6 +283,7 @@ The remaining strings collectively represent the section's payload data, written An arbitrary number of custom annotations (even of the same name) may occur in a module, each defining a separate custom section when converting to :ref:`binary format `. Placement of the sections in the binary can be customized via explicit *placement* directives, that position them either directly before or directly after a known section. +That section must exist and be non-empty in the binary encoding of the annotated module. The placements :math:`\T{(before~first)}` and :math:`\T{(after~last)}` denote virtual sections before the first and after the last known section, respectively. When the placement directive is omitted, it defaults to :math:`\T{(after~last)}`. diff --git a/proposals/annotations/Overview.md b/proposals/annotations/Overview.md index 47d1a58a79..4bd2a0ba87 100644 --- a/proposals/annotations/Overview.md +++ b/proposals/annotations/Overview.md @@ -41,6 +41,31 @@ Extend the Appendix on the Custom Sections: They may be placed after the binder for any construct that can be named by the name section. * Define annotation syntax expressing arbitrary custom sections; cf. https://gist.github.com/binji/d1cfff7faaebb2aa4f8b1c995234e5a0 + + With that, a custom section annotation is specified as follows: + ``` + custom ::= '(' '@custom' string place? datastring ')' + place ::= + | '(' 'before' section ')' + | '(' 'after' section ')' + | '(' 'before' 'first' ')' + | '(' 'after' 'last' ')' + section ::= + | 'type' + | 'import' + | 'func' + | 'table' + | 'memory' + | 'global' + | 'export' + | 'start' + | 'elem' + | 'code' + | 'data' + | 'datacount' + ``` + If placement relative to an explicit section is used, then that section must exist in the encoding of the annotated module. + As with any matter concerning annotations, it is up to implementations how they handle the case where an explicit custom section overlaps with individual annotations that are associated with the same custom section. From 9d07ed0e89a454cb965a5c669b37bc7bdad3b238 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Fri, 18 Feb 2022 17:27:35 +0100 Subject: [PATCH 015/130] Fix conf --- document/core/conf.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/document/core/conf.py b/document/core/conf.py index 1cde497d75..3bc2eb66d6 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 = 'annotations' # The name of the proposal it represents, if any -proposal = '' +proposal = 'custom annotations' # The draft version string (clear out for release cuts) draft = ' (Draft ' + date.today().strftime("%Y-%m-%d") + ')' From f857c7ccc9f43148d32fbe4e4ab9c3d3724114e5 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Fri, 18 Feb 2022 20:57:12 +0100 Subject: [PATCH 016/130] Link to spec --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 93e3300c92..80851cced4 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@ It is meant for discussion, prototype specification and implementation of a prop See the [overview](proposals/annotations/Overview.md) for a summary of the proposal. +See draft spec at [webassembly.github.io/annotations](https://webassembly.github.io/annotations/). + Original `README` from upstream repository follows... # spec From 87a3a3dc99ecfeabe364ca5b23955a773b294467 Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Thu, 8 Oct 2020 11:44:46 +0200 Subject: [PATCH 017/130] Update README.md --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 80851cced4..35a4eebabc 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,15 @@ See draft spec at [webassembly.github.io/annotations](https://webassembly.github Original `README` from upstream repository follows... +# Branch hinting Proposal for WebAssembly + +This repository is a clone of [github.com/WebAssembly/spec/](https://github.com/WebAssembly/spec/). +It is meant for discussion, prototype specification and implementation of a proposal to add a branch-hinting instruction to WebAssembly. + +See the [overview](proposals/branch-hinting/Overview.md) for a summary of the proposal. + +Original `README` from upstream repository follows... + # spec This repository holds a prototypical reference implementation for WebAssembly, From b14661cbc200ac34067eaa3785e932b669aadbab Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Thu, 8 Oct 2020 13:15:00 +0200 Subject: [PATCH 018/130] Add proof-of-concept benchmark for branch-hinting --- benchmarks/README.txt | 18 ++++++++++++++++++ benchmarks/test.js | 8 ++++++++ benchmarks/test.wasm | Bin 0 -> 101 bytes benchmarks/test.wat | 34 ++++++++++++++++++++++++++++++++++ benchmarks/test_brnull.wasm | Bin 0 -> 101 bytes 5 files changed, 60 insertions(+) create mode 100644 benchmarks/README.txt create mode 100644 benchmarks/test.js create mode 100644 benchmarks/test.wasm create mode 100644 benchmarks/test.wat create mode 100644 benchmarks/test_brnull.wasm diff --git a/benchmarks/README.txt b/benchmarks/README.txt new file mode 100644 index 0000000000..f2ab41d510 --- /dev/null +++ b/benchmarks/README.txt @@ -0,0 +1,18 @@ +test.js - Loader, passes 1 import to the wasm module +test.wat - Text representation for the non-optimized version +test.wasm - wat2wasm of test.wat +test_brnull.wasm - Manually modified test.wasm to use br_on_null + - Locals have been changed from i32/i64/f64 -> i32/optref 0 + - The number of locals have decreased from 3 -> 2 + - The optref local require 1 "memory index", not sure what that actually does + - The optref is null-initialized, we can then use br_on_null which is guaranteed to be taken + - The pointless block + branch in the original code is converted to br_on_null + - The idea is to make the "deferred" block reachable only by br_on_null + +test.js will run test.wasm by default, you can edit the file to run the optimized version + +$D8_PATH/d8 --experimental-wasm-gc --experimental-wasm-typed_funcref test.js + +Useful d8 options: + - --print-wasm-code to see the generated assembly code + - --trace-wasm-ast-end=100 to dump the AST of the wasm file, since normal dump tools do not work with br_on_null diff --git a/benchmarks/test.js b/benchmarks/test.js new file mode 100644 index 0000000000..b4db423a3b --- /dev/null +++ b/benchmarks/test.js @@ -0,0 +1,8 @@ +var testBuffer = read('test.wasm','binary'); +var m = new WebAssembly.Module(testBuffer); +function testImport() +{ + console.log("Import called"); +} +var i = new WebAssembly.Instance(m, {i:{import:testImport}}); +i.exports.test(0x7fffffff); diff --git a/benchmarks/test.wasm b/benchmarks/test.wasm new file mode 100644 index 0000000000000000000000000000000000000000..cf8d33783aeb3f0ded8c55870336640db9812ba6 GIT binary patch literal 101 zcmWm3F%E(-07l{ewM7lZ=*-l30>cT)Lc%R{a6m&K(2>B^g*SZ5(|hibM8=Cvrhx9$ x_2V!l$r_Y7_Rbev`pik>6;I2?%3@<6sOHzWXksuWg?!+CQ1gB4v%SjS{2$@=4KM%z literal 0 HcmV?d00001 diff --git a/benchmarks/test.wat b/benchmarks/test.wat new file mode 100644 index 0000000000..3431846765 --- /dev/null +++ b/benchmarks/test.wat @@ -0,0 +1,34 @@ +(module + (type (;0;) (func (param i32))) + (import "i" "import" (func (;0;) (type 0))) + (memory (;0;) 1 1) + (func $test (type 0) + (local i32 i64 f64) + loop + local.get 1 + local.get 0 + i32.const 1 + i32.sub + i32.eq + if + block + local.get 2 + drop + nop + br 0 + end + local.get 1 + call 0 + end + local.get 1 + i32.const 1 + i32.add + local.tee 1 + local.get 0 + i32.lt_u + br_if 0 + end + return + ) + (export "test" (func $test)) +) diff --git a/benchmarks/test_brnull.wasm b/benchmarks/test_brnull.wasm new file mode 100644 index 0000000000000000000000000000000000000000..ac1bc69cd0a1c4303402f182f4625a43978bfc00 GIT binary patch literal 101 zcmWN`F%E)27zN=sKMNWc14r0!0^87lL4iUfvOONs1G!Ut&1l#bBvJBUm(?&; y)3UxlNh%DLj@;phOXHTr>B_~}nZGJxAgJecbJ1e3pK5%dRi@|J<#|8LH~tUt(+%1H literal 0 HcmV?d00001 From f7db140555105d3f95a17f5db1365e82b408509e Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Thu, 8 Oct 2020 13:22:54 +0200 Subject: [PATCH 019/130] Add WIP overview of the proposal --- proposals/branch-hinting/Overview.md | 38 ++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 proposals/branch-hinting/Overview.md diff --git a/proposals/branch-hinting/Overview.md b/proposals/branch-hinting/Overview.md new file mode 100644 index 0000000000..e05685ad8e --- /dev/null +++ b/proposals/branch-hinting/Overview.md @@ -0,0 +1,38 @@ +# Branch hinting + +## Introduction + +### Motivation + +The primary motivations are: + + +### Background + +This proposal has first been presented here: + +https://github.com/WebAssembly/design/issues/1363 + +This topic was preliminarily discussed at the CG-09-29 meeting: + +https://github.com/WebAssembly/meetings/blob/master/main/2020/CG-09-29.md + +The consensus seems to be to proceed with the idea, but to present some benchmarks +to prove the need for the proposal. + +This repo contains the current work toward a spec, and the benchmarks. + +### Design + +This proposal introduces 1 new instruction: + + - `branch_hint` + +The semantic... +### Encoding + +The encoding for the new instruction is the following: + +| Name | Opcode | Immediate | Description | +| ---- | ---- | ---- | ---- | +| `branch_hint` | `0xXX` | | :bowling: branch hinting | From 97b679ab45721988ac34443fd9837788eb25f8cc Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Fri, 9 Oct 2020 12:15:04 +0200 Subject: [PATCH 020/130] Improve readme --- benchmarks/README.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 benchmarks/README.md diff --git a/benchmarks/README.md b/benchmarks/README.md new file mode 100644 index 0000000000..77b4bef8d7 --- /dev/null +++ b/benchmarks/README.md @@ -0,0 +1,34 @@ +# Preliminary Benchmark + +Idea: use `br_on_null` to "simulate" the branch hinting instruction. +This works because currently v8 assumes that the branch will not be taken when it +encounters a `br_on_null`, and puts the target of the branch in a "deferred" block. + +The result is similar to what we expect a `branch_hint` instruction before a normal branch to do. + +This simple test case features a hot loop with a condition in the middle which is always false. +It is around 30% faster when using `br_on_null`, compared to a normal `br_if`. + +Since standard tools like wat2wasm don't work with `br_on_null` yet, the binary wasm had to be manually patched +to make the optimized version. + +## Files + +- `test.js`: Loader, passes 1 import to the wasm module +- `test.wat`: Text representation for the non-optimized version +- `test.wasm`: wat2wasm of test.wat +- `test_brnull.wasm`: Manually modified test.wasm to use br_on_null + - Locals have been changed from i32/i64/f64 -> i32/optref 0 + - The number of locals have decreased from 3 -> 2 + - The optref local require 1 "memory index", not sure what that actually does + - The optref is null-initialized, we can then use br_on_null which is guaranteed to be taken + - The pointless block + branch in the original code is converted to br_on_null + - The idea is to make the "deferred" block reachable only by br_on_null + +test.js will run test.wasm by default, you can edit the file to run the optimized version + +$D8_PATH/d8 --experimental-wasm-gc --experimental-wasm-typed_funcref test.js + +Useful d8 options: + - --print-wasm-code to see the generated assembly code + - --trace-wasm-ast-end=100 to dump the AST of the wasm file, since normal dump tools do not work with br_on_null From 65aff2bce47d841e95425334f473cd61a6cbed8c Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Fri, 9 Oct 2020 12:19:03 +0200 Subject: [PATCH 021/130] Update Overview.md --- proposals/branch-hinting/Overview.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proposals/branch-hinting/Overview.md b/proposals/branch-hinting/Overview.md index e05685ad8e..4094ea91c6 100644 --- a/proposals/branch-hinting/Overview.md +++ b/proposals/branch-hinting/Overview.md @@ -18,7 +18,7 @@ This topic was preliminarily discussed at the CG-09-29 meeting: https://github.com/WebAssembly/meetings/blob/master/main/2020/CG-09-29.md The consensus seems to be to proceed with the idea, but to present some benchmarks -to prove the need for the proposal. +to prove the need for the proposal (see [here](benchmarks)). This repo contains the current work toward a spec, and the benchmarks. @@ -35,4 +35,4 @@ The encoding for the new instruction is the following: | Name | Opcode | Immediate | Description | | ---- | ---- | ---- | ---- | -| `branch_hint` | `0xXX` | | :bowling: branch hinting | +| `branch_hint` | `0xXX` | | branch hinting | From eca0577b83fc4580b240021b4f57f46f1ae29345 Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Fri, 9 Oct 2020 13:09:13 +0200 Subject: [PATCH 022/130] Improve benchmark readme --- benchmarks/README.md | 7 ++++--- benchmarks/README.txt | 18 ------------------ 2 files changed, 4 insertions(+), 21 deletions(-) delete mode 100644 benchmarks/README.txt diff --git a/benchmarks/README.md b/benchmarks/README.md index 77b4bef8d7..66aace524f 100644 --- a/benchmarks/README.md +++ b/benchmarks/README.md @@ -2,11 +2,12 @@ Idea: use `br_on_null` to "simulate" the branch hinting instruction. This works because currently v8 assumes that the branch will not be taken when it -encounters a `br_on_null`, and puts the target of the branch in a "deferred" block. +encounters a `br_on_null`, and puts the target of the branch in a "deferred" block +(if the `br_on_null` is the only way to reach the target). -The result is similar to what we expect a `branch_hint` instruction before a normal branch to do. +The result is similar to what we expect a `branch_hint` instruction before a normal branch would do. -This simple test case features a hot loop with a condition in the middle which is always false. +This simple test case features a hot loop with a condition in the middle which is almost always false. It is around 30% faster when using `br_on_null`, compared to a normal `br_if`. Since standard tools like wat2wasm don't work with `br_on_null` yet, the binary wasm had to be manually patched diff --git a/benchmarks/README.txt b/benchmarks/README.txt deleted file mode 100644 index f2ab41d510..0000000000 --- a/benchmarks/README.txt +++ /dev/null @@ -1,18 +0,0 @@ -test.js - Loader, passes 1 import to the wasm module -test.wat - Text representation for the non-optimized version -test.wasm - wat2wasm of test.wat -test_brnull.wasm - Manually modified test.wasm to use br_on_null - - Locals have been changed from i32/i64/f64 -> i32/optref 0 - - The number of locals have decreased from 3 -> 2 - - The optref local require 1 "memory index", not sure what that actually does - - The optref is null-initialized, we can then use br_on_null which is guaranteed to be taken - - The pointless block + branch in the original code is converted to br_on_null - - The idea is to make the "deferred" block reachable only by br_on_null - -test.js will run test.wasm by default, you can edit the file to run the optimized version - -$D8_PATH/d8 --experimental-wasm-gc --experimental-wasm-typed_funcref test.js - -Useful d8 options: - - --print-wasm-code to see the generated assembly code - - --trace-wasm-ast-end=100 to dump the AST of the wasm file, since normal dump tools do not work with br_on_null From f916b1db703649f04adc1d38aaa7749739f1b441 Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Fri, 9 Oct 2020 15:33:58 +0200 Subject: [PATCH 023/130] Improve benchmark readme --- proposals/branch-hinting/Overview.md | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/proposals/branch-hinting/Overview.md b/proposals/branch-hinting/Overview.md index 4094ea91c6..014d36a4ae 100644 --- a/proposals/branch-hinting/Overview.md +++ b/proposals/branch-hinting/Overview.md @@ -4,7 +4,12 @@ ### Motivation -The primary motivations are: +The motivation for this proposal is to improve the performance of the compiled wasm +code, by informing the engine that a particular branch instruction is very likely to take +a specific path. + +This allows the engine to make better decisions for code layout (improving instruction cache hits) +and register allocation. ### Background @@ -28,11 +33,19 @@ This proposal introduces 1 new instruction: - `branch_hint` -The semantic... +The semantic of the instruction is a `nop`, but the engine can use this information +when compiling the branch instruction following `branch_hint`. + ### Encoding The encoding for the new instruction is the following: | Name | Opcode | Immediate | Description | | ---- | ---- | ---- | ---- | -| `branch_hint` | `0xXX` | | branch hinting | +| `branch_hint` | `0xXX` | index: `varint32` | The following branching instruction is very likely to take branch `index` | + +### Open questions + +- Should it be a validation error to have a `branch_hint` not followed by a branch instruction? Or with an immediate with a value out of range? +- What kind of branches are supported? (what about `br_table`? should it support multiple preceding `branch_hint` instructions?) +- Would it be better to implement this functionality through custom sections, instead of a new instruction? From 476b363c27c852089c45f5fa4d015f170af5b4ec Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Fri, 6 Nov 2020 16:18:38 +0100 Subject: [PATCH 024/130] Improve benchmark code and add actual branch hinting version --- benchmarks/README.md | 35 ++++++++++------------ benchmarks/test.js | 61 ++++++++++++++++++++++++++++++++++---- benchmarks/test.wasm | Bin 101 -> 93 bytes benchmarks/test.wat | 7 +---- benchmarks/test_hint.wasm | Bin 0 -> 93 bytes 5 files changed, 73 insertions(+), 30 deletions(-) create mode 100644 benchmarks/test_hint.wasm diff --git a/benchmarks/README.md b/benchmarks/README.md index 66aace524f..1572e151a6 100644 --- a/benchmarks/README.md +++ b/benchmarks/README.md @@ -1,35 +1,32 @@ # Preliminary Benchmark -Idea: use `br_on_null` to "simulate" the branch hinting instruction. -This works because currently v8 assumes that the branch will not be taken when it -encounters a `br_on_null`, and puts the target of the branch in a "deferred" block -(if the `br_on_null` is the only way to reach the target). +We are benchmarking 3 similar wasm modules, all exporting a 'test' function: -The result is similar to what we expect a `branch_hint` instruction before a normal branch would do. +- vanilla: Execute a loop many times doing some arithmetic, with a very unlikely + if branch in the middle of the loop +- branch hinting proposal: Same, but use a branch hinting instruction to signal that + the branch is unlikely +- br_on_null hack: similar to the previous one, but does not require a modified v8, + because the br_on_null instruction already considers the null case unlikely. This requires some extra code to setup the branch compared to the branch hinting proposal -This simple test case features a hot loop with a condition in the middle which is almost always false. -It is around 30% faster when using `br_on_null`, compared to a normal `br_if`. - -Since standard tools like wat2wasm don't work with `br_on_null` yet, the binary wasm had to be manually patched -to make the optimized version. +Since standard tools like wat2wasm don't work with `br_on_null` yet, let alone branch hinting, the modules had to be manually patched to make the optimized versions. ## Files -- `test.js`: Loader, passes 1 import to the wasm module -- `test.wat`: Text representation for the non-optimized version +- `test.js`: Load the wasm modules and run benchmarks +- `test.wat`: Text representation for the vanilla version - `test.wasm`: wat2wasm of test.wat - `test_brnull.wasm`: Manually modified test.wasm to use br_on_null - - Locals have been changed from i32/i64/f64 -> i32/optref 0 - - The number of locals have decreased from 3 -> 2 - - The optref local require 1 "memory index", not sure what that actually does - - The optref is null-initialized, we can then use br_on_null which is guaranteed to be taken - - The pointless block + branch in the original code is converted to br_on_null - - The idea is to make the "deferred" block reachable only by br_on_null +- `test_hint.wasm`: Manually modified test.wasm to use branch hinting (temporary opcode 0x16) -test.js will run test.wasm by default, you can edit the file to run the optimized version +run the benchmark: $D8_PATH/d8 --experimental-wasm-gc --experimental-wasm-typed_funcref test.js Useful d8 options: - --print-wasm-code to see the generated assembly code - --trace-wasm-ast-end=100 to dump the AST of the wasm file, since normal dump tools do not work with br_on_null + +NOTE: In order to run the branch hinting version, you need a modified v8 (see [this repo](https://github.com/yuri91/v8/tree/branch_hinting)). + +If you don't want to do that, just comment that entry and test only the br_on_null version (results are similar but a bit worse due to the extra overhead). diff --git a/benchmarks/test.js b/benchmarks/test.js index b4db423a3b..7615a124d1 100644 --- a/benchmarks/test.js +++ b/benchmarks/test.js @@ -1,8 +1,59 @@ -var testBuffer = read('test.wasm','binary'); -var m = new WebAssembly.Module(testBuffer); +const warmup = 3; +const iters = 5; + function testImport() { - console.log("Import called"); } -var i = new WebAssembly.Instance(m, {i:{import:testImport}}); -i.exports.test(0x7fffffff); +function readModule(path) +{ + const buf = read(path,'binary'); + const m = new WebAssembly.Module(buf); + const i = new WebAssembly.Instance(m, {i:{import:testImport}}); + return i; +} + +const modules = [ + {path: 'test.wasm', desc: "vanilla code"}, + {path: 'test_brnull.wasm', desc: "br_on_null hack"}, + {path: 'test_hint.wasm', desc: "branch hinting proposal"}, +]; +function doBench(m) +{ + const start = Date.now(); + m.exports.test(0x7fffffff); + const end = Date.now(); + return end - start; +} + +function benchmark(m) +{ + for (let i = 0; i < warmup; i++) + doBench(m); + + const results = []; + + for (let i = 0; i < iters; i++) + results.push(doBench(m)); + + return results; +} + +function stats(results) +{ + const mean = results.reduce((acc, i) => acc+i, 0)/results.length; + const stddev = Math.sqrt(results.reduce((acc,i) => acc+(i-mean)*(i-mean), 0)/results.length); + + return { mean, stddev }; + +} + +for (let m of modules) { + console.log(`Running '${m.desc}'...`); + const i = readModule(m.path); + const res = benchmark(i); + const { mean, stddev} = stats(res); + + console.log("mean=",mean,"; stddev=",stddev); + console.log("--------------------------"); +} + diff --git a/benchmarks/test.wasm b/benchmarks/test.wasm index cf8d33783aeb3f0ded8c55870336640db9812ba6..aa4b9e8e140afadd143745e6b0dd3e400f7e0acb 100644 GIT binary patch delta 31 mcmYd|onR!c#i+r|SkG9;Si|g~z^K6B$e8WM$l@?DPy_&GsRkeb delta 56 zcmaz|onT~a#Av|GSkG9;Si|g~z^K6B$e8WM;=tsfz$C@U!@#Y;C;%cH8MBmtlAgQ_ H-2B`C5SItC diff --git a/benchmarks/test.wat b/benchmarks/test.wat index 3431846765..16792cd99d 100644 --- a/benchmarks/test.wat +++ b/benchmarks/test.wat @@ -10,13 +10,8 @@ i32.const 1 i32.sub i32.eq + nop if - block - local.get 2 - drop - nop - br 0 - end local.get 1 call 0 end diff --git a/benchmarks/test_hint.wasm b/benchmarks/test_hint.wasm new file mode 100644 index 0000000000000000000000000000000000000000..cfb5faa621de069025d154a9c970fde6246ba4e2 GIT binary patch literal 93 zcmWN_F$#k)07l{enb?*_v6FM?Bt1o41aF~(gNn3hM$xOAH+?+y+kzxgI!+}SjJI+5 r|JERx1f`bP{eca`7R2*IWjHz5&DY~qGdHD;e93ugrgxleE?2k Date: Mon, 9 Nov 2020 10:08:57 +0100 Subject: [PATCH 025/130] Update Overview.md fix benchmarks link --- proposals/branch-hinting/Overview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/branch-hinting/Overview.md b/proposals/branch-hinting/Overview.md index 014d36a4ae..43090aa6ff 100644 --- a/proposals/branch-hinting/Overview.md +++ b/proposals/branch-hinting/Overview.md @@ -23,7 +23,7 @@ This topic was preliminarily discussed at the CG-09-29 meeting: https://github.com/WebAssembly/meetings/blob/master/main/2020/CG-09-29.md The consensus seems to be to proceed with the idea, but to present some benchmarks -to prove the need for the proposal (see [here](benchmarks)). +to prove the need for the proposal (see [here](/benchmarks)). This repo contains the current work toward a spec, and the benchmarks. From 98b371de0d3ec3f80c20f342e7b7cb3c702167bc Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Mon, 9 Nov 2020 10:10:28 +0100 Subject: [PATCH 026/130] Update README.md --- benchmarks/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/README.md b/benchmarks/README.md index 1572e151a6..c454a52c85 100644 --- a/benchmarks/README.md +++ b/benchmarks/README.md @@ -21,7 +21,7 @@ Since standard tools like wat2wasm don't work with `br_on_null` yet, let alone b run the benchmark: -$D8_PATH/d8 --experimental-wasm-gc --experimental-wasm-typed_funcref test.js +`$D8_PATH/d8 --experimental-wasm-gc --experimental-wasm-typed_funcref test.js` Useful d8 options: - --print-wasm-code to see the generated assembly code From e5cd6968918307e866e88cae8b8987e21ecab3a1 Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Mon, 9 Nov 2020 10:12:33 +0100 Subject: [PATCH 027/130] Update README.md --- benchmarks/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/benchmarks/README.md b/benchmarks/README.md index c454a52c85..5f1750da9b 100644 --- a/benchmarks/README.md +++ b/benchmarks/README.md @@ -24,9 +24,9 @@ run the benchmark: `$D8_PATH/d8 --experimental-wasm-gc --experimental-wasm-typed_funcref test.js` Useful d8 options: - - --print-wasm-code to see the generated assembly code - - --trace-wasm-ast-end=100 to dump the AST of the wasm file, since normal dump tools do not work with br_on_null +- `--print-wasm-code` to see the generated assembly code +- `--trace-wasm-ast-end=100` to dump the AST of the wasm file, since normal dump tools do not work with br_on_null -NOTE: In order to run the branch hinting version, you need a modified v8 (see [this repo](https://github.com/yuri91/v8/tree/branch_hinting)). +NOTE: In order to run the branch hinting version, you need a modified v8 (see [this repo](https://github.com/yuri91/v8)). -If you don't want to do that, just comment that entry and test only the br_on_null version (results are similar but a bit worse due to the extra overhead). +If you don't want to do that, just comment that entry and test only the `br_on_null` version (results are similar but a bit worse due to the extra overhead). From 86362a7e7ec5fa4e25ddfe01f3acfe2e25f7773d Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Tue, 10 Nov 2020 14:25:12 +0100 Subject: [PATCH 028/130] Remove extra parameters from benchmark --- benchmarks/test.wasm | Bin 93 -> 89 bytes benchmarks/test.wat | 2 +- benchmarks/test_hint.wasm | Bin 93 -> 89 bytes 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/test.wasm b/benchmarks/test.wasm index aa4b9e8e140afadd143745e6b0dd3e400f7e0acb..7659124d531bb9f0b564fabd82d6c6b01135a533 100644 GIT binary patch delta 14 Vcma!zoM6PJ#;C%`SU=H55dax@133Ty delta 18 Zcma!yonXYJ#i+r|SkG9;SToT=5dbJO1U~=( diff --git a/benchmarks/test.wat b/benchmarks/test.wat index 16792cd99d..73939d7475 100644 --- a/benchmarks/test.wat +++ b/benchmarks/test.wat @@ -3,7 +3,7 @@ (import "i" "import" (func (;0;) (type 0))) (memory (;0;) 1 1) (func $test (type 0) - (local i32 i64 f64) + (local i32) loop local.get 1 local.get 0 diff --git a/benchmarks/test_hint.wasm b/benchmarks/test_hint.wasm index cfb5faa621de069025d154a9c970fde6246ba4e2..a88b0990238914789ae1f9c44704564eb7c9f7a6 100644 GIT binary patch delta 14 Vcma!zoM6PJ#;C%`SU=H55dax@133Ty delta 18 Zcma!yonXYJ#i+r|SkG9;SToT=5dbJO1U~=( From 13016bc060628532805c38da60e325583023b5cd Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Mon, 4 Jan 2021 18:19:30 +0100 Subject: [PATCH 029/130] Update the overview with the new custom section approach --- proposals/branch-hinting/Overview.md | 45 ++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/proposals/branch-hinting/Overview.md b/proposals/branch-hinting/Overview.md index 43090aa6ff..b624fd83d8 100644 --- a/proposals/branch-hinting/Overview.md +++ b/proposals/branch-hinting/Overview.md @@ -29,23 +29,42 @@ This repo contains the current work toward a spec, and the benchmarks. ### Design -This proposal introduces 1 new instruction: +This proposal introduces a new custom section named "branchHints". - - `branch_hint` +The section, if present, must appear before the code section (this can help a +streaming compiler to make use of the hints). -The semantic of the instruction is a `nop`, but the engine can use this information -when compiling the branch instruction following `branch_hint`. +The content of the section consists of a sequence of subsections. -### Encoding +Each subsection corresponds to one function and consists of: -The encoding for the new instruction is the following: +- the u32 index of the function +- the u32 number of branch hints contained in the subsection +- the list of branch hints for the function -| Name | Opcode | Immediate | Description | -| ---- | ---- | ---- | ---- | -| `branch_hint` | `0xXX` | index: `varint32` | The following branching instruction is very likely to take branch `index` | +Each element N of the list of hints implicitly refers to the Nth `br` or `br_if` +instruction in the function. It is ok to list less hints than branches instruction +in the function; -### Open questions +Each element consists of a byte indicating what the hint for that particular branch +is: -- Should it be a validation error to have a `branch_hint` not followed by a branch instruction? Or with an immediate with a value out of range? -- What kind of branches are supported? (what about `br_table`? should it support multiple preceding `branch_hint` instructions?) -- Would it be better to implement this functionality through custom sections, instead of a new instruction? +| value | meaning | +|-------|--------------| +| 0 | no hint | +| 1 | likely false | +| 2 | likely true | + + +### Open issues + +Using the number of branch instructions as an implicit index has the advantage +of saving space and simplifying validation (compared to, say, an explicit byte index). + +But it has the disadvantage that if in the future we want to expand the set of instructions +that are hintable, old programs may find themselves with an invalid or misleading +hinting section. + +A middle ground could be using the number of total instructions. +While not as space-saving, and requiring more validation than the current approach, it +is still much better than using a byte offset, while being more future proof. From 1aa3478b9c4dffcfb784c834ffc0adf4cae9699e Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Fri, 29 Jan 2021 18:21:05 +0100 Subject: [PATCH 030/130] Update the overview with the new byte offset format --- proposals/branch-hinting/Overview.md | 27 +++++---------------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/proposals/branch-hinting/Overview.md b/proposals/branch-hinting/Overview.md index b624fd83d8..d58faf0f94 100644 --- a/proposals/branch-hinting/Overview.md +++ b/proposals/branch-hinting/Overview.md @@ -42,29 +42,12 @@ Each subsection corresponds to one function and consists of: - the u32 number of branch hints contained in the subsection - the list of branch hints for the function -Each element N of the list of hints implicitly refers to the Nth `br` or `br_if` -instruction in the function. It is ok to list less hints than branches instruction -in the function; - -Each element consists of a byte indicating what the hint for that particular branch -is: +Each element of the branch hints list consists of: +- the u32 byte offset of the hinted istruction from the beginning of the function +- A byte indicating the direction of the hint: | value | meaning | |-------|--------------| -| 0 | no hint | -| 1 | likely false | -| 2 | likely true | - - -### Open issues - -Using the number of branch instructions as an implicit index has the advantage -of saving space and simplifying validation (compared to, say, an explicit byte index). - -But it has the disadvantage that if in the future we want to expand the set of instructions -that are hintable, old programs may find themselves with an invalid or misleading -hinting section. +| 0 | likely false | +| 1 | likely true | -A middle ground could be using the number of total instructions. -While not as space-saving, and requiring more validation than the current approach, it -is still much better than using a byte offset, while being more future proof. From 359f83f810282310ecff50c7c755435c99fb26bd Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Tue, 2 Feb 2021 15:02:05 +0100 Subject: [PATCH 031/130] remove br_null hack benchmark and update the branch hinting one --- benchmarks/test.js | 1 - benchmarks/test_brnull.wasm | Bin 101 -> 0 bytes benchmarks/test_hint.wasm | Bin 89 -> 109 bytes 3 files changed, 1 deletion(-) delete mode 100644 benchmarks/test_brnull.wasm diff --git a/benchmarks/test.js b/benchmarks/test.js index 7615a124d1..6137b611b2 100644 --- a/benchmarks/test.js +++ b/benchmarks/test.js @@ -14,7 +14,6 @@ function readModule(path) const modules = [ {path: 'test.wasm', desc: "vanilla code"}, - {path: 'test_brnull.wasm', desc: "br_on_null hack"}, {path: 'test_hint.wasm', desc: "branch hinting proposal"}, ]; function doBench(m) diff --git a/benchmarks/test_brnull.wasm b/benchmarks/test_brnull.wasm deleted file mode 100644 index ac1bc69cd0a1c4303402f182f4625a43978bfc00..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 101 zcmWN`F%E)27zN=sKMNWc14r0!0^87lL4iUfvOONs1G!Ut&1l#bBvJBUm(?&; y)3UxlNh%DLj@;phOXHTr>B_~}nZGJxAgJecbJ1e3pK5%dRi@|J<#|8LH~tUt(+%1H diff --git a/benchmarks/test_hint.wasm b/benchmarks/test_hint.wasm index a88b0990238914789ae1f9c44704564eb7c9f7a6..a47a2f01384ead69187ac355690798cc903472e9 100644 GIT binary patch delta 65 zcma#donUCgAjF+il$e*C;gOkFQq0K2%^<_brN*ej$XL(ppuniW;K-Qm#>fI>3NUah RFgh}3DFFpNc^SC*xdFo*3fTYv delta 45 xcmd0eoM5QIrN*ej$XL(ppuniW;K-QmCdL9}3NUahFgh}3DFFpNc^SC*xdEwu1|9$a From a6287ec9763fd62b5b9a8a1862c751e56390b0f2 Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Mon, 15 Feb 2021 11:43:55 +0100 Subject: [PATCH 032/130] Update english text --- proposals/branch-hinting/Overview.md | 55 +++++++++++++++++++--------- 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/proposals/branch-hinting/Overview.md b/proposals/branch-hinting/Overview.md index d58faf0f94..0c7bba54c6 100644 --- a/proposals/branch-hinting/Overview.md +++ b/proposals/branch-hinting/Overview.md @@ -22,32 +22,51 @@ This topic was preliminarily discussed at the CG-09-29 meeting: https://github.com/WebAssembly/meetings/blob/master/main/2020/CG-09-29.md -The consensus seems to be to proceed with the idea, but to present some benchmarks -to prove the need for the proposal (see [here](/benchmarks)). +The consensus seemed to be to proceed with the idea, but to present some benchmarks +to prove the need for the proposal. + +A [preliminary benchmark](/benchmarks) showed that the proposal is worth investigating + +The proposal was accepted for phase 1 at the CG-11-10 meeting: + +https://github.com/WebAssembly/meetings/blob/master/main/2020/CG-11-10.md + +Discussion about how to implement the proposal happened in this issue: + +https://github.com/WebAssembly/branch-hinting/issues/1 + +And some more discussion and feedback on the custom section format was done in the CG-01-05: + +https://github.com/WebAssembly/meetings/blob/master/main/2021/CG-01-05.md + +After that, a tentative spec was written and a poll for phase 2 scheduled for the CG-02-16: + +https://github.com/WebAssembly/meetings/blob/master/main/2021/CG-02-16.md -This repo contains the current work toward a spec, and the benchmarks. ### Design -This proposal introduces a new custom section named "branchHints". +The *branch hints section* is a custom section whose name string is "branchHints". +The branch hints section should appear only once in a module, and only before the code section. + +The purpose of this section is to aid the compilation of conditional branch instructions, by providing a hint that a branch is very likely (or unlikely) to be taken. + +An implementation is not required to follow the hints, and this section can be entirely ignored. -The section, if present, must appear before the code section (this can help a -streaming compiler to make use of the hints). +The section contains a vector of *function hints* each representing the branch hints for a single function. -The content of the section consists of a sequence of subsections. +Each *function hints* structure consists of -Each subsection corresponds to one function and consists of: +* the funcidx of the function the hints are referring to, +* a vector of *branch hints* for the function. -- the u32 index of the function -- the u32 number of branch hints contained in the subsection -- the list of branch hints for the function +Each *branch hint* structure consists of -Each element of the branch hints list consists of: -- the u32 byte offset of the hinted istruction from the beginning of the function -- A byte indicating the direction of the hint: +* the u32 byte offset of the hinted instruction from the first instruction of the function, +* a byte indicating the meaning of the hint: -| value | meaning | -|-------|--------------| -| 0 | likely false | -| 1 | likely true | +| value | meaning | +|-------|-------------------| +| 0 | likely taken | +| 1 | likely not taken | From 5d97e7d28f1827f80b407bf1f6d3cab6399f934a Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Mon, 15 Feb 2021 14:13:58 +0100 Subject: [PATCH 033/130] Update spec text --- document/core/appendix/custom.rst | 46 ++++++++++++++++++++++++++++ document/core/util/macros.def | 5 +++ proposals/branch-hinting/Overview.md | 2 +- 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/document/core/appendix/custom.rst b/document/core/appendix/custom.rst index 034779d29e..8d7f29e876 100644 --- a/document/core/appendix/custom.rst +++ b/document/core/appendix/custom.rst @@ -339,3 +339,49 @@ Their relative placement will depend on the placement directive given for the :m custom section "G" custom section "A" custom section "D" + + +.. index:: ! branch hints section, hint +.. _binary-branchHintsSec: +.. _binary-funchints: + +Branch Hints Section +~~~~~~~~~~~~~~~~~~~~ + +The *branch hints section* is a :ref:`custom section ` whose name string is :math:`\text{branchHints}`. +The branch hints section should appear only once in a module, and only before the :ref:`code section `. + +The purpose of this section is to aid the compilation of conditional branch instructions, by providing a hint that a branch is very likely (or unlikely) to be taken. + +An implementation is not required to follow the hints, and this section can be entirely ignored. + +The section contains a vector of *function branch hints* each representing the branch hints for a single function. + +Each *function function hints* structure consists of + +* the :ref:`function index ` of the function the hints are referring to, +* a vector of *branch hints* for the function. + +Each *branch hint* structure consists of + +* the |U32| byte offset of the hinted instruction from the first instruction of the function, +* a byte indicating the meaning of the hint: + +===== =========================================== +Value Meaning +===== =========================================== + 0x00 branch likely not taken + 0x01 branch likely taken +===== =========================================== + +.. math:: + \begin{array}{llclll} + \production{function branch hints} & \Bfuncbranchhints &::=& + \Bfuncidx~\Bvec(\Bbranchhint) \\ + \production{branch hint} & \Bbranchhint &::=& + \X{instoff}{:}\Bu32~~\Bbranchhintkind \\ + \production{branch hint kind} & \Bbranchhintkind &::=& + \hex{00} \\ &&& + \hex{01} \\ + \end{array} + diff --git a/document/core/util/macros.def b/document/core/util/macros.def index 844e6b72ae..e6362b6b1a 100644 --- a/document/core/util/macros.def +++ b/document/core/util/macros.def @@ -1267,6 +1267,11 @@ .. |Bfuncnamesubsec| mathdef:: \xref{appendix/custom}{binary-funcnamesec}{\B{funcnamesubsec}} .. |Blocalnamesubsec| mathdef:: \xref{appendix/custom}{binary-localnamesec}{\B{localnamesubsec}} +.. Branch Hints Section, non-terminals + +.. |Bfuncbranchhints| mathdef:: \xref{appendix/custom}{binary-branchhintssec}{\B{funcbranchhints}} +.. |Bbranchhint| mathdef:: \xref{appendix/custom}{binary-branchhintsec}{\B{branchhint}} +.. |Bbranchhintkind| mathdef:: \xref{appendix/custom}{binary-branchhintsec}{\B{branchhintkind}} .. Annotations .. ----------- diff --git a/proposals/branch-hinting/Overview.md b/proposals/branch-hinting/Overview.md index 0c7bba54c6..0c8331571c 100644 --- a/proposals/branch-hinting/Overview.md +++ b/proposals/branch-hinting/Overview.md @@ -57,7 +57,7 @@ The section contains a vector of *function hints* each representing the branch h Each *function hints* structure consists of -* the funcidx of the function the hints are referring to, +* the index of the function the hints are referring to, * a vector of *branch hints* for the function. Each *branch hint* structure consists of From d61a3939e7cb1769d77e77c2296adb9c10e695a9 Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Tue, 16 Feb 2021 17:48:45 +0100 Subject: [PATCH 034/130] Overview: Fix table of hint meaning --- proposals/branch-hinting/Overview.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proposals/branch-hinting/Overview.md b/proposals/branch-hinting/Overview.md index 0c8331571c..7388fd741a 100644 --- a/proposals/branch-hinting/Overview.md +++ b/proposals/branch-hinting/Overview.md @@ -67,6 +67,6 @@ Each *branch hint* structure consists of | value | meaning | |-------|-------------------| -| 0 | likely taken | -| 1 | likely not taken | +| 0 | likely not taken | +| 1 | likely taken | From 5c8dd613ff2c973d4c02b57c406a559d10da2d20 Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Wed, 17 Feb 2021 10:59:09 +0100 Subject: [PATCH 035/130] Update benchmark readme Removed references to the br_on_null hack --- benchmarks/README.md | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/benchmarks/README.md b/benchmarks/README.md index 5f1750da9b..fbe5b6ba9a 100644 --- a/benchmarks/README.md +++ b/benchmarks/README.md @@ -1,23 +1,18 @@ # Preliminary Benchmark -We are benchmarking 3 similar wasm modules, all exporting a 'test' function: +We are benchmarking 2 similar wasm modules, all exporting a 'test' function: - vanilla: Execute a loop many times doing some arithmetic, with a very unlikely if branch in the middle of the loop -- branch hinting proposal: Same, but use a branch hinting instruction to signal that - the branch is unlikely -- br_on_null hack: similar to the previous one, but does not require a modified v8, - because the br_on_null instruction already considers the null case unlikely. This requires some extra code to setup the branch compared to the branch hinting proposal +- branch hinting proposal: Same, but includes a brancHints section with a hint that that if is unlikely -Since standard tools like wat2wasm don't work with `br_on_null` yet, let alone branch hinting, the modules had to be manually patched to make the optimized versions. ## Files - `test.js`: Load the wasm modules and run benchmarks - `test.wat`: Text representation for the vanilla version - `test.wasm`: wat2wasm of test.wat -- `test_brnull.wasm`: Manually modified test.wasm to use br_on_null -- `test_hint.wasm`: Manually modified test.wasm to use branch hinting (temporary opcode 0x16) +- `test_hint.wasm`: Manually modified test.wasm to use branch hinting run the benchmark: @@ -28,5 +23,3 @@ Useful d8 options: - `--trace-wasm-ast-end=100` to dump the AST of the wasm file, since normal dump tools do not work with br_on_null NOTE: In order to run the branch hinting version, you need a modified v8 (see [this repo](https://github.com/yuri91/v8)). - -If you don't want to do that, just comment that entry and test only the `br_on_null` version (results are similar but a bit worse due to the extra overhead). From a5f20614b41dfa4ed57c718393ad0bc6a1f35f10 Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Thu, 18 Feb 2021 10:38:07 +0100 Subject: [PATCH 036/130] Remove one more mention of br_on_null and remove unneded d8 arguments --- benchmarks/README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/benchmarks/README.md b/benchmarks/README.md index fbe5b6ba9a..8068d2ca6e 100644 --- a/benchmarks/README.md +++ b/benchmarks/README.md @@ -16,10 +16,9 @@ We are benchmarking 2 similar wasm modules, all exporting a 'test' function: run the benchmark: -`$D8_PATH/d8 --experimental-wasm-gc --experimental-wasm-typed_funcref test.js` +`$D8_PATH/d8 test.js` Useful d8 options: - `--print-wasm-code` to see the generated assembly code -- `--trace-wasm-ast-end=100` to dump the AST of the wasm file, since normal dump tools do not work with br_on_null NOTE: In order to run the branch hinting version, you need a modified v8 (see [this repo](https://github.com/yuri91/v8)). From ea7c4e0fd87877138aa65614e72c5bf6e7b87490 Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Tue, 23 Feb 2021 16:20:26 +0100 Subject: [PATCH 037/130] Update test_hint.wasm --- benchmarks/test_hint.wasm | Bin 109 -> 107 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/benchmarks/test_hint.wasm b/benchmarks/test_hint.wasm index a47a2f01384ead69187ac355690798cc903472e9..b58a062807109de0990f65474862cc3740323b87 100644 GIT binary patch delta 25 gcmd1Jo?s*>z@1c-n3tU4k(pOg%*e>iFws>50A;2JMgRZ+ delta 27 icmd1KonRy^#GO=>n3tU4k(pOg%*e#eAj3G(SpxubA_ryw From af5d6c80125402d189d6156d8f0f9a97e47cb11c Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Tue, 23 Feb 2021 16:21:28 +0100 Subject: [PATCH 038/130] Add a file explaining the motivations of the proposal --- proposals/branch-hinting/Motivation.md | 393 +++++++++++++++++++++++++ 1 file changed, 393 insertions(+) create mode 100644 proposals/branch-hinting/Motivation.md diff --git a/proposals/branch-hinting/Motivation.md b/proposals/branch-hinting/Motivation.md new file mode 100644 index 0000000000..a8e30d734b --- /dev/null +++ b/proposals/branch-hinting/Motivation.md @@ -0,0 +1,393 @@ +# Proposal motivation + +This document has the purpose of explaining better the underlying issues that the proposal +aim to solve, and why they can't be solved in other ways (for example with better tooling). + +# Example code + +We will refer to the following example code, which is purposefully simple to make +the analysis easier. The analysis generalizes for more complex code. + +``` +void foo(); +int run(int i) { + int ret = 0; + int b = 0; + while(i) { + if(__builtin_expect(b==i-1, 0)) { + foo(); + } + b++; + ret += b; + if(b>=i) + break; + } + return ret; +} +``` + +`__builtin_expect` is a gcc and clang specific builtin that hints the compiler that +we know that `b==i-1` is very likely to be false. + +The compiler can use this information to make better decisions regarding register allocation, +inlining, code layout, etc... + +For example here the compiler may decide that it is not worth it to inline the call to `foo()`, +and that in the resulting machine code the call should be placed far from the rest of the code. + +# Native x86-64 code generation + +We can see the effect of `__builtin_expect` when compiling native code by compiling +first with the expected value `1` and then `0`: + +``` +// expected 1 +0000000000000000 : + 0: 55 push rbp + 1: 41 57 push r15 + 3: 41 56 push r14 + 5: 53 push rbx + 6: 50 push rax + 7: 41 89 ff mov r15d,edi + a: 85 ff test edi,edi + c: bb 01 00 00 00 mov ebx,0x1 + 11: 41 be 01 00 00 00 mov r14d,0x1 + 17: 44 0f 4f f7 cmovg r14d,edi + 1b: 41 f7 de neg r14d + 1e: 31 ed xor ebp,ebp + 20: /----> 45 85 ff test r15d,r15d + 23: /--|----- 74 21 je 46 + 25: | | 41 39 df cmp r15d,ebx + 28: | | /-- 75 05 jne 2f + 2a: | | | e8 00 00 00 00 call 2f foo + 2f: | | \-> 01 dd add ebp,ebx + 31: | | 41 8d 04 1e lea eax,[r14+rbx*1] + 35: | | 83 c0 01 add eax,0x1 + 38: | | 89 d9 mov ecx,ebx + 3a: | | 83 c1 01 add ecx,0x1 + 3d: | | 89 cb mov ebx,ecx + 3f: | | 83 f8 01 cmp eax,0x1 + 42: | \----- 75 dc jne 20 + 44: | /-- eb 02 jmp 48 + 46: \-----|-> 31 ed xor ebp,ebp + 48: \-> 89 e8 mov eax,ebp + 4a: 48 83 c4 08 add rsp,0x8 + 4e: 5b pop rbx + 4f: 41 5e pop r14 + 51: 41 5f pop r15 + 53: 5d pop rbp + 54: c3 ret +``` + +``` +// expected 0 +0000000000000000 : + 0: 55 push rbp + 1: 41 57 push r15 + 3: 41 56 push r14 + 5: 53 push rbx + 6: 50 push rax + 7: 41 89 ff mov r15d,edi + a: 85 ff test edi,edi + c: bb 01 00 00 00 mov ebx,0x1 + 11: 41 be 01 00 00 00 mov r14d,0x1 + 17: 44 0f 4f f7 cmovg r14d,edi + 1b: 41 f7 de neg r14d + 1e: 31 ed xor ebp,ebp + 20: /-> 45 85 ff test r15d,r15d + 23: /-----------|-- 74 23 je 48 + 25: | | 41 39 df cmp r15d,ebx + 28: | /-----|-- 74 17 je 41 + 2a: | /--|-----|-> 01 dd add ebp,ebx + 2c: | | | | 41 8d 04 1e lea eax,[r14+rbx*1] + 30: | | | | 83 c0 01 add eax,0x1 + 33: | | | | 89 d9 mov ecx,ebx + 35: | | | | 83 c1 01 add ecx,0x1 + 38: | | | | 89 cb mov ebx,ecx + 3a: | | | | 83 f8 01 cmp eax,0x1 + 3d: | | | \-- 75 e1 jne 20 + 3f: | | | /----- eb 09 jmp 4a + 41: | | \--|----> e8 00 00 00 00 call 46 foo + 46: | \-----|----- eb e2 jmp 2a + 48: \--------|----> 31 ed xor ebp,ebp + 4a: \----> 89 e8 mov eax,ebp + 4c: 48 83 c4 08 add rsp,0x8 + 50: 5b pop rbx + 51: 41 5e pop r14 + 53: 41 5f pop r15 + 55: 5d pop rbp + 56: c3 ret +``` + +You can see that if the compiler expects the branch to be taken, it puts the call +with the rest of the loop code, while if it expects it to be not take, it puts it after. + +This is to maximise the likelyhood that the most often executed code is in the instruction cache. + +# Wasm code generation + +When compiling into Wasm, the compiler can still use `__builtin_expect` to make better decisions: + +For example it can still decide that inlining the call to `foo()` is not worth it. + +But a key difference is that in the case of Wasm, the Wasm code is not the actual machine +code that the cpu will execute. +Moreover, Wasm's structured control flow has no 1 to 1 relationship with the final machine code +that a Wasm engine will generate in tems of code layout. + +This means that there is no way that a Wasm compiler can tell a Wasm engine how it would +like the machine code to be laid out. + +The Wasm generated from the above code is the following (regardless of the presence of `__builtin_expect`): + +``` +func[2] : + local[0..3] type=i32 + local.get 0 + i32.const 4294967295 + i32.add + local.set 1 + local.get 0 + i32.const 0 + i32.ne + local.set 2 + i32.const 0 + local.tee 3 + local.tee 4 + loop + local.get 2 + if + local.get 4 + local.get 1 + i32.eq + if + call 0 + end + local.get 4 + i32.const 1 + i32.add + local.tee 4 + local.get 3 + i32.add + local.set 3 + local.get 4 + local.get 0 + i32.lt_s + br_if 1 + local.get 3 + return + end + end + end +``` + +And the machine code generated by V8's TurboFan is: + +``` +0x3ed39fc0d640 0 55 push rbp +0x3ed39fc0d641 1 4889e5 REX.W movq rbp,rsp +0x3ed39fc0d644 4 6a0a push 0xa +0x3ed39fc0d646 6 56 push rsi +0x3ed39fc0d647 7 4883ec20 REX.W subq rsp,0x20 +0x3ed39fc0d64b b 488b5e23 REX.W movq rbx,[rsi+0x23] +0x3ed39fc0d64f f 488945e8 REX.W movq [rbp-0x18],rax +0x3ed39fc0d653 13 483b23 REX.W cmpq rsp,[rbx] +0x3ed39fc0d656 16 0f869b000000 jna 0x3ed39fc0d6f7 <+0xb7> +0x3ed39fc0d65c 1c 83f800 cmpl rax,0x0 +0x3ed39fc0d65f 1f 0f95c3 setnzl bl +0x3ed39fc0d662 22 0fb6db movzxbl rbx,rbx +0x3ed39fc0d665 25 33c9 xorl rcx,rcx +0x3ed39fc0d667 27 48895dd0 REX.W movq [rbp-0x30],rbx +0x3ed39fc0d66b 2b 488bd1 REX.W movq rdx,rcx +0x3ed39fc0d66e 2e 488bf9 REX.W movq rdi,rcx +0x3ed39fc0d671 31 660f1f840000000000 nop +0x3ed39fc0d67a 3a 660f1f440000 nop +0x3ed39fc0d680 40 4c8b4623 REX.W movq r8,[rsi+0x23] +0x3ed39fc0d684 44 493b20 REX.W cmpq rsp,[r8] +0x3ed39fc0d687 47 0f867c000000 jna 0x3ed39fc0d709 <+0xc9> +0x3ed39fc0d68d 4d 837dd000 cmpl [rbp-0x30],0x0 +0x3ed39fc0d691 51 0f8454000000 jz 0x3ed39fc0d6eb <+0xab> +0x3ed39fc0d697 57 448d40ff leal r8,[rax-0x1] +0x3ed39fc0d69b 5b 443bc7 cmpl r8,rdi +0x3ed39fc0d69e 5e 0f8539000000 jnz 0x3ed39fc0d6dd <+0x9d> +0x3ed39fc0d6a4 64 448b462b movl r8,[rsi+0x2b] +0x3ed39fc0d6a8 68 4d03c5 REX.W addq r8,r13 +0x3ed39fc0d6ab 6b 458b4007 movl r8,[r8+0x7] +0x3ed39fc0d6af 6f 4d03c5 REX.W addq r8,r13 +0x3ed39fc0d6b2 72 4c8b4e2f REX.W movq r9,[rsi+0x2f] +0x3ed39fc0d6b6 76 4d8b09 REX.W movq r9,[r9] +0x3ed39fc0d6b9 79 48894de0 REX.W movq [rbp-0x20],rcx +0x3ed39fc0d6bd 7d 48897dd8 REX.W movq [rbp-0x28],rdi +0x3ed39fc0d6c1 81 4c8bd6 REX.W movq r10,rsi +0x3ed39fc0d6c4 84 498bf0 REX.W movq rsi,r8 +0x3ed39fc0d6c7 87 4d8bc2 REX.W movq r8,r10 +0x3ed39fc0d6ca 8a 41ffd1 call r9 +0x3ed39fc0d6cd 8d 488b45e8 REX.W movq rax,[rbp-0x18] +0x3ed39fc0d6d1 91 488b4de0 REX.W movq rcx,[rbp-0x20] +0x3ed39fc0d6d5 95 488b7dd8 REX.W movq rdi,[rbp-0x28] +0x3ed39fc0d6d9 99 488b75f0 REX.W movq rsi,[rbp-0x10] +0x3ed39fc0d6dd 9d 83c701 addl rdi,0x1 +0x3ed39fc0d6e0 a0 03cf addl rcx,rdi +0x3ed39fc0d6e2 a2 3bf8 cmpl rdi,rax +0x3ed39fc0d6e4 a4 7c9a jl 0x3ed39fc0d680 <+0x40> +0x3ed39fc0d6e6 a6 e907000000 jmp 0x3ed39fc0d6f2 <+0xb2> +0x3ed39fc0d6eb ab 33c0 xorl rax,rax +0x3ed39fc0d6ed ad 488be5 REX.W movq rsp,rbp +0x3ed39fc0d6f0 b0 5d pop rbp +0x3ed39fc0d6f1 b1 c3 retl +0x3ed39fc0d6f2 b2 488bc1 REX.W movq rax,rcx +0x3ed39fc0d6f5 b5 ebf6 jmp 0x3ed39fc0d6ed <+0xad> +0x3ed39fc0d6f7 b7 e884fbffff call 0x3ed39fc0d280 ;; wasm stub: WasmStackGuard +0x3ed39fc0d6fc bc 488b45e8 REX.W movq rax,[rbp-0x18] +0x3ed39fc0d700 c0 488b75f0 REX.W movq rsi,[rbp-0x10] +0x3ed39fc0d704 c4 e953ffffff jmp 0x3ed39fc0d65c <+0x1c> +0x3ed39fc0d709 c9 48894de0 REX.W movq [rbp-0x20],rcx +0x3ed39fc0d70d cd 48897dd8 REX.W movq [rbp-0x28],rdi +0x3ed39fc0d711 d1 e86afbffff call 0x3ed39fc0d280 ;; wasm stub: WasmStackGuard +0x3ed39fc0d716 d6 488b45e8 REX.W movq rax,[rbp-0x18] +0x3ed39fc0d71a da 488b4de0 REX.W movq rcx,[rbp-0x20] +0x3ed39fc0d71e de 488b7dd8 REX.W movq rdi,[rbp-0x28] +0x3ed39fc0d722 e2 488b75f0 REX.W movq rsi,[rbp-0x10] +0x3ed39fc0d726 e6 e962ffffff jmp 0x3ed39fc0d68d <+0x4d> +0x3ed39fc0d72b eb 90 nop +``` + +As you can see the call to `foo()` (`call r9`) is in the middle of the loop code. + +Is there a way to produce different Wasm code which will result in the call being after +the rest of the loop code? + +No, because: + +- the call is part of the loop +- Wasm loops can only have one entry point + +Therefore it is impossible in Wasm to have some code part of a loop moved after it, +because it would cause irreducible control flow. + +Of course we could introduce irreducible control flow and then turn it into reducible control flow +again (Wasm compilers already must be able to do this), but there are only two way of +fixing the irreducible control flow: duplicating the code or introducing a new variable +to direct the control flow: + +- The first alternative is not feasible in the general case because the code duplication +can incur in exponential blowup + +- The second is feasible but introduces so much overhead that it defeats the purpose + +# Branch Hinting proposal + +The underlying problem is that there is a gap of information between the high level source code +and the final machine code that the engine runs. + +The Branch Hinting proposal aims to close the gap by explicitly passing on the missing information +to the engine. + +As a matter of fact, V8 already has the concept of "branch hinting": It is used internally +to produce better code in the presence of unlikely conditions. + +It is also currently used to implement the experimental `br_on_null` instruction (with the assumption +that it is unlikely to be null). + +These of course are implementation details, but they hint at the fact that this functionality +is valuable. + +Without this proposal, performance sesitive applications that benefits from branch hinting +may have to rely on internal engine behavior to achieve maximum performance. + +For example the CheerpX virtual machine is currently experimenting with using br_on_null to take advantage of internal branch hinting in V8. +Even though this solution is inefficient the performance gains are nonetheless significant. +Proper support for branch hinting would improve the performance even more. + +# Wasm code generation with branch hinting + +The V8 POC with branch hinting support produces the following machine code for our example code: + +``` +0xfe77b01d640 0 55 push rbp +0xfe77b01d641 1 4889e5 REX.W movq rbp,rsp +0xfe77b01d644 4 6a0a push 0xa +0xfe77b01d646 6 56 push rsi +0xfe77b01d647 7 4883ec20 REX.W subq rsp,0x20 +0xfe77b01d64b b 488b5e23 REX.W movq rbx,[rsi+0x23] +0xfe77b01d64f f 483b23 REX.W cmpq rsp,[rbx] +0xfe77b01d652 12 0f8656000000 jna 0xfe77b01d6ae <+0x6e> +0xfe77b01d658 18 83f800 cmpl rax,0x0 +0xfe77b01d65b 1b 0f95c3 setnzl bl +0xfe77b01d65e 1e 0fb6db movzxbl rbx,rbx +0xfe77b01d661 21 33c9 xorl rcx,rcx +0xfe77b01d663 23 488bd1 REX.W movq rdx,rcx +0xfe77b01d666 26 488bf9 REX.W movq rdi,rcx +0xfe77b01d669 29 0f1f8000000000 nop +0xfe77b01d670 30 4c8b4623 REX.W movq r8,[rsi+0x23] +0xfe77b01d674 34 493b20 REX.W cmpq rsp,[r8] +0xfe77b01d677 37 0f8644000000 jna 0xfe77b01d6c1 <+0x81> +0xfe77b01d67d 3d 83fb00 cmpl rbx,0x0 +0xfe77b01d680 40 0f841b000000 jz 0xfe77b01d6a1 <+0x61> +0xfe77b01d686 46 448d40ff leal r8,[rax-0x1] +0xfe77b01d68a 4a 443bc7 cmpl r8,rdi +0xfe77b01d68d 4d 0f845b000000 jz 0xfe77b01d6ee <+0xae> +0xfe77b01d693 53 83c701 addl rdi,0x1 +0xfe77b01d696 56 03cf addl rcx,rdi +0xfe77b01d698 58 3bf8 cmpl rdi,rax +0xfe77b01d69a 5a 7cd4 jl 0xfe77b01d670 <+0x30> +0xfe77b01d69c 5c e908000000 jmp 0xfe77b01d6a9 <+0x69> +0xfe77b01d6a1 61 488bc2 REX.W movq rax,rdx +0xfe77b01d6a4 64 488be5 REX.W movq rsp,rbp +0xfe77b01d6a7 67 5d pop rbp +0xfe77b01d6a8 68 c3 retl +0xfe77b01d6a9 69 488bc1 REX.W movq rax,rcx +0xfe77b01d6ac 6c ebf6 jmp 0xfe77b01d6a4 <+0x64> +0xfe77b01d6ae 6e 488945e8 REX.W movq [rbp-0x18],rax +0xfe77b01d6b2 72 e8c9fbffff call 0xfe77b01d280 ;; wasm stub: WasmStackGuard +0xfe77b01d6b7 77 488b45e8 REX.W movq rax,[rbp-0x18] +0xfe77b01d6bb 7b 488b75f0 REX.W movq rsi,[rbp-0x10] +0xfe77b01d6bf 7f eb97 jmp 0xfe77b01d658 <+0x18> +0xfe77b01d6c1 81 488945e8 REX.W movq [rbp-0x18],rax +0xfe77b01d6c5 85 48894de0 REX.W movq [rbp-0x20],rcx +0xfe77b01d6c9 89 48897dd8 REX.W movq [rbp-0x28],rdi +0xfe77b01d6cd 8d 48895dd0 REX.W movq [rbp-0x30],rbx +0xfe77b01d6d1 91 e8aafbffff call 0xfe77b01d280 ;; wasm stub: WasmStackGuard +0xfe77b01d6d6 96 33d2 xorl rdx,rdx +0xfe77b01d6d8 98 488b45e8 REX.W movq rax,[rbp-0x18] +0xfe77b01d6dc 9c 488b4de0 REX.W movq rcx,[rbp-0x20] +0xfe77b01d6e0 a0 488b7dd8 REX.W movq rdi,[rbp-0x28] +0xfe77b01d6e4 a4 488b75f0 REX.W movq rsi,[rbp-0x10] +0xfe77b01d6e8 a8 488b5dd0 REX.W movq rbx,[rbp-0x30] +0xfe77b01d6ec ac eb8f jmp 0xfe77b01d67d <+0x3d> +0xfe77b01d6ee ae 448b462b movl r8,[rsi+0x2b] +0xfe77b01d6f2 b2 4d03c5 REX.W addq r8,r13 +0xfe77b01d6f5 b5 458b4007 movl r8,[r8+0x7] +0xfe77b01d6f9 b9 4d03c5 REX.W addq r8,r13 +0xfe77b01d6fc bc 4c8b4e2f REX.W movq r9,[rsi+0x2f] +0xfe77b01d700 c0 4d8b09 REX.W movq r9,[r9] +0xfe77b01d703 c3 488945e8 REX.W movq [rbp-0x18],rax +0xfe77b01d707 c7 48894de0 REX.W movq [rbp-0x20],rcx +0xfe77b01d70b cb 48897dd8 REX.W movq [rbp-0x28],rdi +0xfe77b01d70f cf 48895dd0 REX.W movq [rbp-0x30],rbx +0xfe77b01d713 d3 4c8bd6 REX.W movq r10,rsi +0xfe77b01d716 d6 498bf0 REX.W movq rsi,r8 +0xfe77b01d719 d9 4d8bc2 REX.W movq r8,r10 +0xfe77b01d71c dc 41ffd1 call r9 +0xfe77b01d71f df 33d2 xorl rdx,rdx +0xfe77b01d721 e1 488b45e8 REX.W movq rax,[rbp-0x18] +0xfe77b01d725 e5 488b4de0 REX.W movq rcx,[rbp-0x20] +0xfe77b01d729 e9 488b7dd8 REX.W movq rdi,[rbp-0x28] +0xfe77b01d72d ed 488b75f0 REX.W movq rsi,[rbp-0x10] +0xfe77b01d731 f1 488b5dd0 REX.W movq rbx,[rbp-0x30] +0xfe77b01d735 f5 e959ffffff jmp 0xfe77b01d693 <+0x53> +0xfe77b01d73a fa 90 nop +0xfe77b01d73b fb 90 nop +``` + +As you can see the call to `foo()` (`call r9`) is laid out after the rest of the loop code. + +As a result, the hinted version runs ~25% faster than the non-hinted one. + +Of course real world code is more complex and probably doing some real computation +instead of just adding numbers in a tight loop. The actual performance gain will +depend heavily on the specific code, and how good the assumptions about the likeness +of a branch are. + +Techniques like Performance Guided Optimization can also make use of this feature +and provide more precise hints. From 88586a0db363e43c93283e5ae4d88198673c457d Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Tue, 23 Feb 2021 16:22:44 +0100 Subject: [PATCH 039/130] Add a link to the motivation in the overview --- proposals/branch-hinting/Overview.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/proposals/branch-hinting/Overview.md b/proposals/branch-hinting/Overview.md index 7388fd741a..7efb18cb0a 100644 --- a/proposals/branch-hinting/Overview.md +++ b/proposals/branch-hinting/Overview.md @@ -11,6 +11,8 @@ a specific path. This allows the engine to make better decisions for code layout (improving instruction cache hits) and register allocation. +See [Motivation](/proposals/branch-hinting/Motivation.md) for more information. + ### Background From 3d086c19433f0e89d9cb68c4a047f12850854cd0 Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Mon, 8 Mar 2021 12:06:18 +0100 Subject: [PATCH 040/130] Make the binary format of branch hinting more flexible An extra 0 byte is added after the function index, to make room for possibible future function-level hints. Also the offset and hint values in the branchint structure are swapped. Again, for flexible forward compatibility. See https://github.com/WebAssembly/branch-hinting/issues/6 for the rationale --- document/core/appendix/custom.rst | 11 +++++++---- proposals/branch-hinting/Overview.md | 6 ++++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/document/core/appendix/custom.rst b/document/core/appendix/custom.rst index 8d7f29e876..2a01c7c37a 100644 --- a/document/core/appendix/custom.rst +++ b/document/core/appendix/custom.rst @@ -360,12 +360,12 @@ The section contains a vector of *function branch hints* each representing the b Each *function function hints* structure consists of * the :ref:`function index ` of the function the hints are referring to, +* a single 0 byte, * a vector of *branch hints* for the function. Each *branch hint* structure consists of -* the |U32| byte offset of the hinted instruction from the first instruction of the function, -* a byte indicating the meaning of the hint: +* a |U32| indicating the meaning of the hint: ===== =========================================== Value Meaning @@ -374,12 +374,15 @@ Value Meaning 0x01 branch likely taken ===== =========================================== +* the |U32| byte offset of the hinted instruction from the first instruction of the function. + + .. math:: \begin{array}{llclll} \production{function branch hints} & \Bfuncbranchhints &::=& - \Bfuncidx~\Bvec(\Bbranchhint) \\ + \Bfuncidx~\hex{00}~\Bvec(\Bbranchhint) \\ \production{branch hint} & \Bbranchhint &::=& - \X{instoff}{:}\Bu32~~\Bbranchhintkind \\ + \Bbranchhintkind~~\X{instoff}{:}\Bu32 \\ \production{branch hint kind} & \Bbranchhintkind &::=& \hex{00} \\ &&& \hex{01} \\ diff --git a/proposals/branch-hinting/Overview.md b/proposals/branch-hinting/Overview.md index 7efb18cb0a..ffd4f984cb 100644 --- a/proposals/branch-hinting/Overview.md +++ b/proposals/branch-hinting/Overview.md @@ -60,15 +60,17 @@ The section contains a vector of *function hints* each representing the branch h Each *function hints* structure consists of * the index of the function the hints are referring to, +* a single 0 byte * a vector of *branch hints* for the function. Each *branch hint* structure consists of -* the u32 byte offset of the hinted instruction from the first instruction of the function, -* a byte indicating the meaning of the hint: +* a u32 indicating the meaning of the hint: | value | meaning | |-------|-------------------| | 0 | likely not taken | | 1 | likely taken | +* the u32 byte offset of the hinted instruction from the first instruction of the function + From c2babd6442cc319848516c11fae6b8b1d152b445 Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Mon, 8 Mar 2021 16:32:03 +0100 Subject: [PATCH 041/130] Update benchmark to new format --- benchmarks/test_hint.wasm | Bin 107 -> 109 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/benchmarks/test_hint.wasm b/benchmarks/test_hint.wasm index b58a062807109de0990f65474862cc3740323b87..5699652715bc7e37cfec996154c2f8a9ccc118ac 100644 GIT binary patch delta 27 icmd1KonRy^#GO=>n3tU4k(pOg%*e>V$iO|(SpxuaZwE;L delta 25 gcmd1Jo?s*>z@1c-n3tU4k(pOg%*e>iFws>50A;2JMgRZ+ From b0913a91554da963cbe2f0ccb56f63781e053206 Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Fri, 12 Mar 2021 16:10:48 +0100 Subject: [PATCH 042/130] Fix binary grammar definition of the branch hints custom section (#12) * Fix binary grammar definition of the branch hints custom section The overall section structure definition wasm missing. --- document/core/appendix/custom.rst | 2 ++ document/core/util/macros.def | 1 + 2 files changed, 3 insertions(+) diff --git a/document/core/appendix/custom.rst b/document/core/appendix/custom.rst index 2a01c7c37a..26590836a9 100644 --- a/document/core/appendix/custom.rst +++ b/document/core/appendix/custom.rst @@ -379,6 +379,8 @@ Value Meaning .. math:: \begin{array}{llclll} + \production{branch hints section} & \Bbranchhintssec &::=& + \Bsection_0(\Bvec(\Bfuncbranchhints)) \\ \production{function branch hints} & \Bfuncbranchhints &::=& \Bfuncidx~\hex{00}~\Bvec(\Bbranchhint) \\ \production{branch hint} & \Bbranchhint &::=& diff --git a/document/core/util/macros.def b/document/core/util/macros.def index e6362b6b1a..11a1a8e386 100644 --- a/document/core/util/macros.def +++ b/document/core/util/macros.def @@ -1269,6 +1269,7 @@ .. Branch Hints Section, non-terminals +.. |Bbranchhintssec| mathdef:: \xref{appendix/custom}{binary-branchhintssec}{\B{branchhintssec}} .. |Bfuncbranchhints| mathdef:: \xref{appendix/custom}{binary-branchhintssec}{\B{funcbranchhints}} .. |Bbranchhint| mathdef:: \xref{appendix/custom}{binary-branchhintsec}{\B{branchhint}} .. |Bbranchhintkind| mathdef:: \xref{appendix/custom}{binary-branchhintsec}{\B{branchhintkind}} From 36a0550c7bf4bcb63ceba0e202c2aea408e6e6a6 Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Mon, 15 Mar 2021 10:15:01 +0100 Subject: [PATCH 043/130] Add syntactic requirements to the branchHints section. (#10) See https://github.com/WebAssembly/branch-hinting/issues/2 --- document/core/appendix/custom.rst | 9 ++++++++- proposals/branch-hinting/Overview.md | 12 ++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/document/core/appendix/custom.rst b/document/core/appendix/custom.rst index 26590836a9..8a236aed22 100644 --- a/document/core/appendix/custom.rst +++ b/document/core/appendix/custom.rst @@ -357,12 +357,15 @@ An implementation is not required to follow the hints, and this section can be e The section contains a vector of *function branch hints* each representing the branch hints for a single function. -Each *function function hints* structure consists of +Each *function branch hints* structure consists of * the :ref:`function index ` of the function the hints are referring to, * a single 0 byte, * a vector of *branch hints* for the function. +Elements of the *function branch hints* vector must appear in increasing function index order, +and a function index can appear at most once. + Each *branch hint* structure consists of * a |U32| indicating the meaning of the hint: @@ -376,6 +379,10 @@ Value Meaning * the |U32| byte offset of the hinted instruction from the first instruction of the function. +Elements of the *branch hints* vector must appear in increasing byte offset order, +and a byte offset can appear at most once. A |BRIF| or |IF| instruction must be present +in the code section at the specified offset. + .. math:: \begin{array}{llclll} diff --git a/proposals/branch-hinting/Overview.md b/proposals/branch-hinting/Overview.md index ffd4f984cb..1c079e3540 100644 --- a/proposals/branch-hinting/Overview.md +++ b/proposals/branch-hinting/Overview.md @@ -51,7 +51,8 @@ https://github.com/WebAssembly/meetings/blob/master/main/2021/CG-02-16.md The *branch hints section* is a custom section whose name string is "branchHints". The branch hints section should appear only once in a module, and only before the code section. -The purpose of this section is to aid the compilation of conditional branch instructions, by providing a hint that a branch is very likely (or unlikely) to be taken. +The purpose of this section is to aid the compilation of conditional branch instructions, +by providing a hint that a branch is very likely (or unlikely) to be taken. An implementation is not required to follow the hints, and this section can be entirely ignored. @@ -63,6 +64,9 @@ Each *function hints* structure consists of * a single 0 byte * a vector of *branch hints* for the function. +Elements of the *function hints* vector must appear in increasing function index order, +and a function index can appear at most once. + Each *branch hint* structure consists of * a u32 indicating the meaning of the hint: @@ -72,5 +76,9 @@ Each *branch hint* structure consists of | 0 | likely not taken | | 1 | likely taken | -* the u32 byte offset of the hinted instruction from the first instruction of the function +* the u32 byte offset of the hinted instruction from the first instruction of the function. + +Elements of the *branch hints* vector must appear in increasing byte offset order, +and a byte offset can appear at most once. A `br_if` or `if` instruction must be present +in the code section at the specified offset. From 40ea5f5a4302cbcca36faa444a09043cf1cb1d58 Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Fri, 6 Aug 2021 17:06:03 +0200 Subject: [PATCH 044/130] Update the background with relevant discussions --- proposals/branch-hinting/Overview.md | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/proposals/branch-hinting/Overview.md b/proposals/branch-hinting/Overview.md index 1c079e3540..09faceda00 100644 --- a/proposals/branch-hinting/Overview.md +++ b/proposals/branch-hinting/Overview.md @@ -41,10 +41,29 @@ And some more discussion and feedback on the custom section format was done in t https://github.com/WebAssembly/meetings/blob/master/main/2021/CG-01-05.md -After that, a tentative spec was written and a poll for phase 2 scheduled for the CG-02-16: +After that, a tentative spec was written and there was further discussion in CG-02-16: https://github.com/WebAssembly/meetings/blob/master/main/2021/CG-02-16.md +And in CG-03-02: + +https://github.com/WebAssembly/meetings/blob/main/main/2021/CG-03-02.md + +Finally after working on the feedback received, a poll for phase 2 was made, and passed, in CG-03-16: + +https://github.com/WebAssembly/meetings/blob/main/main/2021/CG-03-16.md + +The feature landed in V8 92 under an experimental flag, and the CheerpX virtual machine started using it, +with measurable performance improvements. The results were shown in CG-06-08, plus the start of +a discussion about testing requirements for phase 3: + +https://github.com/WebAssembly/meetings/blob/main/main/2021/CG-06-08.md + +After the Instrument and Tracing Proposal passed to phase 2 in CG-07-20, the CG felt the need to +have a framework for standardizing proposals that use custom section as a way to hint the code +without altering the semantics. Ongoing discussion is in a design issue: + +https://github.com/WebAssembly/design/issues/1424 ### Design From 5ff3f0a4857247307ec09fdce67dba40ed52550f Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Fri, 5 Nov 2021 10:05:39 +0100 Subject: [PATCH 045/130] Branch Hinting: rewrite spec based on new code annotation approach --- document/core/appendix/custom.rst | 34 +++++++++++++++---------------- document/core/util/macros.def | 3 ++- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/document/core/appendix/custom.rst b/document/core/appendix/custom.rst index 8a236aed22..8c869fc111 100644 --- a/document/core/appendix/custom.rst +++ b/document/core/appendix/custom.rst @@ -342,32 +342,30 @@ Their relative placement will depend on the placement directive given for the :m .. index:: ! branch hints section, hint -.. _binary-branchHintsSec: -.. _binary-funchints: +.. _binary-branchhintsec: -Branch Hints Section +Branch Hint Section ~~~~~~~~~~~~~~~~~~~~ -The *branch hints section* is a :ref:`custom section ` whose name string is :math:`\text{branchHints}`. +The *branch hint section* is a :ref:`custom section ` whose name string is :math:`\text{code\_annotation.branch\_hint}`. The branch hints section should appear only once in a module, and only before the :ref:`code section `. The purpose of this section is to aid the compilation of conditional branch instructions, by providing a hint that a branch is very likely (or unlikely) to be taken. -An implementation is not required to follow the hints, and this section can be entirely ignored. - The section contains a vector of *function branch hints* each representing the branch hints for a single function. Each *function branch hints* structure consists of * the :ref:`function index ` of the function the hints are referring to, -* a single 0 byte, -* a vector of *branch hints* for the function. +* a vector of *branch hint* for the function. -Elements of the *function branch hints* vector must appear in increasing function index order, +Elements of the vector of *function branch hints* must appear in increasing function index order, and a function index can appear at most once. Each *branch hint* structure consists of +* the |U32| byte offset of the hinted instruction from the beginning of the function body, +* A byte with value 0x01, * a |U32| indicating the meaning of the hint: ===== =========================================== @@ -377,21 +375,21 @@ Value Meaning 0x01 branch likely taken ===== =========================================== -* the |U32| byte offset of the hinted instruction from the first instruction of the function. - -Elements of the *branch hints* vector must appear in increasing byte offset order, +Elements of the vector of *branch hint* must appear in increasing byte offset order, and a byte offset can appear at most once. A |BRIF| or |IF| instruction must be present in the code section at the specified offset. - .. math:: - \begin{array}{llclll} - \production{branch hints section} & \Bbranchhintssec &::=& - \Bsection_0(\Bvec(\Bfuncbranchhints)) \\ + \begin{array}{llcll} + \production{branch hint section} & \Bbranchhintsec &::=& + \Bsection_0(\Bbranchhintdata) \\ + \production{branch hint data} & \Bbranchhintdata &::=& + n{:}\Bname & (\iff n = \text{code\_annotation.branch\_hint}) \\ &&& + \Bvec(\Bfuncbranchhints) \\ \production{function branch hints} & \Bfuncbranchhints &::=& - \Bfuncidx~\hex{00}~\Bvec(\Bbranchhint) \\ + fidx{:}\Bfuncidx~\Bvec(\Bbranchhint) \\ \production{branch hint} & \Bbranchhint &::=& - \Bbranchhintkind~~\X{instoff}{:}\Bu32 \\ + \X{instoff}{:}\Bu32 ~~ \hex{01} ~~ \Bbranchhintkind \\ \production{branch hint kind} & \Bbranchhintkind &::=& \hex{00} \\ &&& \hex{01} \\ diff --git a/document/core/util/macros.def b/document/core/util/macros.def index 11a1a8e386..2e733d8546 100644 --- a/document/core/util/macros.def +++ b/document/core/util/macros.def @@ -1269,7 +1269,8 @@ .. Branch Hints Section, non-terminals -.. |Bbranchhintssec| mathdef:: \xref{appendix/custom}{binary-branchhintssec}{\B{branchhintssec}} +.. |Bbranchhintsec| mathdef:: \xref{appendix/custom}{binary-branchhintsec}{\B{branchhintsec}} +.. |Bbranchhintdata| mathdef:: \xref{appendix/custom}{binary-branchhintsec}{\B{branchhintdata}} .. |Bfuncbranchhints| mathdef:: \xref{appendix/custom}{binary-branchhintssec}{\B{funcbranchhints}} .. |Bbranchhint| mathdef:: \xref{appendix/custom}{binary-branchhintsec}{\B{branchhint}} .. |Bbranchhintkind| mathdef:: \xref{appendix/custom}{binary-branchhintsec}{\B{branchhintkind}} From a4a90d1636db6cffef3f834dc52ade09352eb997 Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Mon, 8 Nov 2021 17:30:53 +0100 Subject: [PATCH 046/130] Branch Hinting: Update benchmarks to new code annotation approach --- benchmarks/README.md | 7 +++---- benchmarks/test.wasm | Bin 89 -> 103 bytes benchmarks/test.wat | 1 - benchmarks/test_hint.wasm | Bin 109 -> 142 bytes benchmarks/test_hint.wat | 37 +++++++++++++++++++++++++++++++++++++ 5 files changed, 40 insertions(+), 5 deletions(-) create mode 100644 benchmarks/test_hint.wat diff --git a/benchmarks/README.md b/benchmarks/README.md index 8068d2ca6e..a672b0454f 100644 --- a/benchmarks/README.md +++ b/benchmarks/README.md @@ -11,14 +11,13 @@ We are benchmarking 2 similar wasm modules, all exporting a 'test' function: - `test.js`: Load the wasm modules and run benchmarks - `test.wat`: Text representation for the vanilla version -- `test.wasm`: wat2wasm of test.wat -- `test_hint.wasm`: Manually modified test.wasm to use branch hinting +- `test.wasm`: `wat2wasm test.wat -o test.wasm` +- `test_hint.wasm`: `wat2wasm --enable-code-annotations --enable-annotations test_hint.wat -o test_hint.wasm` run the benchmark: -`$D8_PATH/d8 test.js` +`$D8_PATH/d8 --experimental-wasm-branch-hinting test.js` Useful d8 options: - `--print-wasm-code` to see the generated assembly code -NOTE: In order to run the branch hinting version, you need a modified v8 (see [this repo](https://github.com/yuri91/v8)). diff --git a/benchmarks/test.wasm b/benchmarks/test.wasm index 7659124d531bb9f0b564fabd82d6c6b01135a533..e47ac02b2bc13fb4fb5fe566a415cbd18897bc90 100644 GIT binary patch delta 58 ycmaz{pI~Ha!f3?ESkLUBz^K6B$e8WM0%Qp=aD%x_NL)w8EG3{4PhJLYer^B~&Ii{3 delta 25 gcmYd~oM0rV#;C%`SkLUBz^K6B$e8WMI5AKR06^IU&;S4c diff --git a/benchmarks/test.wat b/benchmarks/test.wat index 73939d7475..435166f6ef 100644 --- a/benchmarks/test.wat +++ b/benchmarks/test.wat @@ -10,7 +10,6 @@ i32.const 1 i32.sub i32.eq - nop if local.get 1 call 0 diff --git a/benchmarks/test_hint.wasm b/benchmarks/test_hint.wasm index 5699652715bc7e37cfec996154c2f8a9ccc118ac..0108da1102300afe2ea8aa101d7ebfb358eb1983 100644 GIT binary patch delta 98 zcmd1pW1L_Vqbi-8pOPA%n3tDdl30?NpQo2pl$e*C5ucHnSHj51#LLJa!^ps8!f3?E mSkLUBz^K6B$e8WM0%Qp=aD%x_NL)w8EG3{4PhJLYer^Eec@vfZ delta 65 zcmeBU%$;ClEySHvl$e*C;gOkFQq0K6z{tSOrN*ej$XL(ppuniW;K-Qm#>fI>3NUah RFgh}3DFFpNc^SC*xdF Date: Wed, 10 Nov 2021 14:13:12 +0100 Subject: [PATCH 047/130] Branch Hinting: fix error in formal notation --- document/core/appendix/custom.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/document/core/appendix/custom.rst b/document/core/appendix/custom.rst index 8c869fc111..9b4b950419 100644 --- a/document/core/appendix/custom.rst +++ b/document/core/appendix/custom.rst @@ -391,7 +391,7 @@ in the code section at the specified offset. \production{branch hint} & \Bbranchhint &::=& \X{instoff}{:}\Bu32 ~~ \hex{01} ~~ \Bbranchhintkind \\ \production{branch hint kind} & \Bbranchhintkind &::=& - \hex{00} \\ &&& + \hex{00} \\ &&|& \hex{01} \\ \end{array} From f199a4b6ead09e2bc2033fb67adcad20ef94d6d8 Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Wed, 10 Nov 2021 14:13:56 +0100 Subject: [PATCH 048/130] Branch Hinting: update the overview --- proposals/branch-hinting/Overview.md | 45 ++++++++++++++++++---------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/proposals/branch-hinting/Overview.md b/proposals/branch-hinting/Overview.md index 09faceda00..5f522d2006 100644 --- a/proposals/branch-hinting/Overview.md +++ b/proposals/branch-hinting/Overview.md @@ -65,39 +65,52 @@ without altering the semantics. Ongoing discussion is in a design issue: https://github.com/WebAssembly/design/issues/1424 +The result of that discussion prompted the design of Code Annotations, presented in CG-08-17: + +https://github.com/WebAssembly/meetings/blob/main/main/2021/CG-08-17.md + +and in CG-09-28: + +https://github.com/WebAssembly/meetings/blob/main/main/2021/CG-09-28.md + +Branch hinting adpoted the Code Annotation format and an update about the new format +and the current status of the proposal, as well as a poll for phase 3 (which passed) + was held on CG-11-09: + +https://github.com/WebAssembly/meetings/blob/main/main/2021/CG-11-09.md + + + ### Design -The *branch hints section* is a custom section whose name string is "branchHints". +The *branch hint section* is a :ref:`custom section ` whose name string is `code_annotation.branch_hint`. The branch hints section should appear only once in a module, and only before the code section. -The purpose of this section is to aid the compilation of conditional branch instructions, -by providing a hint that a branch is very likely (or unlikely) to be taken. +The purpose of this section is to aid the compilation of conditional branch instructions, by providing a hint that a branch is very likely (or unlikely) to be taken. -An implementation is not required to follow the hints, and this section can be entirely ignored. +The section contains a vector of *function branch hints* each representing the branch hints for a single function. -The section contains a vector of *function hints* each representing the branch hints for a single function. +Each *function branch hints* structure consists of -Each *function hints* structure consists of +* the function index of the function the hints are referring to, +* a vector of *branch hint* for the function. -* the index of the function the hints are referring to, -* a single 0 byte -* a vector of *branch hints* for the function. - -Elements of the *function hints* vector must appear in increasing function index order, +Elements of the vector of *function branch hints* must appear in increasing function index order, and a function index can appear at most once. Each *branch hint* structure consists of -* a u32 indicating the meaning of the hint: +* the |U32| byte offset of the hinted instruction from the beginning of the function body, +* A byte with value 0x01, +* a |U32| indicating the meaning of the hint: | value | meaning | |-------|-------------------| | 0 | likely not taken | | 1 | likely taken | -* the u32 byte offset of the hinted instruction from the first instruction of the function. - -Elements of the *branch hints* vector must appear in increasing byte offset order, -and a byte offset can appear at most once. A `br_if` or `if` instruction must be present +Elements of the vector of *branch hint* must appear in increasing byte offset order, +and a byte offset can appear at most once. A |BRIF| or |IF| instruction must be present in the code section at the specified offset. +See the [the spec](/document/core/appendix/custom.rst) for the formal notation. From 24d885631b7cbe28c2cbf4b50294bd1d5efbde79 Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Mon, 7 Feb 2022 16:07:06 +0100 Subject: [PATCH 049/130] Branch Hinting: change section name to metadata.code.branch_hint --- document/core/appendix/custom.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/document/core/appendix/custom.rst b/document/core/appendix/custom.rst index 9b4b950419..0d7ef5d9a8 100644 --- a/document/core/appendix/custom.rst +++ b/document/core/appendix/custom.rst @@ -347,7 +347,7 @@ Their relative placement will depend on the placement directive given for the :m Branch Hint Section ~~~~~~~~~~~~~~~~~~~~ -The *branch hint section* is a :ref:`custom section ` whose name string is :math:`\text{code\_annotation.branch\_hint}`. +The *branch hint section* is a :ref:`custom section ` whose name string is :math:`\text{metadata.code.branch\_hint}`. The branch hints section should appear only once in a module, and only before the :ref:`code section `. The purpose of this section is to aid the compilation of conditional branch instructions, by providing a hint that a branch is very likely (or unlikely) to be taken. @@ -384,7 +384,7 @@ in the code section at the specified offset. \production{branch hint section} & \Bbranchhintsec &::=& \Bsection_0(\Bbranchhintdata) \\ \production{branch hint data} & \Bbranchhintdata &::=& - n{:}\Bname & (\iff n = \text{code\_annotation.branch\_hint}) \\ &&& + n{:}\Bname & (\iff n = \text{metadata.code.branch\_hint}) \\ &&& \Bvec(\Bfuncbranchhints) \\ \production{function branch hints} & \Bfuncbranchhints &::=& fidx{:}\Bfuncidx~\Bvec(\Bbranchhint) \\ From 20a71a6ca876439824018f9f275e69370fe8142b Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Mon, 21 Feb 2022 16:03:12 +0100 Subject: [PATCH 050/130] Branch Hinting: Add spec text for the branch hint annotations --- document/core/appendix/custom.rst | 116 ++++++++++++++++++------------ document/core/util/macros.def | 5 ++ 2 files changed, 74 insertions(+), 47 deletions(-) diff --git a/document/core/appendix/custom.rst b/document/core/appendix/custom.rst index 0d7ef5d9a8..14e8d35a6f 100644 --- a/document/core/appendix/custom.rst +++ b/document/core/appendix/custom.rst @@ -239,9 +239,63 @@ It may only be placed on a declaration that declares exactly one local. \end{array} +.. index:: ! branch hints section, hint +.. _binary-branchhintsec: + +Branch Hint Section +~~~~~~~~~~~~~~~~~~~~ + +The *branch hint section* is a :ref:`custom section ` whose name string is :math:`\text{metadata.code.branch\_hint}`. +The branch hints section should appear only once in a module, and only before the :ref:`code section `. + +The purpose of this section is to aid the compilation of conditional branch instructions, by providing a hint that a branch is very likely (or unlikely) to be taken. + +The section contains a vector of *function branch hints* each representing the branch hints for a single function. + +Each *function branch hints* structure consists of + +* the :ref:`function index ` of the function the hints are referring to, +* a vector of *branch hint* for the function. + +Elements of the vector of *function branch hints* must appear in increasing function index order, +and a function index can appear at most once. + +Each *branch hint* structure consists of + +* the |U32| byte offset of the hinted instruction from the beginning of the function body, +* A byte with value 0x01, +* a |U32| indicating the meaning of the hint: + +===== =========================================== +Value Meaning +===== =========================================== + 0x00 branch likely not taken + 0x01 branch likely taken +===== =========================================== + +Elements of the vector of *branch hint* must appear in increasing byte offset order, +and a byte offset can appear at most once. A |BRIF| or |IF| instruction must be present +in the code section at the specified offset. + +.. math:: + \begin{array}{llcll} + \production{branch hint section} & \Bbranchhintsec &::=& + \Bsection_0(\Bbranchhintdata) \\ + \production{branch hint data} & \Bbranchhintdata &::=& + n{:}\Bname & (\iff n = \text{metadata.code.branch\_hint}) \\ &&& + \Bvec(\Bfuncbranchhints) \\ + \production{function branch hints} & \Bfuncbranchhints &::=& + fidx{:}\Bfuncidx~\Bvec(\Bbranchhint) \\ + \production{branch hint} & \Bbranchhint &::=& + \X{instoff}{:}\Bu32 ~~ \hex{01} ~~ \Bbranchhintkind \\ + \production{branch hint kind} & \Bbranchhintkind &::=& + \hex{00} \\ &&|& + \hex{01} \\ + \end{array} .. index:: ! custom annotation, custom section .. _text-customannot: + Custom Annotations ~~~~~~~~~~~~~~~~~~ @@ -341,57 +395,25 @@ Their relative placement will depend on the placement directive given for the :m custom section "D" -.. index:: ! branch hints section, hint -.. _binary-branchhintsec: - -Branch Hint Section -~~~~~~~~~~~~~~~~~~~~ - -The *branch hint section* is a :ref:`custom section ` whose name string is :math:`\text{metadata.code.branch\_hint}`. -The branch hints section should appear only once in a module, and only before the :ref:`code section `. - -The purpose of this section is to aid the compilation of conditional branch instructions, by providing a hint that a branch is very likely (or unlikely) to be taken. - -The section contains a vector of *function branch hints* each representing the branch hints for a single function. +.. index:: ! branch hints annotation, hint +.. _text-branchhintannot: -Each *function branch hints* structure consists of +Branch Hint Annotations +~~~~~~~~~~~~~~~~~~~~~~~ -* the :ref:`function index ` of the function the hints are referring to, -* a vector of *branch hint* for the function. +*Branch Hint annotations* are the textual analogue to the :ref:`branch hint section ` and provide a textual representation for it. +Consequently, their id is :math:`\T{@metadata.code.branch\_hint}`. -Elements of the vector of *function branch hints* must appear in increasing function index order, -and a function index can appear at most once. +Branch hint annotations are allowed only on |BRIF| and |IF| instructions, +and at most one branch hint annotation may be given per instruction. -Each *branch hint* structure consists of - -* the |U32| byte offset of the hinted instruction from the beginning of the function body, -* A byte with value 0x01, -* a |U32| indicating the meaning of the hint: - -===== =========================================== -Value Meaning -===== =========================================== - 0x00 branch likely not taken - 0x01 branch likely taken -===== =========================================== - -Elements of the vector of *branch hint* must appear in increasing byte offset order, -and a byte offset can appear at most once. A |BRIF| or |IF| instruction must be present -in the code section at the specified offset. +Branch hint annotations have the following format: .. math:: - \begin{array}{llcll} - \production{branch hint section} & \Bbranchhintsec &::=& - \Bsection_0(\Bbranchhintdata) \\ - \production{branch hint data} & \Bbranchhintdata &::=& - n{:}\Bname & (\iff n = \text{metadata.code.branch\_hint}) \\ &&& - \Bvec(\Bfuncbranchhints) \\ - \production{function branch hints} & \Bfuncbranchhints &::=& - fidx{:}\Bfuncidx~\Bvec(\Bbranchhint) \\ - \production{branch hint} & \Bbranchhint &::=& - \X{instoff}{:}\Bu32 ~~ \hex{01} ~~ \Bbranchhintkind \\ - \production{branch hint kind} & \Bbranchhintkind &::=& - \hex{00} \\ &&|& - \hex{01} \\ + \begin{array}{llclll} + \production{branch hint annotation} & \Tbranchhintannot &::=& + \text{(@metadata.code.branch\_hint}~\Tbranchhintstr~\text{)} \\ + \production{branch hint string} & \Tbranchhintstr &::=& + \text{"\backslash 00"} \\ &&|& + \text{"\backslash 01"} \\ \end{array} - diff --git a/document/core/util/macros.def b/document/core/util/macros.def index 2e733d8546..a8692813d5 100644 --- a/document/core/util/macros.def +++ b/document/core/util/macros.def @@ -1293,6 +1293,11 @@ .. |Tparamnameannot| mathdef:: \xref{appendix/custom}{text-paramnameannot}{\T{paramnameannot}} .. |Tlocalnameannot| mathdef:: \xref{appendix/custom}{text-localnameannot}{\T{localnameannot}} +.. Branch Hint annotations, non-terminals + +.. |Tbranchhintannot| mathdef:: \xref{appendix/custom}{text-branchhintannot}{\T{branchhintannot}} +.. |Tbranchhintstr| mathdef:: \xref{appendix/custom}{text-branchhintannot}{\T{branchhintstr}} + .. Embedding .. --------- From cb747210c6e6b4535784a10352562b5cc218df59 Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Wed, 16 Feb 2022 16:41:30 +0100 Subject: [PATCH 051/130] Remove custom annotations section from the README --- README.md | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/README.md b/README.md index 35a4eebabc..0a3719cfc3 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,5 @@ ![Build Status](https://github.com/WebAssembly/annotations/actions/workflows/main.yml/badge.svg) -# Custom Annotations Proposal for WebAssembly - -This repository is a clone of [github.com/WebAssembly/spec/](https://github.com/WebAssembly/spec/). -It is meant for discussion, prototype specification and implementation of a proposal to add support for custom annotations to the WebAssembly text format. - -See the [overview](proposals/annotations/Overview.md) for a summary of the proposal. - -See draft spec at [webassembly.github.io/annotations](https://webassembly.github.io/annotations/). - -Original `README` from upstream repository follows... - # Branch hinting Proposal for WebAssembly This repository is a clone of [github.com/WebAssembly/spec/](https://github.com/WebAssembly/spec/). From cbb438fc3d351aea0f1863550d94170c650734d1 Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Wed, 16 Feb 2022 16:51:54 +0100 Subject: [PATCH 052/130] Branch Hinting: update Overview --- proposals/branch-hinting/Overview.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/proposals/branch-hinting/Overview.md b/proposals/branch-hinting/Overview.md index 5f522d2006..362cedb460 100644 --- a/proposals/branch-hinting/Overview.md +++ b/proposals/branch-hinting/Overview.md @@ -83,7 +83,7 @@ https://github.com/WebAssembly/meetings/blob/main/main/2021/CG-11-09.md ### Design -The *branch hint section* is a :ref:`custom section ` whose name string is `code_annotation.branch_hint`. +The *branch hint section* is a **custom section** whose name string is `metadata.code.branch_hint`. The branch hints section should appear only once in a module, and only before the code section. The purpose of this section is to aid the compilation of conditional branch instructions, by providing a hint that a branch is very likely (or unlikely) to be taken. @@ -113,4 +113,18 @@ Elements of the vector of *branch hint* must appear in increasing byte offset or and a byte offset can appear at most once. A |BRIF| or |IF| instruction must be present in the code section at the specified offset. +#### Annotations + +*Branch Hint annotations* are the textual analogue to the branch hint section and provide a textual representation for it. +Consequently, their id is :math:`@metadata.code.branch_hint`. + +Branch hint annotations are allowed only on |BRIF| and |IF| instructions, +and at most one branch hint annotation may be given per instruction. + +Branch hint annotations have the following format: + +``` +(@metadata.code.branch_hint "\00" | "\01") +``` + See the [the spec](/document/core/appendix/custom.rst) for the formal notation. From 64cb3bd5249d6a35585636bd5ba5321197de3160 Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Mon, 21 Feb 2022 16:24:28 +0100 Subject: [PATCH 053/130] Fix conf for branch hinting proposl --- document/core/conf.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/document/core/conf.py b/document/core/conf.py index 3bc2eb66d6..9530718f24 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 = 'annotations' +repo = 'branch-hinting' # The name of the proposal it represents, if any -proposal = 'custom annotations' +proposal = 'branch hinting' # The draft version string (clear out for release cuts) draft = ' (Draft ' + date.today().strftime("%Y-%m-%d") + ')' From 032f458fb41a5a2373e3ad8bc91439e5b13216f5 Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Mon, 21 Feb 2022 16:43:23 +0100 Subject: [PATCH 054/130] Branch Hinting: update readme with link to rendered spec --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 0a3719cfc3..c76518a437 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@ It is meant for discussion, prototype specification and implementation of a prop See the [overview](proposals/branch-hinting/Overview.md) for a summary of the proposal. +See draft spec at [webassembly.github.io/branch-hinting](https://webassembly.github.io/branch-hinting). + Original `README` from upstream repository follows... # spec From 4992a1df1cc7ad541d2ced0b6ee0df4663183ad3 Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Wed, 23 Feb 2022 10:57:06 +0100 Subject: [PATCH 055/130] Branch Hinting: update benchmark with new format --- benchmarks/README.md | 28 +++++++++++++++++++++++----- benchmarks/test.wasm | Bin 103 -> 0 bytes benchmarks/test.wat | 11 ++++++++++- benchmarks/test_hint.wasm | Bin 142 -> 0 bytes benchmarks/test_hint.wat | 37 ------------------------------------- 5 files changed, 33 insertions(+), 43 deletions(-) delete mode 100644 benchmarks/test.wasm delete mode 100644 benchmarks/test_hint.wasm delete mode 100644 benchmarks/test_hint.wat diff --git a/benchmarks/README.md b/benchmarks/README.md index a672b0454f..70565920f5 100644 --- a/benchmarks/README.md +++ b/benchmarks/README.md @@ -4,17 +4,35 @@ We are benchmarking 2 similar wasm modules, all exporting a 'test' function: - vanilla: Execute a loop many times doing some arithmetic, with a very unlikely if branch in the middle of the loop -- branch hinting proposal: Same, but includes a brancHints section with a hint that that if is unlikely +- branch hinting proposal: Same, but includes a metadata.code.branch_hint section with a hint that that if is unlikely +## Prerequisites + +You need: + +- This version of V8: https://github.com/yuri91/v8/tree/branch_hinting +- This version of Wabt: https://github.com/yuri91/wabt/tree/metadata ## Files - `test.js`: Load the wasm modules and run benchmarks -- `test.wat`: Text representation for the vanilla version -- `test.wasm`: `wat2wasm test.wat -o test.wasm` -- `test_hint.wasm`: `wat2wasm --enable-code-annotations --enable-annotations test_hint.wat -o test_hint.wasm` +- `test.wat`: Benchmark code in text formata + +### compile to wasm + +compile vanilla version: + +``` +wat2wasm test.wat --enable-annotations -o test.wasm +``` + +compile branch hinted version: + +``` +wat2wasm test.wat --enable-annotations --enable-code-metadata -o test_hint.wasm +``` -run the benchmark: +### run the benchmark `$D8_PATH/d8 --experimental-wasm-branch-hinting test.js` diff --git a/benchmarks/test.wasm b/benchmarks/test.wasm deleted file mode 100644 index e47ac02b2bc13fb4fb5fe566a415cbd18897bc90..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 103 zcmYj{K@LDL00eidMU?P_#uLN?^dj*K4i1PA?Y&>uIGNK-GFaS6092eAAWCvexAVRp o4_F4qN) Date: Thu, 24 Feb 2022 14:00:01 +0100 Subject: [PATCH 056/130] Branch Hinting: change fixed '1' value type from byte to u32 This does not change much but it is more compatible with the code metadata format, where the field is not fixed but it represents the size of the payload as a u32. --- document/core/appendix/custom.rst | 4 ++-- proposals/branch-hinting/Overview.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/document/core/appendix/custom.rst b/document/core/appendix/custom.rst index 14e8d35a6f..4f2c634f8e 100644 --- a/document/core/appendix/custom.rst +++ b/document/core/appendix/custom.rst @@ -263,7 +263,7 @@ and a function index can appear at most once. Each *branch hint* structure consists of * the |U32| byte offset of the hinted instruction from the beginning of the function body, -* A byte with value 0x01, +* A |U32| with value '1', * a |U32| indicating the meaning of the hint: ===== =========================================== @@ -287,7 +287,7 @@ in the code section at the specified offset. \production{function branch hints} & \Bfuncbranchhints &::=& fidx{:}\Bfuncidx~\Bvec(\Bbranchhint) \\ \production{branch hint} & \Bbranchhint &::=& - \X{instoff}{:}\Bu32 ~~ \hex{01} ~~ \Bbranchhintkind \\ + \X{instoff}{:}\Bu32 ~~ 1{:}\Bu32 ~~ \Bbranchhintkind \\ \production{branch hint kind} & \Bbranchhintkind &::=& \hex{00} \\ &&|& \hex{01} \\ diff --git a/proposals/branch-hinting/Overview.md b/proposals/branch-hinting/Overview.md index 362cedb460..923b174be4 100644 --- a/proposals/branch-hinting/Overview.md +++ b/proposals/branch-hinting/Overview.md @@ -101,7 +101,7 @@ and a function index can appear at most once. Each *branch hint* structure consists of * the |U32| byte offset of the hinted instruction from the beginning of the function body, -* A byte with value 0x01, +* A |U32| with value `1`, * a |U32| indicating the meaning of the hint: | value | meaning | From b2f68948d8bb88490f5d0f2e8ffb6cd4a4b5eed0 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Tue, 25 Apr 2023 11:57:52 +0200 Subject: [PATCH 057/130] Attempt to downgrade node.js --- .github/workflows/ci-interpreter.yml | 2 +- interpreter/winmake.bat | 153 ++++++++++++++------------- 2 files changed, 83 insertions(+), 72 deletions(-) diff --git a/.github/workflows/ci-interpreter.yml b/.github/workflows/ci-interpreter.yml index 6edfa0c460..8f3209f5e9 100644 --- a/.github/workflows/ci-interpreter.yml +++ b/.github/workflows/ci-interpreter.yml @@ -27,7 +27,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v2 with: - node-version: 19.x + node-version: 18.x - name: Build interpreter run: cd interpreter && opam exec make - name: Run tests diff --git a/interpreter/winmake.bat b/interpreter/winmake.bat index 6ff7e8caae..39278a8a0c 100644 --- a/interpreter/winmake.bat +++ b/interpreter/winmake.bat @@ -1,75 +1,86 @@ rem Auto-generated from Makefile! set NAME=wasm if '%1' neq '' set NAME=%1 -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I exec -I main -I syntax -I text -I binary -I script -I runtime -I util -I host -I valid -o exec/numeric_error.cmo exec/numeric_error.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I exec -I main -I syntax -I text -I binary -I script -I runtime -I util -I host -I valid -o exec/int.cmo exec/int.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I util -I main -I syntax -I text -I binary -I exec -I script -I runtime -I host -I valid -o util/lib.cmi util/lib.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I exec -I main -I syntax -I text -I binary -I script -I runtime -I util -I host -I valid -o exec/i32.cmo exec/i32.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I exec -I main -I syntax -I text -I binary -I script -I runtime -I util -I host -I valid -o exec/float.cmo exec/float.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I syntax -I main -I text -I binary -I exec -I script -I runtime -I util -I host -I valid -o syntax/types.cmo syntax/types.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I exec -I main -I syntax -I text -I binary -I script -I runtime -I util -I host -I valid -o exec/f32.cmo exec/f32.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I exec -I main -I syntax -I text -I binary -I script -I runtime -I util -I host -I valid -o exec/f64.cmo exec/f64.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I exec -I main -I syntax -I text -I binary -I script -I runtime -I util -I host -I valid -o exec/i64.cmo exec/i64.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I syntax -I main -I text -I binary -I exec -I script -I runtime -I util -I host -I valid -o syntax/values.cmo syntax/values.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I runtime -I main -I syntax -I text -I binary -I exec -I script -I util -I host -I valid -o runtime/memory.cmi runtime/memory.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I util -I main -I syntax -I text -I binary -I exec -I script -I runtime -I host -I valid -o util/source.cmi util/source.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I syntax -I main -I text -I binary -I exec -I script -I runtime -I util -I host -I valid -o syntax/ast.cmo syntax/ast.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I runtime -I main -I syntax -I text -I binary -I exec -I script -I util -I host -I valid -o runtime/func.cmi runtime/func.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I runtime -I main -I syntax -I text -I binary -I exec -I script -I util -I host -I valid -o runtime/global.cmi runtime/global.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I runtime -I main -I syntax -I text -I binary -I exec -I script -I util -I host -I valid -o runtime/table.cmi runtime/table.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I runtime -I main -I syntax -I text -I binary -I exec -I script -I util -I host -I valid -o runtime/instance.cmo runtime/instance.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I exec -I main -I syntax -I text -I binary -I script -I runtime -I util -I host -I valid -o exec/eval.cmi exec/eval.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I binary -I main -I syntax -I text -I exec -I script -I runtime -I util -I host -I valid -o binary/utf8.cmi binary/utf8.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I host -I main -I syntax -I text -I binary -I exec -I script -I runtime -I util -I valid -o host/env.cmo host/env.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I main -I syntax -I text -I binary -I exec -I script -I runtime -I util -I host -I valid -o main/flags.cmo main/flags.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I script -I main -I syntax -I text -I binary -I exec -I runtime -I util -I host -I valid -o script/import.cmi script/import.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I script -I main -I syntax -I text -I binary -I exec -I runtime -I util -I host -I valid -o script/run.cmi script/run.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I host -I main -I syntax -I text -I binary -I exec -I script -I runtime -I util -I valid -o host/spectest.cmo host/spectest.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I main -I syntax -I text -I binary -I exec -I script -I runtime -I util -I host -I valid -o main/main.cmo main/main.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I util -I main -I syntax -I text -I binary -I exec -I script -I runtime -I host -I valid -o util/error.cmi util/error.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I script -I main -I syntax -I text -I binary -I exec -I runtime -I util -I host -I valid -o script/script.cmo script/script.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I binary -I main -I syntax -I text -I exec -I script -I runtime -I util -I host -I valid -o binary/decode.cmi binary/decode.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I binary -I main -I syntax -I text -I exec -I script -I runtime -I util -I host -I valid -o binary/encode.cmi binary/encode.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I script -I main -I syntax -I text -I binary -I exec -I runtime -I util -I host -I valid -o script/js.cmi script/js.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I text -I main -I syntax -I binary -I exec -I script -I runtime -I util -I host -I valid -o text/parse.cmi text/parse.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I text -I main -I syntax -I binary -I exec -I script -I runtime -I util -I host -I valid -o text/print.cmi text/print.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I valid -I main -I syntax -I text -I binary -I exec -I script -I runtime -I util -I host -o valid/valid.cmi valid/valid.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I script -I main -I syntax -I text -I binary -I exec -I runtime -I util -I host -I valid -o script/import.cmo script/import.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I script -I main -I syntax -I text -I binary -I exec -I runtime -I util -I host -I valid -o script/run.cmo script/run.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I binary -I main -I syntax -I text -I exec -I script -I runtime -I util -I host -I valid -o binary/utf8.cmo binary/utf8.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I exec -I main -I syntax -I text -I binary -I script -I runtime -I util -I host -I valid -o exec/eval_numeric.cmi exec/eval_numeric.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I exec -I main -I syntax -I text -I binary -I script -I runtime -I util -I host -I valid -o exec/i64_convert.cmi exec/i64_convert.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I exec -I main -I syntax -I text -I binary -I script -I runtime -I util -I host -I valid -o exec/eval.cmo exec/eval.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I runtime -I main -I syntax -I text -I binary -I exec -I script -I util -I host -I valid -o runtime/func.cmo runtime/func.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I util -I main -I syntax -I text -I binary -I exec -I script -I runtime -I host -I valid -o util/source.cmo util/source.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I exec -I main -I syntax -I text -I binary -I script -I runtime -I util -I host -I valid -o exec/f32_convert.cmi exec/f32_convert.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I exec -I main -I syntax -I text -I binary -I script -I runtime -I util -I host -I valid -o exec/f64_convert.cmi exec/f64_convert.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I exec -I main -I syntax -I text -I binary -I script -I runtime -I util -I host -I valid -o exec/i32_convert.cmi exec/i32_convert.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I util -I main -I syntax -I text -I binary -I exec -I script -I runtime -I host -I valid -o util/error.cmo util/error.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I exec -I main -I syntax -I text -I binary -I script -I runtime -I util -I host -I valid -o exec/eval_numeric.cmo exec/eval_numeric.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I runtime -I main -I syntax -I text -I binary -I exec -I script -I util -I host -I valid -o runtime/global.cmo runtime/global.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I exec -I main -I syntax -I text -I binary -I script -I runtime -I util -I host -I valid -o exec/i64_convert.cmo exec/i64_convert.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I util -I main -I syntax -I text -I binary -I exec -I script -I runtime -I host -I valid -o util/lib.cmo util/lib.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I runtime -I main -I syntax -I text -I binary -I exec -I script -I util -I host -I valid -o runtime/memory.cmo runtime/memory.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I runtime -I main -I syntax -I text -I binary -I exec -I script -I util -I host -I valid -o runtime/table.cmo runtime/table.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I exec -I main -I syntax -I text -I binary -I script -I runtime -I util -I host -I valid -o exec/f32_convert.cmo exec/f32_convert.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I exec -I main -I syntax -I text -I binary -I script -I runtime -I util -I host -I valid -o exec/f64_convert.cmo exec/f64_convert.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I exec -I main -I syntax -I text -I binary -I script -I runtime -I util -I host -I valid -o exec/i32_convert.cmo exec/i32_convert.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I syntax -I main -I text -I binary -I exec -I script -I runtime -I util -I host -I valid -o syntax/operators.cmo syntax/operators.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I exec -I main -I syntax -I text -I binary -I script -I tests -I runtime -I util -I host -I valid -o exec/ixx.cmo exec/ixx.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I util -I main -I syntax -I text -I binary -I exec -I script -I tests -I runtime -I host -I valid -o util/lib.cmi util/lib.mli +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I exec -I main -I syntax -I text -I binary -I script -I tests -I runtime -I util -I host -I valid -o exec/i32.cmo exec/i32.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I exec -I main -I syntax -I text -I binary -I script -I tests -I runtime -I util -I host -I valid -o exec/fxx.cmo exec/fxx.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I syntax -I main -I text -I binary -I exec -I script -I tests -I runtime -I util -I host -I valid -o syntax/types.cmo syntax/types.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I exec -I main -I syntax -I text -I binary -I script -I tests -I runtime -I util -I host -I valid -o exec/f32.cmo exec/f32.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I exec -I main -I syntax -I text -I binary -I script -I tests -I runtime -I util -I host -I valid -o exec/f64.cmo exec/f64.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I exec -I main -I syntax -I text -I binary -I script -I tests -I runtime -I util -I host -I valid -o exec/i16.cmo exec/i16.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I exec -I main -I syntax -I text -I binary -I script -I tests -I runtime -I util -I host -I valid -o exec/i64.cmo exec/i64.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I exec -I main -I syntax -I text -I binary -I script -I tests -I runtime -I util -I host -I valid -o exec/i8.cmo exec/i8.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I exec -I main -I syntax -I text -I binary -I script -I tests -I runtime -I util -I host -I valid -o exec/v128.cmi exec/v128.mli +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I util -I main -I syntax -I text -I binary -I exec -I script -I tests -I runtime -I host -I valid -o util/source.cmi util/source.mli +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I binary -I main -I syntax -I text -I exec -I script -I tests -I runtime -I util -I host -I valid -o binary/utf8.cmi binary/utf8.mli +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I syntax -I main -I text -I binary -I exec -I script -I tests -I runtime -I util -I host -I valid -o syntax/values.cmo syntax/values.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I syntax -I main -I text -I binary -I exec -I script -I tests -I runtime -I util -I host -I valid -o syntax/ast.cmo syntax/ast.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I runtime -I main -I syntax -I text -I binary -I exec -I script -I tests -I util -I host -I valid -o runtime/memory.cmi runtime/memory.mli +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I runtime -I main -I syntax -I text -I binary -I exec -I script -I tests -I util -I host -I valid -o runtime/table.cmi runtime/table.mli +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I runtime -I main -I syntax -I text -I binary -I exec -I script -I tests -I util -I host -I valid -o runtime/data.cmi runtime/data.mli +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I runtime -I main -I syntax -I text -I binary -I exec -I script -I tests -I util -I host -I valid -o runtime/elem.cmi runtime/elem.mli +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I runtime -I main -I syntax -I text -I binary -I exec -I script -I tests -I util -I host -I valid -o runtime/func.cmi runtime/func.mli +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I runtime -I main -I syntax -I text -I binary -I exec -I script -I tests -I util -I host -I valid -o runtime/global.cmi runtime/global.mli +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I runtime -I main -I syntax -I text -I binary -I exec -I script -I tests -I util -I host -I valid -o runtime/instance.cmo runtime/instance.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I exec -I main -I syntax -I text -I binary -I script -I tests -I runtime -I util -I host -I valid -o exec/eval.cmi exec/eval.mli +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I host -I main -I syntax -I text -I binary -I exec -I script -I tests -I runtime -I util -I valid -o host/env.cmo host/env.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I main -I syntax -I text -I binary -I exec -I script -I tests -I runtime -I util -I host -I valid -o main/flags.cmo main/flags.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I script -I main -I syntax -I text -I binary -I exec -I tests -I runtime -I util -I host -I valid -o script/import.cmi script/import.mli +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I script -I main -I syntax -I text -I binary -I exec -I tests -I runtime -I util -I host -I valid -o script/run.cmi script/run.mli +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I host -I main -I syntax -I text -I binary -I exec -I script -I tests -I runtime -I util -I valid -o host/spectest.cmo host/spectest.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I main -I syntax -I text -I binary -I exec -I script -I tests -I runtime -I util -I host -I valid -o main/main.cmo main/main.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I util -I main -I syntax -I text -I binary -I exec -I script -I tests -I runtime -I host -I valid -o util/error.cmi util/error.mli +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I script -I main -I syntax -I text -I binary -I exec -I tests -I runtime -I util -I host -I valid -o script/script.cmo script/script.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I binary -I main -I syntax -I text -I exec -I script -I tests -I runtime -I util -I host -I valid -o binary/decode.cmi binary/decode.mli +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I binary -I main -I syntax -I text -I exec -I script -I tests -I runtime -I util -I host -I valid -o binary/encode.cmi binary/encode.mli +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I script -I main -I syntax -I text -I binary -I exec -I tests -I runtime -I util -I host -I valid -o script/js.cmi script/js.mli +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I text -I main -I syntax -I binary -I exec -I script -I tests -I runtime -I util -I host -I valid -o text/parse.cmi text/parse.mli +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I text -I main -I syntax -I binary -I exec -I script -I tests -I runtime -I util -I host -I valid -o text/print.cmi text/print.mli +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I valid -I main -I syntax -I text -I binary -I exec -I script -I tests -I runtime -I util -I host -o valid/valid.cmi valid/valid.mli +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I script -I main -I syntax -I text -I binary -I exec -I tests -I runtime -I util -I host -I valid -o script/import.cmo script/import.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I script -I main -I syntax -I text -I binary -I exec -I tests -I runtime -I util -I host -I valid -o script/run.cmo script/run.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I binary -I main -I syntax -I text -I exec -I script -I tests -I runtime -I util -I host -I valid -o binary/utf8.cmo binary/utf8.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I exec -I main -I syntax -I text -I binary -I script -I tests -I runtime -I util -I host -I valid -o exec/eval_num.cmi exec/eval_num.mli +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I exec -I main -I syntax -I text -I binary -I script -I tests -I runtime -I util -I host -I valid -o exec/eval_vec.cmi exec/eval_vec.mli +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I exec -I main -I syntax -I text -I binary -I script -I tests -I runtime -I util -I host -I valid -o exec/i64_convert.cmi exec/i64_convert.mli +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I exec -I main -I syntax -I text -I binary -I script -I tests -I runtime -I util -I host -I valid -o exec/eval.cmo exec/eval.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I runtime -I main -I syntax -I text -I binary -I exec -I script -I tests -I util -I host -I valid -o runtime/func.cmo runtime/func.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I util -I main -I syntax -I text -I binary -I exec -I script -I tests -I runtime -I host -I valid -o util/source.cmo util/source.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I exec -I main -I syntax -I text -I binary -I script -I tests -I runtime -I util -I host -I valid -o exec/f32_convert.cmi exec/f32_convert.mli +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I exec -I main -I syntax -I text -I binary -I script -I tests -I runtime -I util -I host -I valid -o exec/f64_convert.cmi exec/f64_convert.mli +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I exec -I main -I syntax -I text -I binary -I script -I tests -I runtime -I util -I host -I valid -o exec/i32_convert.cmi exec/i32_convert.mli +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I runtime -I main -I syntax -I text -I binary -I exec -I script -I tests -I util -I host -I valid -o runtime/data.cmo runtime/data.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I runtime -I main -I syntax -I text -I binary -I exec -I script -I tests -I util -I host -I valid -o runtime/elem.cmo runtime/elem.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I util -I main -I syntax -I text -I binary -I exec -I script -I tests -I runtime -I host -I valid -o util/error.cmo util/error.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I exec -I main -I syntax -I text -I binary -I script -I tests -I runtime -I util -I host -I valid -o exec/eval_num.cmo exec/eval_num.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I exec -I main -I syntax -I text -I binary -I script -I tests -I runtime -I util -I host -I valid -o exec/eval_vec.cmo exec/eval_vec.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I runtime -I main -I syntax -I text -I binary -I exec -I script -I tests -I util -I host -I valid -o runtime/global.cmo runtime/global.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I exec -I main -I syntax -I text -I binary -I script -I tests -I runtime -I util -I host -I valid -o exec/i64_convert.cmo exec/i64_convert.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I util -I main -I syntax -I text -I binary -I exec -I script -I tests -I runtime -I host -I valid -o util/lib.cmo util/lib.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I runtime -I main -I syntax -I text -I binary -I exec -I script -I tests -I util -I host -I valid -o runtime/memory.cmo runtime/memory.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I runtime -I main -I syntax -I text -I binary -I exec -I script -I tests -I util -I host -I valid -o runtime/table.cmo runtime/table.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I exec -I main -I syntax -I text -I binary -I script -I tests -I runtime -I util -I host -I valid -o exec/v128.cmo exec/v128.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I exec -I main -I syntax -I text -I binary -I script -I tests -I runtime -I util -I host -I valid -o exec/f32_convert.cmo exec/f32_convert.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I exec -I main -I syntax -I text -I binary -I script -I tests -I runtime -I util -I host -I valid -o exec/f64_convert.cmo exec/f64_convert.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I exec -I main -I syntax -I text -I binary -I script -I tests -I runtime -I util -I host -I valid -o exec/i32_convert.cmo exec/i32_convert.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I syntax -I main -I text -I binary -I exec -I script -I tests -I runtime -I util -I host -I valid -o syntax/free.cmi syntax/free.mli +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I syntax -I main -I text -I binary -I exec -I script -I tests -I runtime -I util -I host -I valid -o syntax/operators.cmo syntax/operators.ml ocamlyacc text/parser.mly -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I text -I main -I syntax -I binary -I exec -I script -I runtime -I util -I host -I valid -o text/parser.cmi text/parser.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I text -I main -I syntax -I binary -I exec -I script -I runtime -I util -I host -I valid -o text/lexer.cmi text/lexer.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I util -I main -I syntax -I text -I binary -I exec -I script -I runtime -I host -I valid -o util/sexpr.cmi util/sexpr.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I text -I main -I syntax -I binary -I exec -I script -I runtime -I util -I host -I valid -o text/arrange.cmi text/arrange.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I binary -I main -I syntax -I text -I exec -I script -I runtime -I util -I host -I valid -o binary/decode.cmo binary/decode.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I binary -I main -I syntax -I text -I exec -I script -I runtime -I util -I host -I valid -o binary/encode.cmo binary/encode.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I script -I main -I syntax -I text -I binary -I exec -I runtime -I util -I host -I valid -o script/js.cmo script/js.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I text -I main -I syntax -I binary -I exec -I script -I runtime -I util -I host -I valid -o text/parse.cmo text/parse.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I text -I main -I syntax -I binary -I exec -I script -I runtime -I util -I host -I valid -o text/print.cmo text/print.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I valid -I main -I syntax -I text -I binary -I exec -I script -I runtime -I util -I host -o valid/valid.cmo valid/valid.ml -ocamllex.opt -q text/lexer.mll -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I text -I main -I syntax -I binary -I exec -I script -I runtime -I util -I host -I valid -o text/lexer.cmo text/lexer.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I text -I main -I syntax -I binary -I exec -I script -I runtime -I util -I host -I valid -o text/parser.cmo text/parser.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I text -I main -I syntax -I binary -I exec -I script -I runtime -I util -I host -I valid -o text/arrange.cmo text/arrange.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I util -I main -I syntax -I text -I binary -I exec -I script -I runtime -I host -I valid -o util/sexpr.cmo util/sexpr.ml -ocamlc.opt bigarray.cma -I util -I binary -I exec -I syntax -I runtime -I host -I main -I script -I text -I valid util/lib.cmo binary/utf8.cmo exec/float.cmo exec/f32.cmo exec/f64.cmo exec/numeric_error.cmo exec/int.cmo exec/i32.cmo exec/i64.cmo exec/i32_convert.cmo exec/f32_convert.cmo exec/i64_convert.cmo exec/f64_convert.cmo syntax/types.cmo syntax/values.cmo runtime/memory.cmo util/source.cmo syntax/ast.cmo exec/eval_numeric.cmo runtime/func.cmo runtime/global.cmo runtime/table.cmo runtime/instance.cmo util/error.cmo exec/eval.cmo host/env.cmo host/spectest.cmo main/flags.cmo script/import.cmo binary/encode.cmo syntax/operators.cmo binary/decode.cmo script/script.cmo text/parser.cmo text/lexer.cmo text/parse.cmo script/js.cmo util/sexpr.cmo text/arrange.cmo text/print.cmo valid/valid.cmo script/run.cmo main/main.cmo -o main/main.byte +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I text -I main -I syntax -I binary -I exec -I script -I tests -I runtime -I util -I host -I valid -o text/parser.cmi text/parser.mli +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I text -I main -I syntax -I binary -I exec -I script -I tests -I runtime -I util -I host -I valid -o text/lexer.cmi text/lexer.mli +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I util -I main -I syntax -I text -I binary -I exec -I script -I tests -I runtime -I host -I valid -o util/sexpr.cmi util/sexpr.mli +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I text -I main -I syntax -I binary -I exec -I script -I tests -I runtime -I util -I host -I valid -o text/arrange.cmi text/arrange.mli +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I binary -I main -I syntax -I text -I exec -I script -I tests -I runtime -I util -I host -I valid -o binary/decode.cmo binary/decode.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I binary -I main -I syntax -I text -I exec -I script -I tests -I runtime -I util -I host -I valid -o binary/encode.cmo binary/encode.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I script -I main -I syntax -I text -I binary -I exec -I tests -I runtime -I util -I host -I valid -o script/js.cmo script/js.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I text -I main -I syntax -I binary -I exec -I script -I tests -I runtime -I util -I host -I valid -o text/parse.cmo text/parse.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I text -I main -I syntax -I binary -I exec -I script -I tests -I runtime -I util -I host -I valid -o text/print.cmo text/print.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I valid -I main -I syntax -I text -I binary -I exec -I script -I tests -I runtime -I util -I host -o valid/valid.cmo valid/valid.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I syntax -I main -I text -I binary -I exec -I script -I tests -I runtime -I util -I host -I valid -o syntax/free.cmo syntax/free.ml +ocamllex.opt -ml -q text/lexer.mll +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I text -I main -I syntax -I binary -I exec -I script -I tests -I runtime -I util -I host -I valid -o text/lexer.cmo text/lexer.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I text -I main -I syntax -I binary -I exec -I script -I tests -I runtime -I util -I host -I valid -o text/parser.cmo text/parser.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I text -I main -I syntax -I binary -I exec -I script -I tests -I runtime -I util -I host -I valid -o text/arrange.cmo text/arrange.ml +ocamlc.opt -c -w +a-4-27-42-44-45-70 -warn-error +a-3 -I util -I main -I syntax -I text -I binary -I exec -I script -I tests -I runtime -I host -I valid -o util/sexpr.cmo util/sexpr.ml +ocamlc.opt -I util -I binary -I exec -I syntax -I main -I runtime -I host -I script -I text -I valid util/lib.cmo binary/utf8.cmo exec/fxx.cmo exec/f32.cmo exec/f64.cmo exec/ixx.cmo exec/i32.cmo exec/i64.cmo exec/i32_convert.cmo exec/f32_convert.cmo exec/i64_convert.cmo exec/f64_convert.cmo exec/i16.cmo exec/i8.cmo syntax/types.cmo exec/v128.cmo syntax/values.cmo util/source.cmo syntax/ast.cmo exec/eval_num.cmo exec/eval_vec.cmo main/flags.cmo runtime/memory.cmo runtime/data.cmo runtime/table.cmo runtime/elem.cmo runtime/func.cmo runtime/global.cmo runtime/instance.cmo util/error.cmo exec/eval.cmo host/env.cmo host/spectest.cmo script/import.cmo syntax/free.cmo binary/encode.cmo syntax/operators.cmo binary/decode.cmo script/script.cmo text/parser.cmo text/lexer.cmo text/parse.cmo script/js.cmo util/sexpr.cmo text/arrange.cmo text/print.cmo valid/valid.cmo script/run.cmo main/main.cmo -o main/main.byte From e3c0b5d845e289a2353576b528b1436e8d53edeb Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Tue, 25 Apr 2023 12:03:57 +0200 Subject: [PATCH 058/130] Rrrh... --- .github/workflows/ci-interpreter.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-interpreter.yml b/.github/workflows/ci-interpreter.yml index 8f3209f5e9..416449d54e 100644 --- a/.github/workflows/ci-interpreter.yml +++ b/.github/workflows/ci-interpreter.yml @@ -27,7 +27,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v2 with: - node-version: 18.x + node-version: 18.14.x - name: Build interpreter run: cd interpreter && opam exec make - name: Run tests From cff2af9b38042524bb8448cce25f7360209beeb8 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Tue, 25 Apr 2023 12:32:47 +0200 Subject: [PATCH 059/130] Try to get output --- .github/workflows/ci-interpreter.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci-interpreter.yml b/.github/workflows/ci-interpreter.yml index 416449d54e..6a1da30919 100644 --- a/.github/workflows/ci-interpreter.yml +++ b/.github/workflows/ci-interpreter.yml @@ -27,8 +27,10 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v2 with: - node-version: 18.14.x + node-version: 19.x - name: Build interpreter run: cd interpreter && opam exec make + - name: Run annotate test + run: cd interpreter && (opam exec make test/annotations || node _output/annotations.js) - name: Run tests run: cd interpreter && opam exec make JS=node ci From 603d14861821258418b2cf202b903d3e114987b5 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Tue, 25 Apr 2023 14:04:19 +0200 Subject: [PATCH 060/130] Another attempt to get output --- .github/workflows/ci-interpreter.yml | 2 -- test/core/run.py | 6 +++++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-interpreter.yml b/.github/workflows/ci-interpreter.yml index 6a1da30919..6edfa0c460 100644 --- a/.github/workflows/ci-interpreter.yml +++ b/.github/workflows/ci-interpreter.yml @@ -30,7 +30,5 @@ jobs: node-version: 19.x - name: Build interpreter run: cd interpreter && opam exec make - - name: Run annotate test - run: cd interpreter && (opam exec make test/annotations || node _output/annotations.js) - name: Run tests run: cd interpreter && opam exec make JS=node ci diff --git a/test/core/run.py b/test/core/run.py index 27c0694364..62a99c6b42 100755 --- a/test/core/run.py +++ b/test/core/run.py @@ -47,7 +47,11 @@ 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)) + if exitCode != expectedExitCode: + print("=== log ===") + subprocess.call("cat %s" % logPath, shell=True) + print("===========") + 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): From 09c8953976a7c525abb105d0836796f92fdb2e91 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Tue, 25 Apr 2023 14:30:45 +0200 Subject: [PATCH 061/130] Avoid duplicate module name in test and improve diagnostics --- interpreter/script/run.ml | 23 +++++++++++++---------- test/core/annotations.wast | 4 ++-- test/core/run.py | 11 +++++------ 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/interpreter/script/run.ml b/interpreter/script/run.ml index e0019d84a0..583bd2a22f 100644 --- a/interpreter/script/run.ml +++ b/interpreter/script/run.ml @@ -303,11 +303,14 @@ let modules : Ast.module_ Map.t ref = ref Map.empty let instances : Instance.module_inst Map.t ref = ref Map.empty let registry : Instance.module_inst Map.t ref = ref Map.empty -let bind map x_opt y = +let bind category map x_opt y = let map' = match x_opt with | None -> !map - | Some x -> Map.add x.it y !map + | Some x -> + if Map.mem x.it !map then + IO.error x.at (category ^ " " ^ x.it ^ " already defined"); + Map.add x.it y !map in map := Map.add "" y map' let lookup category map x_opt at = @@ -518,13 +521,13 @@ let rec run_command cmd = print_module x_opt m end end; - bind scripts x_opt [cmd]; - bind modules x_opt m; + bind "module" modules x_opt m; + bind "script" scripts x_opt [cmd]; if not !Flags.dry then begin trace "Initializing..."; let imports = Import.link m in let inst = Eval.init m imports in - bind instances x_opt inst + bind "instance" instances x_opt inst end | Register (name, x_opt) -> @@ -556,17 +559,17 @@ and run_meta cmd = match cmd.it with | Script (x_opt, script) -> run_quote_script script; - bind scripts x_opt (lookup_script None cmd.at) + bind "script" scripts x_opt (lookup_script None cmd.at) | Input (x_opt, file) -> (try if not (input_file file run_quote_script) then Abort.error cmd.at "aborting" with Sys_error msg -> IO.error cmd.at msg); - bind scripts x_opt (lookup_script None cmd.at); + bind "script" scripts x_opt (lookup_script None cmd.at); if x_opt <> None then begin - bind modules x_opt (lookup_module None cmd.at); + bind "module" modules x_opt (lookup_module None cmd.at); if not !Flags.dry then begin - bind instances x_opt (lookup_instance None cmd.at) + bind "instance" instances x_opt (lookup_instance None cmd.at) end end @@ -588,7 +591,7 @@ and run_quote_script script = let save_quote = !quote in quote := []; (try run_script script with exn -> quote := save_quote; raise exn); - bind scripts None (List.rev !quote); + bind "script" scripts None (List.rev !quote); quote := !quote @ save_quote let run_file file = input_file file run_script diff --git a/test/core/annotations.wast b/test/core/annotations.wast index ce538d9371..865581c68a 100644 --- a/test/core/annotations.wast +++ b/test/core/annotations.wast @@ -117,7 +117,7 @@ ) (@a) ) (@a) -((@a) module (@a) $m (@a) (@a) +((@a) module (@a) $m1 (@a) (@a) ((@a) global (@a) $g (@a) ((@a) export (@a) "g" (@a)) (@a) ((@a) import (@a) "spectest" (@a) "global_i32" (@a)) (@a) @@ -142,7 +142,7 @@ ) (@a) ) (@a) -((@a) module (@a) $m (@a) (@a) +((@a) module (@a) $m2 (@a) (@a) ((@a) type (@a) $T (@a) ((@a) func (@a) ((@a) param (@a) i32 (@a) i64 (@a)) (@a) diff --git a/test/core/run.py b/test/core/run.py index 62a99c6b42..fa80ea969b 100755 --- a/test/core/run.py +++ b/test/core/run.py @@ -47,11 +47,10 @@ 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) - if exitCode != expectedExitCode: - print("=== log ===") - subprocess.call("cat %s" % logPath, shell=True) - print("===========") - self.assertEqual(expectedExitCode, exitCode, "failed with exit code %i (expected %i) for %s" % (exitCode, expectedExitCode, command)) + with open(logPath) as out: + log = out.read() + msg = "failed with exit code %i (expected %i)\nCommand:\n %s\nLog:\n%s" + self.assertEqual(expectedExitCode, exitCode, msg % (exitCode, expectedExitCode, command, log)) def _auxFile(self, path): if os.path.exists(path): @@ -64,7 +63,7 @@ def _compareFile(self, expectFile, actualFile): with open(actualFile) as actual: expectText = expect.read() actualText = actual.read() - self.assertEqual(expectText, actualText) + self.assertEqual(expectText, actualText) def _runTestFile(self, inputPath): dir, inputFile = os.path.split(inputPath) From 891253cb48949195025d1a358fcf8695eaa6c051 Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Tue, 25 Apr 2023 19:10:33 +0200 Subject: [PATCH 062/130] [interpreter] Handle custom sections and annotations (#17) * [interpreter] Handle custom sections and annotations Co-authored-by: Yuri Iozzelli * Fix merge conflict * Fix lexer priorities * Fix wast.ml * Oops * Update wast.ml --------- Co-authored-by: Andreas Rossberg --- interpreter/Makefile | 62 ++++- interpreter/binary/decode.ml | 154 ++++++----- interpreter/binary/decode.mli | 3 +- interpreter/binary/encode.ml | 48 +++- interpreter/binary/encode.mli | 2 +- interpreter/custom/custom.ml | 85 ++++++ interpreter/custom/handler_custom.ml | 168 ++++++++++++ interpreter/custom/handler_custom.mli | 1 + interpreter/custom/handler_name.ml | 358 ++++++++++++++++++++++++++ interpreter/custom/handler_name.mli | 1 + interpreter/main/flags.ml | 1 + interpreter/main/main.ml | 27 +- interpreter/meta/jslib/wast.ml | 2 +- interpreter/script/js.ml | 8 +- interpreter/script/run.ml | 41 +-- interpreter/script/script.ml | 2 +- interpreter/text/annot.ml | 53 ++++ interpreter/text/arrange.ml | 28 +- interpreter/text/arrange.mli | 8 + interpreter/text/lexer.mll | 46 +++- interpreter/text/parse.ml | 27 +- interpreter/text/parser.mly | 49 +++- interpreter/text/print.ml | 1 + interpreter/text/print.mli | 1 + interpreter/valid/valid.ml | 4 + interpreter/valid/valid.mli | 1 + test/core/annotations.wast | 36 +-- test/core/run.py | 16 +- test/custom/custom/custom_annot.wast | 99 +++++++ test/custom/name/name_annot.wast | 20 ++ 30 files changed, 1180 insertions(+), 172 deletions(-) create mode 100644 interpreter/custom/custom.ml create mode 100644 interpreter/custom/handler_custom.ml create mode 100644 interpreter/custom/handler_custom.mli create mode 100644 interpreter/custom/handler_name.ml create mode 100644 interpreter/custom/handler_name.mli create mode 100644 interpreter/text/annot.ml create mode 100644 test/custom/custom/custom_annot.wast create mode 100644 test/custom/name/name_annot.wast diff --git a/interpreter/Makefile b/interpreter/Makefile index 3294e26822..0ce6ed8c56 100644 --- a/interpreter/Makefile +++ b/interpreter/Makefile @@ -17,7 +17,7 @@ ZIP = $(NAME).zip JSLIB = wast WINMAKE = winmake.bat -DIRS = util syntax binary text valid runtime exec script host main tests +DIRS = util syntax binary text valid runtime exec custom script host main tests LIBS = FLAGS = -lexflags -ml -cflags '-w +a-4-27-42-44-45-70 -warn-error +a-3' OCBA = ocamlbuild $(FLAGS) $(DIRS:%=-I %) @@ -37,10 +37,10 @@ unopt: $(UNOPT) libopt: _build/$(LIB).cmx _build/$(LIB).cmxa libunopt: _build/$(LIB).cmo _build/$(LIB).cma jslib: $(JSLIB).js -all: unopt opt libunopt libopt test +all: unopt opt libunopt libopt alltest +alltest: unittest test customtest land: $(WINMAKE) all zip: $(ZIP) -smallint: smallint.native ci: land wast.js dunebuild dunebuild: @@ -135,21 +135,18 @@ $(WINMAKE): clean >>$@ -# Executing test suite +# Executing core test suite TESTDIR = ../test/core -# Skip _output directory, since that's a tmp directory, and list all other wast files. TESTFILES = $(shell cd $(TESTDIR); ls *.wast; ls [a-z]*/*.wast) TESTS = $(TESTFILES:%.wast=%) -.PHONY: test debugtest partest dune-test +.PHONY: test debugtest partest dune-test quiettest -test: $(OPT) smallint +test: $(OPT) $(TESTDIR)/run.py --wasm `pwd`/$(OPT) $(if $(JS),--js '$(JS)',) - ./smallint.native -debugtest: $(UNOPT) smallint +debugtest: $(UNOPT) $(TESTDIR)/run.py --wasm `pwd`/$(UNOPT) $(if $(JS),--js '$(JS)',) - ./smallint.native test/%: $(OPT) $(TESTDIR)/run.py --wasm `pwd`/$(OPT) $(if $(JS),--js '$(JS)',) $(TESTDIR)/$*.wast @@ -171,9 +168,52 @@ quiettest/%: $(OPT) ) || \ cat $(@F).out || rm $(@F).out || exit 1 -smallinttest: smallint + +# Executing custom test suite + +CUSTOMTESTDIR = ../test/custom +CUSTOMTESTDIRS = $(shell cd $(CUSTOMTESTDIR); ls -d [a-z]*) +CUSTOMTESTFILES = $(shell cd $(CUSTOMTESTDIR); ls [a-z]*/*.wast) +CUSTOMTESTS = $(CUSTOMTESTFILES:%.wast=%) +CUSTOMOPTS = -c custom $(CUSTOMTESTDIRS:%=-c %) + +.PHONY: customtest customdebugtest custompartest customquiettest + +customtest: $(OPT) + $(TESTDIR)/run.py --wasm `pwd`/$(OPT) --opts '$(CUSTOMOPTS)' $(if $(JS),--js '$(JS)',) $(CUSTOMTESTFILES:%=$(CUSTOMTESTDIR)/%) +customdebugtest: $(UNOPT) + $(TESTDIR)/run.py --wasm `pwd`/$(UNOPT) --opts '$(CUSTOMOPTS)' $(if $(JS),--js '$(JS)',) $(CUSTOMTESTFILES:%=$(CUSTOMTESTDIR)/%) + +customtest/%: $(OPT) + $(TESTDIR)/run.py --wasm `pwd`/$(OPT) --opts '$(CUSTOMOPTS) ' $(if $(JS),--js '$(JS)',) $(CUSTOMTESTDIR)/$*.wast +customdebugtest/%: $(UNOPT) + $(TESTDIR)/run.py --wasm `pwd`/$(UNOPT) --opts '$(CUSTOMOPTS)' $(if $(JS),--js '$(JS)',) $(CUSTOMTESTDIR)/$*.wast + +customrun/%: $(OPT) + ./$(OPT) $(CUSTOMOPTS) $(CUSTOMTESTDIR)/$*.wast +customdebug/%: $(UNOPT) + ./$(UNOPT) $(CUSTOMOPTS) $(CUSTOMTESTDIR)/$*.wast + +custompartest: $(CUSTOMTESTS:%=customquiettest/%) + @echo All custom tests passed. + +customquiettest/%: $(OPT) + @ ( \ + $(TESTDIR)/run.py 2>$(@F).out --wasm `pwd`/$(OPT) --opts '$(CUSTOMOPTS)' $(if $(JS),--js '$(JS)',) $(TESTDIR)/$*.wast && \ + rm $(@F).out \ + ) || \ + cat $(@F).out || rm $(@F).out || exit 1 + + +# Executing unit tests + +.PHONY: unittest + +unittest: smallint @./smallint.native +smallint: smallint.native + dunetest: dune test diff --git a/interpreter/binary/decode.ml b/interpreter/binary/decode.ml index fa3a0ef9e5..d557978290 100644 --- a/interpreter/binary/decode.ml +++ b/interpreter/binary/decode.ml @@ -798,19 +798,19 @@ let id s = let bo = peek s in Lib.Option.map (function - | 0 -> `CustomSection - | 1 -> `TypeSection - | 2 -> `ImportSection - | 3 -> `FuncSection - | 4 -> `TableSection - | 5 -> `MemorySection - | 6 -> `GlobalSection - | 7 -> `ExportSection - | 8 -> `StartSection - | 9 -> `ElemSection - | 10 -> `CodeSection - | 11 -> `DataSection - | 12 -> `DataCountSection + | 0 -> Custom.Custom + | 1 -> Custom.Type + | 2 -> Custom.Import + | 3 -> Custom.Func + | 4 -> Custom.Table + | 5 -> Custom.Memory + | 6 -> Custom.Global + | 7 -> Custom.Export + | 8 -> Custom.Start + | 9 -> Custom.Elem + | 10 -> Custom.Code + | 11 -> Custom.Data + | 12 -> Custom.DataCount | _ -> error s (pos s) "malformed section id" ) bo @@ -828,7 +828,7 @@ let section tag f default s = let type_ s = at func_type s let type_section s = - section `TypeSection (vec type_) [] s + section Custom.Type (vec type_) [] s (* Import section *) @@ -848,13 +848,13 @@ let import s = {module_name; item_name; idesc} let import_section s = - section `ImportSection (vec (at import)) [] s + section Custom.Import (vec (at import)) [] s (* Function section *) let func_section s = - section `FuncSection (vec (at var)) [] s + section Custom.Func (vec (at var)) [] s (* Table section *) @@ -864,7 +864,7 @@ let table s = {ttype} let table_section s = - section `TableSection (vec (at table)) [] s + section Custom.Table (vec (at table)) [] s (* Memory section *) @@ -874,7 +874,7 @@ let memory s = {mtype} let memory_section s = - section `MemorySection (vec (at memory)) [] s + section Custom.Memory (vec (at memory)) [] s (* Global section *) @@ -885,7 +885,7 @@ let global s = {gtype; ginit} let global_section s = - section `GlobalSection (vec (at global)) [] s + section Custom.Global (vec (at global)) [] s (* Export section *) @@ -904,7 +904,7 @@ let export s = {name; edesc} let export_section s = - section `ExportSection (vec (at export)) [] s + section Custom.Export (vec (at export)) [] s (* Start section *) @@ -914,7 +914,7 @@ let start s = {sfunc} let start_section s = - section `StartSection (opt (at start) true) None s + section Custom.Start (opt (at start) true) None s (* Code section *) @@ -939,7 +939,7 @@ let code _ s = {locals; body; ftype = -1l @@ no_region} let code_section s = - section `CodeSection (vec (at (sized code))) [] s + section Custom.Code (vec (at (sized code))) [] s (* Element section *) @@ -1012,7 +1012,7 @@ let elem s = | _ -> error s (pos s - 1) "malformed elements segment kind" let elem_section s = - section `ElemSection (vec (at elem)) [] s + section Custom.Elem (vec (at elem)) [] s (* Data section *) @@ -1034,7 +1034,7 @@ let data s = | _ -> error s (pos s - 1) "malformed data segment kind" let data_section s = - section `DataSection (vec (at data)) [] s + section Custom.Data (vec (at data)) [] s (* DataCount section *) @@ -1043,62 +1043,64 @@ let data_count s = Some (u32 s) let data_count_section s = - section `DataCountSection data_count None s + section Custom.DataCount data_count None s (* Custom section *) -let custom size s = +let custom place size s = let start = pos s in - let id = name s in - let bs = get_string (size - (pos s - start)) s in - Some (id, bs) + let name = name s in + let content = get_string (size - (pos s - start)) s in + Custom.{name; content; place} -let custom_section s = - section_with_size `CustomSection custom None s +let some_custom place size s = + Some (at (custom place size) s) -let non_custom_section s = - match id s with - | None | Some `CustomSection -> None - | _ -> skip 1 s; sized skip s; Some () +let custom_section place s = + section_with_size Custom.Custom (some_custom place) None s (* Modules *) -let rec iterate f s = if f s <> None then iterate f s +let rec iterate f s = + match f s with + | None -> [] + | Some x -> x :: iterate f s let magic = 0x6d736100l let module_ s = + let open Custom in let header = word32 s in require (header = magic) s 0 "magic header not detected"; let version = word32 s in require (version = Encode.version) s 4 "unknown binary version"; - iterate custom_section s; + let customs = iterate (custom_section (Before Type)) s in let types = type_section s in - iterate custom_section s; + let customs = customs @ iterate (custom_section (After Type)) s in let imports = import_section s in - iterate custom_section s; + let customs = customs @ iterate (custom_section (After Import)) s in let func_types = func_section s in - iterate custom_section s; + let customs = customs @ iterate (custom_section (After Func)) s in let tables = table_section s in - iterate custom_section s; + let customs = customs @ iterate (custom_section (After Table)) s in let memories = memory_section s in - iterate custom_section s; + let customs = customs @ iterate (custom_section (After Memory)) s in let globals = global_section s in - iterate custom_section s; + let customs = customs @ iterate (custom_section (After Global)) s in let exports = export_section s in - iterate custom_section s; + let customs = customs @ iterate (custom_section (After Export)) s in let start = start_section s in - iterate custom_section s; + let customs = customs @ iterate (custom_section (After Start)) s in let elems = elem_section s in - iterate custom_section s; + let customs = customs @ iterate (custom_section (After Elem)) s in let data_count = data_count_section s in - iterate custom_section s; + let customs = customs @ iterate (custom_section (After DataCount)) s in let func_bodies = code_section s in - iterate custom_section s; + let customs = customs @ iterate (custom_section (After Code)) s in let datas = data_section s in - iterate custom_section s; + let customs = customs @ iterate (custom_section (After Data)) s in require (pos s = len s) s (len s) "unexpected content after last section"; require (List.length func_types = List.length func_bodies) s (len s) "function and code section have inconsistent lengths"; @@ -1108,23 +1110,37 @@ let module_ s = List.for_all Free.(fun f -> (func f).datas = Set.empty) func_bodies) s (len s) "data count section required"; let funcs = - List.map2 (fun t f -> {f.it with ftype = t} @@ f.at) func_types func_bodies - in {types; tables; memories; globals; funcs; imports; exports; elems; datas; start} - - -let decode name bs = at module_ (stream name bs) - -let all_custom tag s = - let header = word32 s in - require (header = magic) s 0 "magic header not detected"; - let version = word32 s in - require (version = Encode.version) s 4 "unknown binary version"; - let rec collect () = - iterate non_custom_section s; - match custom_section s with - | None -> [] - | Some (n, s) when n = tag -> s :: collect () - | Some _ -> collect () - in collect () - -let decode_custom tag name bs = all_custom tag (stream name bs) + List.map2 Source.(fun t f -> {f.it with ftype = t} @@ f.at) + func_types func_bodies + in + {types; tables; memories; globals; funcs; imports; exports; elems; datas; start}, + customs + + +let decode_custom m bs custom = + let open Source in + let Custom.{name; content; place} = custom.it in + match Custom.handler name, Custom.handler (Utf8.decode "custom") with + | Some (module Handler), _ -> + let fmt = Handler.decode m bs custom in + let module S = struct module Handler = Handler let it = fmt end in + [(module S : Custom.Section)] + | None, Some (module Handler') -> + let fmt = Handler'.decode m bs custom in + let module S = struct module Handler = Handler' let it = fmt end in + [(module S : Custom.Section)] + | None, None -> + if !Flags.custom_reject then + raise (Custom.Code (custom.at, + "unknown custom section \"" ^ Utf8.encode name ^ "\"")) + else + [] + +let decode_with_custom name bs = + let m_cs = at module_ (stream name bs) in + let open Source in + let m', cs = m_cs.it in + let m = m' @@ m_cs.at in + m, List.flatten (List.map (decode_custom m bs) cs) + +let decode name bs = fst (decode_with_custom name bs) diff --git a/interpreter/binary/decode.mli b/interpreter/binary/decode.mli index 4460023d25..b02b332364 100644 --- a/interpreter/binary/decode.mli +++ b/interpreter/binary/decode.mli @@ -1,5 +1,4 @@ exception Code of Source.region * string val decode : string -> string -> Ast.module_ (* raises Code *) - -val decode_custom : Ast.name -> string -> string -> string list (* raises Code *) +val decode_with_custom : string -> string -> Ast.module_ * Custom.section list (* raises Code *) diff --git a/interpreter/binary/encode.ml b/interpreter/binary/encode.ml index f5665bb1cd..3e22481d35 100644 --- a/interpreter/binary/encode.ml +++ b/interpreter/binary/encode.ml @@ -930,39 +930,67 @@ struct (* Custom section *) - - let custom (n, bs) = + let custom c = + let Custom.{name = n; content; _} = c.it in name n; - put_string s bs + put_string s content - let custom_section n bs = - section 0 custom (n, bs) true + let custom_section place c = + let here = Custom.(compare_place c.it.place place) <= 0 in + if here then section 0 custom c true; + here (* Module *) + let rec iterate f xs = + match xs with + | [] -> [] + | x::xs' -> if f x then iterate f xs' else xs - let module_ m = + let module_ m cs = + let open Custom in word32 0x6d736100l; word32 version; + let cs = iterate (custom_section (Before Type)) cs in type_section m.it.types; + let cs = iterate (custom_section (Before Import)) cs in import_section m.it.imports; + let cs = iterate (custom_section (Before Func)) cs in func_section m.it.funcs; + let cs = iterate (custom_section (Before Table)) cs in table_section m.it.tables; + let cs = iterate (custom_section (Before Memory)) cs in memory_section m.it.memories; + let cs = iterate (custom_section (Before Global)) cs in global_section m.it.globals; + let cs = iterate (custom_section (Before Export)) cs in export_section m.it.exports; + let cs = iterate (custom_section (Before Start)) cs in start_section m.it.start; + let cs = iterate (custom_section (Before Elem)) cs in elem_section m.it.elems; + let cs = iterate (custom_section (Before DataCount)) cs in data_count_section m.it.datas m; + let cs = iterate (custom_section (Before Code)) cs in code_section m.it.funcs; - data_section m.it.datas + let cs = iterate (custom_section (Before Data)) cs in + data_section m.it.datas; + let cs = iterate (custom_section (After Data)) cs in + assert (cs = []) end +let encode_custom m bs (module S : Custom.Section) = + let open Source in + let c = S.Handler.encode m bs S.it in + Custom.{c.it with place = S.Handler.place S.it} @@ c.at + let encode m = let module E = E (struct let stream = stream () end) in - E.module_ m; to_string E.s + E.module_ m []; to_string E.s -let encode_custom name content = +let encode_with_custom (m, secs) = + let bs = encode m in let module E = E (struct let stream = stream () end) in - E.custom_section name content; to_string E.s + let cs = List.map (encode_custom m bs) secs in + E.module_ m cs; to_string E.s diff --git a/interpreter/binary/encode.mli b/interpreter/binary/encode.mli index 00fcd31640..05d1f2a677 100644 --- a/interpreter/binary/encode.mli +++ b/interpreter/binary/encode.mli @@ -2,4 +2,4 @@ exception Code of Source.region * string val version : int32 val encode : Ast.module_ -> string -val encode_custom : Ast.name -> string -> string +val encode_with_custom : Ast.module_ * Custom.section list -> string diff --git a/interpreter/custom/custom.ml b/interpreter/custom/custom.ml new file mode 100644 index 0000000000..17ed651f6b --- /dev/null +++ b/interpreter/custom/custom.ml @@ -0,0 +1,85 @@ +(* Raw custom section *) + +type section_kind = + | Custom + | Type + | Import + | Func + | Table + | Memory + | Global + | Export + | Start + | Elem + | Code + | Data + | DataCount + +type place = + | Before of section_kind + | After of section_kind + +type custom = custom' Source.phrase +and custom' = +{ + name : Ast.name; + content : string; + place : place; +} + + +let first = Type +let last = Data + +let compare_place pl1 pl2 = + match pl1, pl2 with + | Before s1, Before s2 + | After s1, After s2 -> compare s1 s2 + | Before s1, After s2 -> if s1 = s2 then -1 else compare s1 s2 + | After s1, Before s2 -> if s1 = s2 then +1 else compare s1 s2 + + +(* Handlers *) + +exception Code of Source.region * string +exception Syntax of Source.region * string +exception Invalid of Source.region * string + +module type Handler = +sig + type format' + type format = format' Source.phrase + val name : Ast.name + val place : format -> place + val decode : Ast.module_ -> string -> custom -> format (* raise Code *) + val encode : Ast.module_ -> string -> format -> custom + val parse : Ast.module_ -> string -> Annot.annot list -> format list (* raise Syntax *) + val arrange : Ast.module_ -> Sexpr.sexpr -> format -> Sexpr.sexpr + val check : Ast.module_ -> format -> unit (* raise Invalid *) +end + +module type Section = +sig + module Handler : Handler + val it : Handler.format +end + +type section = (module Section) + +let compare_section (module S1 : Section) (module S2 : Section) = + match compare_place (S1.Handler.place S1.it) (S2.Handler.place S2.it) with + | 0 -> compare S1.it.Source.at S2.it.Source.at + | n -> n + + +(* Handler registry *) + +module Registry = Map.Make(struct type t = Ast.name let compare = compare end) + +let registry = ref Registry.empty + +let register (module H : Handler) = + registry := Registry.add H.name (module H : Handler) !registry + +let handler (name : Ast.name) : (module Handler) option = + Registry.find_opt name !registry diff --git a/interpreter/custom/handler_custom.ml b/interpreter/custom/handler_custom.ml new file mode 100644 index 0000000000..3a1d8054f8 --- /dev/null +++ b/interpreter/custom/handler_custom.ml @@ -0,0 +1,168 @@ +(* Handler for @custom annotations *) + +open Custom +open Annot +open Source + +type format' = Custom.custom' +type format = Custom.custom + +let name = Utf8.decode "custom" + +let place fmt = fmt.it.place + + +(* Decoding & encoding *) + +let decode_content m custom = + let Custom.{name; content; place} = custom.it in + match Custom.handler name with + | Some (module Handler) -> + let module S = + struct + module Handler = Handler + let it = Handler.decode m "" custom + end + in Some (module S : Custom.Section) + | None -> + if !Flags.custom_reject then + raise (Custom.Code (custom.at, + "unknown custom section \"" ^ Utf8.encode name ^ "\"")) + else + None + +let decode m _bs custom = + ignore (decode_content m custom); + custom + +let encode _m _bs custom = custom + + +(* Parsing *) + +let parse_error at msg = raise (Custom.Syntax (at, msg)) + +let rec parse m _bs annots = List.map (parse_annot m) annots + +and parse_annot m annot = + let {name = n; items} = annot.it in + assert (n = name); + let cname, items' = parse_name annot.at items in + let place, items'' = parse_place_opt items' in + let content, items''' = parse_content items'' in + parse_end items'''; + let Ast.{types; globals; tables; memories; funcs; start; + elems; datas; imports; exports} = m.it in + let outside x = + if annot.at.left >= x.at.left && annot.at.right <= x.at.right then + parse_error annot.at "misplaced @custom annotation" + in + List.iter outside types; + List.iter outside globals; + List.iter outside tables; + List.iter outside memories; + List.iter outside funcs; + List.iter outside (Option.to_list start); + List.iter outside elems; + List.iter outside datas; + List.iter outside imports; + List.iter outside exports; + let custom = {name = cname; content; place} @@ annot.at in + ignore (decode_content m custom); + custom + +and parse_name at = function + | {it = String s; at} :: items -> + (try Utf8.decode s, items with Utf8.Utf8 -> + parse_error at "@custom annotation: malformed UTF-8 encoding" + ) + | _ -> + parse_error at "@custom annotation: missing section name" + +and parse_place_opt = function + | {it = Parens items'; at} :: items -> + let dir, items'' = parse_direction at items' in + let sec, items''' = parse_section at items'' in + parse_end items'''; + dir sec, items + | items -> + After last, items + +and parse_direction at = function + | {it = Atom "before"; _} :: items -> (fun sec -> Before sec), items + | {it = Atom "after"; _} :: items -> (fun sec -> After sec), items + | _ -> + parse_error at "@custom annotation: malformed placement" + +and parse_section at = function + | {it = Atom "type"; _} :: items -> Type, items + | {it = Atom "import"; _} :: items -> Import, items + | {it = Atom "func"; _} :: items -> Func, items + | {it = Atom "table"; _} :: items -> Table, items + | {it = Atom "memory"; _} :: items -> Memory, items + | {it = Atom "global"; _} :: items -> Global, items + | {it = Atom "export"; _} :: items -> Export, items + | {it = Atom "start"; _} :: items -> Start, items + | {it = Atom "elem"; _} :: items -> Elem, items + | {it = Atom "code"; _} :: items -> Code, items + | {it = Atom "data"; _} :: items -> Data, items + | {it = Atom "datacount"; _} :: items -> DataCount, items + | {it = Atom "first"; _} :: items -> first, items + | {it = Atom "last"; _} :: items -> last, items + | _ -> + parse_error at "@custom annotation: malformed section kind" + +and parse_content = function + | {it = String bs; _} :: items -> + let bs', items' = parse_content items in + bs ^ bs', items' + | items -> "", items + +and parse_end = function + | [] -> () + | item :: _ -> + parse_error item.at "@custom annotation: unexpected token" + + +(* Printing *) + +open Sexpr + +let rec arrange _m mnode custom = + let {name; content; place} = custom.it in + let node = Node ("@custom " ^ Arrange.name name, + arrange_place place :: Arrange.break_bytes content + ) in + match mnode with + | Sexpr.Atom _ -> assert false + | Node (name, secs) -> Node (name, secs @ [node]) + +and arrange_place = function + | Before sec -> Node ("before", [Atom (arrange_sec sec)]) + | After sec -> Node ("after", [Atom (arrange_sec sec)]) + +and arrange_sec = function + | Custom -> assert false + | Type -> "type" + | Import -> "import" + | Func -> "func" + | Table -> "table" + | Memory -> "memory" + | Global -> "global" + | Export -> "export" + | Start -> "start" + | Elem -> "elem" + | Code -> "code" + | Data -> "data" + | DataCount -> "datacount" + + +(* Checking *) + +let check m custom = + let {place; _} = custom.it in + assert (compare_place place (After Custom) > 0); + match decode_content m custom with + | None -> () + | Some (module S : Custom.Section) -> + S.Handler.check m S.it diff --git a/interpreter/custom/handler_custom.mli b/interpreter/custom/handler_custom.mli new file mode 100644 index 0000000000..618ad1e4bd --- /dev/null +++ b/interpreter/custom/handler_custom.mli @@ -0,0 +1 @@ +include Custom.Handler with type format' = Custom.custom' diff --git a/interpreter/custom/handler_name.ml b/interpreter/custom/handler_name.ml new file mode 100644 index 0000000000..7c28708b9b --- /dev/null +++ b/interpreter/custom/handler_name.ml @@ -0,0 +1,358 @@ +(* Handler for "name" section and @name annotations *) + +open Custom +open Annot +open Source + +module IdxMap = Map.Make(Int32) + +type name = Ast.name Source.phrase +type name_map = name IdxMap.t +type indirect_name_map = name_map Source.phrase IdxMap.t + +type format = format' Source.phrase +and format' = +{ + module_ : name option; + funcs : name_map; + locals : indirect_name_map; +} + + +let empty = {module_ = None; funcs = IdxMap.empty; locals = IdxMap.empty } + +let name = Utf8.decode "name" + +let place _fmt = After last + + +(* Decoding *) + +(* TODO: make Decode module reusable instead of duplicating code *) + +type stream = {bytes : string; pos : int ref} + +exception EOS + +let stream bs = {bytes = bs; pos = ref 0} + +let len s = String.length s.bytes +let pos s = !(s.pos) +let eos s = (pos s = len s) + +let check n s = if pos s + n > len s then raise EOS +let skip n s = if n < 0 then raise EOS else check n s; s.pos := !(s.pos) + n + +let read s = Char.code (s.bytes.[!(s.pos)]) +let peek s = if eos s then None else Some (read s) +let get s = check 1 s; let b = read s in skip 1 s; b +let get_string n s = let i = pos s in skip n s; String.sub s.bytes i n + +let position pos = Source.{file = "@name section"; line = -1; column = pos} +let region left right = Source.{left = position left; right = position right} + +let at f s = + let left = pos s in + let x = f s in + let right = pos s in + Source.(x @@ region left right) + +let decode_error pos msg = raise (Custom.Code (region pos pos, msg)) +let require b pos msg = if not b then decode_error pos msg + +let decode_byte s = + get s + +let rec decode_uN n s = + require (n > 0) (pos s) "integer representation too long"; + let b = decode_byte s in + require (n >= 7 || b land 0x7f < 1 lsl n) (pos s - 1) "integer too large"; + let x = Int32.of_int (b land 0x7f) in + if b land 0x80 = 0 then x else + Int32.(logor x (shift_left (decode_uN (n - 7) s) 7)) + +let decode_u32 = decode_uN 32 + +let decode_size s = + Int32.to_int (decode_u32 s) + +let decode_name s = + let n = decode_size s in + let pos = pos s in + try Utf8.decode (get_string n s) with Utf8.Utf8 -> + decode_error pos "malformed UTF-8 encoding" + +let decode_name_assoc s = + let x = decode_u32 s in + let n = decode_name s in + (x, n) + +let decode_name_map s = + let n = decode_size s in + let m = ref IdxMap.empty in + for _ = 1 to n do + let {it = (x, name); at} = at decode_name_assoc s in + if IdxMap.mem x !m then + decode_error at.left.column "custom @name: multiple function or local names"; + m := IdxMap.add x (name @@ at) !m + done; + !m + +let decode_indirect_name_assoc s = + let x = decode_u32 s in + let m = at decode_name_map s in + (x, m) + +let decode_indirect_name_map s = + let n = decode_size s in + let m = ref IdxMap.empty in + for _ = 1 to n do + let {it = (x, m'); at} = at decode_indirect_name_assoc s in + if IdxMap.mem x !m then + decode_error at.left.column "custom @name: multiple function names"; + m := IdxMap.add x m' !m + done; + !m + +let decode_module s = Some (at decode_name s) +let decode_funcs s = decode_name_map s +let decode_locals s = decode_indirect_name_map s + +let decode_subsec id f default s = + match peek s with + | None -> default + | Some id' when id' <> id -> default + | _ -> + let _id = decode_byte s in + let n = decode_size s in + let pos' = pos s in + let ss = f s in + require (pos s = pos' + n) (pos s) "name subsection size mismatch"; + ss + +let decode _m _bs custom = + let s = stream custom.it.content in + try + let module_ = decode_subsec 0x00 decode_module None s in + let funcs = decode_subsec 0x01 decode_funcs IdxMap.empty s in + let locals = decode_subsec 0x02 decode_locals IdxMap.empty s in + require (eos s) (pos s) "invalid name subsection id"; + {module_; funcs; locals} @@ custom.at + with EOS -> decode_error (pos s) "unexpected end of name section" + + +(* Encoding *) + +(* TODO: make Encode module reusable *) + +let encode_byte buf b = + Buffer.add_char buf (Char.chr b) + +let rec encode_u32 buf i = + let b = Int32.(to_int (logand i 0x7fl)) in + if 0l <= i && i < 128l then encode_byte buf b + else ( + encode_byte buf (b lor 0x80); + encode_u32 buf (Int32.shift_right_logical i 7) + ) + +let encode_size buf n = + encode_u32 buf (Int32.of_int n) + +let encode_name buf n = + let s = Utf8.encode n in + encode_size buf (String.length s); + Buffer.add_string buf s + +let encode_name_assoc buf x n = + encode_u32 buf x; + encode_name buf n.it + +let encode_name_map buf m = + encode_size buf (IdxMap.cardinal m); + IdxMap.iter (encode_name_assoc buf) m + +let encode_indirect_name_assoc buf x m = + encode_u32 buf x; + encode_name_map buf m.it + +let encode_indirect_name_map buf m = + encode_size buf (IdxMap.cardinal m); + IdxMap.iter (encode_indirect_name_assoc buf) m + +let encode_subsec_begin buf id = + encode_byte buf id; + let pre = Buffer.contents buf in + Buffer.clear buf; + pre + +let encode_subsec_end buf pre = + let contents = Buffer.contents buf in + Buffer.clear buf; + Buffer.add_string buf pre; + encode_size buf (String.length contents); + Buffer.add_string buf contents + +let encode_module buf name_opt = + match name_opt with + | None -> () + | Some name -> + let subsec = encode_subsec_begin buf 0x00 in + encode_name buf name.it; + encode_subsec_end buf subsec + +let encode_funcs buf name_map = + if not (IdxMap.is_empty name_map) then begin + let subsec = encode_subsec_begin buf 0x01 in + encode_name_map buf name_map; + encode_subsec_end buf subsec + end + +let encode_locals buf name_map_map = + if not (IdxMap.is_empty name_map_map) then begin + let subsec = encode_subsec_begin buf 0x02 in + encode_indirect_name_map buf name_map_map; + encode_subsec_end buf subsec + end + +let encode _m _bs sec = + let {module_; funcs; locals} = sec.it in + let buf = Buffer.create 200 in + encode_module buf module_; + encode_funcs buf funcs; + encode_locals buf locals; + let content = Buffer.contents buf in + {name = Utf8.decode "name"; content; place = After last} @@ sec.at + + +(* Parsing *) + +open Ast + +let parse_error at msg = raise (Custom.Syntax (at, msg)) + +let merge_name_opt n1 n2 = + match n1, n2 with + | None, None -> None + | None, some + | some, None -> some + | Some _, Some n2 -> + parse_error n2.at "@name annotation: multiple module names" + +let merge_name_map m1 m2 = + IdxMap.union (fun x _ n2 -> + parse_error n2.at "@name annotation: multiple function names" + ) m1 m2 + +let merge_indirect_name_map m1 m2 = + IdxMap.union (fun x m1' m2' -> + Some ( + IdxMap.union (fun x _ n2 -> + parse_error n2.at "@name annotation: multiple local names" + ) m1'.it m2'.it @@ {left = m1'.at.left; right = m2'.at.right} + ) + ) m1 m2 + +let merge s1 s2 = + { + module_ = merge_name_opt s1.it.module_ s2.it.module_; + funcs = merge_name_map s1.it.funcs s2.it.funcs; + locals = merge_indirect_name_map s1.it.locals s2.it.locals; + } @@ {left = s1.at.left; right = s2.at.right} + + +let is_contained r1 r2 = r1.left >= r2.left && r1.right <= r2.right +let is_left r1 r2 = r1.right <= r2.left + +let locate_func bs x name at (f : func) = + if is_left at f.it.ftype.at then + {empty with funcs = IdxMap.singleton x name} + else if f.it.body = [] || is_left at (List.hd f.it.body).at then + (* TODO re-parse the function params and locals from bs *) + parse_error at "@name annotation: local names not yet supported" + else + parse_error at "@name annotation: misplaced annotation" + +let locate_module bs name at (m : module_) = + if not (is_contained at m.at) then + parse_error at "misplaced @name annotation"; + let {types; globals; tables; memories; funcs; start; + elems; datas; imports; exports} = m.it in + let ats = + List.map (fun p -> p.at) types @ + List.map (fun p -> p.at) globals @ + List.map (fun p -> p.at) tables @ + List.map (fun p -> p.at) memories @ + List.map (fun p -> p.at) funcs @ + List.map (fun p -> p.at) (Option.to_list start) @ + List.map (fun p -> p.at) elems @ + List.map (fun p -> p.at) datas @ + List.map (fun p -> p.at) imports @ + List.map (fun p -> p.at) exports |> List.sort compare + in + match ats with + | [] -> {empty with module_ = Some name} + | at1::_ when is_left at at1 -> {empty with module_ = Some name} + | _ -> + match Lib.List.index_where (fun f -> is_contained at f.at) funcs with + | Some x -> locate_func bs (Int32.of_int x) name at (List.nth funcs x) + | None -> parse_error at "misplaced @name annotation" + + +let rec parse m bs annots = + let ms = List.map (parse_annot m bs) annots in + match ms with + | [] -> [] + | m::ms' -> [List.fold_left merge (empty @@ m.at) ms] + +and parse_annot m bs annot = + let {name = n; items} = annot.it in + assert (n = name); + let name, items' = parse_name annot.at items in + parse_end items'; + locate_module bs name annot.at m @@ annot.at + +and parse_name at = function + | {it = String s; at} :: items -> + (try Utf8.decode s @@ at, items with Utf8.Utf8 -> + parse_error at "malformed UTF-8 encoding" + ) + | _ -> + parse_error at "@name annotation: string expected" + +and parse_end = function + | [] -> () + | item :: _ -> + parse_error item.at "@name annotation: unexpected token" + + +(* Printing *) + +let arrange m bs fmt = + (* Print as generic custom section *) + Handler_custom.arrange m bs (encode m "" fmt) + + +(* Checking *) + +let check_error at msg = raise (Custom.Invalid (at, msg)) + +let check (m : module_) (fmt : format) = + IdxMap.iter (fun x name -> + if I32.ge_u x (Lib.List32.length m.it.funcs) then + check_error name.at ("custom @name: invalid function index " ^ + I32.to_string_u x) + ) fmt.it.funcs; + IdxMap.iter (fun x map -> + if I32.ge_u x (Lib.List32.length m.it.funcs) then + check_error map.at ("custom @name: invalid function index " ^ + I32.to_string_u x); + let f = Lib.List32.nth m.it.funcs x in + let Types.FuncType (ts, _) = func_type_for m f.it.ftype in + let n = I32.add (Lib.List32.length ts) (Lib.List32.length f.it.locals) in + IdxMap.iter (fun y name -> + if I32.ge_u y n then + check_error name.at ("custom @name: invalid local index " ^ + I32.to_string_u y ^ " for function " ^ I32.to_string_u x) + ) map.it; + ) fmt.it.locals diff --git a/interpreter/custom/handler_name.mli b/interpreter/custom/handler_name.mli new file mode 100644 index 0000000000..caccb08bc1 --- /dev/null +++ b/interpreter/custom/handler_name.mli @@ -0,0 +1 @@ +include Custom.Handler diff --git a/interpreter/main/flags.ml b/interpreter/main/flags.ml index b92378aa2f..14140ff358 100644 --- a/interpreter/main/flags.ml +++ b/interpreter/main/flags.ml @@ -5,4 +5,5 @@ let print_sig = ref false let dry = ref false let width = ref 80 let harness = ref true +let custom_reject = ref false let budget = ref 256 diff --git a/interpreter/main/main.ml b/interpreter/main/main.ml index beeb980494..bf594b827a 100644 --- a/interpreter/main/main.ml +++ b/interpreter/main/main.ml @@ -1,9 +1,15 @@ let name = "wasm" let version = "2.0" -let configure () = +let all_handlers = [ + (module Handler_custom : Custom.Handler); + (module Handler_name : Custom.Handler); +] + +let configure custom_handlers = Import.register (Utf8.decode "spectest") Spectest.lookup; - Import.register (Utf8.decode "env") Env.lookup + Import.register (Utf8.decode "env") Env.lookup; + List.iter Custom.register custom_handlers let banner () = print_endline (name ^ " " ^ version ^ " reference interpreter") @@ -13,6 +19,15 @@ let usage = "Usage: " ^ name ^ " [option] [file ...]" let args = ref [] let add_arg source = args := !args @ [source] +let customs = ref [] +let add_custom name = + let n = Utf8.decode name in + match List.find_opt (fun (module H : Custom.Handler) -> n = H.name) all_handlers with + | Some h -> customs := !customs @ [h] + | None -> + prerr_endline ("option -c: unknown custom section \"" ^ name ^ "\""); + exit 1 + let quote s = "\"" ^ String.escaped s ^ "\"" let argspec = Arg.align @@ -28,6 +43,12 @@ let argspec = Arg.align " configure call depth budget (default is " ^ string_of_int !Flags.budget ^ ")"; "-w", Arg.Int (fun n -> Flags.width := n), " configure output width (default is " ^ string_of_int !Flags.width ^ ")"; + "-c", Arg.String add_custom, + " recognize custom section"; + "-ca", Arg.Unit (fun () -> customs := all_handlers), + " recognize all known custom section"; + "-cr", Arg.Set Flags.custom_reject, + " reject unrecognized custom sections"; "-s", Arg.Set Flags.print_sig, " show module signatures"; "-u", Arg.Set Flags.unchecked, " unchecked, do not perform validation"; "-j", Arg.Clear Flags.harness, " exclude harness for JS conversion"; @@ -39,9 +60,9 @@ let argspec = Arg.align let () = Printexc.record_backtrace true; try - configure (); Arg.parse argspec (fun file -> add_arg ("(input " ^ quote file ^ ")")) usage; + configure !customs; List.iter (fun arg -> if not (Run.run_string arg) then exit 1) !args; if !args = [] then Flags.interactive := true; if !Flags.interactive then begin diff --git a/interpreter/meta/jslib/wast.ml b/interpreter/meta/jslib/wast.ml index 9af04f9189..a2dd7809d7 100644 --- a/interpreter/meta/jslib/wast.ml +++ b/interpreter/meta/jslib/wast.ml @@ -11,7 +11,7 @@ let _ = let def = Parse.string_to_module (Js.to_string s) in let bs = match def.Source.it with - | Script.Textual m -> (Encode.encode m) + | Script.Textual (m, cs) -> Encode.encode_with_custom (m, cs) | Script.Encoded (_, bs) -> bs | Script.Quoted (_, _) -> failwith "Unsupported" in let buf = new%js Typed_array.arrayBuffer (String.length bs) in diff --git a/interpreter/script/js.ml b/interpreter/script/js.ml index 2eb849a6c1..1ae30f55bf 100644 --- a/interpreter/script/js.ml +++ b/interpreter/script/js.ml @@ -523,11 +523,11 @@ let of_result res = let rec of_definition def = match def.it with - | Textual m -> of_bytes (Encode.encode m) + | Textual (m, _) -> of_bytes (Encode.encode m) | Encoded (_, bs) -> of_bytes bs | Quoted (_, s) -> - try of_definition (Parse.string_to_module s) with Parse.Syntax _ -> - of_bytes "" + try of_definition (Parse.string_to_module s) + with Parse.Syntax _ | Custom.Syntax _ -> of_bytes "" let of_wrapper mods x_opt name wrap_action wrap_assertion at = let x = of_var_opt mods x_opt in @@ -592,7 +592,7 @@ let of_command mods cmd = | Module (x_opt, def) -> let rec unquote def = match def.it with - | Textual m -> m + | Textual (m, _) -> m | Encoded (_, bs) -> Decode.decode "binary" bs | Quoted (_, s) -> unquote (Parse.string_to_module s) in bind mods x_opt (unquote def); diff --git a/interpreter/script/run.ml b/interpreter/script/run.ml index 583bd2a22f..90d2aa75c1 100644 --- a/interpreter/script/run.ml +++ b/interpreter/script/run.ml @@ -43,7 +43,7 @@ let dispatch_file_ext on_binary on_sexpr on_script_binary on_script on_js file = let create_binary_file file _ get_module = trace ("Encoding (" ^ file ^ ")..."); - let s = Encode.encode (get_module ()) in + let s = Encode.encode_with_custom (get_module ()) in let oc = open_out_bin file in try trace "Writing..."; @@ -55,7 +55,7 @@ let create_sexpr_file file _ get_module = trace ("Writing (" ^ file ^ ")..."); let oc = open_out file in try - Print.module_ oc !Flags.width (get_module ()); + Print.module_with_custom oc !Flags.width (get_module ()); close_out oc with exn -> close_out oc; raise exn @@ -87,7 +87,7 @@ let output_file = let output_stdout get_module = trace "Printing..."; - Print.module_ stdout !Flags.width (get_module ()) + Print.module_with_custom stdout !Flags.width (get_module ()) (* Input *) @@ -106,7 +106,10 @@ let input_from get_script run = with | Decode.Code (at, msg) -> error at "decoding error" msg | Parse.Syntax (at, msg) -> error at "syntax error" msg - | Valid.Invalid (at, msg) -> error at "invalid module" msg + | Valid.Invalid (at, msg) -> error at "validation error" msg + | Custom.Code (at, msg) -> error at "custom section decoding error" msg + | Custom.Syntax (at, msg) -> error at "custom annotation syntax error" msg + | Custom.Invalid (at, msg) -> error at "custom validation error" msg | Import.Unknown (at, msg) -> error at "link failure" msg | Eval.Link (at, msg) -> error at "link failure" msg | Eval.Trap (at, msg) -> error at "runtime trap" msg @@ -299,7 +302,7 @@ module Map = Map.Make(String) let quote : script ref = ref [] let scripts : script Map.t ref = ref Map.empty -let modules : Ast.module_ Map.t ref = ref Map.empty +let modules : (Ast.module_ * Custom.section list) Map.t ref = ref Map.empty let instances : Instance.module_inst Map.t ref = ref Map.empty let registry : Instance.module_inst Map.t ref = ref Map.empty @@ -332,12 +335,12 @@ let lookup_registry module_name item_name _t = (* Running *) -let rec run_definition def : Ast.module_ = +let rec run_definition def : Ast.module_ * Custom.section list = match def.it with - | Textual m -> m + | Textual (m, cs) -> m, cs | Encoded (name, bs) -> trace "Decoding..."; - Decode.decode name bs + Decode.decode_with_custom name bs | Quoted (_, s) -> trace "Parsing quote..."; let def' = Parse.string_to_module s in @@ -447,24 +450,28 @@ let run_assertion ass = (match ignore (run_definition def) with | exception Decode.Code (_, msg) -> assert_message ass.at "decoding" msg re | exception Parse.Syntax (_, msg) -> assert_message ass.at "parsing" msg re + | exception Custom.Syntax (_, msg) -> + assert_message ass.at "annotation parsing" msg re | _ -> Assert.error ass.at "expected decoding/parsing error" ) | AssertInvalid (def, re) -> trace "Asserting invalid..."; (match - let m = run_definition def in - Valid.check_module m + let m, cs = run_definition def in + Valid.check_module_with_custom (m, cs) with | exception Valid.Invalid (_, msg) -> assert_message ass.at "validation" msg re + | exception Custom.Invalid (_, msg) -> + assert_message ass.at "custom validation" msg re | _ -> Assert.error ass.at "expected validation error" ) | AssertUnlinkable (def, re) -> trace "Asserting unlinkable..."; - let m = run_definition def in - if not !Flags.unchecked then Valid.check_module m; + let m, cs = run_definition def in + if not !Flags.unchecked then Valid.check_module_with_custom (m, cs); (match let imports = Import.link m in ignore (Eval.init m imports) @@ -476,8 +483,8 @@ let run_assertion ass = | AssertUninstantiable (def, re) -> trace "Asserting trap..."; - let m = run_definition def in - if not !Flags.unchecked then Valid.check_module m; + let m, cs = run_definition def in + if not !Flags.unchecked then Valid.check_module_with_custom (m, cs); (match let imports = Import.link m in ignore (Eval.init m imports) @@ -512,16 +519,16 @@ let rec run_command cmd = match cmd.it with | Module (x_opt, def) -> quote := cmd :: !quote; - let m = run_definition def in + let m, cs = run_definition def in if not !Flags.unchecked then begin trace "Checking..."; - Valid.check_module m; + Valid.check_module_with_custom (m, cs); if !Flags.print_sig then begin trace "Signature:"; print_module x_opt m end end; - bind "module" modules x_opt m; + bind "module" modules x_opt (m, cs); bind "script" scripts x_opt [cmd]; if not !Flags.dry then begin trace "Initializing..."; diff --git a/interpreter/script/script.ml b/interpreter/script/script.ml index 4c4f550f2c..e7ad2fa906 100644 --- a/interpreter/script/script.ml +++ b/interpreter/script/script.ml @@ -7,7 +7,7 @@ type literal = Values.value Source.phrase type definition = definition' Source.phrase and definition' = - | Textual of Ast.module_ + | Textual of Ast.module_ * Custom.section list | Encoded of string * string | Quoted of string * string diff --git a/interpreter/text/annot.ml b/interpreter/text/annot.ml new file mode 100644 index 0000000000..779086e6f2 --- /dev/null +++ b/interpreter/text/annot.ml @@ -0,0 +1,53 @@ +open Source + +type annot = annot' Source.phrase +and annot' = {name : Ast.name; items : item list} + +and item = item' Source.phrase +and item' = + | Atom of string + | Var of string + | String of string + | Nat of string + | Int of string + | Float of string + | Parens of item list + | Annot of annot + + +(* Stateful recorder for annotations *) +(* I wish this could be encapsulated in the parser somehow *) + +module NameMap = Map.Make(struct type t = Ast.name let compare = compare end) +type map = annot list NameMap.t + +let current : map ref = ref NameMap.empty +let current_source : Buffer.t = Buffer.create 512 + +let reset () = + current := NameMap.empty; + Buffer.clear current_source + +let get_source () = + Buffer.contents current_source + +let record annot = + let old = Lib.Option.get (NameMap.find_opt annot.it.name !current) [] in + current := NameMap.add annot.it.name (annot::old) !current + +let is_contained r1 r2 = r1.left >= r2.left && r1.right <= r2.right + +let get_all () = + let all = !current in + current := NameMap.empty; + all + +let filter f map = + NameMap.filter (fun _ annots -> annots <> []) + (NameMap.map (List.filter f) map) + +let get r = + let sub = filter (fun annot -> is_contained annot.at r) !current in + let map' = filter (fun annot -> not (is_contained annot.at r)) !current in + current := map'; + sub diff --git a/interpreter/text/arrange.ml b/interpreter/text/arrange.ml index dc56743eb6..458e130a64 100644 --- a/interpreter/text/arrange.ml +++ b/interpreter/text/arrange.ml @@ -620,31 +620,35 @@ let global off i g = let start s = Node ("start " ^ var s.it.sfunc, []) +let custom m mnode (module S : Custom.Section) = + S.Handler.arrange m mnode S.it -(* Modules *) +(* Module *) let var_opt = function | None -> "" | Some x -> " " ^ x.it -let module_with_var_opt x_opt m = +let module_with_var_opt x_opt (m, cs) = let fx = ref 0 in let tx = ref 0 in let mx = ref 0 in let gx = ref 0 in let imports = list (import fx tx mx gx) m.it.imports in - Node ("module" ^ var_opt x_opt, + let ret = Node ("module" ^ var_opt x_opt, listi typedef m.it.types @ imports @ listi (table !tx) m.it.tables @ listi (memory !mx) m.it.memories @ listi (global !gx) m.it.globals @ - listi (func_with_index !fx) m.it.funcs @ list export m.it.exports @ opt start m.it.start @ listi elem m.it.elems @ + listi (func_with_index !fx) m.it.funcs @ listi data m.it.datas - ) + ) in + List.fold_left (custom m) ret cs + let binary_module_with_var_opt x_opt bs = Node ("module" ^ var_opt x_opt ^ " binary", break_bytes bs) @@ -652,7 +656,8 @@ let binary_module_with_var_opt x_opt bs = let quoted_module_with_var_opt x_opt s = Node ("module" ^ var_opt x_opt ^ " quote", break_string s) -let module_ = module_with_var_opt None +let module_with_custom = module_with_var_opt None +let module_ m = module_with_custom (m, []) (* Scripts *) @@ -677,20 +682,21 @@ let definition mode x_opt def = | `Textual -> let rec unquote def = match def.it with - | Textual m -> m - | Encoded (_, bs) -> Decode.decode "" bs + | Textual (m, cs) -> m, cs + | Encoded (_, bs) -> Decode.decode_with_custom "" bs | Quoted (_, s) -> unquote (Parse.string_to_module s) in module_with_var_opt x_opt (unquote def) | `Binary -> let rec unquote def = match def.it with - | Textual m -> Encode.encode m - | Encoded (_, bs) -> Encode.encode (Decode.decode "" bs) + | Textual (m, cs) -> Encode.encode_with_custom (m, cs) + | Encoded (_, bs) -> + Encode.encode_with_custom (Decode.decode_with_custom "" bs) | Quoted (_, s) -> unquote (Parse.string_to_module s) in binary_module_with_var_opt x_opt (unquote def) | `Original -> match def.it with - | Textual m -> module_with_var_opt x_opt m + | Textual (m, cs) -> module_with_var_opt x_opt (m, cs) | Encoded (_, bs) -> binary_module_with_var_opt x_opt bs | Quoted (_, s) -> quoted_module_with_var_opt x_opt s with Parse.Syntax _ -> diff --git a/interpreter/text/arrange.mli b/interpreter/text/arrange.mli index 051686a443..a0fddd5d43 100644 --- a/interpreter/text/arrange.mli +++ b/interpreter/text/arrange.mli @@ -1,6 +1,14 @@ open Sexpr +val bytes : string -> string +val string : string -> string +val name : Ast.name -> string + +val break_bytes : string -> sexpr list +val break_string : string -> sexpr list + val instr : Ast.instr -> sexpr val func : Ast.func -> sexpr val module_ : Ast.module_ -> sexpr +val module_with_custom : Ast.module_ * Custom.section list -> sexpr val script : [`Textual | `Binary] -> Script.script -> sexpr list diff --git a/interpreter/text/lexer.mll b/interpreter/text/lexer.mll index e9897c8796..012387a6a7 100644 --- a/interpreter/text/lexer.mll +++ b/interpreter/text/lexer.mll @@ -697,7 +697,10 @@ rule token = parse | id as s { VAR s } - | "(@"name { annot (Lexing.lexeme_start_p lexbuf) lexbuf; token lexbuf } + | "(@"(name as n) + { let r = region lexbuf in + let items = annot (Lexing.lexeme_start_p lexbuf) lexbuf in + Annot.record (Annot.{name = Utf8.decode n; items} @@ r); token lexbuf } | "(@" { error lexbuf "malformed annotation id" } | ";;"utf8_no_nl*eof { EOF } @@ -714,16 +717,37 @@ rule token = parse | _ { error lexbuf "malformed UTF-8 encoding" } and annot start = parse - | ")" { () } - | "(" { annot (Lexing.lexeme_start_p lexbuf) lexbuf; annot start lexbuf } - - | reserved { annot start lexbuf } - | nat { annot start lexbuf } - | int { annot start lexbuf } - | float { annot start lexbuf } - | id { annot start lexbuf } - | string { annot start lexbuf } - | '"'character*('\n'|eof) { error lexbuf "unclosed string literal" } + | ")" { [] } + | "(" + { let r = region lexbuf in + let items = annot (Lexing.lexeme_start_p lexbuf) lexbuf in + (Annot.Parens items @@ r) :: annot start lexbuf } + | "(@"(name as n) + { let r = region lexbuf in + let items = annot (Lexing.lexeme_start_p lexbuf) lexbuf in + let ann = Annot.{name = Utf8.decode n; items} @@ r in + (Annot.Annot ann @@ r) :: annot start lexbuf } + + | nat as s + { let r = region lexbuf in + (Annot.Nat s @@ r) :: annot start lexbuf } + | int as s + { let r = region lexbuf in + (Annot.Int s @@ r) :: annot start lexbuf } + | float as s + { let r = region lexbuf in + (Annot.Float s @@ r) :: annot start lexbuf } + | id as s + { let r = region lexbuf in + (Annot.Var s @@ r) :: annot start lexbuf } + | string as s + { let r = region lexbuf in + (Annot.String (string s) @@ r) :: annot start lexbuf } + | reserved as s + { let r = region lexbuf in + (Annot.Atom s @@ r) :: annot start lexbuf } + | '"'character*('\n'|eof) + { error lexbuf "unclosed string literal" } | '"'character*['\x00'-'\x09''\x0b'-'\x1f''\x7f'] { error lexbuf "illegal control character in string literal" } | '"'character*'\\'_ diff --git a/interpreter/text/parse.ml b/interpreter/text/parse.ml index 71c4cc4a9c..666df7992f 100644 --- a/interpreter/text/parse.ml +++ b/interpreter/text/parse.ml @@ -5,10 +5,35 @@ type 'a start = exception Syntax = Script.Syntax + +let wrap_lexbuf lexbuf = + let open Lexing in + let inner_refill = lexbuf.refill_buff in + let refill_buff lexbuf = + let oldlen = lexbuf.lex_buffer_len - lexbuf.lex_start_pos in + inner_refill lexbuf; + let newlen = lexbuf.lex_buffer_len - lexbuf.lex_start_pos in + let start = lexbuf.lex_start_pos + oldlen in + let n = newlen - oldlen in + Buffer.add_subbytes Annot.current_source lexbuf.lex_buffer start n + in + let n = lexbuf.lex_buffer_len - lexbuf.lex_start_pos in + Buffer.add_subbytes Annot.current_source lexbuf.lex_buffer lexbuf.lex_start_pos n; + {lexbuf with refill_buff} + let parse' name lexbuf start = + Annot.reset (); + let lexbuf = wrap_lexbuf lexbuf in lexbuf.Lexing.lex_curr_p <- {lexbuf.Lexing.lex_curr_p with Lexing.pos_fname = name}; - try start Lexer.token lexbuf + try + let result = start Lexer.token lexbuf in + let annots = Annot.get_all () in + if not (Annot.NameMap.is_empty annots) then + let annot = List.hd (snd (Annot.NameMap.choose annots)) in + raise (Custom.Syntax (annot.Source.at, "misplaced annotation")) + else + result with Syntax (region, s) -> let region' = if region <> Source.no_region then region else {Source.left = Lexer.convert_pos lexbuf.Lexing.lex_start_p; diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly index 7489acf72b..b940ad0d9e 100644 --- a/interpreter/text/parser.mly +++ b/interpreter/text/parser.mly @@ -202,6 +202,30 @@ let inline_type_explicit (c : context) x ft at = error at "inline function type does not match explicit type"; x + +(* Custom annotations *) + +let parse_annots (m : module_) : Custom.section list = + let bs = Annot.get_source () in + let annots = Annot.get m.at in + let secs = + Annot.NameMap.fold (fun name anns secs -> + match Custom.handler name with + | Some (module Handler) -> + let secs' = Handler.parse m bs anns in + List.map (fun fmt -> + let module S = struct module Handler = Handler let it = fmt end in + (module S : Custom.Section) + ) secs' @ secs + | None -> + if !Flags.custom_reject then + raise (Custom.Syntax ((List.hd anns).at, + "unknown annotation @" ^ Utf8.encode name)) + else [] + ) annots [] + in + List.stable_sort Custom.compare_section secs + %} %token LPAR RPAR @@ -915,13 +939,13 @@ inline_export : /* Modules */ type_ : - | def_type { $1 @@ at () } + | def_type { $1 } type_def : | LPAR TYPE type_ RPAR - { fun c -> anon_type c $3 } + { let at = at () in fun c -> anon_type c ($3 @@ at) } | LPAR TYPE bind_var type_ RPAR /* Sugar */ - { fun c -> bind_type c $3 $4 } + { let at = at () in fun c -> bind_type c $3 ($4 @@ at) } start : | LPAR START var RPAR @@ -992,13 +1016,26 @@ module_var_opt : module_ : | LPAR MODULE module_var_opt module_fields RPAR - { $3, Textual ($4 (empty_context ()) () @@ at ()) @@ at () } + { let m = $4 (empty_context ()) () @@ at () in + $3, Textual (m, parse_annots m) @@ at () } inline_module : /* Sugar */ - | module_fields { Textual ($1 (empty_context ()) () @@ at ()) @@ at () } + | module_fields + { let at = at () in + (* Hack for empty modules *) + let at = if at.left <> at.right then at else + {at with right = {at.right with line = Stdlib.Int.max_int}} in + let m = $1 (empty_context ()) () @@ at in + Textual (m, parse_annots m) @@ at } inline_module1 : /* Sugar */ - | module_fields1 { Textual ($1 (empty_context ()) () @@ at ()) @@ at () } + | module_fields1 + { let at = at () in + (* Hack for empty modules *) + let at = if at.left <> at.right then at else + {at with right = {at.right with line = Stdlib.Int.max_int}} in + let m = $1 (empty_context ()) () @@ at in + Textual (m, parse_annots m) @@ at } /* Scripts */ diff --git a/interpreter/text/print.ml b/interpreter/text/print.ml index 9496182147..44bf4e5756 100644 --- a/interpreter/text/print.ml +++ b/interpreter/text/print.ml @@ -1,5 +1,6 @@ let instr oc width e = Sexpr.output oc width (Arrange.instr e) let func oc width f = Sexpr.output oc width (Arrange.func f) let module_ oc width m = Sexpr.output oc width (Arrange.module_ m) +let module_with_custom oc width m_cs = Sexpr.output oc width (Arrange.module_with_custom m_cs) let script oc width mode s = List.iter (Sexpr.output oc width) (Arrange.script mode s) diff --git a/interpreter/text/print.mli b/interpreter/text/print.mli index 861ae40d97..c97dc9f618 100644 --- a/interpreter/text/print.mli +++ b/interpreter/text/print.mli @@ -1,4 +1,5 @@ val instr : out_channel -> int -> Ast.instr -> unit val func : out_channel -> int -> Ast.func -> unit val module_ : out_channel -> int -> Ast.module_ -> unit +val module_with_custom : out_channel -> int -> Ast.module_ * Custom.section list -> unit val script : out_channel -> int -> [`Textual | `Binary] -> Script.script -> unit diff --git a/interpreter/valid/valid.ml b/interpreter/valid/valid.ml index cfe7f310f2..bda7a74986 100644 --- a/interpreter/valid/valid.ml +++ b/interpreter/valid/valid.ml @@ -735,3 +735,7 @@ let check_module (m : module_) = ignore (List.fold_left (check_export c) NameSet.empty exports); require (List.length c.memories <= 1) m.at "multiple memories are not allowed (yet)" + +let check_module_with_custom ((m : module_), (cs : Custom.section list)) = + check_module m; + List.iter (fun (module S : Custom.Section) -> S.Handler.check m S.it) cs diff --git a/interpreter/valid/valid.mli b/interpreter/valid/valid.mli index 5827ae56e9..ef89313312 100644 --- a/interpreter/valid/valid.mli +++ b/interpreter/valid/valid.mli @@ -1,3 +1,4 @@ exception Invalid of Source.region * string val check_module : Ast.module_ -> unit (* raises Invalid *) +val check_module_with_custom : Ast.module_ * Custom.section list -> unit (* raises Invalid, Custom.Check *) diff --git a/test/core/annotations.wast b/test/core/annotations.wast index 865581c68a..f90dc4fb34 100644 --- a/test/core/annotations.wast +++ b/test/core/annotations.wast @@ -1,18 +1,20 @@ -(@a) +(module + (@a) -(@aas-3!@$d-@#4) -(@@) (@$) (@+) (@0) (@.) (@!$@#$23414@#$) -(@a x y z) -(@a x-y $yz "aa" -2 0.3 0x3) -(@a x-y$yz"aa"-2) -(@a block func module i32.add) -(@a 0x 8q 0xfa #4g0-.@f#^&@#$*0sf -- @#) -(@a , ; ] [ }} }x{ ({) ,{{};}] ;) -(@a (bla) () (5-g) ("aa" a) ($x) (bla bla) (x (y)) ")" "(" x")"y) -(@a @ @x (@x) (@x y) (@) (@ x) (@(@(@(@))))) -(@a (;bla;) (; ) ;) - ;; bla) - ;; bla (@x + (@aas-3!@$d-@#4) + (@@) (@$) (@+) (@0) (@.) (@!$@#$23414@#$) + (@a x y z) + (@a x-y $yz "aa" -2 0.3 0x3) + (@a x-y$yz"aa"-2) + (@a block func module i32.add) + (@a 0x 8q 0xfa #4g0-.@f#^&@#$*0sf -- @#) + (@a , ; ] [ }} }x{ ({) ,{{};}] ;) + (@a (bla) () (5-g) ("aa" a) ($x) (bla bla) (x (y)) ")" "(" x")"y) + (@a @ @x (@x) (@x y) (@) (@ x) (@(@(@(@))))) + (@a (;bla;) (; ) ;) + ;; bla) + ;; bla (@x + ) ) (assert_malformed (module quote "(@a \00)") "illegal character") @@ -115,7 +117,7 @@ ((@a) export (@a) "f" (@a) ((@a) func (@a) $f (@a)) (@a) ) (@a) -) (@a) +) ((@a) module (@a) $m1 (@a) (@a) ((@a) global (@a) $g (@a) @@ -140,7 +142,7 @@ ((@a) param (@a) i32 (@a) f32 (@a)) (@a) ((@a) result (@a)) (@a) ) (@a) -) (@a) +) ((@a) module (@a) $m2 (@a) (@a) ((@a) type (@a) $T (@a) @@ -192,4 +194,4 @@ (func $s) ((@a) start (@a) $s (@a)) (@a) -) (@a) +) diff --git a/test/core/run.py b/test/core/run.py index fa80ea969b..350810a91a 100755 --- a/test/core/run.py +++ b/test/core/run.py @@ -13,27 +13,29 @@ ownDir = os.path.dirname(os.path.abspath(sys.argv[0])) inputDir = ownDir outputDir = os.path.join(inputDir, "_output") +opts = "" + +mainTestFiles = glob.glob(os.path.join(inputDir, "*.wast")) +otherTestFiles = glob.glob(os.path.join(inputDir, "[a-z]*/*.wast")) 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("--opts", metavar="", default=opts) parser.add_argument("file", nargs='*') arguments = parser.parse_args() sys.argv = sys.argv[:1] -main_test_files = glob.glob(os.path.join(inputDir, "*.wast")) -# SIMD test files are in a subdirectory. -simd_test_files = glob.glob(os.path.join(inputDir, "simd", "*.wast")) - -wasmCommand = arguments.wasm +wasmExec = arguments.wasm jsCommand = arguments.js generateJsOnly = arguments.generate_js_only outputDir = arguments.out -inputFiles = arguments.file if arguments.file else main_test_files + simd_test_files +inputFiles = arguments.file if arguments.file else mainTestFiles + otherTestFiles +wasmCommand = wasmExec + " " + arguments.opts -if not os.path.exists(wasmCommand): +if not os.path.exists(wasmExec): sys.stderr.write("""\ Error: The executable '%s' does not exist. Provide the correct path with the '--wasm' flag. diff --git a/test/custom/custom/custom_annot.wast b/test/custom/custom/custom_annot.wast new file mode 100644 index 0000000000..6d6735e85f --- /dev/null +++ b/test/custom/custom/custom_annot.wast @@ -0,0 +1,99 @@ +(module + (type $t (func)) + (@custom "my-section1" "contents-bytes1") + (@custom "my-section2" "more-contents-bytes0") + (@custom "my-section1" "contents-bytes2") + (@custom "my-section2" (before global) "more-contents-bytes1") + (@custom "my-section2" (after func) "more-contents-bytes2") + (@custom "my-section2" (after func) "more-contents-bytes3") + (@custom "my-section2" (before global) "more-contents-bytes4") + (func) + (@custom "my-section2" "more-contents-bytes5") + + (global $g i32 (i32.const 0)) + (@custom "my-section3") + (@custom "my-section4" "" "1" "" "2" "3" "") + (@custom "") +) + +(module quote "(@custom \"bla\")") +(module quote "(module (@custom \"bla\"))") + + +;; Malformed name + +(assert_malformed + (module quote "(@custom)") + "@custom annotation: missing section name" +) + +(assert_malformed + (module quote "(@custom 4)") + "@custom annotation: missing section name" +) + +(assert_malformed + (module quote "(@custom bla)") + "@custom annotation: missing section name" +) + +(assert_malformed + (module quote "(@custom \"\\df\")") + "@custom annotation: malformed UTF-8 encoding" +) + + +;; Malformed placement + +(assert_malformed + (module quote "(@custom \"bla\" here)") + "@custom annotation: unexpected token" +) + +(assert_malformed + (module quote "(@custom \"bla\" after)") + "@custom annotation: unexpected token" +) + +(assert_malformed + (module quote "(@custom \"bla\" (after))") + "@custom annotation: malformed section kind" +) + +(assert_malformed + (module quote "(@custom \"bla\" (type))") + "@custom annotation: malformed placement" +) + +(assert_malformed + (module quote "(@custom \"bla\" (aft type))") + "@custom annotation: malformed placement" +) + +(assert_malformed + (module quote "(@custom \"bla\" (before types))") + "@custom annotation: malformed section kind" +) + + +;; Misplaced + +(assert_malformed + (module quote "(type (@custom \"bla\") $t (func))") + "misplaced @custom annotation" +) + +(assert_malformed + (module quote "(func (@custom \"bla\"))") + "misplaced @custom annotation" +) + +(assert_malformed + (module quote "(func (block (@custom \"bla\")))") + "misplaced @custom annotation" +) + +(assert_malformed + (module quote "(func (nop (@custom \"bla\")))") + "misplaced @custom annotation" +) diff --git a/test/custom/name/name_annot.wast b/test/custom/name/name_annot.wast new file mode 100644 index 0000000000..5421151fd2 --- /dev/null +++ b/test/custom/name/name_annot.wast @@ -0,0 +1,20 @@ +;; Module names + +(module (@name "Modül")) + +(module $moduel (@name "Modül")) + +(assert_malformed + (module quote "(module (@name \"M1\") (@name \"M2\"))") + "@name annotation: multiple module" +) + +(assert_malformed + (module quote "(module (func) (@name \"M\"))") + "misplaced @name annotation" +) + +(assert_malformed + (module quote "(module (start $f (@name \"M\")) (func $f))") + "misplaced @name annotation" +) From b2fa7867d07365354c5ccfc79ed80c1c7ed73435 Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Tue, 25 Apr 2023 19:11:06 +0200 Subject: [PATCH 063/130] [interpreter] Handle custom sections and annotations (#17) * [interpreter] Handle custom sections and annotations Co-authored-by: Yuri Iozzelli * Fix merge conflict * Fix lexer priorities * Fix wast.ml * Oops * Update wast.ml --------- Co-authored-by: Andreas Rossberg From e09ddc412e0489a20c4e66b8376059441fd64dd3 Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Fri, 30 Jun 2023 13:42:20 +0200 Subject: [PATCH 064/130] [interpreter] add handler for branch hints custom section (#20) --- interpreter/custom/handler_branch_hint.ml | 456 ++++++++++++++++++ interpreter/main/main.ml | 1 + .../branch_hint.wast | 99 ++++ 3 files changed, 556 insertions(+) create mode 100644 interpreter/custom/handler_branch_hint.ml create mode 100644 test/custom/metadata.code.branch_hint/branch_hint.wast diff --git a/interpreter/custom/handler_branch_hint.ml b/interpreter/custom/handler_branch_hint.ml new file mode 100644 index 0000000000..1f46d5de11 --- /dev/null +++ b/interpreter/custom/handler_branch_hint.ml @@ -0,0 +1,456 @@ +(* Handler for "metadata.code.branch_hint" section and @metadata.code.branch_hint annotations *) + +open Custom +open Annot +open Source +open Ast +module IdxMap = Map.Make (Int32) + +type kind = Likely | Unlikely + +type hint = hint' Source.phrase +and hint' = kind * int + +type hints = hint list +type func_hints = hints IdxMap.t + +type format = format' Source.phrase +and format' = { func_hints : func_hints } + +let empty = { func_hints = IdxMap.empty } +let name = Utf8.decode "metadata.code.branch_hint" +let place _fmt = Before Code +let is_contained r1 r2 = r1.left >= r2.left && r1.right <= r2.right + +let is_left r1 r2 = + r1.right.line < r2.left.line + || (r1.right.line == r2.left.line && r1.right.column <= r2.left.column) + +let starts_before r1 r2 = + r1.left.line < r2.left.line + || (r1.left.line == r2.left.line && r1.left.column < r2.left.column) + +let get_func m fidx = + let nimp = List.length m.it.imports in + let fn = Int32.to_int fidx - nimp in + List.nth m.it.funcs fn + +let flatten_instr_locs is = + let rec flatten is = + match is with + | [] -> [] + | i :: rest -> + let group = + match i.it with + | Block (_, inner) -> [ i ] @ flatten inner + | Loop (_, inner) -> [ i ] @ flatten inner + | If (_, inner1, inner2) -> [ i ] @ flatten inner1 @ flatten inner2 + | _ -> [ i ] + in + group @ flatten rest + in + let flat = flatten is in + let indexed = List.mapi (fun idx i -> (idx, i)) flat in + let sorter (_, i1) (_, i2) = if starts_before i1.at i2.at then -1 else 1 in + let sorted = List.sort sorter indexed in + sorted + +let get_inst_idx locs at = + let finder (i, l) = is_left at l.at in + let o = List.find_opt finder locs in + match o with Some (i, _) -> Some i | None -> None + +let get_nth_inst locs idx = + match List.find_opt (fun (i_idx, i) -> i_idx == idx) locs with + | Some (_, i) -> Some i + | None -> None + +(* Decoding *) + +(* TODO: make Decode module reusable instead of duplicating code *) + +type stream = { bytes : string; pos : int ref } + +exception EOS + +let stream bs = { bytes = bs; pos = ref 0 } +let len s = String.length s.bytes +let pos s = !(s.pos) +let check n s = if pos s + n > len s then raise EOS + +let skip n s = + if n < 0 then raise EOS else check n s; + s.pos := !(s.pos) + n + +let read s = Char.code s.bytes.[!(s.pos)] + +let get s = + check 1 s; + let b = read s in + skip 1 s; + b + +let position file pos = Source.{ file; line = -1; column = pos } + +let region file left right = + Source.{ left = position file left; right = position file right } + +let decode_error pos msg = + raise (Custom.Code (region "@metadata.code.branch_hint section" pos pos, msg)) + +let require b pos msg = if not b then decode_error pos msg +let decode_byte s = get s + +let rec decode_uN n s = + require (n > 0) (pos s) "integer representation too long"; + let b = decode_byte s in + require (n >= 7 || b land 0x7f < 1 lsl n) (pos s - 1) "integer too large"; + let x = Int32.of_int (b land 0x7f) in + if b land 0x80 = 0 then x + else Int32.(logor x (shift_left (decode_uN (n - 7) s) 7)) + +let decode_u32 = decode_uN 32 + +let decode_vec f s = + let n = decode_u32 s in + let n = Int32.to_int n in + let rec it i s = if i = 0 then [] else [ f s ] @ it (i - 1) s in + it n s + +let decode_hint locs foff s = + let off = decode_u32 s in + let one = decode_u32 s in + require (one = 1l) (pos s) + "@metadata.code.branch_hint section: missing reserved byte"; + let k = decode_byte s in + let hint = + match k with + | 0x00 -> Unlikely + | 0x01 -> Likely + | _ -> + decode_error (pos s) + "@metadata.code.branch_hint section: invalid hint value" + in + let abs_off = Int32.to_int (Int32.add off foff) in + let at = region "" abs_off abs_off in + let idx = + match get_inst_idx locs at with + | Some i -> i + | None -> + decode_error (pos s) + "@metadata.code.branch_hint section: invalid offset" + in + (hint, idx) @@ at + +let decode_func_hints locs foff = decode_vec (decode_hint locs foff) + +let decode_func m s = + let fidx = decode_u32 s in + let f = get_func m fidx in + let foff = Int32.of_int f.at.left.column in + let locs = flatten_instr_locs f.it.body in + let hs = decode_func_hints locs foff s in + (fidx, List.rev hs) + +let decode_funcs m s = + let fs = decode_vec (decode_func m) s in + IdxMap.add_seq (List.to_seq fs) IdxMap.empty + +let decode m _ custom = + let s = stream custom.it.content in + try { func_hints = decode_funcs m s } @@ custom.at + with EOS -> decode_error (pos s) "unexpected end of name section" + +(* Encoding *) + +(* TODO: make Encode module reusable *) + +let encode_byte buf b = Buffer.add_char buf (Char.chr b) + +let rec encode_u32 buf i = + let b = Int32.(to_int (logand i 0x7fl)) in + if 0l <= i && i < 128l then encode_byte buf b + else ( + encode_byte buf (b lor 0x80); + encode_u32 buf (Int32.shift_right_logical i 7)) + +let encode_size buf n = encode_u32 buf (Int32.of_int n) + +let encode_vec buf f v = + encode_size buf (List.length v); + let rec it v = + match v with + | [] -> () + | e :: es -> + f buf e; + it es + in + it v + +let encode_hint locs foff buf h = + let kind, idx = h.it in + let i = + match get_nth_inst locs idx with Some i -> i | None -> assert false + in + let off = i.at.left.column - foff in + encode_size buf off; + encode_u32 buf 1l; + let b = match kind with Unlikely -> 0l | Likely -> 1l in + encode_u32 buf b + +let encode_func_hints buf locs foff = encode_vec buf (encode_hint locs foff) + +let encode_func m buf t = + let fidx, hs = t in + encode_u32 buf fidx; + let f = get_func m fidx in + let foff = f.at.left.column in + let locs = flatten_instr_locs f.it.body in + encode_func_hints buf locs foff hs + +let encode_funcs buf m fhs = + encode_vec buf (encode_func m) (List.of_seq (IdxMap.to_seq fhs)) + +let encode m bs sec = + let { func_hints } = sec.it in + let m2 = Decode.decode "" bs in + let buf = Buffer.create 200 in + encode_funcs buf m2 func_hints; + let content = Buffer.contents buf in + { + name = Utf8.decode "metadata.code.branch_hint"; + content; + place = Before Code; + } + @@ sec.at + +(* Parsing *) + +open Ast + +let parse_error at msg = raise (Custom.Syntax (at, msg)) + +let merge_func_hints = + IdxMap.merge (fun key x y -> + match (x, y) with + | Some a, None -> Some a + | None, Some b -> Some b + | Some a, Some [ ({ at = _; it = _, idx } as b) ] -> + let _, last_idx = (List.hd (List.rev a)).it in + if last_idx >= idx then + parse_error b.at + "@metadata.code.branch_hint annotation: duplicate annotation" + else Some (a @ [ b ]) + | Some _, Some _ -> assert false + | None, None -> None) + +let merge s1 s2 = + { func_hints = merge_func_hints s1.it.func_hints s2.it.func_hints } + @@ { left = s1.at.left; right = s2.at.right } + +let find_func_idx m annot = + let idx = + Lib.List.index_where (fun f -> is_contained annot.at f.at) m.it.funcs + in + match idx with + | Some i -> Int32.of_int (i + List.length m.it.imports) + | None -> + parse_error annot.at + "@metadata.code.branch_hint annotation: not in a function" + +let rec parse m _bs annots = + let annots' = List.rev annots in + let ms = List.map (parse_annot m) annots' in + match ms with + | [] -> [] + | m :: ms' -> [ List.fold_left merge (empty @@ m.at) ms ] + +and parse_annot m annot = + let { name = n; items } = annot.it in + assert (n = name); + let payload a = + match a.it with + | String s -> s + | _ -> + parse_error a.at + "@metadata.code.branch_hint annotation: unexpected token" + in + let fold_payload bs a = bs ^ payload a in + let p = List.fold_left fold_payload "" items in + let at_last = (List.hd (List.rev items)).at in + let fidx = find_func_idx m annot in + let f = get_func m fidx in + let locs = flatten_instr_locs f.it.body in + let hint = + match p with + | "\x00" -> Unlikely + | "\x01" -> Likely + | _ -> + parse_error annot.at + "@metadata.code.branch_hint annotation: invalid hint value" + in + let at = Source.{ left = annot.at.left; right = at_last.right } in + let hidx = + match get_inst_idx locs at with + | Some i -> i + | None -> + parse_error annot.at + "@metadata.code.branch_hint annotation: invalid placement" + in + let e = + { func_hints = IdxMap.add fidx [ (hint, hidx) @@ at ] IdxMap.empty } + in + e @@ at + +(* Arranging *) + +let hint_to_string = function Likely -> "\"\\01\"" | Unlikely -> "\"\\00\"" + +let collect_one f hat = + let h, hidx = hat.it in + ( Int32.to_int f, + hidx, + Sexpr.Node ("@metadata.code.branch_hint ", [ Sexpr.Atom (hint_to_string h) ]) + ) + +let collect_func (f, hs) = List.map (collect_one f) hs +let collect_funcs fhs = List.concat (List.map collect_func fhs) + +let string_starts_with s1 s2 = + let s2l = String.length s2 in + let s1l = String.length s1 in + let len = Stdlib.min s2l s1l in + let s1sub = String.sub s1 0 len in + String.equal s1sub s2 + +let rec get_instrs n1 n2 = + match n2 with + | [] -> (n1, []) + | Sexpr.Atom s :: rest -> (n1 @ [ Sexpr.Atom s ], rest) + | Sexpr.Node (h, els) :: rest -> + if + string_starts_with h "type " + || String.equal h "local" + || string_starts_with h "result" + then get_instrs (n1 @ [ Sexpr.Node (h, els) ]) rest + else (n1, n2) + +let get_annot annots fidx idx h = + match !annots with + | [] -> [] + | (a_fidx, a_hidx, a_node) :: rest -> + if a_fidx = fidx && a_hidx = idx then ( + annots := rest; + [ a_node ]) + else [] + +let rec apply_instrs annots fidx curi is = + match is with + | [] -> [] + | i :: rest -> + let idx = !curi in + curi := idx + 1; + let newn = + match i with + | Sexpr.Node (h, ns) -> + let annot = get_annot annots fidx idx h in + if string_starts_with h "block" || string_starts_with h "loop" then + let pre, inner = get_instrs [] ns in + annot + @ [ Sexpr.Node (h, pre @ apply_instrs annots fidx curi inner) ] + else if string_starts_with h "if" then + match ns with + | [ Sexpr.Node (hif, nif); Sexpr.Node (helse, nelse) ] -> + let newif = apply_instrs annots fidx curi nif in + let newelse = apply_instrs annots fidx curi nelse in + annot + @ [ + Sexpr.Node + ( h, + [ + Sexpr.Node (hif, newif); Sexpr.Node (helse, newelse); + ] ); + ] + | [ + Sexpr.Node ("result", res); + Sexpr.Node (hif, nif); + Sexpr.Node (helse, nelse); + ] -> + let newif = apply_instrs annots fidx curi nif in + let newelse = apply_instrs annots fidx curi nelse in + annot + @ [ + Sexpr.Node + ( h, + [ + Sexpr.Node ("result", res); + Sexpr.Node (hif, newif); + Sexpr.Node (helse, newelse); + ] ); + ] + | _ -> assert false + else annot @ [ Sexpr.Node (h, ns) ] + | Sexpr.Atom s -> [ Sexpr.Atom s ] + in + newn @ apply_instrs annots fidx curi rest + +let apply_func nodes annots fidx = + let curi = ref 0 in + let pre, instrs = get_instrs [] nodes in + let new_instrs = apply_instrs annots fidx curi instrs in + pre @ new_instrs + +let apply_secs annots curf node = + match node with + | Sexpr.Atom a -> Sexpr.Atom a + | Sexpr.Node (head, rest) -> + if string_starts_with head "func" then ( + let ret = apply_func rest annots !curf in + curf := !curf + 1; + Sexpr.Node (head, ret)) + else Sexpr.Node (head, rest) + +let apply mnode annots curf = + match mnode with + | Sexpr.Atom a -> Sexpr.Atom a + | Sexpr.Node (h, secs) -> + Sexpr.Node (h, List.map (apply_secs annots curf) secs) + +let arrange m mnode fmt = + let annots = + ref (collect_funcs (List.of_seq (IdxMap.to_seq fmt.it.func_hints))) + in + let curf = ref 0 in + let ret = apply mnode annots curf in + ret + +(* Checking *) + +let check_error at msg = raise (Custom.Invalid (at, msg)) + +let check_one locs prev_hidx h = + let kind, idx = h.it in + match get_nth_inst locs idx with + | None -> assert false + | Some i -> ( + match i.it with + | If _ | BrIf _ -> + if !prev_hidx >= idx then + check_error h.at + "@metadata.code.branch_hint annotation: invalid order" + else ( + prev_hidx := idx; + ()) + | _ -> + check_error h.at + "@metadata.code.branch_hint annotation: invalid target") + +let check_fun m fidx hs = + let f = get_func m fidx in + let locs = flatten_instr_locs f.it.body in + let prev_hidx = ref 0 in + List.iter (check_one locs prev_hidx) hs + +let check (m : module_) (fmt : format) = + IdxMap.iter (check_fun m) fmt.it.func_hints; + () diff --git a/interpreter/main/main.ml b/interpreter/main/main.ml index bf594b827a..c8d6b6d448 100644 --- a/interpreter/main/main.ml +++ b/interpreter/main/main.ml @@ -4,6 +4,7 @@ let version = "2.0" let all_handlers = [ (module Handler_custom : Custom.Handler); (module Handler_name : Custom.Handler); + (module Handler_branch_hint : Custom.Handler); ] let configure custom_handlers = diff --git a/test/custom/metadata.code.branch_hint/branch_hint.wast b/test/custom/metadata.code.branch_hint/branch_hint.wast new file mode 100644 index 0000000000..e50a186051 --- /dev/null +++ b/test/custom/metadata.code.branch_hint/branch_hint.wast @@ -0,0 +1,99 @@ +(module + (type (;0;) (func (param i32))) + (memory (;0;) 1 1) + (func $dummy) + (func $test1 (type 0) + (local i32) + local.get 1 + local.get 0 + i32.eq + (@metadata.code.branch_hint "\00" ) if + return + end + return + ) + (func $test2 (type 0) + (local i32) + local.get 1 + local.get 0 + i32.eq + (@metadata.code.branch_hint "\01" ) if + return + end + return + ) + (func (export "nested") (param i32 i32) (result i32) + (@metadata.code.branch_hint "\00") + (if (result i32) (local.get 0) + (then + (if (local.get 1) (then (call $dummy) (block) (nop))) + (if (local.get 1) (then) (else (call $dummy) (block) (nop))) + (@metadata.code.branch_hint "\01") + (if (result i32) (local.get 1) + (then (call $dummy) (i32.const 9)) + (else (call $dummy) (i32.const 10)) + ) + ) + (else + (if (local.get 1) (then (call $dummy) (block) (nop))) + (@metadata.code.branch_hint "\00") + (if (local.get 1) (then) (else (call $dummy) (block) (nop))) + (if (result i32) (local.get 1) + (then (call $dummy) (i32.const 10)) + (else (call $dummy) (i32.const 11)) + ) + ) + ) + ) +) + +(assert_malformed + (module quote + "(func $test2 (type 0)" + " (local i32)" + " local.get 1" + " local.get 0" + " i32.eq" + " (@metadata.code.branch_hint \"\\01\" )" + " (@metadata.code.branch_hint \"\\01\" )" + " if" + " return" + " end" + " return" + ")" + ) + "@metadata.code.branch_hint annotation: duplicate annotation" +) +(assert_malformed + (module quote + "(module" + " (@metadata.code.branch_hint \"\\01\" )" + " (type (;0;) (func (param i32)))" + " (memory (;0;) 1 1)" + " (func $test (type 0)" + " (local i32)" + " local.get 1" + " local.get 0" + " i32.eq" + " return" + " )" + ")" + ) + "@metadata.code.branch_hint annotation: not in a function" +) + +(assert_invalid + (module + (type (;0;) (func (param i32))) + (memory (;0;) 1 1) + (func $test (type 0) + (local i32) + local.get 1 + local.get 0 + (@metadata.code.branch_hint "\01" ) + i32.eq + return + ) + ) + "@metadata.code.branch_hint annotation: invalid target" +) From eeb243ba47f651354adfea1edfe1be4d7597d2ec Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Wed, 6 Sep 2023 17:06:45 +0200 Subject: [PATCH 065/130] [interpreter] Fix custom section ordering (#20) --- interpreter/custom/custom.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interpreter/custom/custom.ml b/interpreter/custom/custom.ml index 17ed651f6b..d54e27023b 100644 --- a/interpreter/custom/custom.ml +++ b/interpreter/custom/custom.ml @@ -11,9 +11,9 @@ type section_kind = | Export | Start | Elem + | DataCount | Code | Data - | DataCount type place = | Before of section_kind From 755cb78fa0a1445c7a14290b97d26db270159aa6 Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Wed, 8 Nov 2023 15:08:28 +0100 Subject: [PATCH 066/130] [interpreter] add new assertions for custom sections (#19) * [interpreter] add new assertions for custom sections assert_malformed and assert_invalid now have a _custom variant, for asserting custom section/annotation errors. The js implementation is a no-op, since no JS engine currently support any kind of diagnostic for custom sections. * Update interpreter/script/run.ml Co-authored-by: Andreas Rossberg * Update interpreter/script/run.ml Co-authored-by: Andreas Rossberg * revert check_module change * add custom assertions in the test harness --------- Co-authored-by: Andreas Rossberg --- interpreter/script/js.ml | 12 ++++++++++++ interpreter/script/run.ml | 19 +++++++++++++++++-- interpreter/script/script.ml | 2 ++ interpreter/text/arrange.ml | 8 ++++++++ interpreter/text/lexer.mll | 2 ++ interpreter/text/parser.mly | 5 +++++ test/custom/custom/custom_annot.wast | 28 ++++++++++++++-------------- test/custom/name/name_annot.wast | 6 +++--- test/harness/async_index.js | 6 ++++++ test/harness/sync_index.js | 12 ++++++++++++ 10 files changed, 81 insertions(+), 19 deletions(-) diff --git a/interpreter/script/js.ml b/interpreter/script/js.ml index 1ae30f55bf..4db73ab5c6 100644 --- a/interpreter/script/js.ml +++ b/interpreter/script/js.ml @@ -107,6 +107,10 @@ function assert_malformed(bytes) { throw new Error("Wasm decoding failure expected"); } +function assert_malformed_custom(bytes) { + return; +} + function assert_invalid(bytes) { try { module(bytes, false) } catch (e) { if (e instanceof WebAssembly.CompileError) return; @@ -114,6 +118,10 @@ function assert_invalid(bytes) { throw new Error("Wasm validation failure expected"); } +function assert_invalid_custom(bytes) { + return; +} + function assert_unlinkable(bytes) { let mod = module(bytes); try { new WebAssembly.Instance(mod, registry) } catch (e) { @@ -571,8 +579,12 @@ let of_assertion mods ass = match ass.it with | AssertMalformed (def, _) -> "assert_malformed(" ^ of_definition def ^ ");" + | AssertMalformedCustom (def, _) -> + "assert_malformed_custom(" ^ of_definition def ^ ");" | AssertInvalid (def, _) -> "assert_invalid(" ^ of_definition def ^ ");" + | AssertInvalidCustom (def, _) -> + "assert_invalid_custom(" ^ of_definition def ^ ");" | AssertUnlinkable (def, _) -> "assert_unlinkable(" ^ of_definition def ^ ");" | AssertUninstantiable (def, _) -> diff --git a/interpreter/script/run.ml b/interpreter/script/run.ml index 90d2aa75c1..e2b3e7076d 100644 --- a/interpreter/script/run.ml +++ b/interpreter/script/run.ml @@ -450,9 +450,15 @@ let run_assertion ass = (match ignore (run_definition def) with | exception Decode.Code (_, msg) -> assert_message ass.at "decoding" msg re | exception Parse.Syntax (_, msg) -> assert_message ass.at "parsing" msg re + | _ -> Assert.error ass.at "expected decoding/parsing error" + ) + + | AssertMalformedCustom (def, re) -> + trace "Asserting malformed custom..."; + (match ignore (run_definition def) with | exception Custom.Syntax (_, msg) -> assert_message ass.at "annotation parsing" msg re - | _ -> Assert.error ass.at "expected decoding/parsing error" + | _ -> Assert.error ass.at "expected custom decoding/parsing error" ) | AssertInvalid (def, re) -> @@ -463,9 +469,18 @@ let run_assertion ass = with | exception Valid.Invalid (_, msg) -> assert_message ass.at "validation" msg re + | _ -> Assert.error ass.at "expected validation error" + ) + + | AssertInvalidCustom (def, re) -> + trace "Asserting invalid custom..."; + (match + let m, cs = run_definition def in + Valid.check_module_with_custom (m, cs) + with | exception Custom.Invalid (_, msg) -> assert_message ass.at "custom validation" msg re - | _ -> Assert.error ass.at "expected validation error" + | _ -> Assert.error ass.at "expected custom validation error" ) | AssertUnlinkable (def, re) -> diff --git a/interpreter/script/script.ml b/interpreter/script/script.ml index e7ad2fa906..cc089f5a52 100644 --- a/interpreter/script/script.ml +++ b/interpreter/script/script.ml @@ -40,7 +40,9 @@ and result' = type assertion = assertion' Source.phrase and assertion' = | AssertMalformed of definition * string + | AssertMalformedCustom of definition * string | AssertInvalid of definition * string + | AssertInvalidCustom of definition * string | AssertUnlinkable of definition * string | AssertUninstantiable of definition * string | AssertReturn of action * result list diff --git a/interpreter/text/arrange.ml b/interpreter/text/arrange.ml index 458e130a64..67fd55d1ae 100644 --- a/interpreter/text/arrange.ml +++ b/interpreter/text/arrange.ml @@ -758,8 +758,16 @@ let assertion mode ass = | _ -> [Node ("assert_malformed", [definition `Original None def; Atom (string re)])] ) + | AssertMalformedCustom (def, re) -> + (match mode, def.it with + | `Binary, Quoted _ -> [] + | _ -> + [Node ("assert_malformed_custom", [definition `Original None def; Atom (string re)])] + ) | AssertInvalid (def, re) -> [Node ("assert_invalid", [definition mode None def; Atom (string re)])] + | AssertInvalidCustom (def, re) -> + [Node ("assert_invalid_custom", [definition mode None def; Atom (string re)])] | AssertUnlinkable (def, re) -> [Node ("assert_unlinkable", [definition mode None def; Atom (string re)])] | AssertUninstantiable (def, re) -> diff --git a/interpreter/text/lexer.mll b/interpreter/text/lexer.mll index 012387a6a7..1ea00e522e 100644 --- a/interpreter/text/lexer.mll +++ b/interpreter/text/lexer.mll @@ -680,6 +680,8 @@ rule token = parse | "get" -> GET | "assert_malformed" -> ASSERT_MALFORMED | "assert_invalid" -> ASSERT_INVALID + | "assert_malformed_custom" -> ASSERT_MALFORMED_CUSTOM + | "assert_invalid_custom" -> ASSERT_INVALID_CUSTOM | "assert_unlinkable" -> ASSERT_UNLINKABLE | "assert_return" -> ASSERT_RETURN | "assert_trap" -> ASSERT_TRAP diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly index b940ad0d9e..dc9501fcde 100644 --- a/interpreter/text/parser.mly +++ b/interpreter/text/parser.mly @@ -258,6 +258,7 @@ let parse_annots (m : module_) : Custom.section list = %token MODULE BIN QUOTE %token SCRIPT REGISTER INVOKE GET %token ASSERT_MALFORMED ASSERT_INVALID ASSERT_UNLINKABLE +%token ASSERT_MALFORMED_CUSTOM ASSERT_INVALID_CUSTOM %token ASSERT_RETURN ASSERT_TRAP ASSERT_EXHAUSTION %token NAN %token INPUT OUTPUT @@ -1062,6 +1063,10 @@ assertion : { AssertMalformed (snd $3, $4) @@ at () } | LPAR ASSERT_INVALID script_module STRING RPAR { AssertInvalid (snd $3, $4) @@ at () } + | LPAR ASSERT_MALFORMED_CUSTOM script_module STRING RPAR + { AssertMalformedCustom (snd $3, $4) @@ at () } + | LPAR ASSERT_INVALID_CUSTOM script_module STRING RPAR + { AssertInvalidCustom (snd $3, $4) @@ at () } | LPAR ASSERT_UNLINKABLE script_module STRING RPAR { AssertUnlinkable (snd $3, $4) @@ at () } | LPAR ASSERT_TRAP script_module STRING RPAR diff --git a/test/custom/custom/custom_annot.wast b/test/custom/custom/custom_annot.wast index 6d6735e85f..19ed6bd77a 100644 --- a/test/custom/custom/custom_annot.wast +++ b/test/custom/custom/custom_annot.wast @@ -22,22 +22,22 @@ ;; Malformed name -(assert_malformed +(assert_malformed_custom (module quote "(@custom)") "@custom annotation: missing section name" ) -(assert_malformed +(assert_malformed_custom (module quote "(@custom 4)") "@custom annotation: missing section name" ) -(assert_malformed +(assert_malformed_custom (module quote "(@custom bla)") "@custom annotation: missing section name" ) -(assert_malformed +(assert_malformed_custom (module quote "(@custom \"\\df\")") "@custom annotation: malformed UTF-8 encoding" ) @@ -45,32 +45,32 @@ ;; Malformed placement -(assert_malformed +(assert_malformed_custom (module quote "(@custom \"bla\" here)") "@custom annotation: unexpected token" ) -(assert_malformed +(assert_malformed_custom (module quote "(@custom \"bla\" after)") "@custom annotation: unexpected token" ) -(assert_malformed +(assert_malformed_custom (module quote "(@custom \"bla\" (after))") "@custom annotation: malformed section kind" ) -(assert_malformed +(assert_malformed_custom (module quote "(@custom \"bla\" (type))") "@custom annotation: malformed placement" ) -(assert_malformed +(assert_malformed_custom (module quote "(@custom \"bla\" (aft type))") "@custom annotation: malformed placement" ) -(assert_malformed +(assert_malformed_custom (module quote "(@custom \"bla\" (before types))") "@custom annotation: malformed section kind" ) @@ -78,22 +78,22 @@ ;; Misplaced -(assert_malformed +(assert_malformed_custom (module quote "(type (@custom \"bla\") $t (func))") "misplaced @custom annotation" ) -(assert_malformed +(assert_malformed_custom (module quote "(func (@custom \"bla\"))") "misplaced @custom annotation" ) -(assert_malformed +(assert_malformed_custom (module quote "(func (block (@custom \"bla\")))") "misplaced @custom annotation" ) -(assert_malformed +(assert_malformed_custom (module quote "(func (nop (@custom \"bla\")))") "misplaced @custom annotation" ) diff --git a/test/custom/name/name_annot.wast b/test/custom/name/name_annot.wast index 5421151fd2..7a0e30c003 100644 --- a/test/custom/name/name_annot.wast +++ b/test/custom/name/name_annot.wast @@ -4,17 +4,17 @@ (module $moduel (@name "Modül")) -(assert_malformed +(assert_malformed_custom (module quote "(module (@name \"M1\") (@name \"M2\"))") "@name annotation: multiple module" ) -(assert_malformed +(assert_malformed_custom (module quote "(module (func) (@name \"M\"))") "misplaced @name annotation" ) -(assert_malformed +(assert_malformed_custom (module quote "(module (start $f (@name \"M\")) (func $f))") "misplaced @name annotation" ) diff --git a/test/harness/async_index.js b/test/harness/async_index.js index bb7d4cf5d0..6a1ff3cfb6 100644 --- a/test/harness/async_index.js +++ b/test/harness/async_index.js @@ -176,6 +176,12 @@ function assert_invalid(bytes) { const assert_malformed = assert_invalid; +function assert_invalid_custom(bytes) { + module(bytes); +} + +const assert_malformed_custom = assert_invalid_custom; + function instance(bytes, imports, valid = true) { const test = valid ? "Test that WebAssembly instantiation succeeds" diff --git a/test/harness/sync_index.js b/test/harness/sync_index.js index 79469ee9be..0bb9ef68c1 100644 --- a/test/harness/sync_index.js +++ b/test/harness/sync_index.js @@ -191,6 +191,18 @@ function assert_invalid(bytes) { const assert_malformed = assert_invalid; +function assert_invalid_custom(bytes) { + uniqueTest(() => { + try { + module(bytes, /* valid */ true); + } catch(e) { + throw new Error('failed on custom section error'); + } + }, "A wast module that should have an invalid or malformed custom section."); +} + +const assert_malformed_custom = assert_invalid_custom; + function instance(bytes, imports = registry, valid = true) { if (imports instanceof Result) { if (imports.isError()) From 9abf61e3aa64bf9283b257bdc4f46f7a6dee24d3 Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Thu, 9 Nov 2023 16:20:06 +0100 Subject: [PATCH 067/130] [test] use the new custom test assertions in BH tests --- test/custom/metadata.code.branch_hint/branch_hint.wast | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/custom/metadata.code.branch_hint/branch_hint.wast b/test/custom/metadata.code.branch_hint/branch_hint.wast index e50a186051..f3c63b32b0 100644 --- a/test/custom/metadata.code.branch_hint/branch_hint.wast +++ b/test/custom/metadata.code.branch_hint/branch_hint.wast @@ -47,7 +47,7 @@ ) ) -(assert_malformed +(assert_malformed_custom (module quote "(func $test2 (type 0)" " (local i32)" @@ -64,7 +64,7 @@ ) "@metadata.code.branch_hint annotation: duplicate annotation" ) -(assert_malformed +(assert_malformed_custom (module quote "(module" " (@metadata.code.branch_hint \"\\01\" )" @@ -82,7 +82,7 @@ "@metadata.code.branch_hint annotation: not in a function" ) -(assert_invalid +(assert_invalid_custom (module (type (;0;) (func (param i32))) (memory (;0;) 1 1) From 3dbe24e37c938acdaaac7c67eae2ceea3dca513b Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Fri, 15 Mar 2024 17:24:37 -0700 Subject: [PATCH 068/130] Fix catching in throw_ref (#299) The address `a` is a tag address, not an exception address. --- document/core/exec/instructions.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index 5d19010c1a..175dc07c2d 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -2803,13 +2803,13 @@ Control Instructions 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: + b. 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`. - 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: + c. 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. From 153ca9a90ef27d427f1ce3d2b5aa1e6e2694f48c Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Tue, 2 Apr 2024 11:26:50 -0700 Subject: [PATCH 069/130] Add exceptional return to func_invoke in embedding doc (#268) Embedding: * Adds an auxiliary syntactic class to represent exception throwing/propagation * Allows `func_invoke` to propagate exceptions * Adds `tag_type` and `exn_alloc` to the embedding interface core/exec: * Refactors exception allocation into `alloc-exception` in modules.rst to expose it to the embedder --- document/core/appendix/embedding.rst | 79 +++++++++++++++++++++++++--- document/core/exec/instructions.rst | 16 +++--- document/core/exec/modules.rst | 28 +++++++++- document/core/util/macros.def | 3 ++ 4 files changed, 110 insertions(+), 16 deletions(-) diff --git a/document/core/appendix/embedding.rst b/document/core/appendix/embedding.rst index 380794fe5a..173f60a22b 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} @@ -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/exec/instructions.rst b/document/core/exec/instructions.rst index 175dc07c2d..5d1b766ba4 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -2719,11 +2719,11 @@ Control Instructions 2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MITAGS[x]` exists. -3. Let :math:`a` be the :ref:`tag address ` :math:`F.\AMODULE.\MITAGS[x]`. +3. Let :math:`ta` be the :ref:`tag address ` :math:`F.\AMODULE.\MITAGS[x]`. -4. Assert: due to :ref:`validation `, :math:`S.\STAGS[a]` exists. +4. Assert: due to :ref:`validation `, :math:`S.\STAGS[ta]` exists. -5. Let :math:`\X{ti}` be the :ref:`tag instance ` :math:`S.\STAGS[a]`. +5. Let :math:`\X{ti}` be the :ref:`tag instance ` :math:`S.\STAGS[ta]`. 6. Let :math:`[t^n] \toF [{t'}^\ast]` be the :ref:`tag type ` :math:`\X{ti}.\TAGITYPE`. @@ -2731,15 +2731,13 @@ Control Instructions 8. Pop the :math:`n` values :math:`\val^n` from the stack. -9. Let :math:`\X{exn}` be the :ref:`exception instance ` :math:`\{ \EITAG~a, \EIFIELDS~\val^n \}`. +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{ea}` be the length of :math:`S.\SEXNS`. +10. Let :math:`\X{exn}` be :math:`S.\SEXNS[ea]` -11. Append :math:`\X{exn}` to :math:`S.\SEXNS`. +11. Push the value :math:`\REFEXNADDR~\X{ea}` to the stack. -12. Push the value :math:`\REFEXNADDR~\X{ea}` to the stack. - -13. Execute the instruction |THROWREF|. +12. Execute the instruction |THROWREF|. .. math:: ~\\[-1ex] diff --git a/document/core/exec/modules.rst b/document/core/exec/modules.rst index a43f55e91f..2a52bc96f3 100644 --- a/document/core/exec/modules.rst +++ b/document/core/exec/modules.rst @@ -190,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 @@ -338,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: diff --git a/document/core/util/macros.def b/document/core/util/macros.def index f2e71072b3..ed0da33288 100644 --- a/document/core/util/macros.def +++ b/document/core/util/macros.def @@ -981,6 +981,7 @@ .. |alloctable| mathdef:: \xref{exec/modules}{alloc-table}{\F{alloctable}} .. |allocmem| mathdef:: \xref{exec/modules}{alloc-mem}{\F{allocmem}} .. |alloctag| mathdef:: \xref{exec/modules}{alloc-tag}{\F{alloctag}} +.. |allocexn| mathdef:: \xref{exec/modules}{alloc-exception}{\F{allocexn}} .. |allocglobal| mathdef:: \xref{exec/modules}{alloc-global}{\F{allocglobal}} .. |allocelem| mathdef:: \xref{exec/modules}{alloc-elem}{\F{allocelem}} .. |allocdata| mathdef:: \xref{exec/modules}{alloc-data}{\F{allocdata}} @@ -1335,3 +1336,5 @@ .. |error| mathdef:: \xref{appendix/embedding}{embed-error}{\X{error}} .. |ERROR| mathdef:: \xref{appendix/embedding}{embed-error}{\K{error}} +.. |exception| mathdef:: \xref{appendix/embedding}{embed-error}{\X{exception}} +.. |ETHROW| mathdef:: \xref{appendix/embedding}{embed-error}{\K{THROW}} From d76b5b336777cee76c048a3e4cc1bc96d287f24a Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Thu, 4 Apr 2024 00:09:53 -0700 Subject: [PATCH 070/130] Constrain custom section annotation placement (#22) --- proposals/annotations/Overview.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/proposals/annotations/Overview.md b/proposals/annotations/Overview.md index 4bd2a0ba87..ba6ad8461a 100644 --- a/proposals/annotations/Overview.md +++ b/proposals/annotations/Overview.md @@ -66,6 +66,8 @@ Extend the Appendix on the Custom Sections: ``` If placement relative to an explicit section is used, then that section must exist in the encoding of the annotated module. + Custom section annotations that appear within module fields rather than as siblings of module fields may be ignored. + As with any matter concerning annotations, it is up to implementations how they handle the case where an explicit custom section overlaps with individual annotations that are associated with the same custom section. From ad4dcdb8bbfaad319b4218510ae359b773a5f28e Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Mon, 26 Feb 2024 17:11:10 +0100 Subject: [PATCH 071/130] WIP move branch hinting specification in separate document --- document/Makefile | 2 +- document/index.html | 13 + document/metadata/code/.gitignore | 3 + document/metadata/code/LICENSE | 50 + document/metadata/code/Makefile | 354 +++++ document/metadata/code/README.md | 25 + document/metadata/code/binary.rst | 49 + document/metadata/code/conf.py | 500 ++++++ document/metadata/code/index.rst | 16 + document/metadata/code/intro.rst | 12 + document/metadata/code/static/custom.css | 78 + document/metadata/code/static/webassembly.png | Bin 0 -> 43955 bytes document/metadata/code/syntax.rst | 22 + document/metadata/code/text.rst | 21 + document/metadata/code/util/macros.def | 1359 +++++++++++++++++ document/metadata/code/util/mathdef.py | 122 ++ document/metadata/code/util/pseudo-lexer.py | 32 + 17 files changed, 2657 insertions(+), 1 deletion(-) create mode 100644 document/metadata/code/.gitignore create mode 100644 document/metadata/code/LICENSE create mode 100644 document/metadata/code/Makefile create mode 100644 document/metadata/code/README.md create mode 100644 document/metadata/code/binary.rst create mode 100644 document/metadata/code/conf.py create mode 100644 document/metadata/code/index.rst create mode 100644 document/metadata/code/intro.rst create mode 100644 document/metadata/code/static/custom.css create mode 100644 document/metadata/code/static/webassembly.png create mode 100644 document/metadata/code/syntax.rst create mode 100644 document/metadata/code/text.rst create mode 100644 document/metadata/code/util/macros.def create mode 100644 document/metadata/code/util/mathdef.py create mode 100644 document/metadata/code/util/pseudo-lexer.py diff --git a/document/Makefile b/document/Makefile index 875efc7206..74341a553e 100644 --- a/document/Makefile +++ b/document/Makefile @@ -1,4 +1,4 @@ -DIRS = core js-api web-api +DIRS = core js-api web-api metadata/code FILES = index.html BUILDDIR = _build diff --git a/document/index.html b/document/index.html index 37eed9762e..6323384ec4 100644 --- a/document/index.html +++ b/document/index.html @@ -62,6 +62,19 @@

Embedder specifications

+

Metadata specifications

+ +

Define the format and semantics of extra information attached to a WebAssembly module

+ + +

Source for these documents is available here. diff --git a/document/metadata/code/.gitignore b/document/metadata/code/.gitignore new file mode 100644 index 0000000000..b932ec283e --- /dev/null +++ b/document/metadata/code/.gitignore @@ -0,0 +1,3 @@ +_build +_static +document/*.pyc diff --git a/document/metadata/code/LICENSE b/document/metadata/code/LICENSE new file mode 100644 index 0000000000..795b406e4e --- /dev/null +++ b/document/metadata/code/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/metadata/code/Makefile b/document/metadata/code/Makefile new file mode 100644 index 0000000000..9146ee74db --- /dev/null +++ b/document/metadata/code/Makefile @@ -0,0 +1,354 @@ +# 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-Metadata-Code + +# 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. + + +%.rst: %.py + (cd `dirname $@`; ./`basename $^`) + +.PHONY: pdf +pdf: 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) + +.PHONY: html +html: + $(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: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +.PHONY: singlehtml +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +.PHONY: bikeshed +bikeshed: + $(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: + $(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/metadata/code/README.md b/document/metadata/code/README.md new file mode 100644 index 0000000000..d5fe68ce8d --- /dev/null +++ b/document/metadata/code/README.md @@ -0,0 +1,25 @@ +# WebAssembly Code Metadata Specification + +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/metadata/code/binary.rst b/document/metadata/code/binary.rst new file mode 100644 index 0000000000..05cc2cb7e8 --- /dev/null +++ b/document/metadata/code/binary.rst @@ -0,0 +1,49 @@ +.. _binary: + +Binary Format +============= + +Code Metadata +------------- + +All code metadata items of a given type *T* are grouped under a custom section +named *'metadata.code.T'*. +The following parametrized grammar rules define the generic structure of a code metadata +section of type *T*. + +.. math:: + \begin{array}{llcll} + \production{code metadata section} & \Bcodemetadatasec(\B{T}) &::=& + \Bsection_0(\Bcodemetadata(\B{T})) \\ + \production{code metadata} & \Bcodemetadata(\B{T}) &::=& + n{:}\Bname & (\iff n = \text{metadata.code.T}) \\ &&& + \Bvec(\Bcodemetadatafunc(\B{T})) \\ + \production{code metadata function} & \Bcodemetadatafunc(\B{T}) &::=& + fidx{:}\Bfuncidx~\Bvec(\Bcodemetadataitem(\B{T})) \\ + \production{code metadata item} & \Bcodemetadataitem(\B{T}) &::=& + \X{instoff}{:}\Bu32 ~~ \X{size}{:}\Bu32 & (\iff \X{size} = ||\B{T}||) \\ &&& + \X{data}{:}\B{T} \\ + \end{array} +.. index:: ! code metadata section + +Where *funcpos* is the byte offset of the annotation starting from the beginning of the function body, and *data* is a further payload, whose content depends on the type *T*. + +*code metadata function* entries must appear in order of increasing *function id*, and duplicate id values are not allowed. *code metadata item* entries must appear in order of increasing *instruction offset*, and duplicate offset values are not allowed. + +Branch Hints +~~~~~~~~~~~~ + +A Branch Hint is code metadata item with type *branch_hint*. +All branch hints for a module are contained in a single code metadata section +with name *'metadata.code.branch_hint'*. + +.. math:: + \begin{array}{llcll} + \production{branch hint section} & \Bbranchhintsec &::=& + \Bcodemetadatasec(\Bbranchhint) \\ + \production{branch hint} & \Bbranchhint &::=& + \hex{00} \\ &&|& + \hex{01} \\ + \end{array} +.. index:: ! branch hint section + diff --git a/document/metadata/code/conf.py b/document/metadata/code/conf.py new file mode 100644 index 0000000000..f72fefdc73 --- /dev/null +++ b/document/metadata/code/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-Metadata-Code' +project = u'WebAssembly-Metadata-Code' +title = u'WebAssembly Code Metadata Specification' +copyright = u'2024, 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 Custom Sections' + +# 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/metadata/code/index.rst b/document/metadata/code/index.rst new file mode 100644 index 0000000000..e8a0c3cad1 --- /dev/null +++ b/document/metadata/code/index.rst @@ -0,0 +1,16 @@ +WebAssembly Code Metadata +========================= + +.. only:: html + + | Editor: Andreas Rossberg + + | Issue Tracker: |WasmIssues| + +.. toctree:: + :maxdepth: 1 + + intro + syntax + binary + text diff --git a/document/metadata/code/intro.rst b/document/metadata/code/intro.rst new file mode 100644 index 0000000000..2143e5fe78 --- /dev/null +++ b/document/metadata/code/intro.rst @@ -0,0 +1,12 @@ +.. _intro: + +Introduction +============ + +This document defines a generic mechanism for attaching arbitrary metadata to WebAssembly instructions. +Additionally, it defines specific metadata types using this mechanism. + +Such metadata do not contribute to, or otherwise affect, the WebAssembly semantics, and may be ignored by an implementation. + +However, it can provides useful information that implementations can make use of to improve user experience or take compilation hints. + diff --git a/document/metadata/code/static/custom.css b/document/metadata/code/static/custom.css new file mode 100644 index 0000000000..33bb863d42 --- /dev/null +++ b/document/metadata/code/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/metadata/code/static/webassembly.png b/document/metadata/code/static/webassembly.png new file mode 100644 index 0000000000000000000000000000000000000000..f9edc61098a6f6957903d4e67d92c81269c22e49 GIT binary patch literal 43955 zcmeFZc{G&o|37}um@*~HAWMiQLRrfevJat1$`T=KvWG08v6OuYA-l@bD~Xh)#8@I_ zuk6cMLLpNsMD@F_+w1-Le1D&Fet-PV`Tp@e-_x8^n)|+%=kj>2*QMxF20Dy8_v}Ov zgi-gn)@cNx?}dNx+rg9iqM#}8V~6K)b8iIcY=eI=CJA8y2qJ*!YN?;`A6^`L<0jZ% zdt=hNX)$(hxw619n*a)pJStLklKDnk*yPaVx5^wP_Ue`5EN$U?nH7~4VmFW0eTz?j zX78xXtQMCaPc~%P*^@>1l6WmAy+n=^761L0AY2UnBu6p*`!7f&IppC9^sC|4_Tb8s#-0J0b;cCA}r)T*bqX7JY~UlLH7@UEIwXiV|*%)I8=u z_KKYZatLOFP%!PsQo`*Z(-UxS%KN7Xjlw7nRyzt;i}LgpM@B7B`JsCg!Z6@_CYb;8 zzrQP?%%6lC62U4_=Y}hGgAwQgQ3}!+Bm!;?#X-qWt9pV(a#k$x|2~+=uBXfQI|L{| zpc*_4wdg4x`@sIk;Pe_{UZm&YxnXrJF)=_bx&(aD5Dq9_g%nfAFXT4Sk@uoV(n1Fq z8%$!T@+^SmOt`Od6_7^`geo}-YL8ru!y(U%^)0kp3V=ac2Kvu%ZVf zgf>VtoW`gb0tq6>XH?SOfXW_jVYo!Ye?Pd*25H}-l@pimJo^a|uB5 zc0{oPDutE-2@2{4I$P@m01iZ9JW&Y=r0s>fqLM-fbmXk|fSr~JaKGiF{}hUMB9so4 zO=V#S1J%c1TF3(6U>s#TvGfE&v3%dh)N~a}+V8&}k|&M=*CCH`wLkLd6T2gbl<`Xd zZOSS-rW;HoPbh#f!swVI1|Km}N&#LLz}VKV3%901*tsQC4FFe4|@9*hF{q@(JE zf76t{ILKI?8!QTh&rd7p7?T6$^q7LwpZ>BmHDWZ--LAs#JTPVacQO;yT^Y>>&QN`f# z1}hc#^vPK*-g98Rf1k!S?_xuw9OuwYQ9B*~1eS?AE50N^?1DhAOG6oWZ@zse!gUvw zum=zaf-HNvV-f97(7{nG&`q!6*^xK{akt%s$TYC=xCWHx__UPfHY6@Ou@2}#9$Gqi zmGvOP6@PB{FwsC9?r;m;VZeDi1Hu)K?y!vRkVTbIM6R0ZE77vRCUvM2a%~E@!GH`F zvl1ANfIa>lSdJfDKT23A7tU^O+RlBnfQZ)&K0i_C+dDZz$K(g0PU<8A5P|<^O zz!V1W@jz1;L5=#kCvYg^hg4rHR)BfsC()%Dbe=x(K7!B;P?=Ss9`nivuyEa3@rMz{ z&}^B|4a#`?`y_z9^91Yxvj=yedlbf=8xG}0{DBflTX-7Ww)KLfpo^y*nrSmlhY+|z zf)Kc}RGN0hbvt4;fA~gXIed&F<3}T4CPY;A*-slNr*u?K{05htU+zLS!xGDYE^<)3 z1lPXybH`A5)+^ql8aluA^k`fZzyQrM#Qp<2)FUU#m|?>}Uz#IAz5Rwur3wIj5RD## z)j%MgkJ7I268Isi7h@sj7Dsf&mqvFXf&(=G&{t7ovh%#PJb~@0fShHU!3EF+ge#m> z)6bXh^7M(rE{_5*dJ#o!+)HQRW4Dvt&%dM@fk;EKLj6I;C>*T%^a(4W7|Nkl4a%W) zM#}O7L(i>E|4*%~V5}J`;K3lzhe~Ru?oG0v!Lumz8CNZsPFLmyCmlzp&Px%?IuI%A zt!JovX#FH+D1wzTT=0xnLJ%np$i9?gnJ;}t!G96YwI8a5tCF-!csC{^`rNRWmL)WQ zu0!ba=PAk+c#869gbQ?C1XQk~Yx@l)uu>PEK6wzO@EGV^$`M_8_qYyyM)|pO(NWAO zO9qgxqA3xSu4C(jck$4AL{aMzJ^BFJna$=m&)oAnWXsEnSP>bypImO zZyvGQi#gD!1R=+cN{>B&pU-CIlJgrH6J$vp-Tti8(=$fy8mlQq( zf>AV;9^C^NlRAoy_Fbqu%ta==vd}=C*a=iwC&q|3l0s~Dl7GD(QU6^IS#v-~)9XlE z^6jGJ&O8)wfo|0pjcVRrCi>51=qR5*xCtz9xzhvKWXM3VWu#2FIL|pEgSA;)?%UvF zW%O~@1CVZTBUkRGU18hO`z#9dSw{k)dRp?6_A0|W(P7OrO=LIYH zu7-X`v$A7seVAMVbaLZRw`$7~K4igsU_TJ&2th-UOa_LC=Gx@YBqkqyIMrVO1{h_Q zzR=HjIBY8^Hyn%nc1x68%LZ0M>e1bTTnL1`OU`pe$Sg|3TKxn}<7t}wF3w&rtVT1i z8NgGiYmI8R+>`|`>OTkqL{YkfOAF6ufDn!W@}LetPRQ09`yU2PqLxLL*SlDhQt z$x753I~G2Sh1?^L{MZS80mlwgMBew6ZD|~_LUrh$1x&QB`y?g~xTJgtAbxboKy=9w zapIJn_);G`h3j1(ldb=s&5k`_IS({Dshe1S`oy>O5c$O`;RE$8v>5;x!~=ExuC30y z2A)fv#4Mgu5&ts5<^Br1qVk~(cOH$2dVX&BH9MtjW@C;YM&fdAbT>z^TZ&&_sM~`= zzIT0}n>OaaEFM(gu94vR!*(9Y`iRwTFhdUY0)x44xyt-h<+hcJ2E2V)O#2P8Jcpg+F1X@y82)~LW2d6qRmy5gt4{e@1H3aAHFa7NsoGhGXKmsG@hJk#%fzJi6g!{qE zK@{&c*9>fH#$RM$qoPV6KmCL+%TZ=#Ku9)ds!aZMPOGKC#d!gQw4?dfAVb*} zibE9@heEb?3ukd(foj0d&4WZ0QcD2|EdB#cGq{++izA5!dDqH8vPV%sd7hp=qu7!C z7D{azr7!O7wDCuMZ%WV%{bB2-kKTYMBNSe(OESdImz+6^$j%Q6#Q_abYks@p92D^-g2IACa;ENjBZFT2cS7J9UP;KRg9Dxv7vONKfQMFS zdPRNl*|2!RUnwW}b#<4%f-l@i2_@CFFHaix{prH^(Die}2XC;=3Du!*w{N|DbB$=r z2R6LKBv%ML9P{L;FSIFFv{^xsz<;WX^@NL+p~Dw5^Sfg4P)dv8C^IT!4Fw@rftS4< z4zhxMnU6FSfGTX5QF>da9&s6zOaL9bcz-JZ1xw_`kV^zG`3IV6+LWraX`b=Z3qEkk znO+*Va<--jih%I56FRTBce=kx;txqJOTY3;RQS5@tREyMl!CZP$v6rzO<{i;RTCRo z65^8V^=e_rl;FjC2e=%B4Rv}_oYz`e`j?xWzvsL%o?Wfj{GG=D!{1i0N4$S1lunRZ z#z24Rz1X94;f}<-Ujf~`VD}*ydy)ChUuS84gfAa{=K<(&zSVlym$2WKTT{?_b|TsV ztTTTdvX3zTj*EIEUH5cv;_stbY>V9O%v1Z4RDXLvhD)JkIzqdA?WJenFu&V(_t9TTY$4$i&Ef zJm2h2?K9ftSj1&E_~*f#2*u&Ij^4+HSd4%Kuz1T0s*I$a_fq@Zv;XMo`K+Z}>*(-2 zVzdvpY+)F3Q)BJ+y7|u1e6y>KXDg2i2`Q>wv;voS(!DEU2YwSUn??k6-VJAe-H8bm zWOGQKkaYSrkuuC6SDh;^T4>IScmX#=y{zYBWqc=m8L#3^J2uH`juTsal6T`S7xhvK z9+?8}iSpqw-v1@ZbB*p1n=EH&Wk)OZ(}PiZU7ITMGAlB2M~j~P=Gf=fb@g5MQcnl> zH9r`qDnB}ua6bz9{krpjJ%K9ECHDs0^$CT$DO!E(a*>E=4j|ziiL|Vtg)}df(5IZP z10j2?PV3R@A}#m8dJFahT1*o@NWSC~sVzm2;@Yx~lXp<{G3)0f{4XP7Cq1nQp|$vo z_)S;&t~?;#WQr?hLKLae0UmVV%TJP(F-POF!S`tU4ieRggqw6AP^&qs+*BF=2zr=e z@w#vr_a`<%+VsqxHFH8}H^0K0XQ5))%^zXQyO9x;76$_DwK|TLLJaFkjquE^_DM>v zK37pU6#t?;Mi+;C5dmxkN`!pLj5VPush`!?c+?Ovv769R#WNR~+Lt0IWsx5(`;e7S zKmaOKGL~%0euE}ysChvmY|s3y|Mb2fGZ#n!#t zS-CB!8yQpqw2C#S%-0oZ(HlD308;5Z+KD#XNVsyvM?Um;Eg-o!{-g0L;anw_y!4!x zr8yf{L#qL~G9E}+R&ci?P-Q+~=z~4sRILJ2J^f~B6mnWmv~$B*ia&q@!?1AxTf=R5 zmkw6|NBI{ji58~*c0=qYEllW9|x>H}eZ!=0V&}0h%wPNW4tUTIdv{ z4Xfj*O-k-{FI_`h1Aut(kmR;)(g4kD<^;?vac!@s2?s`hrIoYhU(|H1vsB71+Ea zuw%1cV|!`Gy5OA95G4FPi{!+?m%z z;z1(CGGb!zH8O_>@2}OzAotJ3|k6VbcEmGjI=29gG#I`H(5S~%o`?CEJMoz_VDFv z!cpz+*)RHX_?1JoagZRY|D1f+j`Gjg30-6lwDj*aHaFNV5sg?U{X-`@t!jB8F_QUL zbG7K_lOVMzBsE`lOpelG@g!+i5Sf*)O|feS_3#hP$oTtn8dZm|^U(bIr*(ZoJTZK2 z3U!b3ZV0-a8FDyK~JQ z+j9W&{^srcCha87r!9O8Y`CkzM6h*)w6@J}}9C9=PS$DaT8PZZ)!;GNFCMI!rhMjVbt^7)};OgS*O z7(OagP2Tz?!!Fu$w9Vh1|FVSn9#!`ALS_|w10O0i`PV(>$OvUY*pRMs%pXzK=oqSgPbqs zJLMsm&Bq^;d7LXghh^0D@#V8Ydh!@9ZsvO7T}HVwy_vKanc&Mwb@n08!ssTKI=^{JOHG(PPa%!sajXG|#u5|c zff0V^!bD z_vQd>LHvz&mGjIQ+6oMD=KKJQ2wI#6!=izwyi&4pkgk6_GMWL21_+!Hl^ve7m2jze zzb$0id8`s|W=6osc(7vBvVgWdfi)Wp8*1LfG8(f?4u-9a+OrSBIA#{Qvi;(pP3vf; z9uc@-8fy+e6EWY2ge%pGPO!^Jb0FA^ZL6DnfJcV!LIHk_(FswAA#009d%A|&WlYqX zrxoVZjbWb|0iO55B{EEpov!UMh@Az#=8E}syI3Z6LWE;{;%#glR61(rBP*#pMQcTF zOmlRtAHbgbpq*3$Ge&r~yPh;?rn?|b6-WB5Z43j3gH%ugt!jaNj0LLYVvqbQN8 zJ!%tS$FUGd^tNOA22(Ib82E$zS@|A`7s)1=^18rybI}}^AxcqtgsBr8vB$`0LSm#B zTg`78=vi5u;4#RJn!1rX|D-5Npy(O@&%1(B#$@I-;8^6K2trcl@7)t?^4h8TC5@@$ zcoPHYc;F!3ct5UGO3 zwF+G8*Kd0gj6FLh&0YrXtv^IWCVY`9b@*;Y5c}gTb%wi5bkjgu_fSV$KG2uVF`!h- zi>w&R4`_J_SEjQI)$~3JVC6bop4QR>#GkF|QrvrFTg|JGJwSAf5cI(S%c+)Pb|W$P z8rhA;zMhIp+UMHB!9r62WK}2OZnsEa84;}9iQDZj{28zob0-h?f1&y@*PJ0>C{=K; zdgaEj6er$1&s-h_DgL3yP6V4G#FVDzM~;UE8oZSZPm0D2{__^3wJqc!e1g&Mr!az> zfWYqs!be8k`|UPwp+>Kn<0cJrL1`eYTdq!$<$jy-pSu9K(VJncZ6f{4T8hHJugzH? zu2BF`pSur@>9*I;yBZTPtB>=xZxc!|syY};zCOgvXZsZp!3c@?VEz2%w`7IoG5 zAa&3_b`%%ujiFxp&d6Q~WDXPG)m1TU^5f*C+s7QDhwvT;iBZk~amIS#P{Y^#_wd== z1q7C3zT5Ivh{kxH2%BbUJ1~+?BHzY}l|&&n(6-AN^}bO-)|QIpG1j7N7uoIU`dIeA z@)tET;MxYEZM$l6VA_BGXZIy&WMj*`H{8=%&(Op;kS+SJ_-jq#=Sn_Um z0{N%_mb?T(uD#fLRDWOHUHo7a5i6&4A)340#OzU}%tis7YL%3tF4o2ZlFtXFpB>9S zh%XdM(D6KB`=aY-=^xArvc)?eG`B~+jyy5=!I+=+Os=zj!^U@|-~a027Ydc-EKdgc zKUx4Sow}2fTs%_K02H2JYhza*jWoP9dtg_DycjkNXXUf8Lw8I3zJt?NDTb`%EzQ{` zq`-&goea0iEDF4BPN9`asg4~mbx8|kTix~!vLxWrD|gtvWAg+Xo<6oF=U zo5Mb4ir>=Im zat!dNgL@61<%>*N#o(oQCQFANq}vU{lqcjZnFnkN-~+a~nmXV3KK9#Z<+*+XP`eW7 z9QS7z(qcfAxeiMQW3s9!5kb9+Yxi6CZ2lIOTn3lXa|Ddz{*0TO2V#*GT#dBh9XeN# zo*`B3Z|6l~JUbef!It}Lr8f$ut9RAh|9PW4ToCyTQ`C`E5=(CE_y1bJMZU}3^`$cA z^M_dczawVC_+p6e?c>=Q@w6)AU}BsMzLOF)H| z_R}UYc+a}93A^8CS2g(sLnoxD2?q$knL>sR#R@2ME_s!PPTx`*0WnqMxcfy&?y)0) z5kWzBE)gm8#-0Y5W3`o;G zg&}Wpk9>5DT807PqhS*lLXt_8zQsr;O9iEb_8*54KL`(yyi89WbIDvFaRaL2K!ENq zZM?AKhbDa)2;ZJp;WAZXVKmD+r;{K(kEb0dOqW#vF2aHe5ax%X^eS3#Y8bOmu7z2@ zlNaeows9cgzPx+7nj#47MDEEC@&0u7iul}-? zYZ{sTDaSSSg+nCGL<g<}wegPA|IV*$$CVJl)p z9$0D$7a+Xi1`&JCB#$*$D0IRq?Jwy-14FRsy{8qZcFg2FljOKru zrI)SkNP=h@D1w_xCqkb>wEYCQ>`4H6H6YqxCbZO?V(@0kJOiaq8<*K^>Jg|`;Kcb1 zTPq?!F|O^O!V{1EXQO~QnUcwHF~am2-6%BV;V(6?Vu~mdvE2c|LG_;!b~kZw2Iw&{ zo_hn_*aGNOsaZV6Ya9am>?A%rElKQ3ro^@E;aRvs$;Q}-0(@PJEw+d5_YmKYw>08* z#d~Wl6)m!l@lyKaR?vW;yoR)L2 zyLEF8jN=ZQafEgV%17sPABm3P6K!Kf+gNp*0MS4 z8rcG3%oo^x{;}M&$t--08Ud5w<)6}bs7MUk!AjY~MfQgL=Z`5kiAG#u$M8Re)vIE0 z4dqL-j=6EA%z`+ze=gw9y;Or_&`E$=vA6y3LZi5ndI}Iz(eKL>4X7{tlY5{q3w=02eo;-g373iIbL0`V~RVL6?Vr|8$ z_?HatOP~;t)8IdX>{f`(jibPL4+^6|*BB!2AzJJ&nL0s_Pn7H#$;HSny#{sCP6{7r za8R1yurjf*9^lJLDdszkR6s70aNB=0?lp92qgRi4pAh8}#FXZMI4E+Vl?n4(+u{Vwl;dlO-S%(zNRF08L8_`I*(EA3vc-?7F>holS~=vJMCemf@!ZlW_oZDj3>cfR_32;!9z`i?Z2u8SM>Y zh|EaY6a)D~4oFnl>B@~#@JJcVAyw=N5m#6+4L~kJq6y5U=@sKxTQpsx>Y=L$_d?}@ zE-K6UvE^Z_q&nZAjFd0-1e+Jzz^^~zkaUn~tMP+KnpymDE&4LPL+AH=7G48%!t^W0 zu^po11n45zo_qa}dB$dUynW%Ty_6H_Q~2!E2pybLKcR4~#lQ_jPou;xPr)sC}hGZ1S(8lf2hO6Cx?V z2zHLf(aG4UG71HF^HE4}AgAHowhtP66X<9!s33zXO>E@Fgn?R=vh6p>j`9y3tu0}D zZ-iU>-JCTM`$uT|LHV;Smi*!0Iru?f`!l~jQJr_=4^1>O%i_=ZT?jvvdA)z%fs$V` zo0U8-3K&1ItXWb0shlVq`5vIbx$cu<^oQS2RaZUGF1$PBAqYzcQEFC$NL#_j#`)2`iWWXrHrW<`=}!q@fbuoLbHl zKEV0S)|+ixMxp}K8gRe;7M21{JmVd0{`DY-gQ+>yJ|lz|=NY#_q=6uJq7<@;9 zf$~O1rzGbuJfe!TF$N_cQ4q$BB&@RUCzJe{v%q+2}gB<wBgRtR~jsug=%17r2I z0xPq4XyHT9RZ{67D=m5TfR$vxiXm-%r4lr3KoW7~TPx$*zF-iLH=z9+>V2z;!3TY& znCqSKP8QheWOX$yM((w}5~L@}*!X*BNZ8{fjuHTf^dz3JPSyI-vEfXsZMGIsZMyb* z_TEz|%V_~@Wpl%A1BhWINTDI9Z+OFo44d`!J_<&kV%MaF=p|*;M+;=5M6hVI$Ui&w z{0hq(P$c!YAj<#{2q!Y%ZG8rzsf&*;S zDNyZo*r^yiwV8>Ce;Mz98vpg7$%(|F?VjSm(SAD_y>~#K5RuP|o#6Rh8YPeox&aB) z(e>uXngYC_4%xg8f}kZHNc;{Lz)nz0_RMn_Vav-?9(rqZBy@`w?(^R@>m=n{6`;vR z;Ro8GL`wyqX8qo+(qN-9wbDAA?z@{1L7ny9xTEtO)W06k>&yu^5%CKmVV`#sC~e>r z$WNHbFsbz}z8OHmp75$Mj*e;ynaCbE*LqKIXQR`u^p#I~-pMNFtF{TAJLIVu1^Ynj zFb~#<$Q)1}WgF&aq2Q-1Q}*y>W)-J{SNBwgZBZCG!|1LWN5q3-|7Y*Qp-)l8QTY}-)oQ{n%i=6DTc%r$N(*bXI6{?=Tayr)64+LO zP-Gp`9|HJ&pISOAm{anIKO_~$khv7O_Xdw=NE*pz3`g+;JV!NN4<&;HFZr~h?j3#i zBxGWLQ2iz>Aa@hK0q26YI6`c#zrlVpbr)E=C5gn+Z-g5=8gO_gM}htKb=!vw9->5i zW9O{nLD9m%kdNXgkp@WXE(xZVvs%<6+qzCa{^0^r!*2OBP*hY)Db0k{(w7Uu#iZVu zz9%HIHahLhu7DYock+)VP^S+u=Qz|7gqh}E%{dSvWR1im|*l<#JG7P?_0u z)1w%?hG$Cc(CcLg-WUM5DbJe%5)K-wpbr6bRJJJ?iyXmK+Iii@YXJALmJWx|{&`ko ziC@$qU@{Und+*m@zmC);+?IW3y60_!7`S{Z3vL* z&Pp@Otp1(B9|S5JbL}tvt)Phxs-1eMcQJF^K2i3dG|Gsjh>UPW)ph{))f$f>;u2Xuy%S zP0oH@t&n`?ZAk8ca!gF2W~6E@9U_uH1bpi8;OhkE;^$%$hruzH-bYfLBJ2!qplx}CwK6$R zq={xhUbzrZkqa6-cc4&|yNU4l0*EO^FcSvwgfFWTig|V{zKP@NtYY)02HpU}qG|$- zn-VZAIY2|$%dEU}69td6MEML{q+Tw}$_CsT#G{{T}1HH6p^d2-@ zr|~s=@ct2n4vh~_u@LL9RC%JJQk2S+jDV9zI&zB5)G4Va?bjJ<7!40^#5bQy17SeJ z^T@h`>kcP5Yy>P>GAxy&bQ^n$h*+up(udaFVH;Xl*F5c4&-5!|jsK6=5(hwYTLUt6 z!VpvUi#!@Xx zS9j(JUC=<#l_xMM12*|+Ts4locjfmmS8kd0%Dy;C4AY-rl#wpiR4o!iB!nr_q7EacwR*CpgRh-#i<8~|rM5y@KGgQ%^%ZOG%bM`o z1Wfa_phRkJ{FGs?Fd*+{bQ2|BY?CxRelT#@Ub|}UjO1rl(Ak7a8SdCMdl{U)pc4iy zk4LqipNaQ;tNHfG`}&)1UvpM&SGaBEIoJL@TJw532lKGTQe2buW{vJ(a(b7WSV>A7XrOYuR;IF@)ICR=ameZVR~b22mUzN2f_ zC}m1M-VH*TVMQ}7<2F(at#`1_UE#p>@b2i5jx$2fmiHb)+eTcD2lbDrb}*|*#0r$^ z;?!h-jBAG-E=-%ccW1%j#0Q!W|DDER* z{03?JRX=lKZ$pdaU9TLF-hxx;C|DHLl(3}4 z-caFpm(ri`*T`Ws{wL#>YohtD!Txg@{I62;K+?eiJ)QrPV)Nr9Tvid+rQc40y3}Pa%iY5>w z5Cih`X;wF5g1Yq)ANejvS3Bi`dHG!nXF8ZWnC;&T`Cis_e?=b#M~c>Js{TX7<}t|M zE&vLwlL#6~webQ420-CxX8`a=!qO2RoPE%H3rVN-!r7=v3BOs+el*_Ol>7ilocw1-w>^oS zFyb`~J?~i83C_!%$J4w@9p23T zL(5DS-n;E)ci0<;mG`Txc{}=#c z*sE07J`0219o>rE3UI?Cg4lc~NcmH-u%x;$Hy+Eur69-Q!*`E;m%Rl}GD5i-X6dg@ z&U&t7j+EZIHLo@Ru)E5$fg*-yZjU2BS2-3=lyV*Uu`eK; z{*5Afi(r=i!7EUTKfsf%fL{VY6A}DusLN?*ap z$lM`LzU*&PM{IJ;Z@=sp6nfSjHgZI=qQ7bLVjDznFp_ zmX`~9(zxsM*2K&_TAT9N2?}|n&te|nKpma}s3k($A6Y($3+PkQpDF_YSaEH=ar38N3m=>RiC-aQps4#9>#ombZM)X94X23AqEnQRSxo9>oI>;#TpL`#cuqb4SdV# zC>C^vpq{b*1suBwnHT$Le+cg)<9;BP5+JT-2zfkeNQ`n&WqcjIk>N0rc8;uS zwcb`kanb(j1v*!brRz~cjj}E>a~0qmkR?;NH}o^aN+rmEa0vOH>%kZOxm>BY{&n#2FiR?F<&4v(8n zC;1k?jHF#(_4g^Le!(4ZLbNlPw$XB_gOoPAJ=@GhMt;(DZspZ!eCIR9dD#D5W8*wB zeKd;d2(p9j7O}1aqV}5-6??r2F5=nMnR8FT*?tcL#G*sv1ag@nff-? z&x2-h4;^&-GwA~{cz4^fjYDsvK!CiLn#-}dpMN1w7j*CrJAo5Bv$v0L%ImN)d6klhI zbZE$nKD{5M)-TrfAfuwIY5h{VD`TWD?-m{MdV7VRi-F$UVL67*fh(d;_MMNxX;IqC zz<*Sqd+jY`$pj6*PLMhw*QVR^{Zly>z6MUUg2Mr0J!iAY#E?=$8(VGS!mG#d3Wa)x z?C=~2E*Z;~_s137A1LHILts4uV4RUpyNfp|WWUs%d8Fs9as2(O%FhI9>T4ZO{^?Lp z%Y94QIZHqGsK7bAxHq&2bu0~=ppU6H4oXQGr%r|^vo2X3x|PWv2IbR*0;UsJ&Qwje zTcnrHX(3Nwx1%mnX>-~ObNSfo>L2ziw?GRlBJCa?@2-2x1@Gg8^dMtZ|h~&)cCC9w=;f$Z! z(dMiVj=mF4pU?Z%W1hSeW!p}?7#7?MP6p4xTlC}Ll#I#nOR095KpoXclkI9X=FU8@FP- zvUi2srV?7=)qpWaWxY6ufR`8TK3RQ8lwW&biIdxZ(@hJ_>;yXYEWv0L5ny-(9HfY& zyv{z&0xr0`1mJS?(k$cC@?!Cr@mqtZ1>-R1ar_4 zv2{+r`=7f2gjYvux^sS?7XvqefWsDxei`7RgX9ulDl*I!svK!rKZwnjh2Yqqs$Aj! z`gCru!^-Xnm)o|pz2I2o2yWq0hcj6S0D+w7SwT$tsn?Mr$T7M5u3KRJR`wE<@p4Kx=mRfaAfM|tomjBBc$#X1iM!48hJ7tUNFRi7G-kW*e=?8o! zXjKWwA8NJjd{?Biai`4${CA_ru@~W8!Zi_2aa&PhlHIBG)@u{gCR?E5H<=6DOcYI= z#=t$2SZDkA8{JHEFV#)~(kaoB*QV~w9EPFi=&OnL-Ipen^qV}G`jgF^F5IA2PCo)6 zP{*HmxwMxzv?;lWnSG=f6*V-+G%Gmceb zt?+)B%JzxxHlroGK^eqwh$y8=Gq=4#S4x6%(Tm>u#t6snnAaueuyQN$pNa40teoC# zVe32jWe0@0y?*On-M(=r<#eVN;tK2Cnll{gA|xFDY?FIdRk`(}^-Bh?6ZV4BRPS*8 zcTK)YTBfCb;UlooIS8G;=Y3G}gFg1I>$JArgeMM~8{Y#Dw`HgD%^m`XaeH^9fdSm6 z1BXKv&{LI7+G?|)Rb7tYmwhB$XFJdOGVMvxa?q0rE}>_#`!i~vlxsIT#h5eUK-q+3 zuYI-BA=KraF44^r4OnCw5}a6n1Hyyselw@u*L&h$4g$O^#xl8PL&~*L%9o4SFTHj8 zBX0ScM@gaxU+IWj5F0;J&2lw4Vq*IOUxs4C+lvI+tyQYQUwDw-=*^YN!4r$5KmKEH`O3+%3(h;@;9 zMgym+Amg)XhT3`h7;jth=vVY_{parXMvp0M z1a*E(wsb<|pntV|bG_G0S$fSc@|pZ$$Dy;I4kbzNziOhzq5+ipm_Jb2UF;i=`X68& zt}uo3?0cgFl96{0#I5qr-jOdFSMyGe2x#~79m&(tEzbvCoFgsgO2EaYj3tT*^f@la zq6OHmM=~H|Lo^q`^9pjpo%-j%MWWhJ?k0Z!w+Osrhh7u%l-NC{bl&xoKC@ z?g!=C_C`N6tF`Z{mI|XXndaiX`69} zslVhlePwf;ic=G~re@;;#6nK7QhB|tqk1J~etiB==XLKqn_KqWkoPOP*K`gR z`GXuXC+Bs&0~6?%=yja2ePL{0$zRpJs?qZ4um9A)C3?CJ7g|#)`*G~rS;w1_6lP3N z6kfL^{bEegdDhT98Y!jqEfWvMxi#rXy+Fs82Rq_Le&&DivSd~FwVli}WILaeO89h$ z%jx?ou9E#fNIE(6diQ|3W~Pd&`S^REIX99T z{sKGZ6zfS)>T<^ChFoL{?zH;i8*}}d${UM*(P-*DPJ&Nk$b88IF1p^=8QI$w+tk_k zL}Ctr?5ikU-@|ojb>pdE*umX@us!Zd0lN29tmKjn2gKgQdU3R>SkAX|cy)wCBO=$q zgrrz{zTjTurtbGy`X}K(_1vxGPD_5dEHorUDA}j*xnvd5?}N;7cW}+eY>&$N#j!~{ zY9#E?d|r!?)cgEbPkgWEQa(?b4}DAl@1CJ);ZgEJOJ!kqF;ZR&DM zmFdz)g$P`CCu`nDuGjxO%c{0R252i=Ch%tghR7`Iax~M(SC4o~@+!Ew`_9Q4b-kA6C ziG)G6-lpK6-BA~ey>wQ=_^{$7-`lIp!RZl!L;ECuC8daazhn7n+o3<0sJYW>n0{wI zpxoYJM|au9h|P@ydC%UNJWxJmB5YA$_0OYx$NU@AwH3a~-q82Xz@NJZ)~3z&SX*hG zD&$v@{4_H)KF9r2=F)heZ4!=Kh~NWG>&{n7Dt=NuwF~M`9@SrM?IZKj#g$vK3MJq?6Q;o4; zph9u|7dxi>0HB1rS9x<@XSs6c(((iC_0f_Pr{P4+WR2&u=_2yU0{dm}sv6;NlC#r_ z2)hOwaEbJQ@NeV1myI8xqvt9v>u%h^OLa}1d%pCIr7kMmWoKT8#VhmoJIvxC@NT4A zT)bm^cTP`rHAS=7pvKB(Q%AU{HXv+I*b2tZnSAyl5Z)?HEKJ2L)6}>`?)egXaLBvp zvw{Q}!(fe0Du>BvqwMuZaYUs54p7JFOMqN_U!qmI=@HF;3{-T z^RuS=aK}uVR!@!yR;5Bx@mgY`EYJ_S#hu=_iQ&s9Nq2^00xOgy`R+f=cmK-x;P&Kj zlXQa?QVL83@oawcFfjPlZQh>;Z$~F6*4A+rlfC#Yo6^*SD`L3I#A{Z!qoz6b{bh6(oqjrJYU8{s6WXWWfLtLHU997i!EE=Ai=^|aH(KQUN9xtLCE!#n?j>U#?<>*p z;NJBXS05WANcRg5fBu&}*K;!k(+-pw8#7N_84*>y=ljt=U}|Q*T3=kFQ-IDFH-|4H zsNIB+y}HuxPyb`O$Czy_{%X#hVLgnM(q@2Oy%7V+Z;!PMe?;vT`sx&R|w33ti9(c6H54#0pk%7A(9BmVO;k&5F3HICvc zK36lXnbdN=1)IMd?cows*KRdyz36#@9aFZO(gzuM4j7ORyqIRDSY}YsyIfdhQq-L8 zDbxGjq(+N1R1w>?yPn&SUjx6KjHE%YQZp$u(CPY#>T(HxU%j5QI?(sL8e^EM%Uz(Q z!;eZTZ{o_1S~ezsrV!!kLK)&iiTx9JL#B#7GgrOtT3NLQ_?Emkk!qca5Wz}FEmoy? zZy(sTC3{w7`z4))&VBL=w}#w`+j>6dzPR*2@xIk#M>pAUc3HY=Sx0cnh{bfJLYG3&2tIixC^8r_OjERe%4$oCCg{$*LQ2HD=g0p=qD1- zb&ebd*G}xjMtP=2FUYP`Mw;p(t1x7Wk?t1rpOiD~_@~rR_{iCJCcclg+V{DiW5-!y`SD4|vnGz?DtFS&4K6)+Hg&ZkRRsHPSDb~}kO?j*8Hha=k|Vg0{{3#@u@>vq zY1(9x$z0^J-lR;gk;nYlyZJZi*&HNFeD3TmBLUoz-cTiIB^(Za9=r1fahmiS-*uW+ zzcYL~X{JZ6Q-SGwm_$hQtrjoa*dC z`*T6^CF57U%Ue`}R2?Q-0#>`{E z{w`Fdi}?G}PibMvdyK*=xw2tt6#vl?X{mlS0;{?AstqS&L9fBPGdBo2`*7Z77Mdeb0SXpTFVz z!`qMM&hwso?&F;EIOm?{9cudi$^5X0JnttjQ_?(qYzuNqm6n%v(hkL@)jSuFzM#CW z$z7vR&R@h!Rx>^mg)Fz^vy?Rhmp4S*{x7rRr1iefKl+;IPW#He14pD&rf=Tf^#xU6R1QK0FHi>$mhKIzN1X?M)myi z!2b0MM2i^%(>~D1{RmC{oI1mnDJNIzF{JOihTQ%+uZ({@2)8^p=4k$~BdOQ0+~%u_ zTb=*m)>Y$o#P5GwU2E=Z0cP<5muZwj+JCzEhu=~1%jZmcIk}J8o^7LWxGy!-$J=VoFA5ZQt#(x$QE6_gpQwEWeaC2|d=!oC zrJDW5EWLNz`wbV3dW!4Qu5DbNpIY#p_u-9w$zU)46z03S*7-IDMxlt7s}@A-j;LwT znTj^B6Yn=DDqVBB^oQSuh%!$v1$+T2x3)a07_AqpO-14twAJktJ6?R;F7RaYEnXvu z=$4mz&z1~y6$Qn(g>m+7^PW{C#+-LV{;mxk4|pH24ST_hbo1q?WA7xx&o#z)B!T?< zPQQ7RwBl0`ehhnyV`j!BpHpp<%@?R92 ze1z<#q6n_XU>(4rU}vL|Kb6VuVH#p>TQd?Xy=*j7yk+KMeP5mCNr*=U(!>#NpTR>1 zA-;R#+tnr(bWUSFW8f-F)fUgErbn{Xw;gWs04rH-Mbdb;*^b#OAE~n4Imp}joVhow z@tUznursS*`b|jzSKp(eL1a7DLyi~S*@COZSwM~HNDdjFynY>(E-Qn>`e)U4wH>qP zB?vy8dNypv{)wzH<_bVjDa&bQv|){eaWVcI@CsQmONYuh!}DzR;h z-2kTV`r>5=uG5eCGrYi7bysV-d~Dn|oUOFYaQ60xioU*tmb7lAxRl?7CWj1{nD7~n z*AlcpBeM({V|OvPJ+CNvJGYkJ%-@zNa%*eb!gG!U-G>Zg5PJ|xFDv*&1MkjoI>pJeUdcw`5M zcgf4RSEs3^Xk>9o+q{V=VO;#^f;^ESgv6CsJu75CuPFWEfvrbPrkFlim?EO~rMf3i z;FgVnUteo?wGnrxqgmra(K1)nV>>utGo@EEtnsgEd3-dud3H%QqQJz8fQ_!d{-|%Qr2sfxnzR+E?OkmFaYvGy zWf~Q zlF3v*+?Kk(c)r^wnZ14+uh*qkIS0>JIWvDXVobS)Y!sEKeU_4~loHF4VTAB&#j7`C zO~@WTm&JEQsEcXM9nHj7RpuO&$}A)5-V3)^O^W(t66Yh33Z*z*`t0>xn`8aZMk!y~ zyzBiTp~GIIr3FhGb=#!PUcHoKJ_#kDnqHoa^xl)1XV@g`Oo;Pw@Lh&%vYJP3o{r+N zn#?-d4ZG^^j+XZF$q=wd!?c~oiz3Gf^ctieo;5SaY=mr^j~TDY(exy}C@b9SXq{;i zx2qEJ!TR^>oO|k{QU1Emub_L6gCFZ%y;Ij66n2<$7*)248I>~Z zz$5Lv`Fv5!C4uCFmn>wH?}}(Ho$wQG%lhn@Tb%ewcID7dxxjcsmly(bloSJ5h7A(L zI*6;MUQKulWpNf5uUuIAX@Xv9-K&KV5gm~z*_*{5e%!Jvl3|GCOJ%WP8}Q8nt!K+> zCVxNK7Tc<6tDvyVKCqLQ&}2WLQGJ>$c}!Yw7}%hFt09Xya%55YZ+oiM=A_?UF*r$r zNZ_Laal0-&?Pgi%-V2(ceu=M|-a<|W*~T-pr`{(WdyZ~cG5g*LcQ%y23aNFMJ#%p^ znU94MZ^d)rHZw19PPD5c$oXDxWlH^7+Lb~%RDLC2|E2BSliGGumYfXsp9WK4+KF$X zunrcgDUOwBDUYF?Yb&y!^yIUQXm-xcpMYcv95{GPj}7wXA9Aa7(re7mB$KB3kj?!_ zA7D{dZQJeNex&KJ>@mb0{v*5dVt>}EhA4J{V^p-|>Uj{3zyjHk3s5;TTA&B85uskzm=2%G(4&Gr|0m2# zfh~D=oZWI?RGpm(X|&0k6&%_42`(bJOUigqwdGYvB54{i086H}te+?Bl0DcxSJ^hl zPy!NdKd0P(TL27wb&SkJ%DJv>vXR*QZoqcY1s2t>``!~ugbzJB|6%U~na?S2^Fvl# zf}hI6`|O9TNWsH}WNHV3tI%oP9vw6PxJap5w#tQIJJl#s?-={A)Pt6Bz z_+}>`rMv$~;+dabY%y-|qUwl(_m)Q=YOj(e)jYbiR)t(8aiOZ4<&`!_x-aK=&ZW(I zJZeAV`F-g1HF9qY--@te>z%tF+=7n;uS$%TVvu21@o#_=Iw`Vo;q15c@*(f-&mBtl zsK4A(8}4|EqEKG6jRIX{`(b} zSJ1smsUPdCTGDu9!i7|OD=%`W+F60T3KSDfhO6pWcR=rh> zShI<5dG0oK@YET0a8)^F-|vD`592B@`Ly}SWhvcEj2aEzB@;)&TBFXYn%46NcsvtT z14i5CCY4=-(}aJhK8dD$fU8k3&EYdFe@42l422)b+J94UkCNH`pqYpM5s!MTCyzsf z&V$32&Wpc-LO+Z7l*IVW$ei}kU77h$xNV-pj#Reh5bgpuU9UL=6ND@IZL|bH`FlPuH0`C+;ZZ4 zj(7Dw8}ZPWvX&b#MxXNBFo&x*jR!^XSkc>>mTlH(j_iT63wAxP_`QKb=+($mx z@*_|tvie9(=3>F~kAoo-m_L-9CgPEe6uZOtB-#0e0f$^2D^l@y9)t6<-%peu+G8^; z3@;?tauBsqE$i0Zesdw6*!#Z5H`4o&ye4L)HgRe0vm9!CG36NJ@{)!KDl}2+k$Y6@ zfu-G5FG|x3>2Y#bnKHH5f3mkux=GgYZbSww?ug5 z$d^G^bF%lQE=l+hUL&U^mCdUt9V$)=zcNCf_4W)cP6u4Mj4BIaRTIf%nmBsq zOGW#>sv3pm-8}p5E+)O8MLHK&b!Quy8O0K)S%7Czw0JLmqs{__WVvc---jiNR^fmA zie^OOvLZ7OIS9gFd|SX1Vaw|yvEL|B>}@Z3UcJ9>z}H}(q=HFNv7)nr-;!g?je>-0 z@Pp*7WBe~5K{$syHh6fIf5W4N`{EItSAU6)oc=M^lDJ)eb7PgQ^QD8Ow*|1;t;9Bb zs5;K_(`HXKJUY7d$V1g&5l-(wvo*U99km8Nese80eFA6?{@A^=;hr+nG<}LwNTY_B z=!1e)XMPna&qRj_Qywm^H~H5K5dXYNoF#yW>77CBwI}G;KVU69co3V+jfOY~x`)VlA z<@i1rYM&3(`cRtuu53hKrw#EM}Z(RUf}T*SXZ9fv%G?#q8PWdJKtU*U}TN_hq>T+an3<}plWbmK*{h7Du#aB1NDj1jS%*tax~?89$id} z(j;QRQ-F4}zYpzGotoKx?%S2tf|BH9XORt)BMy0`ESKO{Tz}e-I>nIo)jFg+ zdO}1(vb9rhSeMF$-a7p;N9P%Eu>Q}ro9uo{sK6BsAi_8wV0#nNfFGO*nB+KSyJzo9 zsC7=e6UQH@s@^d4XnyA>x3e)p&GHc3%eDf*Q6-~lS7YJ+Y++rB$jdW4dbYXbTjj}x z%j%0d4R2U6r=1txA*gHu#J%ocT-lpYYi$>0Y2(;xzh*{y-6MhqPA+Rhg?G z>NxIzcrL2{ChGCjwWmObe#nJ?y76u$Vo5{#c9rY$es5_#Stul(Udx0zxrcPE81Zz* zt$;0c(vZhVxjFE~%rn98Wouf=T3TxS-q^-3}-|UETw(vMbBqZ4< zR0t|ceODSK7Z;4|Xorx>igU^Isf1&#hUGoO%`0Z3klIPU;miz%7g(`hF;dj6xWRN! z6CRm<7aU6@6`B5CSV?hz+8HNDoU~HFu-CQ>RD0GfRt=_UrA@?%ztFtIwY>e(^bW(W z3_0Q!6Df?U^>YM#x9WQ+`D3bz;ank6gs5+dp|_UENwOs^z(7OC9A3DJG(R=r!{T3; zb3I<+W$J}21EU>rGt-yEclAu14{`fxHLq)hGsN9P5_p|gMc~2K@E7I3D$2TY$ z(a$U{(qFm2wV^Lu*RIsp$H)?a>my=1oDAk?_W9g`<00Kmo)S`e! zyvqvlqHFV$p%Sb@(e%DS7}BS+AvgWK>R!=(bdB)u(%cyJsFF__aw2SN#2uV@FQl;+ z74nWt5HW}L5Rq2H2v#KULzr7p32dlC3Y)#|CBu!;-$UELCuFDot~Hstye?L53N`y} zL=QNO)%+Cr5@D`W4h!aD!W7$&`4=I!(Rodd=+HFqLr}U))y#i-U!D$Hoe+C4V&oH% z5uFtPM>Rf63wd+cWawx9ivn#Vb(Y6G^__5>a<432s>0|20`pn;L)+?}sQR3TGS%62 zgn`%SppPpHEE%p7pa#H!cP}afPQ<2Ot6(?F<^aZ-#yZCb=bbQjMHWt*z&UXsxSUW8 zX0#(H>zOexHp#W?!HD|+2o?kubt{rjV46;xn#+JbLsHTdsi&5_|GZBmZRki4t)ODe8k*`&`~;IdE~WYT)>q>v6O+Ef`IF zMRlHGj+bmIt{U1u(=s7UK0Xnh0khBq-0}>V(SyW{xaotZDNmJIV(jHCkP-aH1eHJl z%#C5DkOLZHj2a_&{hb42ehcp7()53;<!yf{SUuh*vLA^|wUj;Hlr-`f!>l z3+uNO0ZhP=5@5pfH~kz?h3z2b7chni*nTTPP!9qrYT`a>?kkVmV^7`TCc)S-c_aUx7xI56J$X zZV?t`Mcmew{Gg+r|1E-_PRx8Y@M-Fv743P zU*nI-y|eiDIW(o+fkR6G)4Zq^@;`F@bzZH~tL53xs4VKvc^7r}s{ z$8y9!pFWTy*0wEfX_1JW)Q-erOy!LTzGx z$ub;GAN6(uFV13|rNeef;>Oxx{XqNRu%AHFEF1j4kGy`;$JCvRsGqf?sk;?f*s#R^ zg9fS>QqcqBWBC>6Q{gW~VPe}mH@5Q{!iLkoH!|if`Vn9KwG)OA#{i=B5|<7F8GVY` zcWoXGv?4JA8*d?u>flu$R^$q%lR+V^i{GCc^DH(+^TCKS&Tx7uxe6xzj4(7?$kUDLf*&h8S5RjJ&;QZP8Vc#p=jT0s z(^KpGL(i}}dfi;=d=B@FVIGeyxaq%f>2f|Yg(!Wv4Pvnx_{mIv`u1KLQ)} zoOvNDOqpJz(lzYA>D(UE=Lpbghh#NNzM$Yct+ZpHh+dOR)~L)Pdda_lPLKY@L+vXG zq&@B#bC1H$!xldC-u@7LTt4A5B5U(Ca>V(hF}d+KK&TrbR2ve!60(o>8D&)A-m0f>ZCZ^Z_|P+g+b+t@$2M_(l0Tf2lwiZ7H#buG zjO(#6k4rGvNj%yns<6ZK14fo=m)@pPbGU2gv!beNWxshyhscAWM`2vRreB~yJ)f3t zKm9=BPnCLkY zl7t}R10Y{KGIYW(o@D=>Dju_`St*k062Rv1Y3|FBkhs(upHykW3q;>F%zIdtxs9kZ zEQ{;@_?h2s0c@M?XxsDPRbHe>Z|7kVvF`Va1Xs3}gU~m}>v2tHa2p^r2~l95jC}54 z@if}Np_CdD)w@l__;|G5e-x5HwjShG8qgTxfNB!-)k(W9txQ|5uCccGCQJmYqe=b|%=p$ehIIOeEcc(dmQfdf z!B5;f*-)1Z=j)xSruSVHF$EMX5%Am3H|wwGzRT-9gHnFwAJFUIWYO^ELflu>9OD3P z5u?v(-FWu`@3O3Xj8`Zv~32&|N zuQ4v)0u7X@HJ9J)BHo|YS{WPWgj57Sp_xR1fT3kY^4~SWGR`;99wqi6!I1h{&VNG` z=E~%NoH;#6t0Z?Pc%E{`8A#!SHxx<}op$DIPx2qXo-IXPzyWl{@$ir47wcinR_Nck zZb-dP44Ij(`AdQrI=D!O&wFTYe}~g}21ht5r!i$-mXf$O7c^z#V?jLk_Vl_2bz@Kg z(s>31rnu9V7iZYK-DQMNQlwnGZ>&k6P8vds81@2bTqC=HQ#%rr6!sb3ngkiE9f&V>9e~*BR*o&uLYf(V-CUAE5-s z@VTI*9ZQasq6cxbt7t$`E`+4C{wlz(;YFRx7j|gG9mW~;2i!OXIm>;rF3zymuf-W- zkwWLgw#5W75m!oJGpdR*wt&hzB-uC#z9Efs1wp3-1+odButI5WU1xlv+gFsdE8fYP zLUOVO*uynxqMLI&0nVAM@SwQ`si-!C#X$-( zR0E=~h5+#kY2E3+C~CN;*ZW|m5mL)R`M_R2U2TRFFhyg0&YmARN8re(kQQeh4!Ny7 zgxvdMR&VYPTnyQ3{0mBG({89YiM+LpdWjJ86MmAwD}+cezC!LWwX!q*KQlg-tlJ)8C{~of62K zb(q>+0Aw2&arhkStqZ*RFHydJsp2Y0q1&+Vr>0Oo$~;=L46zJaBmx2OiXj=oYa9n= zaMf!k{qS+O>D;)-I}*s#Cpmn=3x9=qXf!2E`rsJvKkZ@8mP>X>*A}(fDS63dhyQ>( zmaHs{Tq*;#F<>>{e4^JGa?`RxHBGn^$d>ll-B1xcy&u50YHN~20drci2IsKJ%tls7 zPNgHU*G3GYTkcHe0V(Qd1h9eTkgz==%U;WttZhWEBO4z=)5RoJVI-V3|s zH724}dXI<5!{yV%?6O4c!fDeK8(x+NC@&)XE(lw~ z%)ZlbyyzG6LwgF&^)c_l)s!|ksj?W>OmdQiRNaa5f`S$tOlMBE4#Lh7Lpk!(dxlvTMC=H+W`4?TKSj=O%*y!F_hZqe?D#t zKFDLyGEa`k>Ux9(gKUvk_F+=#`qd8P6~#7PF)PxZW`n&^uB*iOGK)DIqQxO=p)Rm8 zRzY#^-lIkbrY(p9G&i9%{#%tD`=>HgmdXsX{0AXtv00*x-w`RWr5iD zuK64|&gE?p>*4JPnK+yTQmvL)TiK;NM%|4Mh?Js9iFI3-44$&Kurh!PFbI-S8njl(qET0 zaot>02AI~^x74HJ@r|@BmoJ1M1d$Jr8!&6_Y1qbEqrC6BQ>*^7bENq6w-X|FQP0pY zO3bhz&qan-SpQqGi-#QBE`sj|3jvQez8xIdJB0Y=7mZ3@Tt>PdRX2jH4JdcA+(&KA z0-foxXSi(D%s>s=66JqFsdXEt&DI1O(b?qjJ<4ZiL+Up{pADdI6CMIyLXg)mQwnC7M?$8IffTLfFVcu%^OoQZ& z+DqdP07bBvMrl;E|#Ss49VFQrLy@TerXUK~TL_{3aP-@s_YVZ#z zsUn8dqoO|UhoHvcz@=W7Fbo)%TxwBaV^ zana9};+kG;71bMxw||QTsGY|LWXsAPjgrzu1By+hbdM8Q!76s5P67QCX~KC#plWw; zKKEI^;Fk*Z`S|A$%QjJe8!$uAJbtRPHpztKIdJ9msvQ1ZD zLMfFlWw$@8Qfy>5dBp{NMXX+O#pz?CR(i(?ueP=-u|8II%WXt_$3@VJR6=j$?zQ%* zzg>?*Cp0A%#W8fMw2O#lOyYsq%Hdt`jXD!6Bm<}LtDvZmIRynywBIiBVoxf=-MMK= zk4ML}qv3TEKp?KXQ=+IVOWEZMu@I?P(G~6nX_Wfnw=-|6*!=ByaIuhLWIuEFVzXpL zdKP<7XBs+$4+S1PE45@|k%uLyqgA!+lJ;F9!eq0xil z?aH@qi$_Q^k9~WK8Yf7WT$KvIMYSHbPAvCGICGWPV%=yKya; z=P>5C?ta%ADFy2_QFrl;2VVt@>|K zv{M1ibp%diFiuY^(}sIbTj1Ki6In)>z=EaZh~RxhUn@#tN4skagUToLcvRb?r8H{f zGM74kY3W2;W2{HO2!F{F&)@^KI4ABE$`Lg;w<^U@g-mX8NYUrTiw--L8vFjSW(v=b zT}WL)R&bR$i-gAO;WJ75PzoNia=`=;5NOQZxgLo$YQ)W0426Q$wZze+=Ze5B6wxuh zz-u}`uF7#qp}8N@L`_I!{i5_A!W%9I?9kOwx72LRqx*a=zS;!1MQ#r?4#TtF`o%oh z9G%c!l=q<^JOSlk_EcZ4(v$-n!BW^Dv*e^GcY~nJP!jFy$SSAnL?+)O}&@eUdO4{48P8A2sZ`$P9g# zRpIpX9cr9)x&{;#e2-=2=JpG}(Oe}vXCg9k$rGKM%O7L*=^c^_IoDuWO$)mDSuv&C zU`ALwYUHBM!Yg%Gq1G|i0KF`K8f}Y|sP~N;Ln5ip$TgJg9Er$4O@OTS$l*&9mr z&d^$bTch=>3wy!TrP2N@8S2tCd znv3U_Yc20Vt#9A}^bG{G6-!TCKq|Pe<Fv}suP>0ikm@6K=7TldUdksh>JOfESN;*Ud^jenzg@7CXW;@MYiFa`Y@Wu2rF_`_2wm%A_n1*J;qsc zSqd{9%MH16%QNdLbJLuz0_0bL31kn{*iZirhQCZdUh=7dFGB^b?VBJiu1ip*%MRXKCjP#1s7K!&xFnZbO7 zkVknoS;2JrT^9+9&0pEj88lF~g#&^&a& zzkbH%&!;p+5ZHpTwYrG`uh~H0qtCN%4iA0w4{N5l2Hy`0k9SI6T6-+E;p)tLWt6c2 z1E1~>aE~W-R)8(!3d}dj5%;1hw`J0wLzQQzeF*MdhT{sKHr%VjJz4D}mI=(}9R;pp zM+|uM8yCko%X}uIj^+ebr=%N^OP&u;olr%t0>lpZ7Qb%M+~?ep{eM2q8vE+YFr6{c zR!X4p;ScCq90sZ9UsaOlj}2`crSO2p=_h*m;a5u*pC0p1L&b7N!F7{XGg_=PqvTyQ ze}d2PQL!Po6zarl;aTR1NO*4r%oAEFKE0VzbPaGmN8uvrs)Y zToZ>^$+WXgpKbW13+G&x2dHst>=+F8B>%$ID;+D#+2YEVrdOhg7)@?U@{+ppbUNxI zU|)Rqb24Ss1&OHK38m_tL=9bHpAVU%g36TEZ}52CrENPO7oQrJRSEvEO+{TLK6>?= z=jYs<#^a_`T#mFWoE}%r${pc6CW~S7l$|?7umjs-d|1Cs9V24v#_Na 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/metadata/code/util/pseudo-lexer.py b/document/metadata/code/util/pseudo-lexer.py new file mode 100644 index 0000000000..fd3a251d5e --- /dev/null +++ b/document/metadata/code/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"(? Date: Thu, 29 Feb 2024 12:31:06 +0100 Subject: [PATCH 072/130] Update CI to build and publish code metadata spec --- .github/workflows/ci-spec.yml | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-spec.yml b/.github/workflows/ci-spec.yml index 7610b33b0c..192dfaa8a9 100644 --- a/.github/workflows/ci-spec.yml +++ b/.github/workflows/ci-spec.yml @@ -70,9 +70,28 @@ jobs: name: web-api-rendered path: document/web-api/index.html + build-code-metadata-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/metadata/code && make main + - name: Upload artifact + uses: actions/upload-artifact@v2 + with: + name: code-metadata-rendered + path: document/metadata/code/_build/html + publish-spec: runs-on: ubuntu-latest - needs: [build-core-spec, build-js-api-spec, build-web-api-spec] + needs: [build-core-spec, build-js-api-spec, build-web-api-spec, build-code-metadata-spec] steps: - name: Checkout repo uses: actions/checkout@v2 @@ -93,8 +112,13 @@ jobs: with: name: web-api-rendered path: _output/web-api + - name: Download code metadata spec artifact + uses: actions/download-artifact@v2 + with: + name: code-metadata-rendered + path: _output/metadata/code - name: Publish to GitHub Pages - if: github.ref == 'refs/heads/main' + if: github.ref == 'refs/heads/move-spec' uses: peaceiris/actions-gh-pages@v3 with: publish_dir: ./_output From 81d6ff74584e2149517349fce4f118e6152fb4cf Mon Sep 17 00:00:00 2001 From: sideshowbarker Date: Thu, 15 Feb 2024 18:07:33 +0900 Subject: [PATCH 073/130] [spec] Update katex submodule (#1726) --- document/core/util/katex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/document/core/util/katex b/document/core/util/katex index e751278cff..3d5de92fb0 160000 --- a/document/core/util/katex +++ b/document/core/util/katex @@ -1 +1 @@ -Subproject commit e751278cff42fada16dba6df331fda52aaa90f73 +Subproject commit 3d5de92fb0d0511ac64901bb60b5d46c5677eb28 From a2505108ab31481ff483d689046213f4dd8b8520 Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Fri, 22 Mar 2024 17:34:39 +0100 Subject: [PATCH 074/130] Fix crossrefs for metadata spec, deduplicate conf and macros --- document/core/appendix/custom.rst | 80 -- document/core/util/macros.def | 13 - document/metadata/code/binary.rst | 4 + document/metadata/code/conf.py | 9 +- document/metadata/code/text.rst | 3 + document/metadata/code/util/macros.def | 1339 +------------------ document/metadata/code/util/mathdef.py | 10 +- document/metadata/code/util/pseudo-lexer.py | 32 - 8 files changed, 33 insertions(+), 1457 deletions(-) delete mode 100644 document/metadata/code/util/pseudo-lexer.py diff --git a/document/core/appendix/custom.rst b/document/core/appendix/custom.rst index 9bfc7f04bb..33c9404dcf 100644 --- a/document/core/appendix/custom.rst +++ b/document/core/appendix/custom.rst @@ -239,63 +239,6 @@ It may only be placed on a declaration that declares exactly one local. \end{array} -.. index:: ! branch hints section, hint -.. _binary-branchhintsec: - -Branch Hint Section -~~~~~~~~~~~~~~~~~~~~ - -The *branch hint section* is a :ref:`custom section ` whose name string is :math:`\text{metadata.code.branch\_hint}`. -The branch hints section should appear only once in a module, and only before the :ref:`code section `. - -The purpose of this section is to aid the compilation of conditional branch instructions, by providing a hint that a branch is very likely (or unlikely) to be taken. - -The section contains a vector of *function branch hints* each representing the branch hints for a single function. - -Each *function branch hints* structure consists of - -* the :ref:`function index ` of the function the hints are referring to, -* a vector of *branch hint* for the function. - -Elements of the vector of *function branch hints* must appear in increasing function index order, -and a function index can appear at most once. - -Each *branch hint* structure consists of - -* the |U32| byte offset of the hinted instruction from the beginning of the function body, -* A |U32| with value '1', -* a |U32| indicating the meaning of the hint: - -===== =========================================== -Value Meaning -===== =========================================== - 0x00 branch likely not taken - 0x01 branch likely taken -===== =========================================== - -Elements of the vector of *branch hint* must appear in increasing byte offset order, -and a byte offset can appear at most once. A |BRIF| or |IF| instruction must be present -in the code section at the specified offset. - -.. math:: - \begin{array}{llcll} - \production{branch hint section} & \Bbranchhintsec &::=& - \Bsection_0(\Bbranchhintdata) \\ - \production{branch hint data} & \Bbranchhintdata &::=& - n{:}\Bname & (\iff n = \text{metadata.code.branch\_hint}) \\ &&& - \Bvec(\Bfuncbranchhints) \\ - \production{function branch hints} & \Bfuncbranchhints &::=& - fidx{:}\Bfuncidx~\Bvec(\Bbranchhint) \\ - \production{branch hint} & \Bbranchhint &::=& - \X{instoff}{:}\Bu32 ~~ 1{:}\Bu32 ~~ \Bbranchhintkind \\ - \production{branch hint kind} & \Bbranchhintkind &::=& - \hex{00} \\ &&|& - \hex{01} \\ - \end{array} -.. index:: ! custom annotation, custom section -.. _text-customannot: - - Custom Annotations ~~~~~~~~~~~~~~~~~~ @@ -394,26 +337,3 @@ Their relative placement will depend on the placement directive given for the :m custom section "A" custom section "D" - -.. index:: ! branch hints annotation, hint -.. _text-branchhintannot: - -Branch Hint Annotations -~~~~~~~~~~~~~~~~~~~~~~~ - -*Branch Hint annotations* are the textual analogue to the :ref:`branch hint section ` and provide a textual representation for it. -Consequently, their id is :math:`\T{@metadata.code.branch\_hint}`. - -Branch hint annotations are allowed only on |BRIF| and |IF| instructions, -and at most one branch hint annotation may be given per instruction. - -Branch hint annotations have the following format: - -.. math:: - \begin{array}{llclll} - \production{branch hint annotation} & \Tbranchhintannot &::=& - \text{(@metadata.code.branch\_hint}~\Tbranchhintstr~\text{)} \\ - \production{branch hint string} & \Tbranchhintstr &::=& - \text{"\backslash 00"} \\ &&|& - \text{"\backslash 01"} \\ - \end{array} diff --git a/document/core/util/macros.def b/document/core/util/macros.def index 75e41a4ef6..f0766cd8bf 100644 --- a/document/core/util/macros.def +++ b/document/core/util/macros.def @@ -1271,14 +1271,6 @@ .. |Bfuncnamesubsec| mathdef:: \xref{appendix/custom}{binary-funcnamesec}{\B{funcnamesubsec}} .. |Blocalnamesubsec| mathdef:: \xref{appendix/custom}{binary-localnamesec}{\B{localnamesubsec}} -.. Branch Hints Section, non-terminals - -.. |Bbranchhintsec| mathdef:: \xref{appendix/custom}{binary-branchhintsec}{\B{branchhintsec}} -.. |Bbranchhintdata| mathdef:: \xref{appendix/custom}{binary-branchhintsec}{\B{branchhintdata}} -.. |Bfuncbranchhints| mathdef:: \xref{appendix/custom}{binary-branchhintssec}{\B{funcbranchhints}} -.. |Bbranchhint| mathdef:: \xref{appendix/custom}{binary-branchhintsec}{\B{branchhint}} -.. |Bbranchhintkind| mathdef:: \xref{appendix/custom}{binary-branchhintsec}{\B{branchhintkind}} - .. Annotations .. ----------- @@ -1297,11 +1289,6 @@ .. |Tparamnameannot| mathdef:: \xref{appendix/custom}{text-paramnameannot}{\T{paramnameannot}} .. |Tlocalnameannot| mathdef:: \xref{appendix/custom}{text-localnameannot}{\T{localnameannot}} -.. Branch Hint annotations, non-terminals - -.. |Tbranchhintannot| mathdef:: \xref{appendix/custom}{text-branchhintannot}{\T{branchhintannot}} -.. |Tbranchhintstr| mathdef:: \xref{appendix/custom}{text-branchhintannot}{\T{branchhintstr}} - .. Embedding .. --------- diff --git a/document/metadata/code/binary.rst b/document/metadata/code/binary.rst index 05cc2cb7e8..8b381e8df5 100644 --- a/document/metadata/code/binary.rst +++ b/document/metadata/code/binary.rst @@ -3,6 +3,8 @@ Binary Format ============= +.. _binary-codemetadata: + Code Metadata ------------- @@ -30,6 +32,8 @@ Where *funcpos* is the byte offset of the annotation starting from the beginning *code metadata function* entries must appear in order of increasing *function id*, and duplicate id values are not allowed. *code metadata item* entries must appear in order of increasing *instruction offset*, and duplicate offset values are not allowed. +.. _binary-branchhints: + Branch Hints ~~~~~~~~~~~~ diff --git a/document/metadata/code/conf.py b/document/metadata/code/conf.py index f72fefdc73..debd8455d3 100644 --- a/document/metadata/code/conf.py +++ b/document/metadata/code/conf.py @@ -19,6 +19,8 @@ import sys from datetime import date +core_dir = os.path.abspath('../../core') +sys.path.insert(0, core_dir) pwd = os.path.abspath('.') sys.path.insert(0, pwd) @@ -294,7 +296,7 @@ # Additional stuff for the LaTeX preamble. # Don't type-set cross references with emphasis. - 'preamble': '\\renewcommand\\sphinxcrossref[1]{#1}\n', + 'preamble': '\\renewcommand\\sphinxcrossref[1]{#1}\n\\externaldocument[Core-]{'+core_dir+'/_build/latex/WebAssembly}[https://webassembly.github.io//'+repo+'/core/_download/WebAssembly.pdf]\n', # Latex figure (float) alignment 'figure_align': 'htbp', @@ -303,7 +305,9 @@ 'fncychap': '\\usepackage[Sonny]{fncychap}', # Allow chapters to start on even pages - 'extraclassoptions': 'openany' + 'extraclassoptions': 'openany', + + 'extrapackages': '\\usepackage{xr-hyper}', } # Grouping the document tree into LaTeX files. List of tuples @@ -489,6 +493,7 @@ rst_prolog = """ .. |issuelink| replace:: https://github.com/webassembly/""" + repo + """/issues/ .. |pagelink| replace:: https://webassembly.github.io/""" + repo + """/core/ +.. include:: /""" + core_dir + """/util/macros.def .. include:: /""" + pwd + """/util/macros.def """ diff --git a/document/metadata/code/text.rst b/document/metadata/code/text.rst index ba7da48218..4bf2e02875 100644 --- a/document/metadata/code/text.rst +++ b/document/metadata/code/text.rst @@ -3,6 +3,8 @@ Text Format =========== +.. _text-codemetadata: + Code Metadata ------------- @@ -15,6 +17,7 @@ attached to the first instruction that follows them. \production{code metadata annotation} & \Tcodemetadataannot(\B{T}) &::=& \text{(@metadata.code.T}~\X{data}{:}\B{T}~\text{)} \\ \end{array} +.. index:: ! code metadata annotation Where `T` is the type of the item, and `data` is a byte string containing the same payload as in the binary format. diff --git a/document/metadata/code/util/macros.def b/document/metadata/code/util/macros.def index 80d87d5067..ffebbdab8d 100644 --- a/document/metadata/code/util/macros.def +++ b/document/metadata/code/util/macros.def @@ -3,1357 +3,40 @@ .. 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 +.. Code Metadata, non-terminals -.. |utf8| mathdef:: \xref{binary/values}{binary-utf8}{\F{utf8}} +.. |Bcodemetadatasec| mathdef:: \xref{binary}{binary-codemetada}{\B{codemetadatasec}} +.. |Bcodemetadata| mathdef:: \xref{binary}{binary-codemetada}{\B{codemetada}} +.. |Bcodemetadatafunc| mathdef:: \xref{binary}{binary-codemetada}{\B{codemetadafunc}} +.. |Bcodemetadataitem| mathdef:: \xref{binary}{binary-codemetada}{\B{codemetadataitem}} +.. Branch Hints, non-terminals -.. 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}} +.. |Bbranchhintsec| mathdef:: \xref{binary}{binary-branchhints}{\B{branchhintsec}} +.. |Bbranchhint| mathdef:: \xref{binary}{binary-branchhints}{\B{branchhint}} .. 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}} - - -.. Metadata -.. -------- - -.. Code Metadata sections, non-terminals + \production{code metadata annotation} & \Tcodemetadataannot(\B{T}) &::=& -.. |Bcodemetadatasec| mathdef:: \xref{appendix/custom}{binary-branchhintsec}{\B{codemetadatasec}} -.. |Bcodemetadata| mathdef:: \xref{appendix/custom}{binary-branchhintsec}{\B{codemetadata}} -.. |Bcodemetadatafunc| mathdef:: \xref{appendix/custom}{binary-branchhintssec}{\B{codemetadatafunc}} -.. |Bcodemetadataitem| mathdef:: \xref{appendix/custom}{binary-branchhintsec}{\B{codemetadataitem}} -.. |Bbranchhintsec| mathdef:: \xref{appendix/custom}{binary-branchhintsec}{\B{branchhintsec}} -.. |Bbranchhint| mathdef:: \xref{appendix/custom}{binary-branchhintsec}{\B{branch\_hint}} +.. Branch Hints, non-terminals -.. Code Metadata annotations, non-terminals +.. |Tcodemetadataannot| mathdef:: \xref{text}{text-codemetadata}{\T{codemetadataannot}} -.. |Tcodemetadataannot| mathdef:: \xref{appendix/custom}{text-branchhintannot}{\T{codemetadataannot}} diff --git a/document/metadata/code/util/mathdef.py b/document/metadata/code/util/mathdef.py index a10fc458ff..57a6cf043d 100644 --- a/document/metadata/code/util/mathdef.py +++ b/document/metadata/code/util/mathdef.py @@ -14,7 +14,10 @@ xref_re = re.compile('\\\\xref\{([^}]*)\}\{([^}]*)\}', re.M) def html_hyperlink(file, id): - return '\\href{../%s.html#%s}' % (file, id.replace('_', '-')) + if "/" in file: + return '\\href{../../core/%s.html#%s}' % (file, id.replace('_', '-')) + else: + 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()) @@ -25,7 +28,10 @@ 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) + if "/" in file: + return '\\hyperref[Core-%s:%s]' % (file, id) + else: + 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()) diff --git a/document/metadata/code/util/pseudo-lexer.py b/document/metadata/code/util/pseudo-lexer.py deleted file mode 100644 index fd3a251d5e..0000000000 --- a/document/metadata/code/util/pseudo-lexer.py +++ /dev/null @@ -1,32 +0,0 @@ -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"(? Date: Mon, 25 Mar 2024 16:54:50 +0100 Subject: [PATCH 075/130] Disable the bikeshed build for metadata.code --- document/metadata/code/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/document/metadata/code/Makefile b/document/metadata/code/Makefile index 9146ee74db..21d52d4818 100644 --- a/document/metadata/code/Makefile +++ b/document/metadata/code/Makefile @@ -72,10 +72,10 @@ deploy: publish: clean all deploy .PHONY: publish-main -publish-main: clean main bikeshed-keep deploy +publish-main: clean main deploy .PHONY: all -all: pdf html bikeshed +all: pdf html .PHONY: main main: pdf html From 9d3d01ec73d1724207ebd1880dc561c27fd29537 Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Mon, 25 Mar 2024 16:57:09 +0100 Subject: [PATCH 076/130] metadata.code: rename type->format --- document/metadata/code/binary.rst | 8 ++++---- document/metadata/code/intro.rst | 2 +- document/metadata/code/syntax.rst | 4 ++-- document/metadata/code/text.rst | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/document/metadata/code/binary.rst b/document/metadata/code/binary.rst index 8b381e8df5..b7980a037e 100644 --- a/document/metadata/code/binary.rst +++ b/document/metadata/code/binary.rst @@ -8,10 +8,10 @@ Binary Format Code Metadata ------------- -All code metadata items of a given type *T* are grouped under a custom section +All code metadata items of a given format *T* are grouped under a custom section named *'metadata.code.T'*. The following parametrized grammar rules define the generic structure of a code metadata -section of type *T*. +section of format *T*. .. math:: \begin{array}{llcll} @@ -28,7 +28,7 @@ section of type *T*. \end{array} .. index:: ! code metadata section -Where *funcpos* is the byte offset of the annotation starting from the beginning of the function body, and *data* is a further payload, whose content depends on the type *T*. +Where *funcpos* is the byte offset of the annotation starting from the beginning of the function body, and *data* is a further payload, whose content depends on the format *T*. *code metadata function* entries must appear in order of increasing *function id*, and duplicate id values are not allowed. *code metadata item* entries must appear in order of increasing *instruction offset*, and duplicate offset values are not allowed. @@ -37,7 +37,7 @@ Where *funcpos* is the byte offset of the annotation starting from the beginning Branch Hints ~~~~~~~~~~~~ -A Branch Hint is code metadata item with type *branch_hint*. +A Branch Hint is code metadata item with format *branch_hint*. All branch hints for a module are contained in a single code metadata section with name *'metadata.code.branch_hint'*. diff --git a/document/metadata/code/intro.rst b/document/metadata/code/intro.rst index 2143e5fe78..7d732b78a8 100644 --- a/document/metadata/code/intro.rst +++ b/document/metadata/code/intro.rst @@ -4,7 +4,7 @@ Introduction ============ This document defines a generic mechanism for attaching arbitrary metadata to WebAssembly instructions. -Additionally, it defines specific metadata types using this mechanism. +Additionally, it defines specific metadata formats using this mechanism. Such metadata do not contribute to, or otherwise affect, the WebAssembly semantics, and may be ignored by an implementation. diff --git a/document/metadata/code/syntax.rst b/document/metadata/code/syntax.rst index 3a2e690d0b..9836119156 100644 --- a/document/metadata/code/syntax.rst +++ b/document/metadata/code/syntax.rst @@ -8,14 +8,14 @@ Code Metadata A Code Metadata item is a piece of information logically attached to an instruction. -An item has a type and a paylod, whose format is defined by its type. +An item is associated with a format, which defines the item's payload. TODO: can this be expressed with the math notation? Branch Hints ~~~~~~~~~~~~ -A Branch Hint is a type of Code Metadata that can be attached to `br_if` and `if` instructions. +A Branch Hint is a Code Metadata format that can be attached to `br_if` and `if` instructions. Its payload indicates whether the branch is likely or unlikely to be taken. TODO: math definition diff --git a/document/metadata/code/text.rst b/document/metadata/code/text.rst index 4bf2e02875..701fea4db0 100644 --- a/document/metadata/code/text.rst +++ b/document/metadata/code/text.rst @@ -19,6 +19,6 @@ attached to the first instruction that follows them. \end{array} .. index:: ! code metadata annotation -Where `T` is the type of the item, and `data` is a byte string containing the same +Where `T` is the format of the item, and `data` is a byte string containing the same payload as in the binary format. From 4d79f0248f6731f2af57871c992b567961de7dbd Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Mon, 25 Mar 2024 17:43:21 +0100 Subject: [PATCH 077/130] metadata/code: Add explicit dependency on core spec latex build for aux file --- .github/workflows/ci-spec.yml | 1 + document/metadata/code/Makefile | 13 ++++++++++--- document/metadata/code/conf.py | 2 +- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-spec.yml b/.github/workflows/ci-spec.yml index 192dfaa8a9..fe2f7199f6 100644 --- a/.github/workflows/ci-spec.yml +++ b/.github/workflows/ci-spec.yml @@ -72,6 +72,7 @@ jobs: build-code-metadata-spec: runs-on: ubuntu-latest + needs: [build-core-spec] steps: - name: Checkout repo uses: actions/checkout@v2 diff --git a/document/metadata/code/Makefile b/document/metadata/code/Makefile index 21d52d4818..e8b975c727 100644 --- a/document/metadata/code/Makefile +++ b/document/metadata/code/Makefile @@ -255,8 +255,15 @@ epub3: @echo @echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3." + +.PHONY: latex-core-aux +latex-core-aux: + (cd ../../core; make BUILDDIR=$(BUILDDIR) latexpdf) + mkdir -p $(BUILDDIR)/latex + cp ../../core/$(BUILDDIR)/latex/WebAssembly.aux $(BUILDDIR)/latex/ + .PHONY: latex -latex: +latex: latex-core-aux $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @@ -264,14 +271,14 @@ latex: "(use \`make latexpdf' here to do that automatically)." .PHONY: latexpdf -latexpdf: +latexpdf: latex-core-aux $(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: +latexpdfja: latex-core-aux $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through platex and dvipdfmx..." $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja diff --git a/document/metadata/code/conf.py b/document/metadata/code/conf.py index debd8455d3..7861f72c02 100644 --- a/document/metadata/code/conf.py +++ b/document/metadata/code/conf.py @@ -296,7 +296,7 @@ # Additional stuff for the LaTeX preamble. # Don't type-set cross references with emphasis. - 'preamble': '\\renewcommand\\sphinxcrossref[1]{#1}\n\\externaldocument[Core-]{'+core_dir+'/_build/latex/WebAssembly}[https://webassembly.github.io//'+repo+'/core/_download/WebAssembly.pdf]\n', + 'preamble': '\\renewcommand\\sphinxcrossref[1]{#1}\n\\externaldocument[Core-]{WebAssembly}[https://webassembly.github.io//'+repo+'/core/_download/WebAssembly.pdf]\n', # Latex figure (float) alignment 'figure_align': 'htbp', From 64c6799b1276e5a767a58a282928bf23da879dce Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Tue, 26 Mar 2024 14:52:19 +0100 Subject: [PATCH 078/130] metadata/code: Mention dependency on core spec in the introduction --- document/metadata/code/intro.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/document/metadata/code/intro.rst b/document/metadata/code/intro.rst index 7d732b78a8..247ef71ea3 100644 --- a/document/metadata/code/intro.rst +++ b/document/metadata/code/intro.rst @@ -10,3 +10,9 @@ Such metadata do not contribute to, or otherwise affect, the WebAssembly semanti However, it can provides useful information that implementations can make use of to improve user experience or take compilation hints. +Dependencies +~~~~~~~~~~~~ + +This document is based on the WebAssembly core specification (|WasmDraft|), and makes use of +terms and definitions described there. These uses always link to the corresponding definition +in the core specification. From 1a2f8bffd597edb43e4bc9c057ab81dfb399a668 Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Wed, 27 Mar 2024 14:26:55 +0100 Subject: [PATCH 079/130] metadata/code: fixes to spec document --- document/metadata/code/binary.rst | 14 +++++++++----- document/metadata/code/conf.py | 2 +- document/metadata/code/index.rst | 2 +- document/metadata/code/intro.rst | 2 +- document/metadata/code/text.rst | 2 +- document/metadata/code/util/macros.def | 10 ++++++---- 6 files changed, 19 insertions(+), 13 deletions(-) diff --git a/document/metadata/code/binary.rst b/document/metadata/code/binary.rst index b7980a037e..6e402b456c 100644 --- a/document/metadata/code/binary.rst +++ b/document/metadata/code/binary.rst @@ -8,7 +8,7 @@ Binary Format Code Metadata ------------- -All code metadata items of a given format *T* are grouped under a custom section +All code metadata items of a format named *T* are grouped under a custom section named *'metadata.code.T'*. The following parametrized grammar rules define the generic structure of a code metadata section of format *T*. @@ -21,14 +21,14 @@ section of format *T*. n{:}\Bname & (\iff n = \text{metadata.code.T}) \\ &&& \Bvec(\Bcodemetadatafunc(\B{T})) \\ \production{code metadata function} & \Bcodemetadatafunc(\B{T}) &::=& - fidx{:}\Bfuncidx~\Bvec(\Bcodemetadataitem(\B{T})) \\ + x{:}\Bfuncidx~\Bvec(\Bcodemetadataitem(\B{T})) \\ \production{code metadata item} & \Bcodemetadataitem(\B{T}) &::=& - \X{instoff}{:}\Bu32 ~~ \X{size}{:}\Bu32 & (\iff \X{size} = ||\B{T}||) \\ &&& + \X{off}{:}\Bu32 ~~ \X{size}{:}\Bu32 & (\iff \X{size} = ||\B{T}||) \\ &&& \X{data}{:}\B{T} \\ \end{array} .. index:: ! code metadata section -Where *funcpos* is the byte offset of the annotation starting from the beginning of the function body, and *data* is a further payload, whose content depends on the format *T*. +Where :math:`\X{off}` is the byte offset of the annotation starting from the beginning of the function body, and :math:`\X{data}` is a further payload, whose content depends on the format :math:`T`. *code metadata function* entries must appear in order of increasing *function id*, and duplicate id values are not allowed. *code metadata item* entries must appear in order of increasing *instruction offset*, and duplicate offset values are not allowed. @@ -46,7 +46,11 @@ with name *'metadata.code.branch_hint'*. \production{branch hint section} & \Bbranchhintsec &::=& \Bcodemetadatasec(\Bbranchhint) \\ \production{branch hint} & \Bbranchhint &::=& - \hex{00} \\ &&|& + \Bunlikely \\ &&|& + \Blikely \\ + \production{unlikely} & \Bunlikely &::=& + \hex{00} \\ + \production{likely} & \Blikely &::=& \hex{01} \\ \end{array} .. index:: ! branch hint section diff --git a/document/metadata/code/conf.py b/document/metadata/code/conf.py index 7861f72c02..bff6550b48 100644 --- a/document/metadata/code/conf.py +++ b/document/metadata/code/conf.py @@ -64,7 +64,7 @@ title = u'WebAssembly Code Metadata Specification' copyright = u'2024, WebAssembly Community Group' author = u'WebAssembly Community Group' -editor = u'Andreas Rossberg (editor)' +editor = u'Yuri Iozzelli (editor)' logo = 'static/webassembly.png' # The name of the GitHub repository this resides in diff --git a/document/metadata/code/index.rst b/document/metadata/code/index.rst index e8a0c3cad1..8cd099942b 100644 --- a/document/metadata/code/index.rst +++ b/document/metadata/code/index.rst @@ -3,7 +3,7 @@ WebAssembly Code Metadata .. only:: html - | Editor: Andreas Rossberg + | Editor: Yuri Iozzelli | Issue Tracker: |WasmIssues| diff --git a/document/metadata/code/intro.rst b/document/metadata/code/intro.rst index 247ef71ea3..59503b413e 100644 --- a/document/metadata/code/intro.rst +++ b/document/metadata/code/intro.rst @@ -6,7 +6,7 @@ Introduction This document defines a generic mechanism for attaching arbitrary metadata to WebAssembly instructions. Additionally, it defines specific metadata formats using this mechanism. -Such metadata do not contribute to, or otherwise affect, the WebAssembly semantics, and may be ignored by an implementation. +Such metadata does not contribute to, or otherwise affect, the WebAssembly semantics, and may be ignored by an implementation. However, it can provides useful information that implementations can make use of to improve user experience or take compilation hints. diff --git a/document/metadata/code/text.rst b/document/metadata/code/text.rst index 701fea4db0..c5ff1fbd04 100644 --- a/document/metadata/code/text.rst +++ b/document/metadata/code/text.rst @@ -19,6 +19,6 @@ attached to the first instruction that follows them. \end{array} .. index:: ! code metadata annotation -Where `T` is the format of the item, and `data` is a byte string containing the same +Where `T` is the format name of the item, and `data` is a byte string containing the same payload as in the binary format. diff --git a/document/metadata/code/util/macros.def b/document/metadata/code/util/macros.def index ffebbdab8d..3b8321c1b6 100644 --- a/document/metadata/code/util/macros.def +++ b/document/metadata/code/util/macros.def @@ -20,15 +20,17 @@ .. Code Metadata, non-terminals -.. |Bcodemetadatasec| mathdef:: \xref{binary}{binary-codemetada}{\B{codemetadatasec}} -.. |Bcodemetadata| mathdef:: \xref{binary}{binary-codemetada}{\B{codemetada}} -.. |Bcodemetadatafunc| mathdef:: \xref{binary}{binary-codemetada}{\B{codemetadafunc}} -.. |Bcodemetadataitem| mathdef:: \xref{binary}{binary-codemetada}{\B{codemetadataitem}} +.. |Bcodemetadatasec| mathdef:: \xref{binary}{binary-codemetadata}{\B{codemetadatasec}} +.. |Bcodemetadata| mathdef:: \xref{binary}{binary-codemetadata}{\B{codemetada}} +.. |Bcodemetadatafunc| mathdef:: \xref{binary}{binary-codemetadata}{\B{codemetadafunc}} +.. |Bcodemetadataitem| mathdef:: \xref{binary}{binary-codemetadata}{\B{codemetadataitem}} .. Branch Hints, non-terminals .. |Bbranchhintsec| mathdef:: \xref{binary}{binary-branchhints}{\B{branchhintsec}} .. |Bbranchhint| mathdef:: \xref{binary}{binary-branchhints}{\B{branchhint}} +.. |Bunlikely| mathdef:: \xref{binary}{binary-branchhints}{\B{unlikely}} +.. |Blikely| mathdef:: \xref{binary}{binary-branchhints}{\B{likely}} .. Text Format From 71581502fcc59e22b55a67abb9700b64a34d0a10 Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Thu, 28 Mar 2024 14:48:28 +0100 Subject: [PATCH 080/130] metadata/code: remove syntax section and integrate with the binary section --- document/metadata/code/binary.rst | 16 ++++++++++++++-- document/metadata/code/index.rst | 1 - document/metadata/code/syntax.rst | 22 ---------------------- 3 files changed, 14 insertions(+), 25 deletions(-) delete mode 100644 document/metadata/code/syntax.rst diff --git a/document/metadata/code/binary.rst b/document/metadata/code/binary.rst index 6e402b456c..609cd401b5 100644 --- a/document/metadata/code/binary.rst +++ b/document/metadata/code/binary.rst @@ -8,6 +8,10 @@ Binary Format Code Metadata ------------- +A Code Metadata item is a piece of information logically attached to an instruction. + +An item is associated with a format, which defines the item's payload. + All code metadata items of a format named *T* are grouped under a custom section named *'metadata.code.T'*. The following parametrized grammar rules define the generic structure of a code metadata @@ -30,14 +34,19 @@ section of format *T*. Where :math:`\X{off}` is the byte offset of the annotation starting from the beginning of the function body, and :math:`\X{data}` is a further payload, whose content depends on the format :math:`T`. -*code metadata function* entries must appear in order of increasing *function id*, and duplicate id values are not allowed. *code metadata item* entries must appear in order of increasing *instruction offset*, and duplicate offset values are not allowed. +|Bcodemetadatafunc| entries must appear in order of increasing :math:`x`, and duplicate id values are not allowed. |Bcodemetadata| entries must appear in order of increasing :math:`\X{off}`, and duplicate offset values are not allowed. .. _binary-branchhints: Branch Hints ~~~~~~~~~~~~ -A Branch Hint is code metadata item with format *branch_hint*. +A Branch Hint is a code metadata item with format *branch_hint*. + +It can only be attached to |BRIF| and |IF| instructions. + +Its payload indicates whether the branch is likely or unlikely to be taken. + All branch hints for a module are contained in a single code metadata section with name *'metadata.code.branch_hint'*. @@ -55,3 +64,6 @@ with name *'metadata.code.branch_hint'*. \end{array} .. index:: ! branch hint section +A value of |Blikely| means that the branch is likely to be taken, while a +value of |Bunlikely| means the opposite. A branch with no hints is considered +equally likely to be taken or not. diff --git a/document/metadata/code/index.rst b/document/metadata/code/index.rst index 8cd099942b..7485244829 100644 --- a/document/metadata/code/index.rst +++ b/document/metadata/code/index.rst @@ -11,6 +11,5 @@ WebAssembly Code Metadata :maxdepth: 1 intro - syntax binary text diff --git a/document/metadata/code/syntax.rst b/document/metadata/code/syntax.rst deleted file mode 100644 index 9836119156..0000000000 --- a/document/metadata/code/syntax.rst +++ /dev/null @@ -1,22 +0,0 @@ -.. _syntax: - -Structure -========= - -Code Metadata -------------- - -A Code Metadata item is a piece of information logically attached to an instruction. - -An item is associated with a format, which defines the item's payload. - -TODO: can this be expressed with the math notation? - -Branch Hints -~~~~~~~~~~~~ - -A Branch Hint is a Code Metadata format that can be attached to `br_if` and `if` instructions. -Its payload indicates whether the branch is likely or unlikely to be taken. - -TODO: math definition - From 8d24dbf0b8d8cb14502f90d836d8ddc8c7a09688 Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Tue, 9 Apr 2024 10:50:53 +0200 Subject: [PATCH 081/130] branch hinting: reword the byte offset description "function body" is unclear, and actually at odds with the definition in the core spec. The byte offset is relative to the start of the locals vector --- document/metadata/code/binary.rst | 2 +- proposals/branch-hinting/Overview.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/document/metadata/code/binary.rst b/document/metadata/code/binary.rst index 609cd401b5..1b17265513 100644 --- a/document/metadata/code/binary.rst +++ b/document/metadata/code/binary.rst @@ -32,7 +32,7 @@ section of format *T*. \end{array} .. index:: ! code metadata section -Where :math:`\X{off}` is the byte offset of the annotation starting from the beginning of the function body, and :math:`\X{data}` is a further payload, whose content depends on the format :math:`T`. +Where :math:`\X{off}` is the byte offset of the attached instruction, relative to the beginning of the |Bfunc| declaration, and :math:`\X{data}` is a further payload, whose content depends on the format :math:`T`. |Bcodemetadatafunc| entries must appear in order of increasing :math:`x`, and duplicate id values are not allowed. |Bcodemetadata| entries must appear in order of increasing :math:`\X{off}`, and duplicate offset values are not allowed. diff --git a/proposals/branch-hinting/Overview.md b/proposals/branch-hinting/Overview.md index 923b174be4..dedd4b4c8c 100644 --- a/proposals/branch-hinting/Overview.md +++ b/proposals/branch-hinting/Overview.md @@ -100,7 +100,7 @@ and a function index can appear at most once. Each *branch hint* structure consists of -* the |U32| byte offset of the hinted instruction from the beginning of the function body, +* the |U32| byte offset of the hinted instruction, relative to the beginning of the function locals declaration, * A |U32| with value `1`, * a |U32| indicating the meaning of the hint: From 82b031a3d59a371c06d50914a9532d56375107f5 Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Tue, 9 Apr 2024 18:47:26 +0200 Subject: [PATCH 082/130] restore publishing of main branch to gh pages --- .github/workflows/ci-spec.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-spec.yml b/.github/workflows/ci-spec.yml index fe2f7199f6..bb02ee4ce0 100644 --- a/.github/workflows/ci-spec.yml +++ b/.github/workflows/ci-spec.yml @@ -119,7 +119,7 @@ jobs: name: code-metadata-rendered path: _output/metadata/code - name: Publish to GitHub Pages - if: github.ref == 'refs/heads/move-spec' + if: github.ref == 'refs/heads/main' uses: peaceiris/actions-gh-pages@v3 with: publish_dir: ./_output From a76bb8fb7352668d52d0f60fef61085043c9b9f4 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Wed, 10 Apr 2024 14:38:32 +0200 Subject: [PATCH 083/130] Simplify hack --- interpreter/text/parse.ml | 10 +--------- interpreter/text/parser.mly | 16 ++++++---------- 2 files changed, 7 insertions(+), 19 deletions(-) diff --git a/interpreter/text/parse.ml b/interpreter/text/parse.ml index 452614aaca..986f44dddb 100644 --- a/interpreter/text/parse.ml +++ b/interpreter/text/parse.ml @@ -24,12 +24,6 @@ let wrap_lexbuf lexbuf = Annot.extend_source (Bytes.sub_string lexbuf.lex_buffer lexbuf.lex_start_pos n); {lexbuf with refill_buff} -let provider lexbuf () = - let tok = Lexer.token lexbuf in - let start = Lexing.lexeme_start_p lexbuf in - let stop = Lexing.lexeme_end_p lexbuf in - tok, start, stop - let convert_pos lexbuf = { Source.left = Lexer.convert_pos lexbuf.Lexing.lex_start_p; Source.right = Lexer.convert_pos lexbuf.Lexing.lex_curr_p @@ -43,10 +37,8 @@ let make (type a) (start : _ -> _ -> a) : (module S with type t = a) = Annot.reset (); Lexing.set_filename lexbuf name; let lexbuf = wrap_lexbuf lexbuf in - let prov = provider lexbuf in let result = - try MenhirLib.Convert.Simplified.traditional2revised start prov - with Parser.Error -> + try start Lexer.token lexbuf with Parser.Error -> raise (Syntax (convert_pos lexbuf, "unexpected token")) in let annots = Annot.get_all () in diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly index 34b9140237..48731201eb 100644 --- a/interpreter/text/parser.mly +++ b/interpreter/text/parser.mly @@ -1009,21 +1009,17 @@ module_ : $3, Textual (m, parse_annots m) @@ $sloc } inline_module : /* Sugar */ - | module_fields EOF + | module_fields { let m = $1 (empty_context ()) () @@ $sloc in (* Hack to handle annotations before first and after last token *) - (* Note: need EOF token here, since Menhir delivers a location - * with empty filename for $1 in case module_fields is empty! *) - let all = all_region (at $loc($2)).left.file in + let all = all_region (at $sloc).left.file in Textual (m, parse_annots Source.(m.it @@ all)) @@ $sloc } inline_module1 : /* Sugar */ - | module_fields1 EOF + | module_fields1 { let m = $1 (empty_context ()) () @@ $sloc in (* Hack to handle annotations before first and after last token *) - (* Note: need EOF token here, since Menhir delivers a location - * with empty filename for $1 in case module_fields is empty! *) - let all = all_region (at $loc($2)).left.file in + let all = all_region (at $sloc).left.file in Textual (m, parse_annots Source.(m.it @@ all)) @@ $sloc } @@ -1110,12 +1106,12 @@ result : script : | list(cmd) EOF { $1 } - | inline_module1 { [Module (None, $1) @@ $sloc] } /* Sugar */ + | inline_module1 EOF { [Module (None, $1) @@ $sloc] } /* Sugar */ script1 : | cmd { [$1] } module1 : | module_ EOF { $1 } - | inline_module { None, $1 } /* Sugar */ + | inline_module EOF { None, $1 } /* Sugar */ %% From 534bf803a7de0c9343c6bf0fdcf47f77027216cb Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Wed, 10 Apr 2024 14:41:57 +0200 Subject: [PATCH 084/130] Fix CI --- interpreter/jslib/wast.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interpreter/jslib/wast.ml b/interpreter/jslib/wast.ml index ba75ad9811..266eab1000 100644 --- a/interpreter/jslib/wast.ml +++ b/interpreter/jslib/wast.ml @@ -13,7 +13,7 @@ let () = let bs = match def.Source.it with | Script.Textual (m, cs) -> Encode.encode_with_custom (m, cs) - | Script.Encoded (_, bs) -> bs + | Script.Encoded (_, bs) -> bs.Source.it | Script.Quoted (_, _) -> failwith "Unsupported" in let buf = new%js Typed_array.arrayBuffer (String.length bs) in let u8arr = new%js Typed_array.uint8Array_fromBuffer buf in From c97651fb6fe4bebab70581bcbe6a6bddb8f067cf Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Thu, 11 Apr 2024 11:17:41 -0700 Subject: [PATCH 085/130] Update JS API for exnref (#301) This change updates exception object allocation, initialization, and construction for exnref; as well as dealing with exception propagation from invoking exported functions; throwing exceptions from host functions into wasm; and wrapping and unwrapping JS exceptions as they propagate into and out of wasm. --- document/js-api/index.bs | 129 +++++++++++++++++++++++---------------- 1 file changed, 75 insertions(+), 54 deletions(-) diff --git a/document/js-api/index.bs b/document/js-api/index.bs index 1519c04948..ba25a4cc56 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -64,6 +64,7 @@ urlPrefix: https://webassembly.github.io/exception-handling/core/; spec: WebAsse text: ref.null text: ref.func text: ref.extern + text: ref.exn text: function index; url: syntax/modules.html#syntax-funcidx text: function instance; url: exec/runtime.html#function-instances text: store_init; url: appendix/embedding.html#embed-store-init @@ -101,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 @@ -145,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 @@ -238,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

@@ -760,7 +770,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. @@ -807,7 +817,7 @@ Each {{Table}} object has a \[[Table]] internal slot, which is a [=table address 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. 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|). @@ -819,7 +829,7 @@ Each {{Table}} object has a \[[Table]] internal slot, which is a [=table address 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. Throw a {{TypeError}} exception. 1. If |value| is missing, 1. Let |ref| be [=DefaultValue=](|elementType|). 1. Otherwise, @@ -1011,15 +1021,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]). @@ -1048,7 +1059,7 @@ Note: Exported Functions do not have a \[[Construct]] method and thus it is not 1. Otherwise, if |resultsSize| is 1, return « [=?=] [=ToWebAssemblyValue=](|ret|, |results|[0]) ». 1. Otherwise, 1. Let |method| be [=?=] [$GetMethod$](|ret|, {{@@iterator}}). - 1. If |method| is undefined, [=throw=] a {{TypeError}}. + 1. If |method| is undefined, throw a {{TypeError}}. 1. Let |values| be [=?=] [$IterableToList$](|ret|, |method|). 1. Let |wasmValues| be a new, empty [=list=]. 1. If |values|'s [=list/size=] is not |resultsSize|, throw a {{TypeError}} exception. @@ -1071,18 +1082,18 @@ Note: Exported Functions do not have a \[[Construct]] method and thus it is not 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|. @@ -1171,10 +1182,6 @@ 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|. -

Exception types

@@ -1235,7 +1242,7 @@ 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 [|parameters|] → [] be [=tag_type=](|store|, **this**.\[[Address]]).
 1. Let |idlParameters| be «».
 1. [=list/iterate|For each=] |type| of |parameters|,
     1. [=list/Append=] [$FromValueType$](|type|) to |idlParameters|.
@@ -1255,7 +1262,7 @@ dictionary ExceptionOptions {
 [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);
+  any getArg([EnforceRange] unsigned long index);
   boolean is(Tag exceptionTag);
   readonly attribute (DOMString or undefined) stack;
 };
@@ -1265,19 +1272,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|. +
@@ -1288,28 +1307,28 @@ lt="Exception(exceptionTag, payload, options)">new Exception(|exceptionTag|, |pa constructor steps are: 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. [=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. Return [=ToJSValue=](|payload|[|index|]). @@ -1336,20 +1355,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: - -1. Unwind the stack until reaching the *catching try block* given |type|. -1. Invoke the catch block with |payload| and |opaqueData|. +To get the JavaScript exception tag, perform the following steps: -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|.
From d399b9e0711b408e15fdfbea1cafe956a6f3d481 Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Fri, 26 Apr 2024 10:34:08 -0700 Subject: [PATCH 086/130] Expose the JavaScript Exception tag and allow importing it (#269) As discussed in #202 The JS tag was added to the JS API spec in #301, but it is not observable. This change exposes it on the WebAssembly namespace, allowing it to be imported into wasm modules. This allows wasm modules to explicitly extract the thrown JS objects as externrefs from the caught exrefs, and also to throw fresh exceptions with externref payloads that will propagate into JS and can be caught as bare JS objects not wrapped in a WebAssembly.Exception. It also places the restriction that WebAssembly.Exception objects cannot be created with the JS tag, because it would result in ambiguity or asymmetry when such objects unwind from JS into wasm and back out. --- document/js-api/index.bs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/document/js-api/index.bs b/document/js-api/index.bs index ba25a4cc56..d3464d9210 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -267,6 +267,8 @@ namespace WebAssembly { Promise<Instance> instantiate( Module moduleObject, optional object importObject); + + readonly attribute Tag JSTag; };
@@ -505,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

@@ -1306,6 +1313,9 @@ 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_type=](|store|, |exceptionTag|.\[[Address]]).
 1. If |types|'s [=list/size=] is not |payload|'s [=list/size=],

From 7b6af09fdfacd5945a69e645b493afd503a3d9e9 Mon Sep 17 00:00:00 2001
From: Ben Visness 
Date: Tue, 7 May 2024 11:19:54 -0500
Subject: [PATCH 087/130] Fix "metada" typo

---
 document/metadata/code/util/macros.def | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/document/metadata/code/util/macros.def b/document/metadata/code/util/macros.def
index 3b8321c1b6..fbdd841402 100644
--- a/document/metadata/code/util/macros.def
+++ b/document/metadata/code/util/macros.def
@@ -21,8 +21,8 @@
 .. Code Metadata, non-terminals
 
 .. |Bcodemetadatasec| mathdef:: \xref{binary}{binary-codemetadata}{\B{codemetadatasec}}
-.. |Bcodemetadata| mathdef:: \xref{binary}{binary-codemetadata}{\B{codemetada}}
-.. |Bcodemetadatafunc| mathdef:: \xref{binary}{binary-codemetadata}{\B{codemetadafunc}}
+.. |Bcodemetadata| mathdef:: \xref{binary}{binary-codemetadata}{\B{codemetadata}}
+.. |Bcodemetadatafunc| mathdef:: \xref{binary}{binary-codemetadata}{\B{codemetadatafunc}}
 .. |Bcodemetadataitem| mathdef:: \xref{binary}{binary-codemetadata}{\B{codemetadataitem}}
 
 .. Branch Hints, non-terminals

From ff86dc295b3c3aea128376fba4c756ae7767d2a3 Mon Sep 17 00:00:00 2001
From: Andreas Rossberg 
Date: Tue, 21 May 2024 19:29:44 +0200
Subject: [PATCH 088/130] Allow quoted identifiers (#23)

---
 .github/workflows/ci-interpreter.yml |  2 +-
 document/core/text/conventions.rst   | 21 ++++++-------
 document/core/text/instructions.rst  | 20 ++++++-------
 document/core/text/lexical.rst       |  8 +++--
 document/core/text/modules.rst       | 44 ++++++++++++++--------------
 document/core/text/values.rst        |  8 +++--
 document/core/util/macros.def        |  1 +
 interpreter/text/arrange.ml          |  5 +++-
 interpreter/text/lexer.mll           | 37 ++++++++++++++++++-----
 interpreter/text/parser.mly          | 36 ++++++++++++++++++-----
 interpreter/util/lib.ml              |  9 ++++++
 interpreter/util/lib.mli             |  9 ++++++
 proposals/annotations/Overview.md    | 18 +++++++++---
 test/core/annotations.wast           | 21 ++++++++-----
 test/core/id.wast                    | 31 ++++++++++++++++++++
 15 files changed, 195 insertions(+), 75 deletions(-)
 create mode 100644 test/core/id.wast

diff --git a/.github/workflows/ci-interpreter.yml b/.github/workflows/ci-interpreter.yml
index 8e0f4cb543..76f44418e6 100644
--- a/.github/workflows/ci-interpreter.yml
+++ b/.github/workflows/ci-interpreter.yml
@@ -21,7 +21,7 @@ jobs:
       - name: Setup OCaml
         uses: ocaml/setup-ocaml@v2
         with:
-          ocaml-compiler: 4.12.x
+          ocaml-compiler: 4.14.x
       - name: Setup OCaml tools
         run: opam install --yes ocamlfind.1.9.5 js_of_ocaml.4.0.0 js_of_ocaml-ppx.4.0.0
       - name: Setup Node.js
diff --git a/document/core/text/conventions.rst b/document/core/text/conventions.rst
index 1efc88b036..493d7921a5 100644
--- a/document/core/text/conventions.rst
+++ b/document/core/text/conventions.rst
@@ -120,20 +120,21 @@ It is convenient to define identifier contexts as :ref:`records ` assigned to the defined indices.
+For each index space, such a context contains the list of :ref:`names ` assigned to the defined indices,
+which were denoted by the corresponding :ref:`identifiers `.
 Unnamed indices are associated with empty (:math:`\epsilon`) entries in these lists.
 
 An identifier context is *well-formed* if no index space contains duplicate identifiers.
diff --git a/document/core/text/instructions.rst b/document/core/text/instructions.rst
index 4592953613..c284326ff4 100644
--- a/document/core/text/instructions.rst
+++ b/document/core/text/instructions.rst
@@ -32,11 +32,11 @@ The following grammar handles the corresponding update to the :ref:`identifier c
 .. math::
    \begin{array}{llcllll}
    \production{label} & \Tlabel_I &::=&
-     v{:}\Tid &\Rightarrow& \{\ILABELS~v\} \compose I
+     v{:}\Tid &\Rightarrow& v, \{\ILABELS~v\} \compose I
        & (\iff v \notin I.\ILABELS) \\ &&|&
-     v{:}\Tid &\Rightarrow& \{\ILABELS~v\} \compose (I \with \ILABELS[i] = \epsilon)
+     v{:}\Tid &\Rightarrow& v, \{\ILABELS~v\} \compose (I \with \ILABELS[i] = \epsilon)
        & (\iff I.\ILABELS[i] = v) \\ &&|&
-     \epsilon &\Rightarrow& \{\ILABELS~(\epsilon)\} \compose I \\
+     \epsilon &\Rightarrow& \epsilon, \{\ILABELS~(\epsilon)\} \compose I \\
    \end{array}
 
 .. note::
@@ -79,16 +79,16 @@ However, the special case of a type use that is syntactically empty or consists
      x,I'{:}\Ttypeuse_I &\Rightarrow& x & (\iff I' = \{\ILOCALS~(\epsilon)^\ast\}) \\
    \end{array} \\
    \production{block instruction} & \Tblockinstr_I &::=&
-     \text{block}~~I'{:}\Tlabel_I~~\X{bt}{:}\Tblocktype_I~~(\X{in}{:}\Tinstr_{I'})^\ast~~\text{end}~~\Tid^?
+     \text{block}~~(v^?,I'){:}\Tlabel_I~~\X{bt}{:}\Tblocktype_I~~(\X{in}{:}\Tinstr_{I'})^\ast~~\text{end}~~{v'}^?{:}\Tid^?
        \\ &&&\qquad \Rightarrow\quad \BLOCK~\X{bt}~\X{in}^\ast~\END
-       \qquad\quad~~ (\iff \Tid^? = \epsilon \vee \Tid^? = \Tlabel) \\ &&|&
-     \text{loop}~~I'{:}\Tlabel_I~~\X{bt}{:}\Tblocktype_I~~(\X{in}{:}\Tinstr_{I'})^\ast~~\text{end}~~\Tid^?
+       \qquad\quad~~ (\iff {v'}^? = \epsilon \vee {v'}^? = v^?) \\ &&|&
+     \text{loop}~~(v^?,I'){:}\Tlabel_I~~\X{bt}{:}\Tblocktype_I~~(\X{in}{:}\Tinstr_{I'})^\ast~~\text{end}~~{v'}^?{:}\Tid^?
        \\ &&&\qquad \Rightarrow\quad \LOOP~\X{bt}~\X{in}^\ast~\END
-       \qquad\qquad (\iff \Tid^? = \epsilon \vee \Tid^? = \Tlabel) \\ &&|&
-     \text{if}~~I'{:}\Tlabel_I~~\X{bt}{:}\Tblocktype_I~~(\X{in}_1{:}\Tinstr_{I'})^\ast~~
-       \text{else}~~\Tid_1^?~~(\X{in}_2{:}\Tinstr_{I'})^\ast~~\text{end}~~\Tid_2^?
+       \qquad\qquad (\iff {v'}^? = \epsilon \vee {v'}^? = v^?) \\ &&|&
+     \text{if}~~(v^?,I'){:}\Tlabel_I~~\X{bt}{:}\Tblocktype_I~~(\X{in}_1{:}\Tinstr_{I'})^\ast~~
+       \text{else}~~v_1^?{:}\Tid_1^?~~(\X{in}_2{:}\Tinstr_{I'})^\ast~~\text{end}~~v_2^?{:}\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) \\
+       \qquad (\iff v_1^? = \epsilon \vee v_1^? = v^?, v_2^? = \epsilon \vee v_2^? = v^?) \\
    \end{array}
 
 .. note::
diff --git a/document/core/text/lexical.rst b/document/core/text/lexical.rst
index 55cbe3a45a..077dae17f4 100644
--- a/document/core/text/lexical.rst
+++ b/document/core/text/lexical.rst
@@ -135,7 +135,7 @@ The *look-ahead* restrictions on the productions for |Tblockchar| disambiguate t
 Annotations
 ~~~~~~~~~~~
 
-An *annotation* is a bracketed token sequence headed by an *annotation id* of the form :math:`\T{@id}`.
+An *annotation* is a bracketed token sequence headed by an *annotation id* of the form :math:`\text{@id}` or :math:`\text{@"..."}`.
 No :ref:`space ` is allowed between the opening parenthesis and this id.
 Annotations are intended to be used for third-party extensions;
 they can appear anywhere in a program but are ignored by the WebAssembly semantics itself, which treats them as :ref:`white space `.
@@ -145,8 +145,10 @@ Annotations can contain other parenthesized token sequences (including nested an
 
 .. math::
    \begin{array}{llclll@{\qquad\qquad}l}
-   \production{annot} & \Tannot &::=&
-     \text{(@}~\Tidchar^+ ~(\Tspace ~|~ \Ttoken)^\ast~\text{)} \\
+   \production{annotation} & \Tannot &::=&
+     \text{(@}~\Tannotid ~(\Tspace ~|~ \Ttoken)^\ast~\text{)} \\
+   \production{annotation identifier} & \Tannotid &::=&
+     \Tidchar^+ ~|~ \Tname \\
    \end{array}
 
 .. note::
diff --git a/document/core/text/modules.rst b/document/core/text/modules.rst
index 5aab9b32cd..69d5f90ac6 100644
--- a/document/core/text/modules.rst
+++ b/document/core/text/modules.rst
@@ -679,28 +679,28 @@ The definition of the initial :ref:`identifier context ` :math:`I`
 
 .. math::
    \begin{array}{@{}lcl@{\qquad\qquad}l}
-   \F{idc}(\text{(}~\text{type}~\Tid^?~\X{ft}{:}\Tfunctype~\text{)}) &=&
-     \{\ITYPES~(\Tid^?), \ITYPEDEFS~\X{ft}\} \\
-   \F{idc}(\text{(}~\text{func}~\Tid^?~\dots~\text{)}) &=&
-     \{\IFUNCS~(\Tid^?)\} \\
-   \F{idc}(\text{(}~\text{table}~\Tid^?~\dots~\text{)}) &=&
-     \{\ITABLES~(\Tid^?)\} \\
-   \F{idc}(\text{(}~\text{memory}~\Tid^?~\dots~\text{)}) &=&
-     \{\IMEMS~(\Tid^?)\} \\
-   \F{idc}(\text{(}~\text{global}~\Tid^?~\dots~\text{)}) &=&
-     \{\IGLOBALS~(\Tid^?)\} \\
-   \F{idc}(\text{(}~\text{elem}~\Tid^?~\dots~\text{)}) &=&
-     \{\IELEM~(\Tid^?)\} \\
-   \F{idc}(\text{(}~\text{data}~\Tid^?~\dots~\text{)}) &=&
-     \{\IDATA~(\Tid^?)\} \\
-   \F{idc}(\text{(}~\text{import}~\dots~\text{(}~\text{func}~\Tid^?~\dots~\text{)}~\text{)}) &=&
-     \{\IFUNCS~(\Tid^?)\} \\
-   \F{idc}(\text{(}~\text{import}~\dots~\text{(}~\text{table}~\Tid^?~\dots~\text{)}~\text{)}) &=&
-     \{\ITABLES~(\Tid^?)\} \\
-   \F{idc}(\text{(}~\text{import}~\dots~\text{(}~\text{memory}~\Tid^?~\dots~\text{)}~\text{)}) &=&
-     \{\IMEMS~(\Tid^?)\} \\
-   \F{idc}(\text{(}~\text{import}~\dots~\text{(}~\text{global}~\Tid^?~\dots~\text{)}~\text{)}) &=&
-     \{\IGLOBALS~(\Tid^?)\} \\
+   \F{idc}(\text{(}~\text{type}~v^?{:}\Tid^?~\X{ft}{:}\Tfunctype~\text{)}) &=&
+     \{\ITYPES~(v^?), \ITYPEDEFS~\X{ft}\} \\
+   \F{idc}(\text{(}~\text{func}~v^?{:}\Tid^?~\dots~\text{)}) &=&
+     \{\IFUNCS~(v^?)\} \\
+   \F{idc}(\text{(}~\text{table}~v^?{:}\Tid^?~\dots~\text{)}) &=&
+     \{\ITABLES~(v^?)\} \\
+   \F{idc}(\text{(}~\text{memory}~v^?{:}\Tid^?~\dots~\text{)}) &=&
+     \{\IMEMS~(v^?)\} \\
+   \F{idc}(\text{(}~\text{global}~v^?{:}\Tid^?~\dots~\text{)}) &=&
+     \{\IGLOBALS~(v^?)\} \\
+   \F{idc}(\text{(}~\text{elem}~v^?{:}\Tid^?~\dots~\text{)}) &=&
+     \{\IELEM~(v^?)\} \\
+   \F{idc}(\text{(}~\text{data}~v^?{:}\Tid^?~\dots~\text{)}) &=&
+     \{\IDATA~(v^?)\} \\
+   \F{idc}(\text{(}~\text{import}~\dots~\text{(}~\text{func}~v^?{:}\Tid^?~\dots~\text{)}~\text{)}) &=&
+     \{\IFUNCS~(v^?)\} \\
+   \F{idc}(\text{(}~\text{import}~\dots~\text{(}~\text{table}~v^?{:}\Tid^?~\dots~\text{)}~\text{)}) &=&
+     \{\ITABLES~(v^?)\} \\
+   \F{idc}(\text{(}~\text{import}~\dots~\text{(}~\text{memory}~v^?{:}\Tid^?~\dots~\text{)}~\text{)}) &=&
+     \{\IMEMS~(v^?)\} \\
+   \F{idc}(\text{(}~\text{import}~\dots~\text{(}~\text{global}~v^?{:}\Tid^?~\dots~\text{)}~\text{)}) &=&
+     \{\IGLOBALS~(v^?)\} \\
    \F{idc}(\text{(}~\dots~\text{)}) &=&
      \{\} \\
    \end{array}
diff --git a/document/core/text/values.rst b/document/core/text/values.rst
index 2b869d251a..3c74112d1a 100644
--- a/document/core/text/values.rst
+++ b/document/core/text/values.rst
@@ -211,12 +211,13 @@ Identifiers
 ~~~~~~~~~~~
 
 :ref:`Indices ` can be given in both numeric and symbolic form.
-Symbolic *identifiers* that stand in lieu of indices start with :math:`\text{\$}`, followed by any sequence of printable |ASCII|_ characters that does not contain a space, quotation mark, comma, semicolon, or bracket.
+Symbolic *identifiers* that stand in lieu of indices start with :math:`\text{\$}`, followed by eiter a sequence of printable |ASCII|_ characters that does not contain a space, quotation mark, comma, semicolon, or bracket, or by a quoted :ref:`name `.
 
 .. math::
    \begin{array}{llclll@{\qquad}l}
    \production{identifier} & \Tid &::=&
-     \text{\$}~\Tidchar^+ \\
+     \text{\$}~c^\ast{:}\Tidchar^+ &\Rightarrow& c^\ast \\ &&|&
+     \text{\$}~c^\ast{:}\Tname &\Rightarrow& c^\ast & (\iff |c^\ast| > 0) \\
    \production{identifier character} & \Tidchar &::=&
      \text{0} ~~|~~ \dots ~~|~~ \text{9} \\ &&|&
      \text{A} ~~|~~ \dots ~~|~~ \text{Z} \\ &&|&
@@ -246,6 +247,9 @@ Symbolic *identifiers* that stand in lieu of indices start with :math:`\text{\$}
      \text{\tilde{~~}} \\
    \end{array}
 
+.. note::
+   The value of an identifier character is its the Unicode codepoint denoting it.
+
 .. _text-id-fresh:
 
 Conventions
diff --git a/document/core/util/macros.def b/document/core/util/macros.def
index 8f78e99285..17eb3fab42 100644
--- a/document/core/util/macros.def
+++ b/document/core/util/macros.def
@@ -719,6 +719,7 @@
 .. |Tblockchar| mathdef:: \xref{text/lexical}{text-comment}{\T{blockchar}}
 
 .. |Tannot| mathdef:: \xref{text/lexical}{text-annot}{\T{annot}}
+.. |Tannotid| mathdef:: \xref{text/lexical}{text-annot}{\T{annotid}}
 .. |Tannottoken| mathdef:: \xref{text/lexical}{text-annot}{\T{annottoken}}
 
 
diff --git a/interpreter/text/arrange.ml b/interpreter/text/arrange.ml
index 4ea2633809..9559a889a1 100644
--- a/interpreter/text/arrange.ml
+++ b/interpreter/text/arrange.ml
@@ -627,7 +627,10 @@ let custom m mnode (module S : Custom.Section) =
 
 let var_opt = function
   | None -> ""
-  | Some x -> " " ^ x.it
+  | Some x when
+    String.for_all (fun c -> Lib.Char.is_alphanum_ascii c || c = '_') x.it ->
+    " $" ^ x.it
+  | Some x -> " $" ^ name (Utf8.decode x.it)
 
 let module_with_var_opt x_opt (m, cs) =
   let fx = ref 0 in
diff --git a/interpreter/text/lexer.mll b/interpreter/text/lexer.mll
index bda1aa81b7..b2f4e2a3d7 100644
--- a/interpreter/text/lexer.mll
+++ b/interpreter/text/lexer.mll
@@ -48,6 +48,11 @@ let string s =
   done;
   Buffer.contents b
 
+let annot_id lexbuf s =
+  let s' = string s in
+  if s' = "" then error lexbuf "empty annotation id";
+  try Utf8.decode s' with Utf8.Utf8 -> error lexbuf "malformed UTF-8 encoding"
+
 let opt = Lib.Option.get
 }
 
@@ -102,8 +107,7 @@ let float =
 let string = '"' character* '"'
 
 let idchar = letter | digit | '_' | symbol
-let name = idchar+
-let id = '$' name
+let id = idchar+
 
 let keyword = ['a'-'z'] (letter | digit | '_' | '.' | ':')+
 let reserved = (idchar | string)+ | ',' | ';' | '[' | ']' | '{' | '}'
@@ -699,13 +703,21 @@ rule token = parse
   | "offset="(nat as s) { OFFSET_EQ_NAT s }
   | "align="(nat as s) { ALIGN_EQ_NAT s }
 
-  | id as s { VAR s }
+  | '$'(id as s) { VAR s }
+  | '$'(string as s)
+    { let s' = string s in
+      if s' = "" then error lexbuf "empty identifier"; VAR s' }
+  | '$' { error lexbuf "empty identifier" }
 
-  | "(@"(name as n)
+  | "(@"(id as n)
     { let r = region lexbuf in
       let items = annot (Lexing.lexeme_start_p lexbuf) lexbuf in
       Annot.record (Annot.{name = Utf8.decode n; items} @@ r); token lexbuf }
-  | "(@" { error lexbuf "malformed annotation id" }
+  | "(@"(string as s)
+    { let r = region lexbuf in
+      let items = annot (Lexing.lexeme_start_p lexbuf) lexbuf in
+      Annot.record (Annot.{name = annot_id lexbuf s; items} @@ r); token lexbuf }
+  | "(@" { error lexbuf "empty annotation id" }
 
   | ";;"utf8_no_nl*eof { EOF }
   | ";;"utf8_no_nl*newline { Lexing.new_line lexbuf; token lexbuf }
@@ -726,11 +738,16 @@ and annot start = parse
     { let r = region lexbuf in
       let items = annot (Lexing.lexeme_start_p lexbuf) lexbuf in
       (Annot.Parens items @@ r) :: annot start lexbuf }
-  | "(@"(name as n)
+  | "(@"(id as n)
     { let r = region lexbuf in
       let items = annot (Lexing.lexeme_start_p lexbuf) lexbuf in
       let ann = Annot.{name = Utf8.decode n; items} @@ r in
       (Annot.Annot ann @@ r) :: annot start lexbuf }
+  | "(@"(string as s)
+    { let r = region lexbuf in
+      let items = annot (Lexing.lexeme_start_p lexbuf) lexbuf in
+      let ann = Annot.{name = annot_id lexbuf s; items} @@ r in
+      (Annot.Annot ann @@ r) :: annot start lexbuf }
 
   | nat as s
     { let r = region lexbuf in
@@ -741,9 +758,15 @@ and annot start = parse
   | float as s
     { let r = region lexbuf in
       (Annot.Float s @@ r) :: annot start lexbuf }
-  | id as s
+  | '$'(id as s)
     { let r = region lexbuf in
       (Annot.Var s @@ r) :: annot start lexbuf }
+  | '$'(string as s)
+    { let r = region lexbuf in
+      let s' = string s in
+      if s' = "" then error lexbuf "empty identifier";
+      (Annot.Var s' @@ r) :: annot start lexbuf }
+  | '$' { error lexbuf "empty identifier" }
   | string as s
     { let r = region lexbuf in
       (Annot.String (string s) @@ r) :: annot start lexbuf }
diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly
index 48731201eb..ac77c1e3e1 100644
--- a/interpreter/text/parser.mly
+++ b/interpreter/text/parser.mly
@@ -88,6 +88,11 @@ let nat32 s loc =
 let name s loc =
   try Utf8.decode s with Utf8.Utf8 -> error (at loc) "malformed UTF-8 encoding"
 
+let var s loc =
+  let r = at loc in
+  try ignore (Utf8.decode s); Source.(s @@ r)
+  with Utf8.Utf8 -> error r "malformed UTF-8 encoding"
+
 
 (* Symbolic variables *)
 
@@ -120,9 +125,24 @@ let force_locals (c : context) =
 let enter_func (c : context) =
   {c with labels = VarMap.empty; locals = empty ()}
 
+let print_char = function
+  | 0x09 -> "\\t"
+  | 0x0a -> "\\n"
+  | 0x22 -> "\\\""
+  | 0x5c -> "\\\\"
+  | c when 0x20 <= c && c < 0x7f -> String.make 1 (Char.chr c)
+  | c -> Printf.sprintf "\\u{%02x}" c
+
+let print x =
+  "$" ^
+  if String.for_all (fun c -> Lib.Char.is_alphanum_ascii c || c = '_') x.it
+  then x.it
+  else "\"" ^ String.concat "" (List.map print_char (Utf8.decode x.it)) ^ "\""
+
+
 let lookup category space x =
   try VarMap.find x.it space.map
-  with Not_found -> error x.at ("unknown " ^ category ^ " " ^ x.it)
+  with Not_found -> error x.at ("unknown " ^ category ^ " " ^ print x)
 
 let type_ (c : context) x = lookup "type" c.types.space x
 let func (c : context) x = lookup "function" c.funcs x
@@ -134,7 +154,7 @@ let elem (c : context) x = lookup "elem segment" c.elems x
 let data (c : context) x = lookup "data segment" c.datas x
 let label (c : context) x =
   try VarMap.find x.it c.labels
-  with Not_found -> error x.at ("unknown label " ^ x.it)
+  with Not_found -> error x.at ("unknown label " ^ print x)
 
 let func_type (c : context) x =
   try (Lib.List32.nth c.types.list x.it).it
@@ -151,7 +171,7 @@ let anon category space n =
 let bind category space x =
   let i = anon category space 1l in
   if VarMap.mem x.it space.map then
-    error x.at ("duplicate " ^ category ^ " " ^ x.it);
+    error x.at ("duplicate " ^ category ^ " " ^ print x);
   space.map <- VarMap.add x.it i space.map;
   i
 
@@ -336,8 +356,8 @@ num :
   | FLOAT { $1 @@ $sloc }
 
 var :
-  | NAT { let at = $sloc in fun c lookup -> nat32 $1 at @@ at }
-  | VAR { let at = $sloc in fun c lookup -> lookup c ($1 @@ at) @@ at }
+  | NAT { fun c lookup -> nat32 $1 $sloc @@ $sloc }
+  | VAR { fun c lookup -> lookup c (var $1 $sloc) @@ $sloc }
 
 var_list :
   | /* empty */ { fun c lookup -> [] }
@@ -348,7 +368,7 @@ bind_var_opt :
   | bind_var { fun c anon bind -> bind c $1 }  /* Sugar */
 
 bind_var :
-  | VAR { $1 @@ $sloc }
+  | VAR { var $1 $sloc }
 
 labeling_opt :
   | /* empty */
@@ -1001,7 +1021,7 @@ module_fields1 :
       {m with exports = $1 c :: m.exports} }
 
 module_var :
-  | VAR { $1 @@ $sloc }  /* Sugar */
+  | VAR { var $1 $sloc }  /* Sugar */
 
 module_ :
   | LPAR MODULE option(module_var) module_fields RPAR
@@ -1026,7 +1046,7 @@ inline_module1 :  /* Sugar */
 /* Scripts */
 
 script_var :
-  | VAR { $1 @@ $sloc }  /* Sugar */
+  | VAR { var $1 $sloc }  /* Sugar */
 
 script_module :
   | module_ { $1 }
diff --git a/interpreter/util/lib.ml b/interpreter/util/lib.ml
index 90c4e4fe0f..aaa6039523 100644
--- a/interpreter/util/lib.ml
+++ b/interpreter/util/lib.ml
@@ -22,6 +22,15 @@ struct
     n <> 0 && n land (n - 1) = 0
 end
 
+module Char =
+struct
+  let is_digit_ascii c = '0' <= c && c <= '9'
+  let is_uppercase_ascii c = 'A' <= c && c <= 'Z'
+  let is_lowercase_ascii c = 'a' <= c && c <= 'z'
+  let is_letter_ascii c = is_uppercase_ascii c || is_lowercase_ascii c
+  let is_alphanum_ascii c = is_digit_ascii c || is_letter_ascii c
+end
+
 module String =
 struct
   let implode cs =
diff --git a/interpreter/util/lib.mli b/interpreter/util/lib.mli
index b66b8b0e82..d0ba325096 100644
--- a/interpreter/util/lib.mli
+++ b/interpreter/util/lib.mli
@@ -75,6 +75,15 @@ sig
   val is_power_of_two : int -> bool
 end
 
+module Char :
+sig
+  val is_digit_ascii : char -> bool
+  val is_uppercase_ascii : char -> bool
+  val is_lowercase_ascii : char -> bool
+  val is_letter_ascii : char -> bool
+  val is_alphanum_ascii : char -> bool
+end
+
 module String :
 sig
   val implode : char list -> string
diff --git a/proposals/annotations/Overview.md b/proposals/annotations/Overview.md
index ba6ad8461a..dbd1842062 100644
--- a/proposals/annotations/Overview.md
+++ b/proposals/annotations/Overview.md
@@ -17,6 +17,8 @@ Solution
 
 * Neither the syntactic shape nor the semantics is prescribed by the Wasm specification, though the Appendix might include a description of optional support for name section annotations and generic custom sections.
 
+* As an aside, the syntax of symbolic identifiers is extended to allow arbitrary strings in the form `$"..."`.
+
 * This proposal only affects the text format, nothing else.
 
 
@@ -26,15 +28,23 @@ Extend the Text Format as follows:
 
 * Anywhere where white space is allowed, allow *annotations* of the following form:
   ```
-  annot ::= "(@"idchar+  annotelem* ")"
-  annotelem ::= keyword | reserved | uN | sN | fN | string | id | "(" annotelem* ")" | "(@"idchar+ annotelem* ")"
+  annot ::= "(@"annotid  annotelem* ")"
+  annotid ::= idchar+ | name
+  annotelem ::= keyword | reserved | uN | sN | fN | string | id | "(" annotelem* ")"
   ```
   In other words, an annotation can contain any sequence of tokens, as long as it is well-bracketed.
-  No white space is allowed as part of the initial `(@idchar+` delimiter.
+  No white space is allowed as part of the initial `(@annotid` delimiter.
 
-* The initial `idchar+` is meant to be an identifier categorising the extension, and plays a role similar to the name of a custom section.
+* The initial `annotid` is meant to be an identifier categorising the extension, and plays a role similar to the name of a custom section.
   By convention, annotations corresponding to a custom section should use the same id.
 
+* Extend the grammar of identifiers as follows:
+  ```
+  id ::= "$"idchar+ | "$"name
+  ```
+
+* Elaborate identifiers to their denotation as a name, treating the unquoted form as a shorthand for the name `"idchar+"`. In all places where identifiers are compared, compare the denotated names instead. In particular, change the identifier environment `I` to record names instead of identifiers.
+
 Extend the Appendix on the Custom Sections:
 
 * Define annotations reflecting the Name section, which take the form of annotations `(@name "name")`.
diff --git a/test/core/annotations.wast b/test/core/annotations.wast
index 5a828f129e..912d10f38a 100644
--- a/test/core/annotations.wast
+++ b/test/core/annotations.wast
@@ -1,8 +1,11 @@
 (module
   (@a)
-
+  (@0)
   (@aas-3!@$d-@#4)
   (@@) (@$) (@+) (@0) (@.) (@!$@#$23414@#$)
+  (@"a")
+  (@" @ asd\2a 045 \" fdaf \t \u{45}")
+
   (@a x y z)
   (@a x-y $yz "aa" -2 0.3 0x3)
   (@a x-y$yz"aa"-2)
@@ -66,10 +69,14 @@
 
 (assert_malformed (module quote "( @a)") "unknown operator")
 
-(assert_malformed (module quote "(@)") "malformed annotation id")
-(assert_malformed (module quote "(@ )") "malformed annotation id")
-(assert_malformed (module quote "(@ x)") "malformed annotation id")
-(assert_malformed (module quote "(@(@a)x)") "malformed annotation id")
+(assert_malformed (module quote "(@)") "empty annotation id")
+(assert_malformed (module quote "(@ )") "empty annotation id")
+(assert_malformed (module quote "(@ x)") "empty annotation id")
+(assert_malformed (module quote "(@(@a)x)") "empty annotation id")
+(assert_malformed (module quote "(@\"\")") "empty annotation id")
+(assert_malformed (module quote "(@ \"a\")") "empty annotation id")
+(assert_malformed (module quote "(@\"\n\")") "empty annotation id")
+(assert_malformed (module quote "(@\"\\ef\")") "malformed UTF-8")
 
 (assert_malformed (module quote "(@x ") "unclosed annotation")
 (assert_malformed (module quote "(@x ()") "unclosed annotation")
@@ -85,8 +92,8 @@
 (assert_malformed (module quote "(@x \")") "unclosed string")
 
 (assert_malformed (module quote "((@a)@b)") "unknown operator")
-(assert_malformed (module quote "(func $(@a))") "unknown operator")
-(assert_malformed (module quote "(func $(@a)f)") "unknown operator")
+(assert_malformed (module quote "(func $(@a))") "empty identifier")
+(assert_malformed (module quote "(func $(@a)f)") "empty identifier")
 
 ((@a) module (@a) $m (@a) (@a)
   ((@a) import (@a) "spectest" (@a) "global_i32" (@a)
diff --git a/test/core/id.wast b/test/core/id.wast
new file mode 100644
index 0000000000..dcf151f22c
--- /dev/null
+++ b/test/core/id.wast
@@ -0,0 +1,31 @@
+(module
+  (func $fg) (func (call $fg))
+  (func $03) (func (call $03))
+  (func $!?@#a$%^&*b-+_.:9'`|/\<=>~) (func (call $!?@#a$%^&*b-+_.:9'`|/\<=>~))
+  (func $" random \t \n stuff ") (func (call $" random \t \n stuff "))
+  (func $" ") (func (call $" "))
+
+  (func $fh) (func (call $"fh"))
+  (func $"fi") (func (call $fi))
+  (func $!?@#a$%^&*-+_.:9'`|/\<=>~) (func (call $"!?@#a$%^&*-+_.:9'`|/\\<=>~"))
+
+  (func $"\41B") (func (call $"AB") (call $"A\42") (call $"\41\42") (call $"\u{41}\u{42}"))
+  (func $"\t") (func (call $"\09") (call $"\u{09}"))
+  (func $"") (func (call $"\ef\98\9a\ef\92\a9") (call $"\u{f61a}\u{f4a9}"))
+
+  (func
+    block $l1 (br $"l1") end $"l1"
+    block $007 (br $"007") end $"007"
+    block $!?@#a$%^&*-+_.:9'`|/\<=>~ end $"!?@#a$%^&*-+_.:9'`|/\\<=>~"
+    (i32.const 0) if $"\41B" (br $AB) else $"A\42" end $"\u{41}\u{42}"
+    (i32.const 0) if $"\t" else $"\09" end $"\u{09}"
+    (i32.const 0) if $" " else $"\ef\98\9a\ef\92\a9 " end $"\u{f61a}\u{f4a9} "
+  )
+)
+
+(assert_malformed (module quote "(func $)") "empty identifier")
+(assert_malformed (module quote "(func $\"\")") "empty identifier")
+(assert_malformed (module quote "(func $ \"a\")") "empty identifier")
+(assert_malformed (module quote "(func $\"a\nb\")") "empty identifier")
+(assert_malformed (module quote "(func $\"a\tb\")") "empty identifier")
+(assert_malformed (module quote "(func $\"\\ef\")") "malformed UTF-8")

From e0de08969c3fa9a7e44e2ac53fb71050b217d603 Mon Sep 17 00:00:00 2001
From: Heejin Ahn 
Date: Thu, 23 May 2024 13:44:06 -0700
Subject: [PATCH 089/130] Restructure explainers (#302)

- Revives the legacy Phase 3 explainer and put it in
  `proposals/exception-handling/legacy` directory. Given that we still
  maintain the legacy formal spec in `document/legacy`, I think it makes
  sense to have the legacy expliner too.
- Moves two auxiliary docs for the legacy proposal
  (`Exception-formal-overview.md` and `Exception-formal-examples.md`),
  currently still in `proposals/exception-handling`, to the new
  `proposals/exception-handling/legacy` directory too.
- Renames `proposals/exception-handling/old` to
  `proposals/exception-handling/pre-legacy`, signifying this precedes
  the "legacy" proposal.
- Fixes the CG meeting date from the current explainer.
- Adds more historical context to the beginning of each explainer in
  `pre-legacy` and `legacy` directories.
---
 proposals/exception-handling/Exceptions.md    |   4 +-
 .../Exceptions-formal-examples.md             |   0
 .../Exceptions-formal-overview.md             |   0
 .../exception-handling/legacy/Exceptions.md   | 711 ++++++++++++++++++
 .../{old => pre-legacy}/Exceptions-v1.md      |  10 +-
 .../Exceptions-v2-Level-1+N.md                |   5 +
 .../Exceptions-v2-Level-1.md                  |  12 +-
 .../{old => pre-legacy}/Exceptions-v2.md      |  19 +-
 8 files changed, 742 insertions(+), 19 deletions(-)
 rename proposals/exception-handling/{ => legacy}/Exceptions-formal-examples.md (100%)
 rename proposals/exception-handling/{ => legacy}/Exceptions-formal-overview.md (100%)
 create mode 100644 proposals/exception-handling/legacy/Exceptions.md
 rename proposals/exception-handling/{old => pre-legacy}/Exceptions-v1.md (98%)
 rename proposals/exception-handling/{old => pre-legacy}/Exceptions-v2-Level-1+N.md (97%)
 rename proposals/exception-handling/{old => pre-legacy}/Exceptions-v2-Level-1.md (97%)
 rename proposals/exception-handling/{old => pre-legacy}/Exceptions-v2.md (96%)

diff --git a/proposals/exception-handling/Exceptions.md b/proposals/exception-handling/Exceptions.md
index 9a2ddfb8de..bc508eff9a 100644
--- a/proposals/exception-handling/Exceptions.md
+++ b/proposals/exception-handling/Exceptions.md
@@ -1,8 +1,8 @@
 # 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).
 
 ---
 
diff --git a/proposals/exception-handling/Exceptions-formal-examples.md b/proposals/exception-handling/legacy/Exceptions-formal-examples.md
similarity index 100%
rename from proposals/exception-handling/Exceptions-formal-examples.md
rename to proposals/exception-handling/legacy/Exceptions-formal-examples.md
diff --git a/proposals/exception-handling/Exceptions-formal-overview.md b/proposals/exception-handling/legacy/Exceptions-formal-overview.md
similarity index 100%
rename from proposals/exception-handling/Exceptions-formal-overview.md
rename to proposals/exception-handling/legacy/Exceptions-formal-overview.md
diff --git a/proposals/exception-handling/legacy/Exceptions.md b/proposals/exception-handling/legacy/Exceptions.md
new file mode 100644
index 0000000000..74270f88c0
--- /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` | 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
+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 a5ca40df86..c48fa64ed5 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 7372ef029a..08a1a5e0e3 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 8c9ce8eda0..32400e9a91 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 233f28529e..4ab9eb5f66 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.
 

From f3ebba329fea4a7d926b82eab63501e4c2871dc7 Mon Sep 17 00:00:00 2001
From: Heejin Ahn 
Date: Thu, 23 May 2024 17:06:30 -0700
Subject: [PATCH 090/130] Revive legacy JS API and restructure legacy spec
 directory (#303)

This adds `core` and `js-api` directory in `document/legacy/exceptions`,
moves all core spec files into `core/`, and restores the deleted legacy
JS API files in `js-api/`.

The core legacy spec only contains the EH instructions, which is easier
to view, but it is hard to precisely carve out the modified part from
the JS API file, so this adds the whole file for the legacy spec.
---
 .github/workflows/ci-spec.yml                 |   70 +-
 document/Makefile                             |    2 +-
 document/legacy/exceptions/{ => core}/LICENSE |    0
 .../legacy/exceptions/{ => core}/Makefile     |    0
 .../legacy/exceptions/{ => core}/README.md    |    0
 .../{ => core}/appendix/index-instructions.py |    0
 .../legacy/exceptions/{ => core}/binary.rst   |    0
 document/legacy/exceptions/{ => core}/conf.py |    0
 .../legacy/exceptions/{ => core}/exec.rst     |    0
 .../legacy/exceptions/{ => core}/index.rst    |    0
 .../legacy/exceptions/{ => core}/intro.rst    |    0
 .../exceptions/{ => core}/static/custom.css   |    0
 .../{ => core}/static/webassembly.png         |  Bin
 .../legacy/exceptions/{ => core}/syntax.rst   |    0
 .../legacy/exceptions/{ => core}/text.rst     |    0
 .../exceptions/{ => core}/util/macros.def     |    0
 .../exceptions/{ => core}/util/mathdef.py     |    0
 .../{ => core}/util/pseudo-lexer.py           |    0
 .../legacy/exceptions/{ => core}/valid.rst    |    0
 document/legacy/exceptions/js-api/Makefile    |   44 +
 document/legacy/exceptions/js-api/index.bs    | 1450 +++++++++++++++++
 21 files changed, 1540 insertions(+), 26 deletions(-)
 rename document/legacy/exceptions/{ => core}/LICENSE (100%)
 rename document/legacy/exceptions/{ => core}/Makefile (100%)
 rename document/legacy/exceptions/{ => core}/README.md (100%)
 rename document/legacy/exceptions/{ => core}/appendix/index-instructions.py (100%)
 rename document/legacy/exceptions/{ => core}/binary.rst (100%)
 rename document/legacy/exceptions/{ => core}/conf.py (100%)
 rename document/legacy/exceptions/{ => core}/exec.rst (100%)
 rename document/legacy/exceptions/{ => core}/index.rst (100%)
 rename document/legacy/exceptions/{ => core}/intro.rst (100%)
 rename document/legacy/exceptions/{ => core}/static/custom.css (100%)
 rename document/legacy/exceptions/{ => core}/static/webassembly.png (100%)
 rename document/legacy/exceptions/{ => core}/syntax.rst (100%)
 rename document/legacy/exceptions/{ => core}/text.rst (100%)
 rename document/legacy/exceptions/{ => core}/util/macros.def (100%)
 rename document/legacy/exceptions/{ => core}/util/mathdef.py (100%)
 rename document/legacy/exceptions/{ => core}/util/pseudo-lexer.py (100%)
 rename document/legacy/exceptions/{ => core}/valid.rst (100%)
 create mode 100644 document/legacy/exceptions/js-api/Makefile
 create mode 100644 document/legacy/exceptions/js-api/index.bs

diff --git a/.github/workflows/ci-spec.yml b/.github/workflows/ci-spec.yml
index 08b093cc5e..fecb936575 100644
--- a/.github/workflows/ci-spec.yml
+++ b/.github/workflows/ci-spec.yml
@@ -41,25 +41,6 @@ jobs:
           name: core-rendered
           path: document/core/_build/html
 
-  build-legacy-exceptions-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 && make main
-      - name: Upload artifact
-        uses: actions/upload-artifact@v2
-        with:
-          name: legacy-exceptions-rendered
-          path: document/legacy/exceptions/_build/html
-
   build-js-api-spec:
     runs-on: ubuntu-latest
     steps:
@@ -90,9 +71,43 @@ jobs:
           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@v2
+        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@v2
+        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-legacy-exceptions-spec, build-js-api-spec, build-web-api-spec]
+    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
@@ -103,11 +118,6 @@ jobs:
         with:
           name: core-rendered
           path: _output/core
-      - name: Download legacy exceptions spec artifact
-        uses: actions/download-artifact@v2
-        with:
-          name: legacy-exceptions-rendered
-          path: _output/legacy/exceptions
       - name: Download JS API spec artifact
         uses: actions/download-artifact@v2
         with:
@@ -118,6 +128,16 @@ jobs:
         with:
           name: web-api-rendered
           path: _output/web-api
+      - name: Download legacy exceptions core spec artifact
+        uses: actions/download-artifact@v2
+        with:
+          name: legacy-exceptions-core-rendered
+          path: _output/legacy/exceptions/core
+      - name: Download legacy exceptions JS API spec artifact
+        uses: actions/download-artifact@v2
+        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
diff --git a/document/Makefile b/document/Makefile
index 629d5f5125..1a9625c145 100644
--- a/document/Makefile
+++ b/document/Makefile
@@ -1,4 +1,4 @@
-DIRS     = core js-api web-api legacy/exceptions
+DIRS     = core js-api web-api legacy/exception-handling
 FILES    = index.html
 BUILDDIR = _build
 
diff --git a/document/legacy/exceptions/LICENSE b/document/legacy/exceptions/core/LICENSE
similarity index 100%
rename from document/legacy/exceptions/LICENSE
rename to document/legacy/exceptions/core/LICENSE
diff --git a/document/legacy/exceptions/Makefile b/document/legacy/exceptions/core/Makefile
similarity index 100%
rename from document/legacy/exceptions/Makefile
rename to document/legacy/exceptions/core/Makefile
diff --git a/document/legacy/exceptions/README.md b/document/legacy/exceptions/core/README.md
similarity index 100%
rename from document/legacy/exceptions/README.md
rename to document/legacy/exceptions/core/README.md
diff --git a/document/legacy/exceptions/appendix/index-instructions.py b/document/legacy/exceptions/core/appendix/index-instructions.py
similarity index 100%
rename from document/legacy/exceptions/appendix/index-instructions.py
rename to document/legacy/exceptions/core/appendix/index-instructions.py
diff --git a/document/legacy/exceptions/binary.rst b/document/legacy/exceptions/core/binary.rst
similarity index 100%
rename from document/legacy/exceptions/binary.rst
rename to document/legacy/exceptions/core/binary.rst
diff --git a/document/legacy/exceptions/conf.py b/document/legacy/exceptions/core/conf.py
similarity index 100%
rename from document/legacy/exceptions/conf.py
rename to document/legacy/exceptions/core/conf.py
diff --git a/document/legacy/exceptions/exec.rst b/document/legacy/exceptions/core/exec.rst
similarity index 100%
rename from document/legacy/exceptions/exec.rst
rename to document/legacy/exceptions/core/exec.rst
diff --git a/document/legacy/exceptions/index.rst b/document/legacy/exceptions/core/index.rst
similarity index 100%
rename from document/legacy/exceptions/index.rst
rename to document/legacy/exceptions/core/index.rst
diff --git a/document/legacy/exceptions/intro.rst b/document/legacy/exceptions/core/intro.rst
similarity index 100%
rename from document/legacy/exceptions/intro.rst
rename to document/legacy/exceptions/core/intro.rst
diff --git a/document/legacy/exceptions/static/custom.css b/document/legacy/exceptions/core/static/custom.css
similarity index 100%
rename from document/legacy/exceptions/static/custom.css
rename to document/legacy/exceptions/core/static/custom.css
diff --git a/document/legacy/exceptions/static/webassembly.png b/document/legacy/exceptions/core/static/webassembly.png
similarity index 100%
rename from document/legacy/exceptions/static/webassembly.png
rename to document/legacy/exceptions/core/static/webassembly.png
diff --git a/document/legacy/exceptions/syntax.rst b/document/legacy/exceptions/core/syntax.rst
similarity index 100%
rename from document/legacy/exceptions/syntax.rst
rename to document/legacy/exceptions/core/syntax.rst
diff --git a/document/legacy/exceptions/text.rst b/document/legacy/exceptions/core/text.rst
similarity index 100%
rename from document/legacy/exceptions/text.rst
rename to document/legacy/exceptions/core/text.rst
diff --git a/document/legacy/exceptions/util/macros.def b/document/legacy/exceptions/core/util/macros.def
similarity index 100%
rename from document/legacy/exceptions/util/macros.def
rename to document/legacy/exceptions/core/util/macros.def
diff --git a/document/legacy/exceptions/util/mathdef.py b/document/legacy/exceptions/core/util/mathdef.py
similarity index 100%
rename from document/legacy/exceptions/util/mathdef.py
rename to document/legacy/exceptions/core/util/mathdef.py
diff --git a/document/legacy/exceptions/util/pseudo-lexer.py b/document/legacy/exceptions/core/util/pseudo-lexer.py
similarity index 100%
rename from document/legacy/exceptions/util/pseudo-lexer.py
rename to document/legacy/exceptions/core/util/pseudo-lexer.py
diff --git a/document/legacy/exceptions/valid.rst b/document/legacy/exceptions/core/valid.rst
similarity index 100%
rename from document/legacy/exceptions/valid.rst
rename to document/legacy/exceptions/core/valid.rst
diff --git a/document/legacy/exceptions/js-api/Makefile b/document/legacy/exceptions/js-api/Makefile
new file mode 100644
index 0000000000..84ba5d3abd
--- /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 0000000000..e7db140740
--- /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. From 4433e3f6f39d8187ffab1993225b773537991354 Mon Sep 17 00:00:00 2001 From: Soni L Date: Fri, 24 May 2024 14:47:12 -0300 Subject: [PATCH 091/130] Test breaking out of a try (#270) Tests that breaking out of a try resets the exception handler correctly. See WebAssembly/wabt#2203 --- test/legacy/exceptions/try_catch.wast | 11 ++++++ test/legacy/exceptions/try_delegate.wast | 45 ++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/test/legacy/exceptions/try_catch.wast b/test/legacy/exceptions/try_catch.wast index 2a0e9ff620..07399f3a51 100644 --- a/test/legacy/exceptions/try_catch.wast +++ b/test/legacy/exceptions/try_catch.wast @@ -167,6 +167,14 @@ (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")) @@ -211,6 +219,9 @@ (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/legacy/exceptions/try_delegate.wast b/test/legacy/exceptions/try_delegate.wast index aae3a301b9..39ee09a2b1 100644 --- a/test/legacy/exceptions/try_delegate.wast +++ b/test/legacy/exceptions/try_delegate.wast @@ -145,6 +145,46 @@ (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)) @@ -173,6 +213,11 @@ (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" From 3b5e9e1b8f85382dc74aa1c7e08ede4e69b7d793 Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Sat, 25 May 2024 09:34:27 -0700 Subject: [PATCH 092/130] Fix links to legacy spec documents (#304) #303 broke the core spec links. This fixes it by adding `core/` to the directory links and also adds the JS API spec link to the web page. --- document/index.html | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/document/index.html b/document/index.html index a5766fac4b..b23262bd67 100644 --- a/document/index.html +++ b/document/index.html @@ -69,8 +69,17 @@

Legacy Extensions

From 54d35c63c7fb8b68866e7314cf4b22d9058254e2 Mon Sep 17 00:00:00 2001 From: SasakiSaki <192608617@qq.com> Date: Mon, 27 May 2024 01:17:29 +0800 Subject: [PATCH 093/130] call `ref.func` needs to be declared first --- proposals/function-references/Overview.md | 1 + 1 file changed, 1 insertion(+) diff --git a/proposals/function-references/Overview.md b/proposals/function-references/Overview.md index da2b27ab58..0a58dd2c19 100644 --- a/proposals/function-references/Overview.md +++ b/proposals/function-references/Overview.md @@ -46,6 +46,7 @@ Typed references have no canonical default value, because they cannot be null. T The function `$hof` takes a function pointer as parameter, and is invoked by `$caller`, passing `$inc` as argument: ```wasm (type $i32-i32 (func (param i32) (result i32))) +(elem declare funcref (ref.func $inc)) (func $hof (param $f (ref $i32-i32)) (result i32) (i32.add (i32.const 10) (call_ref $i32-i32 (i32.const 42) (local.get $f))) From 013cf5d6618f7fa5cb210fd2692f14fb01e59ee0 Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Wed, 29 May 2024 11:17:33 -0700 Subject: [PATCH 094/130] Test `return_call*`s to callees that return more values than the caller does While a `call $f; return` sequence where `$f` returns more values than its caller is valid so long as the tail of `$f`'s returns match the caller's returns, however that situation is not valid for `return_call $f`. Tail callees must return the exact same number of results as the caller, not more. This case was not previously exercised in any of the spec tests. Procedural note: I am adding all these tests to the function-references proposal to avoid needing to make multiple PRs to multiple repos because `return_call_ref` was not introduced until this proposal. --- test/core/return_call.wast | 10 +++++++++- test/core/return_call_indirect.wast | 12 +++++++++++- test/core/return_call_ref.wast | 11 +++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/test/core/return_call.wast b/test/core/return_call.wast index 2f91f4deac..b9e8f8f010 100644 --- a/test/core/return_call.wast +++ b/test/core/return_call.wast @@ -188,7 +188,15 @@ ) "type mismatch" ) - +(assert_invalid + (module + (func $f (result i32 i32) unreachable) + (func (result i32) + return_call $f + ) + ) + "type mismatch" +) ;; Unbound function diff --git a/test/core/return_call_indirect.wast b/test/core/return_call_indirect.wast index acf0a72e06..aa158be256 100644 --- a/test/core/return_call_indirect.wast +++ b/test/core/return_call_indirect.wast @@ -508,7 +508,17 @@ ) "type mismatch" ) - +(assert_invalid + (module + (type $ty (func (result i32 i32))) + (import "env" "table" (table $table 0 funcref)) + (func (param i32) (result i32) + local.get 0 + return_call_indirect $table (type $ty) + ) + ) + "type mismatch" +) ;; Unbound type diff --git a/test/core/return_call_ref.wast b/test/core/return_call_ref.wast index 2b495f46e9..327dc84b89 100644 --- a/test/core/return_call_ref.wast +++ b/test/core/return_call_ref.wast @@ -374,3 +374,14 @@ ) "type mismatch" ) + +(assert_invalid + (module + (type $ty (func (result i32 i32))) + (func (param funcref) (result i32) + local.get 0 + return_call_ref $ty + ) + ) + "type mismatch" +) From f561006dc68a5e6d5453ac71d96a7c4d10527195 Mon Sep 17 00:00:00 2001 From: Ty Overby Date: Mon, 3 Jun 2024 07:14:32 -0700 Subject: [PATCH 095/130] Fixup out of date reference to rtt.get The overview currently contains this section: > A runtime type is an expression of type `rtt `, which is another form of opaque value type. It represents the static type `` at runtime. > In its plain form, a runtime type is obtained using the instruction `rtt.get` > ``` > (rtt.canon ) > ``` I believe that the text "`rtt.get`" was intended to be replaced by "`rtt.canon`" --- proposals/gc/Overview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/gc/Overview.md b/proposals/gc/Overview.md index 210c4e53be..7799a7f7ba 100644 --- a/proposals/gc/Overview.md +++ b/proposals/gc/Overview.md @@ -729,7 +729,7 @@ This instruction checks whether the runtime type stored in `` is a runt In order to cast down the type of a struct or array, the aggregate itself must be equipped with a suitable RTT. Attaching runtime type information to aggregates happens at allocation time. A runtime type is an expression of type `rtt `, which is another form of opaque value type. It represents the static type `` at runtime. -In its plain form, a runtime type is obtained using the instruction `rtt.get` +In its plain form, a runtime type is obtained using the instruction `rtt.canon` ``` (rtt.canon ) ``` From 87ae341cae5d09f4a46f8d25257396ccbf716ce7 Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Mon, 10 Jun 2024 18:24:11 -0400 Subject: [PATCH 096/130] [js-api] Move JS API legacy tests into test/legacy (#305) This moves legacy JS API tests, which use the old `try` instruction, into `test/legacy/js-api`. This also moves the legacy core tests from `test/legacy` to `test/legacy/core`. --- test/legacy/exceptions/{ => core}/rethrow.wast | 0 test/legacy/{ => exceptions/core}/run.py | 2 +- test/legacy/exceptions/{ => core}/throw.wast | 0 test/legacy/exceptions/{ => core}/try_catch.wast | 0 test/legacy/exceptions/{ => core}/try_delegate.wast | 0 .../exceptions/js-api}/basic.tentative.any.js | 0 .../exceptions/js-api}/identity.tentative.any.js | 0 7 files changed, 1 insertion(+), 1 deletion(-) rename test/legacy/exceptions/{ => core}/rethrow.wast (100%) rename test/legacy/{ => exceptions/core}/run.py (98%) rename test/legacy/exceptions/{ => core}/throw.wast (100%) rename test/legacy/exceptions/{ => core}/try_catch.wast (100%) rename test/legacy/exceptions/{ => core}/try_delegate.wast (100%) rename test/{js-api/exception => legacy/exceptions/js-api}/basic.tentative.any.js (100%) rename test/{js-api/exception => legacy/exceptions/js-api}/identity.tentative.any.js (100%) diff --git a/test/legacy/exceptions/rethrow.wast b/test/legacy/exceptions/core/rethrow.wast similarity index 100% rename from test/legacy/exceptions/rethrow.wast rename to test/legacy/exceptions/core/rethrow.wast diff --git a/test/legacy/run.py b/test/legacy/exceptions/core/run.py similarity index 98% rename from test/legacy/run.py rename to test/legacy/exceptions/core/run.py index f727aeef37..b2f6c314b3 100755 --- a/test/legacy/run.py +++ b/test/legacy/exceptions/core/run.py @@ -23,7 +23,7 @@ arguments = parser.parse_args() sys.argv = sys.argv[:1] -exceptions_test_files = glob.glob(os.path.join(inputDir, "exceptions", "*.wast")) +exceptions_test_files = glob.glob(os.path.join(inputDir, "*.wast")) wasmCommand = arguments.wasm jsCommand = arguments.js diff --git a/test/legacy/exceptions/throw.wast b/test/legacy/exceptions/core/throw.wast similarity index 100% rename from test/legacy/exceptions/throw.wast rename to test/legacy/exceptions/core/throw.wast diff --git a/test/legacy/exceptions/try_catch.wast b/test/legacy/exceptions/core/try_catch.wast similarity index 100% rename from test/legacy/exceptions/try_catch.wast rename to test/legacy/exceptions/core/try_catch.wast diff --git a/test/legacy/exceptions/try_delegate.wast b/test/legacy/exceptions/core/try_delegate.wast similarity index 100% rename from test/legacy/exceptions/try_delegate.wast rename to test/legacy/exceptions/core/try_delegate.wast diff --git a/test/js-api/exception/basic.tentative.any.js b/test/legacy/exceptions/js-api/basic.tentative.any.js similarity index 100% rename from test/js-api/exception/basic.tentative.any.js rename to test/legacy/exceptions/js-api/basic.tentative.any.js diff --git a/test/js-api/exception/identity.tentative.any.js b/test/legacy/exceptions/js-api/identity.tentative.any.js similarity index 100% rename from test/js-api/exception/identity.tentative.any.js rename to test/legacy/exceptions/js-api/identity.tentative.any.js From f30dfeeff5a340ec620700ac9c7d178064a60faa Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Fri, 14 Jun 2024 11:56:43 -0700 Subject: [PATCH 097/130] Throw TypeError if new Exception or getArg would expose v128 to JS (#309) Fixes #308 Fixes #295 --- document/js-api/index.bs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/document/js-api/index.bs b/document/js-api/index.bs index d3464d9210..6f96f2408f 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -1322,6 +1322,8 @@ constructor steps are: 1. Throw a {{TypeError}}. 1. Let |wasmPayload| be « ». 1. [=list/iterate|For each=] |value| and |resultType| of |payload| and |types|, paired linearly, + 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|. @@ -1341,6 +1343,9 @@ The getArg(|index|) method steps are: 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|]). From 901a9b0e33501535691707fe79115b14de9f457c Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Fri, 21 Jun 2024 11:08:51 -0700 Subject: [PATCH 098/130] [js-api] Sync with WPT tests (#306) This reflects the WPT changes in https://github.com/web-platform-tests/wpt/commit/5623804845b906f272c3f808e717c50f5cd8e14e https://github.com/web-platform-tests/wpt/commit/e0c0429460a5982c4e4889026dbfbcb60c3c9ef9 and https://github.com/web-platform-tests/wpt/pull/42764 `wasm-module-builder.js` was not fully synced with the WPT repo; the changes reflected were just enough to pass the tests. This also changes `worker` from `dedicatedworker` in `legacy/exceptions/js-api/basic.tentative.any.js`, even though the matching WPT test has not been updated to use it, because all other tests seem to be using `dedicatedworker` now. --- .../exception/constructor.tentative.any.js | 2 +- test/js-api/exception/getArg.tentative.any.js | 2 +- test/js-api/exception/is.tentative.any.js | 2 +- .../exception/toString.tentative.any.js | 2 +- test/js-api/instanceTestFactory.js | 6 +- test/js-api/module/exports.any.js | 6 +- test/js-api/tag/constructor.tentative.any.js | 2 +- test/js-api/tag/toString.tentative.any.js | 2 +- test/js-api/tag/type.tentative.any.js | 2 +- test/js-api/wasm-module-builder.js | 57 +++++++++++++++---- .../exceptions/js-api/basic.tentative.any.js | 11 ++-- .../js-api/identity.tentative.any.js | 2 +- 12 files changed, 66 insertions(+), 30 deletions(-) diff --git a/test/js-api/exception/constructor.tentative.any.js b/test/js-api/exception/constructor.tentative.any.js index 7ad08e1883..a46d1816c3 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 4b72c61f47..6d56ac8c6a 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(() => { diff --git a/test/js-api/exception/is.tentative.any.js b/test/js-api/exception/is.tentative.any.js index e28a88a3c5..840d00bf0d 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/toString.tentative.any.js b/test/js-api/exception/toString.tentative.any.js index 00e801a6fc..6885cf0deb 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 ac468947ec..7936810a52 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/module/exports.any.js b/test/js-api/module/exports.any.js index 40a3935a4a..0d62725ae4 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 de63e7bf46..54edf8c8f5 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 ad9a4ba152..76fff0feef 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 index 9d2f0de1a0..58c96078bf 100644 --- a/test/js-api/tag/type.tentative.any.js +++ b/test/js-api/tag/type.tentative.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/assertions.js function assert_type(argument) { diff --git a/test/js-api/wasm-module-builder.js b/test/js-api/wasm-module-builder.js index d0f9e78bcd..58b616f013 100644 --- a/test/js-api/wasm-module-builder.js +++ b/test/js-api/wasm-module-builder.js @@ -97,8 +97,35 @@ 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; + +// 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 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; @@ -146,14 +173,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]); @@ -554,6 +581,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 @@ -898,11 +935,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); } } }); @@ -1161,7 +1198,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}); diff --git a/test/legacy/exceptions/js-api/basic.tentative.any.js b/test/legacy/exceptions/js-api/basic.tentative.any.js index acf644f904..9b82d2eaf4 100644 --- a/test/legacy/exceptions/js-api/basic.tentative.any.js +++ b/test/legacy/exceptions/js-api/basic.tentative.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/wasm-module-builder.js function assert_throws_wasm(fn, message) { @@ -11,8 +11,7 @@ function assert_throws_wasm(fn, message) { } promise_test(async () => { - const kWasmAnyRef = 0x6f; - const kSig_v_r = makeSig([kWasmAnyRef], []); + const kSig_v_r = makeSig([kWasmExternRef], []); const builder = new WasmModuleBuilder(); const tagIndex = builder.addTag(kSig_v_r); builder.addFunction("throw_param", kSig_v_r) @@ -48,7 +47,7 @@ promise_test(async () => { const tagIndex = builder.addTag(kSig_v_a); builder.addFunction("throw_null", kSig_v_v) .addBody([ - kExprRefNull, kWasmAnyFunc, + kExprRefNull, kAnyFuncCode, kExprThrow, tagIndex, ]) .exportFunc(); @@ -82,7 +81,7 @@ promise_test(async () => { kExprCatch, tagIndex, kExprReturn, kExprEnd, - kExprRefNull, kWasmAnyRef, + kExprRefNull, kExternRefCode, ]) .exportFunc(); @@ -106,7 +105,7 @@ promise_test(async () => { kExprCatchAll, kExprRethrow, 0x00, kExprEnd, - kExprRefNull, kWasmAnyRef, + kExprRefNull, kExternRefCode, ]) .exportFunc(); diff --git a/test/legacy/exceptions/js-api/identity.tentative.any.js b/test/legacy/exceptions/js-api/identity.tentative.any.js index e431197d1a..0cdb41d229 100644 --- a/test/legacy/exceptions/js-api/identity.tentative.any.js +++ b/test/legacy/exceptions/js-api/identity.tentative.any.js @@ -1,4 +1,4 @@ -// 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 From 0b840dad9f6f0092058c20616465206c80681a50 Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Fri, 21 Jun 2024 14:06:14 -0700 Subject: [PATCH 099/130] Wrap explainer text to 80 columns (#311) --- proposals/exception-handling/Exceptions.md | 118 +++++++++++---------- 1 file changed, 61 insertions(+), 57 deletions(-) diff --git a/proposals/exception-handling/Exceptions.md b/proposals/exception-handling/Exceptions.md index bc508eff9a..37cb994c9c 100644 --- a/proposals/exception-handling/Exceptions.md +++ b/proposals/exception-handling/Exceptions.md @@ -36,8 +36,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 the *catch clauses* 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,21 +86,22 @@ 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. 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. +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. ### 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. +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_table` instruction, and ends with an `end` -instruction. That is, a try 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: ``` @@ -109,10 +110,11 @@ try_table blocktype catch* end ``` -A try block contains zero or more _catch clauses_. If there are no catch clauses, then the try block does not catch any exceptions. +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. +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: ``` @@ -121,16 +123,16 @@ catch_ref tag label catch_all label catch_all_ref label ``` -All forms have a label which is branched to when an exception is cought (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. +All forms have a label which is branched to when an exception is cought (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 clause. -Because `try_table` defines a control-flow block, it 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 @@ -160,37 +162,38 @@ 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 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. +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. If no catch clauses were matched, the exception is implicitly rethrown. -Note that a caught exception can be rethrown explicitly using the `exnref` and the `throw_ref` instruction. +Note that a caught exception can be rethrown explicitly using the `exnref` and +the `throw_ref` instruction. ### Rethrowing an exception -The `throw_ref` takes an operand of type `exnref` and re-throws the corresponding caught exception. -If the operand is null, a trap occurs. +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 -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. +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 `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 `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. +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 @@ -232,22 +235,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 a `catch[_all]_ref` clause -and rethrown by `throw_ref`. +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: @@ -331,16 +334,17 @@ document](https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md). 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. +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. +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 @@ -439,13 +443,13 @@ 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 instructions -The control flow instructions are extended to define try blocks and -throws as follows: +The control flow instructions are extended to define try blocks and throws as +follows: | Name | Opcode | Immediates | Description | | ---- | ---- | ---- | ---- | From f0282c8ce0932a5dfb248cb320a341492a14bf91 Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Fri, 21 Jun 2024 15:39:08 -0700 Subject: [PATCH 100/130] Fix typo in explainer (#312) --- proposals/exception-handling/Exceptions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/exception-handling/Exceptions.md b/proposals/exception-handling/Exceptions.md index 37cb994c9c..d982592ced 100644 --- a/proposals/exception-handling/Exceptions.md +++ b/proposals/exception-handling/Exceptions.md @@ -123,7 +123,7 @@ catch_ref tag label catch_all label catch_all_ref label ``` -All forms have a label which is branched to when an exception is cought (see +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. From 2f5a7c524fdc4dec280c6a53bc3cc800b6ad1c11 Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Mon, 24 Jun 2024 20:57:01 -0700 Subject: [PATCH 101/130] [js-api] Update wasm-module-builder.js for exnref (#314) This pulls in some exnref-related changes from https://github.com/v8/v8/blob/main/test/mjsunit/wasm/wasm-module-builder.js but does not sync with it completely. That v8 version contains a lot of features from new proposals that are not really relevant to EH and exnref, so this pulls only the relevant EH parts in. This also renames `kWasmStmt` to `kWasmVoid` as in the V8 version, because it looks more intuitive. Also renames `kTagAttribute` to `kExceptionAttribute`. --- test/js-api/wasm-module-builder.js | 25 +++++++++++++------ .../exceptions/js-api/basic.tentative.any.js | 4 +-- .../js-api/identity.tentative.any.js | 10 ++++---- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/test/js-api/wasm-module-builder.js b/test/js-api/wasm-module-builder.js index 58b616f013..b23cea5f91 100644 --- a/test/js-api/wasm-module-builder.js +++ b/test/js-api/wasm-module-builder.js @@ -90,8 +90,8 @@ 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; @@ -107,6 +107,8 @@ 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; @@ -116,6 +118,8 @@ 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; @@ -137,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]); @@ -217,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; @@ -230,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; @@ -494,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; @@ -976,7 +987,7 @@ class WasmModuleBuilder { 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); @@ -1079,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); } }); diff --git a/test/legacy/exceptions/js-api/basic.tentative.any.js b/test/legacy/exceptions/js-api/basic.tentative.any.js index 9b82d2eaf4..c57c79cca6 100644 --- a/test/legacy/exceptions/js-api/basic.tentative.any.js +++ b/test/legacy/exceptions/js-api/basic.tentative.any.js @@ -76,7 +76,7 @@ promise_test(async () => { const tagIndex= builder.addTag(kSig_v_r); builder.addFunction("catch_exception", kSig_r_v) .addBody([ - kExprTry, kWasmStmt, + kExprTry, kWasmVoid, kExprCallFunction, fnIndex, kExprCatch, tagIndex, kExprReturn, @@ -100,7 +100,7 @@ promise_test(async () => { const fnIndex = builder.addImport("module", "fn", kSig_v_v); builder.addFunction("catch_and_rethrow", kSig_r_v) .addBody([ - kExprTry, kWasmStmt, + kExprTry, kWasmVoid, kExprCallFunction, fnIndex, kExprCatchAll, kExprRethrow, 0x00, diff --git a/test/legacy/exceptions/js-api/identity.tentative.any.js b/test/legacy/exceptions/js-api/identity.tentative.any.js index 0cdb41d229..36651c7d5b 100644 --- a/test/legacy/exceptions/js-api/identity.tentative.any.js +++ b/test/legacy/exceptions/js-api/identity.tentative.any.js @@ -35,7 +35,7 @@ test(() => { builder .addFunction("catch_js_tag_rethrow", kSig_v_v) .addBody([ - kExprTry, kWasmStmt, + kExprTry, kWasmVoid, kExprCallFunction, throwJSTagExnIndex, kExprCatch, jsTagIndex, kExprDrop, @@ -49,7 +49,7 @@ test(() => { builder .addFunction("catch_wasm_tag_rethrow", kSig_v_v) .addBody([ - kExprTry, kWasmStmt, + kExprTry, kWasmVoid, kExprCallFunction, throwWasmTagExnIndex, kExprCatch, wasmTagIndex, kExprDrop, @@ -63,7 +63,7 @@ test(() => { builder .addFunction("catch_all_js_tag_rethrow", kSig_v_v) .addBody([ - kExprTry, kWasmStmt, + kExprTry, kWasmVoid, kExprCallFunction, throwJSTagExnIndex, kExprCatchAll, kExprRethrow, 0x00, @@ -76,7 +76,7 @@ test(() => { builder .addFunction("catch_all_wasm_tag_rethrow", kSig_v_v) .addBody([ - kExprTry, kWasmStmt, + kExprTry, kWasmVoid, kExprCallFunction, throwWasmTagExnIndex, kExprCatchAll, kExprRethrow, 0x00, @@ -103,7 +103,7 @@ test(() => { builder .addFunction("catch_js_tag_throw_payload", kSig_v_v) .addBody([ - kExprTry, kWasmStmt, + kExprTry, kWasmVoid, kExprCallFunction, throwJSTagExnIndex, kExprCatch, jsTagIndex, kExprThrow, jsTagIndex, From e2c8d9084e856dd6043b3df6ff863b68f81890b6 Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Mon, 24 Jun 2024 20:57:15 -0700 Subject: [PATCH 102/130] [js-api] Re-add old tests to test/js-api/exception (#315) These two tests used to be in https://github.com/WebAssembly/exception-handling/tree/main/test/js-api/exception and were moved into https://github.com/WebAssembly/exception-handling/tree/main/test/legacy/exceptions/js-api in #305. I'm planning new version of these tests that use `try_table` and `throw_ref` in https://github.com/WebAssembly/exception-handling/tree/main/test/js-api/exception, but it wouldn't require to rewrite the whole tests, but copying these tests into the this directory and modify them in a single PR makes Github think these are brand-new files, resulting in a large diff containing the whole files that is difficult to review (and which has been reviewed and in the repo for a long time already). So I'm making a PR that only re-adds these file here so that I can add changes to these files in another PR. --- test/js-api/exception/basic.tentative.any.js | 120 +++++++++++++ .../exception/identity.tentative.any.js | 170 ++++++++++++++++++ 2 files changed, 290 insertions(+) create mode 100644 test/js-api/exception/basic.tentative.any.js create mode 100644 test/js-api/exception/identity.tentative.any.js 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 0000000000..c57c79cca6 --- /dev/null +++ b/test/js-api/exception/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/js-api/exception/identity.tentative.any.js b/test/js-api/exception/identity.tentative.any.js new file mode 100644 index 0000000000..36651c7d5b --- /dev/null +++ b/test/js-api/exception/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"); From 2adc918d9ce5df6405d78a5b990b6318fef6cb9a Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 25 Jun 2024 19:54:22 -0700 Subject: [PATCH 103/130] Fix typo in execution of array.copy (#546) --- document/core/exec/instructions.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index e1c5f43b6e..f7c1bea4bf 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -1217,13 +1217,13 @@ Reference Instructions a. Push the value :math:`\REFARRAYADDR~a_1` to the stack. - b. Assert: due to the earlier check against the memory size, :math:`d+n-1 < 2^{32}`. + b. Assert: due to the earlier check against the array size, :math:`d+n-1 < 2^{32}`. c. Push the value :math:`\I32.\CONST~(d+n-1)` to the stack. d. Push the value :math:`\REFARRAYADDR~a_2` to the stack. - e. Assert: due to the earlier check against the memory size, :math:`s+n-1 < 2^{32}`. + e. Assert: due to the earlier check against the array size, :math:`s+n-1 < 2^{32}`. f. Push the value :math:`\I32.\CONST~(s+n-1)` to the stack. From cfb909da069ae6904406fc1c799d60cafc9ea184 Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Thu, 27 Jun 2024 17:37:46 -0700 Subject: [PATCH 104/130] Rename section 4.7 from "Tags" to "Exceptions" (#317) This section is about general exception-related topics, not just tags. --- document/js-api/index.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/document/js-api/index.bs b/document/js-api/index.bs index 6f96f2408f..0bf129e60b 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -1187,7 +1187,7 @@ The algorithm ToWebAssemblyValue(|v|, |type|) coerces a JavaScript va -

Tags

+

Exceptions

Exception types

From 8e8700d4ee3910e813318a1894df3bce7fa1ea0f Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 28 Jun 2024 10:59:51 -0700 Subject: [PATCH 105/130] Add missing memory specifier to memory.init execution semantics --- document/core/exec/instructions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index e4d77cdb85..4abdf5b408 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -2437,7 +2437,7 @@ Memory Instructions 20. Push the value :math:`\I32.\CONST~b` to the stack. -21. Execute the instruction :math:`\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}`. +21. Execute the instruction :math:`\I32\K{.}\STORE\K{8}~x~\{ \OFFSET~0, \ALIGN~0 \}`. 22. Assert: due to the earlier check against the memory size, :math:`d+1 < 2^{32}`. From 48158db77877133ce317fcb7c67be09ebc0b9334 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Mon, 1 Jul 2024 08:54:48 +0200 Subject: [PATCH 106/130] Typo --- document/core/valid/types.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/document/core/valid/types.rst b/document/core/valid/types.rst index 39ab9601ed..931af6e823 100644 --- a/document/core/valid/types.rst +++ b/document/core/valid/types.rst @@ -51,7 +51,8 @@ Vector Types Heap Types ~~~~~~~~~~ -Concrete :ref:`Heap types ` are only valid when the :ref:`type index ` is. +Concrete :ref:`heap types ` are only valid when the :ref:`type index ` is, +while abstract ones are vacuously valid. :math:`\absheaptype` .................... From d73ac324e6ace2a190bf9a1af4ebd1638dd26d48 Mon Sep 17 00:00:00 2001 From: Rao Xiaojia Date: Tue, 2 Jul 2024 11:08:14 +0100 Subject: [PATCH 107/130] [spec] Typo in rules for vector load/store_lane (#1763) --- document/core/valid/instructions.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/document/core/valid/instructions.rst b/document/core/valid/instructions.rst index 44bd241912..6a8a110a57 100644 --- a/document/core/valid/instructions.rst +++ b/document/core/valid/instructions.rst @@ -1098,7 +1098,7 @@ Memory Instructions \qquad C.\CMEMS[0] = \memtype \qquad - 2^{\memarg.\ALIGN} < N/8 + 2^{\memarg.\ALIGN} \leq N/8 }{ C \vdashinstr \K{v128.}\LOAD{N}\K{\_lane}~\memarg~\laneidx : [\I32~\V128] \to [\V128] } @@ -1122,7 +1122,7 @@ Memory Instructions \qquad C.\CMEMS[0] = \memtype \qquad - 2^{\memarg.\ALIGN} < N/8 + 2^{\memarg.\ALIGN} \leq N/8 }{ C \vdashinstr \K{v128.}\STORE{N}\K{\_lane}~\memarg~\laneidx : [\I32~\V128] \to [] } From d6ea0c9638a651c2ae0752abc6c36094046c5828 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Wed, 3 Jul 2024 11:36:13 +0200 Subject: [PATCH 108/130] Some more tests --- test/core/token.wast | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/core/token.wast b/test/core/token.wast index 624bdca6d8..44e41f22bc 100644 --- a/test/core/token.wast +++ b/test/core/token.wast @@ -88,6 +88,12 @@ ) "unknown operator" ) +(assert_malformed + (module quote + "(func (block $l (i32.const 0) (br_table 0$\"l\")))" + ) + "unknown operator" +) (module (func (block $l (i32.const 0) (br_table $l 0))) @@ -98,6 +104,12 @@ ) "unknown label" ) +(assert_malformed + (module quote + "(func (block $l (i32.const 0) (br_table $\"l\"0)))" + ) + "unknown operator" +) (module (func (block $l (i32.const 0) (br_table $l $l))) @@ -108,6 +120,12 @@ ) "unknown label" ) +(assert_malformed + (module quote + "(func (block $l (i32.const 0) (br_table $\"l\"$l)))" + ) + "unknown operator" +) (module (func (block $l0 (i32.const 0) (br_table $l0))) From 25a68820ea328a81e3a6c18f2bbeccb96d76cbc7 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Wed, 3 Jul 2024 13:20:15 +0200 Subject: [PATCH 109/130] Fallout --- README.md | 15 ++------------- document/core/appendix/custom.rst | 4 ++-- document/core/conf.py | 4 ++-- document/core/text/values.rst | 2 +- test/custom/custom/custom_annot.wast | 2 +- 5 files changed, 8 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 8ab431dc68..533bcf1758 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,5 @@ -[![CI for specs](https://github.com/WebAssembly/annotations/actions/workflows/ci-spec.yml/badge.svg)](https://github.com/WebAssembly/annotations/actions/workflows/ci-spec.yml) -[![CI for interpreter & tests](https://github.com/WebAssembly/annotations/actions/workflows/ci-interpreter.yml/badge.svg)](https://github.com/WebAssembly/annotations/actions/workflows/ci-interpreter.yml) - -# Custom Annotations Proposal for WebAssembly - -This repository is a clone of [github.com/WebAssembly/spec/](https://github.com/WebAssembly/spec/). -It is meant for discussion, prototype specification and implementation of a proposal to add support for custom annotations to the WebAssembly text format. - -See the [overview](proposals/annotations/Overview.md) for a summary of the proposal. - -See draft spec at [webassembly.github.io/annotations](https://webassembly.github.io/annotations/). - -Original `README` from upstream repository follows... +[![CI for specs](https://github.com/WebAssembly/spec/actions/workflows/ci-spec.yml/badge.svg)](https://github.com/WebAssembly/spec/actions/workflows/ci-spec.yml) +[![CI for interpreter & tests](https://github.com/WebAssembly/spec/actions/workflows/ci-interpreter.yml/badge.svg)](https://github.com/WebAssembly/spec/actions/workflows/ci-interpreter.yml) # spec diff --git a/document/core/appendix/custom.rst b/document/core/appendix/custom.rst index 6dbdbc5c52..4f84483af2 100644 --- a/document/core/appendix/custom.rst +++ b/document/core/appendix/custom.rst @@ -150,7 +150,7 @@ It consists of an :ref:`indirect name map ` assigning lo .. _binary-typenamesec: Type Names -.............. +.......... The *type name subsection* has the id 4. It consists of a :ref:`name map ` assigning type names to :ref:`type indices `. @@ -295,7 +295,7 @@ directly after the :math:`\text{type}` keyword, or if present, after the followi Field Names ........... -A *field name annotation* must be placed on the :ref:`field ` of a :ref:`structure type `, +A *field name annotation* must be placed on the field of a :ref:`structure type `, directly after the :math:`\text{field}` keyword, or if present, after the following field :ref:`identifier `. It may only be placed on a declaration that declares exactly one field. diff --git a/document/core/conf.py b/document/core/conf.py index 86410d0955..eab24731f2 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 = 'annotations' +repo = 'spec' # The name of the proposal it represents, if any -proposal = 'custom annotations' +proposal = '' # The draft version string (clear out for release cuts) draft = ' (Draft ' + date.today().strftime("%Y-%m-%d") + ')' diff --git a/document/core/text/values.rst b/document/core/text/values.rst index 3c74112d1a..80a142fa15 100644 --- a/document/core/text/values.rst +++ b/document/core/text/values.rst @@ -248,7 +248,7 @@ Symbolic *identifiers* that stand in lieu of indices start with :math:`\text{\$} \end{array} .. note:: - The value of an identifier character is its the Unicode codepoint denoting it. + The value of an identifier character is the Unicode codepoint denoting it. .. _text-id-fresh: diff --git a/test/custom/custom/custom_annot.wast b/test/custom/custom/custom_annot.wast index 19ed6bd77a..011a5776fc 100644 --- a/test/custom/custom/custom_annot.wast +++ b/test/custom/custom/custom_annot.wast @@ -43,7 +43,7 @@ ) -;; Malformed placement +;; Malformed placement (assert_malformed_custom (module quote "(@custom \"bla\" here)") From 583775527f151276b60876aab99162da14226283 Mon Sep 17 00:00:00 2001 From: YAMAMOTO Takashi Date: Thu, 4 Jul 2024 16:24:35 +0900 Subject: [PATCH 110/130] [interpreter] Fix crashes on try_table with parameters (#321) The test case was ported from toywasm. --- interpreter/exec/eval.ml | 2 +- test/core/try_table.wast | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/interpreter/exec/eval.ml b/interpreter/exec/eval.ml index 13f82a9d8a..17baad842d 100644 --- a/interpreter/exec/eval.ml +++ b/interpreter/exec/eval.ml @@ -244,7 +244,7 @@ let rec step (c : config) : config = 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', [Handler (n2, cs, (args, [Label (n2, [], ([], 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', [] diff --git a/test/core/try_table.wast b/test/core/try_table.wast index e64b6c189f..43ae52ccff 100644 --- a/test/core/try_table.wast +++ b/test/core/try_table.wast @@ -238,6 +238,10 @@ ) ) ) + + (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)) @@ -294,6 +298,8 @@ (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) From c5b968f31fbffff93f43c7b71c80e7075c913a4f Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Thu, 4 Jul 2024 12:16:53 -0700 Subject: [PATCH 111/130] [js-api] Update basic and identity tests for exnref (#316) This updates `basic.tentative.any.js` and `identity.tentative.any.js` tests to use the new instructions (`try_table` and `throw_ref`). In addition to converting existing tests to use the new instruction while maintaining the semantics, I added a new test in `basic.tentative.any.js` that makes use of all four `catch` clause variants to show all catch clauses works well in JS API tests. These new tests reauire `--js-flags=--experimental-wasm-exnref` argument to chrome, which is not currently supported in WPT out of the box. I've instead confirmed these run with chrome web tests infrastructure (https://chromium.googlesource.com/chromium/src/+/HEAD/docs/testing/web_tests.md#Running-Web-Tests). --- test/js-api/exception/basic.tentative.any.js | 90 ++++++++++++--- .../exception/identity.tentative.any.js | 107 +++++++++++------- .../exceptions/js-api/basic.tentative.any.js | 2 +- 3 files changed, 146 insertions(+), 53 deletions(-) diff --git a/test/js-api/exception/basic.tentative.any.js b/test/js-api/exception/basic.tentative.any.js index c57c79cca6..09f8479aa8 100644 --- a/test/js-api/exception/basic.tentative.any.js +++ b/test/js-api/exception/basic.tentative.any.js @@ -13,11 +13,11 @@ function assert_throws_wasm(fn, message) { promise_test(async () => { const kSig_v_r = makeSig([kWasmExternRef], []); const builder = new WasmModuleBuilder(); - const tagIndex = builder.addTag(kSig_v_r); + const tagIndexExternref = builder.addTag(kSig_v_r); builder.addFunction("throw_param", kSig_v_r) .addBody([ kExprLocalGet, 0, - kExprThrow, tagIndex, + kExprThrow, tagIndexExternref, ]) .exportFunc(); const buffer = builder.toBuffer(); @@ -44,11 +44,11 @@ promise_test(async () => { promise_test(async () => { const builder = new WasmModuleBuilder(); - const tagIndex = builder.addTag(kSig_v_a); + const tagIndexAnyref = builder.addTag(kSig_v_a); builder.addFunction("throw_null", kSig_v_v) .addBody([ kExprRefNull, kAnyFuncCode, - kExprThrow, tagIndex, + kExprThrow, tagIndexAnyref, ]) .exportFunc(); const buffer = builder.toBuffer(); @@ -58,11 +58,11 @@ promise_test(async () => { promise_test(async () => { const builder = new WasmModuleBuilder(); - const tagIndex = builder.addTag(kSig_v_i); + const tagIndexI32 = builder.addTag(kSig_v_i); builder.addFunction("throw_int", kSig_v_v) .addBody([ ...wasmI32Const(7), - kExprThrow, tagIndex, + kExprThrow, tagIndexI32, ]) .exportFunc(); const buffer = builder.toBuffer(); @@ -73,12 +73,18 @@ promise_test(async () => { promise_test(async () => { const builder = new WasmModuleBuilder(); const fnIndex = builder.addImport("module", "fn", kSig_v_v); - const tagIndex= builder.addTag(kSig_v_r); + const tagIndexExternref = builder.addTag(kSig_v_r); + builder.addFunction("catch_exception", kSig_r_v) .addBody([ - kExprTry, kWasmVoid, - kExprCallFunction, fnIndex, - kExprCatch, tagIndex, + kExprBlock, kWasmVoid, + kExprBlock, kExternRefCode, + kExprTryTable, kWasmVoid, 1, + kCatchNoRef, tagIndexExternref, 0, + kExprCallFunction, fnIndex, + kExprEnd, + kExprBr, 1, + kExprEnd, kExprReturn, kExprEnd, kExprRefNull, kExternRefCode, @@ -100,10 +106,15 @@ promise_test(async () => { 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, + kExprBlock, kWasmVoid, + kExprBlock, kExnRefCode, + kExprTryTable, kWasmVoid, 1, + kCatchAllRef, 0, + kExprCallFunction, fnIndex, + kExprEnd, + kExprBr, 1, + kExprEnd, + kExprThrowRef, kExprEnd, kExprRefNull, kExternRefCode, ]) @@ -118,3 +129,54 @@ promise_test(async () => { }); 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/identity.tentative.any.js b/test/js-api/exception/identity.tentative.any.js index 36651c7d5b..802e7053ac 100644 --- a/test/js-api/exception/identity.tentative.any.js +++ b/test/js-api/exception/identity.tentative.any.js @@ -22,6 +22,9 @@ test(() => { 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: { throwJSTagExn: function() { throw jsTagExn; }, @@ -31,55 +34,73 @@ test(() => { }; // Call a JS function that throws an exception using a JS-defined tag, catches - // it with a 'catch' instruction, and rethrows it. + // it with a 'catch_ref' instruction, and rethrows it. builder - .addFunction("catch_js_tag_rethrow", kSig_v_v) + .addFunction("catch_ref_js_tag_throw_ref", kSig_v_v) .addBody([ - kExprTry, kWasmVoid, - kExprCallFunction, throwJSTagExnIndex, - kExprCatch, jsTagIndex, - kExprDrop, - kExprRethrow, 0x00, + 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' instruction, and rethrows it. + // catches it with a 'catch_ref' instruction, and rethrows it. builder - .addFunction("catch_wasm_tag_rethrow", kSig_v_v) + .addFunction("catch_ref_wasm_tag_throw_ref", kSig_v_v) .addBody([ - kExprTry, kWasmVoid, - kExprCallFunction, throwWasmTagExnIndex, - kExprCatch, wasmTagIndex, - 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' instruction, and rethrows it. + // it with a 'catch_all_ref' instruction, and rethrows it. builder - .addFunction("catch_all_js_tag_rethrow", kSig_v_v) + .addFunction("catch_all_ref_js_tag_throw_ref", kSig_v_v) .addBody([ - kExprTry, kWasmVoid, - kExprCallFunction, throwJSTagExnIndex, - 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' instruction, and rethrows it. + // catches it with a 'catch_all_ref' instruction, and rethrows it. builder - .addFunction("catch_all_wasm_tag_rethrow", kSig_v_v) + .addFunction("catch_all_ref_wasm_tag_throw_ref", kSig_v_v) .addBody([ - kExprTry, kWasmVoid, - kExprCallFunction, throwWasmTagExnIndex, - kExprCatchAll, - kExprRethrow, 0x00, + kExprBlock, kWasmVoid, + kExprBlock, kExnRefCode, + kExprTryTable, kWasmVoid, 1, + kCatchAllRef, 0, + kExprCallFunction, throwWasmTagExnIndex, + kExprEnd, + kExprBr, 1, + kExprEnd, + kExprThrowRef, kExprEnd ]) .exportFunc(); @@ -89,12 +110,17 @@ test(() => { builder .addFunction("catch_js_tag_return_payload", kSig_i_v) .addBody([ - kExprTry, kWasmI32, - kExprCallFunction, throwJSTagExnIndex, - kExprI32Const, 0x00, - kExprCatch, jsTagIndex, + kExprBlock, kWasmVoid, + kExprBlock, kWasmI32, + kExprTryTable, kWasmVoid, 1, + kCatchNoRef, jsTagIndex, 0, + kExprCallFunction, throwJSTagExnIndex, + kExprEnd, + kExprBr, 1, + kExprEnd, kExprReturn, - kExprEnd + kExprEnd, + kExprI32Const, 0 ]) .exportFunc(); @@ -103,9 +129,14 @@ test(() => { builder .addFunction("catch_js_tag_throw_payload", kSig_v_v) .addBody([ - kExprTry, kWasmVoid, - kExprCallFunction, throwJSTagExnIndex, - kExprCatch, jsTagIndex, + kExprBlock, kWasmVoid, + kExprBlock, kWasmI32, + kExprTryTable, kWasmVoid, 1, + kCatchNoRef, jsTagIndex, 0, + kExprCallFunction, throwJSTagExnIndex, + kExprEnd, + kExprBr, 1, + kExprEnd, kExprThrow, jsTagIndex, kExprEnd ]) @@ -117,7 +148,7 @@ test(() => { // 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(); + 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 @@ -126,7 +157,7 @@ test(() => { assert_not_equals(e, jsTagExnDiffPayload); } try { - result.instance.exports.catch_all_js_tag_rethrow(); + result.instance.exports.catch_all_ref_js_tag_throw_ref(); } catch (e) { assert_equals(e, jsTagExn); assert_not_equals(e, jsTagExnSamePayload); @@ -139,14 +170,14 @@ test(() => { wasmTagExnSamePayload = new WebAssembly.Exception(wasmTag, [42]); wasmTagExnDiffPayload = new WebAssembly.Exception(wasmTag, [53]); try { - result.instance.exports.catch_wasm_tag_rethrow(); + result.instance.exports.catch_ref_wasm_tag_throw_ref(); } 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(); + result.instance.exports.catch_all_ref_wasm_tag_throw_ref(); } catch (e) { assert_equals(e, wasmTagExn); assert_not_equals(e, wasmTagExnSamePayload); diff --git a/test/legacy/exceptions/js-api/basic.tentative.any.js b/test/legacy/exceptions/js-api/basic.tentative.any.js index c57c79cca6..81478529a4 100644 --- a/test/legacy/exceptions/js-api/basic.tentative.any.js +++ b/test/legacy/exceptions/js-api/basic.tentative.any.js @@ -73,7 +73,7 @@ promise_test(async () => { promise_test(async () => { const builder = new WasmModuleBuilder(); const fnIndex = builder.addImport("module", "fn", kSig_v_v); - const tagIndex= builder.addTag(kSig_v_r); + const tagIndex = builder.addTag(kSig_v_r); builder.addFunction("catch_exception", kSig_r_v) .addBody([ kExprTry, kWasmVoid, From 4c93161c9d3fb1e20126ce1903be33308b494ba1 Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Thu, 4 Jul 2024 12:17:16 -0700 Subject: [PATCH 112/130] [js-api] Add tests for WebAssembly.JSTag (#319) This adds tests for `WebAssembly.JSTag`. The tests are adapted from https://github.com/v8/v8/blob/main/test/mjsunit/wasm/exnref-api.js. Confirmed that they run successfully with web test infrastructure in Chrome with `--js-flags=--experimental-wasm-exnref` command line argument. The only thing failing there was the shadowrealm test, which I think we should add a separate expectation files like the existing `***.tentative.any.shadowrealm-expected.txt` in https://github.com/chromium/chromium/tree/main/third_party/blink/web_tests/external/wpt/wasm/jsapi/exception. But given that we don't host these files in this EH repo, I'll just upload the js files. --- test/js-api/exception/jsTag.tentative.any.js | 121 +++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 test/js-api/exception/jsTag.tentative.any.js 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 0000000000..c5db553701 --- /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"); From ccdbf4f5b86ba9eef58022b27006236082d72d4c Mon Sep 17 00:00:00 2001 From: Dmitry Polyakov <91780534+eduVcJy0UE0cy0zo3BS7XYO3b@users.noreply.github.com> Date: Fri, 5 Jul 2024 04:18:23 +0000 Subject: [PATCH 113/130] Update instructions.rst According to other places in docs and my research on dumped wat files, I consider that funcidx for this call places on stack, not as parameter. --- document/core/syntax/instructions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/document/core/syntax/instructions.rst b/document/core/syntax/instructions.rst index 93cdbc9054..07a7c8bdcf 100644 --- a/document/core/syntax/instructions.rst +++ b/document/core/syntax/instructions.rst @@ -764,7 +764,7 @@ Instructions in this group affect the flow of control. \CALLREF~\typeidx \\&&|& \CALLINDIRECT~\tableidx~\typeidx \\&&|& \RETURNCALL~\funcidx \\&&|& - \RETURNCALLREF~\funcidx \\&&|& + \RETURNCALLREF~\typeidx \\&&|& \RETURNCALLINDIRECT~\tableidx~\typeidx \\ \end{array} From caf5877cd9914287383b4e8d9a34031bdc6ce2ef Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Wed, 10 Jul 2024 17:33:35 -0400 Subject: [PATCH 114/130] Fix type in return_call_ref.wast (#549) The modified test case previously had two errors. Fix the unintentional error, ensuring that the test properly tests the intended error. --- test/core/return_call_ref.wast | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/core/return_call_ref.wast b/test/core/return_call_ref.wast index 327dc84b89..1d7e2755c3 100644 --- a/test/core/return_call_ref.wast +++ b/test/core/return_call_ref.wast @@ -378,7 +378,7 @@ (assert_invalid (module (type $ty (func (result i32 i32))) - (func (param funcref) (result i32) + (func (param (ref $ty)) (result i32) local.get 0 return_call_ref $ty ) From e8529784a15b8b8c11b7e4288d5e55b0b6694bad Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Thu, 11 Jul 2024 10:29:52 -0400 Subject: [PATCH 115/130] Add tests that call_ref does not accept funcref (#550) --- test/core/call_ref.wast | 10 ++++++++++ test/core/return_call_ref.wast | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/test/core/call_ref.wast b/test/core/call_ref.wast index da480a7f23..aa9ac7b873 100644 --- a/test/core/call_ref.wast +++ b/test/core/call_ref.wast @@ -206,3 +206,13 @@ ) "type mismatch" ) + +(assert_invalid + (module + (type $t (func)) + (func $f (param $r funcref) + (call_ref $t (local.get $r)) + ) + ) + "type mismatch" +) diff --git a/test/core/return_call_ref.wast b/test/core/return_call_ref.wast index 1d7e2755c3..5f5a7cba72 100644 --- a/test/core/return_call_ref.wast +++ b/test/core/return_call_ref.wast @@ -375,6 +375,16 @@ "type mismatch" ) +(assert_invalid + (module + (type $t (func)) + (func $f (param $r funcref) + (return_call_ref $t (local.get $r)) + ) + ) + "type mismatch" +) + (assert_invalid (module (type $ty (func (result i32 i32))) From 24be4255901e9db4c9aab23b838f2bcc46d9c6e4 Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Mon, 15 Jul 2024 22:42:43 -0700 Subject: [PATCH 116/130] Remove type() method from Tag object (#318) This method mirrors the type methods on the other interfaces (Global, Memory, etc) as defined in the JS type reflection proposal (https://github.com/WebAssembly/js-types/blob/main/proposals/js-types/Overview.md) Since this proposal will be standardized first, JS types should be rebased on top of exception-handling, and this method should be moved there. --- document/js-api/index.bs | 16 ---------------- test/js-api/tag/type.tentative.any.js | 21 --------------------- 2 files changed, 37 deletions(-) delete mode 100644 test/js-api/tag/type.tentative.any.js diff --git a/document/js-api/index.bs b/document/js-api/index.bs index 0bf129e60b..9586c48ee1 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -1199,7 +1199,6 @@ dictionary TagType { [LegacyNamespace=WebAssembly, Exposed=(Window,Worker,Worklet)] interface Tag { constructor(TagType type); - TagType type(); };
@@ -1244,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_type=](|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

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 58c96078bf..0000000000
--- a/test/js-api/tag/type.tentative.any.js
+++ /dev/null
@@ -1,21 +0,0 @@
-// META: global=window,dedicatedworker,jsshell,shadowrealm
-// 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]");

From 1a26677ab25b7220118d313f16a8391d68000a0a Mon Sep 17 00:00:00 2001
From: Andreas Rossberg 
Date: Wed, 17 Jul 2024 10:56:52 +0200
Subject: [PATCH 117/130] Fix xref anchors

---
 document/core/appendix/custom.rst | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/document/core/appendix/custom.rst b/document/core/appendix/custom.rst
index adf4eb17e2..fcbf8e7da5 100644
--- a/document/core/appendix/custom.rst
+++ b/document/core/appendix/custom.rst
@@ -190,7 +190,7 @@ directly after the :math:`\text{module}` keyword, or if present, after the follo
 
 
 .. index:: function
-.. _binary-funcnameannot:
+.. _text-funcnameannot:
 
 Function Names
 ..............
@@ -206,7 +206,7 @@ directly after the :math:`\text{func}` keyword, or if present, after the followi
 
 
 .. index:: function, parameter
-.. _binary-paramnameannot:
+.. _text-paramnameannot:
 
 Parameter Names
 ...............
@@ -223,7 +223,7 @@ It may only be placed on a declaration that declares exactly one parameter.
 
 
 .. index:: function, local
-.. _binary-localnameannot:
+.. _text-localnameannot:
 
 Local Names
 ...........

From 97848ea3cf6f45d081c9ab38e3207a070463620a Mon Sep 17 00:00:00 2001
From: Andreas Rossberg 
Date: Wed, 17 Jul 2024 11:46:54 +0200
Subject: [PATCH 118/130] Add Changes

---
 document/core/appendix/changes.rst | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/document/core/appendix/changes.rst b/document/core/appendix/changes.rst
index 339cb25f9d..6b01d14f5d 100644
--- a/document/core/appendix/changes.rst
+++ b/document/core/appendix/changes.rst
@@ -155,3 +155,27 @@ Added vector type and instructions that manipulate multiple numeric values in pa
 
 .. [#proposal-vectype]
    https://github.com/WebAssembly/spec/tree/main/proposals/simd/
+
+
+Release 3.0
+~~~~~~~~~~~
+
+.. index: text format, annotation, custom section, identifier, module, function, local
+
+Custom annotations
+..................
+
+Added generic syntax for custom annotations in the text format,
+mirroring the role of custom sections in the binary format. [#proposal-annot]_
+
+* :ref:`Annotations ` of the form :math:`\text{(@id~\dots)}` are allowed anywhere in the :ref:`text format `
+
+* :ref:`Identifiers ` can be escaped as :math:`\text{@"\dots"}` with arbitrary :ref:`names `
+
+* Defined :ref:`name annotations ` :math:`\text{(@name~"\dots")}` for :ref:`module names `, :ref:`function names `, and :ref:`local names `
+
+* Defined :ref:`custom annotation ` :math:`\text{(@custom~"\dots")}` to represent arbitrary :ref:`custom sections ` in the text format
+
+
+.. [#proposal-annot]
+   https://github.com/WebAssembly/annotations/tree/main/proposals/annotations/

From 5159bc413fc12f46063a23bbb36c4daa3f40948f Mon Sep 17 00:00:00 2001
From: Andreas Rossberg 
Date: Thu, 18 Jul 2024 20:03:53 +0200
Subject: [PATCH 119/130] Merge exception handling

---
 README.md                          |  15 ++--
 deploy_key                         |  49 -------------
 deploy_key.pub                     |   1 -
 document/core/appendix/changes.rst | 107 ++++++++++++++---------------
 4 files changed, 57 insertions(+), 115 deletions(-)
 delete mode 100644 deploy_key
 delete mode 100644 deploy_key.pub

diff --git a/README.md b/README.md
index 533bcf1758..cbc17b462f 100644
--- a/README.md
+++ b/README.md
@@ -3,18 +3,11 @@
 
 # spec
 
-This repository holds a prototypical reference implementation for WebAssembly,
-which is currently serving as the official specification. Eventually, we expect
-to produce a specification either written in human-readable prose or in a formal
-specification language.
+This repository holds the sources for the WebAssembly specification,
+a reference implementation, and the official test suite.
 
-It also holds the WebAssembly testsuite, which tests numerous aspects of
-conformance to the spec.
-
-View the work-in-progress spec at [webassembly.github.io/spec](https://webassembly.github.io/spec/).
-
-At this time, the contents of this repository are under development and known
-to be "incomplet and inkorrect".
+A formatted version of the spec is available here:
+[webassembly.github.io/spec](https://webassembly.github.io/spec/),
 
 Participation is welcome. Discussions about new features, significant semantic
 changes, or any specification change likely to generate substantial discussion
diff --git a/deploy_key b/deploy_key
deleted file mode 100644
index f4e5b00055..0000000000
--- a/deploy_key
+++ /dev/null
@@ -1,49 +0,0 @@
------BEGIN OPENSSH PRIVATE KEY-----
-b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAACFwAAAAdzc2gtcn
-NhAAAAAwEAAQAAAgEAn9FUrQzWcgEOHsDJ+f7L0g7xIYrdBb3K1dQqFWFidZcL8KYMMR0/
-CEYRXfSn3EcvpYnRoIjWfGQgqOpA90FMaAwqdoK72ByW7q2C4ymjX5xR8XFyG5YJVvjaMe
-STXZlynQSOH9lXU5RooeEwRatgQizuwB/Bqahry/8FOfDhVlNO26IbEyJPd23qeyAd+42C
-OTE5oWHEJ3TKSWSfwTAhfrIlIg+dWiSx/IUcLc+7Ms5EpQh3ebX49oaW00SWRDnyqoM95m
-D+Uc3DuTFJyKdHlLouESdNrE9LeBms5N/bHSgedVyZ5fL9SHC6P1HmgDPFspmO6z1s15/a
-5y5hf9zHVoj1ha54LSaPlE5/L5hpY6PCH7fepRXhw84VIQV74IsJow1XUbkmfKkjW3PeBq
-CF5cTKF2LK65SraxEfNMLU0ThOH6B6yzePq7JF+05VGMh2G2Wkwy11pezeqW5tPU1M2qwS
-RN8jAFKIwuC7B73drz8yMhF8MfTW4iGM4RqhQRCK22xmVtzwYFwRKUM++p2iOggGi42jnV
-skv7/yQ6XcaEm+2Jx3C2zy/5OdLql9z8gmKsH4jpQUADmae8KBfJCqHZrtvhRTqH99E3th
-pIKcpzY+n5uhNCyrY+hTfB44/EIntWkXDTLwVVRmmOyHSvEA7/Dz1vtA7gY9Nu25xY/SXS
-sAAAc4dIF4rHSBeKwAAAAHc3NoLXJzYQAAAgEAn9FUrQzWcgEOHsDJ+f7L0g7xIYrdBb3K
-1dQqFWFidZcL8KYMMR0/CEYRXfSn3EcvpYnRoIjWfGQgqOpA90FMaAwqdoK72ByW7q2C4y
-mjX5xR8XFyG5YJVvjaMeSTXZlynQSOH9lXU5RooeEwRatgQizuwB/Bqahry/8FOfDhVlNO
-26IbEyJPd23qeyAd+42COTE5oWHEJ3TKSWSfwTAhfrIlIg+dWiSx/IUcLc+7Ms5EpQh3eb
-X49oaW00SWRDnyqoM95mD+Uc3DuTFJyKdHlLouESdNrE9LeBms5N/bHSgedVyZ5fL9SHC6
-P1HmgDPFspmO6z1s15/a5y5hf9zHVoj1ha54LSaPlE5/L5hpY6PCH7fepRXhw84VIQV74I
-sJow1XUbkmfKkjW3PeBqCF5cTKF2LK65SraxEfNMLU0ThOH6B6yzePq7JF+05VGMh2G2Wk
-wy11pezeqW5tPU1M2qwSRN8jAFKIwuC7B73drz8yMhF8MfTW4iGM4RqhQRCK22xmVtzwYF
-wRKUM++p2iOggGi42jnVskv7/yQ6XcaEm+2Jx3C2zy/5OdLql9z8gmKsH4jpQUADmae8KB
-fJCqHZrtvhRTqH99E3thpIKcpzY+n5uhNCyrY+hTfB44/EIntWkXDTLwVVRmmOyHSvEA7/
-Dz1vtA7gY9Nu25xY/SXSsAAAADAQABAAACAFMayDxgY5bOw6fsOlscSqKFkJAPpJUat0Hv
-3J5XkJpzHAtcXRShD6jevqMr2Knr/nPHMdGXtmjirDUJ8xRfyTqFsQMFQmbDnxyn71ruyP
-yrzdSOWHbN0zd9mgC9yn+ujnHl733SR923W51p+u8PibN/p/sRyGPPp5Zhmzcg8hwwn94H
-8qpFeisxZe/2qICpeiEBXuVzcEvQKGx3vbb4r0IxoquOkRVR5ZfZI+kSj1aA+iMTPwV0Qe
-z32bAshzMdKvnN2z9UCotBQ1imr6Z+jfNhyRi0ZmiGp0jhmQ0+9rK3rPb8Wy6+50RnEgJh
-NUpPIauYvD/JJjMN9genD54skR61JnwRSmMUcuYFvcPKip1FYugYtZY/a9waqcSA73TcuZ
-DQzihYs4fdr2aD3pH8QchYwo5vZFzPCVuXF387pYUmj8u3RLDhemSYjwuG/NWdVKnYnZ2B
-EVOMi4YZ6Kms7rac8zzgFUonxDWLCigOPI0HPfrDKQ7P6NyiAKEEEfK6g2KvnDJaaCdfpb
-70UTFG6YyN+1qa0NWVcU6iEGd/ziT7xPDT3WgJd4SAYkllycQkg5zdFz4T1SqABMrWqjK7
-1Xk//kZxboYZFwBoODiNd2dcLU1XOBhNvoAEajKQNyzAhET6eC02olwUwl7ZwdMxMH8C9H
-/j4lAq+v6PYzFHN/uZAAABAQCExWknkwPAu+eDulQTW1T5kIhsD3Ffe+9yg1Ps83NPST9w
-7dddykxOzZJ4j8WjpsvwCXuxyxPqt3UI3y2t4nC2aIWq5gPoIfDvtt5J8j6i4RwrI2AU3j
-tKdPyLD4qKOCvuqThRCUz3GffU8QNknLYT1jGhO8p//nZq68SVIhtcL8CG1/mQQVApgvd+
-VrBIytptBk0wn4ufMY11CjRTLjASJzBsiT/VmUkQVBQDn6/yvCSxx7nYzMt0XcDqH1/KO7
-iqEN6HfkTNTKBXcRWIS+c7OvAixJTGXRCE2xcQindaHQ3HNK+6r1qAXp65XfsTJUw+FIdc
-4OXiRdnAAanVy6tAAAABAQDKduhs+s+AKQWsuwkzWdnLQdMP+98vKBkMH7/dBA73xDd+hR
-8sHOhoyxYoNoUhvYWcoip2Mqsn/+F5QLvKxaaccQOtfQpYEeB0koL3QEHUIBMwzgEW112T
-ATa8KR6okRAUxn7tqswebAFPmdpGS1YkQAyAQQoPr2NQpPSWN0cKXQZUYLn5r6HSZ7isAm
-K/6mrF+TqK80055A+duZggLIKyMAKDTdgtIu4D/wZIqZYcY8uiA2ZhGM3XEQutTjo4xemu
-V2X+WSwXhrXiSAWqbCBxCRcCLKktweihb1nOkXIOspKr7Adj/ctmlqO875GHuwlrGaNfe2
-DFo67i4udsdrc9AAABAQDKE5rUxfN6K51jWdgiBVx1XVH0YenLGHECYcxg5AHkDTJUOl9F
-SqiP4w128fFjHEO+GGltgkruQ94k+wINub/e7k1NYSpgj03BDs6swpRG7Y3uot1aBFAati
-ITJF6p1rmjmBxtDhaVX9nA6GyOmzXO4Tb6niBHO5u7B3dqZI/iXHUmsZOsa1ijuE8YL5P7
-SzxbkiGGsWv5gfs8RcYuOmGhTx2LxOTNh3kovj4xQSoJVH3IikpodQAuXTdL5utuAzgVEL
-Xpk1XVyVPkFGitmNqTr3D2gKnPnkQf8KYsRmzt4bPKDrKOBleqYbFSabyHUNJEaW7pmf8+
-fNbVF9dWMmyHAAAAAAEC
------END OPENSSH PRIVATE KEY-----
diff --git a/deploy_key.pub b/deploy_key.pub
deleted file mode 100644
index 313f1bd8e1..0000000000
--- a/deploy_key.pub
+++ /dev/null
@@ -1 +0,0 @@
-ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCf0VStDNZyAQ4ewMn5/svSDvEhit0FvcrV1CoVYWJ1lwvwpgwxHT8IRhFd9KfcRy+lidGgiNZ8ZCCo6kD3QUxoDCp2grvYHJburYLjKaNfnFHxcXIblglW+Nox5JNdmXKdBI4f2VdTlGih4TBFq2BCLO7AH8GpqGvL/wU58OFWU07bohsTIk93bep7IB37jYI5MTmhYcQndMpJZJ/BMCF+siUiD51aJLH8hRwtz7syzkSlCHd5tfj2hpbTRJZEOfKqgz3mYP5RzcO5MUnIp0eUui4RJ02sT0t4Gazk39sdKB51XJnl8v1IcLo/UeaAM8WymY7rPWzXn9rnLmF/3MdWiPWFrngtJo+UTn8vmGljo8Ift96lFeHDzhUhBXvgiwmjDVdRuSZ8qSNbc94GoIXlxMoXYsrrlKtrER80wtTROE4foHrLN4+rskX7TlUYyHYbZaTDLXWl7N6pbm09TUzarBJE3yMAUojC4LsHvd2vPzIyEXwx9NbiIYzhGqFBEIrbbGZW3PBgXBEpQz76naI6CAaLjaOdWyS/v/JDpdxoSb7YnHcLbPL/k50uqX3PyCYqwfiOlBQAOZp7woF8kKodmu2+FFOof30Te2GkgpynNj6fm6E0LKtj6FN8Hjj8Qie1aRcNMvBVVGaY7IdK8QDv8PPW+0DuBj027bnFj9JdKw== 
diff --git a/document/core/appendix/changes.rst b/document/core/appendix/changes.rst
index 25516b9954..b798c0f092 100644
--- a/document/core/appendix/changes.rst
+++ b/document/core/appendix/changes.rst
@@ -12,7 +12,7 @@ Release 2.0
 
 .. index:: instruction, integer
 
-Sign extension instructions
+Sign Extension Instructions
 ...........................
 
 Added new numeric instructions for performing sign extension within integer representations. [#proposal-signext]_
@@ -22,7 +22,7 @@ Added new numeric instructions for performing sign extension within integer repr
 
 .. index:: instruction, trap, floating-point, integer
 
-Non-trapping float-to-int conversions
+Non-trapping Float-to-Int Conversions
 .....................................
 
 Added new conversion instructions that avoid trapping when converting a floating-point number to an integer. [#proposal-cvtsat]_
@@ -32,7 +32,7 @@ Added new conversion instructions that avoid trapping when converting a floating
 
 .. index:: block, function, value type, result type
 
-Multiple values
+Multiple Values
 ...............
 
 Generalized the result type of blocks and functions to allow for multiple values; in addition, introduced the ability to have block parameters. [#proposal-multivalue]_
@@ -44,7 +44,7 @@ Generalized the result type of blocks and functions to allow for multiple values
 
 .. index:: value type, reference, reference type, instruction, element segment
 
-Reference types
+Reference Types
 ...............
 
 Added |FUNCREF| and |EXTERNREF| as new value types and respective instructions. [#proposal-reftype]_
@@ -60,7 +60,7 @@ Added |FUNCREF| and |EXTERNREF| as new value types and respective instructions.
 
 .. index:: reference, instruction, table, table type
 
-Table instructions
+Table Instructions
 ..................
 
 Added instructions to directly access and modify tables. [#proposal-reftype]_
@@ -72,7 +72,7 @@ Added instructions to directly access and modify tables. [#proposal-reftype]_
 
 .. index:: table, instruction, table index, element segment, import, export
 
-Multiple tables
+Multiple Tables
 ...............
 
 Added the ability to use multiple tables per module. [#proposal-reftype]_
@@ -86,7 +86,7 @@ Added the ability to use multiple tables per module. [#proposal-reftype]_
 
 .. index:: instruction, table, memory, data segment, element segment
 
-Bulk memory and table instructions
+Bulk Memory and Table Instructions
 ..................................
 
 Added instructions that modify ranges of memory or table entries. [#proposal-reftype]_ [#proposal-bulk]_
@@ -106,7 +106,7 @@ Added instructions that modify ranges of memory or table entries. [#proposal-ref
 
 .. index:: instructions, SIMD, value type, vector type
 
-Vector instructions
+Vector Instructions
 ...................
 
 Added vector type and instructions that manipulate multiple numeric values in parallel (also known as *SIMD*, single instruction multiple data) [#proposal-vectype]_
@@ -160,90 +160,89 @@ Added vector type and instructions that manipulate multiple numeric values in pa
 Release 3.0
 ~~~~~~~~~~~
 
-.. index: instruction, function, call
+.. index: instruction, expression, constant
 
-Tail Calls
-..........
+Extended Constant Expressions
+.............................
 
-Added instructions to perform tail calls [#proposal-tailcall]_.
+Allowed basic numeric computations in constant expressions. [#proposal-extconst]_
 
-* New :ref:`control instructions `: :math:`RETURNCALL` and :math:`RETURNCALLINDIRECT`
+* Extended set of :ref:`constant instructions ` with :math:`\K{i}\X{nn}\K{.add}`, :math:`\K{i}\X{nn}\K{.sub}`, and :math:`\K{i}\X{nn}\K{.mul}`, and |GLOBALGET| for any previously declared immutable :ref:`global `
 
+.. note::
+   The :ref:`garbage collection ` added further constant instructions.
 
-.. index:: reference, reference type, heap type, value type, local, local type, instruction, instruction type, table, function, function type, matching, subtyping
 
-Typeful References
-..................
-
-Added more precise types for references [#proposal-typedref]_.
+.. index: instruction, function, call
 
-* New generalised form of :ref:`reference types `: :math:`(\REF~\NULL^?~\heaptype)`
+Tail Calls
+..........
 
-* New class of :ref:`heap types `: |FUNC|, |EXTERN|, :math:`\typeidx`
+Added instructions to perform tail calls. [#proposal-tailcall]_
 
-* Basic :ref:`subtyping ` on :ref:`reference ` and :ref:`value ` types
+* New :ref:`control instructions `: |RETURNCALL| and |RETURNCALLINDIRECT|
 
-* New :ref:`reference instructions `: |REFASNONNULL|, |BRONNULL|, |BRONNONNULL|
 
-* New :ref:`control instruction `: |CALLREF|
+.. index:: instruction, exception, reference type, tag type, tag, handler
 
-* Refined typing of :ref:`reference instruction ` |REFFUNC| with more precise result type
+Exception Handling
+..................
 
-* Refined typing of :ref:`local instructions ` and :ref:`instruction sequences ` to track the :ref:`initialization status ` of :ref:`locals ` with non-:ref:`defaultable ` type
+Added tag definitions, imports, and exports, and instructions to throw and catch exceptions [#proposal-exn]_
 
-* Extended :ref:`table definitions ` with optional initializer expression
+* Modules may :ref:`define `, :ref:`import `, and :ref:`export ` tags.
 
+* New :ref:`heap types `: |EXN|, |NOEXN|
 
-.. index:: reference, reference type, heap type, field type, storage type, structure type, array type, composite type, sub type, recursive type
+* New :ref:`reference type ` short-hands: |EXNREF|, |NULLEXNREF|
 
-Garbage Collection
-..................
+* New :ref:`control instructions `: |THROW|, |THROWREF|, and |TRYTABLE|.
 
-Added managed reference types [#proposal-gc]_.
+* New :ref:`tag section ` in binary format.
 
-* New forms of :ref:`heap types `: |ANY|, |EQT|, |I31|, |STRUCT|, |ARRAY|, |NONE|, |NOFUNC|, |NOEXTERN|
 
-* New :ref:`reference type ` short-hands: |ANYREF|, |EQREF|, |I31REF|, |STRUCTREF|, |ARRAYREF|, |NULLREF|, |NULLFUNCREF|, |NULLEXTERNREF|
+.. index: instruction, memory, memory index, data segment, import, export
 
-* New forms of type definitions: :ref:`structure ` and :ref:`array types `, :ref:`sub types `, and :ref:`recursive types `
+Multiple Memories
+.................
 
-* Enriched :ref:`subtyping ` based on explicitly declared :ref:`sub types ` and the new heap types
+Added the ability to use multiple memories per module. [#proposal-multimem]_
 
-* New generic :ref:`reference instructions `: |REFEQ|, |REFTEST|, |REFCAST|, |BRONCAST|, |BRONCASTFAIL|
+* :ref:`Modules ` may :ref:`define `, :ref:`import `, and :ref:`export ` multiple memories
 
-* New :ref:`reference instructions ` for :ref:`unboxed scalars `: |REFI31|, :math:`\I31GET\K{\_}\sx`
+* :ref:`Memory instructions ` take a :ref:`memory index ` immediate: |MEMORYSIZE|, |MEMORYGROW|, |MEMORYFILL|, |MEMORYCOPY|, |MEMORYINIT|, :math:`t\K{.load}`, :math:`t\K{.store}`, :math:`t\K{.load}\!N\!\K{\_}\sx`, :math:`t\K{.store}\!N`, :math:`\K{v128.load}\!N\!\K{x}\!M\!\K{\_}\sx`, :math:`\K{v128.load}\!N\!\K{\_zero}`, :math:`\K{v128.load}\!N\!\K{\_splat}`, :math:`\K{v128.load}\!N\!\K{\_lane}`, :math:`\K{v128.store}\!N\!\K{\_lane}`
 
-* New :ref:`reference instructions ` for :ref:`structure types `: |STRUCTNEW|, |STRUCTNEWDEFAULT|, :math:`\STRUCTGET\K{\_}\sx^?`, |STRUCTSET|
+* :ref:`Data segments ` take a :ref:`memory index `
 
-* New :ref:`reference instructions ` for :ref:`array types `: |ARRAYNEW|, |ARRAYNEWDEFAULT|, |ARRAYNEWFIXED|, |ARRAYNEWDATA|, |ARRAYNEWELEM|, :math:`\ARRAYGET\K{\_}\sx^?`, |ARRAYSET|, |ARRAYLEN|, |ARRAYFILL|, |ARRAYCOPY|, |ARRAYINITDATA|, |ARRAYINITELEM|
 
-* New :ref:`reference instructions ` for converting :ref:`host types `: |ANYCONVERTEXTERN|, |EXTERNCONVERTANY|
+.. index:: reference, reference type, heap type, value type, local, local type, instruction, instruction type, table, function, function type, matching, subtyping
 
-* Extended set of :ref:`constant instructions ` with |REFI31|, |STRUCTNEW|, |STRUCTNEWDEFAULT|, |ARRAYNEW|, |ARRAYNEWDEFAULT|, |ARRAYNEWFIXED|, |ANYCONVERTEXTERN|, |EXTERNCONVERTANY|, and |GLOBALGET| for any previously declared immutable :ref:`global `
+Typeful References
+..................
 
+Added more precise types for references. [#proposal-typedref]_
 
-.. index:: instruction, exception, reference type, tag type, tag, handler
+* New generalised form of :ref:`reference types `: :math:`(\REF~\NULL^?~\heaptype)`
 
-Exception Handling
-..................
+* New class of :ref:`heap types `: |FUNC|, |EXTERN|, :math:`\typeidx`
 
-Added tag definitions, imports, and exports, and instructions to throw and catch exceptions [#proposal-exn]_
+* Basic :ref:`subtyping ` on :ref:`reference ` and :ref:`value ` types
 
-* Modules may :ref:`define `, :ref:`import `, and :ref:`export ` tags.
+* New :ref:`reference instructions `: |REFASNONNULL|, |BRONNULL|, |BRONNONNULL|
 
-* New :ref:`heap types `: |EXN|, |NOEXN|
+* New :ref:`control instruction `: |CALLREF|
 
-* New :ref:`reference type ` short-hands: |EXNREF|, |NULLEXNREF|
+* Refined typing of :ref:`reference instruction ` |REFFUNC| with more precise result type
 
-* New :ref:`control instructions `: |THROW|, |THROWREF|, and |TRYTABLE|.
+* Refined typing of :ref:`local instructions ` and :ref:`instruction sequences ` to track the :ref:`initialization status ` of :ref:`locals ` with non-:ref:`defaultable ` type
 
-* New :ref:`tag section ` in binary format.
+* Extended :ref:`table definitions ` with optional initializer expression
 
 
 .. index:: reference, reference type, heap type, field type, storage type, structure type, array type, composite type, sub type, recursive type
 .. _extension-gc:
 
-Garbage collection
+Garbage Collection
 ..................
 
 Added managed reference types. [#proposal-gc]_
@@ -271,7 +270,7 @@ Added managed reference types. [#proposal-gc]_
 
 .. index: text format, annotation, custom section, identifier, module, type, function, local, structure field
 
-Custom annotations
+Custom Annotations
 ..................
 
 Added generic syntax for custom annotations in the text format,
@@ -292,15 +291,15 @@ mirroring the role of custom sections in the binary format. [#proposal-annot]_
 .. [#proposal-tailcall]
    https://github.com/WebAssembly/spec/tree/main/proposals/tail-call/
 
+.. [#proposal-exn]
+   https://github.com/WebAssembly/spec/tree/main/proposals/exception-handling/
+
 .. [#proposal-multimem]
    https://github.com/WebAssembly/multi-memory/blob/main/proposals/multi-memory/
 
 .. [#proposal-typedref]
    https://github.com/WebAssembly/spec/tree/main/proposals/function-references/
 
-.. [#proposal-exn]
-   https://github.com/WebAssembly/spec/tree/main/proposals/exception-handling/
-
 .. [#proposal-gc]
    https://github.com/WebAssembly/spec/tree/main/proposals/gc/
 

From db53a302183a070cc5389d04762a466b73562cce Mon Sep 17 00:00:00 2001
From: Andreas Rossberg 
Date: Thu, 18 Jul 2024 20:06:55 +0200
Subject: [PATCH 120/130] Fix index meta

---
 document/core/appendix/changes.rst | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/document/core/appendix/changes.rst b/document/core/appendix/changes.rst
index b798c0f092..7c23860819 100644
--- a/document/core/appendix/changes.rst
+++ b/document/core/appendix/changes.rst
@@ -160,7 +160,7 @@ Added vector type and instructions that manipulate multiple numeric values in pa
 Release 3.0
 ~~~~~~~~~~~
 
-.. index: instruction, expression, constant
+.. index:: instruction, expression, constant
 
 Extended Constant Expressions
 .............................
@@ -173,7 +173,7 @@ Allowed basic numeric computations in constant expressions. [#proposal-extconst]
    The :ref:`garbage collection ` added further constant instructions.
 
 
-.. index: instruction, function, call
+.. index:: instruction, function, call
 
 Tail Calls
 ..........
@@ -201,7 +201,7 @@ Added tag definitions, imports, and exports, and instructions to throw and catch
 * New :ref:`tag section ` in binary format.
 
 
-.. index: instruction, memory, memory index, data segment, import, export
+.. index:: instruction, memory, memory index, data segment, import, export
 
 Multiple Memories
 .................
@@ -268,7 +268,7 @@ Added managed reference types. [#proposal-gc]_
 * Extended set of :ref:`constant instructions ` with |REFI31|, |STRUCTNEW|, |STRUCTNEWDEFAULT|, |ARRAYNEW|, |ARRAYNEWDEFAULT|, |ARRAYNEWFIXED|, |ANYCONVERTEXTERN|, |EXTERNCONVERTANY|
 
 
-.. index: text format, annotation, custom section, identifier, module, type, function, local, structure field
+.. index:: text format, annotation, custom section, identifier, module, type, function, local, structure field
 
 Custom Annotations
 ..................

From 0f7a95af2931bfd558a49cf6a917c4aed50b5a39 Mon Sep 17 00:00:00 2001
From: Andreas Rossberg 
Date: Mon, 22 Jul 2024 12:26:51 +0200
Subject: [PATCH 121/130] Test catch subtyping

---
 test/core/try_table.wast | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/test/core/try_table.wast b/test/core/try_table.wast
index e64b6c189f..ebda8e0caf 100644
--- a/test/core/try_table.wast
+++ b/test/core/try_table.wast
@@ -370,3 +370,21 @@
   )
   "type mismatch"
 )
+
+
+(module
+  (type $t (func))
+  (func $dummy)
+  (elem declare func $dummy)
+
+  (tag $e (param (ref $t)))
+  (func $throw (throw $e (ref.func $dummy)))
+  (func (export "run") (result (ref null $t))
+    (block $l (result (ref null $t))
+      (try_table (catch $e $l) (call $throw))
+      (unreachable)
+    )
+  )
+)
+
+(assert_return (invoke "run") (ref.func))

From 43f84a3fc65e79dc398b8cbf4322c155cdfc0b6a Mon Sep 17 00:00:00 2001
From: Andreas Rossberg 
Date: Mon, 22 Jul 2024 12:45:56 +0200
Subject: [PATCH 122/130] Test more catch subtyping

---
 interpreter/valid/valid.ml |  4 +--
 test/core/try_table.wast   | 64 ++++++++++++++++++++++++++++++++++++--
 2 files changed, 64 insertions(+), 4 deletions(-)

diff --git a/interpreter/valid/valid.ml b/interpreter/valid/valid.ml
index d4c4967ab6..6c02ff9243 100644
--- a/interpreter/valid/valid.ml
+++ b/interpreter/valid/valid.ml
@@ -939,11 +939,11 @@ and check_catch (c : context) (cc : catch) (ts : val_type list) at =
   | CatchRef (x1, x2) ->
     let TagT dt = tag c x1 in
     let FuncT (ts1, ts2) = as_func_str_type (expand_def_type dt) in
-    match_target c (ts1 @ [RefT (Null, ExnHT)]) (label c x2) cc.at
+    match_target c (ts1 @ [RefT (NoNull, ExnHT)]) (label c x2) cc.at
   | CatchAll x ->
     match_target c [] (label c x) cc.at
   | CatchAllRef x ->
-    match_target c [RefT (Null, ExnHT)] (label c x) cc.at
+    match_target c [RefT (NoNull, ExnHT)] (label c x) cc.at
 
 
 (* Functions & Constants *)
diff --git a/test/core/try_table.wast b/test/core/try_table.wast
index ebda8e0caf..d428ec114d 100644
--- a/test/core/try_table.wast
+++ b/test/core/try_table.wast
@@ -379,12 +379,72 @@
 
   (tag $e (param (ref $t)))
   (func $throw (throw $e (ref.func $dummy)))
-  (func (export "run") (result (ref null $t))
+
+  (func (export "catch") (result (ref null $t))
     (block $l (result (ref null $t))
       (try_table (catch $e $l) (call $throw))
       (unreachable)
     )
   )
+  (func (export "catch_ref1") (result (ref null $t))
+    (block $l (result (ref null $t) (ref exn))
+      (try_table (catch_ref $e $l) (call $throw))
+      (unreachable)
+    )
+    (drop)
+  )
+  (func (export "catch_ref2") (result (ref null $t))
+    (block $l (result (ref null $t) (ref null exn))
+      (try_table (catch_ref $e $l) (call $throw))
+      (unreachable)
+    )
+    (drop)
+  )
+  (func (export "catch_all_ref1")
+    (block $l (result (ref exn))
+      (try_table (catch_all_ref $l) (call $throw))
+      (unreachable)
+    )
+    (drop)
+  )
+  (func (export "catch_all_ref2")
+    (block $l (result (ref null exn))
+      (try_table (catch_all_ref $l) (call $throw))
+      (unreachable)
+    )
+    (drop)
+  )
 )
 
-(assert_return (invoke "run") (ref.func))
+(assert_return (invoke "catch") (ref.func))
+(assert_return (invoke "catch_ref1") (ref.func))
+(assert_return (invoke "catch_ref2") (ref.func))
+(assert_return (invoke "catch_all_ref1"))
+(assert_return (invoke "catch_all_ref2"))
+
+(assert_invalid
+  (module
+    (type $t (func))
+    (tag $e (param (ref null $t)))
+    (func (export "catch") (result (ref $t))
+      (block $l (result (ref $t))
+        (try_table (catch $e $l))
+        (unreachable)
+      )
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (type $t (func))
+    (tag $e (param (ref null $t)))
+    (func (export "catch_ref") (result (ref $t))
+      (block $l (result (ref $t) (ref exn))
+        (try_table (catch $e $l))
+        (unreachable)
+      )
+    )
+  )
+  "type mismatch"
+)

From ef5b07bc9155fea8a9ff94896b858736f9772446 Mon Sep 17 00:00:00 2001
From: Andreas Rossberg 
Date: Mon, 22 Jul 2024 16:02:26 +0200
Subject: [PATCH 123/130] Test link-time tag typing

---
 test/core/tag.wast | 40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/test/core/tag.wast b/test/core/tag.wast
index aba017d2c7..3ea8b558cc 100644
--- a/test/core/tag.wast
+++ b/test/core/tag.wast
@@ -19,3 +19,43 @@
   (module (tag (result i32)))
   "non-empty tag result type"
 )
+
+
+;; Link-time typing
+
+(module
+  (rec
+    (type $t1 (func))
+    (type $t2 (func))
+  )
+  (tag (export "tag") (type $t1))
+)
+
+(register "M")
+
+(module
+  (rec
+    (type $t1 (func))
+    (type $t2 (func))
+  )
+  (tag (import "M" "tag") (type $t1))
+)
+
+(assert_unlinkable
+  (module
+    (rec
+      (type $t1 (func))
+      (type $t2 (func))
+    )
+    (tag (import "M" "tag") (type $t2))
+  )
+  "incompatible import"
+)
+
+(assert_unlinkable
+  (module
+    (type $t (func))
+    (tag (import "M" "tag") (type $t))
+  )
+  "incompatible import"
+)

From 863b64783c5a06c54970ab2b1a394e4b2193abac Mon Sep 17 00:00:00 2001
From: Andreas Rossberg 
Date: Mon, 22 Jul 2024 19:37:39 +0200
Subject: [PATCH 124/130] Split out exceptions

---
 interpreter/exec/eval.ml        |  6 +++---
 interpreter/runtime/exn.ml      | 38 +++++++++++++++++++++++++++++++++
 interpreter/runtime/exn.mli     | 10 +++++++++
 interpreter/runtime/instance.ml |  7 ------
 interpreter/runtime/tag.mli     |  2 +-
 interpreter/runtime/value.ml    |  3 ---
 interpreter/script/run.ml       |  2 +-
 interpreter/syntax/free.mli     |  1 +
 8 files changed, 54 insertions(+), 15 deletions(-)
 create mode 100644 interpreter/runtime/exn.ml
 create mode 100644 interpreter/runtime/exn.mli

diff --git a/interpreter/exec/eval.ml b/interpreter/exec/eval.ml
index f68e20703b..05d727aa0a 100644
--- a/interpreter/exec/eval.ml
+++ b/interpreter/exec/eval.ml
@@ -308,7 +308,7 @@ let rec step (c : config) : config =
       | ThrowRef, Ref (NullRef _) :: vs ->
         vs, [Trapping "null exception reference" @@ e.at]
 
-      | ThrowRef, Ref (ExnRef (t, args)) :: vs ->
+      | ThrowRef, Ref (Exn.(ExnRef (Exn (t, args)))) :: vs ->
         vs, [Throwing (t, args) @@ e.at]
 
       | TryTable (bt, cs, es'), vs ->
@@ -1055,7 +1055,7 @@ let rec step (c : config) : config =
 
     | Handler (n, {it = CatchRef (x1, x2); _} :: cs, (vs', {it = Throwing (a, vs0); at} :: es')), vs ->
       if a == tag c.frame.inst x1 then
-        Ref (ExnRef (a, vs0)) :: vs0 @ vs, [Plain (Br x2) @@ e.at]
+        Ref Exn.(ExnRef (Exn (a, vs0))) :: vs0 @ vs, [Plain (Br x2) @@ e.at]
       else
         vs, [Handler (n, cs, (vs', {it = Throwing (a, vs0); at} :: es')) @@ e.at]
 
@@ -1063,7 +1063,7 @@ let rec step (c : config) : config =
       vs, [Plain (Br x) @@ e.at]
 
     | Handler (n, {it = CatchAllRef x; _} :: cs, (vs', {it = Throwing (a, vs0); at} :: es')), vs ->
-      Ref (ExnRef (a, vs0)) :: vs, [Plain (Br x) @@ e.at]
+      Ref Exn.(ExnRef (Exn (a, vs0))) :: vs, [Plain (Br x) @@ e.at]
 
     | Handler (n, [], (vs', {it = Throwing (a, vs0); at} :: es')), vs ->
       vs, [Throwing (a, vs0) @@ at]
diff --git a/interpreter/runtime/exn.ml b/interpreter/runtime/exn.ml
new file mode 100644
index 0000000000..63463e091a
--- /dev/null
+++ b/interpreter/runtime/exn.ml
@@ -0,0 +1,38 @@
+open Types
+open Value
+
+type exn_ = Exn of Tag.t * value list
+
+type ref_ += ExnRef of exn_
+
+let alloc_exn tag vs =
+  let TagT dt = Tag.type_of tag in
+  assert Free.((def_type dt).types = Set.empty);
+  let FuncT (ts1, ts2) = as_func_str_type (expand_def_type dt) in
+  assert (List.length vs = List.length ts1);
+  assert (ts2 = []);
+  Exn (tag, vs)
+
+let type_of_exn (Exn (tag, _)) =
+  let TagT dt = Tag.type_of tag in
+  dt
+
+let () =
+  let eq_ref' = !Value.eq_ref' in
+  Value.eq_ref' := fun r1 r2 ->
+    match r1, r2 with
+    | ExnRef _, ExnRef _ -> failwith "eq_ref"
+    | _, _ -> eq_ref' r1 r2
+
+let () =
+  let type_of_ref' = !Value.type_of_ref' in
+  Value.type_of_ref' := function
+    | ExnRef e -> DefHT (type_of_exn e)
+    | r -> type_of_ref' r
+
+let () =
+  let string_of_ref' = !Value.string_of_ref' in
+  Value.string_of_ref' := function
+    | ExnRef (Exn (_tag, vs)) ->
+      "(tag " ^ String.concat " " (List.map string_of_value vs) ^ ")"
+    | r -> string_of_ref' r
diff --git a/interpreter/runtime/exn.mli b/interpreter/runtime/exn.mli
new file mode 100644
index 0000000000..8d7cc3384f
--- /dev/null
+++ b/interpreter/runtime/exn.mli
@@ -0,0 +1,10 @@
+open Types
+open Value
+
+type exn_ = Exn of Tag.t * value list
+
+type ref_ += ExnRef of exn_
+
+val alloc_exn : Tag.t -> value list -> exn_
+
+val type_of_exn : exn_ -> def_type
diff --git a/interpreter/runtime/instance.ml b/interpreter/runtime/instance.ml
index cdfa0074dd..4b211c939f 100644
--- a/interpreter/runtime/instance.ml
+++ b/interpreter/runtime/instance.ml
@@ -54,13 +54,6 @@ let () =
     | FuncRef _ -> "func"
     | r -> string_of_ref' r
 
-let () =
-  let eq_ref' = !Value.eq_ref' in
-  Value.eq_ref' := fun r1 r2 ->
-    match r1, r2 with
-    | FuncRef f1, FuncRef f2 -> f1 == f2
-    | _, _ -> eq_ref' r1 r2
-
 
 (* Projections *)
 
diff --git a/interpreter/runtime/tag.mli b/interpreter/runtime/tag.mli
index f8636674b8..c4730e2993 100644
--- a/interpreter/runtime/tag.mli
+++ b/interpreter/runtime/tag.mli
@@ -1,6 +1,6 @@
 open Types
 
-type tag = {ty : tag_type}
+type tag
 type t = tag
 
 val alloc : tag_type -> tag
diff --git a/interpreter/runtime/value.ml b/interpreter/runtime/value.ml
index dec2597229..a24fbaf281 100644
--- a/interpreter/runtime/value.ml
+++ b/interpreter/runtime/value.ml
@@ -18,7 +18,6 @@ type value = Num of num | Vec of vec | Ref of ref_
 type t = value
 
 type ref_ += NullRef of heap_type
-type ref_ += ExnRef of Tag.t * value list
 
 
 (* Injection & projection *)
@@ -109,7 +108,6 @@ let type_of_vec = type_of_vecop
 let type_of_ref' = ref (function _ -> assert false)
 let type_of_ref = function
   | NullRef t -> (Null, Match.bot_of_heap_type [] t)
-  | ExnRef _ -> (NoNull, ExnHT)
   | r -> (NoNull, !type_of_ref' r)
 
 let type_of_value = function
@@ -304,7 +302,6 @@ let hex_string_of_vec = function
 let string_of_ref' = ref (function _ -> "ref")
 let string_of_ref = function
   | NullRef _ -> "null"
-  | ExnRef _ -> "exn"
   | r -> !string_of_ref' r
 
 let string_of_value = function
diff --git a/interpreter/script/run.ml b/interpreter/script/run.ml
index 00ae5c1d0c..1ff6a60b3e 100644
--- a/interpreter/script/run.ml
+++ b/interpreter/script/run.ml
@@ -401,7 +401,7 @@ let assert_ref_pat r p =
   | RefTypePat Types.StructHT, Aggr.StructRef _
   | RefTypePat Types.ArrayHT, Aggr.ArrayRef _ -> true
   | RefTypePat Types.FuncHT, Instance.FuncRef _
-  | RefTypePat Types.ExnHT, Value.ExnRef _
+  | RefTypePat Types.ExnHT, Exn.ExnRef _
   | RefTypePat Types.ExternHT, _ -> true
   | NullPat, Value.NullRef _ -> true
   | _ -> false
diff --git a/interpreter/syntax/free.mli b/interpreter/syntax/free.mli
index cb76c0fb55..3c18c665c2 100644
--- a/interpreter/syntax/free.mli
+++ b/interpreter/syntax/free.mli
@@ -26,6 +26,7 @@ val func_type : Types.func_type -> t
 val global_type : Types.global_type -> t
 val table_type : Types.table_type -> t
 val memory_type : Types.memory_type -> t
+val tag_type : Types.tag_type -> t
 val extern_type : Types.extern_type -> t
 
 val str_type : Types.str_type -> t

From 3fb483d1fd545b2af660afb8351794689d450c99 Mon Sep 17 00:00:00 2001
From: Andreas Rossberg 
Date: Mon, 22 Jul 2024 19:44:44 +0200
Subject: [PATCH 125/130] Rename

---
 interpreter/runtime/exn.ml  | 4 ++--
 interpreter/runtime/exn.mli | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/interpreter/runtime/exn.ml b/interpreter/runtime/exn.ml
index 63463e091a..d4009372e2 100644
--- a/interpreter/runtime/exn.ml
+++ b/interpreter/runtime/exn.ml
@@ -13,7 +13,7 @@ let alloc_exn tag vs =
   assert (ts2 = []);
   Exn (tag, vs)
 
-let type_of_exn (Exn (tag, _)) =
+let type_of (Exn (tag, _)) =
   let TagT dt = Tag.type_of tag in
   dt
 
@@ -27,7 +27,7 @@ let () =
 let () =
   let type_of_ref' = !Value.type_of_ref' in
   Value.type_of_ref' := function
-    | ExnRef e -> DefHT (type_of_exn e)
+    | ExnRef e -> DefHT (type_of e)
     | r -> type_of_ref' r
 
 let () =
diff --git a/interpreter/runtime/exn.mli b/interpreter/runtime/exn.mli
index 8d7cc3384f..13b0340267 100644
--- a/interpreter/runtime/exn.mli
+++ b/interpreter/runtime/exn.mli
@@ -7,4 +7,4 @@ type ref_ += ExnRef of exn_
 
 val alloc_exn : Tag.t -> value list -> exn_
 
-val type_of_exn : exn_ -> def_type
+val type_of : exn_ -> def_type

From babba5751d9730165f53dfe4b4e0ea0e76d9550b Mon Sep 17 00:00:00 2001
From: Andreas Rossberg 
Date: Tue, 23 Jul 2024 11:38:07 +0200
Subject: [PATCH 126/130] Fix binary encoding of tag types

---
 document/core/binary/modules.rst | 2 +-
 document/core/binary/types.rst   | 7 ++-----
 document/core/syntax/modules.rst | 2 +-
 3 files changed, 4 insertions(+), 7 deletions(-)

diff --git a/document/core/binary/modules.rst b/document/core/binary/modules.rst
index 8135c7ccaf..be424e86d7 100644
--- a/document/core/binary/modules.rst
+++ b/document/core/binary/modules.rst
@@ -181,7 +181,7 @@ It decodes into a vector of :ref:`imports ` that represent the |M
      \hex{01}~~\X{tt}{:}\Btabletype &\Rightarrow& \IDTABLE~\X{tt} \\ &&|&
      \hex{02}~~\X{mt}{:}\Bmemtype &\Rightarrow& \IDMEM~\X{mt} \\ &&|&
      \hex{03}~~\X{gt}{:}\Bglobaltype &\Rightarrow& \IDGLOBAL~\X{gt} \\ &&|&
-     \hex{04}~~\X{tt}{:}\Btagtype &\Rightarrow& \IDTAG~\X{tt} \\
+     \hex{04}~~x{:}\Btagtype &\Rightarrow& \IDTAG~x \\
    \end{array}
 
 
diff --git a/document/core/binary/types.rst b/document/core/binary/types.rst
index 525cc33739..c6212ed643 100644
--- a/document/core/binary/types.rst
+++ b/document/core/binary/types.rst
@@ -321,17 +321,14 @@ Global Types
 Tag Types
 ~~~~~~~~~
 
-:ref:`Tag types ` are encoded by their function type.
+:ref:`Tag types ` are encoded by a :ref:`type index ` denoting a :ref:`function type `.
 
 .. math::
    \begin{array}{llclll}
    \production{tag type} & \Btagtype &::=&
-     \hex{00}~~ft{:}\Bfunctype &\Rightarrow& ft \\
+     \hex{00}~~x{:}\Btypeidx &\Rightarrow& x \\
    \end{array}
 
-The |Bfunctype| of a tag is used to characterise exceptions.
-The :math:`\hex{00}` bit signifies an exception and is currently the only allowed value.
-
 .. note::
    In future versions of WebAssembly,
    the preceding zero byte may encode additional flags.
diff --git a/document/core/syntax/modules.rst b/document/core/syntax/modules.rst
index 8ffebb9ded..a0ea7fe750 100644
--- a/document/core/syntax/modules.rst
+++ b/document/core/syntax/modules.rst
@@ -445,7 +445,7 @@ The |MIMPORTS| component of a module defines a set of *imports* that are require
      \IDTABLE~\tabletype \\&&|&
      \IDMEM~\memtype \\&&|&
      \IDGLOBAL~\globaltype \\&&|&
-     \IDTAG~\tagtype \\
+     \IDTAG~\typeidx \\
    \end{array}
 
 Each import is labeled by a two-level :ref:`name ` space, consisting of a |IMODULE| name and a |INAME| for an entity within that module.

From 9a2cab4379ff67c4f487afa77563560c73b3b976 Mon Sep 17 00:00:00 2001
From: Ms2ger 
Date: Mon, 29 Jul 2024 14:58:08 +0200
Subject: [PATCH 127/130] [js-api] Fix bikeshed errors (#1771)

---
 document/js-api/index.bs                     | 45 +++++++++-----------
 document/util/htmldiff.pl                    |  2 +-
 proposals/bulk-memory-operations/Overview.md |  4 +-
 proposals/multi-value/Overview.md            |  4 +-
 proposals/reference-types/Overview.md        |  4 +-
 proposals/simd/SIMD.md                       |  8 ++--
 test/core/float_exprs.wast                   |  2 +-
 test/core/simd/simd_load.wast                |  6 +--
 test/core/simd/simd_store.wast               |  2 +-
 test/core/utf8-custom-section-id.wast        |  2 +-
 test/core/utf8-import-field.wast             |  2 +-
 test/core/utf8-import-module.wast            |  2 +-
 12 files changed, 40 insertions(+), 43 deletions(-)

diff --git a/document/js-api/index.bs b/document/js-api/index.bs
index dd790f819c..b666ef074c 100644
--- a/document/js-api/index.bs
+++ b/document/js-api/index.bs
@@ -62,8 +62,6 @@ urlPrefix: https://tc39.github.io/ecma262/; spec: ECMASCRIPT
         text: 𝔽; url: #𝔽
         text: ℤ; url: #ℤ
         text: SameValue; url: sec-samevalue
-    type: abstract-op
-        text: CreateMethodProperty; url: sec-createmethodproperty
 urlPrefix: https://webassembly.github.io/spec/core/; spec: WebAssembly; type: dfn
     url: valid/modules.html#valid-module
         text: valid
@@ -395,7 +393,7 @@ A {{Module}} object represents a single WebAssembly module. Each {{Module}} obje
                 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 |externtype| is of the form [=external-type/global=] mut |valtype|,
             1. If |v| [=implements=] {{Global}},
                 1. Let |globaladdr| be |v|.\[[Global]].
             1. Otherwise,
@@ -411,16 +409,16 @@ A {{Module}} object represents a single WebAssembly module. Each {{Module}} obje
                 1. Set the [=surrounding agent=]'s [=associated store=] to |store|.
             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 |externtype| is of the form [=external-type/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 |externtype| is of the form [=external-type/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. If |externtype| is of the form [=external-type/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]].
@@ -444,22 +442,22 @@ The verification of WebAssembly type requirements is deferred to the
             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. If |externtype| is of the form [=external-type/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. If |externtype| is of the form [=external-type/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. If |externtype| is of the form [=external-type/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. If |externtype| is of the form [=external-type/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|.
@@ -582,10 +580,10 @@ interface Module {
 
The string value of the extern type |type| is * "function" if |type| is of the form [=external-type/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 + * "table" if |type| is of the form [=external-type/table=] tabletype + * "memory" if |type| is of the form [=external-type/mem=] memtype + * "global" if |type| is of the form [=external-type/global=] globaltype + * "tag" if |type| is of the form [=external-type/tag=] tag
@@ -818,7 +816,8 @@ Immediately after a WebAssembly [=memory.grow=] instruction executes, perform th {{ArrayBuffer}} objects returned by a {{Memory}} object must have a size that is a multiple of a WebAssembly [=page size=] (the constant 65536). For this reason [=HostResizeArrayBuffer=] is redefined as follows.
- The abstract operation [=HostResizeArrayBuffer=] takes arguments |buffer| (an {{ArrayBuffer}}) and |newLength|. It performs the following steps when called. + + The abstract operation [=HostResizeArrayBuffer=] takes arguments |buffer| (an {{ArrayBuffer}}) and |newLength|. It performs the following steps when called. 1. If |buffer|.\[[ArrayBufferDetachKey]] is "WebAssembly.Memory", 1. Let |map| be the [=surrounding agent=]'s associated [=Memory object cache=]. @@ -1149,7 +1148,7 @@ This slot holds a [=function address=] relative to the [=surrounding agent=]'s [ 1. Let |payload| be [=exn_read=](|store|, |exnaddr|). 1. Let |jsTagAddr| be the result of [=get the JavaScript exception tag |getting the JavaScript exception tag=]. 1. If |tagaddr| is equal to |jsTagAddr|, - 1. Throw the result of [=retrieving an extern value=] from |payload|[0]. + 1. Throw the result of [=retrieving a host value=] from |payload|[0]. 1. Otherwise, 1. Let |exception| be [=create an Exception object|a new Exception=] created from |exnaddr|. 1. Throw |exception|. @@ -1180,7 +1179,7 @@ Note: Exported Functions do not have a \[[Construct]] method and thus it is not 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. Let |method| be [=?=] [$GetMethod$](|ret|, {{%Symbol.iterator%}}). 1. If |method| is undefined, [=throw=] a {{TypeError}}. 1. Let |values| be [=?=] [$IteratorToList$]([=?=] [$GetIteratorFromMethod$](|ret|, |method|)). 1. Let |wasmValues| be a new, empty [=list=]. @@ -1229,7 +1228,7 @@ The algorithm ToJSValue(|w|) coerces a [=WebAssembly value=] to a Jav 1. If |w| is of the form [=i64.const=] |u64|, 1. Let |i64| be [=signed_64=](|u64|). 1. Return [=ℤ=](|i64| interpreted as a mathematical value). -1. If |w| is of the form [=i32.const=] |u32|, +1. If |w| is of the form [=i32.const=] |i32|, 1. Let |i32| be [=signed_32=](|i32|). 2. Return [=𝔽=](|i32| interpreted as a mathematical value). 1. If |w| is of the form [=f32.const=] |f32|, @@ -1240,7 +1239,7 @@ The algorithm ToJSValue(|w|) coerces a [=WebAssembly value=] to a Jav 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.null=] t, return null. 1. If |w| is of the form [=ref.i31=] |u31|, 1. Let |i31| be [=signed_31=](|u31|). 1. Let return [=𝔽=](|i31|). @@ -1248,7 +1247,7 @@ The algorithm ToJSValue(|w|) coerces a [=WebAssembly value=] to a Jav 1. If |w| is of the form [=ref.array=] |arrayaddr|, return the result of creating [=a new Exported GC Object=] from |arrayaddr| and "array". 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.host=] |hostaddr|, return the result of [=retrieving a host value=] from |hostaddr|. -1. If |w| is of the form [=ref.extern=] ref, return [=ToJSValue=](|ref|). +1. If |w| is of the form [=ref.extern=] |ref|, return [=ToJSValue=](|ref|). Note: Number values which are equal to NaN may have various observable NaN payloads; see [$NumericToRawBytes$] for details. @@ -1334,8 +1333,6 @@ The algorithm ToWebAssemblyValue(|v|, |type|) coerces a JavaScript va 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|. -

Tag types

@@ -1494,7 +1491,7 @@ The internal methods of an [=Exported GC Object=] use the following implementati
     1. Set |object|.\[[OwnPropertyKeys]] as specified in [=[[OwnPropertyKeys]] internal method of an Exported GC Object=].
     1. [=map/Set=] |map|[|objectaddr|] to |object|.
     1. Return |object|.
-
+

Exceptions

@@ -1639,7 +1636,7 @@ When the [=namespace object=] for the {{WebAssembly}} namespace is [=create a na 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|). + 1. [=!=] [$DefineMethodProperty$](|namespaceObject|, |error|, |constructor|, false).
diff --git a/document/util/htmldiff.pl b/document/util/htmldiff.pl index 4c2780c83f..31ecafef8d 100755 --- a/document/util/htmldiff.pl +++ b/document/util/htmldiff.pl @@ -48,7 +48,7 @@ # also requires the perl modules Getopt::Std # # NOTE: The markup created by htmldiff may not validate against the HTML 4.0 -# DTD. This is because the algorithm is realtively simple, and there are +# DTD. This is because the algorithm is relatively simple, and there are # places in the markup content model where the span element is not allowed. # Htmldiff is NOT aware of these places. # diff --git a/proposals/bulk-memory-operations/Overview.md b/proposals/bulk-memory-operations/Overview.md index 0dfc532642..c93eaa3a0d 100644 --- a/proposals/bulk-memory-operations/Overview.md +++ b/proposals/bulk-memory-operations/Overview.md @@ -228,7 +228,7 @@ The meaning of the bits of the flag field (a `varuint32`) for element segments i | 0 | 0=is active, 1=is passive | | 1 | if bit 0 clear: 0=table 0, 1=has table index | | | if bit 0 set: 0=active, 1=declared | -| 2 | 0=carries indicies; 1=carries elemexprs | +| 2 | 0=carries indices; 1=carries elemexprs | which yields this view, with the fields carried by each flag value: @@ -356,7 +356,7 @@ The bounds check is performed before any data are written. ### `table.init`, `elem.drop`, and `table.copy` instructions -The `table.*` instructions behave similary to the `memory.*` instructions, with +The `table.*` instructions behave similarly to the `memory.*` instructions, with the difference that they operate on element segments and tables, instead of data segments and memories. The offset and length operands of `table.init` and `table.copy` have element units instead of bytes as well. diff --git a/proposals/multi-value/Overview.md b/proposals/multi-value/Overview.md index 42952f0e40..c32af77101 100644 --- a/proposals/multi-value/Overview.md +++ b/proposals/multi-value/Overview.md @@ -9,7 +9,7 @@ - instructions: `value* -> value?` - blocks: `[] -> value?` -* In a stack machine, these asymmetries are artifical restrictions +* In a stack machine, these asymmetries are artificial restrictions - were imposed to simplify the initial WebAssembly release (multiple results deferred to post-MVP) - can easily be lifted by generalising to value* -> value* @@ -32,7 +32,7 @@ - loop labels can have arguments - can represent phis on backward edges - enable future `pick` operator to cross block boundary - - macro definability of instructons with inputs + - macro definability of instructions with inputs * `i32.select3` = `dup if ... else ... end` diff --git a/proposals/reference-types/Overview.md b/proposals/reference-types/Overview.md index 670658f2b7..5a183b64eb 100644 --- a/proposals/reference-types/Overview.md +++ b/proposals/reference-types/Overview.md @@ -95,8 +95,8 @@ New/extended instructions: * The new instruction `table.fill` fills a range in a table with a value. - `table.fill $x : [i32 t i32] -> []` - iff `$x : table t` - - the first operand is the start index of the range, the third operand its length (analoguous to `memory.fill`) - - traps when range+length > size of the table, but only after filling range up to size (analoguous to `memory.fill`) + - the first operand is the start index of the range, the third operand its length (analogous to `memory.fill`) + - traps when range+length > size of the table, but only after filling range up to size (analogous to `memory.fill`) * The `table.init` instruction takes an additional table index as immediate. - `table.init $x $y : [i32 i32 i32] -> []` diff --git a/proposals/simd/SIMD.md b/proposals/simd/SIMD.md index 9f2c802a4a..8e1d2aaaf1 100644 --- a/proposals/simd/SIMD.md +++ b/proposals/simd/SIMD.md @@ -18,7 +18,7 @@ packed data in one instruction. These are commonly used to improve performance for multimedia applications. The set of SIMD instructions in hardware is large, and varies across different versions of hardware. This proposal is comprised of a portable subset of operations that in most cases map to commonly used -instructions in mordern hardware. +instructions in modern hardware. # Types @@ -136,14 +136,14 @@ Accessing WebAssembly module imports or exports containing SIMD Type from JavaSc ### Module Function Imports -Calling an imported function from JavaScript when the function arguments or result is of type v128 will cause the host function to immidiately throw a [`TypeError`](https://tc39.github.io/ecma262/#sec-native-error-types-used-in-this-standard-typeerror). +Calling an imported function from JavaScript when the function arguments or result is of type v128 will cause the host function to immediately throw a [`TypeError`](https://tc39.github.io/ecma262/#sec-native-error-types-used-in-this-standard-typeerror). ### Exported Function Exotic Objects -Invoking the [[Call]] method of an Exported Function Exotic Object when the function type of its [[Closure]] has an argument or result of type v128 will cause the host function to immidiately throw a [`TypeError`](https://tc39.github.io/ecma262/#sec-native-error-types-used-in-this-standard-typeerror). +Invoking the [[Call]] method of an Exported Function Exotic Object when the function type of its [[Closure]] has an argument or result of type v128 will cause the host function to immediately throw a [`TypeError`](https://tc39.github.io/ecma262/#sec-native-error-types-used-in-this-standard-typeerror). -## WebAssembly Module Instatiation +## WebAssembly Module Instantiation Instantiating a WebAssembly Module from a Module moduleObject will throw a LinkError exception, when the global's valtype is v128 and the imported objects type is not WebAssembly.Global. diff --git a/test/core/float_exprs.wast b/test/core/float_exprs.wast index 1f88299212..e6d4f10e91 100644 --- a/test/core/float_exprs.wast +++ b/test/core/float_exprs.wast @@ -1986,7 +1986,7 @@ (assert_return (invoke "f64.xkcd_better_sqrt_5" (f64.const 13.0) (f64.const 4.0) (f64.const 0x1.921fb54442d18p+1) (f64.const 24.0)) (f64.const 0x1.1e3778509a5a3p+1)) ;; Compute the floating-point radix. -;; M. A. Malcom. Algorithms to reveal properties of floating-point arithmetic. +;; M. A. Malcolm. Algorithms to reveal properties of floating-point arithmetic. ;; Communications of the ACM, 15(11):949-951, November 1972. (module (func (export "f32.compute_radix") (param $0 f32) (param $1 f32) (result f32) diff --git a/test/core/simd/simd_load.wast b/test/core/simd/simd_load.wast index 4b2edc160b..2fddd3019e 100644 --- a/test/core/simd/simd_load.wast +++ b/test/core/simd/simd_load.wast @@ -1,4 +1,4 @@ -;; v128.load operater with normal argument (e.g. (i8x16, i16x8 i32x4)) +;; v128.load operator with normal argument (e.g. (i8x16, i16x8 i32x4)) (module (memory 1) @@ -13,7 +13,7 @@ (assert_return (invoke "v128.load") (v128.const i32x4 0x03020100 0x07060504 0x0b0a0908 0x0f0e0d0c)) -;; v128.load operater as the argument of other SIMD instructions +;; v128.load operator as the argument of other SIMD instructions (module (memory 1) (data (i32.const 0) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\00\01\02\03") @@ -185,4 +185,4 @@ (assert_invalid (module (memory 1) (func (drop (v128.load)))) "type mismatch" -) \ No newline at end of file +) diff --git a/test/core/simd/simd_store.wast b/test/core/simd/simd_store.wast index 50349c41bd..7bba053d8e 100644 --- a/test/core/simd/simd_store.wast +++ b/test/core/simd/simd_store.wast @@ -1,4 +1,4 @@ -;; v128.store operater with normal argument (e.g. (i8x16, i16x8, i32x4, f32x4)) +;; v128.store operator with normal argument (e.g. (i8x16, i16x8, i32x4, f32x4)) (module (memory 1) diff --git a/test/core/utf8-custom-section-id.wast b/test/core/utf8-custom-section-id.wast index ee5fd7ccb7..c3765d9da8 100644 --- a/test/core/utf8-custom-section-id.wast +++ b/test/core/utf8-custom-section-id.wast @@ -136,7 +136,7 @@ "malformed UTF-8 encoding" ) -;; byte after (first) 2-byte prefix not a contination byte +;; byte after (first) 2-byte prefix not a continuation byte (assert_malformed (module binary "\00asm" "\01\00\00\00" diff --git a/test/core/utf8-import-field.wast b/test/core/utf8-import-field.wast index 0d030dabb1..330ecf61c8 100644 --- a/test/core/utf8-import-field.wast +++ b/test/core/utf8-import-field.wast @@ -201,7 +201,7 @@ "malformed UTF-8 encoding" ) -;; byte after (first) 2-byte prefix not a contination byte +;; byte after (first) 2-byte prefix not a continuation byte (assert_malformed (module binary "\00asm" "\01\00\00\00" diff --git a/test/core/utf8-import-module.wast b/test/core/utf8-import-module.wast index 5a092da08a..8f509159d7 100644 --- a/test/core/utf8-import-module.wast +++ b/test/core/utf8-import-module.wast @@ -201,7 +201,7 @@ "malformed UTF-8 encoding" ) -;; byte after (first) 2-byte prefix not a contination byte +;; byte after (first) 2-byte prefix not a continuation byte (assert_malformed (module binary "\00asm" "\01\00\00\00" From 7bb80a0f0793d199e9c824f1be6eff85d6b94271 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Wed, 31 Jul 2024 09:46:10 +0200 Subject: [PATCH 128/130] Fix memory index in data instantiation --- document/core/exec/modules.rst | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/document/core/exec/modules.rst b/document/core/exec/modules.rst index e428a4d271..eef15836d0 100644 --- a/document/core/exec/modules.rst +++ b/document/core/exec/modules.rst @@ -659,19 +659,17 @@ It is up to the :ref:`embedder ` to define how such conditions are rep 14. For each :ref:`data segment ` :math:`\data_i` in :math:`\module.\MDATAS` whose :ref:`mode ` is of the form :math:`\DACTIVE~\{ \DMEM~\memidx_i, \DOFFSET~\X{dinstr}^\ast_i~\END \}`, do: - a. Assert: :math:`\memidx_i` is :math:`0`. + a. Let :math:`n` be the length of the vector :math:`\data_i.\DINIT`. - b. Let :math:`n` be the length of the vector :math:`\data_i.\DINIT`. + b. :ref:`Execute ` the instruction sequence :math:`\X{dinstr}^\ast_i`. - c. :ref:`Execute ` the instruction sequence :math:`\X{dinstr}^\ast_i`. - - d. :ref:`Execute ` the instruction :math:`\I32.\CONST~0`. + c. :ref:`Execute ` the instruction :math:`\I32.\CONST~0`. - e. :ref:`Execute ` the instruction :math:`\I32.\CONST~n`. + d. :ref:`Execute ` the instruction :math:`\I32.\CONST~n`. - f. :ref:`Execute ` the instruction :math:`\MEMORYINIT~i`. + e. :ref:`Execute ` the instruction :math:`\MEMORYINIT~i`. - g. :ref:`Execute ` the instruction :math:`\DATADROP~i`. + f. :ref:`Execute ` the instruction :math:`\DATADROP~i`. 15. If the :ref:`start function ` :math:`\module.\MSTART` is not empty, then: @@ -721,8 +719,8 @@ where: \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=\\ \qquad \epsilon \\ - \F{rundata}_i(\{\DINIT~b^n, \DMODE~\DACTIVE \{\DMEM~0, \DOFFSET~\instr^\ast~\END\}\}) \quad=\\ \qquad - \instr^\ast~(\I32.\CONST~0)~(\I32.\CONST~n)~(\MEMORYINIT~i)~(\DATADROP~i) \\ + \F{rundata}_i(\{\DINIT~b^n, \DMODE~\DACTIVE \{\DMEM~x, \DOFFSET~\instr^\ast~\END\}\}) \quad=\\ \qquad + \instr^\ast~(\I32.\CONST~0)~(\I32.\CONST~n)~(\MEMORYINIT~x~i)~(\DATADROP~i) \\ \end{array} .. note:: From 646d4b5803d4acb8ea7bf9d4fb1e496480640054 Mon Sep 17 00:00:00 2001 From: DJ Date: Wed, 24 Jul 2024 16:59:40 +0900 Subject: [PATCH 129/130] [spec] Fix execution semantics prose of `ARRAY.NEW_DATA` --- document/core/exec/instructions.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index 402da167df..3370104907 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -803,11 +803,11 @@ Reference Instructions 17. Let :math:`t` be the :ref:`value type ` :math:`\unpacktype(\X{ft})`. -18. For each consecutive subsequence :math:`{b'}^n` of :math:`b^\ast`: +18. For each of the :math:`n` consecutive subsequences :math:`{b'}^z` of :math:`b^\ast`: a. Assert: due to :ref:`validation `, :math:`\bytes_{\X{ft}}` is defined. - b. Let :math:`c_i` be the constant for which :math:`\bytes_{\X{ft}}(c_i)` is :math:`{b'}^n`. + b. Let :math:`c_i` be the constant for which :math:`\bytes_{\X{ft}}(c_i)` is :math:`{b'}^z`. c. Push the value :math:`t.\CONST~c_i` to the stack. From 9b20411f763b53435895c5b0fff57a71f65081b8 Mon Sep 17 00:00:00 2001 From: YAMAMOTO Takashi Date: Wed, 31 Jul 2024 07:20:44 +0900 Subject: [PATCH 130/130] Fix typos --- document/core/appendix/index-instructions.py | 2 +- document/core/valid/conventions.rst | 2 +- document/core/valid/matching.rst | 2 +- proposals/gc/Overview.md | 8 ++++---- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/document/core/appendix/index-instructions.py b/document/core/appendix/index-instructions.py index 267bf433af..52ffaaf465 100755 --- a/document/core/appendix/index-instructions.py +++ b/document/core/appendix/index-instructions.py @@ -349,7 +349,7 @@ def Instruction(name, opcode, type=None, validation=None, execution=None, operat Instruction(r'\ARRAYINITDATA~x~y', r'\hex{FB}~\hex{12}', r'[(\REF~\NULL~x)~\I32~\I32~\I32] \to []', r'valid-array.init_data', r'exec-array.init_data'), Instruction(r'\ARRAYINITELEM~x~y', r'\hex{FB}~\hex{13}', r'[(\REF~\NULL~x)~\I32~\I32~\I32] \to []', r'valid-array.init_elem', r'exec-array.init_elem'), Instruction(r'\REFTEST~(\REF~t)', r'\hex{FB}~\hex{14}', r"[(\REF~t')] \to [\I32]", r'valid-ref.test', r'exec-ref.test'), - Instruction(r'\REFTEST~(\REF~\NULL~t)', r'\hex{FB}~\hex{15}', r"[(REF~\NULL~t')] \to [\I32]", r'valid-ref.test', r'exec-ref.test'), + Instruction(r'\REFTEST~(\REF~\NULL~t)', r'\hex{FB}~\hex{15}', r"[(\REF~\NULL~t')] \to [\I32]", r'valid-ref.test', r'exec-ref.test'), Instruction(r'\REFCAST~(\REF~t)', r'\hex{FB}~\hex{16}', r"[(\REF~t')] \to [(\REF~t)]", r'valid-ref.cast', r'exec-ref.cast'), Instruction(r'\REFCAST~(\REF~\NULL~t)', r'\hex{FB}~\hex{17}', r"[(\REF~\NULL~t')] \to [(\REF~\NULL~t)]", r'valid-ref.cast', r'exec-ref.cast'), Instruction(r'\BRONCAST~t_1~t_2', r'\hex{FB}~\hex{18}', r'[t_1] \to [t_1\reftypediff t_2]', r'valid-br_on_cast', r'exec-br_on_cast'), diff --git a/document/core/valid/conventions.rst b/document/core/valid/conventions.rst index 6dc6950147..a2a555c904 100644 --- a/document/core/valid/conventions.rst +++ b/document/core/valid/conventions.rst @@ -308,7 +308,7 @@ In addition to field access written :math:`C.\K{field}` the following notation i Convention .......... -Any form of :ref:`type ` can be *closed* to bring it into :ref:`closed ` form relative to a :ref:`context ` it is :ref:`valid ` in by :ref:`substituting ` each :ref:`type index ` :math:`x` occurring in it with the corresponding :ref:`defined type ` :math:`C.\CTYPES[x]`, after first closing the the types in :math:`C.\CTYPES` themselves. +Any form of :ref:`type ` can be *closed* to bring it into :ref:`closed ` form relative to a :ref:`context ` it is :ref:`valid ` in by :ref:`substituting ` each :ref:`type index ` :math:`x` occurring in it with the corresponding :ref:`defined type ` :math:`C.\CTYPES[x]`, after first closing the types in :math:`C.\CTYPES` themselves. .. math:: \begin{array}{@{}lcll@{}} diff --git a/document/core/valid/matching.rst b/document/core/valid/matching.rst index e5575b5ad1..af9c161edf 100644 --- a/document/core/valid/matching.rst +++ b/document/core/valid/matching.rst @@ -456,7 +456,7 @@ A :ref:`defined type ` :math:`\deftype_1` matches a type :math:` .. note:: Note that there is no explicit definition of type _equivalence_, since it coincides with syntactic equality, - as used in the premise of the fomer rule above. + as used in the premise of the former rule above. .. index:: limits diff --git a/proposals/gc/Overview.md b/proposals/gc/Overview.md index 7799a7f7ba..c4982342b8 100644 --- a/proposals/gc/Overview.md +++ b/proposals/gc/Overview.md @@ -437,8 +437,8 @@ For now, we assume that all array types have a ([flexible](#flexible-aggregates) Elements are accessed with generic load/store instructions that take a reference to an array: ``` (func $f (param $v (ref $vector)) - (array.get $vector (local.get $v) (i32.const 1) - (array.set $vector (local.get $v) (i32.const 2)) + (array.set $vector (local.get $v) (i32.const 1) + (array.get $vector (local.get $v) (i32.const 2)) ) ) ``` @@ -717,7 +717,7 @@ Another alternative would be a three-point mutability lattice with readonly as a The Wasm type system is intentionally simple. That implies that it cannot be expressive enough to track all type information that is available in a source program. -To allow producers to work around the inevitable limitations of the type system, down casts have to provided as an "escape hatch". +To allow producers to work around the inevitable limitations of the type system, down casts have to be provided as an "escape hatch". For example, that allows the use of type `anyref` to represent reference values whose type is not locally known. When such a value is used in a context where the producer knows its real type, it can use a down cast to recover it. @@ -776,7 +776,7 @@ There are a number of reasons to make RTTs explicit: * It allows more choice in producers' use of RTT information, including making it optional (post-MVP), in accordance with the pay-as-you-go principle: for example, structs that are not involved in any casts do not need to pay the overhead of carrying runtime type information (depending on specifics of the GC implementation strategy). Some languages may never need to introduce any RTTs at all. -* Most importantly, making RTTs explicit separates the concerns of casting from Wasm-level polymorphism, i.e., [type parameters](Post-MVP.md#type-parameters). Type parameters can thus be treated as purely a validation artifact with no bearing on runtime. This property, known as parametricity, drastically simplifies the implementation of such type parameterisation and avoids the substantial hidden costs of reified generics that would otherwise hvae to be paid for every single use of type parameters (short of non-trivial cross-procedural dataflow analysis in the engine). +* Most importantly, making RTTs explicit separates the concerns of casting from Wasm-level polymorphism, i.e., [type parameters](Post-MVP.md#type-parameters). Type parameters can thus be treated as purely a validation artifact with no bearing on runtime. This property, known as parametricity, drastically simplifies the implementation of such type parameterisation and avoids the substantial hidden costs of reified generics that would otherwise have to be paid for every single use of type parameters (short of non-trivial cross-procedural dataflow analysis in the engine). ## Future Extensions