From ef01de5ef4e7d5cc772110af2e30cc4fb722784a Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Mon, 12 Dec 2022 23:37:45 +0100 Subject: [PATCH 001/132] [interpreter] Refactor parser to handle select & call_indirect correctly (#1567) --- interpreter/text/parser.mly | 100 +++++++++++------------------------ test/core/call_indirect.wast | 20 +++++++ test/core/select.wast | 17 ++++++ 3 files changed, 67 insertions(+), 70 deletions(-) diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly index 535a05d5..7489acf7 100644 --- a/interpreter/text/parser.mly +++ b/interpreter/text/parser.mly @@ -366,12 +366,16 @@ align_opt : /* Instructions & Expressions */ -instr : +instr_list : + | /* empty */ { fun c -> [] } + | instr1 instr_list { fun c -> $1 c @ $2 c } + | select_instr_instr_list { $1 } + | call_instr_instr_list { $1 } + +instr1 : | plain_instr { let at = at () in fun c -> [$1 c @@ at] } - | select_instr_instr { fun c -> let e, es = $1 c in e :: es } - | call_instr_instr { fun c -> let e, es = $1 c in e :: es } | block_instr { let at = at () in fun c -> [$1 c @@ at] } - | expr { $1 } /* Sugar */ + | expr { $1 } /* Sugar */ plain_instr : | UNREACHABLE { fun c -> unreachable } @@ -442,89 +446,51 @@ plain_instr : | VEC_REPLACE NAT { let at = at () in fun c -> $1 (vec_lane_index $2 at) } -select_instr : - | SELECT select_instr_results - { let at = at () in fun c -> let b, ts = $2 in - select (if b then (Some ts) else None) @@ at } - -select_instr_results : - | LPAR RESULT value_type_list RPAR select_instr_results - { let _, ts = $5 in true, $3 @ ts } - | /* empty */ - { false, [] } - -select_instr_instr : - | SELECT select_instr_results_instr +select_instr_instr_list : + | SELECT select_instr_results_instr_list { let at1 = ati 1 in fun c -> let b, ts, es = $2 c in - select (if b then (Some ts) else None) @@ at1, es } + (select (if b then (Some ts) else None) @@ at1) :: es } -select_instr_results_instr : - | LPAR RESULT value_type_list RPAR select_instr_results_instr +select_instr_results_instr_list : + | LPAR RESULT value_type_list RPAR select_instr_results_instr_list { fun c -> let _, ts, es = $5 c in true, $3 @ ts, es } - | instr + | instr_list { fun c -> false, [], $1 c } -call_instr : - | CALL_INDIRECT var call_instr_type - { let at = at () in fun c -> call_indirect ($2 c table) ($3 c) @@ at } - | CALL_INDIRECT call_instr_type /* Sugar */ - { let at = at () in fun c -> call_indirect (0l @@ at) ($2 c) @@ at } - -call_instr_type : - | type_use call_instr_params - { let at1 = ati 1 in - fun c -> - match $2 c with - | FuncType ([], []) -> $1 c type_ - | ft -> inline_type_explicit c ($1 c type_) ft at1 } - | call_instr_params - { let at = at () in fun c -> inline_type c ($1 c) at } - -call_instr_params : - | LPAR PARAM value_type_list RPAR call_instr_params - { fun c -> let FuncType (ts1, ts2) = $5 c in FuncType ($3 @ ts1, ts2) } - | call_instr_results - { fun c -> FuncType ([], $1 c) } - -call_instr_results : - | LPAR RESULT value_type_list RPAR call_instr_results - { fun c -> $3 @ $5 c } - | /* empty */ - { fun c -> [] } - - -call_instr_instr : - | CALL_INDIRECT var call_instr_type_instr +call_instr_instr_list : + | CALL_INDIRECT var call_instr_type_instr_list { let at1 = ati 1 in - fun c -> let x, es = $3 c in call_indirect ($2 c table) x @@ at1, es } - | CALL_INDIRECT call_instr_type_instr /* Sugar */ + fun c -> let x, es = $3 c in + (call_indirect ($2 c table) x @@ at1) :: es } + | CALL_INDIRECT call_instr_type_instr_list /* Sugar */ { let at1 = ati 1 in - fun c -> let x, es = $2 c in call_indirect (0l @@ at1) x @@ at1, es } + fun c -> let x, es = $2 c in + (call_indirect (0l @@ at1) x @@ at1) :: es } -call_instr_type_instr : - | type_use call_instr_params_instr +call_instr_type_instr_list : + | type_use call_instr_params_instr_list { let at1 = ati 1 in fun c -> match $2 c with | FuncType ([], []), es -> $1 c type_, es | ft, es -> inline_type_explicit c ($1 c type_) ft at1, es } - | call_instr_params_instr + | call_instr_params_instr_list { let at = at () in fun c -> let ft, es = $1 c in inline_type c ft at, es } -call_instr_params_instr : - | LPAR PARAM value_type_list RPAR call_instr_params_instr +call_instr_params_instr_list : + | LPAR PARAM value_type_list RPAR call_instr_params_instr_list { fun c -> let FuncType (ts1, ts2), es = $5 c in FuncType ($3 @ ts1, ts2), es } - | call_instr_results_instr + | call_instr_results_instr_list { fun c -> let ts, es = $1 c in FuncType ([], ts), es } -call_instr_results_instr : - | LPAR RESULT value_type_list RPAR call_instr_results_instr +call_instr_results_instr_list : + | LPAR RESULT value_type_list RPAR call_instr_results_instr_list { fun c -> let ts, es = $5 c in $3 @ ts, es } - | instr + | instr_list { fun c -> [], $1 c } @@ -657,12 +623,6 @@ if_ : | LPAR THEN instr_list RPAR /* Sugar */ { fun c c' -> [], $3 c', [] } -instr_list : - | /* empty */ { fun c -> [] } - | select_instr { fun c -> [$1 c] } - | call_instr { fun c -> [$1 c] } - | instr instr_list { fun c -> $1 c @ $2 c } - expr_list : | /* empty */ { fun c -> [] } | expr expr_list { fun c -> $1 c @ $2 c } diff --git a/test/core/call_indirect.wast b/test/core/call_indirect.wast index 1ecd9b7b..79b8dc39 100644 --- a/test/core/call_indirect.wast +++ b/test/core/call_indirect.wast @@ -1015,3 +1015,23 @@ (module (table funcref (elem 0 0))) "unknown function" ) + + + + +;; Flat syntax + +(module + (table 1 funcref) + (func unreachable call_indirect) + (func unreachable call_indirect nop) + (func unreachable call_indirect call_indirect) + (func unreachable call_indirect (call_indirect)) + (func unreachable call_indirect call_indirect call_indirect) + (func unreachable call_indirect (result)) + (func unreachable call_indirect (result) (result)) + (func unreachable call_indirect (result) (result) call_indirect) + (func unreachable call_indirect (result) (result) call_indirect (result)) + (func (result i32) unreachable call_indirect select) + (func (result i32) unreachable call_indirect select call_indirect) +) diff --git a/test/core/select.wast b/test/core/select.wast index 046e6fe2..673dcf47 100644 --- a/test/core/select.wast +++ b/test/core/select.wast @@ -512,3 +512,20 @@ "type mismatch" ) + +;; Flat syntax + +(module + (table 1 funcref) + (func (result i32) unreachable select) + (func (result i32) unreachable select nop) + (func (result i32) unreachable select (select)) + (func (result i32) unreachable select select) + (func (result i32) unreachable select select select) + (func (result i32) unreachable select (result i32)) + (func (result i32) unreachable select (result i32) (result)) + (func (result i32) unreachable select (result i32) (result) select) + (func (result i32) unreachable select (result) (result i32) select (result i32)) + (func (result i32) unreachable select call_indirect) + (func (result i32) unreachable select call_indirect select) +) From a54a1d85400db3cf243717a0ab1cc2fb6098170f Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Thu, 15 Dec 2022 16:23:26 +0100 Subject: [PATCH 002/132] [spec] Remove dead piece of grammar --- document/core/exec/runtime.rst | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/document/core/exec/runtime.rst b/document/core/exec/runtime.rst index 9ee7eccc..6c53a4e9 100644 --- a/document/core/exec/runtime.rst +++ b/document/core/exec/runtime.rst @@ -476,8 +476,8 @@ Intuitively, :math:`\instr^\ast` is the *continuation* to execute when the branc When branching, the empty continuation ends the targeted block, such that execution can proceed with consecutive instructions. -Activations and Frames -...................... +Activation Frames +................. Activation frames carry the return arity :math:`n` of the respective function, hold the values of its :ref:`locals ` (including arguments) in the order corresponding to their static :ref:`local indices `, @@ -485,8 +485,6 @@ and a reference to the function's own :ref:`module instance ` .. math:: \begin{array}{llll} - \production{activation} & \X{activation} &::=& - \FRAME_n\{\frame\} \\ \production{frame} & \frame &::=& \{ \ALOCALS~\val^\ast, \AMODULE~\moduleinst \} \\ \end{array} From 1782235239ddebaf2cb079b00fdaa2d2c4dedba3 Mon Sep 17 00:00:00 2001 From: YAMAMOTO Takashi Date: Fri, 16 Dec 2022 00:24:54 +0900 Subject: [PATCH 003/132] [test] elem.wast: force to use exprs in a element (#1561) --- test/core/elem.wast | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/core/elem.wast b/test/core/elem.wast index 8dc04e6e..5857ae8b 100644 --- a/test/core/elem.wast +++ b/test/core/elem.wast @@ -148,6 +148,25 @@ (assert_return (invoke "call-7") (i32.const 65)) (assert_return (invoke "call-9") (i32.const 66)) +;; Same as the above, but use ref.null to ensure the elements use exprs. +;; Note: some tools like wast2json avoid using exprs when possible. +(module + (type $out-i32 (func (result i32))) + (table 11 funcref) + (elem (i32.const 6) funcref (ref.null func) (ref.func $const-i32-a)) + (elem (i32.const 9) funcref (ref.func $const-i32-b) (ref.null func)) + (func $const-i32-a (type $out-i32) (i32.const 65)) + (func $const-i32-b (type $out-i32) (i32.const 66)) + (func (export "call-7") (type $out-i32) + (call_indirect (type $out-i32) (i32.const 7)) + ) + (func (export "call-9") (type $out-i32) + (call_indirect (type $out-i32) (i32.const 9)) + ) +) +(assert_return (invoke "call-7") (i32.const 65)) +(assert_return (invoke "call-9") (i32.const 66)) + (assert_invalid (module (table 1 funcref) (global i32 (i32.const 0)) (elem (global.get 0) $f) (func $f)) "unknown global" From ca1d792430e353a7de0f2f4948fbb02bb0b83a65 Mon Sep 17 00:00:00 2001 From: Ng Zhi An Date: Tue, 17 Jan 2023 23:47:06 +0000 Subject: [PATCH 004/132] Fix typos in SIMD exec/instructions --- 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 6b028060..72893d64 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -394,7 +394,7 @@ Most vector instructions are defined in terms of generic numeric operators appli .. math:: \begin{array}{l} \begin{array}{lcl@{\qquad}l} - (\V128\K{.}\VCONST~c_1)~(\V128\K{.}\VCONST~c_2)~\V128\K{.}\SWIZZLE &\stepto& (\V128\K{.}\VCONST~c') + (\V128\K{.}\VCONST~c_1)~(\V128\K{.}\VCONST~c_2)~\I8X16\K{.}\SWIZZLE &\stepto& (\V128\K{.}\VCONST~c') \end{array} \\ \qquad \begin{array}[t]{@{}r@{~}l@{}} @@ -431,7 +431,7 @@ Most vector instructions are defined in terms of generic numeric operators appli .. math:: \begin{array}{l} \begin{array}{lcl@{\qquad}l} - (\V128\K{.}\VCONST~c_1)~(\V128\K{.}\VCONST~c_2)~\V128\K{.}\SHUFFLE~x^\ast &\stepto& (\V128\K{.}\VCONST~c) + (\V128\K{.}\VCONST~c_1)~(\V128\K{.}\VCONST~c_2)~\I8X16\K{.}\SHUFFLE~x^\ast &\stepto& (\V128\K{.}\VCONST~c) \end{array} \\ \qquad \begin{array}[t]{@{}r@{~}l@{}} From 4c249c5a575e2b0e252e747af261bbb82f448dd4 Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Wed, 18 Jan 2023 16:34:13 -0600 Subject: [PATCH 005/132] Update interpreter README (#1571) It previously stated that the formal spec did not exist, but the spec has existed for years now. --- interpreter/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interpreter/README.md b/interpreter/README.md index 418b8450..18aa36c0 100644 --- a/interpreter/README.md +++ b/interpreter/README.md @@ -1,6 +1,6 @@ # WebAssembly Reference Interpreter -This repository implements a interpreter for WebAssembly. It is written for clarity and simplicity, _not_ speed. It is intended as a playground for trying out ideas and a device for nailing down the exact semantics, and as a proxy for the (yet to be produced) formal specification of WebAssembly. For that purpose, the code is written in a fairly declarative, "speccy" way. +This repository implements an interpreter for WebAssembly. It is written for clarity and simplicity, _not_ speed. It is intended as a playground for trying out ideas and a device for nailing down their exact semantics. For that purpose, the code is written in a fairly declarative, "speccy" way. The interpreter can From f54b5b81a3649461b4c8be0363844301983868ab Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Tue, 24 Jan 2023 12:22:06 +0100 Subject: [PATCH 006/132] [spec] Remove an obsolete exec step (#1580) --- document/core/exec/instructions.rst | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index 72893d64..cc66dbf2 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -2912,15 +2912,13 @@ Invocation of :ref:`function address ` :math:`a` 7. Pop the values :math:`\val^n` from the stack. -8. Let :math:`\val_0^\ast` be the list of zero values of types :math:`t^\ast`. +8. Let :math:`F` be the :ref:`frame ` :math:`\{ \AMODULE~f.\FIMODULE, \ALOCALS~\val^n~(\default_t)^\ast \}`. -9. Let :math:`F` be the :ref:`frame ` :math:`\{ \AMODULE~f.\FIMODULE, \ALOCALS~\val^n~(\default_t)^\ast \}`. +9. Push the activation of :math:`F` with arity :math:`m` to the stack. -10. Push the activation of :math:`F` with arity :math:`m` to the stack. +10. Let :math:`L` be the :ref:`label ` whose arity is :math:`m` and whose continuation is the end of the function. -11. Let :math:`L` be the :ref:`label ` whose arity is :math:`m` and whose continuation is the end of the function. - -12. :ref:`Enter ` the instruction sequence :math:`\instr^\ast` with label :math:`L`. +11. :ref:`Enter ` the instruction sequence :math:`\instr^\ast` with label :math:`L`. .. math:: ~\\[-1ex] From 6798f054ad1b0493919f0b5244fa46682ccd3e69 Mon Sep 17 00:00:00 2001 From: Keith Winstein Date: Tue, 24 Jan 2023 04:32:02 -0800 Subject: [PATCH 007/132] [test] Optional tableidx for table.{get,set,size,grow,fill} (#1582) --- test/core/table_fill.wast | 6 +++++- test/core/table_get.wast | 2 +- test/core/table_grow.wast | 5 ++++- test/core/table_set.wast | 2 +- test/core/table_size.wast | 2 +- 5 files changed, 12 insertions(+), 5 deletions(-) diff --git a/test/core/table_fill.wast b/test/core/table_fill.wast index 3df64da1..a8e22255 100644 --- a/test/core/table_fill.wast +++ b/test/core/table_fill.wast @@ -5,6 +5,10 @@ (table.fill $t (local.get $i) (local.get $r) (local.get $n)) ) + (func (export "fill-abbrev") (param $i i32) (param $r externref) (param $n i32) + (table.fill (local.get $i) (local.get $r) (local.get $n)) + ) + (func (export "get") (param $i i32) (result externref) (table.get $t (local.get $i)) ) @@ -39,7 +43,7 @@ (assert_return (invoke "get" (i32.const 8)) (ref.extern 4)) (assert_return (invoke "get" (i32.const 9)) (ref.extern 4)) -(assert_return (invoke "fill" (i32.const 9) (ref.null extern) (i32.const 1))) +(assert_return (invoke "fill-abbrev" (i32.const 9) (ref.null extern) (i32.const 1))) (assert_return (invoke "get" (i32.const 8)) (ref.extern 4)) (assert_return (invoke "get" (i32.const 9)) (ref.null extern)) diff --git a/test/core/table_get.wast b/test/core/table_get.wast index 5d57c319..0dedb19f 100644 --- a/test/core/table_get.wast +++ b/test/core/table_get.wast @@ -10,7 +10,7 @@ ) (func (export "get-externref") (param $i i32) (result externref) - (table.get $t2 (local.get $i)) + (table.get (local.get $i)) ) (func $f3 (export "get-funcref") (param $i i32) (result funcref) (table.get $t3 (local.get $i)) diff --git a/test/core/table_grow.wast b/test/core/table_grow.wast index 7d5b5630..9a931a7f 100644 --- a/test/core/table_grow.wast +++ b/test/core/table_grow.wast @@ -7,6 +7,9 @@ (func (export "grow") (param $sz i32) (param $init externref) (result i32) (table.grow $t (local.get $init) (local.get $sz)) ) + (func (export "grow-abbrev") (param $sz i32) (param $init externref) (result i32) + (table.grow (local.get $init) (local.get $sz)) + ) (func (export "size") (result i32) (table.size $t)) ) @@ -22,7 +25,7 @@ (assert_trap (invoke "set" (i32.const 1) (ref.extern 2)) "out of bounds table access") (assert_trap (invoke "get" (i32.const 1)) "out of bounds table access") -(assert_return (invoke "grow" (i32.const 4) (ref.extern 3)) (i32.const 1)) +(assert_return (invoke "grow-abbrev" (i32.const 4) (ref.extern 3)) (i32.const 1)) (assert_return (invoke "size") (i32.const 5)) (assert_return (invoke "get" (i32.const 0)) (ref.extern 2)) (assert_return (invoke "set" (i32.const 0) (ref.extern 2))) diff --git a/test/core/table_set.wast b/test/core/table_set.wast index 5a9cfa37..3362f956 100644 --- a/test/core/table_set.wast +++ b/test/core/table_set.wast @@ -12,7 +12,7 @@ ) (func (export "set-externref") (param $i i32) (param $r externref) - (table.set $t2 (local.get $i) (local.get $r)) + (table.set (local.get $i) (local.get $r)) ) (func (export "set-funcref") (param $i i32) (param $r funcref) (table.set $t3 (local.get $i) (local.get $r)) diff --git a/test/core/table_size.wast b/test/core/table_size.wast index ad293b5e..83fef02b 100644 --- a/test/core/table_size.wast +++ b/test/core/table_size.wast @@ -4,7 +4,7 @@ (table $t2 0 2 externref) (table $t3 3 8 externref) - (func (export "size-t0") (result i32) (table.size $t0)) + (func (export "size-t0") (result i32) table.size) (func (export "size-t1") (result i32) (table.size $t1)) (func (export "size-t2") (result i32) (table.size $t2)) (func (export "size-t3") (result i32) (table.size $t3)) From 7d905dfa61b25ad58b71490eacfb13e70290b5ef Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Thu, 26 Jan 2023 17:03:14 +0100 Subject: [PATCH 008/132] [spec] Fix abstract grammar for const immediate (#1577) --- 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 eae802cb..9c48736b 100644 --- a/document/core/syntax/instructions.rst +++ b/document/core/syntax/instructions.rst @@ -45,7 +45,7 @@ These operations closely match respective operations available in hardware. \production{signedness} & \sx &::=& \K{u} ~|~ \K{s} \\ \production{instruction} & \instr &::=& - \K{i}\X{nn}\K{.}\CONST~\xref{syntax/values}{syntax-int}{\iX{\X{nn}}} ~|~ + \K{i}\X{nn}\K{.}\CONST~\xref{syntax/values}{syntax-int}{\uX{\X{nn}}} ~|~ \K{f}\X{nn}\K{.}\CONST~\xref{syntax/values}{syntax-float}{\fX{\X{nn}}} \\&&|& \K{i}\X{nn}\K{.}\iunop ~|~ \K{f}\X{nn}\K{.}\funop \\&&|& From 0031ea49613c72522eeff11e0511d423cb64645f Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Thu, 26 Jan 2023 17:03:48 +0100 Subject: [PATCH 009/132] [spec] Fix context composition in text format (#1578) --- document/core/text/modules.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/document/core/text/modules.rst b/document/core/text/modules.rst index fde59878..c3407732 100644 --- a/document/core/text/modules.rst +++ b/document/core/text/modules.rst @@ -108,7 +108,7 @@ If inline declarations are given, then their types must match the referenced :re \end{array} \\ \end{array} -The synthesized attribute of a |Ttypeuse| is a pair consisting of both the used :ref:`type index ` and the updated :ref:`identifier context ` including possible parameter identifiers. +The synthesized attribute of a |Ttypeuse| is a pair consisting of both the used :ref:`type index ` and the local :ref:`identifier context ` containing possible parameter identifiers. The following auxiliary function extracts optional identifiers from parameters: .. math:: @@ -200,7 +200,7 @@ Function definitions can bind a symbolic :ref:`function identifier `, a \text{(}~\text{func}~~\Tid^?~~x,I'{:}\Ttypeuse_I~~ (t{:}\Tlocal)^\ast~~(\X{in}{:}\Tinstr_{I''})^\ast~\text{)} \\ &&& \qquad \Rightarrow\quad \{ \FTYPE~x, \FLOCALS~t^\ast, \FBODY~\X{in}^\ast~\END \} \\ &&& \qquad\qquad\qquad - (\iff I'' = I' \compose \{\ILOCALS~\F{id}(\Tlocal)^\ast\} \idcwellformed) \\[1ex] + (\iff I'' = I \compose I' \compose \{\ILOCALS~\F{id}(\Tlocal)^\ast\} \idcwellformed) \\[1ex] \production{local} & \Tlocal &::=& \text{(}~\text{local}~~\Tid^?~~t{:}\Tvaltype~\text{)} \quad\Rightarrow\quad t \\ From dcf4eaa08fe1b3f98e855e0581389bc29f5d496b Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Thu, 26 Jan 2023 17:04:44 +0100 Subject: [PATCH 010/132] [spec] Fix label shadowing (#1579) --- document/core/text/instructions.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/document/core/text/instructions.rst b/document/core/text/instructions.rst index 348aa773..e846ccb5 100644 --- a/document/core/text/instructions.rst +++ b/document/core/text/instructions.rst @@ -34,6 +34,8 @@ The following grammar handles the corresponding update to the :ref:`identifier c \production{label} & \Tlabel_I &::=& v{:}\Tid &\Rightarrow& \{\ILABELS~v\} \compose I & (\iff v \notin I.\ILABELS) \\ &&|& + v{:}\Tid &\Rightarrow& \{\ILABELS~v\} \compose (I \with \ILABELS[i] = \epsilon) + & (\iff I.\ILABELS[i] = v) \\ &&|& \epsilon &\Rightarrow& \{\ILABELS~(\epsilon)\} \compose I \\ \end{array} @@ -42,6 +44,9 @@ The following grammar handles the corresponding update to the :ref:`identifier c This effectively shifts all existing labels up by one, mirroring the fact that control instructions are indexed relatively not absolutely. + If a label with the same name already exists, + then it is shadowed and the earlier label becomes inaccessible. + .. index:: control instructions, structured control, label, block, branch, result type, label index, function index, type index, vector, polymorphism pair: text format; instruction From 45f9845d4ecb92984dd573c93b7143ad42726bf8 Mon Sep 17 00:00:00 2001 From: candymate <31069474+candymate@users.noreply.github.com> Date: Tue, 31 Jan 2023 18:31:53 +0900 Subject: [PATCH 011/132] [spec] Fix typos in instruction index (#1584) --- document/core/appendix/gen-index-instructions.py | 8 ++++---- document/core/appendix/index-instructions.rst | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/document/core/appendix/gen-index-instructions.py b/document/core/appendix/gen-index-instructions.py index 65a97171..fffa2b32 100755 --- a/document/core/appendix/gen-index-instructions.py +++ b/document/core/appendix/gen-index-instructions.py @@ -427,10 +427,10 @@ def Instruction(name, opcode, type=None, validation=None, execution=None, operat Instruction(r'\V128.\LOAD\K{16\_lane}~\memarg~\laneidx', r'\hex{FD}~~\hex{55}', r'[\I32~\V128] \to [\V128]', r'valid-load-lane', r'exec-load-lane'), Instruction(r'\V128.\LOAD\K{32\_lane}~\memarg~\laneidx', r'\hex{FD}~~\hex{56}', r'[\I32~\V128] \to [\V128]', r'valid-load-lane', r'exec-load-lane'), Instruction(r'\V128.\LOAD\K{64\_lane}~\memarg~\laneidx', r'\hex{FD}~~\hex{57}', r'[\I32~\V128] \to [\V128]', r'valid-load-lane', r'exec-load-lane'), - Instruction(r'\V128.\STORE\K{8\_lane}~\memarg~\laneidx', r'\hex{FD}~~\hex{58}', r'[\I32~\V128] \to [\V128]', r'valid-store-lane', r'exec-store-lane'), - Instruction(r'\V128.\STORE\K{16\_lane}~\memarg~\laneidx', r'\hex{FD}~~\hex{59}', r'[\I32~\V128] \to [\V128]', r'valid-store-lane', r'exec-store-lane'), - Instruction(r'\V128.\STORE\K{32\_lane}~\memarg~\laneidx', r'\hex{FD}~~\hex{5A}', r'[\I32~\V128] \to [\V128]', r'valid-store-lane', r'exec-store-lane'), - Instruction(r'\V128.\STORE\K{64\_lane}~\memarg~\laneidx', r'\hex{FD}~~\hex{5B}', r'[\I32~\V128] \to [\V128]', r'valid-store-lane', r'exec-store-lane'), + Instruction(r'\V128.\STORE\K{8\_lane}~\memarg~\laneidx', r'\hex{FD}~~\hex{58}', r'[\I32~\V128] \to []', r'valid-store-lane', r'exec-store-lane'), + Instruction(r'\V128.\STORE\K{16\_lane}~\memarg~\laneidx', r'\hex{FD}~~\hex{59}', r'[\I32~\V128] \to []', r'valid-store-lane', r'exec-store-lane'), + Instruction(r'\V128.\STORE\K{32\_lane}~\memarg~\laneidx', r'\hex{FD}~~\hex{5A}', r'[\I32~\V128] \to []', r'valid-store-lane', r'exec-store-lane'), + Instruction(r'\V128.\STORE\K{64\_lane}~\memarg~\laneidx', r'\hex{FD}~~\hex{5B}', r'[\I32~\V128] \to []', r'valid-store-lane', r'exec-store-lane'), Instruction(r'\V128.\LOAD\K{32\_zero}~\memarg~\laneidx', r'\hex{FD}~~\hex{5C}', r'[\I32] \to [\V128]', r'valid-load-zero', r'exec-load-zero'), Instruction(r'\V128.\LOAD\K{64\_zero}~\memarg~\laneidx', r'\hex{FD}~~\hex{5D}', r'[\I32] \to [\V128]', r'valid-load-zero', r'exec-load-zero'), Instruction(r'\F32X4.\VDEMOTE\K{\_f64x2\_zero}', r'\hex{FD}~~\hex{5E}', r'[\V128] \to [\V128]', r'valid-vcvtop', r'exec-vcvtop', r'op-demote'), diff --git a/document/core/appendix/index-instructions.rst b/document/core/appendix/index-instructions.rst index 84055a9f..977c21fb 100644 --- a/document/core/appendix/index-instructions.rst +++ b/document/core/appendix/index-instructions.rst @@ -367,10 +367,10 @@ Instruction Binary Opcode :math:`\V128.\LOAD\K{16\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{55}` :math:`[\I32~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` :math:`\V128.\LOAD\K{32\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{56}` :math:`[\I32~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` :math:`\V128.\LOAD\K{64\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{57}` :math:`[\I32~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\STORE\K{8\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{58}` :math:`[\I32~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\STORE\K{16\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{59}` :math:`[\I32~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\STORE\K{32\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{5A}` :math:`[\I32~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\STORE\K{64\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{5B}` :math:`[\I32~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\V128.\STORE\K{8\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{58}` :math:`[\I32~\V128] \to []` :ref:`validation ` :ref:`execution ` +:math:`\V128.\STORE\K{16\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{59}` :math:`[\I32~\V128] \to []` :ref:`validation ` :ref:`execution ` +:math:`\V128.\STORE\K{32\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{5A}` :math:`[\I32~\V128] \to []` :ref:`validation ` :ref:`execution ` +:math:`\V128.\STORE\K{64\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{5B}` :math:`[\I32~\V128] \to []` :ref:`validation ` :ref:`execution ` :math:`\V128.\LOAD\K{32\_zero}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{5C}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` :math:`\V128.\LOAD\K{64\_zero}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{5D}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` :math:`\F32X4.\VDEMOTE\K{\_f64x2\_zero}` :math:`\hex{FD}~~\hex{5E}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` From 947badf48a7e2b27aeec7a0eaad6b3053032d9f1 Mon Sep 17 00:00:00 2001 From: Bongjun Jang Date: Tue, 7 Feb 2023 17:00:10 +0900 Subject: [PATCH 012/132] [spec] Fix typo (#1587) --- document/core/text/instructions.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/document/core/text/instructions.rst b/document/core/text/instructions.rst index e846ccb5..0e8c577d 100644 --- a/document/core/text/instructions.rst +++ b/document/core/text/instructions.rst @@ -165,7 +165,7 @@ Reference Instructions \production{instruction} & \Tplaininstr_I &::=& \dots \\ &&|& \text{ref.null}~~t{:}\Theaptype &\Rightarrow& \REFNULL~t \\ &&|& \text{ref.is\_null} &\Rightarrow& \REFISNULL \\ &&|& - \text{ref.func}~~x{:}\Tfuncidx &\Rightarrow& \REFFUNC~x \\ &&|& + \text{ref.func}~~x{:}\Tfuncidx &\Rightarrow& \REFFUNC~x \\ \end{array} @@ -891,7 +891,7 @@ Vector constant instructions have a mandatory :ref:`shape ` de \text{f64x2.convert\_low\_i32x4\_s} &\Rightarrow& \F64X2.\VCONVERT\K{\_low\_i32x4\_s}\\ &&|& \text{f64x2.convert\_low\_i32x4\_u} &\Rightarrow& \F64X2.\VCONVERT\K{\_low\_i32x4\_u}\\ &&|& \text{f32x4.demote\_f64x2\_zero} &\Rightarrow& \F32X4.\VDEMOTE\K{\_f64x2\_zero}\\ &&|& - \text{f64x2.promote\_low\_f32x4} &\Rightarrow& \F64X2.\VPROMOTE\K{\_low\_f32x4}\\ &&|& + \text{f64x2.promote\_low\_f32x4} &\Rightarrow& \F64X2.\VPROMOTE\K{\_low\_f32x4}\\ \end{array} From b1fbe1a89a812a031f556392185cb8d9c65beeb8 Mon Sep 17 00:00:00 2001 From: ShinWonho <50018375+ShinWonho@users.noreply.github.com> Date: Wed, 8 Feb 2023 18:07:52 +0900 Subject: [PATCH 013/132] [spec] Remove inconsistent newline (#1589) --- document/core/exec/modules.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/document/core/exec/modules.rst b/document/core/exec/modules.rst index 4dfdb973..578acfa2 100644 --- a/document/core/exec/modules.rst +++ b/document/core/exec/modules.rst @@ -449,8 +449,7 @@ and list of :ref:`reference ` vectors for the module's :ref:`element a. Let :math:`\limits_i~t_i` be the :ref:`table type ` :math:`\table_i.\TTYPE`. - b. Let :math:`\tableaddr_i` be the :ref:`table address ` resulting from :ref:`allocating ` :math:`\table_i.\TTYPE` - with initialization value :math:`\REFNULL~t_i`. + b. Let :math:`\tableaddr_i` be the :ref:`table address ` resulting from :ref:`allocating ` :math:`\table_i.\TTYPE` with initialization value :math:`\REFNULL~t_i`. 4. For each :ref:`memory ` :math:`\mem_i` in :math:`\module.\MMEMS`, do: From 2b4222d04d33d7d69bdf7a54e018ce3a486d89b1 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Thu, 9 Feb 2023 10:24:19 +0100 Subject: [PATCH 014/132] [interpreter] Remove legacy bigarray linking (#1593) --- interpreter/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interpreter/Makefile b/interpreter/Makefile index 7820e642..499b3a63 100644 --- a/interpreter/Makefile +++ b/interpreter/Makefile @@ -18,7 +18,7 @@ JSLIB = wast WINMAKE = winmake.bat DIRS = util syntax binary text valid runtime exec script host main tests -LIBS = bigarray +LIBS = FLAGS = -lexflags -ml -cflags '-w +a-4-27-42-44-45-70 -warn-error +a-3' OCBA = ocamlbuild $(FLAGS) $(DIRS:%=-I %) OCB = $(OCBA) $(LIBS:%=-libs %) From aa15776984dc41c5f07463297c02fc3f84185437 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=84=9C=EB=8F=99=ED=9C=98?= Date: Fri, 10 Feb 2023 00:25:08 +0900 Subject: [PATCH 015/132] [spec] Show scrolls for overflow math blocks (#1594) --- document/core/static/custom.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/document/core/static/custom.css b/document/core/static/custom.css index 45838c1e..33bb863d 100644 --- a/document/core/static/custom.css +++ b/document/core/static/custom.css @@ -44,6 +44,8 @@ div.admonition p.admonition-title { div.math { background-color: #F0F0F0; padding: 3px 0 3px 0; + overflow-x: auto; + overflow-y: hidden; } div.relations { From 31cabf87f8e605d71933d724430831a841d2d298 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Thu, 9 Feb 2023 18:02:34 +0100 Subject: [PATCH 016/132] [interpreter] Run JS tests via node.js (#1595) --- .github/workflows/main.yml | 4 ++++ interpreter/Makefile | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 00b70e8f..2e43f200 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -19,6 +19,10 @@ jobs: with: ocaml-compiler: 4.12.x - run: opam install --yes ocamlbuild.0.14.0 + - name: Setup Node.js + uses: actions/setup-node@v1 + with: + node-version: 18.x - run: cd interpreter && opam exec make all ref-interpreter-js-library: diff --git a/interpreter/Makefile b/interpreter/Makefile index 499b3a63..78cbea55 100644 --- a/interpreter/Makefile +++ b/interpreter/Makefile @@ -23,7 +23,7 @@ FLAGS = -lexflags -ml -cflags '-w +a-4-27-42-44-45-70 -warn-error +a-3' OCBA = ocamlbuild $(FLAGS) $(DIRS:%=-I %) OCB = $(OCBA) $(LIBS:%=-libs %) JSO = js_of_ocaml -q --opt 3 -JS = # set to JS shell command to run JS tests +JS = node # set to JS shell command to run JS tests, empty to skip # Main targets From e7f6e1c45acc396281e31df78d8ad531ab65a2ee Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Fri, 10 Feb 2023 17:46:52 -0800 Subject: [PATCH 017/132] [spec] Remove stray `x` indices (#1598) --- 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 cc66dbf2..bf5acdfe 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -2244,7 +2244,7 @@ Memory Instructions S; F; (\I32.\CONST~d)~\val~(\I32.\CONST~n)~\MEMORYFILL \quad\stepto\quad S; F; \TRAP \\ \qquad - (\iff d + n > |S.\SMEMS[F.\AMODULE.\MIMEMS[x]].\MIDATA|) + (\iff d + n > |S.\SMEMS[F.\AMODULE.\MIMEMS[0]].\MIDATA|) \\[1ex] S; F; (\I32.\CONST~d)~\val~(\I32.\CONST~0)~\MEMORYFILL \quad\stepto\quad S; F; \epsilon @@ -2451,7 +2451,7 @@ Memory Instructions \\ \qquad \begin{array}[t]{@{}r@{~}l@{}} (\iff & s + n > |S.\SDATAS[F.\AMODULE.\MIDATAS[x]].\DIDATA| \\ - \vee & d + n > |S.\SMEMS[F.\AMODULE.\MIMEMS[x]].\MIDATA|) \\[1ex] + \vee & d + n > |S.\SMEMS[F.\AMODULE.\MIMEMS[0]].\MIDATA|) \\[1ex] \end{array} \\[1ex] S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~0)~(\MEMORYINIT~x) From f8ae6b2443a0f1e6ebc62e2fdbe49e2a98008a17 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Mon, 13 Feb 2023 12:43:34 +0100 Subject: [PATCH 018/132] [spec] Style tweak for cross-refs --- document/core/conf.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/document/core/conf.py b/document/core/conf.py index 22a578a2..3952701b 100644 --- a/document/core/conf.py +++ b/document/core/conf.py @@ -297,7 +297,8 @@ 'pointsize': '10pt', # Additional stuff for the LaTeX preamble. - 'preamble': '', + # Don't type-set cross references with emphasis. + 'preamble': '\\renewcommand\\sphinxcrossref[1]{#1}\n', # Latex figure (float) alignment 'figure_align': 'htbp', From 0f068801d6bcd0219e5ede2a71fcde1d130e3853 Mon Sep 17 00:00:00 2001 From: Bongjun Jang Date: Mon, 13 Feb 2023 21:16:43 +0900 Subject: [PATCH 019/132] [spec] Style eps (#1601) --- 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 f4664666..1dd34c86 100644 --- a/document/core/text/lexical.rst +++ b/document/core/text/lexical.rst @@ -48,7 +48,7 @@ The character stream in the source text is divided, from left to right, into a s \text{(} ~|~ \text{)} ~|~ \Treserved \\ \production{keyword} & \Tkeyword &::=& (\text{a} ~|~ \dots ~|~ \text{z})~\Tidchar^\ast - \qquad (\mbox{if occurring as a literal terminal in the grammar}) \\ + \qquad (\iff~\mbox{occurring as a literal terminal in the grammar}) \\ \production{reserved} & \Treserved &::=& (\Tidchar ~|~ \Tstring)^+ \\ \end{array} From 328e425226dad03539ec0a3891fe0ba6426cc62c Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Thu, 16 Feb 2023 07:00:49 +0100 Subject: [PATCH 020/132] [spec] Clarify that atoms can be symbolic (#1602) --- document/core/syntax/conventions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/document/core/syntax/conventions.rst b/document/core/syntax/conventions.rst index 9e5dca18..5eeff48c 100644 --- a/document/core/syntax/conventions.rst +++ b/document/core/syntax/conventions.rst @@ -20,7 +20,7 @@ Grammar Notation The following conventions are adopted in defining grammar rules for abstract syntax. -* Terminal symbols (atoms) are written in sans-serif font: :math:`\K{i32}, \K{end}`. +* Terminal symbols (atoms) are written in sans-serif font or in symbolic form: :math:`\K{i32}, \K{end}, {\to}, [, ]`. * Nonterminal symbols are written in italic font: :math:`\X{valtype}, \X{instr}`. From deeb164186d17bdb8a5234c3639e143a8cf71700 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Thu, 16 Feb 2023 11:46:44 +0100 Subject: [PATCH 021/132] [test] Import v128 global (#1597) --- .github/workflows/main.yml | 2 +- interpreter/Makefile | 2 +- test/core/linking.wast | 14 ++++++++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2e43f200..0ff1bd5f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -23,7 +23,7 @@ jobs: uses: actions/setup-node@v1 with: node-version: 18.x - - run: cd interpreter && opam exec make all + - run: cd interpreter && opam exec make JS=node all ref-interpreter-js-library: runs-on: ubuntu-latest diff --git a/interpreter/Makefile b/interpreter/Makefile index 78cbea55..97e6e17c 100644 --- a/interpreter/Makefile +++ b/interpreter/Makefile @@ -23,7 +23,7 @@ FLAGS = -lexflags -ml -cflags '-w +a-4-27-42-44-45-70 -warn-error +a-3' OCBA = ocamlbuild $(FLAGS) $(DIRS:%=-I %) OCB = $(OCBA) $(LIBS:%=-libs %) JSO = js_of_ocaml -q --opt 3 -JS = node # set to JS shell command to run JS tests, empty to skip +JS = # set to JS shell command to run JS tests, empty to skip # Main targets diff --git a/test/core/linking.wast b/test/core/linking.wast index 994e0f49..578a8c18 100644 --- a/test/core/linking.wast +++ b/test/core/linking.wast @@ -129,6 +129,20 @@ ) +(module + (global (export "g-v128") v128 (v128.const i64x2 0 0)) + (global (export "mg-v128") (mut v128) (v128.const i64x2 0 0)) +) +(register "Mv128") + +(module + ;; TODO: Reactivate once the fix for https://bugs.chromium.org/p/v8/issues/detail?id=13732 + ;; has made it to the downstream node.js that we use on CI. + ;; (import "Mv128" "g-v128" (global v128)) + (import "Mv128" "mg-v128" (global (mut v128))) +) + + ;; Tables (module $Mt From 19b1243cea1d8c3898ea56e9b193fa9fba9f4583 Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Wed, 12 Oct 2022 15:39:40 +0200 Subject: [PATCH 022/132] [js-api] Expose everywhere --- document/js-api/index.bs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/document/js-api/index.bs b/document/js-api/index.bs index b22e825c..1f703401 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -282,7 +282,7 @@ dictionary WebAssemblyInstantiatedSource { required Instance instance; }; -[Exposed=(Window,Worker,Worklet)] +[Exposed=*] namespace WebAssembly { boolean validate(BufferSource bytes); Promise<Module> compile(BufferSource bytes); @@ -537,7 +537,7 @@ dictionary ModuleImportDescriptor { required ImportExportKind kind; }; -[LegacyNamespace=WebAssembly, Exposed=(Window,Worker,Worklet)] +[LegacyNamespace=WebAssembly, Exposed=*] interface Module { constructor(BufferSource bytes); static sequence<ModuleExportDescriptor> exports(Module moduleObject); @@ -601,7 +601,7 @@ interface Module {

Instances

-[LegacyNamespace=WebAssembly, Exposed=(Window,Worker,Worklet)]
+[LegacyNamespace=WebAssembly, Exposed=*]
 interface Instance {
   constructor(Module module, optional object importObject);
   readonly attribute object exports;
@@ -628,7 +628,7 @@ dictionary MemoryDescriptor {
   [EnforceRange] unsigned long maximum;
 };
 
-[LegacyNamespace=WebAssembly, Exposed=(Window,Worker,Worklet)]
+[LegacyNamespace=WebAssembly, Exposed=*]
 interface Memory {
   constructor(MemoryDescriptor descriptor);
   unsigned long grow([EnforceRange] unsigned long delta);
@@ -738,7 +738,7 @@ dictionary TableDescriptor {
   [EnforceRange] unsigned long maximum;
 };
 
-[LegacyNamespace=WebAssembly, Exposed=(Window,Worker,Worklet)]
+[LegacyNamespace=WebAssembly, Exposed=*]
 interface Table {
   constructor(TableDescriptor descriptor, optional any value);
   unsigned long grow([EnforceRange] unsigned long delta, optional any value);
@@ -860,7 +860,7 @@ dictionary GlobalDescriptor {
   boolean mutable = false;
 };
 
-[LegacyNamespace=WebAssembly, Exposed=(Window,Worker,Worklet)]
+[LegacyNamespace=WebAssembly, Exposed=*]
 interface Global {
   constructor(GlobalDescriptor descriptor, optional any v);
   any valueOf();

From 4feb91964f8e5e80d416abd6e9f62cc626c7c600 Mon Sep 17 00:00:00 2001
From: Ms2ger 
Date: Thu, 16 Feb 2023 15:58:14 +0100
Subject: [PATCH 023/132] [js-api] Try to clarify NaN/infinity handling.
 (#1535)

---
 document/js-api/index.bs | 36 ++++++++++++++++++++++++++++++------
 1 file changed, 30 insertions(+), 6 deletions(-)

diff --git a/document/js-api/index.bs b/document/js-api/index.bs
index 1f703401..961918ea 100644
--- a/document/js-api/index.bs
+++ b/document/js-api/index.bs
@@ -93,6 +93,8 @@ urlPrefix: https://tc39.github.io/ecma262/; spec: ECMASCRIPT
         text: IterableToList; url: sec-iterabletolist
         text: ToBigInt64; url: #sec-tobigint64
         text: BigInt; url: #sec-ecmascript-language-types-bigint-type
+        text: ๐”ฝ; url: #๐”ฝ
+        text: โ„ค; url: #โ„ค
     type: abstract-op
         text: CreateMethodProperty; url: sec-createmethodproperty
 urlPrefix: https://webassembly.github.io/spec/core/; spec: WebAssembly; type: dfn
@@ -163,6 +165,12 @@ urlPrefix: https://webassembly.github.io/spec/core/; spec: WebAssembly; type: df
         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
     text: external value; url: exec/runtime.html#syntax-externval
@@ -1087,10 +1095,16 @@ The algorithm ToJSValue(|w|) coerces a [=WebAssembly value=] to a Jav
 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 a [=BigInt=] representing the mathematical value |v|.
-1. If |w| is of the form [=i32.const=] |i32|, return [=the Number value=] for [=signed_32=](|i32|).
-1. If |w| is of the form [=f32.const=] |f32|, return [=the Number value=] for |f32|.
-1. If |w| is of the form [=f64.const=] |f64|, return [=the Number value=] for |f64|.
+    1. Return [=โ„ค=](|v| interpreted as a mathematical value).
+1. If |w| is of the form [=i32.const=] |i32|, return [=๐”ฝ=]([=signed_32=](|i32| interpreted as a mathematical value)).
+1. If |w| is of the form [=f32.const=] |f32|,
+    1. If |f32| is [=+โˆž=] or [=โˆ’โˆž=], return **+โˆž**๐”ฝ or **-โˆž**๐”ฝ, respectively.
+    1. If |f32| is [=nan=], return **NaN**.
+    1. Return [=๐”ฝ=](|f32| interpreted as a mathematical value).
+1. If |w| is of the form [=f64.const=] |f64|,
+    1. If |f64| is [=+โˆž=] or [=โˆ’โˆž=], return **+โˆž**๐”ฝ or **-โˆž**๐”ฝ, respectively.
+    1. If |f64| is [=nan=], return **NaN**.
+    1. Return [=๐”ฝ=](|f64| interpreted as a mathematical value).
 1. If |w| is of the form [=ref.null=] t, return null.
 1. If |w| is of the form [=ref.func=] |funcaddr|, return the result of creating [=a new Exported Function=] from |funcaddr|.
 1. If |w| is of the form [=ref.extern=] |externaddr|, return the result of [=retrieving an extern value=] from |externaddr|.
@@ -1119,10 +1133,20 @@ The algorithm ToWebAssemblyValue(|v|, |type|) coerces a JavaScript va
     1. Let |i32| be [=?=] [=ToInt32=](|v|).
     1. Return [=i32.const=] |i32|.
 1. If |type| is [=f32=],
-    1. Let |f32| be [=?=] [=ToNumber=](|v|) rounded to the nearest representable value using IEEE 754-2008 round to nearest, ties to even mode.
+    1. Let |number| be [=?=] [=ToNumber=](|v|).
+    1. If |number| is **NaN**,
+        1. Let |n| be an implementation-defined integer such that [=canon=]32 โ‰ค |n| < 2[=signif=](32).
+        1. Let |f32| be [=nan=](n).
+    1. Otherwise,
+        1. Let |f32| be |number| rounded to the nearest representable value using IEEE 754-2008 round to nearest, ties to even mode. [[IEEE-754]]
     1. Return [=f32.const=] |f32|.
 1. If |type| is [=f64=],
-    1. Let |f64| be [=?=] [=ToNumber=](|v|).
+    1. Let |number| be [=?=] [=ToNumber=](|v|).
+    1. If |number| is **NaN**,
+        1. Let |n| be an implementation-defined integer such that [=canon=]64 โ‰ค |n| < 2[=signif=](64).
+        1. Let |f64| be [=nan=](n).
+    1. Otherwise,
+        1. Let |f64| be |number|.
     1. Return [=f64.const=] |f64|.
 1. If |type| is [=funcref=],
     1. If |v| is null,

From 51ff50a1f4f580e8d3bc185fd83479fdbb62ca7a Mon Sep 17 00:00:00 2001
From: Ms2ger 
Date: Fri, 17 Feb 2023 12:26:24 +0100
Subject: [PATCH 024/132] [web-api] Correct MIME type check. (#1537)

Fixes #1138.
---
 document/web-api/index.bs | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/document/web-api/index.bs b/document/web-api/index.bs
index 1e74e094..64c8ecf3 100644
--- a/document/web-api/index.bs
+++ b/document/web-api/index.bs
@@ -69,6 +69,7 @@ url:https://fetch.spec.whatwg.org/#concept-body-consume-body;text:consume body;t
 
 
 
@@ -111,8 +112,10 @@ Note: This algorithm accepts a {{Response}} object, or a
     1. Let |returnValue| be [=a new promise=]
     1. [=Upon fulfillment=] of |source| with value |unwrappedSource|:
         1. Let |response| be |unwrappedSource|'s [=Response/response=].
-        1. Let |mimeType| be the result of [=extracting a MIME type=] from |response|'s [=response/header list=].
-        1. If |mimeType| is not `` `application/wasm` ``, reject |returnValue| with a {{TypeError}} and abort these substeps.
+        1. Let |mimeType| be the result of [=header list/getting=] `` `Content-Type` `` from |response|'s [=response/header list=].
+        1. If |mimeType| is null, reject |returnValue| with a {{TypeError}} and abort these substeps.
+        1. Remove all [=HTTP tab or space byte=] from the start and end of |mimeType|.
+        1. If |mimeType| is not a [=byte-case-insensitive=] match for `` `application/wasm` ``, reject |returnValue| with a {{TypeError}} and abort these substeps.
 
             Note: extra parameters are not allowed, including the empty `` `application/wasm;` ``.
 

From a34d5f9bd39b0c1e089365e4c9cee647a06e7993 Mon Sep 17 00:00:00 2001
From: Heejin Ahn 
Date: Fri, 17 Feb 2023 11:02:04 -0800
Subject: [PATCH 025/132] [js-api] Add basic.tentative.any.js from wpt (#255)

This adds
https://github.com/web-platform-tests/wpt/blob/master/wasm/jsapi/exception/basic.tentative.any.js,
which was somehow added only wpt repo, to this repo as well.
---
 test/js-api/exception/basic.tentative.any.js | 121 +++++++++++++++++++
 1 file changed, 121 insertions(+)
 create mode 100644 test/js-api/exception/basic.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 00000000..acf644f9
--- /dev/null
+++ b/test/js-api/exception/basic.tentative.any.js
@@ -0,0 +1,121 @@
+// META: global=window,worker,jsshell
+// 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 kWasmAnyRef = 0x6f;
+  const kSig_v_r = makeSig([kWasmAnyRef], []);
+  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, kWasmAnyFunc,
+      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, kWasmStmt,
+        kExprCallFunction, fnIndex,
+      kExprCatch, tagIndex,
+        kExprReturn,
+      kExprEnd,
+      kExprRefNull, kWasmAnyRef,
+    ])
+    .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, kWasmStmt,
+        kExprCallFunction, fnIndex,
+      kExprCatchAll,
+        kExprRethrow, 0x00,
+      kExprEnd,
+      kExprRefNull, kWasmAnyRef,
+    ])
+    .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");

From a2f24ee9cd681ba71861b451a271d55243aef2ce Mon Sep 17 00:00:00 2001
From: Ms2ger 
Date: Fri, 17 Feb 2023 10:31:56 +0100
Subject: [PATCH 026/132] [js-api] Add missing EnforceRange to getArg argument.

All other 'unsigned long' arguments in the JS API have EnforceRange extended attributes. I assume this one was missed accidentally.
---
 document/js-api/index.bs                      | 2 +-
 test/js-api/exception/getArg.tentative.any.js | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/document/js-api/index.bs b/document/js-api/index.bs
index 3da64d69..5878b556 100644
--- a/document/js-api/index.bs
+++ b/document/js-api/index.bs
@@ -1270,7 +1270,7 @@ dictionary ExceptionOptions {
 [LegacyNamespace=WebAssembly, Exposed=(Window,Worker,Worklet)]
 interface Exception {
   constructor(Tag exceptionTag, sequence<any> payload, optional ExceptionOptions options = {});
-  any getArg(Tag exceptionTag, unsigned long index);
+  any getArg(Tag exceptionTag, [EnforceRange] unsigned long index);
   boolean is(Tag exceptionTag);
   readonly attribute (DOMString or undefined) stack;
 };
diff --git a/test/js-api/exception/getArg.tentative.any.js b/test/js-api/exception/getArg.tentative.any.js
index f0a568a8..4b72c61f 100644
--- a/test/js-api/exception/getArg.tentative.any.js
+++ b/test/js-api/exception/getArg.tentative.any.js
@@ -43,7 +43,7 @@ test(() => {
   const tag = new WebAssembly.Tag({ parameters: [] });
   const exn = new WebAssembly.Exception(tag, []);
   for (const value of outOfRangeValues) {
-    assert_throws_js(RangeError, () => exn.getArg(tag, value));
+    assert_throws_js(TypeError, () => exn.getArg(tag, value));
   }
 }, "Getting out-of-range argument");
 

From e8a83b22635281a62731df2dcd0488445f71744f Mon Sep 17 00:00:00 2001
From: Heejin Ahn 
Date: Tue, 21 Feb 2023 02:53:49 -0800
Subject: [PATCH 027/132] [ci] Pin nodejs version to avoid fetching failures
 (#1603)

The issues appears to be related to https://github.com/actions/runner-images/issues/7002.

Co-authored-by: Ms2ger 
---
 .github/workflows/main.yml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 0ff1bd5f..b64d31bb 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -64,6 +64,9 @@ jobs:
       - uses: actions/checkout@v2
         with:
           submodules: "recursive"
+      - uses: actions/setup-node@v3
+        with:
+          node-version: 16
       - run: pip install bikeshed && bikeshed update
       - run: pip install six
       - run: sudo apt-get update -y && sudo apt-get install -y latexmk texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended

From 3545ad06f20d7cd4068aeb470f5c8050b5a44e09 Mon Sep 17 00:00:00 2001
From: Tom Stuart 
Date: Tue, 21 Feb 2023 11:03:02 +0000
Subject: [PATCH 028/132] [spec] Add missing value to table.grow reduction rule
 (#1607)

---
 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 bf5acdfe..8bc05499 100644
--- a/document/core/exec/instructions.rst
+++ b/document/core/exec/instructions.rst
@@ -1312,7 +1312,7 @@ Table Instructions
      \end{array}
    \\[1ex]
    \begin{array}{lcl@{\qquad}l}
-   S; F; (\I32.\CONST~n)~(\TABLEGROW~x) &\stepto& S; F; (\I32.\CONST~\signed_{32}^{-1}(-1))
+   S; F; \val~(\I32.\CONST~n)~(\TABLEGROW~x) &\stepto& S; F; (\I32.\CONST~\signed_{32}^{-1}(-1))
    \end{array}
    \end{array}
 

From 585bfa7e08ca1ef2556781707f0668731a0ab63d Mon Sep 17 00:00:00 2001
From: Andreas Rossberg 
Date: Tue, 21 Feb 2023 12:28:29 +0100
Subject: [PATCH 029/132] [test] Move SIMD linking test to simd dir (#1610)

---
 test/core/linking.wast           | 14 --------------
 test/core/simd/simd_linking.wast | 12 ++++++++++++
 2 files changed, 12 insertions(+), 14 deletions(-)
 create mode 100644 test/core/simd/simd_linking.wast

diff --git a/test/core/linking.wast b/test/core/linking.wast
index 578a8c18..994e0f49 100644
--- a/test/core/linking.wast
+++ b/test/core/linking.wast
@@ -129,20 +129,6 @@
 )
 
 
-(module
-  (global (export "g-v128") v128 (v128.const i64x2 0 0))
-  (global (export "mg-v128") (mut v128) (v128.const i64x2 0 0))
-)
-(register "Mv128")
-
-(module
-  ;; TODO: Reactivate once the fix for https://bugs.chromium.org/p/v8/issues/detail?id=13732
-  ;; has made it to the downstream node.js that we use on CI.
-  ;; (import "Mv128" "g-v128" (global v128))
-  (import "Mv128" "mg-v128" (global (mut v128)))
-)
-
-
 ;; Tables
 
 (module $Mt
diff --git a/test/core/simd/simd_linking.wast b/test/core/simd/simd_linking.wast
new file mode 100644
index 00000000..1a1d1635
--- /dev/null
+++ b/test/core/simd/simd_linking.wast
@@ -0,0 +1,12 @@
+(module
+  (global (export "g-v128") v128 (v128.const i64x2 0 0))
+  (global (export "mg-v128") (mut v128) (v128.const i64x2 0 0))
+)
+(register "Mv128")
+
+(module
+  ;; TODO: Reactivate once the fix for https://bugs.chromium.org/p/v8/issues/detail?id=13732
+  ;; has made it to the downstream node.js that we use on CI.
+  ;; (import "Mv128" "g-v128" (global v128))
+  (import "Mv128" "mg-v128" (global (mut v128)))
+)

From f9a726780deb99b3c87cb2f0bad56b90580c60fb Mon Sep 17 00:00:00 2001
From: Daniel Ehrenberg 
Date: Mon, 18 Mar 2019 10:46:12 +0100
Subject: [PATCH 030/132] Editorial: Clarify the name of the instantiate
 algorithm.

---
 document/js-api/index.bs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/document/js-api/index.bs b/document/js-api/index.bs
index 961918ea..df23c7a7 100644
--- a/document/js-api/index.bs
+++ b/document/js-api/index.bs
@@ -485,7 +485,7 @@ The verification of WebAssembly type requirements is deferred to the
 
 
 
- To instantiate a WebAssembly module from a {{Module}} |moduleObject| and imports |importObject|, perform the following steps: + To synchronously instantiate a WebAssembly module from a {{Module}} |moduleObject| and imports |importObject|, perform the following steps: 1. Let |module| be |moduleObject|.\[[Module]]. 1. [=Read the imports=] of |module| with imports |importObject|, and let |imports| be the result. 1. [=Instantiate the core of a WebAssembly module=] |module| with |imports|, and let |instance| be the result. @@ -499,7 +499,7 @@ The verification of WebAssembly type requirements is deferred to the 1. Let |promise| be [=a new promise=]. 1. [=Upon fulfillment=] of |promiseOfModule| with value |module|: - 1. [=instantiate a WebAssembly module|Instantiate the WebAssembly module=] |module| importing |importObject|, and let |instance| be the result. If this throws an exception, catch it, [=reject=] |promise| with the exception, and abort these substeps. + 1. [=synchronously instantiate a WebAssembly module|Synchronously instantiate the WebAssembly module=] |module| importing |importObject|, and let |instance| be the result. If this throws an exception, catch it, [=reject=] |promise| with the exception, and abort these substeps. 1. Let |result| be the {{WebAssemblyInstantiatedSource}} value ยซ[ "{{WebAssemblyInstantiatedSource/module}}" โ†’ |module|, "{{WebAssemblyInstantiatedSource/instance}}" โ†’ |instance| ]ยป. 1. [=Resolve=] |promise| with |result|. 1. [=Upon rejection=] of |promiseOfModule| with reason |reason|: From a114f7a06bb0e867f1a66570dedcf2ebebe95f3c Mon Sep 17 00:00:00 2001 From: Daniel Ehrenberg Date: Mon, 18 Mar 2019 10:51:53 +0100 Subject: [PATCH 031/132] Add notes to discourage using synchronous APIs. --- document/js-api/index.bs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/document/js-api/index.bs b/document/js-api/index.bs index df23c7a7..19600b85 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -604,6 +604,8 @@ interface Module { 1. If |module| is [=error=], throw a {{CompileError}} exception. 1. Set **this**.\[[Module]] to |module|. 1. Set **this**.\[[Bytes]] to |stableBytes|. + +Note: Some implementations enforce a size limitation on |bytes|. Use of this API is discouraged, in favor of asynchronous APIs.

Instances

@@ -622,6 +624,8 @@ interface Instance { 1. [=Read the imports=] of |module| with imports |importObject|, and let |imports| be the result. 1. [=Instantiate the core of a WebAssembly module=] |module| with |imports|, and let |instance| be the result. 1. [=initialize an instance object|Initialize=] **this** from |module| and |instance|. + +Note: The use of this synchronous API is discouraged, as some implementations sometimes do long-running compilation work when instantiating.
From 25b3df3e21324465fefd9aed2cf3901cfd76a7c1 Mon Sep 17 00:00:00 2001 From: Daniel Ehrenberg Date: Mon, 18 Mar 2019 10:52:13 +0100 Subject: [PATCH 032/132] [jsapi] Normative: Always queue a task during asynchronous instantiation JSC will have to do asynchronous compilation work during some instantiations. To be consistent, this PR always queues a task to complete instantiation, except through the synchronous Instance(module) API, to ensure consistency across platforms. This patch also cleans up the specification in various surrounding ways: - Include notes about APIs whose use is discouraged/may be limited Closes #741 See also https://github.com/webpack/webpack/issues/6433 --- document/js-api/index.bs | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/document/js-api/index.bs b/document/js-api/index.bs index 19600b85..19faf7ed 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -474,13 +474,15 @@ The verification of WebAssembly type requirements is deferred to the 1. Let |module| be |moduleObject|.\[[Module]]. 1. [=Read the imports=] of |module| with imports |importObject|, and let |imports| be the result. If this operation throws an exception, catch it, [=reject=] |promise| with the exception, and return |promise|. - 1. [=Queue a task=] to perform the following steps: - 1. [=Instantiate the core of a WebAssembly module=] |module| with |imports|, and let |instance| be the result. - If this throws an exception, catch it, [=reject=] |promise| with the exception, and terminate these substeps. - 1. Let |instanceObject| be a [=/new=] {{Instance}}. - 1. [=initialize an instance object|Initialize=] |instanceObject| from |module| and |instance|. - If this throws an exception, catch it, [=reject=] |promise| with the exception, and terminate these substeps. - 1. [=Resolve=] |promise| with |instanceObject|. + 1. Run the following steps [=in parallel=]: + 1. [=Queue a task=] to perform the following steps: + Note: Implementation-specific work may be performed here. + 1. [=Instantiate the core of a WebAssembly module=] |module| with |imports|, and let |instance| be the result. + If this throws an exception, catch it, [=reject=] |promise| with the exception, and terminate these substeps. + 1. Let |instanceObject| be a [=/new=] {{Instance}}. + 1. [=initialize an instance object|Initialize=] |instanceObject| from |module| and |instance|. + If this throws an exception, catch it, [=reject=] |promise| with the exception, and terminate these substeps. + 1. [=Resolve=] |promise| with |instanceObject|. 1. Return |promise|.
@@ -499,14 +501,15 @@ The verification of WebAssembly type requirements is deferred to the 1. Let |promise| be [=a new promise=]. 1. [=Upon fulfillment=] of |promiseOfModule| with value |module|: - 1. [=synchronously instantiate a WebAssembly module|Synchronously instantiate the WebAssembly module=] |module| importing |importObject|, and let |instance| be the result. If this throws an exception, catch it, [=reject=] |promise| with the exception, and abort these substeps. - 1. Let |result| be the {{WebAssemblyInstantiatedSource}} value ยซ[ "{{WebAssemblyInstantiatedSource/module}}" โ†’ |module|, "{{WebAssemblyInstantiatedSource/instance}}" โ†’ |instance| ]ยป. - 1. [=Resolve=] |promise| with |result|. + 1. [=asynchronously instantiate a WebAssembly module|Instantiate the WebAssembly module=] |module| importing |importObject|, and let |innerPromise| be the result. + 1. [=Upon fulfillment=] of |innerPromise| with value |instance|. + 1. Let |result| be the {{WebAssemblyInstantiatedSource}} value ยซ[ "{{WebAssemblyInstantiatedSource/module}}" โ†’ |module|, "{{WebAssemblyInstantiatedSource/instance}}" โ†’ |instance| ]ยป. + 1. [=Resolve=] |promise| with |result|. + 1. [=Upon rejection=] of |innerPromise| with reason |reason|: + 1. [=Reject=] |promise| with |reason|. 1. [=Upon rejection=] of |promiseOfModule| with reason |reason|: 1. [=Reject=] |promise| with |reason|. 1. Return |promise|. - - Note: It would be valid to perform certain parts of the instantiation [=in parallel=], but several parts need to happen in the event loop, including JavaScript operations to access the |importObject| and execution of the start function.
From 036365a10e47ac1bec0151c148d0b334b3b2ef2b Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Fri, 17 Feb 2023 17:12:31 -0800 Subject: [PATCH 033/132] [test] Exception -> Tag in wasm-module-builder.js The section name has changed to the tag section a few years ago. This adds the corresponding changes added in WebAssembly/exception-handling#252 and WebAssembly/exception-handling#256. --- test/js-api/wasm-module-builder.js | 46 +++++++++++++++--------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/test/js-api/wasm-module-builder.js b/test/js-api/wasm-module-builder.js index 7be72f86..d0f9e78b 100644 --- a/test/js-api/wasm-module-builder.js +++ b/test/js-api/wasm-module-builder.js @@ -65,7 +65,7 @@ let kElementSectionCode = 9; // Elements section let kCodeSectionCode = 10; // Function code let kDataSectionCode = 11; // Data segments let kDataCountSectionCode = 12; // Data segment count (between Element & Code) -let kExceptionSectionCode = 13; // Exception section (between Global & Export) +let kTagSectionCode = 13; // Tag section (between Memory & Global) // Name section types let kModuleNameCode = 0; @@ -104,13 +104,13 @@ let kExternalFunction = 0; let kExternalTable = 1; let kExternalMemory = 2; let kExternalGlobal = 3; -let kExternalException = 4; +let kExternalTag = 4; let kTableZero = 0; let kMemoryZero = 0; let kSegmentZero = 0; -let kExceptionAttribute = 0; +let kTagAttribute = 0; // Useful signatures let kSig_i_i = makeSig([kWasmI32], [kWasmI32]); @@ -681,7 +681,7 @@ class WasmModuleBuilder { this.exports = []; this.globals = []; this.tables = []; - this.exceptions = []; + this.tags = []; this.functions = []; this.element_segments = []; this.data_segments = []; @@ -689,7 +689,7 @@ class WasmModuleBuilder { this.num_imported_funcs = 0; this.num_imported_globals = 0; this.num_imported_tables = 0; - this.num_imported_exceptions = 0; + this.num_imported_tags = 0; return this; } @@ -752,11 +752,11 @@ class WasmModuleBuilder { return table; } - addException(type) { + addTag(type) { let type_index = (typeof type) == "number" ? type : this.addType(type); - let except_index = this.exceptions.length + this.num_imported_exceptions; - this.exceptions.push(type_index); - return except_index; + let tag_index = this.tags.length + this.num_imported_tags; + this.tags.push(type_index); + return tag_index; } addFunction(name, type) { @@ -804,14 +804,14 @@ class WasmModuleBuilder { return this.num_imported_tables++; } - addImportedException(module, name, type) { - if (this.exceptions.length != 0) { - throw new Error('Imported exceptions must be declared before local ones'); + addImportedTag(module, name, type) { + if (this.tags.length != 0) { + throw new Error('Imported tags must be declared before local ones'); } let type_index = (typeof type) == "number" ? type : this.addType(type); - let o = {module: module, name: name, kind: kExternalException, type: type_index}; + let o = {module: module, name: name, kind: kExternalTag, type: type_index}; this.imports.push(o); - return this.num_imported_exceptions++; + return this.num_imported_tags++; } addExport(name, index) { @@ -938,8 +938,8 @@ class WasmModuleBuilder { section.emit_u8(has_max ? 1 : 0); // flags section.emit_u32v(imp.initial); // initial if (has_max) section.emit_u32v(imp.maximum); // maximum - } else if (imp.kind == kExternalException) { - section.emit_u32v(kExceptionAttribute); + } else if (imp.kind == kExternalTag) { + section.emit_u32v(kTagAttribute); section.emit_u32v(imp.type); } else { throw new Error("unknown/unsupported import kind " + imp.kind); @@ -1036,13 +1036,13 @@ class WasmModuleBuilder { }); } - // Add exceptions. - if (wasm.exceptions.length > 0) { - if (debug) print("emitting exceptions @ " + binary.length); - binary.emit_section(kExceptionSectionCode, section => { - section.emit_u32v(wasm.exceptions.length); - for (let type of wasm.exceptions) { - section.emit_u32v(kExceptionAttribute); + // Add tags. + if (wasm.tags.length > 0) { + if (debug) print("emitting tags @ " + binary.length); + binary.emit_section(kTagSectionCode, section => { + section.emit_u32v(wasm.tags.length); + for (let type of wasm.tags) { + section.emit_u32v(kTagAttribute); section.emit_u32v(type); } }); From 8f5c48955b688965c18948c2866d84913347bad4 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Wed, 22 Feb 2023 12:43:02 +0100 Subject: [PATCH 034/132] [spec] Fix reduction rule for label (#1612) Fix #1605. --- document/core/exec/instructions.rst | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index 8bc05499..3f82dce3 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -2860,22 +2860,20 @@ Exiting :math:`\instr^\ast` with label :math:`L` When the end of a block is reached without a jump or trap aborting it, then the following steps are performed. -1. Let :math:`n` be the number of values on the top of the stack. +1. Pop all values :math:`\val^\ast` from the top of the stack. -2. Pop the values :math:`\val^n` from the stack. +2. Assert: due to :ref:`validation `, the label :math:`L` is now on the top of the stack. -3. Assert: due to :ref:`validation `, the label :math:`L` is now on the top of the stack and has arity :math:`n`. +3. Pop the label from the stack. -4. Pop the label from the stack. +4. Push :math:`\val^\ast` back to the stack. -5. Push :math:`\val^n` back to the stack. - -6. Jump to the position after the |END| of the :ref:`structured control instruction ` associated with the label :math:`L`. +5. Jump to the position after the |END| of the :ref:`structured control instruction ` associated with the label :math:`L`. .. math:: ~\\[-1ex] \begin{array}{lcl@{\qquad}l} - \LABEL_n\{\instr^\ast\}~\val^n~\END &\stepto& \val^n + \LABEL_n\{\instr^\ast\}~\val^\ast~\END &\stepto& \val^\ast \end{array} .. note:: From 6db9011875a0cbcac53ec67ce81e240088e021a3 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Wed, 22 Feb 2023 18:20:55 +0100 Subject: [PATCH 035/132] [spec] Clarifying note about canonical NaNs (#1614) --- document/core/syntax/values.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/document/core/syntax/values.rst b/document/core/syntax/values.rst index 564ddc2d..1b155df4 100644 --- a/document/core/syntax/values.rst +++ b/document/core/syntax/values.rst @@ -140,6 +140,8 @@ An *arithmetic NaN* is a floating-point value :math:`\pm\NAN(n)` with :math:`n .. note:: In the abstract syntax, subnormals are distinguished by the leading 0 of the significand. The exponent of subnormals has the same value as the smallest possible exponent of a normal number. Only in the :ref:`binary representation ` the exponent of a subnormal is encoded differently than the exponent of any normal number. + The notion of canonical NaN defined here is unrelated to the notion of canonical NaN that the |IEEE754|_ standard (Section 3.5.2) defines for decimal interchange formats. + Conventions ........... From 721dd6ce2cf53028133bd2ceeea9b0655570c641 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Wed, 22 Feb 2023 21:14:40 +0100 Subject: [PATCH 036/132] [spec] Tweak crossref --- document/core/util/macros.def | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/document/core/util/macros.def b/document/core/util/macros.def index aaefc406..3ab6d548 100644 --- a/document/core/util/macros.def +++ b/document/core/util/macros.def @@ -9,7 +9,7 @@ .. |WasmIssues| replace:: |issuelink| .. _WasmIssues: |issuelink| -.. |IEEE754| replace:: IEEE 754-2019 +.. |IEEE754| replace:: IEEE 754 .. _IEEE754: https://ieeexplore.ieee.org/document/8766229 .. |Unicode| replace:: Unicode From 2558d66b716b8b85e028a595a2a51a3a9063c0f7 Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Thu, 23 Feb 2023 00:00:44 -0800 Subject: [PATCH 037/132] [test] Fix invalid section ID tests (#1615) --- .github/workflows/main.yml | 2 +- test/core/binary.wast | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b64d31bb..a158de1e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -22,7 +22,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v1 with: - node-version: 18.x + node-version: 19.x - run: cd interpreter && opam exec make JS=node all ref-interpreter-js-library: diff --git a/test/core/binary.wast b/test/core/binary.wast index 1b6b4712..526e0a20 100644 --- a/test/core/binary.wast +++ b/test/core/binary.wast @@ -45,11 +45,11 @@ (assert_malformed (module binary "\00asm\00\00\00\01") "unknown binary version") ;; Invalid section id. -(assert_malformed (module binary "\00asm" "\01\00\00\00" "\0d\00") "malformed section id") -(assert_malformed (module binary "\00asm" "\01\00\00\00" "\7f\00") "malformed section id") -(assert_malformed (module binary "\00asm" "\01\00\00\00" "\80\00\01\00") "malformed section id") -(assert_malformed (module binary "\00asm" "\01\00\00\00" "\81\00\01\00") "malformed section id") -(assert_malformed (module binary "\00asm" "\01\00\00\00" "\ff\00\01\00") "malformed section id") +(assert_malformed (module binary "\00asm" "\01\00\00\00" "\0e\01\00") "malformed section id") +(assert_malformed (module binary "\00asm" "\01\00\00\00" "\7f\01\00") "malformed section id") +(assert_malformed (module binary "\00asm" "\01\00\00\00" "\80\01\00\01\01\00") "malformed section id") +(assert_malformed (module binary "\00asm" "\01\00\00\00" "\81\01\00\01\01\00") "malformed section id") +(assert_malformed (module binary "\00asm" "\01\00\00\00" "\ff\01\00\01\01\00") "malformed section id") ;; Unsigned LEB128 can have non-minimal length (module binary From 0eb87db0ed37b1cc3c26a66cf094cc8f22a09a99 Mon Sep 17 00:00:00 2001 From: Ioanna M Dimitriou H <9728696+ioannad@users.noreply.github.com> Date: Thu, 23 Feb 2023 09:45:27 +0100 Subject: [PATCH 038/132] Adds explanatory prose related to `delegate`. (#246) This resolves the last three so far unaddressed `todo::` sections: - Add prose explaining try-delegate's jump. - Adds prose and intuition for delegating exception handlers. + Also a minor modification to the prose of catching exception handlers, that somewhat reduces calling the administrative instruction by its identifier (CAUGHTadm) in the prose. Co-authored-by: Andreas Rossberg --- document/core/syntax/instructions.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/document/core/syntax/instructions.rst b/document/core/syntax/instructions.rst index de01fdf5..e78dd998 100644 --- a/document/core/syntax/instructions.rst +++ b/document/core/syntax/instructions.rst @@ -694,8 +694,8 @@ In case of |BLOCK| or |IF| it is a *forward jump*, resuming execution after the matching |END|. In case of |LOOP| it is a *backward jump* to the beginning of the loop. -.. todo:: - Add prose for try-delegate's jump. +When |TRY|--|DELEGATE| handles an exception, it also behaves similar to a forward jump, +effectively rethrowing the caught exception right before the matching |END|. .. note:: This enforces *structured control flow*. From da3476dad8c25dd67247d8f9416a5fad6c24df14 Mon Sep 17 00:00:00 2001 From: Ioanna M Dimitriou H <9728696+ioannad@users.noreply.github.com> Date: Thu, 23 Feb 2023 18:04:22 +0100 Subject: [PATCH 039/132] Adds validation algorithm case for `throw x`, adds missing x to 'catch' (#260) * Adds validation algorithm case for `throw x`, adds missing x to 'catch' * Apply suggestions from code review Co-authored-by: Andreas Rossberg --- document/core/appendix/algorithm.rst | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/document/core/appendix/algorithm.rst b/document/core/appendix/algorithm.rst index 941653f7..4aa26672 100644 --- a/document/core/appendix/algorithm.rst +++ b/document/core/appendix/algorithm.rst @@ -216,17 +216,20 @@ Other instructions are checked in a similar manner. pop_vals([t1*]) push_ctrl(try, [t1*], [t2*]) - case (catch) + case (catch x) let frame = pop_ctrl() error_if(frame.opcode =/= try || frame.opcode =/= catch) - let params = tags[x].type.params - push_ctrl(catch, params , frame.end_types) + push_ctrl(catch, tags[x].type.params, frame.end_types) case (catch_all) let frame = pop_ctrl() error_if(frame.opcode =/= try || frame.opcode =/= catch) push_ctrl(catch_all, [], frame.end_types) + case (throw x) + pop.vals(tags[x].type.params) + unreachable() + case (br n) error_if(ctrls.size() < n) pop_vals(label_types(ctrls[n])) @@ -249,8 +252,6 @@ Other instructions are checked in a similar manner. pop_vals(label_types(ctrls[m])) unreachable() -.. todo:: - Add a case for :code:`throw`. .. note:: It is an invariant under the current WebAssembly instruction set that an operand of :code:`Unknown` type is never duplicated on the stack. From e987be4b94a94b2ec520be061a7944058bab303d Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Thu, 23 Feb 2023 11:57:53 -0800 Subject: [PATCH 040/132] [js-api] Tidy up rethrow identity test (#256) This makes some cosmetic changes to the identity-preserving `rethrow` test added in #253. This is to prepare for adding the same set of tests for a Wasm-defined-and-exported tag, as requrested in https://github.com/WebAssembly/exception-handling/pull/253#issuecomment-1433703216. --- .../exception/identity.tentative.any.js | 55 +++++++++++-------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/test/js-api/exception/identity.tentative.any.js b/test/js-api/exception/identity.tentative.any.js index 65787c10..3854b014 100644 --- a/test/js-api/exception/identity.tentative.any.js +++ b/test/js-api/exception/identity.tentative.any.js @@ -3,38 +3,44 @@ // META: script=/wasm/jsapi/wasm-module-builder.js test(() => { - const tag = new WebAssembly.Tag({ parameters: ["i32"] }); - const exn = new WebAssembly.Exception(tag, [42]); - const exn_same_payload = new WebAssembly.Exception(tag, [42]); - const exn_diff_payload = new WebAssembly.Exception(tag, [53]); - const builder = new WasmModuleBuilder(); - const jsfuncIndex = builder.addImport("module", "jsfunc", kSig_v_v); - const tagIndex = builder.addImportedTag("module", "tag", kSig_v_i); + + // Tag defined in JavaScript and imported into Wasm + const jsTag = new WebAssembly.Tag({ parameters: ["i32"] }); + const jsTagIndex = builder.addImportedTag("module", "jsTag", kSig_v_i) + const jsTagExn = new WebAssembly.Exception(jsTag, [42]); + const jsTagExnSamePayload = new WebAssembly.Exception(jsTag, [42]); + const jsTagExnDiffPayload = new WebAssembly.Exception(jsTag, [53]); + const throwJSTagExnIndex = builder.addImport("module", "throwJSTagExn", kSig_v_v); + const imports = { module: { - jsfunc: function() { throw exn; }, - tag: tag + throwJSTagExn: function() { throw jsTagExn; }, + 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_rethrow", kSig_v_v) + .addFunction("catch_js_tag_rethrow", kSig_v_v) .addBody([ kExprTry, kWasmStmt, - kExprCallFunction, jsfuncIndex, - kExprCatch, tagIndex, + kExprCallFunction, throwJSTagExnIndex, + kExprCatch, jsTagIndex, 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_rethrow", kSig_v_v) + .addFunction("catch_all_js_tag_rethrow", kSig_v_v) .addBody([ kExprTry, kWasmStmt, - kExprCallFunction, jsfuncIndex, + kExprCallFunction, throwJSTagExnIndex, kExprCatchAll, kExprRethrow, 0x00, kExprEnd @@ -42,20 +48,25 @@ test(() => { .exportFunc(); const buffer = builder.toBuffer(); + + // The exception object's identity should be preserved across 'rethrow's in + // Wasm code. Do tests with a tag defined in JS. WebAssembly.instantiate(buffer, imports).then(result => { try { - result.instance.exports.catch_rethrow(); + result.instance.exports.catch_js_tag_rethrow(); } catch (e) { - assert_equals(e, exn); - assert_not_equals(e, exn_same_payload); - assert_not_equals(e, exn_diff_payload); + 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_rethrow(); + result.instance.exports.catch_all_js_tag_rethrow(); } catch (e) { - assert_equals(e, exn); - assert_not_equals(e, exn_same_payload); - assert_not_equals(e, exn_diff_payload); + assert_equals(e, jsTagExn); + assert_not_equals(e, jsTagExnSamePayload); + assert_not_equals(e, jsTagExnDiffPayload); } }); }, "Identity check"); From 0f577bde2019ea6474d245ff096488bf8fe9a835 Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Thu, 23 Feb 2023 12:18:16 -0800 Subject: [PATCH 041/132] Add detailed example for rethrow to explainer (#263) The current explainer has a detailed example on `delegate`, which was adapted from https://github.com/WebAssembly/exception-handling/issues/146#issue-794482909, but not the one for `rethrow` from the same issue (https://github.com/WebAssembly/exception-handling/issues/146#issuecomment-777714491). This adds the detailed `rethrow` example to the explainer, with the some cosmetic changes to the label names and comments. --- proposals/exception-handling/Exceptions.md | 35 ++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/proposals/exception-handling/Exceptions.md b/proposals/exception-handling/Exceptions.md index a8f2f11d..afaa78f3 100644 --- a/proposals/exception-handling/Exceptions.md +++ b/proposals/exception-handling/Exceptions.md @@ -257,6 +257,41 @@ 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 From 585c7da72e481a257ff7192679584bb812dc1555 Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Mon, 27 Feb 2023 17:17:42 -0800 Subject: [PATCH 042/132] [js-api] Test Wasm-defined tag in rethrow identity test (#265) This addresses https://github.com/WebAssembly/exception-handling/pull/253#issuecomment-1433703216 by adding a set of tests that use a Wasm-defined and exported tag. --- .../exception/identity.tentative.any.js | 61 ++++++++++++++++++- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/test/js-api/exception/identity.tentative.any.js b/test/js-api/exception/identity.tentative.any.js index 3854b014..23b35c5a 100644 --- a/test/js-api/exception/identity.tentative.any.js +++ b/test/js-api/exception/identity.tentative.any.js @@ -13,9 +13,19 @@ test(() => { 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 } }; @@ -34,6 +44,20 @@ test(() => { ]) .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, kWasmStmt, + 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 @@ -47,11 +71,24 @@ test(() => { ]) .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, kWasmStmt, + kExprCallFunction, throwWasmTagExnIndex, + kExprCatchAll, + kExprRethrow, 0x00, + kExprEnd + ]) + .exportFunc(); + const buffer = builder.toBuffer(); - // The exception object's identity should be preserved across 'rethrow's in - // Wasm code. Do tests with a tag defined in JS. 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) { @@ -68,5 +105,25 @@ test(() => { 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); + } }); }, "Identity check"); From 95d87ba16c72ac2cd92c829c4473a9e47c8e8a40 Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Tue, 28 Feb 2023 17:34:09 -0800 Subject: [PATCH 043/132] [js-api] Add more tests reusing payload (#266) As suggested in https://github.com/WebAssembly/exception-handling/pull/256#discussion_r1109501365, this adds two more tests: - JS throws an exception, Wasm catches it and returns the payload. - JS throws an exception, Wasm catches it and throws a new exception using that payload. --- .../exception/identity.tentative.any.js | 43 ++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/test/js-api/exception/identity.tentative.any.js b/test/js-api/exception/identity.tentative.any.js index 23b35c5a..e431197d 100644 --- a/test/js-api/exception/identity.tentative.any.js +++ b/test/js-api/exception/identity.tentative.any.js @@ -7,7 +7,7 @@ test(() => { // 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 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]); @@ -84,6 +84,33 @@ test(() => { ]) .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, kWasmStmt, + kExprCallFunction, throwJSTagExnIndex, + kExprCatch, jsTagIndex, + kExprThrow, jsTagIndex, + kExprEnd + ]) + .exportFunc(); + const buffer = builder.toBuffer(); WebAssembly.instantiate(buffer, imports).then(result => { @@ -125,5 +152,19 @@ test(() => { 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 87461da7a4500bd907b963956ad83ef2d75060af Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Wed, 1 Mar 2023 09:43:47 +0100 Subject: [PATCH 044/132] [spec] Don't check in generated index, to avoid spurious merge conflicts --- document/core/.gitignore | 1 + document/core/Makefile | 1 + document/core/appendix/index-instructions.rst | 523 ------------------ 3 files changed, 2 insertions(+), 523 deletions(-) delete mode 100644 document/core/appendix/index-instructions.rst diff --git a/document/core/.gitignore b/document/core/.gitignore index b932ec28..d21e55e3 100644 --- a/document/core/.gitignore +++ b/document/core/.gitignore @@ -1,3 +1,4 @@ _build _static document/*.pyc +appendix/index-instructions.rst diff --git a/document/core/Makefile b/document/core/Makefile index 3ff1a87c..bfbf70bf 100644 --- a/document/core/Makefile +++ b/document/core/Makefile @@ -103,6 +103,7 @@ pdf: index latexpdf clean: rm -rf $(BUILDDIR) rm -rf $(STATICDIR) + rm -f appendix/index-instructions.rst .PHONY: html html: index diff --git a/document/core/appendix/index-instructions.rst b/document/core/appendix/index-instructions.rst deleted file mode 100644 index 977c21fb..00000000 --- a/document/core/appendix/index-instructions.rst +++ /dev/null @@ -1,523 +0,0 @@ -.. DO NOT EDIT: This file is auto-generated by the gen-index-instructions.py script. - -.. index:: instruction -.. _index-instr: - -Index of Instructions ---------------------- - -================================================= ==================================== ============================================= ============================================= ================================================================== -Instruction Binary Opcode Type Validation Execution -================================================= ==================================== ============================================= ============================================= ================================================================== -:math:`\UNREACHABLE` :math:`\hex{00}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\NOP` :math:`\hex{01}` :math:`[] \to []` :ref:`validation ` :ref:`execution ` -:math:`\BLOCK~\X{bt}` :math:`\hex{02}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\LOOP~\X{bt}` :math:`\hex{03}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\IF~\X{bt}` :math:`\hex{04}` :math:`[t_1^\ast~\I32] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\ELSE` :math:`\hex{05}` -(reserved) :math:`\hex{06}` -(reserved) :math:`\hex{07}` -(reserved) :math:`\hex{08}` -(reserved) :math:`\hex{09}` -(reserved) :math:`\hex{0A}` -:math:`\END` :math:`\hex{0B}` -:math:`\BR~l` :math:`\hex{0C}` :math:`[t_1^\ast~t^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\BRIF~l` :math:`\hex{0D}` :math:`[t^\ast~\I32] \to [t^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\BRTABLE~l^\ast~l` :math:`\hex{0E}` :math:`[t_1^\ast~t^\ast~\I32] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\RETURN` :math:`\hex{0F}` :math:`[t_1^\ast~t^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\CALL~x` :math:`\hex{10}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\CALLINDIRECT~x~y` :math:`\hex{11}` :math:`[t_1^\ast~\I32] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -(reserved) :math:`\hex{12}` -(reserved) :math:`\hex{13}` -(reserved) :math:`\hex{14}` -(reserved) :math:`\hex{15}` -(reserved) :math:`\hex{16}` -(reserved) :math:`\hex{17}` -(reserved) :math:`\hex{18}` -(reserved) :math:`\hex{19}` -:math:`\DROP` :math:`\hex{1A}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` -:math:`\SELECT` :math:`\hex{1B}` :math:`[t~t~\I32] \to [t]` :ref:`validation ` :ref:`execution ` -:math:`\SELECT~t` :math:`\hex{1C}` :math:`[t~t~\I32] \to [t]` :ref:`validation ` :ref:`execution ` -(reserved) :math:`\hex{1D}` -(reserved) :math:`\hex{1E}` -(reserved) :math:`\hex{1F}` -:math:`\LOCALGET~x` :math:`\hex{20}` :math:`[] \to [t]` :ref:`validation ` :ref:`execution ` -:math:`\LOCALSET~x` :math:`\hex{21}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` -:math:`\LOCALTEE~x` :math:`\hex{22}` :math:`[t] \to [t]` :ref:`validation ` :ref:`execution ` -:math:`\GLOBALGET~x` :math:`\hex{23}` :math:`[] \to [t]` :ref:`validation ` :ref:`execution ` -:math:`\GLOBALSET~x` :math:`\hex{24}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` -:math:`\TABLEGET~x` :math:`\hex{25}` :math:`[\I32] \to [t]` :ref:`validation ` :ref:`execution ` -:math:`\TABLESET~x` :math:`\hex{26}` :math:`[\I32~t] \to []` :ref:`validation ` :ref:`execution ` -(reserved) :math:`\hex{27}` -:math:`\I32.\LOAD~\memarg` :math:`\hex{28}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD~\memarg` :math:`\hex{29}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\F32.\LOAD~\memarg` :math:`\hex{2A}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution ` -:math:`\F64.\LOAD~\memarg` :math:`\hex{2B}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\LOAD\K{8\_s}~\memarg` :math:`\hex{2C}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\LOAD\K{8\_u}~\memarg` :math:`\hex{2D}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\LOAD\K{16\_s}~\memarg` :math:`\hex{2E}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\LOAD\K{16\_u}~\memarg` :math:`\hex{2F}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{8\_s}~\memarg` :math:`\hex{30}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{8\_u}~\memarg` :math:`\hex{31}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{16\_s}~\memarg` :math:`\hex{32}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{16\_u}~\memarg` :math:`\hex{33}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{32\_s}~\memarg` :math:`\hex{34}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{32\_u}~\memarg` :math:`\hex{35}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\STORE~\memarg` :math:`\hex{36}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I64.\STORE~\memarg` :math:`\hex{37}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` -:math:`\F32.\STORE~\memarg` :math:`\hex{38}` :math:`[\I32~\F32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\F64.\STORE~\memarg` :math:`\hex{39}` :math:`[\I32~\F64] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I32.\STORE\K{8}~\memarg` :math:`\hex{3A}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I32.\STORE\K{16}~\memarg` :math:`\hex{3B}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I64.\STORE\K{8}~\memarg` :math:`\hex{3C}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I64.\STORE\K{16}~\memarg` :math:`\hex{3D}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I64.\STORE\K{32}~\memarg` :math:`\hex{3E}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` -:math:`\MEMORYSIZE` :math:`\hex{3F}` :math:`[] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\MEMORYGROW` :math:`\hex{40}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\CONST~\i32` :math:`\hex{41}` :math:`[] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\CONST~\i64` :math:`\hex{42}` :math:`[] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\F32.\CONST~\f32` :math:`\hex{43}` :math:`[] \to [\F32]` :ref:`validation ` :ref:`execution ` -:math:`\F64.\CONST~\f64` :math:`\hex{44}` :math:`[] \to [\F64]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\EQZ` :math:`\hex{45}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\EQ` :math:`\hex{46}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\NE` :math:`\hex{47}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\LT\K{\_s}` :math:`\hex{48}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\LT\K{\_u}` :math:`\hex{49}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\GT\K{\_s}` :math:`\hex{4A}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\GT\K{\_u}` :math:`\hex{4B}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\LE\K{\_s}` :math:`\hex{4C}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\LE\K{\_u}` :math:`\hex{4D}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\GE\K{\_s}` :math:`\hex{4E}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\GE\K{\_u}` :math:`\hex{4F}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EQZ` :math:`\hex{50}` :math:`[\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EQ` :math:`\hex{51}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\NE` :math:`\hex{52}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\LT\K{\_s}` :math:`\hex{53}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\LT\K{\_u}` :math:`\hex{54}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\GT\K{\_s}` :math:`\hex{55}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\GT\K{\_u}` :math:`\hex{56}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\LE\K{\_s}` :math:`\hex{57}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\LE\K{\_u}` :math:`\hex{58}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\GE\K{\_s}` :math:`\hex{59}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\GE\K{\_u}` :math:`\hex{5A}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\EQ` :math:`\hex{5B}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\NE` :math:`\hex{5C}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\LT` :math:`\hex{5D}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\GT` :math:`\hex{5E}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\LE` :math:`\hex{5F}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\GE` :math:`\hex{60}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\EQ` :math:`\hex{61}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\NE` :math:`\hex{62}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\LT` :math:`\hex{63}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\GT` :math:`\hex{64}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\LE` :math:`\hex{65}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\GE` :math:`\hex{66}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\CLZ` :math:`\hex{67}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\CTZ` :math:`\hex{68}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\POPCNT` :math:`\hex{69}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\ADD` :math:`\hex{6A}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\SUB` :math:`\hex{6B}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\MUL` :math:`\hex{6C}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\DIV\K{\_s}` :math:`\hex{6D}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\DIV\K{\_u}` :math:`\hex{6E}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\REM\K{\_s}` :math:`\hex{6F}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\REM\K{\_u}` :math:`\hex{70}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\AND` :math:`\hex{71}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\OR` :math:`\hex{72}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\XOR` :math:`\hex{73}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\SHL` :math:`\hex{74}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\SHR\K{\_s}` :math:`\hex{75}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\SHR\K{\_u}` :math:`\hex{76}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\ROTL` :math:`\hex{77}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\ROTR` :math:`\hex{78}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\CLZ` :math:`\hex{79}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\CTZ` :math:`\hex{7A}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\POPCNT` :math:`\hex{7B}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\ADD` :math:`\hex{7C}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\SUB` :math:`\hex{7D}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\MUL` :math:`\hex{7E}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\DIV\K{\_s}` :math:`\hex{7F}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\DIV\K{\_u}` :math:`\hex{80}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\REM\K{\_s}` :math:`\hex{81}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\REM\K{\_u}` :math:`\hex{82}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\AND` :math:`\hex{83}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\OR` :math:`\hex{84}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\XOR` :math:`\hex{85}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\SHL` :math:`\hex{86}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\SHR\K{\_s}` :math:`\hex{87}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\SHR\K{\_u}` :math:`\hex{88}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\ROTL` :math:`\hex{89}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\ROTR` :math:`\hex{8A}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\ABS` :math:`\hex{8B}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\NEG` :math:`\hex{8C}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\CEIL` :math:`\hex{8D}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\FLOOR` :math:`\hex{8E}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\TRUNC` :math:`\hex{8F}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\NEAREST` :math:`\hex{90}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\SQRT` :math:`\hex{91}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\ADD` :math:`\hex{92}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\SUB` :math:`\hex{93}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\MUL` :math:`\hex{94}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\DIV` :math:`\hex{95}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\FMIN` :math:`\hex{96}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\FMAX` :math:`\hex{97}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\COPYSIGN` :math:`\hex{98}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\ABS` :math:`\hex{99}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\NEG` :math:`\hex{9A}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\CEIL` :math:`\hex{9B}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\FLOOR` :math:`\hex{9C}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\TRUNC` :math:`\hex{9D}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\NEAREST` :math:`\hex{9E}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\SQRT` :math:`\hex{9F}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\ADD` :math:`\hex{A0}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\SUB` :math:`\hex{A1}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\MUL` :math:`\hex{A2}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\DIV` :math:`\hex{A3}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\FMIN` :math:`\hex{A4}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\FMAX` :math:`\hex{A5}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\COPYSIGN` :math:`\hex{A6}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\WRAP\K{\_}\I64` :math:`\hex{A7}` :math:`[\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_}\F32\K{\_s}` :math:`\hex{A8}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_}\F32\K{\_u}` :math:`\hex{A9}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_}\F64\K{\_s}` :math:`\hex{AA}` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_}\F64\K{\_u}` :math:`\hex{AB}` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EXTEND\K{\_}\I32\K{\_s}` :math:`\hex{AC}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EXTEND\K{\_}\I32\K{\_u}` :math:`\hex{AD}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_}\F32\K{\_s}` :math:`\hex{AE}` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_}\F32\K{\_u}` :math:`\hex{AF}` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_}\F64\K{\_s}` :math:`\hex{B0}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_}\F64\K{\_u}` :math:`\hex{B1}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\CONVERT\K{\_}\I32\K{\_s}` :math:`\hex{B2}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\CONVERT\K{\_}\I32\K{\_u}` :math:`\hex{B3}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\CONVERT\K{\_}\I64\K{\_s}` :math:`\hex{B4}` :math:`[\I64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\CONVERT\K{\_}\I64\K{\_u}` :math:`\hex{B5}` :math:`[\I64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\DEMOTE\K{\_}\F64` :math:`\hex{B6}` :math:`[\F64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\CONVERT\K{\_}\I32\K{\_s}` :math:`\hex{B7}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\CONVERT\K{\_}\I32\K{\_u}` :math:`\hex{B8}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\CONVERT\K{\_}\I64\K{\_s}` :math:`\hex{B9}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\CONVERT\K{\_}\I64\K{\_u}` :math:`\hex{BA}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\PROMOTE\K{\_}\F32` :math:`\hex{BB}` :math:`[\F32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\REINTERPRET\K{\_}\F32` :math:`\hex{BC}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\REINTERPRET\K{\_}\F64` :math:`\hex{BD}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\REINTERPRET\K{\_}\I32` :math:`\hex{BE}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\REINTERPRET\K{\_}\I64` :math:`\hex{BF}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\EXTEND\K{8\_s}` :math:`\hex{C0}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\EXTEND\K{16\_s}` :math:`\hex{C1}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EXTEND\K{8\_s}` :math:`\hex{C2}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EXTEND\K{16\_s}` :math:`\hex{C3}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EXTEND\K{32\_s}` :math:`\hex{C4}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -(reserved) :math:`\hex{C5}` -(reserved) :math:`\hex{C6}` -(reserved) :math:`\hex{C7}` -(reserved) :math:`\hex{C8}` -(reserved) :math:`\hex{C9}` -(reserved) :math:`\hex{CA}` -(reserved) :math:`\hex{CB}` -(reserved) :math:`\hex{CC}` -(reserved) :math:`\hex{CD}` -(reserved) :math:`\hex{CE}` -(reserved) :math:`\hex{CF}` -:math:`\REFNULL~t` :math:`\hex{D0}` :math:`[] \to [t]` :ref:`validation ` :ref:`execution ` -:math:`\REFISNULL` :math:`\hex{D1}` :math:`[t] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\REFFUNC~x` :math:`\hex{D2}` :math:`[] \to [\FUNCREF]` :ref:`validation ` :ref:`execution ` -(reserved) :math:`\hex{D3}` -(reserved) :math:`\hex{D4}` -(reserved) :math:`\hex{D5}` -(reserved) :math:`\hex{D6}` -(reserved) :math:`\hex{D7}` -(reserved) :math:`\hex{D8}` -(reserved) :math:`\hex{D9}` -(reserved) :math:`\hex{DA}` -(reserved) :math:`\hex{DB}` -(reserved) :math:`\hex{DC}` -(reserved) :math:`\hex{DD}` -(reserved) :math:`\hex{DE}` -(reserved) :math:`\hex{DF}` -(reserved) :math:`\hex{E0}` -(reserved) :math:`\hex{E1}` -(reserved) :math:`\hex{E2}` -(reserved) :math:`\hex{E3}` -(reserved) :math:`\hex{E4}` -(reserved) :math:`\hex{E5}` -(reserved) :math:`\hex{E6}` -(reserved) :math:`\hex{E7}` -(reserved) :math:`\hex{E8}` -(reserved) :math:`\hex{E9}` -(reserved) :math:`\hex{EA}` -(reserved) :math:`\hex{EB}` -(reserved) :math:`\hex{EC}` -(reserved) :math:`\hex{ED}` -(reserved) :math:`\hex{EE}` -(reserved) :math:`\hex{EF}` -(reserved) :math:`\hex{F0}` -(reserved) :math:`\hex{F1}` -(reserved) :math:`\hex{F2}` -(reserved) :math:`\hex{F3}` -(reserved) :math:`\hex{F4}` -(reserved) :math:`\hex{F5}` -(reserved) :math:`\hex{F6}` -(reserved) :math:`\hex{F7}` -(reserved) :math:`\hex{F8}` -(reserved) :math:`\hex{F9}` -(reserved) :math:`\hex{FA}` -(reserved) :math:`\hex{FB}` -:math:`\I32.\TRUNC\K{\_sat\_}\F32\K{\_s}` :math:`\hex{FC}~\hex{00}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_sat\_}\F32\K{\_u}` :math:`\hex{FC}~\hex{01}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_sat\_}\F64\K{\_s}` :math:`\hex{FC}~\hex{02}` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_sat\_}\F64\K{\_u}` :math:`\hex{FC}~\hex{03}` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_sat\_}\F32\K{\_s}` :math:`\hex{FC}~\hex{04}` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_sat\_}\F32\K{\_u}` :math:`\hex{FC}~\hex{05}` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_sat\_}\F64\K{\_s}` :math:`\hex{FC}~\hex{06}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_sat\_}\F64\K{\_u}` :math:`\hex{FC}~\hex{07}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\MEMORYINIT~x` :math:`\hex{FC}~\hex{08}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\DATADROP~x` :math:`\hex{FC}~\hex{09}` :math:`[] \to []` :ref:`validation ` :ref:`execution ` -:math:`\MEMORYCOPY` :math:`\hex{FC}~\hex{0A}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\MEMORYFILL` :math:`\hex{FC}~\hex{0B}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\TABLEINIT~x~y` :math:`\hex{FC}~\hex{0C}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\ELEMDROP~x` :math:`\hex{FC}~\hex{0D}` :math:`[] \to []` :ref:`validation ` :ref:`execution ` -:math:`\TABLECOPY~x~y` :math:`\hex{FC}~\hex{0E}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\TABLEGROW~x` :math:`\hex{FC}~\hex{0F}` :math:`[t~\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\TABLESIZE~x` :math:`\hex{FC}~\hex{10}` :math:`[] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\TABLEFILL~x` :math:`\hex{FC}~\hex{11}` :math:`[\I32~t~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD~\memarg` :math:`\hex{FD}~~\hex{00}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{8x8\_s}~\memarg` :math:`\hex{FD}~~\hex{01}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{8x8\_u}~\memarg` :math:`\hex{FD}~~\hex{02}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{16x4\_s}~\memarg` :math:`\hex{FD}~~\hex{03}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{16x4\_u}~\memarg` :math:`\hex{FD}~~\hex{04}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{32x2\_s}~\memarg` :math:`\hex{FD}~~\hex{05}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{32x2\_u}~\memarg` :math:`\hex{FD}~~\hex{06}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{8\_splat}~\memarg` :math:`\hex{FD}~~\hex{07}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{16\_splat}~\memarg` :math:`\hex{FD}~~\hex{08}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{32\_splat}~\memarg` :math:`\hex{FD}~~\hex{09}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{64\_splat}~\memarg` :math:`\hex{FD}~~\hex{0A}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\STORE~\memarg` :math:`\hex{FD}~~\hex{0B}` :math:`[\I32~\V128] \to []` :ref:`validation ` :ref:`execution ` -:math:`\V128.\VCONST~\i128` :math:`\hex{FD}~~\hex{0C}` :math:`[] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I8X16.\SHUFFLE~\laneidx^{16}` :math:`\hex{FD}~~\hex{0D}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I8X16.\SWIZZLE` :math:`\hex{FD}~~\hex{0E}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I8X16.\SPLAT` :math:`\hex{FD}~~\hex{0F}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\SPLAT` :math:`\hex{FD}~~\hex{10}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\SPLAT` :math:`\hex{FD}~~\hex{11}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I64X2.\SPLAT` :math:`\hex{FD}~~\hex{12}` :math:`[\I64] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\F32X4.\SPLAT` :math:`\hex{FD}~~\hex{13}` :math:`[\F32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\F64X2.\SPLAT` :math:`\hex{FD}~~\hex{14}` :math:`[\F64] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I8X16.\EXTRACTLANE\K{\_s}~\laneidx` :math:`\hex{FD}~~\hex{15}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I8X16.\EXTRACTLANE\K{\_u}~\laneidx` :math:`\hex{FD}~~\hex{16}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I8X16.\REPLACELANE~\laneidx` :math:`\hex{FD}~~\hex{17}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\EXTRACTLANE\K{\_s}~\laneidx` :math:`\hex{FD}~~\hex{18}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\EXTRACTLANE\K{\_u}~\laneidx` :math:`\hex{FD}~~\hex{19}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\REPLACELANE~\laneidx` :math:`\hex{FD}~~\hex{1A}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\EXTRACTLANE~\laneidx` :math:`\hex{FD}~~\hex{1B}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\REPLACELANE~\laneidx` :math:`\hex{FD}~~\hex{1C}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I64X2.\EXTRACTLANE~\laneidx` :math:`\hex{FD}~~\hex{1D}` :math:`[\V128] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64X2.\REPLACELANE~\laneidx` :math:`\hex{FD}~~\hex{1E}` :math:`[\V128~\I64] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\F32X4.\EXTRACTLANE~\laneidx` :math:`\hex{FD}~~\hex{1F}` :math:`[\V128] \to [\F32]` :ref:`validation ` :ref:`execution ` -:math:`\F32X4.\REPLACELANE~\laneidx` :math:`\hex{FD}~~\hex{20}` :math:`[\V128~\F32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\F64X2.\EXTRACTLANE~\laneidx` :math:`\hex{FD}~~\hex{21}` :math:`[\V128] \to [\F64]` :ref:`validation ` :ref:`execution ` -:math:`\F64X2.\REPLACELANE~\laneidx` :math:`\hex{FD}~~\hex{22}` :math:`[\V128~\F64] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I8X16.\VEQ` :math:`\hex{FD}~~\hex{23}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VNE` :math:`\hex{FD}~~\hex{24}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VLT\K{\_s}` :math:`\hex{FD}~~\hex{25}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VLT\K{\_u}` :math:`\hex{FD}~~\hex{26}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VGT\K{\_s}` :math:`\hex{FD}~~\hex{27}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VGT\K{\_u}` :math:`\hex{FD}~~\hex{28}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VLE\K{\_s}` :math:`\hex{FD}~~\hex{29}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VLE\K{\_u}` :math:`\hex{FD}~~\hex{2A}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VGE\K{\_s}` :math:`\hex{FD}~~\hex{2B}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VGE\K{\_u}` :math:`\hex{FD}~~\hex{2C}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VEQ` :math:`\hex{FD}~~\hex{2D}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VNE` :math:`\hex{FD}~~\hex{2E}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VLT\K{\_s}` :math:`\hex{FD}~~\hex{2F}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VLT\K{\_u}` :math:`\hex{FD}~~\hex{30}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VGT\K{\_s}` :math:`\hex{FD}~~\hex{31}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VGT\K{\_u}` :math:`\hex{FD}~~\hex{32}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VLE\K{\_s}` :math:`\hex{FD}~~\hex{33}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VLE\K{\_u}` :math:`\hex{FD}~~\hex{34}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VGE\K{\_s}` :math:`\hex{FD}~~\hex{35}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VGE\K{\_u}` :math:`\hex{FD}~~\hex{36}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VEQ` :math:`\hex{FD}~~\hex{37}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VNE` :math:`\hex{FD}~~\hex{38}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VLT\K{\_s}` :math:`\hex{FD}~~\hex{39}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VLT\K{\_u}` :math:`\hex{FD}~~\hex{3A}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VGT\K{\_s}` :math:`\hex{FD}~~\hex{3B}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VGT\K{\_u}` :math:`\hex{FD}~~\hex{3C}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VLE\K{\_s}` :math:`\hex{FD}~~\hex{3D}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VLE\K{\_u}` :math:`\hex{FD}~~\hex{3E}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VGE\K{\_s}` :math:`\hex{FD}~~\hex{3F}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VGE\K{\_u}` :math:`\hex{FD}~~\hex{40}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VEQ` :math:`\hex{FD}~~\hex{41}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VNE` :math:`\hex{FD}~~\hex{42}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VLT` :math:`\hex{FD}~~\hex{43}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VGT` :math:`\hex{FD}~~\hex{44}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VLE` :math:`\hex{FD}~~\hex{45}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VGE` :math:`\hex{FD}~~\hex{46}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VEQ` :math:`\hex{FD}~~\hex{47}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VNE` :math:`\hex{FD}~~\hex{48}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VLT` :math:`\hex{FD}~~\hex{49}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VGT` :math:`\hex{FD}~~\hex{4A}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VLE` :math:`\hex{FD}~~\hex{4B}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VGE` :math:`\hex{FD}~~\hex{4C}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\V128.\VNOT` :math:`\hex{FD}~~\hex{4D}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\V128.\VAND` :math:`\hex{FD}~~\hex{4E}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\V128.\VANDNOT` :math:`\hex{FD}~~\hex{4F}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\V128.\VOR` :math:`\hex{FD}~~\hex{50}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\V128.\VXOR` :math:`\hex{FD}~~\hex{51}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\V128.\BITSELECT` :math:`\hex{FD}~~\hex{52}` :math:`[\V128~\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\V128.\ANYTRUE` :math:`\hex{FD}~~\hex{53}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{8\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{54}` :math:`[\I32~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{16\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{55}` :math:`[\I32~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{32\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{56}` :math:`[\I32~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{64\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{57}` :math:`[\I32~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\STORE\K{8\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{58}` :math:`[\I32~\V128] \to []` :ref:`validation ` :ref:`execution ` -:math:`\V128.\STORE\K{16\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{59}` :math:`[\I32~\V128] \to []` :ref:`validation ` :ref:`execution ` -:math:`\V128.\STORE\K{32\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{5A}` :math:`[\I32~\V128] \to []` :ref:`validation ` :ref:`execution ` -:math:`\V128.\STORE\K{64\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{5B}` :math:`[\I32~\V128] \to []` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{32\_zero}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{5C}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{64\_zero}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{5D}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\F32X4.\VDEMOTE\K{\_f64x2\_zero}` :math:`\hex{FD}~~\hex{5E}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VPROMOTE\K{\_low\_f32x4}` :math:`\hex{FD}~~\hex{5F}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VABS` :math:`\hex{FD}~~\hex{60}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VNEG` :math:`\hex{FD}~~\hex{61}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VPOPCNT` :math:`\hex{FD}~~\hex{62}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\ALLTRUE` :math:`\hex{FD}~~\hex{63}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I8X16.\BITMASK` :math:`\hex{FD}~~\hex{64}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I8X16.\NARROW\K{\_i16x8\_s}` :math:`\hex{FD}~~\hex{65}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I8X16.\NARROW\K{\_i16x8\_u}` :math:`\hex{FD}~~\hex{66}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\F32X4.\VCEIL` :math:`\hex{FD}~~\hex{67}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VFLOOR` :math:`\hex{FD}~~\hex{68}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VTRUNC` :math:`\hex{FD}~~\hex{69}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VNEAREST` :math:`\hex{FD}~~\hex{6A}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VSHL` :math:`\hex{FD}~~\hex{6B}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VSHR\K{\_s}` :math:`\hex{FD}~~\hex{6C}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VSHR\K{\_u}` :math:`\hex{FD}~~\hex{6D}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VADD` :math:`\hex{FD}~~\hex{6E}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VADD\K{\_sat\_s}` :math:`\hex{FD}~~\hex{6F}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VADD\K{\_sat\_u}` :math:`\hex{FD}~~\hex{70}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VSUB` :math:`\hex{FD}~~\hex{71}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VSUB\K{\_sat\_s}` :math:`\hex{FD}~~\hex{72}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VSUB\K{\_sat\_u}` :math:`\hex{FD}~~\hex{73}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VCEIL` :math:`\hex{FD}~~\hex{74}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VFLOOR` :math:`\hex{FD}~~\hex{75}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VMIN\K{\_s}` :math:`\hex{FD}~~\hex{76}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VMIN\K{\_u}` :math:`\hex{FD}~~\hex{77}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VMAX\K{\_s}` :math:`\hex{FD}~~\hex{78}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VMAX\K{\_u}` :math:`\hex{FD}~~\hex{79}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VTRUNC` :math:`\hex{FD}~~\hex{7A}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\AVGR\K{\_u}` :math:`\hex{FD}~~\hex{7B}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\EXTADDPAIRWISE\K{\_i8x16\_s}` :math:`\hex{FD}~~\hex{7C}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\EXTADDPAIRWISE\K{\_i8x16\_u}` :math:`\hex{FD}~~\hex{7D}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\EXTADDPAIRWISE\K{\_i16x8\_s}` :math:`\hex{FD}~~\hex{7E}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\EXTADDPAIRWISE\K{\_i16x8\_u}` :math:`\hex{FD}~~\hex{7F}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\VABS` :math:`\hex{FD}~~\hex{80}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VNEG` :math:`\hex{FD}~~\hex{81}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\Q15MULRSAT\K{\_s}` :math:`\hex{FD}~~\hex{82}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\ALLTRUE` :math:`\hex{FD}~~\hex{83}~~\hex{01}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\BITMASK` :math:`\hex{FD}~~\hex{84}~~\hex{01}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\NARROW\K{\_i32x4\_s}` :math:`\hex{FD}~~\hex{85}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\NARROW\K{\_i32x4\_u}` :math:`\hex{FD}~~\hex{86}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\VEXTEND\K{\_low\_i8x16\_s}` :math:`\hex{FD}~~\hex{87}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\VEXTEND\K{\_high\_i8x16\_s}` :math:`\hex{FD}~~\hex{88}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\VEXTEND\K{\_low\_i8x16\_u}` :math:`\hex{FD}~~\hex{89}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\VEXTEND\K{\_high\_i8x16\_u}` :math:`\hex{FD}~~\hex{8A}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\VSHL` :math:`\hex{FD}~~\hex{8B}~~\hex{01}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VSHR\K{\_s}` :math:`\hex{FD}~~\hex{8C}~~\hex{01}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VSHR\K{\_u}` :math:`\hex{FD}~~\hex{8D}~~\hex{01}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VADD` :math:`\hex{FD}~~\hex{8E}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VADD\K{\_sat\_s}` :math:`\hex{FD}~~\hex{8F}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VADD\K{\_sat\_u}` :math:`\hex{FD}~~\hex{90}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VSUB` :math:`\hex{FD}~~\hex{91}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VSUB\K{\_sat\_s}` :math:`\hex{FD}~~\hex{92}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VSUB\K{\_sat\_u}` :math:`\hex{FD}~~\hex{93}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VNEAREST` :math:`\hex{FD}~~\hex{94}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VMUL` :math:`\hex{FD}~~\hex{95}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VMIN\K{\_s}` :math:`\hex{FD}~~\hex{96}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VMIN\K{\_u}` :math:`\hex{FD}~~\hex{97}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VMAX\K{\_s}` :math:`\hex{FD}~~\hex{98}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VMAX\K{\_u}` :math:`\hex{FD}~~\hex{99}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\AVGR\K{\_u}` :math:`\hex{FD}~~\hex{9B}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\EXTMUL\K{\_low\_i8x16\_s}` :math:`\hex{FD}~~\hex{9C}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\EXTMUL\K{\_high\_i8x16\_s}` :math:`\hex{FD}~~\hex{9D}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\EXTMUL\K{\_low\_i8x16\_u}` :math:`\hex{FD}~~\hex{9E}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\EXTMUL\K{\_high\_i8x16\_u}` :math:`\hex{FD}~~\hex{9F}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\VABS` :math:`\hex{FD}~~\hex{A0}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VNEG` :math:`\hex{FD}~~\hex{A1}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\ALLTRUE` :math:`\hex{FD}~~\hex{A3}~~\hex{01}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\BITMASK` :math:`\hex{FD}~~\hex{A4}~~\hex{01}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\VEXTEND\K{\_low\_i16x8\_s}` :math:`\hex{FD}~~\hex{A7}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\VEXTEND\K{\_high\_i16x8\_s}` :math:`\hex{FD}~~\hex{A8}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\VEXTEND\K{\_low\_i16x8\_u}` :math:`\hex{FD}~~\hex{A9}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\VEXTEND\K{\_high\_i16x8\_u}` :math:`\hex{FD}~~\hex{AA}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\VSHL` :math:`\hex{FD}~~\hex{AB}~~\hex{01}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VSHR\K{\_s}` :math:`\hex{FD}~~\hex{AC}~~\hex{01}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VSHR\K{\_u}` :math:`\hex{FD}~~\hex{AD}~~\hex{01}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VADD` :math:`\hex{FD}~~\hex{AE}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VSUB` :math:`\hex{FD}~~\hex{B1}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VMUL` :math:`\hex{FD}~~\hex{B5}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VMIN\K{\_s}` :math:`\hex{FD}~~\hex{B6}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VMIN\K{\_u}` :math:`\hex{FD}~~\hex{B7}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VMAX\K{\_s}` :math:`\hex{FD}~~\hex{B8}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VMAX\K{\_u}` :math:`\hex{FD}~~\hex{B9}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\DOT\K{\_i16x8\_s}` :math:`\hex{FD}~~\hex{BA}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\EXTMUL\K{\_low\_i16x8\_s}` :math:`\hex{FD}~~\hex{BC}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\EXTMUL\K{\_high\_i16x8\_s}` :math:`\hex{FD}~~\hex{BD}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\EXTMUL\K{\_low\_i16x8\_u}` :math:`\hex{FD}~~\hex{BE}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\EXTMUL\K{\_high\_i16x8\_u}` :math:`\hex{FD}~~\hex{BF}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I64X2.\VABS` :math:`\hex{FD}~~\hex{C0}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64X2.\VNEG` :math:`\hex{FD}~~\hex{C1}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64X2.\ALLTRUE` :math:`\hex{FD}~~\hex{C3}~~\hex{01}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I64X2.\BITMASK` :math:`\hex{FD}~~\hex{C4}~~\hex{01}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I64X2.\VEXTEND\K{\_low\_i32x4\_s}` :math:`\hex{FD}~~\hex{C7}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I64X2.\VEXTEND\K{\_high\_i32x4\_s}` :math:`\hex{FD}~~\hex{C8}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I64X2.\VEXTEND\K{\_low\_i32x4\_u}` :math:`\hex{FD}~~\hex{C9}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I64X2.\VEXTEND\K{\_high\_i32x4\_u}` :math:`\hex{FD}~~\hex{CA}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I64X2.\VSHL` :math:`\hex{FD}~~\hex{CB}~~\hex{01}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64X2.\VSHR\K{\_s}` :math:`\hex{FD}~~\hex{CC}~~\hex{01}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64X2.\VSHR\K{\_u}` :math:`\hex{FD}~~\hex{CD}~~\hex{01}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64X2.\VADD` :math:`\hex{FD}~~\hex{CE}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64X2.\VSUB` :math:`\hex{FD}~~\hex{D1}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64X2.\VMUL` :math:`\hex{FD}~~\hex{D5}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64X2.\VEQ` :math:`\hex{FD}~~\hex{D6}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64X2.\VNE` :math:`\hex{FD}~~\hex{D7}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64X2.\VLT\K{\_s}` :math:`\hex{FD}~~\hex{D8}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64X2.\VGT\K{\_s}` :math:`\hex{FD}~~\hex{D9}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64X2.\VLE\K{\_s}` :math:`\hex{FD}~~\hex{DA}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64X2.\VGE\K{\_s}` :math:`\hex{FD}~~\hex{DB}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64X2.\EXTMUL\K{\_low\_i32x4\_s}` :math:`\hex{FD}~~\hex{DC}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I64X2.\EXTMUL\K{\_high\_i32x4\_s}` :math:`\hex{FD}~~\hex{DD}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I64X2.\EXTMUL\K{\_low\_i32x4\_u}` :math:`\hex{FD}~~\hex{DE}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I64X2.\EXTMUL\K{\_high\_i32x4\_u}` :math:`\hex{FD}~~\hex{DF}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\F32X4.\VABS` :math:`\hex{FD}~~\hex{E0}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VNEG` :math:`\hex{FD}~~\hex{E1}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VSQRT` :math:`\hex{FD}~~\hex{E3}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VADD` :math:`\hex{FD}~~\hex{E4}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VSUB` :math:`\hex{FD}~~\hex{E5}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VMUL` :math:`\hex{FD}~~\hex{E6}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VDIV` :math:`\hex{FD}~~\hex{E7}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VMIN` :math:`\hex{FD}~~\hex{E8}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VMAX` :math:`\hex{FD}~~\hex{E9}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VPMIN` :math:`\hex{FD}~~\hex{EA}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VPMAX` :math:`\hex{FD}~~\hex{EB}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VABS` :math:`\hex{FD}~~\hex{EC}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VNEG` :math:`\hex{FD}~~\hex{ED}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VSQRT` :math:`\hex{FD}~~\hex{EF}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VADD` :math:`\hex{FD}~~\hex{F0}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VSUB` :math:`\hex{FD}~~\hex{F1}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VMUL` :math:`\hex{FD}~~\hex{F2}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VDIV` :math:`\hex{FD}~~\hex{F3}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VMIN` :math:`\hex{FD}~~\hex{F4}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VMAX` :math:`\hex{FD}~~\hex{F5}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VPMIN` :math:`\hex{FD}~~\hex{F6}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VPMAX` :math:`\hex{FD}~~\hex{F7}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\TRUNC\K{\_sat\_f32x4\_s}` :math:`\hex{FD}~~\hex{F8}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\TRUNC\K{\_sat\_f32x4\_u}` :math:`\hex{FD}~~\hex{F9}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VCONVERT\K{\_i32x4\_s}` :math:`\hex{FD}~~\hex{FA}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VCONVERT\K{\_i32x4\_u}` :math:`\hex{FD}~~\hex{FB}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VTRUNC\K{\_sat\_f64x2\_s\_zero}` :math:`\hex{FD}~~\hex{FC}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VTRUNC\K{\_sat\_f64x2\_u\_zero}` :math:`\hex{FD}~~\hex{FD}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VCONVERT\K{\_low\_i32x4\_s}` :math:`\hex{FD}~~\hex{FE}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VCONVERT\K{\_low\_i32x4\_u}` :math:`\hex{FD}~~\hex{FF}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -================================================= ==================================== ============================================= ============================================= ================================================================== - -.. note:: - Multi-byte opcodes are given with the shortest possible encoding in the table. - However, what is following the first byte is actually a :ref:`u32 ` with variable-length encoding - and consequently has multiple possible representations. From 55333ae8ea53249c2749216e833b5834c73f8d98 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Wed, 1 Mar 2023 09:50:47 +0100 Subject: [PATCH 045/132] [spec] Rename script --- document/core/Makefile | 2 +- .../{gen-index-instructions.py => index-instructions.py} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename document/core/appendix/{gen-index-instructions.py => index-instructions.py} (99%) diff --git a/document/core/Makefile b/document/core/Makefile index bfbf70bf..d8b357c7 100644 --- a/document/core/Makefile +++ b/document/core/Makefile @@ -91,7 +91,7 @@ bikeshed-keep: .PHONY: index index: - (cd appendix; ./gen-index-instructions.py) + (cd appendix; ./index-instructions.py) .PHONY: pdf pdf: index latexpdf diff --git a/document/core/appendix/gen-index-instructions.py b/document/core/appendix/index-instructions.py similarity index 99% rename from document/core/appendix/gen-index-instructions.py rename to document/core/appendix/index-instructions.py index fffa2b32..2503a7ab 100755 --- a/document/core/appendix/gen-index-instructions.py +++ b/document/core/appendix/index-instructions.py @@ -12,7 +12,7 @@ INDEX_INSTRUCTIONS_RST = os.path.join(SCRIPT_DIR, 'index-instructions.rst') HEADER = """\ -.. DO NOT EDIT: This file is auto-generated by the gen-index-instructions.py script. +.. DO NOT EDIT: This file is auto-generated by the index-instructions.py script. .. index:: instruction .. _index-instr: From 7f67637cd638e273f3e9b8be08a9c0e322497498 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Wed, 1 Mar 2023 12:28:33 +0100 Subject: [PATCH 046/132] [spec] Handle generated files more cleanly --- document/core/.gitignore | 1 - document/core/Makefile | 19 ++++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/document/core/.gitignore b/document/core/.gitignore index d21e55e3..b932ec28 100644 --- a/document/core/.gitignore +++ b/document/core/.gitignore @@ -1,4 +1,3 @@ _build _static document/*.pyc -appendix/index-instructions.rst diff --git a/document/core/Makefile b/document/core/Makefile index d8b357c7..5b81bff0 100644 --- a/document/core/Makefile +++ b/document/core/Makefile @@ -89,12 +89,14 @@ bikeshed-keep: echo Downloaded Bikeshed. -.PHONY: index -index: - (cd appendix; ./index-instructions.py) +GENERATED = appendix/index-instructions.rst +.INTERMEDIATE: $(GENERATED) + +%.rst: %.py + (cd `dirname $@`; ./`basename $^`) .PHONY: pdf -pdf: index latexpdf +pdf: $(GENERATED) latexpdf mkdir -p $(BUILDDIR)/html/$(DOWNLOADDIR) ln -f $(BUILDDIR)/latex/$(NAME).pdf $(BUILDDIR)/html/$(DOWNLOADDIR)/$(NAME).pdf @@ -103,10 +105,9 @@ pdf: index latexpdf clean: rm -rf $(BUILDDIR) rm -rf $(STATICDIR) - rm -f appendix/index-instructions.rst .PHONY: html -html: index +html: $(GENERATED) $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html for file in `ls $(BUILDDIR)/html/*.html`; \ do \ @@ -122,19 +123,19 @@ html: index @echo "Build finished. The HTML pages are in `pwd`/$(BUILDDIR)/html/." .PHONY: dirhtml -dirhtml: +dirhtml: $(GENERATED) $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." .PHONY: singlehtml -singlehtml: +singlehtml: $(GENERATED) $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." .PHONY: bikeshed -bikeshed: +bikeshed: $(GENERATED) $(SPHINXBUILD) -b singlehtml -c util/bikeshed \ $(ALLSPHINXOPTS) $(BUILDDIR)/bikeshed_singlehtml python util/bikeshed_fixup.py $(BUILDDIR)/bikeshed_singlehtml/index.html \ From 8f732b8cb482c640c257f83aac2ed5c70e838d42 Mon Sep 17 00:00:00 2001 From: Ioanna M Dimitriou H <9728696+ioannad@users.noreply.github.com> Date: Wed, 1 Mar 2023 17:45:45 +0100 Subject: [PATCH 047/132] Add prose for reduction rules involving thrown exceptions, (#226) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add prose for reduction rules involving thrown exceptions. - Change administrative handler instructions and adding caught exceptions to the runtime stack. + In particular: * Switched to handler ::= (tagaddr? instr*)* | labelidx exn ::= tagaddr val* instr ::= โ€ฆ | handler_n{handler} instr* end | caught_n{exn} instr* end removing DELEGATEadm - Changed prose to just push and pop handlers and exceptions, in the runtime, in the execution steps of the instructions, in the formal overview, and partly in appendix/properties. - Apply suggestions from code review Co-authored-by: Heejin Ahn Co-authored-by: Andreas Rossberg --- document/core/appendix/properties.rst | 37 ++--- document/core/exec/instructions.rst | 142 +++++++++++++----- document/core/exec/runtime.rst | 84 ++++++----- document/core/util/macros.def | 4 +- .../Exceptions-formal-examples.md | 92 ++++++------ .../Exceptions-formal-overview.md | 73 ++++----- 6 files changed, 257 insertions(+), 175 deletions(-) diff --git a/document/core/appendix/properties.rst b/document/core/appendix/properties.rst index 2c2c3eea..1f3c1dfa 100644 --- a/document/core/appendix/properties.rst +++ b/document/core/appendix/properties.rst @@ -612,64 +612,65 @@ To that end, all previous typing judgements :math:`C \vdash \X{prop}` are genera } -.. index:: catch, throw context +.. index:: handler, throw context -:math:`\CATCHadm\{\tagaddr^?~\instr_1^\ast\}^\ast~\instr_2^\ast~\END` -..................................................................... +:math:`\HANDLERadm_n\{(\tagaddr^?~\instr_1^\ast)^\ast\}~\instr_2^\ast~\END` +........................................................................... * Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with the :ref:`label type ` :math:`[t_2^\ast]` prepended to the |CLABELS| vector. * Under context :math:`C'`, - the instruction sequence :math:`\instr_2^\ast` must be :ref:`valid ` with type :math:`[] \to [t_2^\ast]`. + the instruction sequence :math:`\instr_2^\ast` must be :ref:`valid ` with type :math:`[] \to [t_2^n]`. -* Let :math:`C''` be the same :ref:`context ` as :math:`C`, but with the :ref:`label type ` :math:`(\LCATCH~[t_2^\ast])` prepended to the |CLABELS| vector. +* Let :math:`C''` be the same :ref:`context ` as :math:`C`, but with the :ref:`label type ` :math:`(\LCATCH~[t_2^n])` prepended to the |CLABELS| vector. * Under context :math:`C''`, for every :math:`\tagaddr^?` and associated instruction sequence :math:`\instr_1^\ast`: - * If :math:`\tagaddr^? = \epsilon`, then :math:`\instr_1^\ast` must be :ref:`valid ` with type :math:`[] \to [t_2^\ast]`. + * If :math:`\tagaddr^? = \epsilon`, then :math:`\instr_1^\ast` must be :ref:`valid ` with type :math:`[] \to [t_2^n]`. * Else: * The :ref:`external tag value ` :math:`\EVTAG~\tagaddr` must be :ref:`valid ` with some :ref:`external tag type ` :math:`\ETTAG~[t_1^\ast] \to []`. - * The instruction sequence :math:`\instr_1^\ast` must be :ref:`valid ` with type :math:`[t_1^\ast] \to [t_2^\ast]`. + * The instruction sequence :math:`\instr_1^\ast` must be :ref:`valid ` with type :math:`[t_1^\ast] \to [t_2^n]`. -* Then the compound instruction is valid under context :math:`C'` with type :math:`[] \to [t_2^\ast]`. +* Then the compound instruction is valid under context :math:`C'` with type :math:`[] \to [t_2^n]`. .. math:: \frac{ \begin{array}{@{}c@{}} ((S \vdashexternval \EVTAG~\tagaddr : \ETTAG~[t_1^\ast]\to[])^? \\ - ~~S; C,\CLABELS\,(\LCATCH~[t_2^\ast]) \vdashinstrseq \instr_1^\ast : [(t_1^\ast)^?] \to [t_2^\ast])^\ast \\ - S; C,\CLABELS\,[t_2^\ast] \vdashinstrseq \instr_2^\ast : [] \to [t_2^\ast] \\ + ~~S; C,\CLABELS\,(\LCATCH~[t_2^n]) \vdashinstrseq \instr_1^\ast : [(t_1^\ast)^?] \to [t_2^n])^\ast \\ + S; C,\CLABELS\,[t_2^n] \vdashinstrseq \instr_2^\ast : [] \to [t_2^n] \\ \end{array} }{ - S; C,\CLABELS\,[t_2^\ast] \vdashadmininstr \CATCHadm\{\tagaddr^?~{\instr_1}^\ast\}^\ast~\instr_2^\ast~\END : [] \to [t_2^\ast] + S; C,\CLABELS\,[t_2^n] \vdashadmininstr \HANDLERadm_n\{(\tagaddr^?~{\instr_1}^\ast)^\ast\}~\instr_2^\ast~\END : [] \to [t_2^n] } -.. index:: delegate, throw context +.. index:: handler, throw context +.. _valid-handleradm: -:math:`\DELEGATEadm\{l\}~\instr^\ast~\END` -.......................................... +:math:`\HANDLERadm_n\{l\}~\instr^\ast~\END` +........................................... * The label :math:`C.\CLABELS[l]` must be defined in the context. * Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with the label :math:`[t^\ast]` prepended to the |CLABELS| vector. * Under context :math:`C'`, - the instruction sequence :math:`\instr^\ast` must be :ref:`valid ` with type :math:`[]\to[t^\ast]`. + the instruction sequence :math:`\instr^\ast` must be :ref:`valid ` with type :math:`[]\to[t^n]`. -* Then the compound instruction is valid under context :math:`C'` with type :math:`[] \to [t^\ast]`. +* Then the compound instruction is valid under context :math:`C'` with type :math:`[] \to [t^n]`. .. math:: \frac{ - S; C,\CLABELS\,[t^\ast] \vdashinstrseq \instr^\ast : [] \to [t^\ast] + S; C,\CLABELS\,[t^n] \vdashinstrseq \instr^\ast : [] \to [t^n] \qquad C.\CLABELS[l] = \LCATCH^?~[t_0^\ast] }{ - S; C,\CLABELS\,[t^\ast] \vdashadmininstr \DELEGATEadm\{l\}~\instr^\ast~\END : [] \to [t^\ast] + S; C,\CLABELS\,[t^n] \vdashadmininstr \HANDLERadm_n\{l\}~\instr^\ast~\END : [] \to [t^n] } diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index 550775d6..ae57b3d0 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -2636,26 +2636,26 @@ Control Instructions b. Let :math:`a_i` be the tag address :math:`F.\AMODULE.\MITAGS[x_i]`. - c. Let :math:`H_i` be the handler clause :math:`\{a_i~\instr_{2i}^\ast\}`. + c. Let :math:`H_i` be the handler :math:`(a_i~\instr_{2i}^\ast)`. 8. If there is a catch all clause :math:`(\CATCHALL~\instr_3^\ast)`, then: - a. Let :math:`H'^?` be the handler clause :math:`\{\epsilon~\instr_3^\ast\}`. + a. Let :math:`H'^?` be the handler :math:`(\epsilon~\instr_3^\ast)`. 9. Else: - a. Let :math:`H'^?` be the empty handler clause :math:`\epsilon`. + a. Let :math:`H'^?` be the empty handler :math:`\epsilon`. -10. Let :math:`H^\ast` be the :ref:`catching exception handler ` containing the concatenation of the handler clauses :math:`H_i` and :math:`H'^?`. +10. Let :math:`H^\ast` be the concatenation of :math:`H_i` and :math:`H'^?`. -11. :ref:`Enter ` the block :math:`\val^m~\instr_1^\ast` with label :math:`L` and exception handler :math:`H`. +11. :ref:`Enter ` the block :math:`\val^m~\instr_1^\ast` with label :math:`L` and exception handler :math:`H^\ast`. .. math:: ~\\[-1ex] \begin{array}{l} F; \val^m~(\TRY~\X{bt}~\instr_1^\ast~(\CATCH~x~\instr_2^\ast)^\ast~(\CATCHALL~\instr_3^\ast)^?~\END \quad \stepto \\ - \qquad F; \LABEL_n\{\epsilon\}~(\CATCHadm\{a_x~\instr_2^\ast\}^\ast\{\epsilon~\instr_3\ast\}^?~\val^m~\instr_1^\ast~\END)~\END \\ + \qquad F; \LABEL_n\{\epsilon\}~(\HANDLERadm_n\{(a_x~\instr_2^\ast)^\ast~(\epsilon~\instr_3^\ast)^?\}~\val^m~\instr_1^\ast~\END)~\END \\ (\iff \expand_F(\X{bt}) = [t_1^m] \to [t_2^n] \land (F.\AMODULE.\MITAGS[x]=a_x)^\ast) \end{array} @@ -2671,21 +2671,19 @@ Control Instructions 3. Let :math:`L` be the label whose arity is :math:`n` and whose continuation is the end of the |TRY| instruction. -4. Let :math:`H` be the :ref:`delegating exception handler ` :math:`\DELEGATEadm\{l\}`, targeting the :math:`l`-th surrounding block. +4. Let :math:`H` be the :ref:`exception handler ` :math:`l`, targeting the :math:`l`-th surrounding block. 5. Assert: due to :ref:`validation `, there are at least :math:`m` values on the top of the stack. 6. Pop the values :math:`\val^m` from the stack. -7. :ref:`Enter ` the block :math:`H~(\val^n~\instr^\ast)~\END` with label :math:`L`. - -8. :ref:`Install ` the exception handler `H` containing :math:`\val^m~\instr^\ast`. +7. :ref:`Enter ` the block :math:`\val^m~\instr^\ast` with label :math:`L` and exception handler `H`. .. math:: ~\\[-1ex] \begin{array}{lcl} F; \val^m~(\TRY~\X{bt}~\instr^\ast~\DELEGATE~l) &\stepto& - F; \LABEL_n\{\epsilon\}~(\DELEGATEadm\{l\}~\val^m~\instr^\ast~\END)~\END \\ + F; \LABEL_n\{\epsilon\}~(\HANDLERadm_n\{l\}~\val^m~\instr^\ast~\END)~\END \\ && (\iff \expand_F(\X{bt}) = [t_1^m] \to [t_2^n]) \end{array} @@ -2730,8 +2728,8 @@ Control Instructions .. math:: ~\\[-1ex] \begin{array}{lclr@{\qquad}} - \CAUGHTadm\{a~\val^\ast\}~\XB^l[\RETHROW~l]~\END &\stepto& - \CAUGHTadm\{a~\val^\ast\}~\XB^l[\val^\ast~(\THROWadm~a)]~\END \\ + \CAUGHTadm_n\{a~\val^n\}~\XB^l[\RETHROW~l]~\END &\stepto& + \CAUGHTadm_n\{a~\val^n\}~\XB^l[\val^n~(\THROWadm~a)]~\END \\ \end{array} @@ -3053,8 +3051,7 @@ When the end of a :ref:`try ` instruction is reached without a jump, .. math:: ~\\[-1ex] \begin{array}{lcl@{\qquad}l} - \CATCHadm\{a^?~\instr^\ast\}^\ast~\val^m~\END &\stepto& \val^m \\ - \DELEGATEadm\{l\}~\val^m~\END &\stepto& \val^m + \HANDLERadm_m\{\handler\}~\val^m~\END &\stepto& \val^m \\ \end{array} @@ -3063,53 +3060,128 @@ When the end of a :ref:`try ` instruction is reached without a jump, Throwing an exception with :ref:`tag address ` :math:`a` ........................................................................ -.. todo:: - Add prose for the following execution steps. +When a throw occurs, then values, labels, active catch clauses, +and call frames are popped if necessary, until an appropriate exception handler is found +on the top of the stack. + + 1. Assert: due to :ref:`validation `, :math:`S.\STAGS[a]` exists. + + 2. Let :math:`[t^n] \to []` be the :ref:`tag type ` :math:`S.\STAGS[a].\TAGITYPE`. + + 3. Assert: due to :ref:`validation `, there are :math:`n` values on the top of the stack. + + 4. Pop the :math:`n` values :math:`\val^n` from the stack. + + 5. While the stack is not empty and the top of the stack is not an :ref:`exception handler `, do: + + a. Pop the top element from the stack. + + 6. Assert: the stack is now either empty, or there is an exception handler on the top of the stack. + + 7. If the stack is empty, then: + + a. Return the uncaught exception :math:`\val^n~(\THROWadm~a)` as a :ref:`result `. + +8. Else assert: there is an :ref:`exception handler ` :math:`H` on the top of the stack. + +9. Pop the exception handler :math:`H` from the stack. + +10. If :math:`H` is list of handlers, then: + + a. While :math:`H` is not empty, do: + + i. Let :math:`(a_1^?~\instr^\ast)` be the first handler in :math:`H`. + + ii. If :math:`a_1^? = \epsilon`, then: + + * :ref:`Enter ` the block :math:`\instr^\ast` with caught exception :math:`a~\val^n`. + + iii. Else if :math:`a_1^? = a`, then: + + * :ref:`Enter ` the block :math:`\val^n~\instr^\ast` with caught exception :math:`a~\val^n`. + + iv. Else, pop the first handler from :math:`H`. + + b. Else, the exception was not caught by :math:`H`: + i. Put the values :math:`\val^n` back onto the stack. + + ii. :ref:`Throw ` an exception with tag address :math:`a`. + +11. Else :math:`H` is a label index :math:`l`. + + a. Assert: due to :ref:`validation `, the stack contains at least :math:`l` labels. + + b. Repeat :math:`l` times: + + i. While the top of the stack is not a label, do: + + * Pop the top element from the stack. + + c. Assert: due to :ref:`validation `, the top of the stack now is a label. + + d. Pop the label from the stack. + + e. Push the values :math:`\val^n` onto the stack. + + f. :ref:`Throw ` an exception with tag address :math:`a`. .. math:: \begin{array}{rcl} - \CATCHadm\{a_1^?~\instr^\ast\}\{a'^?~\instr'^\ast\}^\ast~\XT[(\THROWadm~a)]~\END &\stepto& - \CATCHadm\{a'^?~\instr'^\ast\}^\ast~\XT[(\THROWadm~a)]~\END \\ + \HANDLERadm_n\{\}~\XT[(\THROWadm~a)]~\END &\stepto& + \XT[(\THROWadm~a)] \\ + \HANDLERadm_n\{(a_1^?~\instr^\ast)~(a'^?~\instr'^\ast)^\ast\}~\XT[(\THROWadm~a)]~\END &\stepto& + \HANDLERadm_n\{(a'^?~\instr'^\ast)^\ast~\XT[(\THROWadm~a)]~\END \\ && (\iff a_1^? \neq \epsilon \land a_1^? \neq a) \\ - S;~\CATCHadm\{a_1^?~\instr^\ast\}\{a'^?~\instr'^\ast\}^\ast~\XT[\val^n~(\THROWadm~a)]~\END &\stepto& - S;~\CAUGHTadm\{a~\val^n\}~(\val^n)?~\instr^\ast~\END \\ + S;~\HANDLERadm_n\{(a_1^?~\instr^\ast)~(a'^?~\instr'^\ast)^\ast\}~\XT[\val^n~(\THROWadm~a)]~\END &\stepto& + S;~\CAUGHTadm_n\{a~\val^n\}~(\val^n)^?~\instr^\ast~\END \\ && (\iff~(a_1^? = \epsilon \lor a_1^? = a)~\land\\ && \ S.\STAGS[a].\TAGITYPE = [t^n]\to[]) \\ - \LABEL_n\{\}~\XB^l[\DELEGATEadm\{l\}~\XT[(\THROWadm~a)]~\END]~\END &\stepto& + \LABEL_n\{\}~\XB^l[\HANDLERadm_n\{l\}~\XT[(\THROWadm~a)]~\END]~\END &\stepto& \XT[(\THROWadm~a)] \\ \end{array} +.. note:: + The rules are formulated in this way to allow looking up the exception values in the throw context, + only when a thrown exception is caught. -.. todo:: - Add explainer note. -.. _exec-caughtadm: +.. _exec-caughtadm-enter: -Exiting a catch clause -...................... +Entering :math:`\instr^\ast` with caught exception :math:`\{\exn\}` +................................................................... + +1. Push the caught exception |exn| onto the stack. + +2. Jump to the start of the instruction sequence :math:`\instr^\ast`. -When the |END| of a catch clause is reached without a jump, exception, or trap, then the following steps are performed. -1. Let :math:`\val^\ast` be the values on the top of the stack. +.. _exec-caughtadm-exit: -2. Pop the values :math:`\val^\ast` from the stack. +Exiting a block with a caught exception +....................................... -3. Assert: due to :ref:`validation `, a caught exception :math:`\{a~\val_0^\ast\}` is now on the top of the stack. +When the |END| of a block with a caught exception is reached without a jump, thrown exception, or trap, then the following steps are performed. + +1. Let :math:`\val^m` be the values on the top of the stack. + +2. Pop the values :math:`\val^m` from the stack. + +3. Assert: due to :ref:`validation `, a caught exception is now on the top of the stack. 4. Pop the caught exception from the stack. -5. Push :math:`\val^\ast` back to the stack. +5. Push :math:`\val^m` back to the stack. -6. Jump to the position after the |END| of the administrative instruction associated with the catch clause. +6. Jump to the position after the |END| of the administrative instruction associated with the caught exception. .. math:: \begin{array}{rcl} - \CAUGHTadm\{a~\val_0^\ast\}~\val^\ast~\END &\stepto& \val^\ast + \CAUGHTadm_n\{\exn\}~\val^m~\END &\stepto& \val^m \end{array} .. note:: - An exception can only be rethrown from the scope of the |CAUGHTadm| administrative instruction holding it, i.e., from the scope of the |CATCH| or |CATCHALL| block of a :ref:`try-catch ` instruction that caught it. Upon exit from a |CAUGHTadm|, the exception it holds is discarded. + A caught exception can only be rethrown from the scope of the administrative instruction associated with it, i.e., from the scope of the |CATCH| or |CATCHALL| block of a :ref:`try-catch ` instruction that caught it. Upon exit from that block, the caught exception is discarded. .. index:: ! call, function, function instance, label, frame diff --git a/document/core/exec/runtime.rst b/document/core/exec/runtime.rst index 81766713..443ee150 100644 --- a/document/core/exec/runtime.rst +++ b/document/core/exec/runtime.rst @@ -75,14 +75,14 @@ Results ~~~~~~~ A *result* is the outcome of a computation. -It is either a sequence of :ref:`values `, a :ref:`trap `, or an uncaught exception wrapped in its :ref:`throw context `. +It is either a sequence of :ref:`values `, a :ref:`trap `, or an :ref:`exception `. .. math:: \begin{array}{llcl} \production{result} & \result &::=& \val^\ast \\&&|& \TRAP \\&&|& - \XT[\val^\ast~(\THROWadm~\tagaddr)] + \XT[(\THROWadm~\tagaddr)] \end{array} .. index:: ! store, function instance, table instance, memory instance, tag instance, global instance, module, allocation @@ -445,7 +445,7 @@ It filters out entries of a specific kind in an order-preserving fashion: -.. index:: ! stack, ! frame, ! label, ! handler, instruction, store, activation, function, call, local, module instance, exception handler +.. index:: ! stack, ! frame, ! label, ! handler, instruction, store, activation, function, call, local, module instance, exception handler, exception pair: abstract syntax; frame pair: abstract syntax; label pair: abstract syntax; handler @@ -454,6 +454,7 @@ It filters out entries of a specific kind in an order-preserving fashion: .. _frame: .. _label: .. _handler: +.. _exn: .. _stack: Stack @@ -470,6 +471,8 @@ The stack contains three kinds of entries: * *Handlers*: active exception handlers. +* *Exceptions*: caught exceptions. + These entries can occur on the stack in any order during the execution of a program. Stack entries are described by abstract syntax as follows. @@ -526,32 +529,37 @@ and a reference to the function's own :ref:`module instance ` The values of the locals are mutated by respective :ref:`variable instructions `. .. _syntax-handler: +.. _syntax-exn: -Exception handlers -.................. +Exception handlers and exceptions +................................. -Exception handlers are installed by |TRY| instructions and are either *catching handlers* or *delegating handlers*. +Exception handlers are installed by |TRY| instructions and are either a list of handlers or a label index. -Catching handlers start with the identifier |CATCHadm| and contain handler clauses, which are mappings from :ref:`tag addresses ` -to their associated branch *targets*, each of which is expressed syntactically as a possibly empty sequence of +A list of handlers is a mapping from :ref:`tag addresses ` +to their associated branch *targets*. A single handler is expressed syntactically as a possibly empty sequence of :ref:`instructions ` possibly following a :ref:`tag address `. -If there is no :ref:`tag address `, the instructions of that handler clause correspond to a |CATCHALL| clause. +If there is no :ref:`tag address `, the instructions of that handler correspond to a |CATCHALL| clause. + +An exception may be temporarily pushed onto the stack when it is :ref:`thrown and caught ` by a handler. -.. todo:: - Add prose for delegating handlers. +A handler can also consist of a single |labelidx|, which denotes an outer block to which every caught exception will be delegated, by implicitly rethrowing inside that block. +This handler does not catch exceptions, but only rethrows them. .. math:: \begin{array}{llllll} - \production{handler} & \handler &::=& \CATCHadm\{\tagaddr^?~\instr^\ast\}^\ast &|& \DELEGATEadm\{l\} + \production{handler} & \handler &::=& (\tagaddr^?~\instr^\ast)^\ast &|& \labelidx\\ + \production{exception} & \exn &::=& \tagaddr~\val^\ast && \end{array} -Intuitively, for each handler clause :math:`\{\tagaddr^?~\instr^\ast\}` of a |CATCHadm|, :math:`\instr^\ast` is the *continuation* to execute -when the handler catches a thrown exception with tag |tagaddr|, or for any exception, when a handler clause specifies no tag address. -In that case, the exception is handled by the exception handler |CATCHadm|. -If this list of targets is empty, or if the tag address of the thrown exception is not in any of the handler's clauses and there is no |CATCHALL| clause, then the exception will be rethrown. +Intuitively, for each individual handler :math:`(\tagaddr^?~\instr^\ast)`, the instruction block :math:`\instr^\ast` is the *continuation* to execute +when the handler catches a thrown exception with tag |tagaddr|, or for any exception, when that handler specifies no tag address. +If the list of handlers is empty, or if the tag address of the thrown exception is not in any of the handlers in the list, and there is no |CATCHALL| clause, then the exception will be rethrown. -.. todo:: - Add prose with intuition on delegating handlers. +When a thrown exception is caught by a handler, the caught exception is pushed onto the stack and the block of that handler's target is :ref:`entered `. +When exiting a block with a caught exception, the exception is discarded. + +A handler consisting of a |labelidx| :math:`l` can be thought of as a branch to that label that happens in case an exception occurs, immediately followed by a rethrow of the exception at the target site. .. _exec-expand: @@ -574,14 +582,13 @@ Conventions \end{array} -.. index:: ! administrative instructions, function, function instance, function address, label, frame, instruction, trap, call, memory, memory instance, table, table instance, element, data, segment, tag, tag instance, tag address, exceptions, reftype, catch, delegate, handler, caught +.. index:: ! administrative instructions, function, function instance, function address, label, frame, instruction, trap, call, memory, memory instance, table, table instance, element, data, segment, tag, tag instance, tag address, exception, reftype, handler, caught, caught exception pair:: abstract syntax; administrative instruction .. _syntax-trap: .. _syntax-reffuncaddr: .. _syntax-invoke: .. _syntax-throwadm: -.. _syntax-catchadm: -.. _syntax-delegateadm: +.. _syntax-handleradm: .. _syntax-caughtadm: .. _syntax-instr-admin: @@ -603,9 +610,8 @@ In order to express the reduction of :ref:`traps `, :ref:`calls `. It unifies the different forms of throwing exceptions. -The |LABEL|, |FRAME|, |CATCHadm|, |DELEGATEadm|, and |CAUGHTadm| instructions model :ref:`labels `, :ref:`frames `, active :ref:`catching exception handlers `, active :ref:`delegating exception handlers `, and :ref:`caught exceptions `, respectively, :ref:`"on the stack" `. +The |LABEL|, |FRAME|, |HANDLERadm|, and |CAUGHTadm| instructions model :ref:`labels `, :ref:`frames `, active :ref:`exception handlers `, and :ref:`caught exceptions `, respectively, :ref:`"on the stack" `. Moreover, the administrative syntax maintains the nesting structure of the original :ref:`structured control instruction ` or :ref:`function body ` and their :ref:`instruction sequences ` with an |END| marker. That way, the end of the inner instruction sequence is known when part of an outer sequence. @@ -676,8 +682,8 @@ In order to be able to break jumping over exception handlers and caught exceptio .. math:: \begin{array}{llll} - \production{control contexts} & \XC^{k} &::=& \handler~\XB^k~\END \\ - & & | & \CAUGHTadm~\{\tagaddr~\val^\ast\}~\XB^k~\END \\ + \production{control contexts} & \XC^{k} &::=& \HANDLERadm_n\{\handler\}~\XB^k~\END \\ + & & | & \CAUGHTadm_n~\{\exn\}~\XB^k~\END \\ \production{block contexts} & \XB^0 &::=& \dots ~|~ \val^\ast~\XC^0~\instr^\ast\\ \production{block contexts} & \XB^{k+1} &::=& \dots ~|~ \val^\ast~\XC^{k+1}~\instr^\ast \\ \end{array} @@ -701,7 +707,7 @@ Throw Contexts .............. In order to specify the reduction of |TRY| blocks -with the help of the administrative instructions |THROWadm|, |CATCHadm|, |DELEGATEadm|, and |CAUGHTadm|, +with the help of the administrative instructions |THROWadm|, |HANDLERadm|, and |CAUGHTadm|, the following syntax of *throw contexts* is defined, as well as associated structural rules: .. math:: @@ -710,18 +716,16 @@ the following syntax of *throw contexts* is defined, as well as associated struc [\_] \\ &&|& \val^\ast~\XT~\instr^\ast \\ &&|& \LABEL_n\{\instr^\ast\}~\XT~\END \\ &&|& - \CAUGHTadm\{\tagaddr~\val^\ast\}~\XT~\END \\ &&|& + \CAUGHTadm_n\{\exn\}~\XT~\END \\ &&|& \FRAME_n\{F\}~\XT~\END \\ \end{array} -Throw contexts allow matching the program context around a throw instruction up to the innermost enclosing |CATCHadm| or |DELEGATEadm|, thereby selecting the exception |handler| responsible for an exception, if one exists. -If no exception :ref:`handler that catches the exception ` is found, the computation :ref:`results ` in an uncaught exception result value, which contains the exception's entire throw context. +Throw contexts allow matching the program context around a throw instruction up to the innermost enclosing |HANDLERadm|, thereby selecting the exception |handler| responsible for an exception, if one exists. +If no exception :ref:`handler that catches the exception ` is found, the computation :ref:`results ` in an uncaught exception result value. .. note:: Contrary to block contexts, throw contexts don't skip over handlers. - Since handlers are not included above, there is always a unique maximal throw context to match the reduction rules. - |CAUGHTadm| blocks do not represent active handlers. Instead, they delimit the continuation of a handler that has already been selected. Their sole purpose is to record the exception that has been caught, such that |RETHROW| can access it inside such a block. .. note:: @@ -734,24 +738,24 @@ If no exception :ref:`handler that catches the exception ` is fo .. math:: \begin{array}{ll} & \hspace{-5ex} F;~\val_{i32}~\val_{f32}~\val_{i64}~(\TRY~\X{bt}~(\THROW~x)~\CATCH~x~\END) \\ - \stepto & F;~\LABEL_2\{\} (\CATCHadm\{a~\epsilon\}~\val_{i32}~\val_{f32}~\val_{i64}~(\THROW~x)~\END)~\END \\ + \stepto & F;~\LABEL_2\{\} (\HANDLERadm_2\{(a~\epsilon)\}~\val_{i32}~\val_{f32}~\val_{i64}~(\THROW~x)~\END)~\END \\ \end{array} :ref:`Handling the thrown exception ` with tag address :math:`a` in the throw context - :math:`T=[\val_{i32}\_]`, with the exception handler :math:`H=\CATCHadm\{a~\epsilon\}` gives: + :math:`T=[\val_{i32}\_]`, with the exception handler :math:`H=(a~\epsilon)` gives: .. math:: \begin{array}{lll} - \stepto & F;~\LABEL_2\{\}~(\CAUGHTadm\{a~\val_{f32}~\val_{i64}\}~\val_{f32}~\val_{i64}~\END)~\END & \hspace{9ex}\ \\ + \stepto & F;~\LABEL_2\{\}~(\CAUGHTadm_2\{a~\val_{f32}~\val_{i64}\}~\val_{f32}~\val_{i64}~\END)~\END & \hspace{9ex}\ \\ \stepto & F;~\LABEL_2\{\}~\val_{f32}~\val_{i64}~\END & \hspace{9ex}\ \\ \stepto & \val_{f32}~\val_{i64} & \\ \end{array} - When a throw of the form :math:`\val^m (\THROWadm~a)` occurs, search for the maximal surrounding throw context :math:`T` is performed, - which means any other values, labels, frames, and |CAUGHTadm| instructions surrounding the throw :math:`\val^m (\THROWadm~a)` are popped, - until a :ref:`handler ` for the exception is found. - Then a new |CAUGHTadm| instruction, containing the tag address :math:`a` and the values :math:`\val^m`, is pushed onto the stack. + When a throw of the form :math:`\val^m (\THROWadm~a)` occurs, search for an enclosing exception handler is performed, + which means any throw context (that is any other values, labels, frames, and |CAUGHTadm| instructions) surrounding the throw :math:`\val^m (\THROWadm~a)` is popped, + until a :ref:`handler ` for the exception tag :math:`a` is found. + Then the :ref:`caught exception ` containing the tag address :math:`a` and the values :math:`\val^m`, is pushed onto the stack. In this particular case, the exception is caught by the exception handler :math:`H` and its values are returned. diff --git a/document/core/util/macros.def b/document/core/util/macros.def index a69bd9ad..eae5e93f 100644 --- a/document/core/util/macros.def +++ b/document/core/util/macros.def @@ -1094,6 +1094,7 @@ .. |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}} +.. |exn| mathdef:: \xref{exec/runtime}{syntax-exn}{\X{exn}} .. Stack, meta functions @@ -1107,8 +1108,7 @@ .. |TRAP| mathdef:: \xref{exec/runtime}{syntax-trap}{\K{trap}} .. |INVOKE| mathdef:: \xref{exec/runtime}{syntax-invoke}{\K{invoke}} .. |THROWadm| mathdef:: \xref{exec/runtime}{syntax-throwadm}{\K{throw}} -.. |CATCHadm| mathdef:: \xref{exec/runtime}{syntax-catchadm}{\K{catch}} -.. |DELEGATEadm| mathdef:: \xref{exec/runtime}{syntax-delegateadm}{\K{delegate}} +.. |HANDLERadm| mathdef:: \xref{exec/runtime}{syntax-handleradm}{\K{handler}} .. |CAUGHTadm| mathdef:: \xref{exec/runtime}{syntax-caughtadm}{\K{caught}} diff --git a/proposals/exception-handling/Exceptions-formal-examples.md b/proposals/exception-handling/Exceptions-formal-examples.md index 10571d85..5beb6d9a 100644 --- a/proposals/exception-handling/Exceptions-formal-examples.md +++ b/proposals/exception-handling/Exceptions-formal-examples.md @@ -63,11 +63,11 @@ Take the frame `F = (locals i32.const 0, module m)`. We have: ``` โ†ช โ†ช โ†ช โ†ช F; (label_1{} - (catch{ a_x (local.get 0) } + (handler_1{ (a_x (local.get 0)) } (label_0{} - (delegate{ 0 } + (handler_0{ 0 } (label_0{} - (catch{ ฮต (local.set 0 (i32.const 27)) (rethrow 0) } + (handler_0{ (ฮต (local.set 0 (i32.const 27)) (rethrow 0)) } (throw a_x) end) end) end) end) end) end) ``` @@ -75,19 +75,19 @@ For the trivial throw context `T = [_]` the above is the same as ``` โ†ช F; (label_1{} - (catch{ a_x (local.get 0) } + (handler_1{ (a_x (local.get 0)) } (label_0{} - (delegate{ 0 } + (handler_0{ 0 } (label_0{} - (catch{ ฮต (local.set 0 (i32.const 27)) (rethrow 0) } + (handler_0{ (ฮต (local.set 0 (i32.const 27)) (rethrow 0)) } T[(throw a_x)]) end) end) end) end) end) โ†ช F; (label_1{} - (catch{ a_x (local.get 0) } + (handler_1{ (a_x (local.get 0)) } (label_0{} - (delegate{ 0 } + (handler_0{ 0 } (label_0{} - (caught{ a_x ฮต } + (caught_0{ a_x ฮต } (local.set 0 (i32.const 27)) (rethrow 0) end) end) end) end) end) end) ``` @@ -96,48 +96,48 @@ Let `F'` be the frame `{locals i32.const 27, module m}`, and let `B^0 = [_]` to ``` โ†ช F'; (label_1{} - (catch{ a_x (local.get 0) } + (handler_1{ (a_x (local.get 0)) } (label_0{} - (delegate{ 0 } + (handler_0{ 0 } (label_0{} - (caught{ a_x ฮต } + (caught_0{ a_x ฮต } B^0[ (rethrow 0) ] end) end) end) end) end) end) โ†ช F'; (label_1{} - (catch{ a_x (local.get 0) } + (handler_1{ (a_x (local.get 0)) } (label_0{} - (delegate{ 0 } + (handler_0{ 0 } (label_0{} - (caught{ a_x ฮต } + (caught_0{ a_x ฮต } (throw a_x) end) end) end) end) end) end) ``` -Let `T' = (label_0{} (caught{ a_x ฮต } [_] end) end)` and use the same `B^0` as above to reduce the throw with the delegate. +Let `T' = (label_0{} (caught_0{ a_x ฮต } [_] end) end)` and use the same `B^0` as above to reduce the throw with the delegate. ``` โ†ช F'; (label_1{} - (catch{ a_x (local.get 0) } + (handler_1{ (a_x (local.get 0)) } (label_0{} - B^0[ (delegate{ 0 } T'[ (throw a_x) ] end) ] end) end) end) + B^0[ (handler_0{ 0 } T'[ (throw a_x) ] end) ] end) end) end) โ†ช F'; (label_1{} - (catch{ a_x (local.get 0) } + (handler_1{ (a_x (local.get 0)) } (throw a_x) end) end) ``` -Use the trivial throw context `T` again, this time to match the throw to the `catch`. +Use the trivial throw context `T` again, this time to match the throw to the `handler_1{(...)}`. ``` โ†ช F'; (label_1{} - (catch{ a_x (local.get 0) } + (handler_1{ (a_x (local.get 0)) } T[ (throw a_x) ] end) end) โ†ช F'; (label_1{} - (caught{ a_x ฮต } + (caught_0{ a_x ฮต } (local.get 0) end) end) โ†ช F'; (label_1{} - (caught{ a_x ฮต } + (caught_0{ a_x ฮต } (i32.const 27) end) end) โ†ช F'; (label_1{} @@ -196,13 +196,13 @@ In the above example, all thrown exceptions get caught and the first one gets re ``` (label_0{} - (caught{ a_x val_x } ;; <---- The exception rethrown by `rethrow 2` below. + (caught_0{ a_x val_x } ;; <---- The exception rethrown by `rethrow 2` below. val_x (label_0{} - (caught{ a_y val_y } + (caught_0{ a_y val_y } ;; The catch_all does not leave val_y here. (label_0{} - (caught{ a_z val_z } + (caught_0{ a_z val_z } val_z ;; (rethrow 2) puts val_x and the throw below. val_x @@ -266,40 +266,40 @@ In folded form and reduced to the point `throw $x` is called, this is: ``` (label_0{} - (catch{ a_x instr* } + (handler_0{ (a_x instr*) } (label_0{} - (catch{ ฮต ฮต } + (handler_0{ (ฮต ฮต) } (label_0{} - (delegate{ 1 } + (handler_0{ 1 } (label_0{} - (delegate{ 0 } + (handler_0{ 0 } (throw a_x) end) end) end) end) end) end) end) end) ``` -The `delegate{ 0 }` reduces using the trivial throw and block contexts to: +The `handler_0{ 0 }` reduces using the trivial throw and block contexts to: ``` (label_0{} - (catch{ a_x instr* } + (handler_0{ (a_x instr*) } (label_0{} - (catch{ ฮต ฮต } + (handler_0{ (ฮต ฮต) } (label_0{} - (delegate{ 1 } + (handler_0{ 1 } (throw a_x) end) end) end) end) end) end) ``` -The `delegate{ 1 }` reduces using the trivial throw context and the block context `B^1 := (catch{ ฮต ฮต } (label_0{} [_] end) end)` to the following: +The `handler_0{ 1 }` reduces using the trivial throw context and the block context `B^1 := (handler_0{ (ฮต ฮต) } (label_0{} [_] end) end)` to the following: ``` (label_0{} - (catch{ a_x instr* } + (handler_0{ (a_x instr*) } (throw a_x) end) end) ``` The thrown exception is (eventually) caught by the outer try's `catch $x`, so the above reduces to the following. ``` (label_0 {} - (caught{a_x} + (caught_0{a_x} instr* end) end) ``` @@ -342,11 +342,11 @@ When it's time to reduce `(throw y)`, the reduction looks as follows. ``` (label_1{} - (catch{ ฮต (i32.const 4) } + (handler_1{ (ฮต (i32.const 4)) } (label_0{} - (caught{ a_x ฮต } + (caught_0{ a_x ฮต } (label_0{} - (delegate{ 0 } + (handler_0{ 0 } (throw a_y) end) end) end) end) end) end) ``` @@ -354,17 +354,17 @@ For `B^0 := [_] := T`, the above is the same as the following. ``` (label_1{} - (catch{ ฮต (i32.const 4) } + (handler_1{ (ฮต (i32.const 4)) } (label_0{} - (caught{ a_x ฮต } + (caught_0{ a_x ฮต } (label_0{} - B^0 [(delegate{ 0 } T[ (throw a_y) ] end)] end) end) end) end) end) + B^0 [(handler_0{ 0 } T[ (throw a_y) ] end)] end) end) end) end) end) โ†ช (label_1{} - (catch{ ฮต (i32.const 4) } + (handler_1{ (ฮต (i32.const 4)) } (label_0{} - (caught{ a_x ฮต } + (caught_0{ a_x ฮต } (throw a_y) end) end) end) end) ``` -So `throw a_y` gets correctly caught by `catch{ ฮต (i32.const 4) }` and this example reduces to `(i32.const 4)`. +So `throw a_y` gets correctly caught by `handler_1{ (ฮต (i32.const 4)) }` and this example reduces to `(i32.const 4)`. diff --git a/proposals/exception-handling/Exceptions-formal-overview.md b/proposals/exception-handling/Exceptions-formal-overview.md index c5d349cf..d7e1ed51 100644 --- a/proposals/exception-handling/Exceptions-formal-overview.md +++ b/proposals/exception-handling/Exceptions-formal-overview.md @@ -110,12 +110,18 @@ taginst ::= {'type' tagtype} ``` m ::= {..., 'tags' tagaddr*} ``` +#### Stack + +``` +handler ::= (tagaddr? instr*)* | labelidx +exn ::= tagaddr val* +``` #### Administrative Instructions ``` -instr ::= ... | 'throw' tagaddr | 'catch'{ tagaddr? instr* }* instr* 'end' - | 'delegate'{ labelidx } instr* 'end' | 'caught'{ tagaddr val* } instr* 'end' +instr ::= ... | 'throw' tagaddr | 'handler'_n{handler} instr* 'end' + | 'handler'_n{ labelidx } instr* 'end' | 'caught'_n{exn} instr* 'end' ``` #### Block Contexts and Label Kinds @@ -125,73 +131,72 @@ So far block contexts are only used in the reduction of `br l` and `return`, and ``` B^0 ::= val* '[_]' instr* | val* C^0 instr* B^{k+1} ::= val* ('label'_n{instr*} B^k 'end') instr* | val* C^{k+1} instr* -C^k ::= 'catch'{ tagaddr? instr* }* B^k 'end' - | 'caught'{ tagaddr val* } B^k 'end' - | 'delegate'{ labelidx } B^k 'end' +C^k ::= 'handler'_n{ handler } B^k 'end' + | 'caught'_n{ exn } B^k 'end' ``` Note the `C` in `C^k` above stands for `control`, because the related administrative instructions are in some ways modeling [control frame opcodes](https://webassembly.github.io/spec/core/appendix/algorithm.html?highlight=control#data-structures) "on the stack". #### Throw Contexts -Throw contexts don't skip over handlers (administrative `catch` or `delegate` instructions). +Throw contexts don't skip over handlers. Throw contexts are used to match a thrown exception with the innermost handler. ``` T ::= '[_]' | val* T instr* | 'label'_n{instr*} T 'end' - | 'caught'{ tagaddr val* } T 'end' + | 'caught'_n{exn} T 'end' | 'frame'_n{F} T 'end' ``` -Note that because `catch` and `delegate` instructions are not included above, there is always a unique maximal throw context to match the reduction rules. Note that this basically means that `caught{..} instr* end` is not a potential catching block for exceptions thrown by `instr*`. The instruction sequence `instr*` is inside a `catch` or `catch_all` block. +Note that because handlers are not included above, popping the throw context stops when the innermost handler is found, if any. Note that this also means that `caught_n{exn} instr* end` is not a potential catching block for exceptions thrown by `instr*`. The instruction sequence `instr*` is inside a `catch` or `catch_all` block. ### Reduction of Instructions Reduction steps for the new instructions or administrative instructions. -An absent tag address in a `catch` administrative instruction (i.e., `a? = ฮต`) represents a `catch_all`. +An absent tag address in a handler (i.e., `a? = ฮต`) represents a `catch_all`. ``` F; throw x โ†ช F; throw a (if F.module.tagaddrs[x]=a) -caught{a val*} B^l[rethrow l] end - โ†ช caught{a val*} B^l[val* (throw a)] end +caught_n{a val*} B^l[rethrow l] end + โ†ช caught_n{a val*} B^l[val* (throw a)] end -caught{a val0*} val* end โ†ช val* +caught_n{a val0*} val^n end โ†ช val^n F; val^n (try bt instr1* (catch x instr2*)* (catch_all instr3*)? end) - โ†ช F; label_m{} (catch{a instr2*}*{ฮต instr3*}? val^n instr1* end) end + โ†ช F; label_m{} (handler_m{(a instr2*)*(ฮต instr3*)?} val^n instr1* end) end (if expand_F(bt) = [t1^n]โ†’[t2^m] โˆง (F.module.tagaddrs[x]=a)*) -catch{a? instr*}* val* end โ†ช val* +handler_m{(a? instr*)*} val^m end โ†ช val^m -S; F; catch{a1? instr1*}{a0? instr0*}* T[val^n (throw a)] end - โ†ช S; F; caught{a val^n} (val^n)? instr1* end +S; F; handler_m{(a1? instr1*)(a0? instr0*)*} T[val^n (throw a)] end + โ†ช S; F; caught_m{a val^n} (val^n)? instr1* end (if (a1? = ฮต โˆจ a1? = a) โˆง S.tags(a).type = [t^n]โ†’[]) -catch{a1? instr*}{a0? instr0*}* T[val^n (throw a)] end - โ†ช catch{a0? instr0*}* T[val^n (throw a)] end +handler_m{(a1? instr*)(a0? instr0*)*} T[(throw a)] end + โ†ช handler_m{(a0? instr0*)*} T[(throw a)] end (if a1? โ‰  ฮต โˆง a1? โ‰  a) -catch T[val^n (throw a)] end โ†ช val^n (throw a) +handler_m{} T[(throw a)] end โ†ช T[(throw a)] (if S.tags(a).type = [t^n]โ†’[]) F; val^n (try bt instr* delegate l) - โ†ช F; label_m{} (delegate{l} val^n instr* end) end + โ†ช F; label_m{} (handler_m{l} val^n instr* end) end (if expand_F(bt) = [t1^n]โ†’[t2^m]) -delegate{l} val* end โ†ช val* +handler_m{l} val^m end โ†ช val^m -label_m{} B^l[ delegate{l} T[val^n (throw a)] end ] end - โ†ช val^n (throw a) +label_m{} B^l[ handler_m{l} T[(throw a)] end ] end + โ†ช T[(throw a)] ``` -Note that the last reduction step above is similar to the reduction of `br l` [1], the entire `delegate{l}...end` is seen as a `br l` immediately followed by a throw. +Note that the last reduction step above is similar to the reduction of `br l` [1], the entire `handler_m{l}...end` is seen as a `br l` immediately followed by a throw. -There is a subtle difference though. The instruction `br l` searches for the `l+1`th surrounding block and breaks out after that block. Because `delegate{l}` is always wrapped in its own `label_n{} ... end` [2], with the same lookup as for `br l` the instruction ends up breaking inside the `l+1`th surrounding block, and throwing there. So if that `l+1`th surrounding block is a try, the exception is thrown in the "try code", and thus correctly getting delegated to that try's catches. +There is a subtle difference though. The instruction `br l` searches for the `l+1`th surrounding block and breaks out after that block. Because `handler_m{l}` is always wrapped in its own `label_m{} ... end` [2], with the same lookup as for `br l` the instruction ends up breaking inside the `l+1`th surrounding block, and throwing there. So if that `l+1`th surrounding block is a try, the exception is thrown in the "try code", and thus correctly getting delegated to that try's catches. - [1] [The execution step for `br l`](https://webassembly.github.io/spec/core/exec/instructions.html#xref-syntax-instructions-syntax-instr-control-mathsf-br-l) - [2] The label that always wraps `delegate{l}...end` can be thought of as "level -1" and cannot be referred to by the delegate's label index `l`. @@ -205,21 +210,21 @@ S โŠข tag a : tag [t*]โ†’[] S;C โŠข throw a : [t1* t*]โ†’[t2*] ((S โŠข tag a : tag [t1*]โ†’[])? - S;C, labels (catch [t2*]) โŠข instr2* : [t1*?]โ†’[t2*])* -S;C, labels [t2*] โŠข instr1* : []โ†’[t2*] + S;C, labels (catch [t2^m]) โŠข instr2* : [t1*?]โ†’[t2^m])* +S;C, labels [t2^m] โŠข instr1* : []โ†’[t2^m] ----------------------------------------------------------- -S;C, labels [t2*] โŠข catch{a? instr2*}* instr1* end : []โ†’[t2*] +S;C, labels [t2^m] โŠข handler_m{(a? instr2*)*} instr1* end : []โ†’[t2^m] -S;C โŠข instr* : []โ†’[t*] +S;C โŠข instr* : []โ†’[t^m] C.labels[l+1] = [t0*] ------------------------------------------------------ -S;C โŠข delegate{l} instr* end : []โ†’[t*] +S;C โŠข handler_m{l} instr* end : []โ†’[t^m] S โŠข tag a : tag [t0*]โ†’[] (val:t0)* -S;C, labels (catch [t*]) โŠข instr* : []โ†’[t*] ----------------------------------------------------------- -S;C, labels [t*] โŠข caught{a val^*} instr* end : []โ†’[t*] +S;C, labels (catch [t^n]) โŠข instr* : []โ†’[t^n] +------------------------------------------------------------ +S;C, labels [t^n] โŠข caught_n{a val^*} instr* end : []โ†’[t^n] ``` ## Uncaught Exceptions @@ -228,6 +233,6 @@ A new [result](https://webassembly.github.io/spec/core/exec/runtime.html#syntax- ``` result ::= val* | trap - | T[val* (throw tagaddr)] + | val* (throw tagaddr) ``` From d12346cf9a10ddeeef0fcf0c08819755e1a4ac4a Mon Sep 17 00:00:00 2001 From: Ioanna M Dimitriou H <9728696+ioannad@users.noreply.github.com> Date: Wed, 1 Mar 2023 18:27:05 +0100 Subject: [PATCH 048/132] Update index of instructions. (#261) * Update index of instructions. Fixes Issue #258 - Python script tweak, TRY has now two validation and two execution rules. --- .../core/appendix/gen-index-instructions.py | 26 +- document/core/appendix/index-instructions.rst | 1020 ++++++++--------- 2 files changed, 528 insertions(+), 518 deletions(-) diff --git a/document/core/appendix/gen-index-instructions.py b/document/core/appendix/gen-index-instructions.py index fffa2b32..04c391ef 100755 --- a/document/core/appendix/gen-index-instructions.py +++ b/document/core/appendix/gen-index-instructions.py @@ -52,18 +52,28 @@ def RefWrap(s, kind): return f':ref:`{kind} <{s}>`' -def Instruction(name, opcode, type=None, validation=None, execution=None, operator=None): +def Instruction(name, opcode, type=None, validation=None, execution=None, operator=None, validation2=None, execution2=None): if operator: execution_str = ', '.join([RefWrap(execution, 'execution'), RefWrap(operator, 'operator')]) + elif execution2: + execution_str = ', '.join([RefWrap(execution, 'execution'), + RefWrap(execution, 'execution')]) + else: execution_str = RefWrap(execution, 'execution') + if validation2: + validation_str = ', '.join([RefWrap(validation, 'validation'), + RefWrap(validation2, 'validation')]) + else: + validation_str = RefWrap(validation, 'validation') + return ( MathWrap(name, '(reserved)'), MathWrap(opcode), MathWrap(type), - RefWrap(validation, 'validation'), + validation_str, execution_str ) @@ -75,10 +85,10 @@ def Instruction(name, opcode, type=None, validation=None, execution=None, operat Instruction(r'\LOOP~\X{bt}', r'\hex{03}', r'[t_1^\ast] \to [t_2^\ast]', r'valid-loop', r'exec-loop'), Instruction(r'\IF~\X{bt}', r'\hex{04}', r'[t_1^\ast~\I32] \to [t_2^\ast]', r'valid-if', r'exec-if'), Instruction(r'\ELSE', r'\hex{05}'), - Instruction(None, r'\hex{06}'), - Instruction(None, r'\hex{07}'), - Instruction(None, r'\hex{08}'), - Instruction(None, r'\hex{09}'), + Instruction(r'\TRY~\X{bt}', r'\hex{06}', r'[t_1^\ast] \to [t_2^\ast]', r'valid-try-catch', r'exec-try-catch', None, r'valid-try-delegate', r'exec-try-delegate'), + Instruction(r'\CATCH~x', r'\hex{07}'), + Instruction(r'\THROW~x', r'\hex{08}', r'[t_1^\ast~t_x^\ast] \to [t_2^\ast]', r'valid-throw', r'exec-throw'), + Instruction(r'\RETHROW~n', r'\hex{09}', r'[t_1^\ast] \to [t_2^\ast]', r'valid-rethrow', r'exec-rethrow'), Instruction(None, r'\hex{0A}'), Instruction(r'\END', r'\hex{0B}'), Instruction(r'\BR~l', r'\hex{0C}', r'[t_1^\ast~t^\ast] \to [t_2^\ast]', r'valid-br', r'exec-br'), @@ -93,8 +103,8 @@ def Instruction(name, opcode, type=None, validation=None, execution=None, operat Instruction(None, r'\hex{15}'), Instruction(None, r'\hex{16}'), Instruction(None, r'\hex{17}'), - Instruction(None, r'\hex{18}'), - Instruction(None, r'\hex{19}'), + Instruction(r'\DELEGATE~l', r'\hex{18}'), + Instruction(r'\CATCHALL', r'\hex{19}', None, r'valid-try-catch', r'exec-try-catch'), Instruction(r'\DROP', r'\hex{1A}', r'[t] \to []', r'valid-drop', r'exec-drop'), Instruction(r'\SELECT', r'\hex{1B}', r'[t~t~\I32] \to [t]', r'valid-select', r'exec-select'), Instruction(r'\SELECT~t', r'\hex{1C}', r'[t~t~\I32] \to [t]', r'valid-select', r'exec-select'), diff --git a/document/core/appendix/index-instructions.rst b/document/core/appendix/index-instructions.rst index 977c21fb..b23991a4 100644 --- a/document/core/appendix/index-instructions.rst +++ b/document/core/appendix/index-instructions.rst @@ -6,516 +6,516 @@ Index of Instructions --------------------- -================================================= ==================================== ============================================= ============================================= ================================================================== -Instruction Binary Opcode Type Validation Execution -================================================= ==================================== ============================================= ============================================= ================================================================== -:math:`\UNREACHABLE` :math:`\hex{00}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\NOP` :math:`\hex{01}` :math:`[] \to []` :ref:`validation ` :ref:`execution ` -:math:`\BLOCK~\X{bt}` :math:`\hex{02}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\LOOP~\X{bt}` :math:`\hex{03}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\IF~\X{bt}` :math:`\hex{04}` :math:`[t_1^\ast~\I32] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\ELSE` :math:`\hex{05}` -(reserved) :math:`\hex{06}` -(reserved) :math:`\hex{07}` -(reserved) :math:`\hex{08}` -(reserved) :math:`\hex{09}` -(reserved) :math:`\hex{0A}` -:math:`\END` :math:`\hex{0B}` -:math:`\BR~l` :math:`\hex{0C}` :math:`[t_1^\ast~t^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\BRIF~l` :math:`\hex{0D}` :math:`[t^\ast~\I32] \to [t^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\BRTABLE~l^\ast~l` :math:`\hex{0E}` :math:`[t_1^\ast~t^\ast~\I32] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\RETURN` :math:`\hex{0F}` :math:`[t_1^\ast~t^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\CALL~x` :math:`\hex{10}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\CALLINDIRECT~x~y` :math:`\hex{11}` :math:`[t_1^\ast~\I32] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -(reserved) :math:`\hex{12}` -(reserved) :math:`\hex{13}` -(reserved) :math:`\hex{14}` -(reserved) :math:`\hex{15}` -(reserved) :math:`\hex{16}` -(reserved) :math:`\hex{17}` -(reserved) :math:`\hex{18}` -(reserved) :math:`\hex{19}` -:math:`\DROP` :math:`\hex{1A}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` -:math:`\SELECT` :math:`\hex{1B}` :math:`[t~t~\I32] \to [t]` :ref:`validation ` :ref:`execution ` -:math:`\SELECT~t` :math:`\hex{1C}` :math:`[t~t~\I32] \to [t]` :ref:`validation ` :ref:`execution ` -(reserved) :math:`\hex{1D}` -(reserved) :math:`\hex{1E}` -(reserved) :math:`\hex{1F}` -:math:`\LOCALGET~x` :math:`\hex{20}` :math:`[] \to [t]` :ref:`validation ` :ref:`execution ` -:math:`\LOCALSET~x` :math:`\hex{21}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` -:math:`\LOCALTEE~x` :math:`\hex{22}` :math:`[t] \to [t]` :ref:`validation ` :ref:`execution ` -:math:`\GLOBALGET~x` :math:`\hex{23}` :math:`[] \to [t]` :ref:`validation ` :ref:`execution ` -:math:`\GLOBALSET~x` :math:`\hex{24}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` -:math:`\TABLEGET~x` :math:`\hex{25}` :math:`[\I32] \to [t]` :ref:`validation ` :ref:`execution ` -:math:`\TABLESET~x` :math:`\hex{26}` :math:`[\I32~t] \to []` :ref:`validation ` :ref:`execution ` -(reserved) :math:`\hex{27}` -:math:`\I32.\LOAD~\memarg` :math:`\hex{28}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD~\memarg` :math:`\hex{29}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\F32.\LOAD~\memarg` :math:`\hex{2A}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution ` -:math:`\F64.\LOAD~\memarg` :math:`\hex{2B}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\LOAD\K{8\_s}~\memarg` :math:`\hex{2C}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\LOAD\K{8\_u}~\memarg` :math:`\hex{2D}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\LOAD\K{16\_s}~\memarg` :math:`\hex{2E}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\LOAD\K{16\_u}~\memarg` :math:`\hex{2F}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{8\_s}~\memarg` :math:`\hex{30}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{8\_u}~\memarg` :math:`\hex{31}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{16\_s}~\memarg` :math:`\hex{32}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{16\_u}~\memarg` :math:`\hex{33}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{32\_s}~\memarg` :math:`\hex{34}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{32\_u}~\memarg` :math:`\hex{35}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\STORE~\memarg` :math:`\hex{36}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I64.\STORE~\memarg` :math:`\hex{37}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` -:math:`\F32.\STORE~\memarg` :math:`\hex{38}` :math:`[\I32~\F32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\F64.\STORE~\memarg` :math:`\hex{39}` :math:`[\I32~\F64] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I32.\STORE\K{8}~\memarg` :math:`\hex{3A}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I32.\STORE\K{16}~\memarg` :math:`\hex{3B}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I64.\STORE\K{8}~\memarg` :math:`\hex{3C}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I64.\STORE\K{16}~\memarg` :math:`\hex{3D}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I64.\STORE\K{32}~\memarg` :math:`\hex{3E}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` -:math:`\MEMORYSIZE` :math:`\hex{3F}` :math:`[] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\MEMORYGROW` :math:`\hex{40}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\CONST~\i32` :math:`\hex{41}` :math:`[] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\CONST~\i64` :math:`\hex{42}` :math:`[] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\F32.\CONST~\f32` :math:`\hex{43}` :math:`[] \to [\F32]` :ref:`validation ` :ref:`execution ` -:math:`\F64.\CONST~\f64` :math:`\hex{44}` :math:`[] \to [\F64]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\EQZ` :math:`\hex{45}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\EQ` :math:`\hex{46}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\NE` :math:`\hex{47}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\LT\K{\_s}` :math:`\hex{48}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\LT\K{\_u}` :math:`\hex{49}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\GT\K{\_s}` :math:`\hex{4A}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\GT\K{\_u}` :math:`\hex{4B}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\LE\K{\_s}` :math:`\hex{4C}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\LE\K{\_u}` :math:`\hex{4D}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\GE\K{\_s}` :math:`\hex{4E}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\GE\K{\_u}` :math:`\hex{4F}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EQZ` :math:`\hex{50}` :math:`[\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EQ` :math:`\hex{51}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\NE` :math:`\hex{52}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\LT\K{\_s}` :math:`\hex{53}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\LT\K{\_u}` :math:`\hex{54}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\GT\K{\_s}` :math:`\hex{55}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\GT\K{\_u}` :math:`\hex{56}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\LE\K{\_s}` :math:`\hex{57}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\LE\K{\_u}` :math:`\hex{58}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\GE\K{\_s}` :math:`\hex{59}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\GE\K{\_u}` :math:`\hex{5A}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\EQ` :math:`\hex{5B}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\NE` :math:`\hex{5C}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\LT` :math:`\hex{5D}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\GT` :math:`\hex{5E}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\LE` :math:`\hex{5F}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\GE` :math:`\hex{60}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\EQ` :math:`\hex{61}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\NE` :math:`\hex{62}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\LT` :math:`\hex{63}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\GT` :math:`\hex{64}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\LE` :math:`\hex{65}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\GE` :math:`\hex{66}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\CLZ` :math:`\hex{67}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\CTZ` :math:`\hex{68}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\POPCNT` :math:`\hex{69}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\ADD` :math:`\hex{6A}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\SUB` :math:`\hex{6B}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\MUL` :math:`\hex{6C}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\DIV\K{\_s}` :math:`\hex{6D}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\DIV\K{\_u}` :math:`\hex{6E}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\REM\K{\_s}` :math:`\hex{6F}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\REM\K{\_u}` :math:`\hex{70}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\AND` :math:`\hex{71}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\OR` :math:`\hex{72}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\XOR` :math:`\hex{73}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\SHL` :math:`\hex{74}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\SHR\K{\_s}` :math:`\hex{75}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\SHR\K{\_u}` :math:`\hex{76}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\ROTL` :math:`\hex{77}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\ROTR` :math:`\hex{78}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\CLZ` :math:`\hex{79}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\CTZ` :math:`\hex{7A}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\POPCNT` :math:`\hex{7B}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\ADD` :math:`\hex{7C}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\SUB` :math:`\hex{7D}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\MUL` :math:`\hex{7E}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\DIV\K{\_s}` :math:`\hex{7F}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\DIV\K{\_u}` :math:`\hex{80}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\REM\K{\_s}` :math:`\hex{81}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\REM\K{\_u}` :math:`\hex{82}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\AND` :math:`\hex{83}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\OR` :math:`\hex{84}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\XOR` :math:`\hex{85}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\SHL` :math:`\hex{86}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\SHR\K{\_s}` :math:`\hex{87}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\SHR\K{\_u}` :math:`\hex{88}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\ROTL` :math:`\hex{89}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\ROTR` :math:`\hex{8A}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\ABS` :math:`\hex{8B}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\NEG` :math:`\hex{8C}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\CEIL` :math:`\hex{8D}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\FLOOR` :math:`\hex{8E}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\TRUNC` :math:`\hex{8F}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\NEAREST` :math:`\hex{90}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\SQRT` :math:`\hex{91}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\ADD` :math:`\hex{92}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\SUB` :math:`\hex{93}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\MUL` :math:`\hex{94}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\DIV` :math:`\hex{95}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\FMIN` :math:`\hex{96}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\FMAX` :math:`\hex{97}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\COPYSIGN` :math:`\hex{98}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\ABS` :math:`\hex{99}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\NEG` :math:`\hex{9A}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\CEIL` :math:`\hex{9B}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\FLOOR` :math:`\hex{9C}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\TRUNC` :math:`\hex{9D}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\NEAREST` :math:`\hex{9E}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\SQRT` :math:`\hex{9F}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\ADD` :math:`\hex{A0}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\SUB` :math:`\hex{A1}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\MUL` :math:`\hex{A2}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\DIV` :math:`\hex{A3}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\FMIN` :math:`\hex{A4}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\FMAX` :math:`\hex{A5}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\COPYSIGN` :math:`\hex{A6}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\WRAP\K{\_}\I64` :math:`\hex{A7}` :math:`[\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_}\F32\K{\_s}` :math:`\hex{A8}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_}\F32\K{\_u}` :math:`\hex{A9}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_}\F64\K{\_s}` :math:`\hex{AA}` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_}\F64\K{\_u}` :math:`\hex{AB}` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EXTEND\K{\_}\I32\K{\_s}` :math:`\hex{AC}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EXTEND\K{\_}\I32\K{\_u}` :math:`\hex{AD}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_}\F32\K{\_s}` :math:`\hex{AE}` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_}\F32\K{\_u}` :math:`\hex{AF}` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_}\F64\K{\_s}` :math:`\hex{B0}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_}\F64\K{\_u}` :math:`\hex{B1}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\CONVERT\K{\_}\I32\K{\_s}` :math:`\hex{B2}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\CONVERT\K{\_}\I32\K{\_u}` :math:`\hex{B3}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\CONVERT\K{\_}\I64\K{\_s}` :math:`\hex{B4}` :math:`[\I64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\CONVERT\K{\_}\I64\K{\_u}` :math:`\hex{B5}` :math:`[\I64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\DEMOTE\K{\_}\F64` :math:`\hex{B6}` :math:`[\F64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\CONVERT\K{\_}\I32\K{\_s}` :math:`\hex{B7}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\CONVERT\K{\_}\I32\K{\_u}` :math:`\hex{B8}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\CONVERT\K{\_}\I64\K{\_s}` :math:`\hex{B9}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\CONVERT\K{\_}\I64\K{\_u}` :math:`\hex{BA}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\PROMOTE\K{\_}\F32` :math:`\hex{BB}` :math:`[\F32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\REINTERPRET\K{\_}\F32` :math:`\hex{BC}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\REINTERPRET\K{\_}\F64` :math:`\hex{BD}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\REINTERPRET\K{\_}\I32` :math:`\hex{BE}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\REINTERPRET\K{\_}\I64` :math:`\hex{BF}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\EXTEND\K{8\_s}` :math:`\hex{C0}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\EXTEND\K{16\_s}` :math:`\hex{C1}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EXTEND\K{8\_s}` :math:`\hex{C2}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EXTEND\K{16\_s}` :math:`\hex{C3}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EXTEND\K{32\_s}` :math:`\hex{C4}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -(reserved) :math:`\hex{C5}` -(reserved) :math:`\hex{C6}` -(reserved) :math:`\hex{C7}` -(reserved) :math:`\hex{C8}` -(reserved) :math:`\hex{C9}` -(reserved) :math:`\hex{CA}` -(reserved) :math:`\hex{CB}` -(reserved) :math:`\hex{CC}` -(reserved) :math:`\hex{CD}` -(reserved) :math:`\hex{CE}` -(reserved) :math:`\hex{CF}` -:math:`\REFNULL~t` :math:`\hex{D0}` :math:`[] \to [t]` :ref:`validation ` :ref:`execution ` -:math:`\REFISNULL` :math:`\hex{D1}` :math:`[t] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\REFFUNC~x` :math:`\hex{D2}` :math:`[] \to [\FUNCREF]` :ref:`validation ` :ref:`execution ` -(reserved) :math:`\hex{D3}` -(reserved) :math:`\hex{D4}` -(reserved) :math:`\hex{D5}` -(reserved) :math:`\hex{D6}` -(reserved) :math:`\hex{D7}` -(reserved) :math:`\hex{D8}` -(reserved) :math:`\hex{D9}` -(reserved) :math:`\hex{DA}` -(reserved) :math:`\hex{DB}` -(reserved) :math:`\hex{DC}` -(reserved) :math:`\hex{DD}` -(reserved) :math:`\hex{DE}` -(reserved) :math:`\hex{DF}` -(reserved) :math:`\hex{E0}` -(reserved) :math:`\hex{E1}` -(reserved) :math:`\hex{E2}` -(reserved) :math:`\hex{E3}` -(reserved) :math:`\hex{E4}` -(reserved) :math:`\hex{E5}` -(reserved) :math:`\hex{E6}` -(reserved) :math:`\hex{E7}` -(reserved) :math:`\hex{E8}` -(reserved) :math:`\hex{E9}` -(reserved) :math:`\hex{EA}` -(reserved) :math:`\hex{EB}` -(reserved) :math:`\hex{EC}` -(reserved) :math:`\hex{ED}` -(reserved) :math:`\hex{EE}` -(reserved) :math:`\hex{EF}` -(reserved) :math:`\hex{F0}` -(reserved) :math:`\hex{F1}` -(reserved) :math:`\hex{F2}` -(reserved) :math:`\hex{F3}` -(reserved) :math:`\hex{F4}` -(reserved) :math:`\hex{F5}` -(reserved) :math:`\hex{F6}` -(reserved) :math:`\hex{F7}` -(reserved) :math:`\hex{F8}` -(reserved) :math:`\hex{F9}` -(reserved) :math:`\hex{FA}` -(reserved) :math:`\hex{FB}` -:math:`\I32.\TRUNC\K{\_sat\_}\F32\K{\_s}` :math:`\hex{FC}~\hex{00}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_sat\_}\F32\K{\_u}` :math:`\hex{FC}~\hex{01}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_sat\_}\F64\K{\_s}` :math:`\hex{FC}~\hex{02}` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_sat\_}\F64\K{\_u}` :math:`\hex{FC}~\hex{03}` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_sat\_}\F32\K{\_s}` :math:`\hex{FC}~\hex{04}` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_sat\_}\F32\K{\_u}` :math:`\hex{FC}~\hex{05}` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_sat\_}\F64\K{\_s}` :math:`\hex{FC}~\hex{06}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_sat\_}\F64\K{\_u}` :math:`\hex{FC}~\hex{07}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\MEMORYINIT~x` :math:`\hex{FC}~\hex{08}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\DATADROP~x` :math:`\hex{FC}~\hex{09}` :math:`[] \to []` :ref:`validation ` :ref:`execution ` -:math:`\MEMORYCOPY` :math:`\hex{FC}~\hex{0A}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\MEMORYFILL` :math:`\hex{FC}~\hex{0B}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\TABLEINIT~x~y` :math:`\hex{FC}~\hex{0C}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\ELEMDROP~x` :math:`\hex{FC}~\hex{0D}` :math:`[] \to []` :ref:`validation ` :ref:`execution ` -:math:`\TABLECOPY~x~y` :math:`\hex{FC}~\hex{0E}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\TABLEGROW~x` :math:`\hex{FC}~\hex{0F}` :math:`[t~\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\TABLESIZE~x` :math:`\hex{FC}~\hex{10}` :math:`[] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\TABLEFILL~x` :math:`\hex{FC}~\hex{11}` :math:`[\I32~t~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD~\memarg` :math:`\hex{FD}~~\hex{00}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{8x8\_s}~\memarg` :math:`\hex{FD}~~\hex{01}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{8x8\_u}~\memarg` :math:`\hex{FD}~~\hex{02}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{16x4\_s}~\memarg` :math:`\hex{FD}~~\hex{03}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{16x4\_u}~\memarg` :math:`\hex{FD}~~\hex{04}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{32x2\_s}~\memarg` :math:`\hex{FD}~~\hex{05}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{32x2\_u}~\memarg` :math:`\hex{FD}~~\hex{06}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{8\_splat}~\memarg` :math:`\hex{FD}~~\hex{07}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{16\_splat}~\memarg` :math:`\hex{FD}~~\hex{08}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{32\_splat}~\memarg` :math:`\hex{FD}~~\hex{09}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{64\_splat}~\memarg` :math:`\hex{FD}~~\hex{0A}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\STORE~\memarg` :math:`\hex{FD}~~\hex{0B}` :math:`[\I32~\V128] \to []` :ref:`validation ` :ref:`execution ` -:math:`\V128.\VCONST~\i128` :math:`\hex{FD}~~\hex{0C}` :math:`[] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I8X16.\SHUFFLE~\laneidx^{16}` :math:`\hex{FD}~~\hex{0D}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I8X16.\SWIZZLE` :math:`\hex{FD}~~\hex{0E}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I8X16.\SPLAT` :math:`\hex{FD}~~\hex{0F}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\SPLAT` :math:`\hex{FD}~~\hex{10}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\SPLAT` :math:`\hex{FD}~~\hex{11}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I64X2.\SPLAT` :math:`\hex{FD}~~\hex{12}` :math:`[\I64] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\F32X4.\SPLAT` :math:`\hex{FD}~~\hex{13}` :math:`[\F32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\F64X2.\SPLAT` :math:`\hex{FD}~~\hex{14}` :math:`[\F64] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I8X16.\EXTRACTLANE\K{\_s}~\laneidx` :math:`\hex{FD}~~\hex{15}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I8X16.\EXTRACTLANE\K{\_u}~\laneidx` :math:`\hex{FD}~~\hex{16}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I8X16.\REPLACELANE~\laneidx` :math:`\hex{FD}~~\hex{17}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\EXTRACTLANE\K{\_s}~\laneidx` :math:`\hex{FD}~~\hex{18}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\EXTRACTLANE\K{\_u}~\laneidx` :math:`\hex{FD}~~\hex{19}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\REPLACELANE~\laneidx` :math:`\hex{FD}~~\hex{1A}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\EXTRACTLANE~\laneidx` :math:`\hex{FD}~~\hex{1B}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\REPLACELANE~\laneidx` :math:`\hex{FD}~~\hex{1C}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I64X2.\EXTRACTLANE~\laneidx` :math:`\hex{FD}~~\hex{1D}` :math:`[\V128] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64X2.\REPLACELANE~\laneidx` :math:`\hex{FD}~~\hex{1E}` :math:`[\V128~\I64] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\F32X4.\EXTRACTLANE~\laneidx` :math:`\hex{FD}~~\hex{1F}` :math:`[\V128] \to [\F32]` :ref:`validation ` :ref:`execution ` -:math:`\F32X4.\REPLACELANE~\laneidx` :math:`\hex{FD}~~\hex{20}` :math:`[\V128~\F32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\F64X2.\EXTRACTLANE~\laneidx` :math:`\hex{FD}~~\hex{21}` :math:`[\V128] \to [\F64]` :ref:`validation ` :ref:`execution ` -:math:`\F64X2.\REPLACELANE~\laneidx` :math:`\hex{FD}~~\hex{22}` :math:`[\V128~\F64] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I8X16.\VEQ` :math:`\hex{FD}~~\hex{23}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VNE` :math:`\hex{FD}~~\hex{24}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VLT\K{\_s}` :math:`\hex{FD}~~\hex{25}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VLT\K{\_u}` :math:`\hex{FD}~~\hex{26}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VGT\K{\_s}` :math:`\hex{FD}~~\hex{27}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VGT\K{\_u}` :math:`\hex{FD}~~\hex{28}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VLE\K{\_s}` :math:`\hex{FD}~~\hex{29}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VLE\K{\_u}` :math:`\hex{FD}~~\hex{2A}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VGE\K{\_s}` :math:`\hex{FD}~~\hex{2B}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VGE\K{\_u}` :math:`\hex{FD}~~\hex{2C}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VEQ` :math:`\hex{FD}~~\hex{2D}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VNE` :math:`\hex{FD}~~\hex{2E}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VLT\K{\_s}` :math:`\hex{FD}~~\hex{2F}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VLT\K{\_u}` :math:`\hex{FD}~~\hex{30}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VGT\K{\_s}` :math:`\hex{FD}~~\hex{31}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VGT\K{\_u}` :math:`\hex{FD}~~\hex{32}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VLE\K{\_s}` :math:`\hex{FD}~~\hex{33}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VLE\K{\_u}` :math:`\hex{FD}~~\hex{34}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VGE\K{\_s}` :math:`\hex{FD}~~\hex{35}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VGE\K{\_u}` :math:`\hex{FD}~~\hex{36}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VEQ` :math:`\hex{FD}~~\hex{37}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VNE` :math:`\hex{FD}~~\hex{38}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VLT\K{\_s}` :math:`\hex{FD}~~\hex{39}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VLT\K{\_u}` :math:`\hex{FD}~~\hex{3A}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VGT\K{\_s}` :math:`\hex{FD}~~\hex{3B}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VGT\K{\_u}` :math:`\hex{FD}~~\hex{3C}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VLE\K{\_s}` :math:`\hex{FD}~~\hex{3D}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VLE\K{\_u}` :math:`\hex{FD}~~\hex{3E}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VGE\K{\_s}` :math:`\hex{FD}~~\hex{3F}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VGE\K{\_u}` :math:`\hex{FD}~~\hex{40}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VEQ` :math:`\hex{FD}~~\hex{41}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VNE` :math:`\hex{FD}~~\hex{42}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VLT` :math:`\hex{FD}~~\hex{43}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VGT` :math:`\hex{FD}~~\hex{44}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VLE` :math:`\hex{FD}~~\hex{45}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VGE` :math:`\hex{FD}~~\hex{46}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VEQ` :math:`\hex{FD}~~\hex{47}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VNE` :math:`\hex{FD}~~\hex{48}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VLT` :math:`\hex{FD}~~\hex{49}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VGT` :math:`\hex{FD}~~\hex{4A}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VLE` :math:`\hex{FD}~~\hex{4B}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VGE` :math:`\hex{FD}~~\hex{4C}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\V128.\VNOT` :math:`\hex{FD}~~\hex{4D}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\V128.\VAND` :math:`\hex{FD}~~\hex{4E}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\V128.\VANDNOT` :math:`\hex{FD}~~\hex{4F}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\V128.\VOR` :math:`\hex{FD}~~\hex{50}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\V128.\VXOR` :math:`\hex{FD}~~\hex{51}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\V128.\BITSELECT` :math:`\hex{FD}~~\hex{52}` :math:`[\V128~\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\V128.\ANYTRUE` :math:`\hex{FD}~~\hex{53}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{8\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{54}` :math:`[\I32~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{16\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{55}` :math:`[\I32~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{32\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{56}` :math:`[\I32~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{64\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{57}` :math:`[\I32~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\STORE\K{8\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{58}` :math:`[\I32~\V128] \to []` :ref:`validation ` :ref:`execution ` -:math:`\V128.\STORE\K{16\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{59}` :math:`[\I32~\V128] \to []` :ref:`validation ` :ref:`execution ` -:math:`\V128.\STORE\K{32\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{5A}` :math:`[\I32~\V128] \to []` :ref:`validation ` :ref:`execution ` -:math:`\V128.\STORE\K{64\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{5B}` :math:`[\I32~\V128] \to []` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{32\_zero}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{5C}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\LOAD\K{64\_zero}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{5D}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\F32X4.\VDEMOTE\K{\_f64x2\_zero}` :math:`\hex{FD}~~\hex{5E}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VPROMOTE\K{\_low\_f32x4}` :math:`\hex{FD}~~\hex{5F}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VABS` :math:`\hex{FD}~~\hex{60}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VNEG` :math:`\hex{FD}~~\hex{61}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VPOPCNT` :math:`\hex{FD}~~\hex{62}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\ALLTRUE` :math:`\hex{FD}~~\hex{63}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I8X16.\BITMASK` :math:`\hex{FD}~~\hex{64}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I8X16.\NARROW\K{\_i16x8\_s}` :math:`\hex{FD}~~\hex{65}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I8X16.\NARROW\K{\_i16x8\_u}` :math:`\hex{FD}~~\hex{66}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\F32X4.\VCEIL` :math:`\hex{FD}~~\hex{67}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VFLOOR` :math:`\hex{FD}~~\hex{68}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VTRUNC` :math:`\hex{FD}~~\hex{69}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VNEAREST` :math:`\hex{FD}~~\hex{6A}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VSHL` :math:`\hex{FD}~~\hex{6B}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VSHR\K{\_s}` :math:`\hex{FD}~~\hex{6C}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VSHR\K{\_u}` :math:`\hex{FD}~~\hex{6D}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VADD` :math:`\hex{FD}~~\hex{6E}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VADD\K{\_sat\_s}` :math:`\hex{FD}~~\hex{6F}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VADD\K{\_sat\_u}` :math:`\hex{FD}~~\hex{70}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VSUB` :math:`\hex{FD}~~\hex{71}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VSUB\K{\_sat\_s}` :math:`\hex{FD}~~\hex{72}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VSUB\K{\_sat\_u}` :math:`\hex{FD}~~\hex{73}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VCEIL` :math:`\hex{FD}~~\hex{74}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VFLOOR` :math:`\hex{FD}~~\hex{75}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VMIN\K{\_s}` :math:`\hex{FD}~~\hex{76}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VMIN\K{\_u}` :math:`\hex{FD}~~\hex{77}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VMAX\K{\_s}` :math:`\hex{FD}~~\hex{78}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\VMAX\K{\_u}` :math:`\hex{FD}~~\hex{79}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VTRUNC` :math:`\hex{FD}~~\hex{7A}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I8X16.\AVGR\K{\_u}` :math:`\hex{FD}~~\hex{7B}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\EXTADDPAIRWISE\K{\_i8x16\_s}` :math:`\hex{FD}~~\hex{7C}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\EXTADDPAIRWISE\K{\_i8x16\_u}` :math:`\hex{FD}~~\hex{7D}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\EXTADDPAIRWISE\K{\_i16x8\_s}` :math:`\hex{FD}~~\hex{7E}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\EXTADDPAIRWISE\K{\_i16x8\_u}` :math:`\hex{FD}~~\hex{7F}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\VABS` :math:`\hex{FD}~~\hex{80}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VNEG` :math:`\hex{FD}~~\hex{81}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\Q15MULRSAT\K{\_s}` :math:`\hex{FD}~~\hex{82}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\ALLTRUE` :math:`\hex{FD}~~\hex{83}~~\hex{01}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\BITMASK` :math:`\hex{FD}~~\hex{84}~~\hex{01}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\NARROW\K{\_i32x4\_s}` :math:`\hex{FD}~~\hex{85}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\NARROW\K{\_i32x4\_u}` :math:`\hex{FD}~~\hex{86}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\VEXTEND\K{\_low\_i8x16\_s}` :math:`\hex{FD}~~\hex{87}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\VEXTEND\K{\_high\_i8x16\_s}` :math:`\hex{FD}~~\hex{88}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\VEXTEND\K{\_low\_i8x16\_u}` :math:`\hex{FD}~~\hex{89}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\VEXTEND\K{\_high\_i8x16\_u}` :math:`\hex{FD}~~\hex{8A}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\VSHL` :math:`\hex{FD}~~\hex{8B}~~\hex{01}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VSHR\K{\_s}` :math:`\hex{FD}~~\hex{8C}~~\hex{01}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VSHR\K{\_u}` :math:`\hex{FD}~~\hex{8D}~~\hex{01}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VADD` :math:`\hex{FD}~~\hex{8E}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VADD\K{\_sat\_s}` :math:`\hex{FD}~~\hex{8F}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VADD\K{\_sat\_u}` :math:`\hex{FD}~~\hex{90}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VSUB` :math:`\hex{FD}~~\hex{91}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VSUB\K{\_sat\_s}` :math:`\hex{FD}~~\hex{92}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VSUB\K{\_sat\_u}` :math:`\hex{FD}~~\hex{93}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VNEAREST` :math:`\hex{FD}~~\hex{94}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VMUL` :math:`\hex{FD}~~\hex{95}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VMIN\K{\_s}` :math:`\hex{FD}~~\hex{96}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VMIN\K{\_u}` :math:`\hex{FD}~~\hex{97}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VMAX\K{\_s}` :math:`\hex{FD}~~\hex{98}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\VMAX\K{\_u}` :math:`\hex{FD}~~\hex{99}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\AVGR\K{\_u}` :math:`\hex{FD}~~\hex{9B}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I16X8.\EXTMUL\K{\_low\_i8x16\_s}` :math:`\hex{FD}~~\hex{9C}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\EXTMUL\K{\_high\_i8x16\_s}` :math:`\hex{FD}~~\hex{9D}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\EXTMUL\K{\_low\_i8x16\_u}` :math:`\hex{FD}~~\hex{9E}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I16X8.\EXTMUL\K{\_high\_i8x16\_u}` :math:`\hex{FD}~~\hex{9F}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\VABS` :math:`\hex{FD}~~\hex{A0}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VNEG` :math:`\hex{FD}~~\hex{A1}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\ALLTRUE` :math:`\hex{FD}~~\hex{A3}~~\hex{01}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\BITMASK` :math:`\hex{FD}~~\hex{A4}~~\hex{01}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\VEXTEND\K{\_low\_i16x8\_s}` :math:`\hex{FD}~~\hex{A7}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\VEXTEND\K{\_high\_i16x8\_s}` :math:`\hex{FD}~~\hex{A8}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\VEXTEND\K{\_low\_i16x8\_u}` :math:`\hex{FD}~~\hex{A9}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\VEXTEND\K{\_high\_i16x8\_u}` :math:`\hex{FD}~~\hex{AA}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\VSHL` :math:`\hex{FD}~~\hex{AB}~~\hex{01}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VSHR\K{\_s}` :math:`\hex{FD}~~\hex{AC}~~\hex{01}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VSHR\K{\_u}` :math:`\hex{FD}~~\hex{AD}~~\hex{01}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VADD` :math:`\hex{FD}~~\hex{AE}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VSUB` :math:`\hex{FD}~~\hex{B1}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VMUL` :math:`\hex{FD}~~\hex{B5}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VMIN\K{\_s}` :math:`\hex{FD}~~\hex{B6}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VMIN\K{\_u}` :math:`\hex{FD}~~\hex{B7}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VMAX\K{\_s}` :math:`\hex{FD}~~\hex{B8}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VMAX\K{\_u}` :math:`\hex{FD}~~\hex{B9}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\DOT\K{\_i16x8\_s}` :math:`\hex{FD}~~\hex{BA}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\EXTMUL\K{\_low\_i16x8\_s}` :math:`\hex{FD}~~\hex{BC}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\EXTMUL\K{\_high\_i16x8\_s}` :math:`\hex{FD}~~\hex{BD}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\EXTMUL\K{\_low\_i16x8\_u}` :math:`\hex{FD}~~\hex{BE}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I32X4.\EXTMUL\K{\_high\_i16x8\_u}` :math:`\hex{FD}~~\hex{BF}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I64X2.\VABS` :math:`\hex{FD}~~\hex{C0}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64X2.\VNEG` :math:`\hex{FD}~~\hex{C1}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64X2.\ALLTRUE` :math:`\hex{FD}~~\hex{C3}~~\hex{01}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I64X2.\BITMASK` :math:`\hex{FD}~~\hex{C4}~~\hex{01}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I64X2.\VEXTEND\K{\_low\_i32x4\_s}` :math:`\hex{FD}~~\hex{C7}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I64X2.\VEXTEND\K{\_high\_i32x4\_s}` :math:`\hex{FD}~~\hex{C8}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I64X2.\VEXTEND\K{\_low\_i32x4\_u}` :math:`\hex{FD}~~\hex{C9}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I64X2.\VEXTEND\K{\_high\_i32x4\_u}` :math:`\hex{FD}~~\hex{CA}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I64X2.\VSHL` :math:`\hex{FD}~~\hex{CB}~~\hex{01}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64X2.\VSHR\K{\_s}` :math:`\hex{FD}~~\hex{CC}~~\hex{01}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64X2.\VSHR\K{\_u}` :math:`\hex{FD}~~\hex{CD}~~\hex{01}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64X2.\VADD` :math:`\hex{FD}~~\hex{CE}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64X2.\VSUB` :math:`\hex{FD}~~\hex{D1}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64X2.\VMUL` :math:`\hex{FD}~~\hex{D5}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64X2.\VEQ` :math:`\hex{FD}~~\hex{D6}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64X2.\VNE` :math:`\hex{FD}~~\hex{D7}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64X2.\VLT\K{\_s}` :math:`\hex{FD}~~\hex{D8}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64X2.\VGT\K{\_s}` :math:`\hex{FD}~~\hex{D9}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64X2.\VLE\K{\_s}` :math:`\hex{FD}~~\hex{DA}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64X2.\VGE\K{\_s}` :math:`\hex{FD}~~\hex{DB}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64X2.\EXTMUL\K{\_low\_i32x4\_s}` :math:`\hex{FD}~~\hex{DC}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I64X2.\EXTMUL\K{\_high\_i32x4\_s}` :math:`\hex{FD}~~\hex{DD}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I64X2.\EXTMUL\K{\_low\_i32x4\_u}` :math:`\hex{FD}~~\hex{DE}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\I64X2.\EXTMUL\K{\_high\_i32x4\_u}` :math:`\hex{FD}~~\hex{DF}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\F32X4.\VABS` :math:`\hex{FD}~~\hex{E0}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VNEG` :math:`\hex{FD}~~\hex{E1}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VSQRT` :math:`\hex{FD}~~\hex{E3}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VADD` :math:`\hex{FD}~~\hex{E4}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VSUB` :math:`\hex{FD}~~\hex{E5}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VMUL` :math:`\hex{FD}~~\hex{E6}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VDIV` :math:`\hex{FD}~~\hex{E7}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VMIN` :math:`\hex{FD}~~\hex{E8}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VMAX` :math:`\hex{FD}~~\hex{E9}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VPMIN` :math:`\hex{FD}~~\hex{EA}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VPMAX` :math:`\hex{FD}~~\hex{EB}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VABS` :math:`\hex{FD}~~\hex{EC}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VNEG` :math:`\hex{FD}~~\hex{ED}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VSQRT` :math:`\hex{FD}~~\hex{EF}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VADD` :math:`\hex{FD}~~\hex{F0}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VSUB` :math:`\hex{FD}~~\hex{F1}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VMUL` :math:`\hex{FD}~~\hex{F2}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VDIV` :math:`\hex{FD}~~\hex{F3}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VMIN` :math:`\hex{FD}~~\hex{F4}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VMAX` :math:`\hex{FD}~~\hex{F5}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VPMIN` :math:`\hex{FD}~~\hex{F6}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VPMAX` :math:`\hex{FD}~~\hex{F7}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\TRUNC\K{\_sat\_f32x4\_s}` :math:`\hex{FD}~~\hex{F8}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\TRUNC\K{\_sat\_f32x4\_u}` :math:`\hex{FD}~~\hex{F9}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VCONVERT\K{\_i32x4\_s}` :math:`\hex{FD}~~\hex{FA}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32X4.\VCONVERT\K{\_i32x4\_u}` :math:`\hex{FD}~~\hex{FB}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VTRUNC\K{\_sat\_f64x2\_s\_zero}` :math:`\hex{FD}~~\hex{FC}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32X4.\VTRUNC\K{\_sat\_f64x2\_u\_zero}` :math:`\hex{FD}~~\hex{FD}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VCONVERT\K{\_low\_i32x4\_s}` :math:`\hex{FD}~~\hex{FE}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64X2.\VCONVERT\K{\_low\_i32x4\_u}` :math:`\hex{FD}~~\hex{FF}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -================================================= ==================================== ============================================= ============================================= ================================================================== +================================================= ==================================== ============================================= =========================================================================== ==================================================================== +Instruction Binary Opcode Type Validation Execution +================================================= ==================================== ============================================= =========================================================================== ==================================================================== +:math:`\UNREACHABLE` :math:`\hex{00}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\NOP` :math:`\hex{01}` :math:`[] \to []` :ref:`validation ` :ref:`execution ` +:math:`\BLOCK~\X{bt}` :math:`\hex{02}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\LOOP~\X{bt}` :math:`\hex{03}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\IF~\X{bt}` :math:`\hex{04}` :math:`[t_1^\ast~\I32] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\ELSE` :math:`\hex{05}` +:math:`\TRY~\X{bt}` :math:`\hex{06}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation `, :ref:`validation ` :ref:`execution `, :ref:`execution ` +:math:`\CATCH~x` :math:`\hex{07}` +:math:`\THROW~x` :math:`\hex{08}` :math:`[t_1^\ast~t_x^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\RETHROW~n` :math:`\hex{09}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +(reserved) :math:`\hex{0A}` +:math:`\END` :math:`\hex{0B}` +:math:`\BR~l` :math:`\hex{0C}` :math:`[t_1^\ast~t^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\BRIF~l` :math:`\hex{0D}` :math:`[t^\ast~\I32] \to [t^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\BRTABLE~l^\ast~l` :math:`\hex{0E}` :math:`[t_1^\ast~t^\ast~\I32] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\RETURN` :math:`\hex{0F}` :math:`[t_1^\ast~t^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\CALL~x` :math:`\hex{10}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\CALLINDIRECT~x~y` :math:`\hex{11}` :math:`[t_1^\ast~\I32] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +(reserved) :math:`\hex{12}` +(reserved) :math:`\hex{13}` +(reserved) :math:`\hex{14}` +(reserved) :math:`\hex{15}` +(reserved) :math:`\hex{16}` +(reserved) :math:`\hex{17}` +:math:`\DELEGATE~l` :math:`\hex{18}` +:math:`\CATCHALL` :math:`\hex{19}` :ref:`validation ` :ref:`execution ` +:math:`\DROP` :math:`\hex{1A}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` +:math:`\SELECT` :math:`\hex{1B}` :math:`[t~t~\I32] \to [t]` :ref:`validation ` :ref:`execution ` +:math:`\SELECT~t` :math:`\hex{1C}` :math:`[t~t~\I32] \to [t]` :ref:`validation ` :ref:`execution ` +(reserved) :math:`\hex{1D}` +(reserved) :math:`\hex{1E}` +(reserved) :math:`\hex{1F}` +:math:`\LOCALGET~x` :math:`\hex{20}` :math:`[] \to [t]` :ref:`validation ` :ref:`execution ` +:math:`\LOCALSET~x` :math:`\hex{21}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` +:math:`\LOCALTEE~x` :math:`\hex{22}` :math:`[t] \to [t]` :ref:`validation ` :ref:`execution ` +:math:`\GLOBALGET~x` :math:`\hex{23}` :math:`[] \to [t]` :ref:`validation ` :ref:`execution ` +:math:`\GLOBALSET~x` :math:`\hex{24}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` +:math:`\TABLEGET~x` :math:`\hex{25}` :math:`[\I32] \to [t]` :ref:`validation ` :ref:`execution ` +:math:`\TABLESET~x` :math:`\hex{26}` :math:`[\I32~t] \to []` :ref:`validation ` :ref:`execution ` +(reserved) :math:`\hex{27}` +:math:`\I32.\LOAD~\memarg` :math:`\hex{28}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD~\memarg` :math:`\hex{29}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\F32.\LOAD~\memarg` :math:`\hex{2A}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution ` +:math:`\F64.\LOAD~\memarg` :math:`\hex{2B}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\LOAD\K{8\_s}~\memarg` :math:`\hex{2C}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\LOAD\K{8\_u}~\memarg` :math:`\hex{2D}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\LOAD\K{16\_s}~\memarg` :math:`\hex{2E}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\LOAD\K{16\_u}~\memarg` :math:`\hex{2F}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD\K{8\_s}~\memarg` :math:`\hex{30}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD\K{8\_u}~\memarg` :math:`\hex{31}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD\K{16\_s}~\memarg` :math:`\hex{32}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD\K{16\_u}~\memarg` :math:`\hex{33}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD\K{32\_s}~\memarg` :math:`\hex{34}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD\K{32\_u}~\memarg` :math:`\hex{35}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\STORE~\memarg` :math:`\hex{36}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\I64.\STORE~\memarg` :math:`\hex{37}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` +:math:`\F32.\STORE~\memarg` :math:`\hex{38}` :math:`[\I32~\F32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\F64.\STORE~\memarg` :math:`\hex{39}` :math:`[\I32~\F64] \to []` :ref:`validation ` :ref:`execution ` +:math:`\I32.\STORE\K{8}~\memarg` :math:`\hex{3A}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\I32.\STORE\K{16}~\memarg` :math:`\hex{3B}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\I64.\STORE\K{8}~\memarg` :math:`\hex{3C}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` +:math:`\I64.\STORE\K{16}~\memarg` :math:`\hex{3D}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` +:math:`\I64.\STORE\K{32}~\memarg` :math:`\hex{3E}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` +:math:`\MEMORYSIZE` :math:`\hex{3F}` :math:`[] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\MEMORYGROW` :math:`\hex{40}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\CONST~\i32` :math:`\hex{41}` :math:`[] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\CONST~\i64` :math:`\hex{42}` :math:`[] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\F32.\CONST~\f32` :math:`\hex{43}` :math:`[] \to [\F32]` :ref:`validation ` :ref:`execution ` +:math:`\F64.\CONST~\f64` :math:`\hex{44}` :math:`[] \to [\F64]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\EQZ` :math:`\hex{45}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\EQ` :math:`\hex{46}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\NE` :math:`\hex{47}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\LT\K{\_s}` :math:`\hex{48}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\LT\K{\_u}` :math:`\hex{49}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\GT\K{\_s}` :math:`\hex{4A}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\GT\K{\_u}` :math:`\hex{4B}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\LE\K{\_s}` :math:`\hex{4C}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\LE\K{\_u}` :math:`\hex{4D}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\GE\K{\_s}` :math:`\hex{4E}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\GE\K{\_u}` :math:`\hex{4F}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EQZ` :math:`\hex{50}` :math:`[\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EQ` :math:`\hex{51}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\NE` :math:`\hex{52}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\LT\K{\_s}` :math:`\hex{53}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\LT\K{\_u}` :math:`\hex{54}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\GT\K{\_s}` :math:`\hex{55}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\GT\K{\_u}` :math:`\hex{56}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\LE\K{\_s}` :math:`\hex{57}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\LE\K{\_u}` :math:`\hex{58}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\GE\K{\_s}` :math:`\hex{59}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\GE\K{\_u}` :math:`\hex{5A}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\EQ` :math:`\hex{5B}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\NE` :math:`\hex{5C}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\LT` :math:`\hex{5D}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\GT` :math:`\hex{5E}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\LE` :math:`\hex{5F}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\GE` :math:`\hex{60}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\EQ` :math:`\hex{61}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\NE` :math:`\hex{62}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\LT` :math:`\hex{63}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\GT` :math:`\hex{64}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\LE` :math:`\hex{65}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\GE` :math:`\hex{66}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\CLZ` :math:`\hex{67}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\CTZ` :math:`\hex{68}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\POPCNT` :math:`\hex{69}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\ADD` :math:`\hex{6A}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\SUB` :math:`\hex{6B}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\MUL` :math:`\hex{6C}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\DIV\K{\_s}` :math:`\hex{6D}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\DIV\K{\_u}` :math:`\hex{6E}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\REM\K{\_s}` :math:`\hex{6F}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\REM\K{\_u}` :math:`\hex{70}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\AND` :math:`\hex{71}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\OR` :math:`\hex{72}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\XOR` :math:`\hex{73}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\SHL` :math:`\hex{74}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\SHR\K{\_s}` :math:`\hex{75}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\SHR\K{\_u}` :math:`\hex{76}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\ROTL` :math:`\hex{77}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\ROTR` :math:`\hex{78}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\CLZ` :math:`\hex{79}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\CTZ` :math:`\hex{7A}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\POPCNT` :math:`\hex{7B}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\ADD` :math:`\hex{7C}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\SUB` :math:`\hex{7D}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\MUL` :math:`\hex{7E}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\DIV\K{\_s}` :math:`\hex{7F}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\DIV\K{\_u}` :math:`\hex{80}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\REM\K{\_s}` :math:`\hex{81}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\REM\K{\_u}` :math:`\hex{82}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\AND` :math:`\hex{83}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\OR` :math:`\hex{84}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\XOR` :math:`\hex{85}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\SHL` :math:`\hex{86}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\SHR\K{\_s}` :math:`\hex{87}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\SHR\K{\_u}` :math:`\hex{88}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\ROTL` :math:`\hex{89}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\ROTR` :math:`\hex{8A}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\ABS` :math:`\hex{8B}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\NEG` :math:`\hex{8C}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\CEIL` :math:`\hex{8D}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\FLOOR` :math:`\hex{8E}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\TRUNC` :math:`\hex{8F}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\NEAREST` :math:`\hex{90}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\SQRT` :math:`\hex{91}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\ADD` :math:`\hex{92}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\SUB` :math:`\hex{93}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\MUL` :math:`\hex{94}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\DIV` :math:`\hex{95}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\FMIN` :math:`\hex{96}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\FMAX` :math:`\hex{97}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\COPYSIGN` :math:`\hex{98}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\ABS` :math:`\hex{99}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\NEG` :math:`\hex{9A}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\CEIL` :math:`\hex{9B}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\FLOOR` :math:`\hex{9C}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\TRUNC` :math:`\hex{9D}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\NEAREST` :math:`\hex{9E}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\SQRT` :math:`\hex{9F}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\ADD` :math:`\hex{A0}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\SUB` :math:`\hex{A1}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\MUL` :math:`\hex{A2}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\DIV` :math:`\hex{A3}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\FMIN` :math:`\hex{A4}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\FMAX` :math:`\hex{A5}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\COPYSIGN` :math:`\hex{A6}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\WRAP\K{\_}\I64` :math:`\hex{A7}` :math:`[\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\TRUNC\K{\_}\F32\K{\_s}` :math:`\hex{A8}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\TRUNC\K{\_}\F32\K{\_u}` :math:`\hex{A9}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\TRUNC\K{\_}\F64\K{\_s}` :math:`\hex{AA}` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\TRUNC\K{\_}\F64\K{\_u}` :math:`\hex{AB}` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EXTEND\K{\_}\I32\K{\_s}` :math:`\hex{AC}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EXTEND\K{\_}\I32\K{\_u}` :math:`\hex{AD}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_}\F32\K{\_s}` :math:`\hex{AE}` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_}\F32\K{\_u}` :math:`\hex{AF}` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_}\F64\K{\_s}` :math:`\hex{B0}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_}\F64\K{\_u}` :math:`\hex{B1}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\CONVERT\K{\_}\I32\K{\_s}` :math:`\hex{B2}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\CONVERT\K{\_}\I32\K{\_u}` :math:`\hex{B3}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\CONVERT\K{\_}\I64\K{\_s}` :math:`\hex{B4}` :math:`[\I64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\CONVERT\K{\_}\I64\K{\_u}` :math:`\hex{B5}` :math:`[\I64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\DEMOTE\K{\_}\F64` :math:`\hex{B6}` :math:`[\F64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\CONVERT\K{\_}\I32\K{\_s}` :math:`\hex{B7}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\CONVERT\K{\_}\I32\K{\_u}` :math:`\hex{B8}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\CONVERT\K{\_}\I64\K{\_s}` :math:`\hex{B9}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\CONVERT\K{\_}\I64\K{\_u}` :math:`\hex{BA}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\PROMOTE\K{\_}\F32` :math:`\hex{BB}` :math:`[\F32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\REINTERPRET\K{\_}\F32` :math:`\hex{BC}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\REINTERPRET\K{\_}\F64` :math:`\hex{BD}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\REINTERPRET\K{\_}\I32` :math:`\hex{BE}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\REINTERPRET\K{\_}\I64` :math:`\hex{BF}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\EXTEND\K{8\_s}` :math:`\hex{C0}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\EXTEND\K{16\_s}` :math:`\hex{C1}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EXTEND\K{8\_s}` :math:`\hex{C2}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EXTEND\K{16\_s}` :math:`\hex{C3}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EXTEND\K{32\_s}` :math:`\hex{C4}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +(reserved) :math:`\hex{C5}` +(reserved) :math:`\hex{C6}` +(reserved) :math:`\hex{C7}` +(reserved) :math:`\hex{C8}` +(reserved) :math:`\hex{C9}` +(reserved) :math:`\hex{CA}` +(reserved) :math:`\hex{CB}` +(reserved) :math:`\hex{CC}` +(reserved) :math:`\hex{CD}` +(reserved) :math:`\hex{CE}` +(reserved) :math:`\hex{CF}` +:math:`\REFNULL~t` :math:`\hex{D0}` :math:`[] \to [t]` :ref:`validation ` :ref:`execution ` +:math:`\REFISNULL` :math:`\hex{D1}` :math:`[t] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\REFFUNC~x` :math:`\hex{D2}` :math:`[] \to [\FUNCREF]` :ref:`validation ` :ref:`execution ` +(reserved) :math:`\hex{D3}` +(reserved) :math:`\hex{D4}` +(reserved) :math:`\hex{D5}` +(reserved) :math:`\hex{D6}` +(reserved) :math:`\hex{D7}` +(reserved) :math:`\hex{D8}` +(reserved) :math:`\hex{D9}` +(reserved) :math:`\hex{DA}` +(reserved) :math:`\hex{DB}` +(reserved) :math:`\hex{DC}` +(reserved) :math:`\hex{DD}` +(reserved) :math:`\hex{DE}` +(reserved) :math:`\hex{DF}` +(reserved) :math:`\hex{E0}` +(reserved) :math:`\hex{E1}` +(reserved) :math:`\hex{E2}` +(reserved) :math:`\hex{E3}` +(reserved) :math:`\hex{E4}` +(reserved) :math:`\hex{E5}` +(reserved) :math:`\hex{E6}` +(reserved) :math:`\hex{E7}` +(reserved) :math:`\hex{E8}` +(reserved) :math:`\hex{E9}` +(reserved) :math:`\hex{EA}` +(reserved) :math:`\hex{EB}` +(reserved) :math:`\hex{EC}` +(reserved) :math:`\hex{ED}` +(reserved) :math:`\hex{EE}` +(reserved) :math:`\hex{EF}` +(reserved) :math:`\hex{F0}` +(reserved) :math:`\hex{F1}` +(reserved) :math:`\hex{F2}` +(reserved) :math:`\hex{F3}` +(reserved) :math:`\hex{F4}` +(reserved) :math:`\hex{F5}` +(reserved) :math:`\hex{F6}` +(reserved) :math:`\hex{F7}` +(reserved) :math:`\hex{F8}` +(reserved) :math:`\hex{F9}` +(reserved) :math:`\hex{FA}` +(reserved) :math:`\hex{FB}` +:math:`\I32.\TRUNC\K{\_sat\_}\F32\K{\_s}` :math:`\hex{FC}~\hex{00}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\TRUNC\K{\_sat\_}\F32\K{\_u}` :math:`\hex{FC}~\hex{01}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\TRUNC\K{\_sat\_}\F64\K{\_s}` :math:`\hex{FC}~\hex{02}` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\TRUNC\K{\_sat\_}\F64\K{\_u}` :math:`\hex{FC}~\hex{03}` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_sat\_}\F32\K{\_s}` :math:`\hex{FC}~\hex{04}` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_sat\_}\F32\K{\_u}` :math:`\hex{FC}~\hex{05}` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_sat\_}\F64\K{\_s}` :math:`\hex{FC}~\hex{06}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_sat\_}\F64\K{\_u}` :math:`\hex{FC}~\hex{07}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\MEMORYINIT~x` :math:`\hex{FC}~\hex{08}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\DATADROP~x` :math:`\hex{FC}~\hex{09}` :math:`[] \to []` :ref:`validation ` :ref:`execution ` +:math:`\MEMORYCOPY` :math:`\hex{FC}~\hex{0A}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\MEMORYFILL` :math:`\hex{FC}~\hex{0B}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\TABLEINIT~x~y` :math:`\hex{FC}~\hex{0C}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\ELEMDROP~x` :math:`\hex{FC}~\hex{0D}` :math:`[] \to []` :ref:`validation ` :ref:`execution ` +:math:`\TABLECOPY~x~y` :math:`\hex{FC}~\hex{0E}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\TABLEGROW~x` :math:`\hex{FC}~\hex{0F}` :math:`[t~\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\TABLESIZE~x` :math:`\hex{FC}~\hex{10}` :math:`[] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\TABLEFILL~x` :math:`\hex{FC}~\hex{11}` :math:`[\I32~t~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\V128.\LOAD~\memarg` :math:`\hex{FD}~~\hex{00}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\V128.\LOAD\K{8x8\_s}~\memarg` :math:`\hex{FD}~~\hex{01}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\V128.\LOAD\K{8x8\_u}~\memarg` :math:`\hex{FD}~~\hex{02}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\V128.\LOAD\K{16x4\_s}~\memarg` :math:`\hex{FD}~~\hex{03}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\V128.\LOAD\K{16x4\_u}~\memarg` :math:`\hex{FD}~~\hex{04}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\V128.\LOAD\K{32x2\_s}~\memarg` :math:`\hex{FD}~~\hex{05}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\V128.\LOAD\K{32x2\_u}~\memarg` :math:`\hex{FD}~~\hex{06}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\V128.\LOAD\K{8\_splat}~\memarg` :math:`\hex{FD}~~\hex{07}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\V128.\LOAD\K{16\_splat}~\memarg` :math:`\hex{FD}~~\hex{08}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\V128.\LOAD\K{32\_splat}~\memarg` :math:`\hex{FD}~~\hex{09}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\V128.\LOAD\K{64\_splat}~\memarg` :math:`\hex{FD}~~\hex{0A}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\V128.\STORE~\memarg` :math:`\hex{FD}~~\hex{0B}` :math:`[\I32~\V128] \to []` :ref:`validation ` :ref:`execution ` +:math:`\V128.\VCONST~\i128` :math:`\hex{FD}~~\hex{0C}` :math:`[] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\I8X16.\SHUFFLE~\laneidx^{16}` :math:`\hex{FD}~~\hex{0D}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\I8X16.\SWIZZLE` :math:`\hex{FD}~~\hex{0E}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\I8X16.\SPLAT` :math:`\hex{FD}~~\hex{0F}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\I16X8.\SPLAT` :math:`\hex{FD}~~\hex{10}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\I32X4.\SPLAT` :math:`\hex{FD}~~\hex{11}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\I64X2.\SPLAT` :math:`\hex{FD}~~\hex{12}` :math:`[\I64] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\F32X4.\SPLAT` :math:`\hex{FD}~~\hex{13}` :math:`[\F32] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\F64X2.\SPLAT` :math:`\hex{FD}~~\hex{14}` :math:`[\F64] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\I8X16.\EXTRACTLANE\K{\_s}~\laneidx` :math:`\hex{FD}~~\hex{15}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I8X16.\EXTRACTLANE\K{\_u}~\laneidx` :math:`\hex{FD}~~\hex{16}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I8X16.\REPLACELANE~\laneidx` :math:`\hex{FD}~~\hex{17}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\I16X8.\EXTRACTLANE\K{\_s}~\laneidx` :math:`\hex{FD}~~\hex{18}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I16X8.\EXTRACTLANE\K{\_u}~\laneidx` :math:`\hex{FD}~~\hex{19}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I16X8.\REPLACELANE~\laneidx` :math:`\hex{FD}~~\hex{1A}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\I32X4.\EXTRACTLANE~\laneidx` :math:`\hex{FD}~~\hex{1B}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I32X4.\REPLACELANE~\laneidx` :math:`\hex{FD}~~\hex{1C}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\I64X2.\EXTRACTLANE~\laneidx` :math:`\hex{FD}~~\hex{1D}` :math:`[\V128] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I64X2.\REPLACELANE~\laneidx` :math:`\hex{FD}~~\hex{1E}` :math:`[\V128~\I64] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\F32X4.\EXTRACTLANE~\laneidx` :math:`\hex{FD}~~\hex{1F}` :math:`[\V128] \to [\F32]` :ref:`validation ` :ref:`execution ` +:math:`\F32X4.\REPLACELANE~\laneidx` :math:`\hex{FD}~~\hex{20}` :math:`[\V128~\F32] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\F64X2.\EXTRACTLANE~\laneidx` :math:`\hex{FD}~~\hex{21}` :math:`[\V128] \to [\F64]` :ref:`validation ` :ref:`execution ` +:math:`\F64X2.\REPLACELANE~\laneidx` :math:`\hex{FD}~~\hex{22}` :math:`[\V128~\F64] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\I8X16.\VEQ` :math:`\hex{FD}~~\hex{23}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I8X16.\VNE` :math:`\hex{FD}~~\hex{24}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I8X16.\VLT\K{\_s}` :math:`\hex{FD}~~\hex{25}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I8X16.\VLT\K{\_u}` :math:`\hex{FD}~~\hex{26}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I8X16.\VGT\K{\_s}` :math:`\hex{FD}~~\hex{27}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I8X16.\VGT\K{\_u}` :math:`\hex{FD}~~\hex{28}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I8X16.\VLE\K{\_s}` :math:`\hex{FD}~~\hex{29}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I8X16.\VLE\K{\_u}` :math:`\hex{FD}~~\hex{2A}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I8X16.\VGE\K{\_s}` :math:`\hex{FD}~~\hex{2B}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I8X16.\VGE\K{\_u}` :math:`\hex{FD}~~\hex{2C}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I16X8.\VEQ` :math:`\hex{FD}~~\hex{2D}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I16X8.\VNE` :math:`\hex{FD}~~\hex{2E}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I16X8.\VLT\K{\_s}` :math:`\hex{FD}~~\hex{2F}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I16X8.\VLT\K{\_u}` :math:`\hex{FD}~~\hex{30}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I16X8.\VGT\K{\_s}` :math:`\hex{FD}~~\hex{31}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I16X8.\VGT\K{\_u}` :math:`\hex{FD}~~\hex{32}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I16X8.\VLE\K{\_s}` :math:`\hex{FD}~~\hex{33}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I16X8.\VLE\K{\_u}` :math:`\hex{FD}~~\hex{34}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I16X8.\VGE\K{\_s}` :math:`\hex{FD}~~\hex{35}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I16X8.\VGE\K{\_u}` :math:`\hex{FD}~~\hex{36}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32X4.\VEQ` :math:`\hex{FD}~~\hex{37}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32X4.\VNE` :math:`\hex{FD}~~\hex{38}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32X4.\VLT\K{\_s}` :math:`\hex{FD}~~\hex{39}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32X4.\VLT\K{\_u}` :math:`\hex{FD}~~\hex{3A}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32X4.\VGT\K{\_s}` :math:`\hex{FD}~~\hex{3B}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32X4.\VGT\K{\_u}` :math:`\hex{FD}~~\hex{3C}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32X4.\VLE\K{\_s}` :math:`\hex{FD}~~\hex{3D}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32X4.\VLE\K{\_u}` :math:`\hex{FD}~~\hex{3E}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32X4.\VGE\K{\_s}` :math:`\hex{FD}~~\hex{3F}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32X4.\VGE\K{\_u}` :math:`\hex{FD}~~\hex{40}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32X4.\VEQ` :math:`\hex{FD}~~\hex{41}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32X4.\VNE` :math:`\hex{FD}~~\hex{42}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32X4.\VLT` :math:`\hex{FD}~~\hex{43}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32X4.\VGT` :math:`\hex{FD}~~\hex{44}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32X4.\VLE` :math:`\hex{FD}~~\hex{45}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32X4.\VGE` :math:`\hex{FD}~~\hex{46}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64X2.\VEQ` :math:`\hex{FD}~~\hex{47}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64X2.\VNE` :math:`\hex{FD}~~\hex{48}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64X2.\VLT` :math:`\hex{FD}~~\hex{49}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64X2.\VGT` :math:`\hex{FD}~~\hex{4A}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64X2.\VLE` :math:`\hex{FD}~~\hex{4B}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64X2.\VGE` :math:`\hex{FD}~~\hex{4C}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\V128.\VNOT` :math:`\hex{FD}~~\hex{4D}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\V128.\VAND` :math:`\hex{FD}~~\hex{4E}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\V128.\VANDNOT` :math:`\hex{FD}~~\hex{4F}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\V128.\VOR` :math:`\hex{FD}~~\hex{50}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\V128.\VXOR` :math:`\hex{FD}~~\hex{51}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\V128.\BITSELECT` :math:`\hex{FD}~~\hex{52}` :math:`[\V128~\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\V128.\ANYTRUE` :math:`\hex{FD}~~\hex{53}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\V128.\LOAD\K{8\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{54}` :math:`[\I32~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\V128.\LOAD\K{16\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{55}` :math:`[\I32~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\V128.\LOAD\K{32\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{56}` :math:`[\I32~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\V128.\LOAD\K{64\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{57}` :math:`[\I32~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\V128.\STORE\K{8\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{58}` :math:`[\I32~\V128] \to []` :ref:`validation ` :ref:`execution ` +:math:`\V128.\STORE\K{16\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{59}` :math:`[\I32~\V128] \to []` :ref:`validation ` :ref:`execution ` +:math:`\V128.\STORE\K{32\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{5A}` :math:`[\I32~\V128] \to []` :ref:`validation ` :ref:`execution ` +:math:`\V128.\STORE\K{64\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{5B}` :math:`[\I32~\V128] \to []` :ref:`validation ` :ref:`execution ` +:math:`\V128.\LOAD\K{32\_zero}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{5C}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\V128.\LOAD\K{64\_zero}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{5D}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\F32X4.\VDEMOTE\K{\_f64x2\_zero}` :math:`\hex{FD}~~\hex{5E}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64X2.\VPROMOTE\K{\_low\_f32x4}` :math:`\hex{FD}~~\hex{5F}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I8X16.\VABS` :math:`\hex{FD}~~\hex{60}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I8X16.\VNEG` :math:`\hex{FD}~~\hex{61}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I8X16.\VPOPCNT` :math:`\hex{FD}~~\hex{62}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I8X16.\ALLTRUE` :math:`\hex{FD}~~\hex{63}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I8X16.\BITMASK` :math:`\hex{FD}~~\hex{64}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I8X16.\NARROW\K{\_i16x8\_s}` :math:`\hex{FD}~~\hex{65}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\I8X16.\NARROW\K{\_i16x8\_u}` :math:`\hex{FD}~~\hex{66}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\F32X4.\VCEIL` :math:`\hex{FD}~~\hex{67}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32X4.\VFLOOR` :math:`\hex{FD}~~\hex{68}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32X4.\VTRUNC` :math:`\hex{FD}~~\hex{69}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32X4.\VNEAREST` :math:`\hex{FD}~~\hex{6A}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I8X16.\VSHL` :math:`\hex{FD}~~\hex{6B}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I8X16.\VSHR\K{\_s}` :math:`\hex{FD}~~\hex{6C}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I8X16.\VSHR\K{\_u}` :math:`\hex{FD}~~\hex{6D}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I8X16.\VADD` :math:`\hex{FD}~~\hex{6E}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I8X16.\VADD\K{\_sat\_s}` :math:`\hex{FD}~~\hex{6F}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I8X16.\VADD\K{\_sat\_u}` :math:`\hex{FD}~~\hex{70}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I8X16.\VSUB` :math:`\hex{FD}~~\hex{71}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I8X16.\VSUB\K{\_sat\_s}` :math:`\hex{FD}~~\hex{72}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I8X16.\VSUB\K{\_sat\_u}` :math:`\hex{FD}~~\hex{73}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64X2.\VCEIL` :math:`\hex{FD}~~\hex{74}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64X2.\VFLOOR` :math:`\hex{FD}~~\hex{75}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I8X16.\VMIN\K{\_s}` :math:`\hex{FD}~~\hex{76}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I8X16.\VMIN\K{\_u}` :math:`\hex{FD}~~\hex{77}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I8X16.\VMAX\K{\_s}` :math:`\hex{FD}~~\hex{78}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I8X16.\VMAX\K{\_u}` :math:`\hex{FD}~~\hex{79}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64X2.\VTRUNC` :math:`\hex{FD}~~\hex{7A}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I8X16.\AVGR\K{\_u}` :math:`\hex{FD}~~\hex{7B}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I16X8.\EXTADDPAIRWISE\K{\_i8x16\_s}` :math:`\hex{FD}~~\hex{7C}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\I16X8.\EXTADDPAIRWISE\K{\_i8x16\_u}` :math:`\hex{FD}~~\hex{7D}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\I32X4.\EXTADDPAIRWISE\K{\_i16x8\_s}` :math:`\hex{FD}~~\hex{7E}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\I32X4.\EXTADDPAIRWISE\K{\_i16x8\_u}` :math:`\hex{FD}~~\hex{7F}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\I16X8.\VABS` :math:`\hex{FD}~~\hex{80}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I16X8.\VNEG` :math:`\hex{FD}~~\hex{81}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I16X8.\Q15MULRSAT\K{\_s}` :math:`\hex{FD}~~\hex{82}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I16X8.\ALLTRUE` :math:`\hex{FD}~~\hex{83}~~\hex{01}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I16X8.\BITMASK` :math:`\hex{FD}~~\hex{84}~~\hex{01}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I16X8.\NARROW\K{\_i32x4\_s}` :math:`\hex{FD}~~\hex{85}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\I16X8.\NARROW\K{\_i32x4\_u}` :math:`\hex{FD}~~\hex{86}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\I16X8.\VEXTEND\K{\_low\_i8x16\_s}` :math:`\hex{FD}~~\hex{87}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\I16X8.\VEXTEND\K{\_high\_i8x16\_s}` :math:`\hex{FD}~~\hex{88}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\I16X8.\VEXTEND\K{\_low\_i8x16\_u}` :math:`\hex{FD}~~\hex{89}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\I16X8.\VEXTEND\K{\_high\_i8x16\_u}` :math:`\hex{FD}~~\hex{8A}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\I16X8.\VSHL` :math:`\hex{FD}~~\hex{8B}~~\hex{01}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I16X8.\VSHR\K{\_s}` :math:`\hex{FD}~~\hex{8C}~~\hex{01}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I16X8.\VSHR\K{\_u}` :math:`\hex{FD}~~\hex{8D}~~\hex{01}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I16X8.\VADD` :math:`\hex{FD}~~\hex{8E}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I16X8.\VADD\K{\_sat\_s}` :math:`\hex{FD}~~\hex{8F}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I16X8.\VADD\K{\_sat\_u}` :math:`\hex{FD}~~\hex{90}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I16X8.\VSUB` :math:`\hex{FD}~~\hex{91}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I16X8.\VSUB\K{\_sat\_s}` :math:`\hex{FD}~~\hex{92}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I16X8.\VSUB\K{\_sat\_u}` :math:`\hex{FD}~~\hex{93}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64X2.\VNEAREST` :math:`\hex{FD}~~\hex{94}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I16X8.\VMUL` :math:`\hex{FD}~~\hex{95}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I16X8.\VMIN\K{\_s}` :math:`\hex{FD}~~\hex{96}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I16X8.\VMIN\K{\_u}` :math:`\hex{FD}~~\hex{97}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I16X8.\VMAX\K{\_s}` :math:`\hex{FD}~~\hex{98}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I16X8.\VMAX\K{\_u}` :math:`\hex{FD}~~\hex{99}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I16X8.\AVGR\K{\_u}` :math:`\hex{FD}~~\hex{9B}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I16X8.\EXTMUL\K{\_low\_i8x16\_s}` :math:`\hex{FD}~~\hex{9C}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\I16X8.\EXTMUL\K{\_high\_i8x16\_s}` :math:`\hex{FD}~~\hex{9D}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\I16X8.\EXTMUL\K{\_low\_i8x16\_u}` :math:`\hex{FD}~~\hex{9E}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\I16X8.\EXTMUL\K{\_high\_i8x16\_u}` :math:`\hex{FD}~~\hex{9F}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\I32X4.\VABS` :math:`\hex{FD}~~\hex{A0}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32X4.\VNEG` :math:`\hex{FD}~~\hex{A1}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32X4.\ALLTRUE` :math:`\hex{FD}~~\hex{A3}~~\hex{01}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I32X4.\BITMASK` :math:`\hex{FD}~~\hex{A4}~~\hex{01}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I32X4.\VEXTEND\K{\_low\_i16x8\_s}` :math:`\hex{FD}~~\hex{A7}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\I32X4.\VEXTEND\K{\_high\_i16x8\_s}` :math:`\hex{FD}~~\hex{A8}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\I32X4.\VEXTEND\K{\_low\_i16x8\_u}` :math:`\hex{FD}~~\hex{A9}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\I32X4.\VEXTEND\K{\_high\_i16x8\_u}` :math:`\hex{FD}~~\hex{AA}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\I32X4.\VSHL` :math:`\hex{FD}~~\hex{AB}~~\hex{01}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32X4.\VSHR\K{\_s}` :math:`\hex{FD}~~\hex{AC}~~\hex{01}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32X4.\VSHR\K{\_u}` :math:`\hex{FD}~~\hex{AD}~~\hex{01}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32X4.\VADD` :math:`\hex{FD}~~\hex{AE}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32X4.\VSUB` :math:`\hex{FD}~~\hex{B1}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32X4.\VMUL` :math:`\hex{FD}~~\hex{B5}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32X4.\VMIN\K{\_s}` :math:`\hex{FD}~~\hex{B6}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32X4.\VMIN\K{\_u}` :math:`\hex{FD}~~\hex{B7}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32X4.\VMAX\K{\_s}` :math:`\hex{FD}~~\hex{B8}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32X4.\VMAX\K{\_u}` :math:`\hex{FD}~~\hex{B9}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32X4.\DOT\K{\_i16x8\_s}` :math:`\hex{FD}~~\hex{BA}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\I32X4.\EXTMUL\K{\_low\_i16x8\_s}` :math:`\hex{FD}~~\hex{BC}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\I32X4.\EXTMUL\K{\_high\_i16x8\_s}` :math:`\hex{FD}~~\hex{BD}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\I32X4.\EXTMUL\K{\_low\_i16x8\_u}` :math:`\hex{FD}~~\hex{BE}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\I32X4.\EXTMUL\K{\_high\_i16x8\_u}` :math:`\hex{FD}~~\hex{BF}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\I64X2.\VABS` :math:`\hex{FD}~~\hex{C0}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64X2.\VNEG` :math:`\hex{FD}~~\hex{C1}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64X2.\ALLTRUE` :math:`\hex{FD}~~\hex{C3}~~\hex{01}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I64X2.\BITMASK` :math:`\hex{FD}~~\hex{C4}~~\hex{01}` :math:`[\V128] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I64X2.\VEXTEND\K{\_low\_i32x4\_s}` :math:`\hex{FD}~~\hex{C7}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\I64X2.\VEXTEND\K{\_high\_i32x4\_s}` :math:`\hex{FD}~~\hex{C8}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\I64X2.\VEXTEND\K{\_low\_i32x4\_u}` :math:`\hex{FD}~~\hex{C9}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\I64X2.\VEXTEND\K{\_high\_i32x4\_u}` :math:`\hex{FD}~~\hex{CA}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\I64X2.\VSHL` :math:`\hex{FD}~~\hex{CB}~~\hex{01}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64X2.\VSHR\K{\_s}` :math:`\hex{FD}~~\hex{CC}~~\hex{01}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64X2.\VSHR\K{\_u}` :math:`\hex{FD}~~\hex{CD}~~\hex{01}` :math:`[\V128~\I32] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64X2.\VADD` :math:`\hex{FD}~~\hex{CE}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64X2.\VSUB` :math:`\hex{FD}~~\hex{D1}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64X2.\VMUL` :math:`\hex{FD}~~\hex{D5}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64X2.\VEQ` :math:`\hex{FD}~~\hex{D6}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64X2.\VNE` :math:`\hex{FD}~~\hex{D7}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64X2.\VLT\K{\_s}` :math:`\hex{FD}~~\hex{D8}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64X2.\VGT\K{\_s}` :math:`\hex{FD}~~\hex{D9}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64X2.\VLE\K{\_s}` :math:`\hex{FD}~~\hex{DA}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64X2.\VGE\K{\_s}` :math:`\hex{FD}~~\hex{DB}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64X2.\EXTMUL\K{\_low\_i32x4\_s}` :math:`\hex{FD}~~\hex{DC}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\I64X2.\EXTMUL\K{\_high\_i32x4\_s}` :math:`\hex{FD}~~\hex{DD}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\I64X2.\EXTMUL\K{\_low\_i32x4\_u}` :math:`\hex{FD}~~\hex{DE}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\I64X2.\EXTMUL\K{\_high\_i32x4\_u}` :math:`\hex{FD}~~\hex{DF}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\F32X4.\VABS` :math:`\hex{FD}~~\hex{E0}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32X4.\VNEG` :math:`\hex{FD}~~\hex{E1}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32X4.\VSQRT` :math:`\hex{FD}~~\hex{E3}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32X4.\VADD` :math:`\hex{FD}~~\hex{E4}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32X4.\VSUB` :math:`\hex{FD}~~\hex{E5}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32X4.\VMUL` :math:`\hex{FD}~~\hex{E6}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32X4.\VDIV` :math:`\hex{FD}~~\hex{E7}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32X4.\VMIN` :math:`\hex{FD}~~\hex{E8}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32X4.\VMAX` :math:`\hex{FD}~~\hex{E9}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32X4.\VPMIN` :math:`\hex{FD}~~\hex{EA}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32X4.\VPMAX` :math:`\hex{FD}~~\hex{EB}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64X2.\VABS` :math:`\hex{FD}~~\hex{EC}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64X2.\VNEG` :math:`\hex{FD}~~\hex{ED}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64X2.\VSQRT` :math:`\hex{FD}~~\hex{EF}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64X2.\VADD` :math:`\hex{FD}~~\hex{F0}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64X2.\VSUB` :math:`\hex{FD}~~\hex{F1}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64X2.\VMUL` :math:`\hex{FD}~~\hex{F2}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64X2.\VDIV` :math:`\hex{FD}~~\hex{F3}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64X2.\VMIN` :math:`\hex{FD}~~\hex{F4}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64X2.\VMAX` :math:`\hex{FD}~~\hex{F5}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64X2.\VPMIN` :math:`\hex{FD}~~\hex{F6}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64X2.\VPMAX` :math:`\hex{FD}~~\hex{F7}~~\hex{01}` :math:`[\V128~\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32X4.\TRUNC\K{\_sat\_f32x4\_s}` :math:`\hex{FD}~~\hex{F8}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32X4.\TRUNC\K{\_sat\_f32x4\_u}` :math:`\hex{FD}~~\hex{F9}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32X4.\VCONVERT\K{\_i32x4\_s}` :math:`\hex{FD}~~\hex{FA}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32X4.\VCONVERT\K{\_i32x4\_u}` :math:`\hex{FD}~~\hex{FB}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32X4.\VTRUNC\K{\_sat\_f64x2\_s\_zero}` :math:`\hex{FD}~~\hex{FC}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32X4.\VTRUNC\K{\_sat\_f64x2\_u\_zero}` :math:`\hex{FD}~~\hex{FD}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64X2.\VCONVERT\K{\_low\_i32x4\_s}` :math:`\hex{FD}~~\hex{FE}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64X2.\VCONVERT\K{\_low\_i32x4\_u}` :math:`\hex{FD}~~\hex{FF}~~\hex{01}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +================================================= ==================================== ============================================= =========================================================================== ==================================================================== .. note:: Multi-byte opcodes are given with the shortest possible encoding in the table. From 601db12823c1dfe3fd9ea261916a4382b1ce4ecb Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Sun, 5 Mar 2023 17:07:34 +0100 Subject: [PATCH 049/132] [spec] Fix a make dependency --- document/core/Makefile | 3 ++- document/core/exec/modules.rst | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/document/core/Makefile b/document/core/Makefile index 5b81bff0..5eaed2d3 100644 --- a/document/core/Makefile +++ b/document/core/Makefile @@ -105,6 +105,7 @@ pdf: $(GENERATED) latexpdf clean: rm -rf $(BUILDDIR) rm -rf $(STATICDIR) + rm -f $(GENERATED) .PHONY: html html: $(GENERATED) @@ -261,7 +262,7 @@ latex: "(use \`make latexpdf' here to do that automatically)." .PHONY: latexpdf -latexpdf: +latexpdf: $(GENERATED) $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex LATEXMKOPTS=" $(BUILDDIR)/latex/LOG 2>&1 || cat $(BUILDDIR)/latex/LOG diff --git a/document/core/exec/modules.rst b/document/core/exec/modules.rst index 578acfa2..e4d542f6 100644 --- a/document/core/exec/modules.rst +++ b/document/core/exec/modules.rst @@ -731,10 +731,10 @@ where: .. math:: \begin{array}{@{}l} - \F{runelem}_i(\{\ETYPE~\X{et}, \EINIT~\reff^n, \EMODE~\EPASSIVE\}) \quad=\quad \epsilon \\ - \F{runelem}_i(\{\ETYPE~\X{et}, \EINIT~\reff^n, \EMODE~\EACTIVE \{\ETABLE~x, \EOFFSET~\instr^\ast~\END\}\}) \quad=\\ \qquad + \F{runelem}_i(\{\ETYPE~\X{et}, \EINIT~\expr^n, \EMODE~\EPASSIVE\}) \quad=\quad \epsilon \\ + \F{runelem}_i(\{\ETYPE~\X{et}, \EINIT~\expr^n, \EMODE~\EACTIVE \{\ETABLE~x, \EOFFSET~\instr^\ast~\END\}\}) \quad=\\ \qquad \instr^\ast~(\I32.\CONST~0)~(\I32.\CONST~n)~(\TABLEINIT~x~i)~(\ELEMDROP~i) \\ - \F{runelem}_i(\{\ETYPE~\X{et}, \EINIT~\reff^n, \EMODE~\EDECLARATIVE\}) \quad=\\ \qquad + \F{runelem}_i(\{\ETYPE~\X{et}, \EINIT~\expr^n, \EMODE~\EDECLARATIVE\}) \quad=\\ \qquad (\ELEMDROP~i) \\[1ex] \F{rundata}_i(\{\DINIT~b^n, \DMODE~\DPASSIVE\}) \quad=\quad \epsilon \\ \F{rundata}_i(\{\DINIT~b^n, \DMODE~\DACTIVE \{\DMEM~0, \DOFFSET~\instr^\ast~\END\}\}) \quad=\\ \qquad From 2224a914ad6306d4bcce4fa4a94d44f059071219 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Mon, 6 Mar 2023 07:18:09 +0100 Subject: [PATCH 050/132] [spec] Remove some obsolete defs --- document/core/exec/modules.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/document/core/exec/modules.rst b/document/core/exec/modules.rst index e4d542f6..5e6f0d5b 100644 --- a/document/core/exec/modules.rst +++ b/document/core/exec/modules.rst @@ -722,9 +722,6 @@ It is up to the :ref:`embedder ` to define how such conditions are rep &\wedge& F = \{ \AMODULE~\moduleinst, \ALOCALS~\epsilon \} \\[1ex] &\wedge& (S'; F; \expr_{\F{g}} \stepto^\ast S'; F; \val~\END)^\ast \\ &\wedge& ((S'; F; \expr_{\F{e}} \stepto^\ast S'; F; \reff~\END)^\ast)^n \\ - &\wedge& (\tableaddr = \moduleinst.\MITABLES[\elem.\ETABLE])^\ast \\ - &\wedge& (\memaddr = \moduleinst.\MIMEMS[\data.\DMEM])^\ast \\ - &\wedge& (\funcaddr = \moduleinst.\MIFUNCS[\start.\SFUNC])^?) \end{array} where: From 92986a3aa8031835054302bc34f0bde34684f48b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dongjun=20Youn=20/=20=EC=9C=A4=EB=8F=99=EC=A4=80?= Date: Wed, 15 Mar 2023 19:45:02 +0900 Subject: [PATCH 051/132] [spec] Fix typo in execution of vector instructions (#1621) --- document/core/exec/instructions.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index 3f82dce3..2a134bdd 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -385,7 +385,7 @@ Most vector instructions are defined in terms of generic numeric operators appli 5. Let :math:`j^\ast` be the sequence :math:`\lanes_{i8x16}(c_1)`. -6. Let :math:`c^\ast` be the concatenation of the two sequences :math:`j^\ast~0^{240}` +6. Let :math:`c^\ast` be the concatenation of the two sequences :math:`j^\ast~0^{240}`. 7. Let :math:`c'` be the result of :math:`\lanes^{-1}_{i8x16}(c^\ast[ i^\ast[0] ] \dots c^\ast[ i^\ast[15] ])`. @@ -518,7 +518,7 @@ Most vector instructions are defined in terms of generic numeric operators appli 7. Let :math:`i^\ast` be the sequence :math:`\lanes_{\shape}(c_2)`. -8. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{\shape}(i^\ast \with [x] = c_1)` +8. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{\shape}(i^\ast \with [x] = c_1)`. 9. Push :math:`\V128.\VCONST~c` on the stack. @@ -658,7 +658,7 @@ Most vector instructions are defined in terms of generic numeric operators appli 2. Pop the value :math:`\V128.\VCONST~c_1` from the stack. -3. Let :math:`i_1^\ast` be the sequence :math:`\lanes_{\shape}(c_1)` +3. Let :math:`i_1^\ast` be the sequence :math:`\lanes_{\shape}(c_1)`. 4. Let :math:`i` be the result of computing :math:`\bool(\bigwedge(i_1 \neq 0)^\ast)`. @@ -751,7 +751,7 @@ Most vector instructions are defined in terms of generic numeric operators appli 3. Let :math:`i^\ast` be the sequence :math:`\lanes_{t_1\K{x}M}(c_1)`. -4. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{t_2\K{x}N}(\vcvtop^{\sx}_{|t_1|,|t_2|}(i^\ast))` +4. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{t_2\K{x}N}(\vcvtop^{\sx}_{|t_1|,|t_2|}(i^\ast))`. 5. Push the value :math:`\V128.\VCONST~c` onto the stack. @@ -928,7 +928,7 @@ where: 4. Let :math:`j^\ast` be the result of computing :math:`\iadd_{N}(i_1, i_2)^\ast`. -5. Let `c` be the result of computing :math:`\lanes^{-1}_{t_2\K{x}N}(j^\ast)`. +5. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{t_2\K{x}N}(j^\ast)`. 6. Push the value :math:`\V128.\VCONST~c` to the stack. From 5cf26496a17bd50715f15c424e6db27445fc231c Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Wed, 15 Mar 2023 20:46:57 +0100 Subject: [PATCH 052/132] [ci] Fix node download? --- .github/workflows/main.yml | 17 +++-------------- document/core/exec/modules.rst | 8 ++++---- interpreter/Makefile | 2 ++ dune-project => interpreter/dune-project | 0 4 files changed, 9 insertions(+), 18 deletions(-) rename dune-project => interpreter/dune-project (100%) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a158de1e..d867a07e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -18,23 +18,12 @@ jobs: uses: ocaml/setup-ocaml@v2 with: ocaml-compiler: 4.12.x - - run: opam install --yes ocamlbuild.0.14.0 + - run: opam install --yes ocamlbuild.0.14.0 ocamlfind.1.9.5 js_of_ocaml.4.0.0 js_of_ocaml-ppx.4.0.0 - name: Setup Node.js - uses: actions/setup-node@v1 + uses: actions/setup-node@v2 with: node-version: 19.x - - run: cd interpreter && opam exec make JS=node all - - ref-interpreter-js-library: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Setup OCaml - uses: ocaml/setup-ocaml@v2 - with: - ocaml-compiler: 4.12.x - - run: opam install --yes ocamlbuild.0.14.0 ocamlfind.1.9.5 js_of_ocaml.4.0.0 js_of_ocaml-ppx.4.0.0 - - run: cd interpreter && opam exec make wast.js + - run: cd interpreter && opam exec make JS=node ci build-js-api-spec: runs-on: ubuntu-latest diff --git a/document/core/exec/modules.rst b/document/core/exec/modules.rst index 5e6f0d5b..0c8cd509 100644 --- a/document/core/exec/modules.rst +++ b/document/core/exec/modules.rst @@ -335,11 +335,11 @@ New instances of :ref:`functions `, :ref:`tables ` ...................................... -1. Let :math:`\bytes` be the vector of :ref:`bytes ` to allocate. +1. Let :math:`b^\ast` be the vector of :ref:`bytes ` to allocate. 2. Let :math:`a` be the first free :ref:`data address ` in :math:`S`. -3. Let :math:`\datainst` be the :ref:`data instance ` :math:`\{ \DIDATA~\bytes \}`. +3. Let :math:`\datainst` be the :ref:`data instance ` :math:`\{ \DIDATA~b^\ast \}`. 4. Append :math:`\datainst` to the |SDATAS| of :math:`S`. @@ -347,10 +347,10 @@ New instances of :ref:`functions `, :ref:`tables Date: Wed, 15 Mar 2023 20:52:35 +0100 Subject: [PATCH 053/132] [ci] Include dunebuild --- interpreter/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interpreter/Makefile b/interpreter/Makefile index 2c81b874..3294e268 100644 --- a/interpreter/Makefile +++ b/interpreter/Makefile @@ -41,11 +41,12 @@ all: unopt opt libunopt libopt test land: $(WINMAKE) all zip: $(ZIP) smallint: smallint.native -ci: land wast.js +ci: land wast.js dunebuild dunebuild: dune build + # Building executable empty = From be820b2ec23294c6e2e043f8b1ee59ec9971bc28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dongjun=20Youn=20/=20=EC=9C=A4=EB=8F=99=EC=A4=80?= Date: Thu, 16 Mar 2023 17:35:57 +0900 Subject: [PATCH 054/132] [spec] Add missing access to current frame in prose (#1624) * [spec] Append missing periods * [spec] Fix execution of control instructions regarding current frame --- document/core/exec/instructions.rst | 40 ++++++++++++++++------------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index 2a134bdd..c763ea5e 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -846,7 +846,7 @@ where: 3. Pop the value :math:`\V128.\VCONST~c_1` from the stack. -4. Let :math:`(i_1~i_2)^\ast` be the result of computing :math:`\imul_{32}(\extends_{16,32}(\lanes_{\I16X8}(c_1)), \extends_{16,32}(\lanes_{\I16X8}(c_2)))` +4. Let :math:`(i_1~i_2)^\ast` be the result of computing :math:`\imul_{32}(\extends_{16,32}(\lanes_{\I16X8}(c_1)), \extends_{16,32}(\lanes_{\I16X8}(c_2)))`. 5. Let :math:`j^\ast` be the result of computing :math:`\iadd_{32}(i_1, i_2)^\ast`. @@ -891,7 +891,7 @@ where: b. Let :math:`j^\ast` be the sequence :math:`\lanes_{t_1\K{x}M}(c_2)[N \slice N]`. -6. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{t_2\K{x}N}(\imul_{t_2\K{x}N}(\extend^{\sx}_{|t_1|,|t_2|}(i^\ast), \extend^{\sx}_{|t_1|,|t_2|}(j^\ast)))` +6. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{t_2\K{x}N}(\imul_{t_2\K{x}N}(\extend^{\sx}_{|t_1|,|t_2|}(i^\ast), \extend^{\sx}_{|t_1|,|t_2|}(j^\ast)))`. 7. Push the value :math:`\V128.\VCONST~c` onto the stack. @@ -2537,17 +2537,19 @@ Control Instructions :math:`\BLOCK~\blocktype~\instr^\ast~\END` .......................................... -1. Assert: due to :ref:`validation `, :math:`\expand_F(\blocktype)` is defined. +1. Let :math:`F` be the :ref:`current ` :ref:`frame `. + +2. Assert: due to :ref:`validation `, :math:`\expand_F(\blocktype)` is defined. -2. Let :math:`[t_1^m] \to [t_2^n]` be the :ref:`function type ` :math:`\expand_F(\blocktype)`. +3. Let :math:`[t_1^m] \to [t_2^n]` be the :ref:`function type ` :math:`\expand_F(\blocktype)`. -3. Let :math:`L` be the label whose arity is :math:`n` and whose continuation is the end of the block. +4. Let :math:`L` be the label whose arity is :math:`n` and whose continuation is the end of the block. -4. Assert: due to :ref:`validation `, there are at least :math:`m` values on the top of the stack. +5. Assert: due to :ref:`validation `, there are at least :math:`m` values on the top of the stack. -5. Pop the values :math:`\val^m` from the stack. +6. Pop the values :math:`\val^m` from the stack. -6. :ref:`Enter ` the block :math:`\val^m~\instr^\ast` with label :math:`L`. +7. :ref:`Enter ` the block :math:`\val^m~\instr^\ast` with label :math:`L`. .. math:: ~\\[-1ex] @@ -2563,17 +2565,19 @@ Control Instructions :math:`\LOOP~\blocktype~\instr^\ast~\END` ......................................... -1. Assert: due to :ref:`validation `, :math:`\expand_F(\blocktype)` is defined. +1. Let :math:`F` be the :ref:`current ` :ref:`frame `. + +2. Assert: due to :ref:`validation `, :math:`\expand_F(\blocktype)` is defined. -2. Let :math:`[t_1^m] \to [t_2^n]` be the :ref:`function type ` :math:`\expand_F(\blocktype)`. +3. Let :math:`[t_1^m] \to [t_2^n]` be the :ref:`function type ` :math:`\expand_F(\blocktype)`. -3. Let :math:`L` be the label whose arity is :math:`m` and whose continuation is the start of the loop. +4. Let :math:`L` be the label whose arity is :math:`m` and whose continuation is the start of the loop. -4. Assert: due to :ref:`validation `, there are at least :math:`m` values on the top of the stack. +5. Assert: due to :ref:`validation `, there are at least :math:`m` values on the top of the stack. -5. Pop the values :math:`\val^m` from the stack. +6. Pop the values :math:`\val^m` from the stack. -6. :ref:`Enter ` the block :math:`\val^m~\instr^\ast` with label :math:`L`. +7. :ref:`Enter ` the block :math:`\val^m~\instr^\ast` with label :math:`L`. .. math:: ~\\[-1ex] @@ -2604,11 +2608,11 @@ Control Instructions .. math:: ~\\[-1ex] \begin{array}{lcl} - F; (\I32.\CONST~c)~\IF~\X{bt}~\instr_1^\ast~\ELSE~\instr_2^\ast~\END &\stepto& - F; \BLOCK~\X{bt}~\instr_1^\ast~\END + (\I32.\CONST~c)~\IF~\X{bt}~\instr_1^\ast~\ELSE~\instr_2^\ast~\END &\stepto& + \BLOCK~\X{bt}~\instr_1^\ast~\END \\&&\quad (\iff c \neq 0) \\ - F; (\I32.\CONST~c)~\IF~\X{bt}~\instr_1^\ast~\ELSE~\instr_2^\ast~\END &\stepto& - F; \BLOCK~\X{bt}~\instr_2^\ast~\END + (\I32.\CONST~c)~\IF~\X{bt}~\instr_1^\ast~\ELSE~\instr_2^\ast~\END &\stepto& + \BLOCK~\X{bt}~\instr_2^\ast~\END \\&&\quad (\iff c = 0) \\ \end{array} From 0bc1e690a4fc21d29a431adf0fa32568e1213bdd Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Wed, 22 Mar 2023 12:18:28 +0100 Subject: [PATCH 055/132] [bikeshed] Produce some output to help debugging bikeshed failure --- document/core/Makefile | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/document/core/Makefile b/document/core/Makefile index 5eaed2d3..3d34f8ac 100644 --- a/document/core/Makefile +++ b/document/core/Makefile @@ -139,8 +139,16 @@ singlehtml: $(GENERATED) bikeshed: $(GENERATED) $(SPHINXBUILD) -b singlehtml -c util/bikeshed \ $(ALLSPHINXOPTS) $(BUILDDIR)/bikeshed_singlehtml + @echo ==== Showing contents of _build/bikeshed_singlehtml/index.html ==== + @head -n20 _build/bikeshed_singlehtml/index.html + @echo ... + @echo =================================================================== python 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 -n20 _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/ From 34a9bdfa9a5be799fd26dca51b0e045bf0fc8b45 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Wed, 22 Mar 2023 13:18:47 +0100 Subject: [PATCH 056/132] [bikeshed] use python3; tweak debug output --- document/core/Makefile | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/document/core/Makefile b/document/core/Makefile index 3d34f8ac..8a3650ec 100644 --- a/document/core/Makefile +++ b/document/core/Makefile @@ -139,21 +139,19 @@ singlehtml: $(GENERATED) bikeshed: $(GENERATED) $(SPHINXBUILD) -b singlehtml -c util/bikeshed \ $(ALLSPHINXOPTS) $(BUILDDIR)/bikeshed_singlehtml - @echo ==== Showing contents of _build/bikeshed_singlehtml/index.html ==== - @head -n20 _build/bikeshed_singlehtml/index.html - @echo ... - @echo =================================================================== - python util/bikeshed_fixup.py $(BUILDDIR)/bikeshed_singlehtml/index.html \ + python3 util/bikeshed_fixup.py $(BUILDDIR)/bikeshed_singlehtml/index.html \ >$(BUILDDIR)/bikeshed_singlehtml/index_fixed.html @echo ==== Showing contents of _build/bikeshed_singlehtml/index_fixed.html ==== - @head -n20 _build/bikeshed_singlehtml/index_fixed.html - @echo ... + @head -n10 _build/bikeshed_singlehtml/index_fixed.html + @echo ... skipping $$(expr `cat _build/bikeshed_singlehtml/index_fixed.html | wc -l` - 20) lines ... + @tail -n10 _build/bikeshed_singlehtml/index_fixed.html + @echo @echo ========================================================================= mkdir -p $(BUILDDIR)/bikeshed_mathjax/ bikeshed spec index.bs $(BUILDDIR)/bikeshed_mathjax/index.html mkdir -p $(BUILDDIR)/html/bikeshed/ (cd util/katex/ && yarn && yarn build && npm install --only=prod) - python util/mathjax2katex.py $(BUILDDIR)/bikeshed_mathjax/index.html \ + python3 util/mathjax2katex.py $(BUILDDIR)/bikeshed_mathjax/index.html \ >$(BUILDDIR)/html/bikeshed/index.html mkdir -p $(BUILDDIR)/html/bikeshed/katex/dist/ cp -r util/katex/dist/* $(BUILDDIR)/html/bikeshed/katex/dist/ From 7669b6be0ee66e07f5ebc79e88b708f8a61cdb78 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Wed, 22 Mar 2023 13:33:49 +0100 Subject: [PATCH 057/132] [bikeshed] Work around bikeshed issues (#1626) --- document/core/util/bikeshed_fixup.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/document/core/util/bikeshed_fixup.py b/document/core/util/bikeshed_fixup.py index dcd4fd07..05439207 100755 --- a/document/core/util/bikeshed_fixup.py +++ b/document/core/util/bikeshed_fixup.py @@ -11,6 +11,12 @@ def Main(): data = open(sys.argv[1]).read() + # Make bikeshed happy + # Apparently it can't handle empty line before DOCTYPE comment + data = data.replace('\n + data = data.replace('
', '\n
')
+
   # Don't add more than 3 levels to TOC.
   data = data.replace('
', '
') From 08e1ee4db1d9372ab46cd017215dfe506012aea0 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Wed, 22 Mar 2023 14:16:23 +0100 Subject: [PATCH 058/132] [ci] Split CI jobs (#1627) --- .github/workflows/ci-interpreter.yml | 34 ++++++ .github/workflows/ci-spec.yml | 101 ++++++++++++++++++ .github/workflows/main.yml | 92 ---------------- .../{mirror.yml => mirror-to-master.yml} | 5 +- 4 files changed, 138 insertions(+), 94 deletions(-) create mode 100644 .github/workflows/ci-interpreter.yml create mode 100644 .github/workflows/ci-spec.yml delete mode 100644 .github/workflows/main.yml rename .github/workflows/{mirror.yml => mirror-to-master.yml} (81%) diff --git a/.github/workflows/ci-interpreter.yml b/.github/workflows/ci-interpreter.yml new file mode 100644 index 00000000..6f2a2ca0 --- /dev/null +++ b/.github/workflows/ci-interpreter.yml @@ -0,0 +1,34 @@ +name: CI for interpreter & tests + +on: + push: + branches: [ main ] + paths: [ interpreter, test ] + + pull_request: + branches: [ main ] + paths: [ interpreter, test ] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +jobs: + interpreter: + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v2 + - name: Setup OCaml + uses: ocaml/setup-ocaml@v2 + with: + ocaml-compiler: 4.12.x + - name: Setup OCaml tools + run: opam install --yes ocamlbuild.0.14.0 ocamlfind.1.9.5 js_of_ocaml.4.0.0 js_of_ocaml-ppx.4.0.0 + - name: Setup Node.js + uses: actions/setup-node@v2 + with: + node-version: 19.x + - name: Build interpreter + run: cd interpreter && opam exec make + - name: Run tests + run: cd interpreter && opam exec make JS=node ci diff --git a/.github/workflows/ci-spec.yml b/.github/workflows/ci-spec.yml new file mode 100644 index 00000000..634f3115 --- /dev/null +++ b/.github/workflows/ci-spec.yml @@ -0,0 +1,101 @@ +name: CI for specs + +on: + push: + branches: [ main ] + paths: [ document ] + + pull_request: + branches: [ main ] + paths: [ document ] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +jobs: + build-core-spec: + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v2 + with: + submodules: "recursive" + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: 16 + - name: Setup Bikeshed + run: pip install bikeshed && bikeshed update + - name: Setup TexLive + run: sudo apt-get update -y && sudo apt-get install -y latexmk texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended + - name: Setup Sphinx + run: pip install six && pip install sphinx==5.1.0 + - name: Build main spec + run: cd document/core && make main + - name: Run Bikeshed + run: cd document/core && make bikeshed + - name: Upload artifact + uses: actions/upload-artifact@v2 + with: + name: core-rendered + path: document/core/_build/html + + build-js-api-spec: + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v2 + - name: Setup Bikeshed + run: pip install bikeshed && bikeshed update + - name: Run Bikeshed + run: bikeshed spec "document/js-api/index.bs" "document/js-api/index.html" + - name: Upload artifact + uses: actions/upload-artifact@v2 + with: + name: js-api-rendered + path: document/js-api/index.html + + build-web-api-spec: + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v2 + - name: Setup Bikeshed + run: pip install bikeshed && bikeshed update + - name: Run Bikeshed + run: bikeshed spec "document/web-api/index.bs" "document/web-api/index.html" + - name: Upload artifact + uses: actions/upload-artifact@v2 + with: + name: web-api-rendered + path: document/web-api/index.html + + publish-spec: + runs-on: ubuntu-latest + needs: [build-core-spec, build-js-api-spec, build-web-api-spec] + steps: + - name: Checkout repo + uses: actions/checkout@v2 + - name: Create output directory + run: mkdir _output && cp document/index.html _output/index.html + - name: Download core spec artifact + uses: actions/download-artifact@v2 + with: + name: core-rendered + path: _output/core + - name: Download JS API spec artifact + uses: actions/download-artifact@v2 + with: + name: js-api-rendered + path: _output/js-api + - name: Download Web API spec artifact + uses: actions/download-artifact@v2 + with: + name: web-api-rendered + path: _output/web-api + - name: Publish to GitHub Pages + if: github.ref == 'refs/heads/main' + uses: peaceiris/actions-gh-pages@v3 + with: + publish_dir: ./_output + github_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml deleted file mode 100644 index d867a07e..00000000 --- a/.github/workflows/main.yml +++ /dev/null @@ -1,92 +0,0 @@ -name: CI - -on: - push: - branches: [ main ] - pull_request: - branches: [ main ] - - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - -jobs: - ref-interpreter: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Setup OCaml - uses: ocaml/setup-ocaml@v2 - with: - ocaml-compiler: 4.12.x - - run: opam install --yes ocamlbuild.0.14.0 ocamlfind.1.9.5 js_of_ocaml.4.0.0 js_of_ocaml-ppx.4.0.0 - - name: Setup Node.js - uses: actions/setup-node@v2 - with: - node-version: 19.x - - run: cd interpreter && opam exec make JS=node ci - - build-js-api-spec: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - run: pip install bikeshed && bikeshed update - - run: bikeshed spec "document/js-api/index.bs" "document/js-api/index.html" - - uses: actions/upload-artifact@v2 - with: - name: js-api-rendered - path: document/js-api/index.html - - build-web-api-spec: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - run: pip install bikeshed && bikeshed update - - run: bikeshed spec "document/web-api/index.bs" "document/web-api/index.html" - - uses: actions/upload-artifact@v2 - with: - name: web-api-rendered - path: document/web-api/index.html - - build-core-spec: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - with: - submodules: "recursive" - - uses: actions/setup-node@v3 - with: - node-version: 16 - - run: pip install bikeshed && bikeshed update - - run: pip install six - - run: sudo apt-get update -y && sudo apt-get install -y latexmk texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended - - run: pip install sphinx==5.1.0 - - run: cd document/core && make all - - uses: actions/upload-artifact@v2 - with: - name: core-api-rendered - path: document/core/_build/html - - publish-spec: - runs-on: ubuntu-latest - needs: [build-core-spec, build-js-api-spec, build-web-api-spec] - steps: - - uses: actions/checkout@v2 - - run: mkdir _output && cp document/index.html _output/index.html - - uses: actions/download-artifact@v2 - with: - name: js-api-rendered - path: _output/js-api - - uses: actions/download-artifact@v2 - with: - name: web-api-rendered - path: _output/web-api - - uses: actions/download-artifact@v2 - with: - name: core-api-rendered - path: _output/core - - name: Publish HTML to GitHub Pages - if: github.ref == 'refs/heads/main' - uses: peaceiris/actions-gh-pages@v3 - with: - publish_dir: ./_output - github_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/mirror.yml b/.github/workflows/mirror-to-master.yml similarity index 81% rename from .github/workflows/mirror.yml rename to .github/workflows/mirror-to-master.yml index 5c470757..7849af75 100644 --- a/.github/workflows/mirror.yml +++ b/.github/workflows/mirror-to-master.yml @@ -1,3 +1,5 @@ +name: Mirror main branch to master branch + on: push: branches: @@ -8,8 +10,7 @@ jobs: runs-on: ubuntu-latest name: Mirror main branch to master branch steps: - - name: Mirror action step - id: mirror + - name: Mirror branch uses: google/mirror-branch-action@v1.0 with: github-token: ${{ secrets.GITHUB_TOKEN }} From a4e9030677c8b8477b0e728b67e8cabdc89c83f0 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Wed, 22 Mar 2023 14:58:50 +0100 Subject: [PATCH 059/132] [ci] Fix path filters --- .github/workflows/ci-interpreter.yml | 4 ++-- .github/workflows/ci-spec.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-interpreter.yml b/.github/workflows/ci-interpreter.yml index 6f2a2ca0..6edfa0c4 100644 --- a/.github/workflows/ci-interpreter.yml +++ b/.github/workflows/ci-interpreter.yml @@ -3,11 +3,11 @@ name: CI for interpreter & tests on: push: branches: [ main ] - paths: [ interpreter, test ] + paths: [ interpreter/**, test/** ] pull_request: branches: [ main ] - paths: [ interpreter, test ] + paths: [ interpreter/**, test/** ] # Allows you to run this workflow manually from the Actions tab workflow_dispatch: diff --git a/.github/workflows/ci-spec.yml b/.github/workflows/ci-spec.yml index 634f3115..7610b33b 100644 --- a/.github/workflows/ci-spec.yml +++ b/.github/workflows/ci-spec.yml @@ -3,11 +3,11 @@ name: CI for specs on: push: branches: [ main ] - paths: [ document ] + paths: [ document/** ] pull_request: branches: [ main ] - paths: [ document ] + paths: [ document/** ] # Allows you to run this workflow manually from the Actions tab workflow_dispatch: From 6129263c4ff527e287fa31e800a9b66bc3a8a57d Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Wed, 22 Mar 2023 15:01:56 +0100 Subject: [PATCH 060/132] [ci] Test path filter for interpreter --- interpreter/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interpreter/README.md b/interpreter/README.md index 18aa36c0..fc2a1827 100644 --- a/interpreter/README.md +++ b/interpreter/README.md @@ -15,7 +15,7 @@ The text format defines modules in S-expression syntax. Moreover, it is generali ## Building -You'll need OCaml 4.08 or higher. Instructions for installing a recent version of OCaml on multiple platforms are available [here](https://ocaml.org/docs/install.html). On most platforms, the recommended way is through [OPAM](https://ocaml.org/docs/install.html#OPAM). +You'll need OCaml 4.12 or higher. Instructions for installing a recent version of OCaml on multiple platforms are available [here](https://ocaml.org/docs/install.html). On most platforms, the recommended way is through [OPAM](https://ocaml.org/docs/install.html#OPAM). Once you have OCaml, simply do From 6802d86eba4d2d0aa7c165db370141b3e914f8fd Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Wed, 1 Mar 2023 14:50:54 +0100 Subject: [PATCH 061/132] [js-api] Remove some anchor definitions WebRef has recently added definitions for ECMAScript, which means most of the explicit anchor definitions are no longer needed. Also, some abstract operations had their names changed. This change should be entirely editorial. --- document/js-api/index.bs | 98 +++++++++------------------------------- 1 file changed, 22 insertions(+), 76 deletions(-) diff --git a/document/js-api/index.bs b/document/js-api/index.bs index 19faf7ed..c085e583 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -37,66 +37,12 @@ urlPrefix: https://tc39.github.io/ecma262/; spec: ECMASCRIPT url: sec-returnifabrupt-shorthands text: ! text: ? - text: agent cluster; url: sec-agent-clusters - text: agent; url: agent - text: data block; url: sec-data-blocks - text: Bound Function; url: sec-bound-function-exotic-objects - text: NumericLiteral; url: sec-literals-numeric-literals - text: surrounding agent; url: surrounding-agent - text: ToNumber; url: sec-tonumber - text: ToInt32; url: sec-toint32 - text: ToString; url: sec-tostring - url: sec-ecmascript-data-types-and-values - text: Type - text: Type(x) - url: sec-iscallable - text: IsCallable - text: callable; for: ECMAScript - url: sec-well-known-intrinsic-objects - text: %ErrorPrototype% - text: %ObjectPrototype%; url: sec-properties-of-the-object-prototype-object - text: %Promise%; url: sec-promise-constructor - text: Property Descriptor; url: sec-property-descriptor-specification-type - text: array index; url: sec-array-exotic-objects - text: OrdinaryGetOwnProperty; url: sec-ordinarygetownproperty - text: OrdinaryDefineOwnProperty; url: sec-ordinarydefineownproperty - text: OrdinaryPreventExtensions; url: sec-ordinarypreventextensions - text: OrdinarySet; url: sec-ordinaryset - text: equally close values; url: sec-ecmascript-language-types-number-type - text: internal slot; url: sec-object-internal-methods-and-internal-slots - text: JavaScript execution context stack; url: execution-context-stack - text: running JavaScript execution context; url: running-execution-context - text: GetIterator; url: sec-getiterator - text: IteratorStep; url: sec-iteratorstep - text: NormalCompletion; url: sec-normalcompletion - text: IteratorValue; url: sec-iteratorvalue - url: sec-well-known-symbols - text: @@iterator - text: @@toStringTag - text: CreateDataProperty; url: sec-createdataproperty - text: DetachArrayBuffer; url: sec-detacharraybuffer - text: SetIntegrityLevel; url: sec-setintegritylevel - text: Call; url: sec-call - text: Get; url: sec-get-o-p - text: DefinePropertyOrThrow; url: sec-definepropertyorthrow + text: Type; url: sec-ecmascript-data-types-and-values text: current Realm; url: current-realm - text: ObjectCreate; url: sec-objectcreate - text: CreateBuiltinFunction; url: sec-createbuiltinfunction - text: SetFunctionName; url: sec-setfunctionname - text: SetFunctionLength; url: sec-setfunctionlength - text: the Number value; url: sec-ecmascript-language-types-number-type - text: NumberToRawBytes; url: sec-numbertorawbytes text: Built-in Function Objects; url: sec-built-in-function-objects text: NativeError Object Structure; url: sec-nativeerror-object-structure - text: CreateArrayFromList; url: sec-createarrayfromlist - text: GetMethod; url: sec-getmethod - text: IterableToList; url: sec-iterabletolist - text: ToBigInt64; url: #sec-tobigint64 - text: BigInt; url: #sec-ecmascript-language-types-bigint-type text: ๐”ฝ; url: #๐”ฝ text: โ„ค; url: #โ„ค - 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 @@ -367,11 +313,11 @@ A {{Module}} object represents a single WebAssembly module. Each {{Module}} obje 1. If |module|.[=imports=] [=list/is empty|is not empty=], and |importObject| is undefined, throw a {{TypeError}} exception. 1. Let |imports| be ยซ ยป. 1. [=list/iterate|For each=] (|moduleName|, |componentName|, |externtype|) of [=module_imports=](|module|), - 1. Let |o| be [=?=] [=Get=](|importObject|, |moduleName|). + 1. Let |o| be [=?=] [$Get$](|importObject|, |moduleName|). 1. If [=Type=](|o|) is not Object, throw a {{TypeError}} exception. - 1. Let |v| be [=?=] [=Get=](|o|, |componentName|). + 1. Let |v| be [=?=] [$Get$](|o|, |componentName|). 1. If |externtype| is of the form [=func=] |functype|, - 1. If [=IsCallable=](|v|) is false, throw a {{LinkError}} exception. + 1. If [$IsCallable$](|v|) is false, throw a {{LinkError}} exception. 1. If |v| has a \[[FunctionAddress]] internal slot, and therefore is an [=Exported Function=], 1. Let |funcaddr| be the value of |v|'s \[[FunctionAddress]] internal slot. 1. Otherwise, @@ -415,7 +361,7 @@ The verification of WebAssembly type requirements is deferred to the
To create an exports object from a WebAssembly module |module| and instance |instance|, perform the following steps: - 1. Let |exportsObject| be [=!=] [=ObjectCreate=](null). + 1. Let |exportsObject| be [=!=] [$OrdinaryObjectCreate$](null). 1. [=list/iterate|For each=] (|name|, |externtype|) of [=module_exports=](|module|), 1. Let |externval| be [=instance_export=](|instance|, |name|). 1. Assert: |externval| is not [=error=]. @@ -439,11 +385,11 @@ The verification of WebAssembly type requirements is deferred to the 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. Let |status| be [=!=] [=CreateDataProperty=](|exportsObject|, |name|, |value|). + 1. Let |status| be [=!=] [$CreateDataProperty$](|exportsObject|, |name|, |value|). 1. Assert: |status| is true. Note: the validity and uniqueness checks performed during [=WebAssembly module validation=] ensure that each property name is valid and no properties are defined twice. - 1. Perform [=!=] [=SetIntegrityLevel=](|exportsObject|, `"frozen"`). + 1. Perform [=!=] [$SetIntegrityLevel$](|exportsObject|, `"frozen"`). 1. Return |exportsObject|.
@@ -706,7 +652,7 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each 1. Let |map| be the [=surrounding agent=]'s associated [=Memory object cache=]. 1. Assert: |map|[|memaddr|] [=map/exists=]. 1. Let |memory| be |map|[|memaddr|]. - 1. Perform [=!=] [=DetachArrayBuffer=](|memory|.\[[BufferObject]], "WebAssembly.Memory"). + 1. Perform [=!=] [$DetachArrayBuffer$](|memory|.\[[BufferObject]], "WebAssembly.Memory"). 1. Let |buffer| be the result of [=create a memory buffer|creating a memory buffer=] from |memaddr|. 1. Set |memory|.\[[BufferObject]] to |buffer|.
@@ -990,13 +936,13 @@ This slot holds a [=function address=] relative to the [=surrounding agent=]'s [ 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. 1. Let |funcinst| be |store|.funcs[|funcaddr|]. 1. If |funcinst| is of the form {type functype, hostcode |hostfunc|}, - 1. Assert: |hostfunc| is a JavaScript object and [=IsCallable=](|hostfunc|) is true. + 1. Assert: |hostfunc| is a JavaScript object and [$IsCallable$](|hostfunc|) is true. 1. Let |index| be the [=index of the host function=] |funcaddr|. 1. Otherwise, 1. Let |moduleinst| be |funcinst|.module. 1. Assert: |funcaddr| is contained in |moduleinst|.funcaddrs. 1. Let |index| be the index of |moduleinst|.funcaddrs where |funcaddr| is found. - 1. Return [=!=] [=ToString=](|index|). + 1. Return [=!=] [$ToString$](|index|).
@@ -1012,7 +958,7 @@ This slot holds a [=function address=] relative to the [=surrounding agent=]'s [ 1. Let [|paramTypes|] โ†’ [resultTypes] be |functype|. 1. Let |arity| be |paramTypes|'s [=list/size=]. 1. Let |name| be the [=name of the WebAssembly function=] |funcaddr|. - 1. Let |function| be [=!=] [=CreateBuiltinFunction=](|steps|, |arity|, |name|, ยซ \[[FunctionAddress]] ยป, |realm|). + 1. Let |function| be [=!=] [$CreateBuiltinFunction$](|steps|, |arity|, |name|, ยซ \[[FunctionAddress]] ยป, |realm|). 1. Set |function|.\[[FunctionAddress]] to |funcaddr|. 1. [=map/Set=] |map|[|funcaddr|] to |function|. 1. Return |function|. @@ -1044,7 +990,7 @@ This slot holds a [=function address=] relative to the [=surrounding agent=]'s [ 1. Let |values| be ยซ ยป. 1. [=list/iterate|For each=] |r| of |ret|, 1. [=list/Append=] [=ToJSValue=](|r|) to |values|. - 1. Return [=CreateArrayFromList=](|values|). + 1. Return [$CreateArrayFromList$](|values|).
Note: [=call an Exported Function|Calling an Exported Function=] executes in the \[[Realm]] of the callee Exported Function, as per the definition of [=built-in function objects=]. @@ -1059,14 +1005,14 @@ Note: Exported Functions do not have a \[[Construct]] method and thus it is not 1. Let |jsArguments| be ยซ ยป. 1. [=list/iterate|For each=] |arg| of |arguments|, 1. [=list/Append=] [=!=] [=ToJSValue=](|arg|) to |jsArguments|. - 1. Let |ret| be [=?=] [=Call=](|func|, undefined, |jsArguments|). + 1. Let |ret| be [=?=] [$Call$](|func|, undefined, |jsArguments|). 1. Let |resultsSize| be |results|'s [=list/size=]. 1. If |resultsSize| is 0, return ยซ ยป. 1. Otherwise, if |resultsSize| is 1, return ยซ [=?=] [=ToWebAssemblyValue=](|ret|, |results|[0]) ยป. 1. Otherwise, - 1. Let |method| be [=?=] [=GetMethod=](|ret|, [=@@iterator=]). + 1. Let |method| be [=?=] [$GetMethod$](|ret|, {{@@iterator}}). 1. If |method| is undefined, [=throw=] a {{TypeError}}. - 1. Let |values| be [=?=] [=IterableToList=](|ret|, |method|). + 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, @@ -1077,11 +1023,11 @@ Note: Exported Functions do not have a \[[Construct]] method and thus it is not
To create a host function from the JavaScript object |func| and type |functype|, perform the following steps: - 1. Assert: [=IsCallable=](|func|). + 1. Assert: [$IsCallable$](|func|). 1. Let |stored settings| be the incumbent settings object. 1. Let |hostfunc| be a [=host function=] which performs the following steps when called with arguments |arguments|: 1. Let |realm| be |func|'s [=associated Realm=]. - 1. Let |relevant settings| be |realm|'s [=Realm/settings object=]. + 1. Let |relevant settings| be |realm|'s [=realm/settings object=]. 1. [=Prepare to run script=] with |relevant settings|. 1. [=Prepare to run a callback=] with |stored settings|. 1. Let |result| be the result of [=run a host function|running a host function=] from |func|, |functype|, and |arguments|. @@ -1116,7 +1062,7 @@ The algorithm ToJSValue(|w|) coerces a [=WebAssembly value=] to a Jav 1. If |w| is of the form [=ref.func=] |funcaddr|, return the result of creating [=a new Exported Function=] from |funcaddr|. 1. If |w| is of the form [=ref.extern=] |externaddr|, return the result of [=retrieving an extern value=] from |externaddr|. -Note: Number values which are equal to NaN may have various observable NaN payloads; see [=NumberToRawBytes=] for details. +Note: Number values which are equal to NaN may have various observable NaN payloads; see [$NumericToRawBytes$] for details.
@@ -1134,13 +1080,13 @@ The algorithm ToWebAssemblyValue(|v|, |type|) coerces a JavaScript va 1. Assert: |type| is not [=v128=]. 1. If |type| is [=i64=], - 1. Let |i64| be [=?=] [=ToBigInt64=](|v|). + 1. Let |i64| be [=?=] [$ToBigInt64$](|v|). 1. Return [=i64.const=] |i64|. 1. If |type| is [=i32=], - 1. Let |i32| be [=?=] [=ToInt32=](|v|). + 1. Let |i32| be [=?=] [$ToInt32$](|v|). 1. Return [=i32.const=] |i32|. 1. If |type| is [=f32=], - 1. Let |number| be [=?=] [=ToNumber=](|v|). + 1. Let |number| be [=?=] [$ToNumber$](|v|). 1. If |number| is **NaN**, 1. Let |n| be an implementation-defined integer such that [=canon=]32 โ‰ค |n| < 2[=signif=](32). 1. Let |f32| be [=nan=](n). @@ -1148,7 +1094,7 @@ The algorithm ToWebAssemblyValue(|v|, |type|) coerces a JavaScript va 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. 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). From f60370c6f15546811e8603df71e7432ddf3dab49 Mon Sep 17 00:00:00 2001 From: Ng Zhi An Date: Wed, 22 Mar 2023 10:04:44 -0700 Subject: [PATCH 062/132] [docs] Update README.md build badges (#1628) --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ab9cd995..21660b8d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ -![Build Status](https://github.com/WebAssembly/spec/actions/workflows/main.yml/badge.svg) +[![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 From c280b356e0da830ce0b7c636c34ea684f5d1b728 Mon Sep 17 00:00:00 2001 From: Soni L Date: Mon, 27 Mar 2023 11:29:31 -0300 Subject: [PATCH 063/132] [test] Reduce large br_table for compatibility with wasm2kotlin (#1630) --- test/core/br_table.wast | 249 ---------------------------------------- 1 file changed, 249 deletions(-) diff --git a/test/core/br_table.wast b/test/core/br_table.wast index 5c1aa50c..3fc533d5 100644 --- a/test/core/br_table.wast +++ b/test/core/br_table.wast @@ -583,255 +583,6 @@ 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 - 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 (local.get 0) ) (return (i32.const -1)) From eb71ed52ea6fcb24cbee62ffbbcef9973d09dfbf Mon Sep 17 00:00:00 2001 From: Jae Hyun Lee <99jaehyunlee@gmail.com> Date: Wed, 5 Apr 2023 20:37:25 +0900 Subject: [PATCH 064/132] [spec] Fix typo in module instantiation of execution (#1636) --- document/core/exec/modules.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/document/core/exec/modules.rst b/document/core/exec/modules.rst index 0c8cd509..ad485c36 100644 --- a/document/core/exec/modules.rst +++ b/document/core/exec/modules.rst @@ -721,7 +721,7 @@ It is up to the :ref:`embedder ` to define how such conditions are rep &\wedge& S', \moduleinst = \allocmodule(S, \module, \externval^k, \val^\ast, (\reff^\ast)^n) \\ &\wedge& F = \{ \AMODULE~\moduleinst, \ALOCALS~\epsilon \} \\[1ex] &\wedge& (S'; F; \expr_{\F{g}} \stepto^\ast S'; F; \val~\END)^\ast \\ - &\wedge& ((S'; F; \expr_{\F{e}} \stepto^\ast S'; F; \reff~\END)^\ast)^n \\ + &\wedge& ((S'; F; \expr_{\F{e}} \stepto^\ast S'; F; \reff~\END)^\ast)^n) \\ \end{array} where: From 56e2779b4ec86587239d722fe5354f704af50820 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dongjun=20Youn=20/=20=EC=9C=A4=EB=8F=99=EC=A4=80?= Date: Wed, 5 Apr 2023 21:12:07 +0900 Subject: [PATCH 065/132] [spec] Tweak phrasing of the prose specification (#1629) --- document/core/exec/instructions.rst | 260 +++++++++++++++++----------- 1 file changed, 163 insertions(+), 97 deletions(-) diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index c763ea5e..4f040d0e 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -220,9 +220,9 @@ Reference Instructions .. math:: \begin{array}{lcl@{\qquad}l} - \val~\REFISNULL &\stepto& \I32.\CONST~1 + \val~\REFISNULL &\stepto& (\I32.\CONST~1) & (\iff \val = \REFNULL~t) \\ - \val~\REFISNULL &\stepto& \I32.\CONST~0 + \val~\REFISNULL &\stepto& (\I32.\CONST~0) & (\otherwise) \\ \end{array} @@ -242,7 +242,7 @@ Reference Instructions .. math:: \begin{array}{lcl@{\qquad}l} - F; \REFFUNC~x &\stepto& F; \REFFUNCADDR~a + F; (\REFFUNC~x) &\stepto& F; (\REFFUNCADDR~a) & (\iff a = F.\AMODULE.\MIFUNCS[x]) \\ \end{array} @@ -379,15 +379,15 @@ Most vector instructions are defined in terms of generic numeric operators appli 2. Pop the value :math:`\V128.\VCONST~c_2` from the stack. -3. Let :math:`i^\ast` be the sequence :math:`\lanes_{i8x16}(c_2)`. +3. Let :math:`i^\ast` be the result of computing :math:`\lanes_{i8x16}(c_2)`. 4. Pop the value :math:`\V128.\VCONST~c_1` from the stack. -5. Let :math:`j^\ast` be the sequence :math:`\lanes_{i8x16}(c_1)`. +5. Let :math:`j^\ast` be the result of computing :math:`\lanes_{i8x16}(c_1)`. -6. Let :math:`c^\ast` be the concatenation of the two sequences :math:`j^\ast~0^{240}`. +6. Let :math:`c^\ast` be the concatenation of the two sequences :math:`j^\ast` and :math:`0^{240}`. -7. Let :math:`c'` be the result of :math:`\lanes^{-1}_{i8x16}(c^\ast[ i^\ast[0] ] \dots c^\ast[ i^\ast[15] ])`. +7. Let :math:`c'` be the result of computing :math:`\lanes^{-1}_{i8x16}(c^\ast[ i^\ast[0] ] \dots c^\ast[ i^\ast[15] ])`. 8. Push the value :math:`\V128.\VCONST~c'` onto the stack. @@ -416,22 +416,22 @@ Most vector instructions are defined in terms of generic numeric operators appli 3. Pop the value :math:`\V128.\VCONST~c_2` from the stack. -4. Let :math:`i_2^\ast` be the sequence :math:`\lanes_{i8x16}(c_2)`. +4. Let :math:`i_2^\ast` be the result of computing :math:`\lanes_{i8x16}(c_2)`. 5. Pop the value :math:`\V128.\VCONST~c_1` from the stack. -6. Let :math:`i_1^\ast` be the sequence :math:`\lanes_{i8x16}(c_1)`. +6. Let :math:`i_1^\ast` be the result of computing :math:`\lanes_{i8x16}(c_1)`. -7. Let :math:`i^\ast` be the concatenation of the two sequences :math:`i_1^\ast~i_2^\ast`. +7. Let :math:`i^\ast` be the concatenation of the two sequences :math:`i_1^\ast` and :math:`i_2^\ast`. -8. Let :math:`c` be the result of :math:`\lanes^{-1}_{i8x16}(i^\ast[x^\ast[0]] \dots i^\ast[x^\ast[15]])`. +8. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{i8x16}(i^\ast[x^\ast[0]] \dots i^\ast[x^\ast[15]])`. 9. Push the value :math:`\V128.\VCONST~c` onto the stack. .. math:: \begin{array}{l} \begin{array}{lcl@{\qquad}l} - (\V128\K{.}\VCONST~c_1)~(\V128\K{.}\VCONST~c_2)~\I8X16\K{.}\SHUFFLE~x^\ast &\stepto& (\V128\K{.}\VCONST~c) + (\V128\K{.}\VCONST~c_1)~(\V128\K{.}\VCONST~c_2)~(\I8X16\K{.}\SHUFFLE~x^\ast) &\stepto& (\V128\K{.}\VCONST~c) \end{array} \\ \qquad \begin{array}[t]{@{}r@{~}l@{}} @@ -454,7 +454,7 @@ Most vector instructions are defined in terms of generic numeric operators appli 4. Let :math:`N` be the integer :math:`\dim(\shape)`. -5. Let :math:`c` be the result of :math:`\lanes^{-1}_{\shape}(c_1^N)`. +5. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{\shape}(c_1^N)`. 6. Push the value :math:`\V128.\VCONST~c` to the stack. @@ -478,7 +478,7 @@ Most vector instructions are defined in terms of generic numeric operators appli 3. Pop the value :math:`\V128.\VCONST~c_1` from the stack. -4. Let :math:`i^\ast` be the sequence :math:`\lanes_{t_1\K{x}N}(c_1)`. +4. Let :math:`i^\ast` be the result of computing :math:`\lanes_{t_1\K{x}N}(c_1)`. 5. Let :math:`t_2` be the type :math:`\unpacked(t_1\K{x}N)`. @@ -489,7 +489,7 @@ Most vector instructions are defined in terms of generic numeric operators appli .. math:: \begin{array}{l} \begin{array}{lcl@{\qquad}l} - (\V128\K{.}\VCONST~c_1)~t_1\K{x}N\K{.}\EXTRACTLANE~x &\stepto& (t_2\K{.}\CONST~c_2) + (\V128\K{.}\VCONST~c_1)~(t_1\K{x}N\K{.}\EXTRACTLANE~x) &\stepto& (t_2\K{.}\CONST~c_2) \end{array} \\ \qquad \begin{array}[t]{@{}r@{~}l@{}} @@ -516,7 +516,7 @@ Most vector instructions are defined in terms of generic numeric operators appli 6. Pop the value :math:`\V128.\VCONST~c_2` from the stack. -7. Let :math:`i^\ast` be the sequence :math:`\lanes_{\shape}(c_2)`. +7. Let :math:`i^\ast` be the result of computing :math:`\lanes_{\shape}(c_2)`. 8. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{\shape}(i^\ast \with [x] = c_1)`. @@ -525,7 +525,7 @@ Most vector instructions are defined in terms of generic numeric operators appli .. math:: \begin{array}{l} \begin{array}{lcl@{\qquad}l} - (t_1\K{.}\CONST~c_1)~(\V128\K{.}\VCONST~c_2)~\shape\K{.}\REPLACELANE~x &\stepto& (\V128\K{.}\VCONST~c) + (t_1\K{.}\CONST~c_1)~(\V128\K{.}\VCONST~c_2)~(\shape\K{.}\REPLACELANE~x) &\stepto& (\V128\K{.}\VCONST~c) \end{array} \\ \qquad \begin{array}[t]{@{}r@{~}l@{}} @@ -596,13 +596,17 @@ Most vector instructions are defined in terms of generic numeric operators appli 3. Pop the value :math:`\V128.\VCONST~c_1` from the stack. -4. Let :math:`i^\ast` be the sequence :math:`\lanes_{t\K{x}N}(c_1)`. +4. Let :math:`i_1^\ast` be the result of computing :math:`\lanes_{t\K{x}N}(c_1)`. -5. Let :math:`j^\ast` be the sequence :math:`\lanes_{t\K{x}N}(c_2)`. +5. Let :math:`i_2^\ast` be the result of computing :math:`\lanes_{t\K{x}N}(c_2)`. -6. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{t\K{x}N}(\extends_{1,|t|}(\vrelop_t(i^\ast, j^\ast)))`. +6. Let :math:`i^\ast` be the result of computing :math:`\vrelop_t(i_1^\ast, i_2^\ast)`. -7. Push the value :math:`\V128.\VCONST~c` to the stack. +7. Let :math:`j^\ast` be the result of computing :math:`\extends_{1,|t|}(i^\ast)`. + +8. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{t\K{x}N}(j^\ast)`. + +9. Push the value :math:`\V128.\VCONST~c` to the stack. .. math:: \begin{array}{l} @@ -629,11 +633,13 @@ Most vector instructions are defined in terms of generic numeric operators appli 4. Pop the value :math:`\V128.\VCONST~c_1` from the stack. -5. Let :math:`i^\ast` be the sequence :math:`\lanes_{t\K{x}N}(c_1)`. +5. Let :math:`i^\ast` be the result of computing :math:`\lanes_{t\K{x}N}(c_1)`. -6. Let :math:`c` be :math:`\lanes^{-1}_{t\K{x}N}(\vishiftop_{t}(i^\ast, s^N))`. +6. Let :math:`j^\ast` be the result of computing :math:`\vishiftop_{t}(i^\ast, s^N)`. -7. Push the value :math:`\V128.\VCONST~c` to the stack. +7. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{t\K{x}N}(j^\ast)`. + +8. Push the value :math:`\V128.\VCONST~c` to the stack. .. math:: \begin{array}{l} @@ -658,7 +664,7 @@ Most vector instructions are defined in terms of generic numeric operators appli 2. Pop the value :math:`\V128.\VCONST~c_1` from the stack. -3. Let :math:`i_1^\ast` be the sequence :math:`\lanes_{\shape}(c_1)`. +3. Let :math:`i_1^\ast` be the result of computing :math:`\lanes_{\shape}(c_1)`. 4. Let :math:`i` be the result of computing :math:`\bool(\bigwedge(i_1 \neq 0)^\ast)`. @@ -687,15 +693,17 @@ Most vector instructions are defined in terms of generic numeric operators appli 2. Pop the value :math:`\V128.\VCONST~c_1` from the stack. -3. Let :math:`i_1^N` be the sequence :math:`\lanes_{t\K{x}N}(c)`. +3. Let :math:`i_1^N` be the result of computing :math:`\lanes_{t\K{x}N}(c)`. 4. Let :math:`B` be the :ref:`bit width ` :math:`|t|` of :ref:`value type ` :math:`t`. -5. Let :math:`i_2^N` be the sequence as a result of computing :math:`\ilts_{B}(i_1^N, 0^N)`. +5. Let :math:`i_2^N` be the result of computing :math:`\ilts_{B}(i_1^N, 0^N)`. + +6. Let :math:`j^\ast` be the concatenation of the two sequences :math:`i_2^N` and :math:`0^{32-N}`. -6. Let :math:`c` be the integer :math:`\ibits_{32}^{-1}(i_2^N~0^{32-N})`. +7. Let :math:`c` be the result of computing :math:`\ibits_{32}^{-1}(j^\ast)`. -7. Push the value :math:`\I32.\CONST~c` onto the stack. +8. Push the value :math:`\I32.\CONST~c` onto the stack. .. math:: \begin{array}{lcl@{\qquad}l} @@ -716,15 +724,21 @@ Most vector instructions are defined in terms of generic numeric operators appli 3. Pop the value :math:`\V128.\VCONST~c_2` from the stack. -4. Let :math:`d_2^M` be the result of computing :math:`\narrow^{\sx}_{|t_1|,|t_2|}(\lanes_{t_1\K{x}M}(c_2))`. +4. Let :math:`i_2^M` be the result of computing :math:`\lanes_{t_1\K{x}M}(c_2)`. -5. Pop the value :math:`\V128.\VCONST~c_1` from the stack. +5. Let :math:`d_2^M` be the result of computing :math:`\narrow^{\sx}_{|t_1|,|t_2|}(i_2^M)`. -6. Let :math:`d_1^M` be the result of computing :math:`\narrow^{\sx}_{|t_1|,|t_2|}(\lanes_{t_1\K{x}M}(c_1))`. +6. Pop the value :math:`\V128.\VCONST~c_1` from the stack. -7. Let :math:`c` be the result of :math:`\lanes^{-1}_{t_2\K{x}N}(d_1^M~d_2^M)`. +7. Let :math:`i_1^M` be the result of computing :math:`\lanes_{t_1\K{x}M}(c_1)`. -8. Push the value :math:`\V128.\VCONST~c` onto the stack. +8. Let :math:`d_1^M` be the result of computing :math:`\narrow^{\sx}_{|t_1|,|t_2|}(i_1^M)`. + +9. Let :math:`j^N` be the concatenation of the two sequences :math:`d_1^M` and :math:`d_2^M`. + +10. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{t_2\K{x}N}(j^N)`. + +11. Push the value :math:`\V128.\VCONST~c` onto the stack. .. math:: \begin{array}{l} @@ -745,15 +759,19 @@ Most vector instructions are defined in terms of generic numeric operators appli :math:`t_2\K{x}N\K{.}\vcvtop\K{\_}t_1\K{x}M\K{\_}\sx` ..................................................... -1. Assert: due to :ref:`validation `, a value of :ref:`value type ` |V128| is on the top of the stack. +1. Assert: due to :ref:`syntax `, :math:`N = M`. -2. Pop the value :math:`\V128.\VCONST~c_1` from the stack. +2. Assert: due to :ref:`validation `, a value of :ref:`value type ` |V128| is on the top of the stack. + +3. Pop the value :math:`\V128.\VCONST~c_1` from the stack. -3. Let :math:`i^\ast` be the sequence :math:`\lanes_{t_1\K{x}M}(c_1)`. +4. Let :math:`i^\ast` be the result of computing :math:`\lanes_{t_1\K{x}M}(c_1)`. -4. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{t_2\K{x}N}(\vcvtop^{\sx}_{|t_1|,|t_2|}(i^\ast))`. +5. Let :math:`j^\ast` be the result of computing :math:`\vcvtop^{\sx}_{|t_1|,|t_2|}(i^\ast)`. -5. Push the value :math:`\V128.\VCONST~c` onto the stack. +6. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{t_2\K{x}N}(j^\ast)`. + +7. Push the value :math:`\V128.\VCONST~c` onto the stack. .. math:: \begin{array}{l} @@ -770,23 +788,27 @@ Most vector instructions are defined in terms of generic numeric operators appli :math:`t_2\K{x}N\K{.}\vcvtop\K{\_}\half\K{\_}t_1\K{x}M\K{\_}\sx^?` .................................................................. -1. Assert: due to :ref:`validation `, a value of :ref:`value type ` |V128| is on the top of the stack. +1. Assert: due to :ref:`syntax `, :math:`N = M / 2`. -2. Pop the value :math:`\V128.\VCONST~c_1` from the stack. +2. Assert: due to :ref:`validation `, a value of :ref:`value type ` |V128| is on the top of the stack. -3. If :math:`\half` is :math:`\K{low}`, then: +3. Pop the value :math:`\V128.\VCONST~c_1` from the stack. - a. Let :math:`i^\ast` be the sequence :math:`\lanes_{t_1\K{x}M}(c_1)[0 \slice N]`. +4. Let :math:`i^\ast` be the result of computing :math:`\lanes_{t_1\K{x}M}(c_1)`. -4. Else: +5. If :math:`\half` is :math:`\K{low}`, then: - a. Let :math:`i^\ast` be the sequence :math:`\lanes_{t_1\K{x}M}(c_1)[N \slice N]`. + a. Let :math:`j^\ast` be the sequence :math:`i^\ast[0 \slice N]`. -5. Let :math:`j^\ast` be the result of computing :math:`\vcvtop^{\sx^?}_{|t_1|,|t_2|}(i^\ast)`. +6. Else: -6. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{t_2\K{x}N}(j^\ast)`. + a. Let :math:`j^\ast` be the sequence :math:`i^\ast[N \slice N]`. -7. Push the value :math:`\V128.\VCONST~c` onto the stack. +7. Let :math:`k^\ast` be the result of computing :math:`\vcvtop^{\sx^?}_{|t_1|,|t_2|}(j^\ast)`. + +8. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{t_2\K{x}N}(k^\ast)`. + +9. Push the value :math:`\V128.\VCONST~c` onto the stack. .. math:: \begin{array}{l} @@ -811,17 +833,21 @@ where: :math:`t_2\K{x}N\K{.}\vcvtop\K{\_}t_1\K{x}M\K{\_}\sx\K{\_zero}` ............................................................... -1. Assert: due to :ref:`validation `, a value of :ref:`value type ` |V128| is on the top of the stack. +1. Assert: due to :ref:`syntax `, :math:`N = 2 \cdot M`. -2. Pop the value :math:`\V128.\VCONST~c_1` from the stack. +2. Assert: due to :ref:`validation `, a value of :ref:`value type ` |V128| is on the top of the stack. + +3. Pop the value :math:`\V128.\VCONST~c_1` from the stack. -3. Let :math:`i^\ast` be the sequence :math:`\lanes_{t_1\K{x}M}(c_1)`. +4. Let :math:`i^\ast` be the result of computing :math:`\lanes_{t_1\K{x}M}(c_1)`. -4. Let :math:`j^\ast` be the result of computing :math:`\vcvtop^{\sx}_{|t_1|,|t_2|}(i^\ast)` concatenated with the vector :math:`0^M`. +5. Let :math:`j^\ast` be the result of computing :math:`\vcvtop^{\sx}_{|t_1|,|t_2|}(i^\ast)`. -5. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{t_2\K{x}N}(j^\ast)`. +6. Let :math:`k^\ast` be the concatenation of the two sequences :math:`j^\ast` and :math:`0^M`. -6. Push the value :math:`\V128.\VCONST~c` onto the stack. +7. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{t_2\K{x}N}(k^\ast)`. + +8. Push the value :math:`\V128.\VCONST~c` onto the stack. .. math:: \begin{array}{l} @@ -846,13 +872,21 @@ where: 3. Pop the value :math:`\V128.\VCONST~c_1` from the stack. -4. Let :math:`(i_1~i_2)^\ast` be the result of computing :math:`\imul_{32}(\extends_{16,32}(\lanes_{\I16X8}(c_1)), \extends_{16,32}(\lanes_{\I16X8}(c_2)))`. +4. Let :math:`i_1^\ast` be the result of computing :math:`\lanes_{\I16X8}(c_1)`. -5. Let :math:`j^\ast` be the result of computing :math:`\iadd_{32}(i_1, i_2)^\ast`. +5. Let :math:`j_1^\ast` be the result of computing :math:`\extends_{16,32}(i_1^\ast)`. -6. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{\I32X4}(j^\ast)`. +6. Let :math:`i_2^\ast` be the result of computing :math:`\lanes_{\I16X8}(c_2)`. -7. Push the value :math:`\V128.\VCONST~c` onto the stack. +7. Let :math:`j_2^\ast` be the result of computing :math:`\extends_{16,32}(i_2^\ast)`. + +8. Let :math:`(k_1~k_2)^\ast` be the result of computing :math:`\imul_{32}(j_1^\ast, j_2^\ast)`. + +9. Let :math:`k^\ast` be the result of computing :math:`\iadd_{32}(k_1, k_2)^\ast`. + +10. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{\I32X4}(k^\ast)`. + +11. Push the value :math:`\V128.\VCONST~c` onto the stack. .. math:: \begin{array}{l} @@ -873,27 +907,39 @@ where: :math:`t_2\K{x}N\K{.}\EXTMUL\K{\_}\half\K{\_}t_1\K{x}M\K{\_}\sx` ................................................................ -1. Assert: due to :ref:`validation `, two values of :ref:`value type ` |V128| are on the top of the stack. +1. Assert: due to :ref:`syntax `, :math:`N = M / 2`. -2. Pop the value :math:`\V128.\VCONST~c_2` from the stack. +2. Assert: due to :ref:`validation `, two values of :ref:`value type ` |V128| are on the top of the stack. -3. Pop the value :math:`\V128.\VCONST~c_1` from the stack. +3. Pop the value :math:`\V128.\VCONST~c_2` from the stack. -4. If :math:`\half` is :math:`\K{low}`, then: +4. Pop the value :math:`\V128.\VCONST~c_1` from the stack. - a. Let :math:`i^\ast` be the sequence :math:`\lanes_{t_1\K{x}M}(c_1)[0 \slice N]`. +5. Let :math:`i_1^\ast` be the result of computing :math:`\lanes_{t_1\K{x}M}(c_1)`. - b. Let :math:`j^\ast` be the sequence :math:`\lanes_{t_1\K{x}M}(c_2)[0 \slice N]`. +6. Let :math:`i_2^\ast` be the result of computing :math:`\lanes_{t_1\K{x}M}(c_2)`. -5. Else: +7. If :math:`\half` is :math:`\K{low}`, then: - a. Let :math:`i^\ast` be the sequence :math:`\lanes_{t_1\K{x}M}(c_1)[N \slice N]`. + a. Let :math:`j_1^\ast` be the sequence :math:`i_1^\ast[0 \slice N]`. - b. Let :math:`j^\ast` be the sequence :math:`\lanes_{t_1\K{x}M}(c_2)[N \slice N]`. + b. Let :math:`j_2^\ast` be the sequence :math:`i_2^\ast[0 \slice N]`. -6. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{t_2\K{x}N}(\imul_{t_2\K{x}N}(\extend^{\sx}_{|t_1|,|t_2|}(i^\ast), \extend^{\sx}_{|t_1|,|t_2|}(j^\ast)))`. +8. Else: -7. Push the value :math:`\V128.\VCONST~c` onto the stack. + a. Let :math:`j_1^\ast` be the sequence :math:`i_1^\ast[N \slice N]`. + + b. Let :math:`j_2^\ast` be the sequence :math:`i_2^\ast[N \slice N]`. + +9. Let :math:`k_1^\ast` be the result of computing :math:`\extend^{\sx}_{|t_1|,|t_2|}(j_1^\ast)`. + +10. Let :math:`k_2^\ast` be the result of computing :math:`\extend^{\sx}_{|t_1|,|t_2|}(j_2^\ast)`. + +11. Let :math:`k^\ast` be the result of computing :math:`\imul_{t_2\K{x}N}(k_1^\ast, k_2^\ast)`. + +12. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{t_2\K{x}N}(k^\ast)`. + +13. Push the value :math:`\V128.\VCONST~c` onto the stack. .. math:: \begin{array}{lcl@{\qquad}l} @@ -920,17 +966,21 @@ where: :math:`t_2\K{x}N\K{.}\EXTADDPAIRWISE\_t_1\K{x}M\_\sx` ..................................................... -1. Assert: due to :ref:`validation `, a value of :ref:`value type ` |V128| is on the top of the stack. +1. Assert: due to :ref:`syntax `, :math:`N = M / 2`. -2. Pop the value :math:`\V128.\VCONST~c_1` from the stack. +2. Assert: due to :ref:`validation `, a value of :ref:`value type ` |V128| is on the top of the stack. + +3. Pop the value :math:`\V128.\VCONST~c_1` from the stack. -3. Let :math:`(i_1~i_2)^\ast` be the sequence :math:`\extend^{\sx}_{|t_1|,|t_2|}(\lanes_{t_1\K{x}M}(c_1))`. +4. Let :math:`i^\ast` be the result of computing :math:`\lanes_{t_1\K{x}M}(c_1)`. -4. Let :math:`j^\ast` be the result of computing :math:`\iadd_{N}(i_1, i_2)^\ast`. +5. Let :math:`(j_1~j_2)^\ast` be the result of computing :math:`\extend^{\sx}_{|t_1|,|t_2|}(i^\ast)`. -5. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{t_2\K{x}N}(j^\ast)`. +6. Let :math:`k^\ast` be the result of computing :math:`\iadd_{N}(j_1, j_2)^\ast`. -6. Push the value :math:`\V128.\VCONST~c` to the stack. +7. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{t_2\K{x}N}(k^\ast)`. + +8. Push the value :math:`\V128.\VCONST~c` to the stack. .. math:: \begin{array}{l} @@ -994,9 +1044,9 @@ Parametric Instructions .. math:: \begin{array}{lcl@{\qquad}l} - \val_1~\val_2~(\I32\K{.}\CONST~c)~\SELECT~t^? &\stepto& \val_1 + \val_1~\val_2~(\I32\K{.}\CONST~c)~(\SELECT~t^?) &\stepto& \val_1 & (\iff c \neq 0) \\ - \val_1~\val_2~(\I32\K{.}\CONST~c)~\SELECT~t^? &\stepto& \val_2 + \val_1~\val_2~(\I32\K{.}\CONST~c)~(\SELECT~t^?) &\stepto& \val_2 & (\iff c = 0) \\ \end{array} @@ -1067,7 +1117,7 @@ Variable Instructions 4. Push the value :math:`\val` to the stack. -5. :ref:`Execute ` the instruction :math:`(\LOCALSET~x)`. +5. :ref:`Execute ` the instruction :math:`\LOCALSET~x`. .. math:: \begin{array}{lcl@{\qquad}l} @@ -1290,13 +1340,19 @@ Table Instructions 11. Let :math:`\X{err}` be the |i32| value :math:`2^{32}-1`, for which :math:`\signed_{32}(\X{err})` is :math:`-1`. -12. Either, try :ref:`growing ` :math:`\X{table}` by :math:`n` entries with initialization value :math:`\val`: +12. Either: + + a. If :ref:`growing ` :math:`\X{tab}` by :math:`n` entries with initialization value :math:`\val` succeeds, then: + + i. Push the value :math:`\I32.\CONST~\X{sz}` to the stack. - a. If it succeeds, push the value :math:`\I32.\CONST~\X{sz}` to the stack. + b. Else: - b. Else, push the value :math:`\I32.\CONST~\X{err}` to the stack. + i. Push the value :math:`\I32.\CONST~\X{err}` to the stack. -13. Or, push the value :math:`\I32.\CONST~\X{err}` to the stack. +13. Or: + + a. push the value :math:`\I32.\CONST~\X{err}` to the stack. .. math:: ~\\[-1ex] @@ -1762,7 +1818,7 @@ Memory Instructions 12. Let :math:`W` be the integer :math:`M \cdot 2`. -13. Let :math:`n_k` be the result of :math:`\extend^{\sx}_{M,W}(m_k)`. +13. Let :math:`n_k` be the result of computing :math:`\extend^{\sx}_{M,W}(m_k)`. 14. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{\X{i}W\K{x}N}(n_0 \dots n_{N-1})`. @@ -1878,7 +1934,7 @@ Memory Instructions 11. Let :math:`n` be the integer for which :math:`\bytes_{\iN}(n) = b^\ast`. -12. Let :math:`c` be the result of :math:`\extendu_{N,128}(n)`. +12. Let :math:`c` be the result of computing :math:`\extendu_{N,128}(n)`. 13. Push the value :math:`\V128.\CONST~c` to the stack. @@ -1939,9 +1995,11 @@ Memory Instructions 14. Let :math:`L` be :math:`128 / N`. -15. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{\K{i}N\K{x}L}(\lanes_{\K{i}N\K{x}L}(v) \with [x] = r)`. +15. Let :math:`j^\ast` be the result of computing :math:`\lanes_{\K{i}N\K{x}L}(v)`. + +16. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{\K{i}N\K{x}L}(j^\ast \with [x] = r)`. -16. Push the value :math:`\V128.\CONST~c` to the stack. +17. Push the value :math:`\V128.\CONST~c` to the stack. .. math:: ~\\[-1ex] @@ -2074,9 +2132,11 @@ Memory Instructions 12. Let :math:`L` be :math:`128/N`. -13. Let :math:`b^\ast` be the byte sequence :math:`\bytes_{\iN}(\lanes_{\K{i}N\K{x}L}(c)[x])`. +13. Let :math:`j^\ast` be the result of computing :math:`\lanes_{\K{i}N\K{x}L}(c)`. -14. Replace the bytes :math:`\X{mem}.\MIDATA[\X{ea} \slice N/8]` with :math:`b^\ast`. +14. Let :math:`b^\ast` be the result of computing :math:`\bytes_{\iN}(j^\ast[x])`. + +15. Replace the bytes :math:`\X{mem}.\MIDATA[\X{ea} \slice N/8]` with :math:`b^\ast`. .. math:: ~\\[-1ex] @@ -2152,13 +2212,19 @@ Memory Instructions 9. Let :math:`\X{err}` be the |i32| value :math:`2^{32}-1`, for which :math:`\signed_{32}(\X{err})` is :math:`-1`. -10. Either, try :ref:`growing ` :math:`\X{mem}` by :math:`n` :ref:`pages `: +10. Either: + + a. If :ref:`growing ` :math:`\X{mem}` by :math:`n` :ref:`pages ` succeeds, then: + + i. Push the value :math:`\I32.\CONST~\X{sz}` to the stack. + + b. Else: - a. If it succeeds, push the value :math:`\I32.\CONST~\X{sz}` to the stack. + i. Push the value :math:`\I32.\CONST~\X{err}` to the stack. - b. Else, push the value :math:`\I32.\CONST~\X{err}` to the stack. +11. Or: -11. Or, push the value :math:`\I32.\CONST~\X{err}` to the stack. + a. Push the value :math:`\I32.\CONST~\X{err}` to the stack. .. math:: ~\\[-1ex] @@ -2599,11 +2665,11 @@ Control Instructions 3. If :math:`c` is non-zero, then: - a. Execute the block instruction :math:`\BLOCK~\X{bt}~\instr_1^\ast~\END`. + a. Execute the block instruction :math:`\BLOCK~\blocktype~\instr_1^\ast~\END`. 4. Else: - a. Execute the block instruction :math:`\BLOCK~\X{bt}~\instr_2^\ast~\END`. + a. Execute the block instruction :math:`\BLOCK~\blocktype~\instr_2^\ast~\END`. .. math:: ~\\[-1ex] @@ -2664,7 +2730,7 @@ Control Instructions 3. If :math:`c` is non-zero, then: - a. :ref:`Execute ` the instruction :math:`(\BR~l)`. + a. :ref:`Execute ` the instruction :math:`\BR~l`. 4. Else: @@ -2693,11 +2759,11 @@ Control Instructions a. Let :math:`l_i` be the label :math:`l^\ast[i]`. - b. :ref:`Execute ` the instruction :math:`(\BR~l_i)`. + b. :ref:`Execute ` the instruction :math:`\BR~l_i`. 4. Else: - a. :ref:`Execute ` the instruction :math:`(\BR~l_N)`. + a. :ref:`Execute ` the instruction :math:`\BR~l_N`. .. math:: ~\\[-1ex] From 2a992ec2d30b0a7f0533ebdb5fe0cd7eb42553ca Mon Sep 17 00:00:00 2001 From: Tethys Svensson Date: Sun, 9 Apr 2023 01:10:38 +0200 Subject: [PATCH 066/132] [spec] Fix xref (#1639) --- document/core/valid/modules.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/document/core/valid/modules.rst b/document/core/valid/modules.rst index 4c8e7b6d..6ce934c0 100644 --- a/document/core/valid/modules.rst +++ b/document/core/valid/modules.rst @@ -151,7 +151,7 @@ Element segments :math:`\elem` are classified by the :ref:`reference type ` with some :ref:`result type ` :math:`[t]`. - * The expression :math:`e_i` must be :ref:`constant `. + * The expression :math:`e_i` must be :ref:`constant `. * The element mode :math:`\elemmode` must be valid with :ref:`reference type ` :math:`t`. From 57858284fb6044643a50eccab283262731294d5d Mon Sep 17 00:00:00 2001 From: Ioanna M Dimitriou H <9728696+ioannad@users.noreply.github.com> Date: Wed, 12 Apr 2023 16:13:56 +0200 Subject: [PATCH 067/132] Added Exception Handling entry to `document/core/appendix/changes.rst` (#267) Co-authored-by: Andreas Rossberg --- document/core/appendix/changes.rst | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/document/core/appendix/changes.rst b/document/core/appendix/changes.rst index 339cb25f..16ea3ff7 100644 --- a/document/core/appendix/changes.rst +++ b/document/core/appendix/changes.rst @@ -138,6 +138,22 @@ Added vector type and instructions that manipulate multiple numeric values in pa * New injection/projection :ref:`vector instructions `: :math:`\K{i}\!N\!\K{x}\!M\!\K{.splat}`, :math:`\K{f}\!N\!\K{x}\!M\!\K{.splat}`, :math:`\K{i}\!N\!\K{x}\!M\!\K{.bitmask}` +.. index:: instructions, exception, tag type, tag, handler + +Exception Handling +.................. + +Added tag definitions, imports, and exports, and instructions to throw and catch exceptions [#proposal-exceptions]_ + +* Modules may :ref:`define `, :ref:`import `, and :ref:`export ` tags. + +* New exception throwing :ref:`control instructions `: :math:`\THROW` and :math:`\RETHROW`. + +* New handler :ref:`control instructions `: :math:`(\TRY~\X{bt}~\instr_1^\ast~(\CATCH~x~\instr_2^\ast)^\ast~(\CATCHALL~\instr_3^\ast)^?\END)` and :math:`(\TRY~\X{bt}~\instr^\ast~\DELEGATE~l)`. + +* New :ref:`tag section ` in binary format. + + .. [#proposal-signext] https://github.com/WebAssembly/spec/tree/main/proposals/sign-extension-ops/ @@ -155,3 +171,6 @@ Added vector type and instructions that manipulate multiple numeric values in pa .. [#proposal-vectype] https://github.com/WebAssembly/spec/tree/main/proposals/simd/ + +.. [#proposal-exceptions] + https://github.com/WebAssembly/spec/tree/main/proposals/exception-handling/ From c2b3446682f79de5c0c676960b8380c1b9c924ae Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 17 Apr 2023 11:50:34 -0700 Subject: [PATCH 068/132] [test] Add test for table elems initialized by imported global funcref (#1641) Fixes: #1640 --- test/core/elem.wast | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/core/elem.wast b/test/core/elem.wast index 5857ae8b..4a399eca 100644 --- a/test/core/elem.wast +++ b/test/core/elem.wast @@ -675,3 +675,26 @@ (assert_return (invoke $m "get" (i32.const 0)) (ref.null extern)) (assert_return (invoke $m "get" (i32.const 1)) (ref.extern 137)) + +;; Initializing a table with imported funcref global + +(module $module4 + (func (result i32) + i32.const 42 + ) + (global (export "f") funcref (ref.func 0)) +) + +(register "module4" $module4) + +(module + (import "module4" "f" (global funcref)) + (type $out-i32 (func (result i32))) + (table 10 funcref) + (elem (offset (i32.const 0)) funcref (global.get 0)) + (func (export "call_imported_elem") (type $out-i32) + (call_indirect (type $out-i32) (i32.const 0)) + ) +) + +(assert_return (invoke "call_imported_elem") (i32.const 42)) From 24440acdc1e0e586fe74fd4ae001818513a9bb8a Mon Sep 17 00:00:00 2001 From: Ioanna M Dimitriou H <9728696+ioannad@users.noreply.github.com> Date: Fri, 21 Apr 2023 15:24:01 +0200 Subject: [PATCH 069/132] Adds validation for exception results. (#254) Co-authored-by: Andreas Rossberg --- document/core/appendix/properties.rst | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/document/core/appendix/properties.rst b/document/core/appendix/properties.rst index 1f3c1dfa..8ecba539 100644 --- a/document/core/appendix/properties.rst +++ b/document/core/appendix/properties.rst @@ -58,8 +58,27 @@ Results S \vdashresult \TRAP : [t^\ast] } -.. todo:: - Add validation for exception results. + +:ref:`Results ` :math:`\val^\ast~(\THROWadm~\tagaddr)` +..................................................................... + +* The :ref:`external tag value ` :math:`\EVTAG~\tagaddr` must be :ref:`valid ` with :ref:`external tag type ` :math:`\ETTAG~[t^\ast]\to[]`. + +* For each :ref:`value ` :math:`\val_i` in :math:`\val^\ast` and corresponding :ref:`value type ` :math:`t_i` in :math:`t_i`: + + * The value :math:`\val_i` must be :ref:`valid ` with :ref:`value type ` :math:`t_i`. + +* Then the result is valid with :ref:`result type ` :math:`[{t'}^\ast]`, for any sequence :math:`{t'}^\ast` of :ref:`value types `. + + +.. math:: + \frac{ + S \vdashexternval \EVTAG~\tagaddr : \ETTAG~[t^\ast] \to [] + \qquad + (S \vdashval \val : t)^\ast + }{ + S \vdashresult \val^\ast~(\THROWadm~\tagaddr) : [{t'}^\ast] + } .. _module-context: From 35b435a096abe04b04dc5235bb14cec8c3aecffc Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Sun, 23 Apr 2023 15:59:51 +0900 Subject: [PATCH 070/132] [interpreter] Update README.md for EH instructions (#272) --- interpreter/README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/interpreter/README.md b/interpreter/README.md index fc2a1827..30e044af 100644 --- a/interpreter/README.md +++ b/interpreter/README.md @@ -203,6 +203,7 @@ func_type: ( type )? * * global_type: | ( mut ) table_type: ? memory_type: ? +tag_type: ( type )? * num: | var: | @@ -231,6 +232,8 @@ expr: ( loop ? * ) ( if ? ( then * ) ( else * )? ) ( if ? + ( then * ) ( else * )? ) ;; = + (if ? (then *) (else *)?) + ( try ? ( do * ) ( catch * )* ( catch_all * )? ) + ( try ? ( do * ) ( delegate ) ) instr: @@ -239,6 +242,9 @@ instr: loop ? * end ? ;; = (loop ? *) if ? * end ? ;; = (if ? (then *)) if ? * else ? * end ? ;; = (if ? (then *) (else *)) + try ? * (catch ? *)* (catch_all ? *)? end ? + ;; = (try ? (do *) (catch *)* (catch_all *)?) + try ? * delegate ;; = (try ? (do *) (delegate )) op: unreachable @@ -279,6 +285,8 @@ op: ref.null ref.is_null ref.func + throw + rethrow .const . . @@ -404,6 +412,7 @@ assertion: ( assert_return * ) ;; assert action has expected results ( assert_trap ) ;; assert action traps with given failure string ( assert_exhaustion ) ;; assert action exhausts system resources + ( assert_exception ) ;; assert action throws an exception ( assert_malformed ) ;; assert module cannot be decoded with given failure string ( assert_invalid ) ;; assert module is invalid with given failure string ( assert_unlinkable ) ;; assert module fails to link @@ -495,6 +504,7 @@ assertion: ( assert_return * ) ;; assert action has expected results ( assert_trap ) ;; assert action traps with given failure string ( assert_exhaustion ) ;; assert action exhausts system resources + ( assert_exception ) ;; assert action throws an exception ( assert_malformed ) ;; assert module cannot be decoded with given failure string ( assert_invalid ) ;; assert module is invalid with given failure string ( assert_unlinkable ) ;; assert module fails to link From e15eb4194e0f29cfdf26e9c96243abc9b4380c90 Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Sun, 23 Apr 2023 16:37:52 +0900 Subject: [PATCH 071/132] [interpreter] Cherry-pick tail call support (#274) This cherry-picks interpreter changes from https://github.com/WebAssembly/tail-call to run spec tests that mix `try`s with `return_call(_indirect)`s (#275). When tail-call is merged to the main spec repo, we can revert this change and merge the upstream spec. This also adds missing handling for `ReturningInvoke` in the new `Catch`/`Caught`/`Delegate` instructions in the evaluator. --- interpreter/binary/decode.ml | 7 ++++++- interpreter/binary/encode.ml | 2 ++ interpreter/exec/eval.ml | 32 ++++++++++++++++++++++++++++---- interpreter/syntax/ast.ml | 2 ++ interpreter/syntax/free.ml | 5 +++-- interpreter/syntax/operators.ml | 2 ++ interpreter/text/arrange.ml | 3 +++ interpreter/text/lexer.mll | 2 ++ interpreter/text/parser.mly | 16 +++++++++++++++- interpreter/valid/valid.ml | 11 +++++++++++ 10 files changed, 74 insertions(+), 8 deletions(-) diff --git a/interpreter/binary/decode.ml b/interpreter/binary/decode.ml index f5e4edf9..88551a15 100644 --- a/interpreter/binary/decode.ml +++ b/interpreter/binary/decode.ml @@ -303,8 +303,13 @@ let rec instr s = let y = at var s in let x = at var s in call_indirect x y + | 0x12 -> return_call (at var s) + | 0x13 -> + let y = at var s in + let x = at var s in + return_call_indirect x y - | 0x12 | 0x13 | 0x14 | 0x15 | 0x16 | 0x17 as b -> illegal s pos b + | 0x14 | 0x15 | 0x16 | 0x17 as b -> illegal s pos b | 0x18 -> error s pos "misplaced DELEGATE opcode" | 0x19 -> error s pos "misplaced CATCH_ALL opcode" diff --git a/interpreter/binary/encode.ml b/interpreter/binary/encode.ml index 7e59a2f1..50ee0000 100644 --- a/interpreter/binary/encode.ml +++ b/interpreter/binary/encode.ml @@ -187,6 +187,8 @@ struct | Return -> op 0x0f | Call x -> op 0x10; var x | CallIndirect (x, y) -> op 0x11; var y; var x + | ReturnCall x -> op 0x12; var x + | ReturnCallIndirect (x, y) -> op 0x13; var y; var x | Throw x -> op 0x08; var x | Rethrow x -> op 0x09; var x diff --git a/interpreter/exec/eval.ml b/interpreter/exec/eval.ml index 97b11362..56834621 100644 --- a/interpreter/exec/eval.ml +++ b/interpreter/exec/eval.ml @@ -63,6 +63,7 @@ and admin_instr' = | Invoke of func_inst | Trapping of string | Returning of value stack + | ReturningInvoke of value stack * func_inst | Breaking of int32 * value stack | Throwing of Tag.t * value stack | Rethrowing of int32 * (admin_instr -> admin_instr) @@ -214,6 +215,21 @@ let rec step (c : config) : config = else vs, [Invoke func @@ e.at] + | ReturnCall x, vs -> + (match (step {c with code = (vs, [Plain (Call x) @@ e.at])}).code with + | vs', [{it = Invoke a; at}] -> vs', [ReturningInvoke (vs', a) @@ at] + | _ -> assert false + ) + + | ReturnCallIndirect (x, y), vs -> + (match + (step {c with code = (vs, [Plain (CallIndirect (x, y)) @@ e.at])}).code + with + | vs', [{it = Invoke a; at}] -> vs', [ReturningInvoke (vs', a) @@ at] + | vs', [{it = Trapping s; at}] -> vs', [Trapping s @@ at] + | _ -> assert false + ) + | Throw x, vs -> let t = tag frame.inst x in let FuncType (ts, _) = Tag.type_of t in @@ -629,7 +645,8 @@ let rec step (c : config) : config = | Trapping msg, vs -> assert false - | Returning vs', vs -> + | Returning _, vs + | ReturningInvoke _, vs -> Crash.error e.at "undefined frame" | Breaking (k, vs'), vs -> @@ -653,6 +670,9 @@ let rec step (c : config) : config = | Label (n, es0, (vs', {it = Returning vs0; at} :: es')), vs -> vs, [Returning vs0 @@ at] + | Label (n, es0, (vs', {it = ReturningInvoke (vs0, f); at} :: es')), vs -> + vs, [ReturningInvoke (vs0, f) @@ at] + | Label (n, es0, (vs', {it = Breaking (0l, vs0); at} :: es')), vs -> take n vs0 e.at @ vs, List.map plain es0 @@ -684,6 +704,10 @@ let rec step (c : config) : config = | Frame (n, frame', (vs', {it = Returning vs0; at} :: es')), vs -> take n vs0 e.at @ vs, [] + | Frame (n, frame', (vs', {it = ReturningInvoke (vs0, f); at} :: es')), vs -> + let FuncType (ins, out) = Func.type_of f in + take (Lib.List32.length ins) vs0 e.at @ vs, [Invoke f @@ at] + | Frame (n, frame', (vs', {it = Throwing (a, vs0); at} :: es')), vs -> vs, [Throwing (a, vs0) @@ at] @@ -694,7 +718,7 @@ let rec step (c : config) : config = | Catch (n, cts, ca, (vs', [])), vs -> vs' @ vs, [] - | Catch (n, cts, ca, (vs', ({it = Trapping _ | Breaking _ | Returning _ | Delegating _; at} as e) :: es')), vs -> + | Catch (n, cts, ca, (vs', ({it = Trapping _ | Breaking _ | Returning _ | ReturningInvoke _ | Delegating _; at} as e) :: es')), vs -> vs, [e] | Catch (n, cts, ca, (vs', {it = Rethrowing (k, cont); at} :: es')), vs -> @@ -719,7 +743,7 @@ let rec step (c : config) : config = | Caught (n, a, vs0, (vs', [])), vs -> vs' @ vs, [] - | Caught (n, a, vs0, (vs', ({it = Trapping _ | Breaking _ | Returning _ | Throwing _ | Delegating _; at} as e) :: es')), vs -> + | Caught (n, a, vs0, (vs', ({it = Trapping _ | Breaking _ | Returning _ | ReturningInvoke _ | Throwing _ | Delegating _; at} as e) :: es')), vs -> vs, [e] | Caught (n, a, vs0, (vs', {it = Rethrowing (0l, cont); at} :: es')), vs -> @@ -735,7 +759,7 @@ let rec step (c : config) : config = | Delegate (l, (vs', [])), vs -> vs' @ vs, [] - | Delegate (l, (vs', ({it = Trapping _ | Breaking _ | Returning _ | Rethrowing _ | Delegating _; at} as e) :: es')), vs -> + | Delegate (l, (vs', ({it = Trapping _ | Breaking _ | Returning _ | ReturningInvoke _ | Rethrowing _ | Delegating _; at} as e) :: es')), vs -> vs, [e] | Delegate (l, (vs', {it = Throwing (a, vs0); at} :: es')), vs -> diff --git a/interpreter/syntax/ast.ml b/interpreter/syntax/ast.ml index b1750ee3..4a717781 100644 --- a/interpreter/syntax/ast.ml +++ b/interpreter/syntax/ast.ml @@ -149,6 +149,8 @@ and instr' = | Return (* break from function body *) | Call of var (* call function *) | CallIndirect of var * var (* call function through table *) + | ReturnCall of var (* tail-call function *) + | ReturnCallIndirect of var * var (* tail-call function through table *) | LocalGet of var (* read local variable *) | LocalSet of var (* write local variable *) | LocalTee of var (* write local variable and keep value *) diff --git a/interpreter/syntax/free.ml b/interpreter/syntax/free.ml index 774b2d03..fdc5f363 100644 --- a/interpreter/syntax/free.ml +++ b/interpreter/syntax/free.ml @@ -79,8 +79,9 @@ let rec instr (e : instr) = | Br x | BrIf x -> labels (var x) | BrTable (xs, x) -> list (fun x -> labels (var x)) (x::xs) | Return -> empty - | Call x -> funcs (var x) - | CallIndirect (x, y) -> tables (var x) ++ types (var y) + | Call x | ReturnCall x -> funcs (var x) + | CallIndirect (x, y) | ReturnCallIndirect (x, y) -> + tables (var x) ++ types (var y) | LocalGet x | LocalSet x | LocalTee x -> locals (var x) | GlobalGet x | GlobalSet x -> globals (var x) | TableGet x | TableSet x | TableSize x | TableGrow x | TableFill x -> diff --git a/interpreter/syntax/operators.ml b/interpreter/syntax/operators.ml index bb44e4f9..487c3051 100644 --- a/interpreter/syntax/operators.ml +++ b/interpreter/syntax/operators.ml @@ -29,6 +29,8 @@ let br_table xs x = BrTable (xs, x) let return = Return let call x = Call x let call_indirect x y = CallIndirect (x, y) +let return_call x = ReturnCall x +let return_call_indirect x y = ReturnCallIndirect (x, y) let throw x = Throw x let rethrow x = Rethrow x diff --git a/interpreter/text/arrange.ml b/interpreter/text/arrange.ml index 76e14bba..ba3f2bcf 100644 --- a/interpreter/text/arrange.ml +++ b/interpreter/text/arrange.ml @@ -453,6 +453,9 @@ let rec instr e = | Call x -> "call " ^ var x, [] | CallIndirect (x, y) -> "call_indirect " ^ var x, [Node ("type " ^ var y, [])] + | ReturnCall x -> "return_call " ^ var x, [] + | ReturnCallIndirect (x, y) -> + "return_call_indirect " ^ var x, [Node ("type " ^ var y, [])] | LocalGet x -> "local.get " ^ var x, [] | LocalSet x -> "local.set " ^ var x, [] | LocalTee x -> "local.tee " ^ var x, [] diff --git a/interpreter/text/lexer.mll b/interpreter/text/lexer.mll index 9c709b13..9a7a5482 100644 --- a/interpreter/text/lexer.mll +++ b/interpreter/text/lexer.mll @@ -168,6 +168,8 @@ rule token = parse | "select" -> SELECT | "call" -> CALL | "call_indirect" -> CALL_INDIRECT + | "return_call" -> RETURN_CALL + | "return_call_indirect" -> RETURN_CALL_INDIRECT | "local.get" -> LOCAL_GET | "local.set" -> LOCAL_SET diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly index af25869c..806ee509 100644 --- a/interpreter/text/parser.mly +++ b/interpreter/text/parser.mly @@ -218,7 +218,7 @@ let inline_type_explicit (c : context) x ft at = %token UNREACHABLE NOP DROP SELECT %token BLOCK END IF THEN ELSE LOOP BR BR_IF BR_TABLE TRY DO CATCH CATCH_ALL %token DELEGATE -%token CALL CALL_INDIRECT RETURN +%token CALL CALL_INDIRECT RETURN RETURN_CALL RETURN_CALL_INDIRECT %token LOCAL_GET LOCAL_SET LOCAL_TEE GLOBAL_GET GLOBAL_SET %token TABLE_GET TABLE_SET %token TABLE_SIZE TABLE_GROW TABLE_FILL TABLE_COPY TABLE_INIT ELEM_DROP @@ -395,6 +395,7 @@ plain_instr : br_table xs x } | RETURN { fun c -> return } | CALL var { fun c -> call ($2 c func) } + | RETURN_CALL var { fun c -> return_call ($2 c func) } | THROW var { fun c -> throw ($2 c tag) } | RETHROW var { fun c -> rethrow ($2 c label) } | LOCAL_GET var { fun c -> local_get ($2 c local) } @@ -477,6 +478,14 @@ call_instr_instr_list : { let at1 = ati 1 in fun c -> let x, es = $2 c in (call_indirect (0l @@ at1) x @@ at1) :: es } + | RETURN_CALL_INDIRECT var call_instr_type_instr_list + { let at1 = ati 1 in + fun c -> let x, es = $3 c in + (return_call_indirect ($2 c table) x @@ at1) :: es } + | RETURN_CALL_INDIRECT call_instr_type_instr_list /* Sugar */ + { let at1 = ati 1 in + fun c -> let x, es = $2 c in + (return_call_indirect (0l @@ at1) x @@ at1) :: es } call_instr_type_instr_list : | type_use call_instr_params_instr_list @@ -600,6 +609,11 @@ expr1 : /* Sugar */ | CALL_INDIRECT call_expr_type /* Sugar */ { let at1 = ati 1 in fun c -> let x, es = $2 c in es, call_indirect (0l @@ at1) x } + | RETURN_CALL_INDIRECT var call_expr_type + { fun c -> let x, es = $3 c in es, return_call_indirect ($2 c table) x } + | RETURN_CALL_INDIRECT call_expr_type /* Sugar */ + { let at1 = ati 1 in + fun c -> let x, es = $2 c in es, return_call_indirect (0l @@ at1) x } | BLOCK labeling_opt block { fun c -> let c' = $2 c [] in let bt, es = $3 c' in [], block bt es } | LOOP labeling_opt block diff --git a/interpreter/valid/valid.ml b/interpreter/valid/valid.ml index 34707dbd..f6d8a921 100644 --- a/interpreter/valid/valid.ml +++ b/interpreter/valid/valid.ml @@ -302,6 +302,17 @@ let rec check_instr (c : context) (e : instr) (s : infer_result_type) : op_type " but table has " ^ string_of_ref_type t); (ts1 @ [NumType I32Type]) --> ts2 + | ReturnCall x -> + let FuncType (ins, out) = func c x in + require (out = c.results) e.at "type mismatch in function result"; + ins -->... [] + + | ReturnCallIndirect (x, y) -> + let TableType (lim, t) = table c x in + let FuncType (ins, out) = type_ c y in + require (out = c.results) e.at "type mismatch in function result"; + (ins @ [NumType I32Type]) -->... [] + | Throw x -> let TagType y = tag c x in let FuncType (ts1, _) = type_ c (y @@ e.at) in From 36a364c010b2d4c5845b473d3161b858f01b3955 Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Sun, 23 Apr 2023 19:26:54 +0900 Subject: [PATCH 072/132] [test] Add tests for return_call(_indirect) in try (#275) This adds tests of `return_call(_indirect)`s within `try`s. Because this repo's interpreter doesn't have the tail call support, this requires #274 to be merged before merging. These test also needs `--experimental-wasm-return_call` to `node` argument in the CI to pass. --- .github/workflows/ci-interpreter.yml | 2 +- test/core/try_catch.wast | 23 +++++++++++++++++++ test/core/try_delegate.wast | 33 ++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci-interpreter.yml b/.github/workflows/ci-interpreter.yml index 6edfa0c4..297abc7f 100644 --- a/.github/workflows/ci-interpreter.yml +++ b/.github/workflows/ci-interpreter.yml @@ -31,4 +31,4 @@ jobs: - name: Build interpreter run: cd interpreter && opam exec make - name: Run tests - run: cd interpreter && opam exec make JS=node ci + run: cd interpreter && opam exec make JS='node --experimental-wasm-return_call' ci diff --git a/test/core/try_catch.wast b/test/core/try_catch.wast index 6564e201..2a0e9ff6 100644 --- a/test/core/try_catch.wast +++ b/test/core/try_catch.wast @@ -147,6 +147,26 @@ (catch $e0 (i32.const 1)) ) ) + + (func $throw-void (throw $e0)) + (func (export "return-call-in-try-catch") + (try + (do + (return_call $throw-void) + ) + (catch $e0) + ) + ) + + (table funcref (elem $throw-void)) + (func (export "return-call-indirect-in-try-catch") + (try + (do + (return_call_indirect (param) (i32.const 0)) + ) + (catch $e0) + ) + ) ) (assert_return (invoke "empty-catch")) @@ -188,6 +208,9 @@ (assert_return (invoke "catchless-try" (i32.const 0)) (i32.const 0)) (assert_return (invoke "catchless-try" (i32.const 1)) (i32.const 1)) +(assert_exception (invoke "return-call-in-try-catch")) +(assert_exception (invoke "return-call-indirect-in-try-catch")) + (module (func $imported-throw (import "test" "throw")) (tag $e0) diff --git a/test/core/try_delegate.wast b/test/core/try_delegate.wast index 8ee864eb..aae3a301 100644 --- a/test/core/try_delegate.wast +++ b/test/core/try_delegate.wast @@ -115,6 +115,36 @@ (delegate $l3)))) unreachable) (catch_all (i32.const 1)))) + + (func $throw-void (throw $e0)) + (func (export "return-call-in-try-delegate") + (try $l + (do + (try + (do + (return_call $throw-void) + ) + (delegate $l) + ) + ) + (catch $e0) + ) + ) + + (table funcref (elem $throw-void)) + (func (export "return-call-indirect-in-try-delegate") + (try $l + (do + (try + (do + (return_call_indirect (param) (i32.const 0)) + ) + (delegate $l) + ) + ) + (catch $e0) + ) + ) ) (assert_return (invoke "delegate-no-throw") (i32.const 1)) @@ -140,6 +170,9 @@ (assert_return (invoke "delegate-correct-targets") (i32.const 1)) +(assert_exception (invoke "return-call-in-try-delegate")) +(assert_exception (invoke "return-call-indirect-in-try-delegate")) + (assert_malformed (module quote "(module (func (delegate 0)))") "unexpected token" From 2768002d30a6726c0383d5cc747ce8f18133d294 Mon Sep 17 00:00:00 2001 From: SoniEx2 Date: Sun, 23 Apr 2023 09:34:33 -0300 Subject: [PATCH 073/132] Test that throw is polymorphic --- test/core/throw.wast | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/core/throw.wast b/test/core/throw.wast index d53b5b55..2148d5ea 100644 --- a/test/core/throw.wast +++ b/test/core/throw.wast @@ -20,6 +20,10 @@ (func (export "throw-param-f64") (param f64) (local.get 0) (throw $e-f64)) + (func (export "throw-polymorphic") (throw $e0) (throw $e-i32)) + + (func (export "throw-polymorphic-block") (block (result i32) (throw $e0)) (throw $e-i32)) + (func $throw-1-2 (i32.const 1) (i32.const 2) (throw $e-i32-i32)) (func (export "test-throw-1-2") (try @@ -42,6 +46,9 @@ (assert_exception (invoke "throw-param-i64" (i64.const 5))) (assert_exception (invoke "throw-param-f64" (f64.const 5.0))) +(assert_exception (invoke "throw-polymorphic")) +(assert_exception (invoke "throw-polymorphic-block")) + (assert_return (invoke "test-throw-1-2")) (assert_invalid (module (func (throw 0))) "unknown tag 0") From 899ce6695d6555e1f3b9cdf3883bdbd2e8936372 Mon Sep 17 00:00:00 2001 From: Thomas Steiner Date: Mon, 24 Apr 2023 14:19:17 +0200 Subject: [PATCH 074/132] [js-api] Editorial: add grouping separators to limit values (#1643) --- document/js-api/index.bs | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/document/js-api/index.bs b/document/js-api/index.bs index c085e583..e31e47ab 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -1191,31 +1191,31 @@ An implementation must reject a module that exceeds one of the following limits In practice, an implementation may run out of resources for valid modules below these limits.
    -
  • The maximum size of a module is 1073741824 bytes (1 GiB).
  • -
  • The maximum number of types defined in the types section is 1000000.
  • -
  • The maximum number of functions defined in a module is 1000000.
  • -
  • The maximum number of imports declared in a module is 100000.
  • -
  • The maximum number of exports declared in a module is 100000.
  • -
  • The maximum number of globals defined in a module is 1000000.
  • -
  • The maximum number of data segments defined in a module is 100000.
  • - -
  • The maximum number of tables, including declared or imported tables, is 100000.
  • -
  • The maximum size of a table is 10000000.
  • -
  • The maximum number of table entries in any table initialization is 10000000.
  • +
  • The maximum size of a module is 1,073,741,824 bytes (1 GiB).
  • +
  • The maximum number of types defined in the types section is 1,000,000.
  • +
  • The maximum number of functions defined in a module is 1,000,000.
  • +
  • The maximum number of imports declared in a module is 100,000.
  • +
  • The maximum number of exports declared in a module is 100,000.
  • +
  • The maximum number of globals defined in a module is 1,000,000.
  • +
  • The maximum number of data segments defined in a module is 100,000.
  • + +
  • The maximum number of tables, including declared or imported tables, is 100,000.
  • +
  • The maximum size of a table is 10,000,000.
  • +
  • The maximum number of table entries in any table initialization is 10,000,000.
  • The maximum number of memories, including declared or imported memories, is 1.
  • -
  • The maximum number of parameters to any function or block is 1000.
  • -
  • The maximum number of return values for any function or block is 1000.
  • -
  • The maximum size of a function body, including locals declarations, is 7654321 bytes.
  • -
  • The maximum number of locals declared in a function, including implicitly declared as parameters, is 50000.
  • +
  • The maximum number of parameters to any function or block is 1,000.
  • +
  • The maximum number of return values for any function or block is 1,000.
  • +
  • The maximum size of a function body, including locals declarations, is 7,654,321 bytes.
  • +
  • The maximum number of locals declared in a function, including implicitly declared as parameters, is 50,000.
An implementation must throw a {{RuntimeError}} if one of the following limits is exceeded during runtime: In practice, an implementation may run out of resources for valid modules below these limits.
    -
  • The maximum size of a table is 10000000.
  • -
  • The maximum number of pages of a memory is 65536.
  • +
  • The maximum size of a table is 10,000,000.
  • +
  • The maximum number of pages of a memory is 65,536.

Security and Privacy Considerations

From 4e16278b2abef667c0154d3c0ceb53f8d2531a95 Mon Sep 17 00:00:00 2001 From: Harry Chiang Date: Wed, 26 Apr 2023 20:19:47 +0800 Subject: [PATCH 075/132] [docs] Fix typo (#279) --- document/core/exec/runtime.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/document/core/exec/runtime.rst b/document/core/exec/runtime.rst index 443ee150..9acda299 100644 --- a/document/core/exec/runtime.rst +++ b/document/core/exec/runtime.rst @@ -461,7 +461,7 @@ Stack ~~~~~ Besides the :ref:`store `, most :ref:`instructions ` interact with an implicit *stack*. -The stack contains three kinds of entries: +The stack contains five kinds of entries: * *Values*: the *operands* of instructions. From 49e87dc14e5e018bc30cb07d4ba54d6501f4de68 Mon Sep 17 00:00:00 2001 From: Keith Winstein Date: Thu, 27 Apr 2023 01:45:50 -0700 Subject: [PATCH 076/132] [test] Add test for init expr with missing end marker (#1645) --- test/core/binary.wast | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/core/binary.wast b/test/core/binary.wast index 526e0a20..4e748e70 100644 --- a/test/core/binary.wast +++ b/test/core/binary.wast @@ -470,6 +470,19 @@ "section size mismatch" ) +;; Init expression with missing end marker +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\01\04\01\60\00\00" ;; Type section: 1 type + "\03\02\01\00" ;; Function section: 1 function + "\06\05\01\7f\00\41\00" ;; Global section: 1 entry with missing end marker + ;; Missing end marker here + "\0a\04\01\02\00\0b" ;; Code section: 1 function + ) + "illegal opcode" +) + ;; Unsigned LEB128 must not be overlong (assert_malformed (module binary From dec27387d723ab7da2667f0dc36dd117eba844d9 Mon Sep 17 00:00:00 2001 From: gahaas Date: Tue, 2 May 2023 07:24:28 +0200 Subject: [PATCH 077/132] Add test for the module size limit (#1642) * Add test for the module size limit The limits test did not test the maximum supported module size of 1GB yet. This PR adds tests which create modules consisting of a single custom section. The first test checks if a module of size 1GB is allowed, the second test checks that a module of size 1GB + 1 byte gets rejected. * Some cleanup --- test/js-api/limits.any.js | 50 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/test/js-api/limits.any.js b/test/js-api/limits.any.js index 7e690cad..91f058d6 100644 --- a/test/js-api/limits.any.js +++ b/test/js-api/limits.any.js @@ -244,3 +244,53 @@ test(() => { () => memory.grow(kJSEmbeddingMaxTableSize)); }, `Grow WebAssembly.Table object beyond the embedder-defined limit`); +function testModuleSizeLimit(size, expectPass) { + // We do not use `testLimit` here to avoid OOMs due to having multiple big + // modules alive at the same time. + + // Define a WebAssembly module that consists of a single custom section which + // has an empty name. The module size will be `size`. + const buffer = new Uint8Array(size); + const header = [ + kWasmH0, kWasmH1, kWasmH2, kWasmH3, // magic word + kWasmV0, kWasmV1, kWasmV2, kWasmV3, // version + 0 // custom section + ]; + // We calculate the section length so that the total module size is `size`. + // For that we have to calculate the length of the leb encoding of the section + // length. + const sectionLength = size - header.length - + wasmSignedLeb(size).length; + const lengthBytes = wasmSignedLeb(sectionLength); + buffer.set(header); + buffer.set(lengthBytes, header.length); + + if (expectPass) { + test(() => { + assert_true(WebAssembly.validate(buffer)); + }, `Validate module size limit`); + test(() => { + new WebAssembly.Module(buffer); + }, `Compile module size limit`); + promise_test(t => { + return WebAssembly.compile(buffer); + }, `Async compile module size limit`); + } else { + test(() => { + assert_false(WebAssembly.validate(buffer)); + }, `Validate module size over limit`); + test(() => { + assert_throws( + new WebAssembly.CompileError(), + () => new WebAssembly.Module(buffer)); + }, `Compile module size over limit`); + promise_test(t => { + return promise_rejects( + t, new WebAssembly.CompileError(), + WebAssembly.compile(buffer)); + }, `Async compile module size over limit`); + } +} + +testModuleSizeLimit(kJSEmbeddingMaxModuleSize, true); +testModuleSizeLimit(kJSEmbeddingMaxModuleSize + 1, false); From b72a1aae7f1a44e16178541b3107e49fba91cfe6 Mon Sep 17 00:00:00 2001 From: Clemens Backes Date: Wed, 10 May 2023 16:20:24 +0200 Subject: [PATCH 078/132] [test] Disable tests that become valid with memory64 (#1648) --- test/core/binary.wast | 237 ++++++++++++++++++++++-------------------- 1 file changed, 122 insertions(+), 115 deletions(-) diff --git a/test/core/binary.wast b/test/core/binary.wast index 4e748e70..1aae74aa 100644 --- a/test/core/binary.wast +++ b/test/core/binary.wast @@ -492,25 +492,27 @@ ) "integer representation too long" ) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\11\01" ;; Code section - ;; function 0 - "\0f\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\28" ;; i32.load - "\02" ;; alignment 2 - "\82\80\80\80\80\00" ;; offset 2 with one byte too many - "\1a" ;; drop - "\0b" ;; end - ) - "integer representation too long" -) +;; The memory offset will be decoded as u64 in the memory64 proposal. +;; TODO: Re-enable this test as assert_trap test in the memory64 repo. +;; (assert_malformed +;; (module binary +;; "\00asm" "\01\00\00\00" +;; "\01\04\01\60\00\00" ;; Type section +;; "\03\02\01\00" ;; Function section +;; "\05\03\01\00\01" ;; Memory section +;; "\0a\11\01" ;; Code section +;; ;; function 0 +;; "\0f\01\01" ;; local type count +;; "\7f" ;; i32 +;; "\41\00" ;; i32.const 0 +;; "\28" ;; i32.load +;; "\02" ;; alignment 2 +;; "\82\80\80\80\80\00" ;; offset 2 with one byte too many +;; "\1a" ;; drop +;; "\0b" ;; end +;; ) +;; "integer representation too long" +;; ) (assert_malformed (module binary "\00asm" "\01\00\00\00" @@ -549,25 +551,27 @@ ) "integer representation too long" ) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\12\01" ;; Code section - ;; function 0 - "\10\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\41\03" ;; i32.const 3 - "\36" ;; i32.store - "\02" ;; alignment 2 - "\82\80\80\80\80\00" ;; offset 2 with one byte too many - "\0b" ;; end - ) - "integer representation too long" -) +;; The memory offset will be decoded as u64 in the memory64 proposal. +;; TODO: Re-enable this test as assert_trap test in the memory64 repo. +;; (assert_malformed +;; (module binary +;; "\00asm" "\01\00\00\00" +;; "\01\04\01\60\00\00" ;; Type section +;; "\03\02\01\00" ;; Function section +;; "\05\03\01\00\01" ;; Memory section +;; "\0a\12\01" ;; Code section +;; ;; function 0 +;; "\10\01\01" ;; local type count +;; "\7f" ;; i32 +;; "\41\00" ;; i32.const 0 +;; "\41\03" ;; i32.const 3 +;; "\36" ;; i32.store +;; "\02" ;; alignment 2 +;; "\82\80\80\80\80\00" ;; offset 2 with one byte too many +;; "\0b" ;; end +;; ) +;; "integer representation too long" +;; ) ;; Signed LEB128 must not be overlong (assert_malformed @@ -629,44 +633,46 @@ ) "integer too large" ) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\10\01" ;; Code section - ;; function 0 - "\0e\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\28" ;; i32.load - "\02" ;; alignment 2 - "\82\80\80\80\10" ;; offset 2 with unused bits set - "\1a" ;; drop - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\10\01" ;; Code section - ;; function 0 - "\0e\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\28" ;; i32.load - "\02" ;; alignment 2 - "\82\80\80\80\40" ;; offset 2 with some unused bits set - "\1a" ;; drop - "\0b" ;; end - ) - "integer too large" -) +;; The memory offset will be decoded as u64 in the memory64 proposal. +;; TODO: Re-enable this test as assert_trap test in the memory64 repo. +;; (assert_malformed +;; (module binary +;; "\00asm" "\01\00\00\00" +;; "\01\04\01\60\00\00" ;; Type section +;; "\03\02\01\00" ;; Function section +;; "\05\03\01\00\01" ;; Memory section +;; "\0a\10\01" ;; Code section +;; ;; function 0 +;; "\0e\01\01" ;; local type count +;; "\7f" ;; i32 +;; "\41\00" ;; i32.const 0 +;; "\28" ;; i32.load +;; "\02" ;; alignment 2 +;; "\82\80\80\80\10" ;; offset 2 with unused bits set +;; "\1a" ;; drop +;; "\0b" ;; end +;; ) +;; "integer too large" +;; ) +;; (assert_malformed +;; (module binary +;; "\00asm" "\01\00\00\00" +;; "\01\04\01\60\00\00" ;; Type section +;; "\03\02\01\00" ;; Function section +;; "\05\03\01\00\01" ;; Memory section +;; "\0a\10\01" ;; Code section +;; ;; function 0 +;; "\0e\01\01" ;; local type count +;; "\7f" ;; i32 +;; "\41\00" ;; i32.const 0 +;; "\28" ;; i32.load +;; "\02" ;; alignment 2 +;; "\82\80\80\80\40" ;; offset 2 with some unused bits set +;; "\1a" ;; drop +;; "\0b" ;; end +;; ) +;; "integer too large" +;; ) (assert_malformed (module binary "\00asm" "\01\00\00\00" @@ -742,45 +748,46 @@ ) "integer too large" ) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\11\01" ;; Code section - ;; function 0 - "\0f\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\41\03" ;; i32.const 3 - "\36" ;; i32.store - "\02" ;; alignment 2 - "\82\80\80\80\10" ;; offset 2 with unused bits set - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\11\01" ;; Code section - - ;; function 0 - "\0f\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\41\03" ;; i32.const 3 - "\36" ;; i32.store - "\02" ;; alignment 2 - "\82\80\80\80\40" ;; offset 2 with some unused bits set - "\0b" ;; end - ) - "integer too large" -) +;; The memory offset will be decoded as u64 in the memory64 proposal. +;; TODO: Re-enable this test as assert_trap test in the memory64 repo. +;; (assert_malformed +;; (module binary +;; "\00asm" "\01\00\00\00" +;; "\01\04\01\60\00\00" ;; Type section +;; "\03\02\01\00" ;; Function section +;; "\05\03\01\00\01" ;; Memory section +;; "\0a\11\01" ;; Code section +;; ;; function 0 +;; "\0f\01\01" ;; local type count +;; "\7f" ;; i32 +;; "\41\00" ;; i32.const 0 +;; "\41\03" ;; i32.const 3 +;; "\36" ;; i32.store +;; "\02" ;; alignment 2 +;; "\82\80\80\80\10" ;; offset 2 with unused bits set +;; "\0b" ;; end +;; ) +;; "integer too large" +;; ) +;; (assert_malformed +;; (module binary +;; "\00asm" "\01\00\00\00" +;; "\01\04\01\60\00\00" ;; Type section +;; "\03\02\01\00" ;; Function section +;; "\05\03\01\00\01" ;; Memory section +;; "\0a\11\01" ;; Code section +;; ;; function 0 +;; "\0f\01\01" ;; local type count +;; "\7f" ;; i32 +;; "\41\00" ;; i32.const 0 +;; "\41\03" ;; i32.const 3 +;; "\36" ;; i32.store +;; "\02" ;; alignment 2 +;; "\82\80\80\80\40" ;; offset 2 with some unused bits set +;; "\0b" ;; end +;; ) +;; "integer too large" +;; ) ;; Signed LEB128s sign-extend (assert_malformed From 0a190c98bf18fe42de359e953a103651702b9d4a Mon Sep 17 00:00:00 2001 From: Clemens Backes Date: Wed, 10 May 2023 18:14:24 +0200 Subject: [PATCH 079/132] Remove duplicated binary tests (#1649) * Remove duplicated binary tests Those tests were moved to `binary-leb128.wast` in #1019, but #1287 brought them back. * Remove more duplicated tests --- test/core/binary.wast | 673 ------------------------------------------ 1 file changed, 673 deletions(-) diff --git a/test/core/binary.wast b/test/core/binary.wast index 1aae74aa..329b8a5a 100644 --- a/test/core/binary.wast +++ b/test/core/binary.wast @@ -51,95 +51,6 @@ (assert_malformed (module binary "\00asm" "\01\00\00\00" "\81\01\00\01\01\00") "malformed section id") (assert_malformed (module binary "\00asm" "\01\00\00\00" "\ff\01\00\01\01\00") "malformed section id") -;; Unsigned LEB128 can have non-minimal length -(module binary - "\00asm" "\01\00\00\00" - "\05\04\01" ;; Memory section with 1 entry - "\00\82\00" ;; no max, minimum 2 -) -(module binary - "\00asm" "\01\00\00\00" - "\05\07\01" ;; Memory section with 1 entry - "\00\82\80\80\80\00" ;; no max, minimum 2 -) - -;; Signed LEB128 can have non-minimal length -(module binary - "\00asm" "\01\00\00\00" - "\06\07\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\80\00" ;; i32.const 0 - "\0b" ;; end -) -(module binary - "\00asm" "\01\00\00\00" - "\06\07\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\ff\7f" ;; i32.const -1 - "\0b" ;; end -) -(module binary - "\00asm" "\01\00\00\00" - "\06\0a\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\80\80\80\80\00" ;; i32.const 0 - "\0b" ;; end -) -(module binary - "\00asm" "\01\00\00\00" - "\06\0a\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\ff\ff\ff\ff\7f" ;; i32.const -1 - "\0b" ;; end -) - -(module binary - "\00asm" "\01\00\00\00" - "\06\07\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\80\00" ;; i64.const 0 with unused bits set - "\0b" ;; end -) -(module binary - "\00asm" "\01\00\00\00" - "\06\07\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\ff\7f" ;; i64.const -1 with unused bits unset - "\0b" ;; end -) -(module binary - "\00asm" "\01\00\00\00" - "\06\0f\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\80\80\80\80\80\80\80\80\80\00" ;; i64.const 0 with unused bits set - "\0b" ;; end -) -(module binary - "\00asm" "\01\00\00\00" - "\06\0f\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\ff\ff\ff\ff\ff\ff\ff\ff\ff\7f" ;; i64.const -1 with unused bits unset - "\0b" ;; end -) - -(module binary - "\00asm" "\01\00\00\00" - "\05\03\01" ;; Memory section with 1 entry - "\00\00" ;; no max, minimum 0 - "\0b\06\01" ;; Data section with 1 entry - "\00" ;; Memory index 0 - "\41\00\0b\00" ;; (i32.const 0) with contents "" -) - -(module binary - "\00asm" "\01\00\00\00" - "\04\04\01" ;; Table section with 1 entry - "\70\00\00" ;; no max, minimum 0, funcref - "\09\06\01" ;; Element section with 1 entry - "\00" ;; Table index 0 - "\41\00\0b\00" ;; (i32.const 0) with no elements -) - ;; Data segment tags and memory index can have non-minimal length (module binary "\00asm" "\01\00\00\00" @@ -218,201 +129,6 @@ "integer representation too long" ) -;; Unsigned LEB128 must not be overlong -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\05\08\01" ;; Memory section with 1 entry - "\00\82\80\80\80\80\00" ;; no max, minimum 2 with one byte too many - ) - "integer representation too long" -) - -;; Signed LEB128 must not be overlong -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0b\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\80\80\80\80\80\00" ;; i32.const 0 with one byte too many - "\0b" ;; end - ) - "integer representation too long" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0b\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\ff\ff\ff\ff\ff\7f" ;; i32.const -1 with one byte too many - "\0b" ;; end - ) - "integer representation too long" -) - -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\10\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\80\80\80\80\80\80\80\80\80\80\00" ;; i64.const 0 with one byte too many - "\0b" ;; end - ) - "integer representation too long" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\10\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\ff\ff\ff\ff\ff\ff\ff\ff\ff\ff\7f" ;; i64.const -1 with one byte too many - "\0b" ;; end - ) - "integer representation too long" -) - -;; Unsigned LEB128s zero-extend -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\05\07\01" ;; Memory section with 1 entry - "\00\82\80\80\80\70" ;; no max, minimum 2 with unused bits set - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\05\07\01" ;; Memory section with 1 entry - "\00\82\80\80\80\40" ;; no max, minimum 2 with some unused bits set - ) - "integer too large" -) - -;; Signed LEB128s sign-extend -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0a\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\80\80\80\80\70" ;; i32.const 0 with unused bits set - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0a\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\ff\ff\ff\ff\0f" ;; i32.const -1 with unused bits unset - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0a\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\80\80\80\80\1f" ;; i32.const 0 with some unused bits set - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0a\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\ff\ff\ff\ff\4f" ;; i32.const -1 with some unused bits unset - "\0b" ;; end - ) - "integer too large" -) - -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0f\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\80\80\80\80\80\80\80\80\80\7e" ;; i64.const 0 with unused bits set - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0f\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\ff\ff\ff\ff\ff\ff\ff\ff\ff\01" ;; i64.const -1 with unused bits unset - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0f\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\80\80\80\80\80\80\80\80\80\02" ;; i64.const 0 with some unused bits set - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0f\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\ff\ff\ff\ff\ff\ff\ff\ff\ff\41" ;; i64.const -1 with some unused bits unset - "\0b" ;; end - ) - "integer too large" -) - -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0f\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\80\80\80\80\80\80\80\80\80\7e" ;; i64.const 0 with unused bits set - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0f\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\ff\ff\ff\ff\ff\ff\ff\ff\ff\01" ;; i64.const -1 with unused bits unset - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0f\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\80\80\80\80\80\80\80\80\80\02" ;; i64.const 0 with some unused bits set - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0f\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\ff\ff\ff\ff\ff\ff\ff\ff\ff\41" ;; i64.const -1 with some unused bits unset - "\0b" ;; end - ) - "integer too large" -) - ;; Function with missing end marker (between two functions) (assert_malformed (module binary @@ -483,395 +199,6 @@ "illegal opcode" ) -;; Unsigned LEB128 must not be overlong -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\05\08\01" ;; Memory section with 1 entry - "\00\82\80\80\80\80\00" ;; no max, minimum 2 with one byte too many - ) - "integer representation too long" -) -;; The memory offset will be decoded as u64 in the memory64 proposal. -;; TODO: Re-enable this test as assert_trap test in the memory64 repo. -;; (assert_malformed -;; (module binary -;; "\00asm" "\01\00\00\00" -;; "\01\04\01\60\00\00" ;; Type section -;; "\03\02\01\00" ;; Function section -;; "\05\03\01\00\01" ;; Memory section -;; "\0a\11\01" ;; Code section -;; ;; function 0 -;; "\0f\01\01" ;; local type count -;; "\7f" ;; i32 -;; "\41\00" ;; i32.const 0 -;; "\28" ;; i32.load -;; "\02" ;; alignment 2 -;; "\82\80\80\80\80\00" ;; offset 2 with one byte too many -;; "\1a" ;; drop -;; "\0b" ;; end -;; ) -;; "integer representation too long" -;; ) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\11\01" ;; Code section - ;; function 0 - "\0f\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\28" ;; i32.load - "\82\80\80\80\80\00" ;; alignment 2 with one byte too many - "\00" ;; offset 0 - "\1a" ;; drop - "\0b" ;; end - ) - "integer representation too long" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\12\01" ;; Code section - ;; function 0 - "\10\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\41\03" ;; i32.const 3 - "\36" ;; i32.store - "\82\80\80\80\80\00" ;; alignment 2 with one byte too many - "\03" ;; offset 3 - "\0b" ;; end - ) - "integer representation too long" -) -;; The memory offset will be decoded as u64 in the memory64 proposal. -;; TODO: Re-enable this test as assert_trap test in the memory64 repo. -;; (assert_malformed -;; (module binary -;; "\00asm" "\01\00\00\00" -;; "\01\04\01\60\00\00" ;; Type section -;; "\03\02\01\00" ;; Function section -;; "\05\03\01\00\01" ;; Memory section -;; "\0a\12\01" ;; Code section -;; ;; function 0 -;; "\10\01\01" ;; local type count -;; "\7f" ;; i32 -;; "\41\00" ;; i32.const 0 -;; "\41\03" ;; i32.const 3 -;; "\36" ;; i32.store -;; "\02" ;; alignment 2 -;; "\82\80\80\80\80\00" ;; offset 2 with one byte too many -;; "\0b" ;; end -;; ) -;; "integer representation too long" -;; ) - -;; Signed LEB128 must not be overlong -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0b\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\80\80\80\80\80\00" ;; i32.const 0 with one byte too many - "\0b" ;; end - ) - "integer representation too long" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0b\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\ff\ff\ff\ff\ff\7f" ;; i32.const -1 with one byte too many - "\0b" ;; end - ) - "integer representation too long" -) - -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\10\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\80\80\80\80\80\80\80\80\80\80\00" ;; i64.const 0 with one byte too many - "\0b" ;; end - ) - "integer representation too long" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\10\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\ff\ff\ff\ff\ff\ff\ff\ff\ff\ff\7f" ;; i64.const -1 with one byte too many - "\0b" ;; end - ) - "integer representation too long" -) - -;; Unsigned LEB128s zero-extend -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\05\07\01" ;; Memory section with 1 entry - "\00\82\80\80\80\70" ;; no max, minimum 2 with unused bits set - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\05\07\01" ;; Memory section with 1 entry - "\00\82\80\80\80\40" ;; no max, minimum 2 with some unused bits set - ) - "integer too large" -) -;; The memory offset will be decoded as u64 in the memory64 proposal. -;; TODO: Re-enable this test as assert_trap test in the memory64 repo. -;; (assert_malformed -;; (module binary -;; "\00asm" "\01\00\00\00" -;; "\01\04\01\60\00\00" ;; Type section -;; "\03\02\01\00" ;; Function section -;; "\05\03\01\00\01" ;; Memory section -;; "\0a\10\01" ;; Code section -;; ;; function 0 -;; "\0e\01\01" ;; local type count -;; "\7f" ;; i32 -;; "\41\00" ;; i32.const 0 -;; "\28" ;; i32.load -;; "\02" ;; alignment 2 -;; "\82\80\80\80\10" ;; offset 2 with unused bits set -;; "\1a" ;; drop -;; "\0b" ;; end -;; ) -;; "integer too large" -;; ) -;; (assert_malformed -;; (module binary -;; "\00asm" "\01\00\00\00" -;; "\01\04\01\60\00\00" ;; Type section -;; "\03\02\01\00" ;; Function section -;; "\05\03\01\00\01" ;; Memory section -;; "\0a\10\01" ;; Code section -;; ;; function 0 -;; "\0e\01\01" ;; local type count -;; "\7f" ;; i32 -;; "\41\00" ;; i32.const 0 -;; "\28" ;; i32.load -;; "\02" ;; alignment 2 -;; "\82\80\80\80\40" ;; offset 2 with some unused bits set -;; "\1a" ;; drop -;; "\0b" ;; end -;; ) -;; "integer too large" -;; ) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\10\01" ;; Code section - "\0e\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\28" ;; i32.load - "\82\80\80\80\10" ;; alignment 2 with unused bits set - "\00" ;; offset 0 - "\1a" ;; drop - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\10\01" ;; Code section - ;; function 0 - "\0e\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\28" ;; i32.load - "\82\80\80\80\40" ;; alignment 2 with some unused bits set - "\00" ;; offset 0 - "\1a" ;; drop - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\11\01" ;; Code section - ;; function 0 - "\0f\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\41\03" ;; i32.const 3 - "\36" ;; i32.store - "\82\80\80\80\10" ;; alignment 2 with unused bits set - "\03" ;; offset 3 - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\11\01" ;; Code section - ;; function 0 - "\0f\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\41\03" ;; i32.const 3 - "\36" ;; i32.store - "\82\80\80\80\40" ;; alignment 2 with some unused bits set - "\03" ;; offset 3 - "\0b" ;; end - ) - "integer too large" -) -;; The memory offset will be decoded as u64 in the memory64 proposal. -;; TODO: Re-enable this test as assert_trap test in the memory64 repo. -;; (assert_malformed -;; (module binary -;; "\00asm" "\01\00\00\00" -;; "\01\04\01\60\00\00" ;; Type section -;; "\03\02\01\00" ;; Function section -;; "\05\03\01\00\01" ;; Memory section -;; "\0a\11\01" ;; Code section -;; ;; function 0 -;; "\0f\01\01" ;; local type count -;; "\7f" ;; i32 -;; "\41\00" ;; i32.const 0 -;; "\41\03" ;; i32.const 3 -;; "\36" ;; i32.store -;; "\02" ;; alignment 2 -;; "\82\80\80\80\10" ;; offset 2 with unused bits set -;; "\0b" ;; end -;; ) -;; "integer too large" -;; ) -;; (assert_malformed -;; (module binary -;; "\00asm" "\01\00\00\00" -;; "\01\04\01\60\00\00" ;; Type section -;; "\03\02\01\00" ;; Function section -;; "\05\03\01\00\01" ;; Memory section -;; "\0a\11\01" ;; Code section -;; ;; function 0 -;; "\0f\01\01" ;; local type count -;; "\7f" ;; i32 -;; "\41\00" ;; i32.const 0 -;; "\41\03" ;; i32.const 3 -;; "\36" ;; i32.store -;; "\02" ;; alignment 2 -;; "\82\80\80\80\40" ;; offset 2 with some unused bits set -;; "\0b" ;; end -;; ) -;; "integer too large" -;; ) - -;; Signed LEB128s sign-extend -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0a\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\80\80\80\80\70" ;; i32.const 0 with unused bits set - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0a\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\ff\ff\ff\ff\0f" ;; i32.const -1 with unused bits unset - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0a\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\80\80\80\80\1f" ;; i32.const 0 with some unused bits set - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0a\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\ff\ff\ff\ff\4f" ;; i32.const -1 with some unused bits unset - "\0b" ;; end - ) - "integer too large" -) - -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0f\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\80\80\80\80\80\80\80\80\80\7e" ;; i64.const 0 with unused bits set - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0f\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\ff\ff\ff\ff\ff\ff\ff\ff\ff\01" ;; i64.const -1 with unused bits unset - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0f\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\80\80\80\80\80\80\80\80\80\02" ;; i64.const 0 with some unused bits set - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0f\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\ff\ff\ff\ff\ff\ff\ff\ff\ff\41" ;; i64.const -1 with some unused bits unset - "\0b" ;; end - ) - "integer too large" -) - ;; memory.grow reserved byte equal to zero. (assert_malformed (module binary From 86b6a183594d770ab37e868e1d755495d44cf243 Mon Sep 17 00:00:00 2001 From: Clemens Backes Date: Wed, 10 May 2023 18:14:50 +0200 Subject: [PATCH 080/132] Make binary-leb128 test memory64-ready (#1650) This merges part of WebAssembly/memory64#14 to make the tests fail both before and after memory64. This allows engines to enable memory64 without failing spec tests. --- test/core/binary-leb128.wast | 165 ++++++++++++++++++----------------- 1 file changed, 84 insertions(+), 81 deletions(-) diff --git a/test/core/binary-leb128.wast b/test/core/binary-leb128.wast index 1b642261..e4a67d6b 100644 --- a/test/core/binary-leb128.wast +++ b/test/core/binary-leb128.wast @@ -404,19 +404,19 @@ (assert_malformed (module binary "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\11\01" ;; Code section + "\01\04\01\60\00\00" ;; Type section + "\03\02\01\00" ;; Function section + "\05\03\01\00\01" ;; Memory section + "\0a\11\01" ;; Code section ;; function 0 - "\0f\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\28" ;; i32.load - "\02" ;; alignment 2 - "\82\80\80\80\80\00" ;; offset 2 with one byte too many - "\1a" ;; drop - "\0b" ;; end + "\0f\01\01" ;; local type count + "\7f" ;; i32 + "\41\00" ;; i32.const 0 + "\28" ;; i32.load + "\02" ;; alignment 2 + "\82\80\80\80\80\80\80\80\80\80\00" ;; offset 2 with one byte too many + "\1a" ;; drop + "\0b" ;; end ) "integer representation too long" ) @@ -461,19 +461,19 @@ (assert_malformed (module binary "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\12\01" ;; Code section + "\01\04\01\60\00\00" ;; Type section + "\03\02\01\00" ;; Function section + "\05\03\01\00\01" ;; Memory section + "\0a\12\01" ;; Code section ;; function 0 - "\10\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\41\03" ;; i32.const 3 - "\36" ;; i32.store - "\02" ;; alignment 2 - "\82\80\80\80\80\00" ;; offset 2 with one byte too many - "\0b" ;; end + "\10\01\01" ;; local type count + "\7f" ;; i32 + "\41\00" ;; i32.const 0 + "\41\03" ;; i32.const 3 + "\36" ;; i32.store + "\02" ;; alignment 2 + "\82\80\80\80\80\80\80\80\80\80\00" ;; offset 2 with one byte too many + "\0b" ;; end ) "integer representation too long" ) @@ -730,40 +730,42 @@ (assert_malformed (module binary "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\10\01" ;; Code section + "\01\04\01\60\00\00" ;; Type section + "\03\02\01\00" ;; Function section + "\05\03\01\00\01" ;; Memory section + "\0a\10\01" ;; Code section ;; function 0 - "\0e\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\28" ;; i32.load - "\02" ;; alignment 2 - "\82\80\80\80\10" ;; offset 2 with unused bits set - "\1a" ;; drop - "\0b" ;; end - ) - "integer too large" + "\0e\01\01" ;; local type count + "\7f" ;; i32 + "\41\00" ;; i32.const 0 + "\28" ;; i32.load + "\02" ;; alignment 2 + "\82\80\80\80\80\80\80\80\80\10" ;; offset 2 with unused bits set + "\1a" ;; drop + "\0b" ;; end + ) + ;; TODO: This changes to "integer too large" with memory64. + "integer representation too long" ) (assert_malformed (module binary "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\10\01" ;; Code section + "\01\04\01\60\00\00" ;; Type section + "\03\02\01\00" ;; Function section + "\05\03\01\00\01" ;; Memory section + "\0a\10\01" ;; Code section ;; function 0 - "\0e\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\28" ;; i32.load - "\02" ;; alignment 2 - "\82\80\80\80\40" ;; offset 2 with some unused bits set - "\1a" ;; drop - "\0b" ;; end - ) - "integer too large" + "\0e\01\01" ;; local type count + "\7f" ;; i32 + "\41\00" ;; i32.const 0 + "\28" ;; i32.load + "\02" ;; alignment 2 + "\82\80\80\80\80\80\80\80\80\40" ;; offset 2 with some unused bits set + "\1a" ;; drop + "\0b" ;; end + ) + ;; TODO: This changes to "integer too large" with memory64. + "integer representation too long" ) (assert_malformed (module binary @@ -843,41 +845,42 @@ (assert_malformed (module binary "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\11\01" ;; Code section + "\01\04\01\60\00\00" ;; Type section + "\03\02\01\00" ;; Function section + "\05\03\01\00\01" ;; Memory section + "\0a\11\01" ;; Code section ;; function 0 - "\0f\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\41\03" ;; i32.const 3 - "\36" ;; i32.store - "\02" ;; alignment 2 - "\82\80\80\80\10" ;; offset 2 with unused bits set - "\0b" ;; end - ) - "integer too large" + "\0f\01\01" ;; local type count + "\7f" ;; i32 + "\41\00" ;; i32.const 0 + "\41\03" ;; i32.const 3 + "\36" ;; i32.store + "\02" ;; alignment 2 + "\82\80\80\80\80\80\80\80\80\10" ;; offset 2 with unused bits set + "\0b" ;; end + ) + ;; TODO: This changes to "integer too large" with memory64. + "integer representation too long" ) (assert_malformed (module binary "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\11\01" ;; Code section - + "\01\04\01\60\00\00" ;; Type section + "\03\02\01\00" ;; Function section + "\05\03\01\00\01" ;; Memory section + "\0a\11\01" ;; Code section ;; function 0 - "\0f\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\41\03" ;; i32.const 3 - "\36" ;; i32.store - "\02" ;; alignment 2 - "\82\80\80\80\40" ;; offset 2 with some unused bits set - "\0b" ;; end - ) - "integer too large" + "\0f\01\01" ;; local type count + "\7f" ;; i32 + "\41\00" ;; i32.const 0 + "\41\03" ;; i32.const 3 + "\36" ;; i32.store + "\02" ;; alignment 2 + "\82\80\80\80\80\80\80\80\80\40" ;; offset 2 with some unused bits set + "\0b" ;; end + ) + ;; TODO: This changes to "integer too large" with memory64. + "integer representation too long" ) ;; Signed LEB128s sign-extend From fe355113fdc439f3cc06b720089168fc853247e5 Mon Sep 17 00:00:00 2001 From: Clemens Backes Date: Wed, 10 May 2023 19:40:24 +0200 Subject: [PATCH 081/132] Move more LEB128 tests to binary-leb128 (#1651) Tests for LEB128 should be in the separate `binary-leb128.wast` test file. --- test/core/binary-leb128.wast | 79 +++++++++++++++++++++++++++++++++++- test/core/binary.wast | 78 ----------------------------------- 2 files changed, 78 insertions(+), 79 deletions(-) diff --git a/test/core/binary-leb128.wast b/test/core/binary-leb128.wast index e4a67d6b..335496f0 100644 --- a/test/core/binary-leb128.wast +++ b/test/core/binary-leb128.wast @@ -966,7 +966,6 @@ "integer too large" ) - (module binary "\00asm" "\01\00\00\00" "\01\04\01" ;; type section @@ -1003,3 +1002,81 @@ ) "integer representation too long" ) + +;; Data segment tags and memory index can have non-minimal length +(module binary + "\00asm" "\01\00\00\00" + "\05\03\01" ;; Memory section with 1 entry + "\00\00" ;; no max, minimum 0 + "\0b\07\01" ;; Data section with 1 entry + "\80\00" ;; Active segment, encoded with 2 bytes + "\41\00\0b\00" ;; (i32.const 0) with contents "" +) +(module binary + "\00asm" "\01\00\00\00" + "\05\03\01" ;; Memory section with 1 entry + "\00\00" ;; no max, minimum 0 + "\0b\08\01" ;; Data section with 1 entry + "\82\00" ;; Active segment, encoded with 2 bytes + "\00" ;; explicit memory index + "\41\00\0b\00" ;; (i32.const 0) with contents "" +) +(module binary + "\00asm" "\01\00\00\00" + "\05\03\01" ;; Memory section with 1 entry + "\00\00" ;; no max, minimum 0 + "\0b\09\01" ;; Data section with 1 entry + "\82\00" ;; Active segment, encoded with 2 bytes + "\80\00" ;; explicit memory index, encoded with 2 bytes + "\41\00\0b\00" ;; (i32.const 0) with contents "" +) + +;; Element segment tags and table index can have non-minimal length +(module binary + "\00asm" "\01\00\00\00" + "\04\04\01" ;; Table section with 1 entry + "\70\00\00" ;; no max, minimum 0, funcref + "\09\07\01" ;; Element section with 1 entry + "\80\00" ;; Active segment + "\41\00\0b\00" ;; (i32.const 0) with no elements +) +(module binary + "\00asm" "\01\00\00\00" + "\04\04\01" ;; Table section with 1 entry + "\70\00\00" ;; no max, minimum 0, funcref + "\09\09\01" ;; Element section with 1 entry + "\02" ;; Active segment + "\80\00" ;; explicit table index, encoded with 2 bytes + "\41\00\0b\00\00" ;; (i32.const 0) with no elements +) +(module binary + "\00asm" "\01\00\00\00" + "\04\04\01" ;; Table section with 1 entry + "\70\00\00" ;; no max, minimum 0, funcref + "\09\09\01" ;; Element section with 1 entry + "\82\00" ;; Active segment, encoded with 2 bytes + "\00" ;; explicit table index + "\41\00\0b\00\00" ;; (i32.const 0) with no elements +) +(module binary + "\00asm" "\01\00\00\00" + "\04\04\01" ;; Table section with 1 entry + "\70\00\00" ;; no max, minimum 0, funcref + "\09\0a\01" ;; Element section with 1 entry + "\82\00" ;; Active segment, encoded with 2 bytes + "\80\00" ;; explicit table index, encoded with 2 bytes + "\41\00\0b\00\00" ;; (i32.const 0) with no elements +) + +;; Type section with signed LEB128 encoded type +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\01" ;; Type section id + "\05" ;; Type section length + "\01" ;; Types vector length + "\e0\7f" ;; Malformed functype, -0x20 in signed LEB128 encoding + "\00\00" + ) + "integer representation too long" +) diff --git a/test/core/binary.wast b/test/core/binary.wast index 329b8a5a..c777bebb 100644 --- a/test/core/binary.wast +++ b/test/core/binary.wast @@ -51,84 +51,6 @@ (assert_malformed (module binary "\00asm" "\01\00\00\00" "\81\01\00\01\01\00") "malformed section id") (assert_malformed (module binary "\00asm" "\01\00\00\00" "\ff\01\00\01\01\00") "malformed section id") -;; Data segment tags and memory index can have non-minimal length -(module binary - "\00asm" "\01\00\00\00" - "\05\03\01" ;; Memory section with 1 entry - "\00\00" ;; no max, minimum 0 - "\0b\07\01" ;; Data section with 1 entry - "\80\00" ;; Active segment, encoded with 2 bytes - "\41\00\0b\00" ;; (i32.const 0) with contents "" -) -(module binary - "\00asm" "\01\00\00\00" - "\05\03\01" ;; Memory section with 1 entry - "\00\00" ;; no max, minimum 0 - "\0b\08\01" ;; Data section with 1 entry - "\82\00" ;; Active segment, encoded with 2 bytes - "\00" ;; explicit memory index - "\41\00\0b\00" ;; (i32.const 0) with contents "" -) -(module binary - "\00asm" "\01\00\00\00" - "\05\03\01" ;; Memory section with 1 entry - "\00\00" ;; no max, minimum 0 - "\0b\09\01" ;; Data section with 1 entry - "\82\00" ;; Active segment, encoded with 2 bytes - "\80\00" ;; explicit memory index, encoded with 2 bytes - "\41\00\0b\00" ;; (i32.const 0) with contents "" -) - -;; Element segment tags and table index can have non-minimal length -(module binary - "\00asm" "\01\00\00\00" - "\04\04\01" ;; Table section with 1 entry - "\70\00\00" ;; no max, minimum 0, funcref - "\09\07\01" ;; Element section with 1 entry - "\80\00" ;; Active segment - "\41\00\0b\00" ;; (i32.const 0) with no elements -) -(module binary - "\00asm" "\01\00\00\00" - "\04\04\01" ;; Table section with 1 entry - "\70\00\00" ;; no max, minimum 0, funcref - "\09\09\01" ;; Element section with 1 entry - "\02" ;; Active segment - "\80\00" ;; explicit table index, encoded with 2 bytes - "\41\00\0b\00\00" ;; (i32.const 0) with no elements -) -(module binary - "\00asm" "\01\00\00\00" - "\04\04\01" ;; Table section with 1 entry - "\70\00\00" ;; no max, minimum 0, funcref - "\09\09\01" ;; Element section with 1 entry - "\82\00" ;; Active segment, encoded with 2 bytes - "\00" ;; explicit table index - "\41\00\0b\00\00" ;; (i32.const 0) with no elements -) -(module binary - "\00asm" "\01\00\00\00" - "\04\04\01" ;; Table section with 1 entry - "\70\00\00" ;; no max, minimum 0, funcref - "\09\0a\01" ;; Element section with 1 entry - "\82\00" ;; Active segment, encoded with 2 bytes - "\80\00" ;; explicit table index, encoded with 2 bytes - "\41\00\0b\00\00" ;; (i32.const 0) with no elements -) - -;; Type section with signed LEB128 encoded type -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\01" ;; Type section id - "\05" ;; Type section length - "\01" ;; Types vector length - "\e0\7f" ;; Malformed functype, -0x20 in signed LEB128 encoding - "\00\00" - ) - "integer representation too long" -) - ;; Function with missing end marker (between two functions) (assert_malformed (module binary From 2e8912e88a3118a46b90e8ccb659e24b4e8f3c23 Mon Sep 17 00:00:00 2001 From: Clemens Backes Date: Fri, 12 May 2023 12:20:37 +0200 Subject: [PATCH 082/132] Allow test for module size limit to fail (#1653) * Allow test for module size limit to fail Allocating a 1GB Uint8Array can fail. In particular, it will always fail on 32-bit systems in V8, where the maximum size of a TypedArray is 2^30-1, thus 1 byte too little. --- test/js-api/limits.any.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/test/js-api/limits.any.js b/test/js-api/limits.any.js index 91f058d6..d913c6c7 100644 --- a/test/js-api/limits.any.js +++ b/test/js-api/limits.any.js @@ -250,7 +250,16 @@ function testModuleSizeLimit(size, expectPass) { // Define a WebAssembly module that consists of a single custom section which // has an empty name. The module size will be `size`. - const buffer = new Uint8Array(size); + let buffer; + try { + buffer = new Uint8Array(size); + } catch (e) { + if (e instanceof RangeError) { + // Allocation of a big TypedArray may fail. + return; + } + throw e; + } const header = [ kWasmH0, kWasmH1, kWasmH2, kWasmH3, // magic word kWasmV0, kWasmV1, kWasmV2, kWasmV3, // version From 083f24cad6f181c7e393ab840e21c0f001cf4615 Mon Sep 17 00:00:00 2001 From: Phosra Date: Mon, 29 May 2023 23:30:51 -0700 Subject: [PATCH 083/132] [spec] Fix table_alloc signature (#1658) --- document/core/appendix/embedding.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/document/core/appendix/embedding.rst b/document/core/appendix/embedding.rst index 27aac4b3..96fa6b2f 100644 --- a/document/core/appendix/embedding.rst +++ b/document/core/appendix/embedding.rst @@ -323,7 +323,7 @@ Tables .. _embed-table-alloc: -:math:`\F{table\_alloc}(\store, \tabletype) : (\store, \tableaddr, \reff)` +:math:`\F{table\_alloc}(\store, \tabletype, \reff) : (\store, \tableaddr)` .......................................................................... 1. Pre-condition: :math:`\tabletype` is :ref:`valid `. From 933d2dd95be2357bd936d4e400e853f8ec728ebd Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Tue, 30 May 2023 11:09:55 +0200 Subject: [PATCH 084/132] [interpreter] Tweak parser --- interpreter/text/parser.mly | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly index 7489acf7..e29be3ae 100644 --- a/interpreter/text/parser.mly +++ b/interpreter/text/parser.mly @@ -732,11 +732,11 @@ elem_expr_list : elem_var_list : | var_list { let f = function {at; _} as x -> [ref_func x @@ at] @@ at in - fun c lookup -> List.map f ($1 c lookup) } + fun c -> List.map f ($1 c func) } elem_list : | elem_kind elem_var_list - { ($1, fun c -> $2 c func) } + { ($1, fun c -> $2 c) } | ref_type elem_expr_list { ($1, fun c -> $2 c) } @@ -768,7 +768,7 @@ elem : { let at = at () in fun c -> ignore ($3 c anon_elem bind_elem); fun () -> - { etype = FuncRefType; einit = $5 c func; + { etype = FuncRefType; einit = $5 c; emode = Active {index = 0l @@ at; offset = $4 c} @@ at } @@ at } table : @@ -788,19 +788,19 @@ table_fields : | inline_export table_fields /* Sugar */ { fun c x at -> let tabs, elems, ims, exs = $2 c x at in tabs, elems, ims, $1 (TableExport x) c :: exs } - | ref_type LPAR ELEM elem_var_list RPAR /* Sugar */ + | ref_type LPAR ELEM elem_expr elem_expr_list RPAR /* Sugar */ { fun c x at -> let offset = [i32_const (0l @@ at) @@ at] @@ at in - let einit = $4 c func in + let einit = $4 c :: $5 c in let size = Lib.List32.length einit in let emode = Active {index = x; offset} @@ at in [{ttype = TableType ({min = size; max = Some size}, $1)} @@ at], - [{etype = FuncRefType; einit; emode} @@ at], + [{etype = $1; einit; emode} @@ at], [], [] } - | ref_type LPAR ELEM elem_expr elem_expr_list RPAR /* Sugar */ + | ref_type LPAR ELEM elem_var_list RPAR /* Sugar */ { fun c x at -> let offset = [i32_const (0l @@ at) @@ at] @@ at in - let einit = (fun c -> $4 c :: $5 c) c in + let einit = $4 c in let size = Lib.List32.length einit in let emode = Active {index = x; offset} @@ at in [{ttype = TableType ({min = size; max = Some size}, $1)} @@ at], From b55d740054915ffc9089e709c99f3319ae6baabc Mon Sep 17 00:00:00 2001 From: Tom Stuart Date: Tue, 30 May 2023 10:57:59 +0100 Subject: [PATCH 085/132] [spec] Include reftype in inline element segment abbreviations (#1657) --- document/core/text/modules.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/document/core/text/modules.rst b/document/core/text/modules.rst index c3407732..5aab9b32 100644 --- a/document/core/text/modules.rst +++ b/document/core/text/modules.rst @@ -292,7 +292,7 @@ An :ref:`element segment ` can be given inline with a table definitio \production{module field} & \text{(}~\text{table}~~\Tid^?~~\Treftype~~\text{(}~\text{elem}~~\expr^n{:}\Tvec(\Telemexpr)~\text{)}~\text{)} \quad\equiv \\ & \qquad \text{(}~\text{table}~~\Tid'~~n~~n~~\Treftype~\text{)} \\ & \qquad - \text{(}~\text{elem}~~\text{(}~\text{table}~~\Tid'~\text{)}~~\text{(}~\text{i32.const}~~\text{0}~\text{)}~~\Tvec(\Telemexpr)~\text{)} + \text{(}~\text{elem}~~\text{(}~\text{table}~~\Tid'~\text{)}~~\text{(}~\text{i32.const}~~\text{0}~\text{)}~~\Treftype~~\Tvec(\Telemexpr)~\text{)} \\ & \qquad\qquad (\iff \Tid^? \neq \epsilon \wedge \Tid' = \Tid^? \vee \Tid^? = \epsilon \wedge \Tid' \idfresh) \\ \end{array} @@ -302,7 +302,7 @@ An :ref:`element segment ` can be given inline with a table definitio \production{module field} & \text{(}~\text{table}~~\Tid^?~~\Treftype~~\text{(}~\text{elem}~~x^n{:}\Tvec(\Tfuncidx)~\text{)}~\text{)} \quad\equiv \\ & \qquad \text{(}~\text{table}~~\Tid'~~n~~n~~\Treftype~\text{)} \\ & \qquad - \text{(}~\text{elem}~~\text{(}~\text{table}~~\Tid'~\text{)}~~\text{(}~\text{i32.const}~~\text{0}~\text{)}~~\Tvec(\Tfuncidx)~\text{)} + \text{(}~\text{elem}~~\text{(}~\text{table}~~\Tid'~\text{)}~~\text{(}~\text{i32.const}~~\text{0}~\text{)}~~\text{func}~~\Tvec(\Tfuncidx)~\text{)} \\ & \qquad\qquad (\iff \Tid^? \neq \epsilon \wedge \Tid' = \Tid^? \vee \Tid^? = \epsilon \wedge \Tid' \idfresh) \\ \end{array} From e19508ade330025158cb2755fa4bbd1b53990a1b Mon Sep 17 00:00:00 2001 From: Reuben Dunnington Date: Mon, 5 Jun 2023 22:47:11 -0700 Subject: [PATCH 086/132] [spec] Fix copypaste error for V128.Load*_Zero instructions in index (#1662) --- document/core/appendix/index-instructions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/document/core/appendix/index-instructions.py b/document/core/appendix/index-instructions.py index 2503a7ab..c3ffc2a3 100755 --- a/document/core/appendix/index-instructions.py +++ b/document/core/appendix/index-instructions.py @@ -431,8 +431,8 @@ def Instruction(name, opcode, type=None, validation=None, execution=None, operat Instruction(r'\V128.\STORE\K{16\_lane}~\memarg~\laneidx', r'\hex{FD}~~\hex{59}', r'[\I32~\V128] \to []', r'valid-store-lane', r'exec-store-lane'), Instruction(r'\V128.\STORE\K{32\_lane}~\memarg~\laneidx', r'\hex{FD}~~\hex{5A}', r'[\I32~\V128] \to []', r'valid-store-lane', r'exec-store-lane'), Instruction(r'\V128.\STORE\K{64\_lane}~\memarg~\laneidx', r'\hex{FD}~~\hex{5B}', r'[\I32~\V128] \to []', r'valid-store-lane', r'exec-store-lane'), - Instruction(r'\V128.\LOAD\K{32\_zero}~\memarg~\laneidx', r'\hex{FD}~~\hex{5C}', r'[\I32] \to [\V128]', r'valid-load-zero', r'exec-load-zero'), - Instruction(r'\V128.\LOAD\K{64\_zero}~\memarg~\laneidx', r'\hex{FD}~~\hex{5D}', r'[\I32] \to [\V128]', r'valid-load-zero', r'exec-load-zero'), + Instruction(r'\V128.\LOAD\K{32\_zero}~\memarg', r'\hex{FD}~~\hex{5C}', r'[\I32] \to [\V128]', r'valid-load-zero', r'exec-load-zero'), + Instruction(r'\V128.\LOAD\K{64\_zero}~\memarg', r'\hex{FD}~~\hex{5D}', r'[\I32] \to [\V128]', r'valid-load-zero', r'exec-load-zero'), Instruction(r'\F32X4.\VDEMOTE\K{\_f64x2\_zero}', r'\hex{FD}~~\hex{5E}', r'[\V128] \to [\V128]', r'valid-vcvtop', r'exec-vcvtop', r'op-demote'), Instruction(r'\F64X2.\VPROMOTE\K{\_low\_f32x4}', r'\hex{FD}~~\hex{5F}', r'[\V128] \to [\V128]', r'valid-vcvtop', r'exec-vcvtop', r'op-promote'), Instruction(r'\I8X16.\VABS', r'\hex{FD}~~\hex{60}', r'[\V128] \to [\V128]', r'valid-vunop', r'exec-vunop', r'op-iabs'), From 123ac59cb650e9537ce129bb2977243bcbe9a773 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Fri, 27 Oct 2023 20:59:25 +0200 Subject: [PATCH 087/132] [interpreter/tests] Switch to Option B' (#285) * Reintroduce exnref * Fix type_of * Simplify parser * Implement 1b * Change opcodes for catch/catch_all to avoid conflict * Put catch clauses first * Remove obsolete Delegating cases * Change exn type opcode to -0x17 * Switch to B' variant * [interpreter] Add boilerplate for ref.exn result patterns * [ci] Deactivate node run, since it can't handle try_table yet * Try -> TryTable in AST * [spec] Update spec for option B' (#283) * Deactivate Bikeshed * [spec/tests] Specification of legacy exceptions + tests (#284) * [legacy] Create specification doc for legacy exception handling * [test] Create infra for legacy tests --- .github/workflows/ci-interpreter.yml | 4 +- .github/workflows/ci-spec.yml | 5 +- document/Makefile | 2 +- document/core/appendix/changes.rst | 4 +- document/core/appendix/index-instructions.py | 14 +- document/core/appendix/index-rules.rst | 1 + document/core/appendix/index-types.rst | 4 +- document/core/appendix/properties.rst | 239 ++- document/core/binary/instructions.rst | 29 +- document/core/binary/types.rst | 3 +- document/core/exec/instructions.rst | 341 ++--- document/core/exec/modules.rst | 19 +- document/core/exec/runtime.rst | 170 +-- document/core/syntax/instructions.rst | 27 +- document/core/syntax/types.rst | 4 +- document/core/text/instructions.rst | 46 +- document/core/text/modules.rst | 1 + document/core/text/types.rst | 2 + document/core/util/macros.def | 34 +- document/core/valid/conventions.rst | 8 +- document/core/valid/instructions.rst | 162 +- document/core/valid/modules.rst | 2 +- document/index.html | 17 +- document/js-api/index.bs | 22 +- document/legacy/exceptions/.gitignore | 3 + document/legacy/exceptions/LICENSE | 50 + document/legacy/exceptions/Makefile | 358 +++++ document/legacy/exceptions/README.md | 25 + .../exceptions/appendix/index-instructions.py | 116 ++ document/legacy/exceptions/binary.rst | 31 + document/legacy/exceptions/conf.py | 498 ++++++ document/legacy/exceptions/exec.rst | 351 +++++ document/legacy/exceptions/index.rst | 22 + document/legacy/exceptions/intro.rst | 8 + document/legacy/exceptions/static/custom.css | 78 + .../legacy/exceptions/static/webassembly.png | Bin 0 -> 43955 bytes document/legacy/exceptions/syntax.rst | 38 + document/legacy/exceptions/text.rst | 37 + document/legacy/exceptions/util/macros.def | 1342 +++++++++++++++++ document/legacy/exceptions/util/mathdef.py | 122 ++ .../legacy/exceptions/util/pseudo-lexer.py | 32 + document/legacy/exceptions/valid.rst | 150 ++ interpreter/README.md | 15 +- interpreter/binary/decode.ml | 65 +- interpreter/binary/encode.ml | 28 +- interpreter/exec/eval.ml | 99 +- interpreter/script/js.ml | 1 + interpreter/script/run.ml | 1 + interpreter/syntax/ast.ml | 15 +- interpreter/syntax/free.ml | 18 +- interpreter/syntax/operators.ml | 10 +- interpreter/syntax/types.ml | 4 +- interpreter/syntax/values.ml | 11 +- interpreter/text/arrange.ml | 23 +- interpreter/text/lexer.mll | 18 +- interpreter/text/parser.mly | 153 +- interpreter/valid/valid.ml | 74 +- proposals/exception-handling/Exceptions.md | 387 +---- test/core/binary.wast | 2 +- test/core/ref_null.wast | 3 + test/core/throw.wast | 13 +- test/core/throw_ref.wast | 118 ++ test/core/try_table.wast | 372 +++++ test/{core => legacy/exceptions}/rethrow.wast | 0 test/legacy/exceptions/throw.wast | 51 + .../exceptions}/try_catch.wast | 0 .../exceptions}/try_delegate.wast | 0 test/legacy/run.py | 117 ++ 68 files changed, 4803 insertions(+), 1216 deletions(-) create mode 100644 document/legacy/exceptions/.gitignore create mode 100644 document/legacy/exceptions/LICENSE create mode 100644 document/legacy/exceptions/Makefile create mode 100644 document/legacy/exceptions/README.md create mode 100755 document/legacy/exceptions/appendix/index-instructions.py create mode 100644 document/legacy/exceptions/binary.rst create mode 100644 document/legacy/exceptions/conf.py create mode 100644 document/legacy/exceptions/exec.rst create mode 100644 document/legacy/exceptions/index.rst create mode 100644 document/legacy/exceptions/intro.rst create mode 100644 document/legacy/exceptions/static/custom.css create mode 100644 document/legacy/exceptions/static/webassembly.png create mode 100644 document/legacy/exceptions/syntax.rst create mode 100644 document/legacy/exceptions/text.rst create mode 100644 document/legacy/exceptions/util/macros.def create mode 100644 document/legacy/exceptions/util/mathdef.py create mode 100644 document/legacy/exceptions/util/pseudo-lexer.py create mode 100644 document/legacy/exceptions/valid.rst create mode 100644 test/core/throw_ref.wast create mode 100644 test/core/try_table.wast rename test/{core => legacy/exceptions}/rethrow.wast (100%) create mode 100644 test/legacy/exceptions/throw.wast rename test/{core => legacy/exceptions}/try_catch.wast (100%) rename test/{core => legacy/exceptions}/try_delegate.wast (100%) create mode 100755 test/legacy/run.py diff --git a/.github/workflows/ci-interpreter.yml b/.github/workflows/ci-interpreter.yml index 297abc7f..22efa999 100644 --- a/.github/workflows/ci-interpreter.yml +++ b/.github/workflows/ci-interpreter.yml @@ -31,4 +31,6 @@ jobs: - name: Build interpreter run: cd interpreter && opam exec make - name: Run tests - run: cd interpreter && opam exec make JS='node --experimental-wasm-return_call' ci + # Node can't handle the new instructions yet + # run: cd interpreter && opam exec make JS='node --experimental-wasm-return_call' ci + run: cd interpreter && opam exec make ci diff --git a/.github/workflows/ci-spec.yml b/.github/workflows/ci-spec.yml index 7610b33b..354dfbd4 100644 --- a/.github/workflows/ci-spec.yml +++ b/.github/workflows/ci-spec.yml @@ -32,8 +32,9 @@ jobs: run: pip install six && pip install sphinx==5.1.0 - name: Build main spec run: cd document/core && make main - - name: Run Bikeshed - run: cd document/core && make bikeshed + # Deactivate broken Bikeshed build for the time being + #- name: Run Bikeshed + # run: cd document/core && make bikeshed - name: Upload artifact uses: actions/upload-artifact@v2 with: diff --git a/document/Makefile b/document/Makefile index 875efc72..629d5f51 100644 --- a/document/Makefile +++ b/document/Makefile @@ -1,4 +1,4 @@ -DIRS = core js-api web-api +DIRS = core js-api web-api legacy/exceptions FILES = index.html BUILDDIR = _build diff --git a/document/core/appendix/changes.rst b/document/core/appendix/changes.rst index 16ea3ff7..db014c5f 100644 --- a/document/core/appendix/changes.rst +++ b/document/core/appendix/changes.rst @@ -147,9 +147,9 @@ Added tag definitions, imports, and exports, and instructions to throw and catch * Modules may :ref:`define `, :ref:`import `, and :ref:`export ` tags. -* New exception throwing :ref:`control instructions `: :math:`\THROW` and :math:`\RETHROW`. +* New :ref:`reference type ` |EXNREF|. -* New handler :ref:`control instructions `: :math:`(\TRY~\X{bt}~\instr_1^\ast~(\CATCH~x~\instr_2^\ast)^\ast~(\CATCHALL~\instr_3^\ast)^?\END)` and :math:`(\TRY~\X{bt}~\instr^\ast~\DELEGATE~l)`. +* New :ref:`control instructions `: |THROW|, |THROWREF|, and |TRYTABLE|. * New :ref:`tag section ` in binary format. diff --git a/document/core/appendix/index-instructions.py b/document/core/appendix/index-instructions.py index 4ab01739..e3a55f53 100755 --- a/document/core/appendix/index-instructions.py +++ b/document/core/appendix/index-instructions.py @@ -85,11 +85,11 @@ def Instruction(name, opcode, type=None, validation=None, execution=None, operat Instruction(r'\LOOP~\X{bt}', r'\hex{03}', r'[t_1^\ast] \to [t_2^\ast]', r'valid-loop', r'exec-loop'), Instruction(r'\IF~\X{bt}', r'\hex{04}', r'[t_1^\ast~\I32] \to [t_2^\ast]', r'valid-if', r'exec-if'), Instruction(r'\ELSE', r'\hex{05}'), - Instruction(r'\TRY~\X{bt}', r'\hex{06}', r'[t_1^\ast] \to [t_2^\ast]', r'valid-try-catch', r'exec-try-catch', None, r'valid-try-delegate', r'exec-try-delegate'), - Instruction(r'\CATCH~x', r'\hex{07}'), + Instruction(None, r'\hex{06}'), + Instruction(None, r'\hex{07}'), Instruction(r'\THROW~x', r'\hex{08}', r'[t_1^\ast~t_x^\ast] \to [t_2^\ast]', r'valid-throw', r'exec-throw'), - Instruction(r'\RETHROW~n', r'\hex{09}', r'[t_1^\ast] \to [t_2^\ast]', r'valid-rethrow', r'exec-rethrow'), - Instruction(None, r'\hex{0A}'), + Instruction(None, r'\hex{09}'), + Instruction(r'\THROWREF', r'\hex{0A}', r'[t_1^\ast~(\REF~\NULL~\EXN)] \to [t_2^\ast]', r'valid-throw_ref', r'exec-throw_ref'), Instruction(r'\END', r'\hex{0B}'), Instruction(r'\BR~l', r'\hex{0C}', r'[t_1^\ast~t^\ast] \to [t_2^\ast]', r'valid-br', r'exec-br'), Instruction(r'\BRIF~l', r'\hex{0D}', r'[t^\ast~\I32] \to [t^\ast]', r'valid-br_if', r'exec-br_if'), @@ -103,14 +103,14 @@ def Instruction(name, opcode, type=None, validation=None, execution=None, operat Instruction(None, r'\hex{15}'), Instruction(None, r'\hex{16}'), Instruction(None, r'\hex{17}'), - Instruction(r'\DELEGATE~l', r'\hex{18}'), - Instruction(r'\CATCHALL', r'\hex{19}', None, r'valid-try-catch', r'exec-try-catch'), + Instruction(None, r'\hex{18}'), + Instruction(None, r'\hex{19}'), Instruction(r'\DROP', r'\hex{1A}', r'[t] \to []', r'valid-drop', r'exec-drop'), Instruction(r'\SELECT', r'\hex{1B}', r'[t~t~\I32] \to [t]', r'valid-select', r'exec-select'), Instruction(r'\SELECT~t', r'\hex{1C}', r'[t~t~\I32] \to [t]', r'valid-select', r'exec-select'), Instruction(None, r'\hex{1D}'), Instruction(None, r'\hex{1E}'), - Instruction(None, r'\hex{1F}'), + Instruction(r'\TRYTABLE~\X{bt}', r'\hex{1F}', r'[t_1^\ast] \to [t_2^\ast]', r'valid-try_table', r'exec-try_table'), Instruction(r'\LOCALGET~x', r'\hex{20}', r'[] \to [t]', r'valid-local.get', r'exec-local.get'), Instruction(r'\LOCALSET~x', r'\hex{21}', r'[t] \to []', r'valid-local.set', r'exec-local.set'), Instruction(r'\LOCALTEE~x', r'\hex{22}', r'[t] \to [t]', r'valid-local.tee', r'exec-local.tee'), diff --git a/document/core/appendix/index-rules.rst b/document/core/appendix/index-rules.rst index 5092be63..1cb3607e 100644 --- a/document/core/appendix/index-rules.rst +++ b/document/core/appendix/index-rules.rst @@ -23,6 +23,7 @@ Construct Judgement :ref:`External type ` :math:`\vdashexterntype \externtype \ok` :ref:`Instruction ` :math:`S;C \vdashinstr \instr : \stacktype` :ref:`Instruction sequence ` :math:`S;C \vdashinstrseq \instr^\ast : \stacktype` +:ref:`Catch clause ` :math:`C \vdashcatch \catch \ok` :ref:`Expression ` :math:`C \vdashexpr \expr : \resulttype` :ref:`Function ` :math:`C \vdashfunc \func : \functype` :ref:`Table ` :math:`C \vdashtable \table : \tabletype` diff --git a/document/core/appendix/index-types.rst b/document/core/appendix/index-types.rst index 5ec06bf4..e560796b 100644 --- a/document/core/appendix/index-types.rst +++ b/document/core/appendix/index-types.rst @@ -16,7 +16,9 @@ Category Constructor (reserved) :math:`\hex{7A}` .. :math:`\hex{71}` :ref:`Reference type ` |FUNCREF| :math:`\hex{70}` (-16 as |Bs7|) :ref:`Reference type ` |EXTERNREF| :math:`\hex{6F}` (-17 as |Bs7|) -(reserved) :math:`\hex{6E}` .. :math:`\hex{61}` +(reserved) :math:`\hex{6E}` .. :math:`\hex{6A}` +:ref:`Reference type ` |EXNREF| :math:`\hex{69}` (-23 as |Bs7|) +(reserved) :math:`\hex{68}` .. :math:`\hex{61}` :ref:`Function type ` :math:`[\valtype^\ast] \to [\valtype^\ast]` :math:`\hex{60}` (-32 as |Bs7|) (reserved) :math:`\hex{5F}` .. :math:`\hex{41}` :ref:`Result type ` :math:`[\epsilon]` :math:`\hex{40}` (-64 as |Bs7|) diff --git a/document/core/appendix/properties.rst b/document/core/appendix/properties.rst index 8ecba539..de9faa46 100644 --- a/document/core/appendix/properties.rst +++ b/document/core/appendix/properties.rst @@ -59,16 +59,12 @@ Results } -:ref:`Results ` :math:`\val^\ast~(\THROWadm~\tagaddr)` +:ref:`Results ` :math:`\XT[(\REFEXNADDR~a)~\THROWREF]` ..................................................................... -* The :ref:`external tag value ` :math:`\EVTAG~\tagaddr` must be :ref:`valid ` with :ref:`external tag type ` :math:`\ETTAG~[t^\ast]\to[]`. +* The value :math:`\REFEXNADDR~a` must be :ref:`valid `. -* For each :ref:`value ` :math:`\val_i` in :math:`\val^\ast` and corresponding :ref:`value type ` :math:`t_i` in :math:`t_i`: - - * The value :math:`\val_i` must be :ref:`valid ` with :ref:`value type ` :math:`t_i`. - -* Then the result is valid with :ref:`result type ` :math:`[{t'}^\ast]`, for any sequence :math:`{t'}^\ast` of :ref:`value types `. +* Then the result is valid with :ref:`result type ` :math:`[t^\ast]`, for any sequence :math:`{t'}^\ast` of :ref:`value types `. .. math:: @@ -77,7 +73,7 @@ Results \qquad (S \vdashval \val : t)^\ast }{ - S \vdashresult \val^\ast~(\THROWadm~\tagaddr) : [{t'}^\ast] + S \vdashresult \XT[(\REFEXNADDR~a)~\THROWREF] : [{t'}^\ast] } @@ -115,6 +111,8 @@ Module instances are classified by *module contexts*, which are regular :ref:`co * Each :ref:`data instance ` :math:`\datainst_i` in :math:`S.\SDATAS` must be :ref:`valid `. +* Each :ref:`exception instance ` :math:`\exninst_i` in :math:`S.\SEXNS` must be :ref:`valid `. + * Then the store is valid. .. math:: @@ -134,6 +132,8 @@ Module instances are classified by *module contexts*, which are regular :ref:`co (S \vdasheleminst \eleminst : \reftype)^\ast \qquad (S \vdashdatainst \datainst \ok)^\ast + \qquad + (S \vdashexninst \exninst \ok)^\ast \\ S = \{ \SFUNCS~\funcinst^\ast, @@ -143,7 +143,8 @@ Module instances are classified by *module contexts*, which are regular :ref:`co \\ \SGLOBALS~\globalinst^\ast, \SELEMS~\eleminst^\ast, - \SDATAS~\datainst^\ast \} + \SDATAS~\datainst^\ast, + \SEXNS~\exninst^\ast \} \end{array} }{ \vdashstore S \ok @@ -356,6 +357,34 @@ Module instances are classified by *module contexts*, which are regular :ref:`co } +.. index:: exception instance, tag, tag address +.. _valid-exninst: + +:ref:`Exception Instances ` :math:`\{ \EITAG~a, \EIFIELDS~\val^\ast \}` +....................................................................................... + +* The store entry :math:`S.\STAGS[a]` must exist. + +* Let :math:`[t^\ast] \toF [{t'}^\ast]` be the :ref:`tag type ` :math:`S.\STAGS[a].\TAGITYPE`. + +* The :ref:`result type ` :math:`[{t'}^\ast]` must be empty. + +* The sequence :math:`\val^ast` of :ref:`values ` must have the same length as the sequence :math:`t^\ast` of :ref:`value types `. + +* For each value :math:`\val_i` in :math:`\val^ast` and corresponding value type :math:`t_i` in :math:`t^\ast`, the value :math:`\val_i` must be valid with type :math:`t_i`. + +* Then the exception instance is valid. + +.. math:: + \frac{ + S.\STAGS[a] = \{\TAGITYPE = [t^\ast] \toF []\} + \qquad + (S \vdashval \val : t)^\ast + }{ + S \vdashexninst \{ \EITAG~a, \EIFIELDS~\val^\ast \} \ok + } + + .. index:: external type, export instance, name, external value .. _valid-exportinst: @@ -583,147 +612,20 @@ To that end, all previous typing judgements :math:`C \vdash \X{prop}` are genera } -.. index:: extern address - -:math:`\REFEXTERNADDR~\externaddr` -.................................. - -* The instruction is valid with type :math:`[] \to [\EXTERNREF]`. - -.. math:: - \frac{ - }{ - S; C \vdashadmininstr \REFEXTERNADDR~\externaddr : [] \to [\EXTERNREF] - } - - -.. index:: function address, extern value, extern type, function type - -:math:`\REFFUNCADDR~\funcaddr` -.............................. - -* The :ref:`external function value ` :math:`\EVFUNC~\funcaddr` must be :ref:`valid ` with :ref:`external function type ` :math:`\ETFUNC~\functype`. - -* Then the instruction is valid with type :math:`[] \to [\FUNCREF]`. - -.. math:: - \frac{ - S \vdashexternval \EVFUNC~\funcaddr : \ETFUNC~\functype - }{ - S; C \vdashadmininstr \REFFUNCADDR~\funcaddr : [] \to [\FUNCREF] - } - - -.. index:: throw, throw context, tag address - -:math:`\THROWadm~\tagaddr` -.......................... - -* The :ref:`external tag value ` :math:`\EVTAG~\tagaddr` must be :ref:`valid ` with :ref:`external tag type ` :math:`\ETTAG~[t^\ast]\to[]`. - -* Then the instruction is valid with type :math:`[t_1^\ast t^\ast] \to [t_2^\ast]` for any sequences of :ref:`value types ` :math:`t_1^\ast` and :math:`t_2^\ast`. - -.. math:: - \frac{ - S \vdashexternval \EVTAG~\tagaddr : \ETTAG~[t^\ast]\to[] - }{ - S; C \vdashadmininstr \THROWadm~\tagaddr : [t_1^\ast t^\ast] \to [t_2^\ast] - } - - -.. index:: handler, throw context - -:math:`\HANDLERadm_n\{(\tagaddr^?~\instr_1^\ast)^\ast\}~\instr_2^\ast~\END` -........................................................................... - -* Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with the :ref:`label type ` :math:`[t_2^\ast]` prepended to the |CLABELS| vector. - -* Under context :math:`C'`, - the instruction sequence :math:`\instr_2^\ast` must be :ref:`valid ` with type :math:`[] \to [t_2^n]`. - -* Let :math:`C''` be the same :ref:`context ` as :math:`C`, but with the :ref:`label type ` :math:`(\LCATCH~[t_2^n])` prepended to the |CLABELS| vector. - -* Under context :math:`C''`, - for every :math:`\tagaddr^?` and associated instruction sequence :math:`\instr_1^\ast`: - - * If :math:`\tagaddr^? = \epsilon`, then :math:`\instr_1^\ast` must be :ref:`valid ` with type :math:`[] \to [t_2^n]`. - - * Else: - - * The :ref:`external tag value ` :math:`\EVTAG~\tagaddr` must be :ref:`valid ` with some :ref:`external tag type ` :math:`\ETTAG~[t_1^\ast] \to []`. - - * The instruction sequence :math:`\instr_1^\ast` must be :ref:`valid ` with type :math:`[t_1^\ast] \to [t_2^n]`. - -* Then the compound instruction is valid under context :math:`C'` with type :math:`[] \to [t_2^n]`. - -.. math:: - \frac{ - \begin{array}{@{}c@{}} - ((S \vdashexternval \EVTAG~\tagaddr : \ETTAG~[t_1^\ast]\to[])^? \\ - ~~S; C,\CLABELS\,(\LCATCH~[t_2^n]) \vdashinstrseq \instr_1^\ast : [(t_1^\ast)^?] \to [t_2^n])^\ast \\ - S; C,\CLABELS\,[t_2^n] \vdashinstrseq \instr_2^\ast : [] \to [t_2^n] \\ - \end{array} - }{ - S; C,\CLABELS\,[t_2^n] \vdashadmininstr \HANDLERadm_n\{(\tagaddr^?~{\instr_1}^\ast)^\ast\}~\instr_2^\ast~\END : [] \to [t_2^n] - } - - -.. index:: handler, throw context -.. _valid-handleradm: - -:math:`\HANDLERadm_n\{l\}~\instr^\ast~\END` -........................................... - -* The label :math:`C.\CLABELS[l]` must be defined in the context. - -* Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with the label :math:`[t^\ast]` prepended to the |CLABELS| vector. - -* Under context :math:`C'`, - the instruction sequence :math:`\instr^\ast` must be :ref:`valid ` with type :math:`[]\to[t^n]`. - -* Then the compound instruction is valid under context :math:`C'` with type :math:`[] \to [t^n]`. - -.. math:: - \frac{ - S; C,\CLABELS\,[t^n] \vdashinstrseq \instr^\ast : [] \to [t^n] - \qquad - C.\CLABELS[l] = \LCATCH^?~[t_0^\ast] - }{ - S; C,\CLABELS\,[t^n] \vdashadmininstr \HANDLERadm_n\{l\}~\instr^\ast~\END : [] \to [t^n] - } - - -.. index:: caught, throw context - -:math:`\CAUGHTadm_n\{\tagaddr~\val^\ast\}~\instr^\ast~\END` -........................................................... - -* The :ref:`external tag value ` :math:`\EVTAG~\tagaddr` must be :ref:`valid ` with some :ref:`external tag type ` :math:`\ETTAG~[t_0^\ast] \to []`. - -* The :ref:`values ` :math:`\val^\ast` must be of type :math:`[t_0^\ast]`. - -* The label :math:`C.\CLABELS[0]` must be defined in the context. - -* Let :math:`(\LCATCH^?~[t^n])` be the :ref:`label type ` :math:`C.\CLABELS[0]`. - -* The |LCATCH| must not be present in the label type :math:`C.\CLABELS[0]`. +.. index:: value, reference -* Let :math:`C''` be the same :ref:`context ` as :math:`C`, but with the label type :math:`(\LCATCH~[t^n])` replacing the first element of the |CLABELS| vector. +:math:`\reff` +............. -* Under context :math:`C''`, - the instruction sequence :math:`\instr^\ast` must be :ref:`valid ` with type :math:`[] \to [t^n]`. +* The reference :math:`\reff` must be :ref:`valid ` with some type :math:`t`. -* Then the compound instruction is valid with type :math:`[] \to [t^n]`. +* Then the instruction is valid with type :math:`[] \to [t]`. .. math:: \frac{ - S \vdashexternval \EVTAG~\tagaddr : \ETTAG~[t_0^\ast]\to[] - \qquad - (val : t_0)^\ast - \qquad - S; C',\CLABELS\,(\LCATCH~[t^n]) \vdashinstrseq \instr^\ast : [] \to [t^n] + S \vdashval \reff : t }{ - S; C',\CLABELS\,[t^n] \vdashadmininstr \CAUGHTadm_n\{\tagaddr~\val^\ast\}~\instr^\ast~\END : [] \to [t^n] + S; C \vdashadmininstr \reff : [] \to [t] } @@ -751,7 +653,7 @@ To that end, all previous typing judgements :math:`C \vdash \X{prop}` are genera * The instruction sequence :math:`\instr_0^\ast` must be :ref:`valid ` with some type :math:`[t_1^n] \to [t_2^*]`. -* Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with the :ref:`label type ` :math:`[t_1^n]` prepended to the |CLABELS| vector. +* Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with the :ref:`result type ` :math:`[t_1^n]` prepended to the |CLABELS| vector. * Under context :math:`C'`, the instruction sequence :math:`\instr^\ast` must be :ref:`valid ` with type :math:`[] \to [t_2^*]`. @@ -768,6 +670,29 @@ To that end, all previous typing judgements :math:`C \vdash \X{prop}` are genera } +.. index:: handler, throw context + +:math:`\HANDLER_n\{\catch^\ast\}~\instr^\ast~\END` +.................................................. + +* For every :ref:`catch clause ` :math:`\catch_i` in :math:`\catch^\ast`, :math:`\catch_i` must be :ref:`valid `. + +* The instruction sequence :math:`\instr^\ast` must be :ref:`valid ` with some type :math:`[t_1^\ast] \to [t_2^\ast]`. + +* Then the compound instruction is valid with type :math:`[t_1^\ast] \to [t_2^\ast]`. + +.. math:: + \frac{ + \begin{array}{c} + (C \vdashcatch \catch \ok)^\ast + \qquad + S; C \vdashinstrseq \instr^\ast : [t_1^\ast] \to [t_2^\ast] \\ + \end{array} + }{ + S; C \vdashadmininstr \HANDLER_n\{\catch^\ast\}~\instr^\ast~\END : [t_1^\ast] \to [t_2^\ast] + } + + .. index:: frame, instruction, result type :math:`\FRAME_n\{F\}~\instr^\ast~\END` @@ -825,6 +750,8 @@ a store state :math:`S'` extends state :math:`S`, written :math:`S \extendsto S' * The length of :math:`S.\SDATAS` must not shrink. +* The length of :math:`S.\SEXNS` must not shrink. + * For each :ref:`function instance ` :math:`\funcinst_i` in the original :math:`S.\SFUNCS`, the new function instance must be an :ref:`extension ` of the old. * For each :ref:`table instance ` :math:`\tableinst_i` in the original :math:`S.\STABLES`, the new table instance must be an :ref:`extension ` of the old. @@ -835,9 +762,11 @@ a store state :math:`S'` extends state :math:`S`, written :math:`S \extendsto S' * For each :ref:`global instance ` :math:`\globalinst_i` in the original :math:`S.\SGLOBALS`, the new global instance must be an :ref:`extension ` of the old. -* For each :ref:`element instance ` :math:`\eleminst_i` in the original :math:`S.\SELEMS`, the new global instance must be an :ref:`extension ` of the old. +* For each :ref:`element instance ` :math:`\eleminst_i` in the original :math:`S.\SELEMS`, the new element instance must be an :ref:`extension ` of the old. -* For each :ref:`data instance ` :math:`\datainst_i` in the original :math:`S.\SDATAS`, the new global instance must be an :ref:`extension ` of the old. +* For each :ref:`data instance ` :math:`\datainst_i` in the original :math:`S.\SDATAS`, the new data instance must be an :ref:`extension ` of the old. + +* For each :ref:`exception instance ` :math:`\exninst_i` in the original :math:`S.\SEXNS`, the new exception instance must be an :ref:`extension ` of the old. .. math:: \frac{ @@ -863,6 +792,9 @@ a store state :math:`S'` extends state :math:`S`, written :math:`S \extendsto S' S_1.\SDATAS = \datainst_1^\ast & S_2.\SDATAS = {\datainst'_1}^\ast~\datainst_2^\ast & (\vdashdatainstextends \datainst_1 \extendsto \datainst'_1)^\ast \\ + S_1.\SEXNS = \exninst_1^\ast & + S_2.\SEXNS = {\exninst'_1}^\ast~\exninst_2^\ast & + (\vdashexninstextends \exninst_1 \extendsto \exninst'_1)^\ast \\ \end{array} }{ \vdashstoreextends S_1 \extendsto S_2 @@ -987,6 +919,21 @@ a store state :math:`S'` extends state :math:`S`, written :math:`S \extendsto S' } +.. index:: exception instance +.. _extend-exninst: + +:ref:`Exception Instance ` :math:`\exninst` +........................................................... + +* An exception instance must remain unchanged. + +.. math:: + \frac{ + }{ + \vdashexninstextends \exninst \extendsto \exninst + } + + .. index:: ! preservation, ! progress, soundness, configuration, thread, terminal configuration, instantiation, invocation, validity, module .. _soundness-statement: diff --git a/document/core/binary/instructions.rst b/document/core/binary/instructions.rst index b8ac093f..d26bfc48 100644 --- a/document/core/binary/instructions.rst +++ b/document/core/binary/instructions.rst @@ -21,7 +21,7 @@ The only exception are :ref:`structured control instructions ` have varying encodings. For structured instructions, the instruction sequences forming nested blocks are separated or terminated with explicit opcodes for |END|, |ELSE|, |CATCH|, |CATCHALL|, and |DELEGATE|. +:ref:`Control instructions ` have varying encodings. For structured instructions, the instruction sequences forming nested blocks are delimited with explicit opcodes for |END| and |ELSE|. :ref:`Block types ` are encoded in special compressed form, by either the byte :math:`\hex{40}` indicating the empty type, as a single :ref:`value type `, or as a :ref:`type index ` encoded as a positive :ref:`signed integer `. @@ -31,22 +31,23 @@ Control Instructions .. _binary-block: .. _binary-loop: .. _binary-if: -.. _binary-try: +.. _binary-try_table: .. _binary-throw: -.. _binary-rethrow: +.. _binary-throw_ref: .. _binary-br: .. _binary-br_if: .. _binary-br_table: .. _binary-return: .. _binary-call: .. _binary-call_indirect: +.. _binary-catch: .. math:: - \begin{array}{llcllll} + \begin{array}{@{}l@{}lclll@{}} \production{block type} & \Bblocktype &::=& \hex{40} &\Rightarrow& \epsilon \\ &&|& t{:}\Bvaltype &\Rightarrow& t \\ &&|& - x{:}\Bs33 &\Rightarrow& x & (\iff x \geq 0) \\ + x{:}\Bs33 &\Rightarrow& x \qquad\qquad (\iff x \geq 0) \\ \production{instruction} & \Binstr &::=& \hex{00} &\Rightarrow& \UNREACHABLE \\ &&|& \hex{01} &\Rightarrow& \NOP \\ &&|& @@ -59,22 +60,22 @@ Control Instructions \hex{04}~~\X{bt}{:}\Bblocktype~~(\X{in}_1{:}\Binstr)^\ast~~ \hex{05}~~(\X{in}_2{:}\Binstr)^\ast~~\hex{0B} &\Rightarrow& \IF~\X{bt}~\X{in}_1^\ast~\ELSE~\X{in}_2^\ast~\END \\ &&|& - \hex{06}~~\X{bt}{:}\Bblocktype~~(\X{in}_1{:}\Binstr)^\ast~~ - (\hex{07}~~x{:}\Btagidx~~(\X{in}_2{:}\Binstr)^\ast)^\ast~~ - (\hex{19}~~(\X{in}_3{:}\Binstr)^\ast)^?~~\hex{0B} - &\Rightarrow& \TRY~\X{bt}~\X{in}_1^\ast~(\CATCH~x~\X{in}_2^\ast)^\ast~ - (\CATCHALL~\X{in}_3^\ast)^?\END \\ &&|& - \hex{06}~~\X{bt}{:}\Bblocktype~~(\X{in}{:}\Binstr)^\ast~~\hex{18}~~l{:}\Blabelidx - &\Rightarrow& \TRY~\X{bt}~\X{in}^\ast~\DELEGATE~l \\ &&|& \hex{08}~~x{:}\Btagidx &\Rightarrow& \THROW~x \\ &&|& - \hex{09}~~l{:}\Blabelidx &\Rightarrow& \RETHROW~l \\ &&|& + \hex{0A} &\Rightarrow& \THROWREF \\ &&|& \hex{0C}~~l{:}\Blabelidx &\Rightarrow& \BR~l \\ &&|& \hex{0D}~~l{:}\Blabelidx &\Rightarrow& \BRIF~l \\ &&|& \hex{0E}~~l^\ast{:}\Bvec(\Blabelidx)~~l_N{:}\Blabelidx &\Rightarrow& \BRTABLE~l^\ast~l_N \\ &&|& \hex{0F} &\Rightarrow& \RETURN \\ &&|& \hex{10}~~x{:}\Bfuncidx &\Rightarrow& \CALL~x \\ &&|& - \hex{11}~~y{:}\Btypeidx~~x{:}\Btableidx &\Rightarrow& \CALLINDIRECT~x~y \\ + \hex{11}~~y{:}\Btypeidx~~x{:}\Btableidx &\Rightarrow& \CALLINDIRECT~x~y \\ &&|& + \hex{1F}~~\X{bt}{:}\Bblocktype~~c^\ast{:}\Bvec(\Bcatch)~~(\X{in}{:}\Binstr)^\ast~~\hex{0B} + &\Rightarrow& \TRYTABLE~\X{bt}~c^\ast~\X{in}^\ast~\END \\ + \production{catch clause} & \Bcatch &::=& + \hex{00}~~x{:}\Btagidx~~l{:}\Blabelidx &\Rightarrow& \CATCH~x~l \\ &&|& + \hex{01}~~x{:}\Btagidx~~l{:}\Blabelidx &\Rightarrow& \CATCHREF~x~l \\ &&|& + \hex{02}~~l{:}\Blabelidx &\Rightarrow& \CATCHALL~l \\ &&|& + \hex{03}~~l{:}\Blabelidx &\Rightarrow& \CATCHALLREF~l \\ \end{array} .. note:: diff --git a/document/core/binary/types.rst b/document/core/binary/types.rst index d9e1ca10..2eef0bee 100644 --- a/document/core/binary/types.rst +++ b/document/core/binary/types.rst @@ -58,7 +58,8 @@ Reference Types \begin{array}{llclll@{\qquad\qquad}l} \production{reference type} & \Breftype &::=& \hex{70} &\Rightarrow& \FUNCREF \\ &&|& - \hex{6F} &\Rightarrow& \EXTERNREF \\ + \hex{6F} &\Rightarrow& \EXTERNREF \\ &&|& + \hex{69} &\Rightarrow& \EXNREF \\ \end{array} diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index 7d6e5f4d..5d19010c 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -2683,123 +2683,184 @@ Control Instructions \end{array} -.. _exec-try-catch: +.. _exec-try_table: -:math:`\TRY~\blocktype~\instr_1^\ast~(\CATCH~x~\instr_2^\ast)^\ast~(\CATCHALL~\instr_3^\ast)^?~\END` -.................................................................................................... +:math:`\TRYTABLE~\blocktype~\catch^\ast~\instr^\ast~\END` +......................................................... 1. Assert: due to :ref:`validation `, :math:`\expand_F(\blocktype)` is defined. 2. Let :math:`[t_1^m] \to [t_2^n]` be the :ref:`function type ` :math:`\expand_F(\blocktype)`. -3. Let :math:`L` be the label whose arity is :math:`n` and whose continuation is the end of the |TRY| instruction. +3. Assert: due to :ref:`validation `, there are at least :math:`m` values on the top of the stack. -4. Assert: due to :ref:`validation `, there are at least :math:`m` values on the top of the stack. +4. Pop the values :math:`\val^m` from the stack. -5. Pop the values :math:`\val^m` from the stack. +5. Let :math:`L` be the label whose arity is :math:`n` and whose continuation is the end of the |TRYTABLE| instruction. -6. Let :math:`F` be the :ref:`current ` :ref:`frame `. +6. :ref:`Enter ` the block :math:`\val^m~\instr_1^\ast` with label :math:`L` and exception handler :math:`\HANDLER_n\{\catch^\ast\}`. -7. For each catch clause :math:`(\CATCH~x_i~\instr_{2i}^\ast)` do: +.. math:: + ~\\[-1ex] + \begin{array}{r} + F; \val^m~(\TRYTABLE~\X{bt}~\catch^\ast~\instr^\ast~\END + \quad \stepto \quad + F; \HANDLER_n\{\catch^\ast\}~(\LABEL_n\{\epsilon\}~\val^m~\instr^\ast~\END)~\END \\ \qquad\qquad + (\iff \expand_F(\X{bt}) = [t_1^m] \to [t_2^n] \land (F.\AMODULE.\MITAGS[x]=a_x)^\ast) + \end{array} + + +.. _exec-throw: + +:math:`\THROW~x` +................ + +1. Let :math:`F` be the :ref:`current ` :ref:`frame `. + +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]`. - a. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MITAGS[x_i]` exists. +4. Assert: due to :ref:`validation `, :math:`S.\STAGS[a]` exists. - b. Let :math:`a_i` be the tag address :math:`F.\AMODULE.\MITAGS[x_i]`. +5. Let :math:`\X{ti}` be the :ref:`tag instance ` :math:`S.\STAGS[a]`. - c. Let :math:`H_i` be the handler :math:`(a_i~\instr_{2i}^\ast)`. +6. Let :math:`[t^n] \toF [{t'}^\ast]` be the :ref:`tag type ` :math:`\X{ti}.\TAGITYPE`. -8. If there is a catch all clause :math:`(\CATCHALL~\instr_3^\ast)`, then: +7. Assert: due to :ref:`validation `, there are at least :math:`n` values on the top of the stack. - a. Let :math:`H'^?` be the handler :math:`(\epsilon~\instr_3^\ast)`. +8. Pop the :math:`n` values :math:`\val^n` from the stack. -9. Else: +9. Let :math:`\X{exn}` be the :ref:`exception instance ` :math:`\{ \EITAG~a, \EIFIELDS~\val^n \}`. - a. Let :math:`H'^?` be the empty handler :math:`\epsilon`. +10. Let :math:`\X{ea}` be the length of :math:`S.\SEXNS`. -10. Let :math:`H^\ast` be the concatenation of :math:`H_i` and :math:`H'^?`. +11. Append :math:`\X{exn}` to :math:`S.\SEXNS`. -11. :ref:`Enter ` the block :math:`\val^m~\instr_1^\ast` with label :math:`L` and exception handler :math:`H^\ast`. +12. Push the value :math:`\REFEXNADDR~\X{ea}` to the stack. + +13. Execute the instruction |THROWREF|. .. math:: ~\\[-1ex] - \begin{array}{l} - F; \val^m~(\TRY~\X{bt}~\instr_1^\ast~(\CATCH~x~\instr_2^\ast)^\ast~(\CATCHALL~\instr_3^\ast)^?~\END - \quad \stepto \\ - \qquad F; \LABEL_n\{\epsilon\}~(\HANDLERadm_n\{(a_x~\instr_2^\ast)^\ast~(\epsilon~\instr_3^\ast)^?\}~\val^m~\instr_1^\ast~\END)~\END \\ - (\iff \expand_F(\X{bt}) = [t_1^m] \to [t_2^n] \land (F.\AMODULE.\MITAGS[x]=a_x)^\ast) + \begin{array}{lclr@{\qquad}l} + S; F; \val^n~(\THROW~x) &\stepto& S'; F; (\REFEXNADDR~|S.\SEXNS|)~\THROWREF & + (\begin{array}[t]{@{}r@{~}l@{}} + \iff & F.\AMODULE.\MITAGS[x] = a \\ + \land & S.\STAGS[a].\TAGITYPE = [t^n] \toF [] \\ + \land & \X{exn} = \{ \EITAG~a, \EIFIELDS~\val^n \} \\ + \land & S' = S \with \SEXNS = S.\SEXNS~\X{exn} ) \\ + \end{array} \\ \end{array} -.. _exec-try-delegate: +.. _exec-throw_ref: -:math:`\TRY~\blocktype~\instr^\ast~\DELEGATE~l` -............................................... +:math:`\THROWREF` +................. -1. Assert: due to :ref:`validation `, :math:`\expand_F(\blocktype)` is defined. +1. Let :math:`F` be the :ref:`current ` :ref:`frame `. -2. Let :math:`[t_1^m] \to [t_2^n]` be the :ref:`function type ` :math:`\expand_F(\blocktype)`. +2. Assert: due to :ref:`validation `, a :ref:`reference ` is on the top of the stack. -3. Let :math:`L` be the label whose arity is :math:`n` and whose continuation is the end of the |TRY| instruction. +3. Pop the reference :math:`\reff` from the stack. -4. Let :math:`H` be the :ref:`exception handler ` :math:`l`, targeting the :math:`l`-th surrounding block. +4. If :math:`\reff` is :math:`\REFNULL~\X{ht}`, then: -5. Assert: due to :ref:`validation `, there are at least :math:`m` values on the top of the stack. + a. Trap. -6. Pop the values :math:`\val^m` from the stack. +5. Assert: due to :ref:`validation `, :math:`\reff` is an :ref:`exception reference `. -7. :ref:`Enter ` the block :math:`\val^m~\instr^\ast` with label :math:`L` and exception handler `H`. +6. Let :math:`\REFEXNADDR~\X{ea}` be :math:`\reff`. -.. math:: - ~\\[-1ex] - \begin{array}{lcl} - F; \val^m~(\TRY~\X{bt}~\instr^\ast~\DELEGATE~l) &\stepto& - F; \LABEL_n\{\epsilon\}~(\HANDLERadm_n\{l\}~\val^m~\instr^\ast~\END)~\END \\ - && (\iff \expand_F(\X{bt}) = [t_1^m] \to [t_2^n]) - \end{array} +7. Assert: due to :ref:`validation `, :math:`S.\SEXNS[\X{ea}]` exists. +8. Let :math:`\X{exn}` be the :ref:`exception instance ` :math:`S.\SEXNS[\X{ea}]`. -.. _exec-throw: +9. Let :math:`a` be the :ref:`tag address ` :math:`\X{exn}.\EITAG`. -:math:`\THROW~x` -................ +10. While the stack is not empty and the top of the stack is not an :ref:`exception handler `, do: -1. Let :math:`F` be the :ref:`current ` :ref:`frame `. + a. Pop the top element from the stack. -2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MITAGS[x]` exists. +11. Assert: the stack is now either empty, or there is an exception handler on the top of the stack. -3. Let :math:`a` be the :ref:`tag address ` :math:`F.\AMODULE.\MITAGS[x]`. +12. If the stack is empty, then: -4. :ref:`Throw ` an exception with :ref:`tag address ` :math:`a`. + a. Return the exception :math:`(\REFEXNADDR~a)` as a :ref:`result `. -.. math:: - ~\\[-1ex] - \begin{array}{lclr@{\qquad}l} - \THROW~x &\stepto& \THROWadm~a & (\iff F.\AMODULE.\MITAGS[x] = a) \\ - \end{array} +13. Assert: there is an :ref:`exception handler ` on the top of the stack. +14. Pop the exception handler :math:`\HANDLER_n\{\catch^\ast\}` from the stack. -.. _exec-rethrow: +15. If :math:`\catch^\ast` is empty, then: -:math:`\RETHROW~l` -.................. + a. Push the exception reference :math:`\REFEXNADDR~\X{ea}` back to the stack. -1. Assert: due to :ref:`validation `, the stack contains at least :math:`l+1` labels. + b. Execute the instruction |THROWREF| again. -2. Let :math:`L` be the :math:`l`-th label appearing on the stack, starting from the top and counting from zero. +16. Else: + + a. Let :math:`\catch_1` be the first :ref:`catch clause ` in :math:`\catch^\ast` and :math:`{\catch'}^\ast` the remaining clauses. + + b. If :math:`\catch_1` is of the form :math:`\CATCH~x~l` and the :ref:`exception address ` :math:`a` equals :math:`F.\AMODULE.\MITAGS[x]`, then: + + i. Push the values :math:`\X{exn}.\EIFIELDS` to the stack. + + ii. Execute the instruction :math:`\BR~l`. -3. Assert: due to :ref:`validation `, :math:`L` is a catch label, i.e., a label of the form :math:`(\LCATCH~[t^\ast])`, which is a label followed by a caught exception in an active catch clause. + 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: -4. Let :math:`\{a~\val^\ast\}` be the caught exception. + i. Push the values :math:`\X{exn}.\EIFIELDS` to the stack. -5. Push the values :math:`\val^\ast` onto the stack. + ii. Push the exception reference :math:`\REFEXNADDR~\X{ea}` to the stack. -6. :ref:`Throw ` an exception with :ref:`tag address ` :math:`a`. + iii. Execute the instruction :math:`\BR~l`. + + d. Else if :math:`\catch_1` is of the form :math:`\CATCHALL~l`, then: + + i. Execute the instruction :math:`\BR~l`. + + e. Else if :math:`\catch_1` is of the form :math:`\CATCHALLREF~l`, then: + + i. Push the exception reference :math:`\REFEXNADDR~\X{ea}` to the stack. + + ii. Execute the instruction :math:`\BR~l`. + + f. Else: + + 1. Push the modified handler :math:`\HANDLER_n\{{\catch'}^\ast\}` back to the stack. + + 2. Push the exception reference :math:`\REFEXNADDR~\X{ea}` back to the stack. + + 3. Execute the instruction :math:`\THROWREF` again. .. math:: ~\\[-1ex] - \begin{array}{lclr@{\qquad}} - \CAUGHTadm_n\{a~\val^n\}~\XB^l[\RETHROW~l]~\END &\stepto& - \CAUGHTadm_n\{a~\val^n\}~\XB^l[\val^n~(\THROWadm~a)]~\END \\ + \begin{array}{rcl} + (\REFNULL~\X{ht})~\THROWREF &\stepto& + \TRAP \\ + \HANDLER_n\{\}~\XT[(\REFEXNADDR~a)~\THROWREF]~\END &\stepto& + (\REFEXNADDR~a)~\THROWREF \\ + S; F; \HANDLER_n\{(\CATCH~x~l)~\catch^\ast\}~\XT[(\REFEXNADDR~a)~\THROWREF]~\END &\stepto& + \X{exn}.\EIFIELDS~(\BR~l) \\ && + (\begin{array}[t]{@{}r@{~}l@{}} + \iff & \X{exn} = S.\SEXNS[a] \\ + \land & \X{exn}.\EITAG = F.\AMODULE.\MITAGS[x]) \\ + \end{array} \\ + S; F; \HANDLER_n\{(\CATCHREF~x~l)~\catch^\ast\}~\XT[(\REFEXNADDR~a)~\THROWREF]~\END &\stepto& + \X{exn}.\EIFIELDS~(\REFEXNADDR~a)~(\BR~l) \\ && + (\begin{array}[t]{@{}r@{~}l@{}} + \iff & \X{exn} = S.\SEXNS[a] \\ + \land & \X{exn}.\EITAG = F.\AMODULE.\MITAGS[x]) \\ + \end{array} \\ + \HANDLER_n\{(\CATCHALL~l)~\catch^\ast\}~\XT[(\REFEXNADDR~a)~\THROWREF]~\END &\stepto& + (\BR~l) \\ + \HANDLER_n\{(\CATCHALLREF~l)~\catch^\ast\}~\XT[(\REFEXNADDR~a)~\THROWREF]~\END &\stepto& + (\REFEXNADDR~a)~(\BR~l) \\ + \HANDLER_n\{\catch_1~\catch^\ast\}~\XT[(\REFEXNADDR~a)~\THROWREF]~\END &\stepto& + \HANDLER_n\{\catch^\ast\}~\XT[(\REFEXNADDR~a)~\THROWREF]~\END \\ && + (\otherwise) \\ \end{array} @@ -2820,9 +2881,9 @@ Control Instructions 6. Repeat :math:`l+1` times: - a. While the top of the stack is a value, a |handler|, or a |CAUGHTadm| instruction, do: + a. While the top of the stack is a value or a :ref:`handler `, do: - i. Pop the value from the stack. + i. Pop the value or handler from the stack. b. Assert: due to :ref:`validation `, the top of the stack now is a label. @@ -3074,13 +3135,12 @@ When the end of a block is reached without a jump, exception, or trap aborting i .. index:: exception handling, throw context, tag, exception tag pair: handling; exception -.. _exec-catchadm: -.. _exec-delegateadm: +.. _exec-handler: Exception Handling ~~~~~~~~~~~~~~~~~~ -The following auxiliary rules define the semantics of entering and exiting :ref:`exception handlers ` through :ref:`try ` instructions, and handling thrown exceptions. +The following auxiliary rules define the semantics of entering and exiting |TRYTABLE| blocks. .. _exec-handler-enter: @@ -3097,163 +3157,36 @@ Entering :math:`\instr^\ast` with label :math:`L` and exception handler :math:`H .. note:: No formal reduction rule is needed for entering an exception :ref:`handler ` because it is an :ref:`administrative instruction ` - that the :ref:`try ` instruction reduces to directly. + that the |TRYTABLE| instruction reduces to directly. .. _exec-handler-exit: Exiting an exception handler ............................ -When the end of a :ref:`try ` instruction is reached without a jump, exception, or trap, then the following steps are performed. +When the end of a |TRYTABLE| block is reached without a jump, exception, or trap, then the following steps are performed. 1. Let :math:`m` be the number of values on the top of the stack. 2. Pop the values :math:`\val^m` from the stack. -3. Assert: due to :ref:`validation `, the handler :math:`H` is now on the top of the stack. +3. Assert: due to :ref:`validation `, a handler and a label are now on the top of the stack. + +4. Pop the label from the stack. -4. Pop the handler from the stack. +5. Pop the handler :math:`H` from the stack. -5. Push :math:`\val^m` back to the stack. +6. Push :math:`\val^m` back to the stack. -6. Jump to the position after the |END| of the administrative instruction associated with the handler :math:`H`. +7. Jump to the position after the |END| of the administrative instruction associated with the handler :math:`H`. .. math:: ~\\[-1ex] \begin{array}{lcl@{\qquad}l} - \HANDLERadm_m\{\handler\}~\val^m~\END &\stepto& \val^m \\ + \HANDLER_m\{\catch^\ast\}~\val^m~\END &\stepto& \val^m \\ \end{array} -.. _exec-throwadm: - -Throwing an exception with :ref:`tag address ` :math:`a` -........................................................................ - -When a throw occurs, then values, labels, active catch clauses, -and call frames are popped if necessary, until an appropriate exception handler is found -on the top of the stack. - - 1. Assert: due to :ref:`validation `, :math:`S.\STAGS[a]` exists. - - 2. Let :math:`[t^n] \to []` be the :ref:`tag type ` :math:`S.\STAGS[a].\TAGITYPE`. - - 3. Assert: due to :ref:`validation `, there are :math:`n` values on the top of the stack. - - 4. Pop the :math:`n` values :math:`\val^n` from the stack. - - 5. While the stack is not empty and the top of the stack is not an :ref:`exception handler `, do: - - a. Pop the top element from the stack. - - 6. Assert: the stack is now either empty, or there is an exception handler on the top of the stack. - - 7. If the stack is empty, then: - - a. Return the uncaught exception :math:`\val^n~(\THROWadm~a)` as a :ref:`result `. - -8. Else assert: there is an :ref:`exception handler ` :math:`H` on the top of the stack. - -9. Pop the exception handler :math:`H` from the stack. - -10. If :math:`H` is list of handlers, then: - - a. While :math:`H` is not empty, do: - - i. Let :math:`(a_1^?~\instr^\ast)` be the first handler in :math:`H`. - - ii. If :math:`a_1^? = \epsilon`, then: - - * :ref:`Enter ` the block :math:`\instr^\ast` with caught exception :math:`a~\val^n`. - - iii. Else if :math:`a_1^? = a`, then: - - * :ref:`Enter ` the block :math:`\val^n~\instr^\ast` with caught exception :math:`a~\val^n`. - - iv. Else, pop the first handler from :math:`H`. - - b. Else, the exception was not caught by :math:`H`: - - i. Put the values :math:`\val^n` back onto the stack. - - ii. :ref:`Throw ` an exception with tag address :math:`a`. - -11. Else :math:`H` is a label index :math:`l`. - - a. Assert: due to :ref:`validation `, the stack contains at least :math:`l` labels. - - b. Repeat :math:`l` times: - - i. While the top of the stack is not a label, do: - - * Pop the top element from the stack. - - c. Assert: due to :ref:`validation `, the top of the stack now is a label. - - d. Pop the label from the stack. - - e. Push the values :math:`\val^n` onto the stack. - - f. :ref:`Throw ` an exception with tag address :math:`a`. - -.. math:: - \begin{array}{rcl} - \HANDLERadm_n\{\}~\XT[(\THROWadm~a)]~\END &\stepto& - \XT[(\THROWadm~a)] \\ - \HANDLERadm_n\{(a_1^?~\instr^\ast)~(a'^?~\instr'^\ast)^\ast\}~\XT[(\THROWadm~a)]~\END &\stepto& - \HANDLERadm_n\{(a'^?~\instr'^\ast)^\ast~\XT[(\THROWadm~a)]~\END \\ - && (\iff a_1^? \neq \epsilon \land a_1^? \neq a) \\ - S;~\HANDLERadm_n\{(a_1^?~\instr^\ast)~(a'^?~\instr'^\ast)^\ast\}~\XT[\val^n~(\THROWadm~a)]~\END &\stepto& - S;~\CAUGHTadm_n\{a~\val^n\}~(\val^n)^?~\instr^\ast~\END \\ - && (\iff~(a_1^? = \epsilon \lor a_1^? = a)~\land\\ - && \ S.\STAGS[a].\TAGITYPE = [t^n]\to[]) \\ - \LABEL_n\{\}~\XB^l[\HANDLERadm_n\{l\}~\XT[(\THROWadm~a)]~\END]~\END &\stepto& - \XT[(\THROWadm~a)] \\ - \end{array} - -.. note:: - The rules are formulated in this way to allow looking up the exception values in the throw context, - only when a thrown exception is caught. - - -.. _exec-caughtadm-enter: - -Entering :math:`\instr^\ast` with caught exception :math:`\{\exn\}` -................................................................... - -1. Push the caught exception |exn| onto the stack. - -2. Jump to the start of the instruction sequence :math:`\instr^\ast`. - - -.. _exec-caughtadm-exit: - -Exiting a block with a caught exception -....................................... - -When the |END| of a block with a caught exception is reached without a jump, thrown exception, or trap, then the following steps are performed. - -1. Let :math:`\val^m` be the values on the top of the stack. - -2. Pop the values :math:`\val^m` from the stack. - -3. Assert: due to :ref:`validation `, a caught exception is now on the top of the stack. - -4. Pop the caught exception from the stack. - -5. Push :math:`\val^m` back to the stack. - -6. Jump to the position after the |END| of the administrative instruction associated with the caught exception. - -.. math:: - \begin{array}{rcl} - \CAUGHTadm_n\{\exn\}~\val^m~\END &\stepto& \val^m - \end{array} - -.. note:: - A caught exception can only be rethrown from the scope of the administrative instruction associated with it, i.e., from the scope of the |CATCH| or |CATCHALL| block of a :ref:`try-catch ` instruction that caught it. Upon exit from that block, the caught exception is discarded. - - .. index:: ! call, function, function instance, label, frame Function Calls diff --git a/document/core/exec/modules.rst b/document/core/exec/modules.rst index f81a4231..a43f55e9 100644 --- a/document/core/exec/modules.rst +++ b/document/core/exec/modules.rst @@ -157,8 +157,23 @@ The following auxiliary typing rules specify this typing relation relative to a } -:ref:`External References ` :math:`\REFEXTERNADDR~a` -....................................................................... +:ref:`Exception References ` :math:`\REFEXNADDR~a` +.............................................................. + +* The store entry :math:`S.\SEXNS[a]` must exist. + +* Then the value is valid with :ref:`reference type ` :math:`\EXNREF`. + +.. math:: + \frac{ + S.\SEXNS[a] = \exninst + }{ + S \vdashval \REFEXNADDR : \EXNREF + } + + +:ref:`External References ` :math:`\REFEXTERNADDR~a` +............................................................................ * The value is valid with :ref:`reference type ` :math:`\EXTERNREF`. diff --git a/document/core/exec/runtime.rst b/document/core/exec/runtime.rst index 9acda299..021a9dcd 100644 --- a/document/core/exec/runtime.rst +++ b/document/core/exec/runtime.rst @@ -12,7 +12,9 @@ Runtime Structure .. _syntax-num: .. _syntax-vecc: .. _syntax-ref: -.. _syntax-ref.extern: +.. _syntax-ref.func-addr: +.. _syntax-ref.exn-addr: +.. _syntax-ref.extern-addr: .. _syntax-val: Values @@ -26,7 +28,8 @@ It is convenient to reuse the same notation as for the |CONST| :ref:`instruction References other than null are represented with additional :ref:`administrative instructions `. They either are *function references*, pointing to a specific :ref:`function address `, -or *external references* pointing to an uninterpreted form of :ref:`extern address ` that can be defined by the :ref:`embedder ` to represent its own objects. +*exception references*, pointing to a specific :ref:`exception address `, +or *external references* pointing to an uninterpreted form of :ref:`external address ` that can be defined by the :ref:`embedder ` to represent its own objects. .. math:: \begin{array}{llcl} @@ -40,6 +43,7 @@ or *external references* pointing to an uninterpreted form of :ref:`extern addre \production{reference} & \reff &::=& \REFNULL~t \\&&|& \REFFUNCADDR~\funcaddr \\&&|& + \REFEXNADDR~\exnaddr \\&&|& \REFEXTERNADDR~\externaddr \\ \production{value} & \val &::=& \num ~|~ \vecc ~|~ \reff \\ @@ -67,7 +71,7 @@ Convention * The meta variable :math:`r` ranges over reference values where clear from context. -.. index:: ! result, value, trap, exception +.. index:: ! result, value, trap, exception, exception address pair: abstract syntax; result .. _syntax-result: @@ -75,16 +79,17 @@ Results ~~~~~~~ A *result* is the outcome of a computation. -It is either a sequence of :ref:`values `, a :ref:`trap `, or an :ref:`exception `. +It is either a sequence of :ref:`values `, a :ref:`trap `, or a thrown :ref:`exception `. .. math:: \begin{array}{llcl} \production{result} & \result &::=& \val^\ast \\&&|& \TRAP \\&&|& - \XT[(\THROWadm~\tagaddr)] + \XT[(\REFEXNADDR~\exnaddr)~\THROWREF] \end{array} + .. index:: ! store, function instance, table instance, memory instance, tag instance, global instance, module, allocation pair: abstract syntax; store .. _syntax-store: @@ -94,7 +99,7 @@ Store ~~~~~ The *store* represents all global state that can be manipulated by WebAssembly programs. -It consists of the runtime representation of all *instances* of :ref:`functions `, :ref:`tables `, :ref:`memories `, :ref:`tags `, and :ref:`globals `, :ref:`element segments `, and :ref:`data segments ` that have been :ref:`allocated ` during the life time of the abstract machine. [#gc]_ +It consists of the runtime representation of all *instances* of :ref:`functions `, :ref:`tables `, :ref:`memories `, :ref:`tags `, and :ref:`globals `, :ref:`element segments `, :ref:`data segments `, and :ref:`exceptions ` that have been :ref:`allocated ` during the life time of the abstract machine. [#gc]_ It is an invariant of the semantics that no element or data instance is :ref:`addressed ` from anywhere else but the owning module instances. @@ -110,12 +115,13 @@ Syntactically, the store is defined as a :ref:`record ` listing \STAGS & \taginst^\ast, \\ \SGLOBALS & \globalinst^\ast, \\ \SELEMS & \eleminst^\ast, \\ - \SDATAS & \datainst^\ast ~\} \\ + \SDATAS & \datainst^\ast, \\ + \SEXNS & \exninst^\ast ~\} \\ \end{array} \end{array} .. [#gc] - In practice, implementations may apply techniques like garbage collection to remove objects from the store that are no longer referenced. + In practice, implementations may apply techniques like garbage collection or reference counting to remove objects from the store that are no longer referenced. However, such techniques are not semantically observable, and hence outside the scope of this specification. @@ -134,6 +140,7 @@ Convention pair: abstract syntax; global address pair: abstract syntax; element address pair: abstract syntax; data address + pair: abstract syntax; exception address pair: abstract syntax; host address pair: function; address pair: table; address @@ -142,6 +149,7 @@ Convention pair: global; address pair: element; address pair: data; address + pair: exception; address pair: host; address .. _syntax-funcaddr: .. _syntax-tableaddr: @@ -150,13 +158,14 @@ Convention .. _syntax-globaladdr: .. _syntax-elemaddr: .. _syntax-dataaddr: +.. _syntax-exnaddr: .. _syntax-externaddr: .. _syntax-addr: Addresses ~~~~~~~~~ -:ref:`Function instances `, :ref:`table instances `, :ref:`memory instances `, :ref:`tag instances `, :ref:`global instances `, :ref:`element instances `, and :ref:`data instances ` in the :ref:`store ` are referenced with abstract *addresses*. +:ref:`Function instances `, :ref:`table instances `, :ref:`memory instances `, :ref:`tag instances `, :ref:`global instances `, :ref:`element instances `, :ref:`data instances `, and :ref:`exception instances ` in the :ref:`store ` are referenced with abstract *addresses*. These are simply indices into the respective store component. In addition, an :ref:`embedder ` may supply an uninterpreted set of *host addresses*. @@ -178,6 +187,8 @@ In addition, an :ref:`embedder ` may supply an uninterpreted set of *h \addr \\ \production{data address} & \dataaddr &::=& \addr \\ + \production{exception address} & \exnaddr &::=& + \addr \\ \production{extern address} & \externaddr &::=& \addr \\ \end{array} @@ -444,6 +455,24 @@ It filters out entries of a specific kind in an order-preserving fashion: * :math:`\evglobals(\externval^\ast) = [\globaladdr ~|~ (\EVGLOBAL~\globaladdr) \in \externval^\ast]` +.. index:: ! exception instance, tag, tag address, + pair: abstract syntax; exception instance + pair: exception; instance +.. _syntax-exninst: + +Exception Instances +~~~~~~~~~~~~~~~~~~~ + +An *exception instance* is the runtime representation of an _exception_ produced by a |THROW| instruction. +It holds the :ref:`address ` of the respective :ref:`tag ` and the argument :ref:`values `. + +.. math:: + \begin{array}{llcl} + \production{exception instance} & \exninst &::=& + \{ \EITAG~\tagaddr, \EIFIELDS~\vec(\val) \} \\ + \end{array} + + .. index:: ! stack, ! frame, ! label, ! handler, instruction, store, activation, function, call, local, module instance, exception handler, exception pair: abstract syntax; frame @@ -451,17 +480,17 @@ It filters out entries of a specific kind in an order-preserving fashion: pair: abstract syntax; handler .. _syntax-frame: .. _syntax-label: +.. _syntax-handler: .. _frame: .. _label: .. _handler: -.. _exn: .. _stack: Stack ~~~~~ Besides the :ref:`store `, most :ref:`instructions ` interact with an implicit *stack*. -The stack contains five kinds of entries: +The stack contains the following kinds of entries: * *Values*: the *operands* of instructions. @@ -471,8 +500,6 @@ The stack contains five kinds of entries: * *Handlers*: active exception handlers. -* *Exceptions*: caught exceptions. - These entries can occur on the stack in any order during the execution of a program. Stack entries are described by abstract syntax as follows. @@ -528,38 +555,18 @@ and a reference to the function's own :ref:`module instance ` The values of the locals are mutated by respective :ref:`variable instructions `. -.. _syntax-handler: -.. _syntax-exn: - -Exception handlers and exceptions -................................. - -Exception handlers are installed by |TRY| instructions and are either a list of handlers or a label index. +Exception Handlers +.................. -A list of handlers is a mapping from :ref:`tag addresses ` -to their associated branch *targets*. A single handler is expressed syntactically as a possibly empty sequence of -:ref:`instructions ` possibly following a :ref:`tag address `. -If there is no :ref:`tag address `, the instructions of that handler correspond to a |CATCHALL| clause. - -An exception may be temporarily pushed onto the stack when it is :ref:`thrown and caught ` by a handler. - -A handler can also consist of a single |labelidx|, which denotes an outer block to which every caught exception will be delegated, by implicitly rethrowing inside that block. -This handler does not catch exceptions, but only rethrows them. +Exception handlers are installed by |TRYTABLE| instructions and record the corresponding list of :ref:`catch clauses `: .. math:: \begin{array}{llllll} - \production{handler} & \handler &::=& (\tagaddr^?~\instr^\ast)^\ast &|& \labelidx\\ - \production{exception} & \exn &::=& \tagaddr~\val^\ast && + \production{handler} & \handler &::=& + \HANDLER_n\{\catch^\ast\} \end{array} -Intuitively, for each individual handler :math:`(\tagaddr^?~\instr^\ast)`, the instruction block :math:`\instr^\ast` is the *continuation* to execute -when the handler catches a thrown exception with tag |tagaddr|, or for any exception, when that handler specifies no tag address. -If the list of handlers is empty, or if the tag address of the thrown exception is not in any of the handlers in the list, and there is no |CATCHALL| clause, then the exception will be rethrown. - -When a thrown exception is caught by a handler, the caught exception is pushed onto the stack and the block of that handler's target is :ref:`entered `. -When exiting a block with a caught exception, the exception is discarded. - -A handler consisting of a |labelidx| :math:`l` can be thought of as a branch to that label that happens in case an exception occurs, immediately followed by a rethrow of the exception at the target site. +The handlers on the stack are searched when an exception is :ref:`thrown `. .. _exec-expand: @@ -585,11 +592,7 @@ Conventions .. index:: ! administrative instructions, function, function instance, function address, label, frame, instruction, trap, call, memory, memory instance, table, table instance, element, data, segment, tag, tag instance, tag address, exception, reftype, handler, caught, caught exception pair:: abstract syntax; administrative instruction .. _syntax-trap: -.. _syntax-reffuncaddr: .. _syntax-invoke: -.. _syntax-throwadm: -.. _syntax-handleradm: -.. _syntax-caughtadm: .. _syntax-instr-admin: Administrative Instructions @@ -607,27 +610,24 @@ In order to express the reduction of :ref:`traps `, :ref:`calls `. Similarly, |REFEXTERNADDR| represents :ref:`external references `. +The |REFFUNCADDR| instruction represents :ref:`function reference values `. +Similarly, |REFEXTERNADDR| represents :ref:`external references `. +The |REFEXNADDR| instruction represents an :ref:`exception reference `. The |INVOKE| instruction represents the imminent invocation of a :ref:`function instance `, identified by its :ref:`address `. It unifies the handling of different forms of calls. -The |THROWadm| instruction represents the imminent throw of an exception based on a :ref:`tag instance `, identified by its :ref:`address `. -The values it will consume depend on its :ref:`tag type `. -It unifies the different forms of throwing exceptions. - -The |LABEL|, |FRAME|, |HANDLERadm|, and |CAUGHTadm| instructions model :ref:`labels `, :ref:`frames `, active :ref:`exception handlers `, and :ref:`caught exceptions `, respectively, :ref:`"on the stack" `. +The |LABEL|, |FRAME|, and |HANDLER| instructions model :ref:`labels `, :ref:`frames `, and active :ref:`exception handlers `, respectively, :ref:`"on the stack" `. Moreover, the administrative syntax maintains the nesting structure of the original :ref:`structured control instruction ` or :ref:`function body ` and their :ref:`instruction sequences ` with an |END| marker. That way, the end of the inner instruction sequence is known when part of an outer sequence. @@ -670,24 +670,16 @@ In order to specify the reduction of :ref:`branches `, the .. math:: \begin{array}{llll} - \production{block contexts} & \XB^0 &::=& - \val^\ast~[\_]~\instr^\ast \\ - \production{block contexts} & \XB^{k+1} &::=& - \val^\ast~\LABEL_n\{\instr^\ast\}~\XB^k~\END~\instr^\ast \\ + \production{block contexts} & \XB^k &::=& + \val~\XB^k ~|~ \XB^k~\instr ~|~ \HANDLER_n\{\catch^\ast\}~\XB^k~\END ~|~ \XC^k \\ + \production{label contexts} & \XC^0 &::=& + [\_] \\ + \production{label contexts} & \XC^{k+1} &::=& + \LABEL_n\{\instr^\ast\}~\XB^k~\END \\ \end{array} This definition allows to index active labels surrounding a :ref:`branch ` or :ref:`return ` instruction. -In order to be able to break jumping over exception handlers and caught exceptions, these new structured administrative control instructions are allowed to appear after labels in block contexts, by extending block context as follows. - -.. math:: - \begin{array}{llll} - \production{control contexts} & \XC^{k} &::=& \HANDLERadm_n\{\handler\}~\XB^k~\END \\ - & & | & \CAUGHTadm_n~\{\exn\}~\XB^k~\END \\ - \production{block contexts} & \XB^0 &::=& \dots ~|~ \val^\ast~\XC^0~\instr^\ast\\ - \production{block contexts} & \XB^{k+1} &::=& \dots ~|~ \val^\ast~\XC^{k+1}~\instr^\ast \\ - \end{array} - .. note:: For example, the :ref:`reduction ` of a simple branch can be defined as follows: @@ -696,18 +688,17 @@ In order to be able to break jumping over exception handlers and caught exceptio Here, the hole :math:`[\_]` of the context is instantiated with a branch instruction. When a branch occurs, - this rule replaces the targeted label and associated instruction sequence with the label's continuation. + this rule replaces the target label and associated instruction sequence with the label's continuation. The selected label is identified through the :ref:`label index ` :math:`l`, which corresponds to the number of surrounding |LABEL| instructions that must be hopped over -- which is exactly the count encoded in the index of a block context. -.. index:: ! throw context, tag, throw address, catch block, handler, exception +.. index:: ! throw context, tag, throw address, catch clause, handler, exception .. _syntax-ctxt-throw: Throw Contexts .............. -In order to specify the reduction of |TRY| blocks -with the help of the administrative instructions |THROWadm|, |HANDLERadm|, and |CAUGHTadm|, +In order to specify the reduction of |TRYTABLE| blocks, the following syntax of *throw contexts* is defined, as well as associated structural rules: .. math:: @@ -716,48 +707,13 @@ the following syntax of *throw contexts* is defined, as well as associated struc [\_] \\ &&|& \val^\ast~\XT~\instr^\ast \\ &&|& \LABEL_n\{\instr^\ast\}~\XT~\END \\ &&|& - \CAUGHTadm_n\{\exn\}~\XT~\END \\ &&|& \FRAME_n\{F\}~\XT~\END \\ \end{array} -Throw contexts allow matching the program context around a throw instruction up to the innermost enclosing |HANDLERadm|, thereby selecting the exception |handler| responsible for an exception, if one exists. -If no exception :ref:`handler that catches the exception ` is found, the computation :ref:`results ` in an uncaught exception result value. +Throw contexts allow matching the program context around a throw instruction up to the innermost enclosing :ref:`exception handler `, if one exists. .. note:: - Contrary to block contexts, throw contexts don't skip over handlers. - - |CAUGHTadm| blocks do not represent active handlers. Instead, they delimit the continuation of a handler that has already been selected. Their sole purpose is to record the exception that has been caught, such that |RETHROW| can access it inside such a block. - -.. note:: - For example, catching a simple :ref:`throw ` in a :ref:`try block ` would be as follows. - - Assume that :math:`\expand_F(bt) = [\I32~\F32~\I64] \to [\F32~\I64]`, - and that the tag address `a` of :math:`x` has tag type :math:`[\F32~\I64] \to []`. - Let :math:`\val_{i32}`, :math:`\val_{f32}`, and :math:`\val_{i64}` be values of type |I32|, |F32|, and |I64| respectively. - - .. math:: - \begin{array}{ll} - & \hspace{-5ex} F;~\val_{i32}~\val_{f32}~\val_{i64}~(\TRY~\X{bt}~(\THROW~x)~\CATCH~x~\END) \\ - \stepto & F;~\LABEL_2\{\} (\HANDLERadm_2\{(a~\epsilon)\}~\val_{i32}~\val_{f32}~\val_{i64}~(\THROW~x)~\END)~\END \\ - \end{array} - - :ref:`Handling the thrown exception ` with tag address :math:`a` in the throw context - :math:`T=[\val_{i32}\_]`, with the exception handler :math:`H=(a~\epsilon)` gives: - - .. math:: - \begin{array}{lll} - \stepto & F;~\LABEL_2\{\}~(\CAUGHTadm_2\{a~\val_{f32}~\val_{i64}\}~\val_{f32}~\val_{i64}~\END)~\END & \hspace{9ex}\ \\ - \stepto & F;~\LABEL_2\{\}~\val_{f32}~\val_{i64}~\END & \hspace{9ex}\ \\ - \stepto & \val_{f32}~\val_{i64} & \\ - \end{array} - - - When a throw of the form :math:`\val^m (\THROWadm~a)` occurs, search for an enclosing exception handler is performed, - which means any throw context (that is any other values, labels, frames, and |CAUGHTadm| instructions) surrounding the throw :math:`\val^m (\THROWadm~a)` is popped, - until a :ref:`handler ` for the exception tag :math:`a` is found. - Then the :ref:`caught exception ` containing the tag address :math:`a` and the values :math:`\val^m`, is pushed onto the stack. - - In this particular case, the exception is caught by the exception handler :math:`H` and its values are returned. + Contrary to block contexts, throw contexts do not skip over handlers. .. index:: ! configuration, ! thread, store, frame, instruction, module instruction diff --git a/document/core/syntax/instructions.rst b/document/core/syntax/instructions.rst index e78dd998..fa835ebf 100644 --- a/document/core/syntax/instructions.rst +++ b/document/core/syntax/instructions.rst @@ -634,6 +634,7 @@ The |DATADROP| instruction prevents further use of a passive data segment. This .. _syntax-call_indirect: .. _syntax-instr-seq: .. _syntax-instr-control: +.. _syntax-catch: Control Instructions ~~~~~~~~~~~~~~~~~~~~ @@ -651,32 +652,35 @@ Instructions in this group affect the flow of control. \BLOCK~\blocktype~\instr^\ast~\END \\&&|& \LOOP~\blocktype~\instr^\ast~\END \\&&|& \IF~\blocktype~\instr^\ast~\ELSE~\instr^\ast~\END \\&&|& - \TRY~\blocktype~\instr^\ast~(\CATCH~\tagidx~\instr^\ast)^\ast~(\CATCHALL~\instr^\ast)^?~\END \\ &&|& - \TRY~\blocktype~\instr^\ast~\DELEGATE~\labelidx \\ &&|& + \TRYTABLE~\blocktype~\catch^\ast~\instr^\ast~\END \\ &&|& \THROW~\tagidx \\&&|& - \RETHROW~\labelidx \\ &&|& + \THROWREF \\ &&|& \BR~\labelidx \\&&|& \BRIF~\labelidx \\&&|& \BRTABLE~\vec(\labelidx)~\labelidx \\&&|& \RETURN \\&&|& \CALL~\funcidx \\&&|& \CALLINDIRECT~\tableidx~\typeidx \\ + \production{catch clause} & \catch &::=& + \CATCH~\tagidx~\labelidx \\ &&|& + \CATCHREF~\tagidx~\labelidx \\ &&|& + \CATCHALL~\labelidx \\ &&|& + \CATCHALLREF~\labelidx \\ \end{array} The |NOP| instruction does nothing. The |UNREACHABLE| instruction causes an unconditional :ref:`trap `. -The |BLOCK|, |LOOP|, |IF|, and |TRY| instructions are *structured* instructions. +The |BLOCK|, |LOOP|, |IF|, and |TRYTABLE| instructions are *structured* instructions. They bracket nested sequences of instructions, called *blocks*, -separated by either |ELSE|, |CATCH|, or |CATCHALL| pseudo-instructions, -and terminated with either an |END| or a |DELEGATE| pseudo-instruction. +separated by the |ELSE| pseudo-instruction, +and terminated with an |END| pseudo-instruction. As the grammar prescribes, they must be well-nested. -The instructions |TRY|, |THROW|, and |RETHROW|, are concerned with handling exceptions. -The |TRY| instruction installs an exception handler, and may either handle exceptions in the case of |CATCH| and |CATCHALL|, -or rethrow them in an outer block in the case of |DELEGATE|. -The |THROW| and |RETHROW| instructions alter control flow by searching for a matching handler in one of the enclosing |TRY| blocks, if any. +The instructions |TRYTABLE|, |THROW|, and |THROWREF| are concerned with *exceptions*. +The |TRYTABLE| instruction installs an exception handler that handles exceptions as specified by its catch clauses.. +The |THROW| and |THROWREF| instructions raise and reraise an exception, repsectively, and transfers control to the innermost enclosing exception handler that has a matching catch clause. A structured instruction can consume *input* and produce *output* on the operand stack according to its annotated *block type*. It is given either as a :ref:`type index ` that refers to a suitable :ref:`function type `, or as an optional :ref:`value type ` inline, which is a shorthand for the function type :math:`[] \to [\valtype^?]`. @@ -694,9 +698,6 @@ In case of |BLOCK| or |IF| it is a *forward jump*, resuming execution after the matching |END|. In case of |LOOP| it is a *backward jump* to the beginning of the loop. -When |TRY|--|DELEGATE| handles an exception, it also behaves similar to a forward jump, -effectively rethrowing the caught exception right before the matching |END|. - .. note:: This enforces *structured control flow*. Intuitively, a branch targeting a |BLOCK| or |IF| behaves like a :math:`\K{break}` statement in most C-like languages, diff --git a/document/core/syntax/types.rst b/document/core/syntax/types.rst index b1c164cc..9e0f8e40 100644 --- a/document/core/syntax/types.rst +++ b/document/core/syntax/types.rst @@ -85,11 +85,13 @@ Reference Types .. math:: \begin{array}{llll} \production{reference type} & \reftype &::=& - \FUNCREF ~|~ \EXTERNREF \\ + \FUNCREF ~|~ \EXNREF ~|~ \EXTERNREF \\ \end{array} The type |FUNCREF| denotes the infinite union of all references to :ref:`functions `, regardless of their :ref:`function types `. +The type |EXNREF| denotes the infinite union of all references to :ref:`exceptions `, regardless of their associated :ref:`tag types `. + The type |EXTERNREF| denotes the infinite union of all references to objects owned by the :ref:`embedder ` and that can be passed into WebAssembly under this type. Reference types are *opaque*, meaning that neither their size nor their bit pattern can be observed. diff --git a/document/core/text/instructions.rst b/document/core/text/instructions.rst index 07882dc2..d4f47253 100644 --- a/document/core/text/instructions.rst +++ b/document/core/text/instructions.rst @@ -62,11 +62,11 @@ Control Instructions .. _text-loop: .. _text-if: .. _text-instr-block: -.. _text-try: +.. _text-try_table: +.. _text-catch: :ref:`Structured control instructions ` can bind an optional symbolic :ref:`label identifier `. -The same label identifier may optionally be repeated after the corresponding :math:`\T{end}`, :math:`\T{else}`, :math:`\T{catch}`, :math:`\T{catch\_all}`, and :math:`\T{delegate}` -pseudo instructions, to indicate the matching delimiters. +The same label identifier may optionally be repeated after the corresponding :math:`\T{end}` or :math:`\T{else}` keywords, to indicate the matching delimiters. Their :ref:`block type ` is given as a :ref:`type use `, analogous to the type of :ref:`functions `. However, the special case of a type use that is syntactically empty or consists of only a single :ref:`result ` is not regarded as an :ref:`abbreviation ` for an inline :ref:`function type `, but is parsed directly into an optional :ref:`value type `. @@ -91,15 +91,22 @@ However, the special case of a type use that is syntactically empty or consists \text{else}~~\Tid_1^?~~(\X{in}_2{:}\Tinstr_{I'})^\ast~~\text{end}~~\Tid_2^? \\ &&&\qquad \Rightarrow\quad \IF~\X{bt}~\X{in}_1^\ast~\ELSE~\X{in}_2^\ast~\END \qquad (\iff \Tid_1^? = \epsilon \vee \Tid_1^? = \Tlabel, \Tid_2^? = \epsilon \vee \Tid_2^? = \Tlabel) \\ &&|& - \text{try}~~I'{:}\Tlabel_I~~\X{bt}{:}\Tblocktype~~(\X{in}_1{:}\Tinstr_{I'})^\ast~~ - (\text{catch}~~\Tid_1^?~~x{:}\Ttagidx_I~~(\X{in}_2{:}\Tinstr_{I'})^\ast)^\ast~~ - \\ &&&\qquad\qquad (\text{catch\_all}~~\Tid_1^?~~(\X{in}_3{:}\Tinstr_{I'})^\ast)^?~~\text{end}~~\Tid_2^? - \\ &&&\qquad \Rightarrow\quad \TRY~\X{bt}~\X{in}_1^\ast~(\CATCH~x~\X{in}_2^\ast)^\ast~(\CATCHALL~\X{in}_3^\ast)^?~\END - \\ &&&\qquad\qquad (\iff \Tid_1^? = \epsilon \vee \Tid_1^? = \Tlabel, \Tid_2^? = \epsilon \vee \Tid_2^? = \Tlabel) \\ &&|& - \text{try}~~I'{:}\Tlabel_I~~\X{bt}{:}\Tblocktype~~(\X{in}_1{:}\Tinstr_{I'})^\ast - ~~\text{delegate}~~l{:}\Tlabelidx_I~~\X{l}{:}\Tlabelidx_I - \\ &&&\qquad \Rightarrow\quad \TRY~\X{bt}~\X{in}_1^\ast~\DELEGATE~l - \qquad\quad~~ (\iff \Tid^? = \epsilon \vee \Tid^? = \Tlabel) \\ + \text{try\_table}~~I'{:}\Tlabel_I~~\X{bt}{:}\Tblocktype~~(c{:}\Tcatch_I)^\ast~~(\X{in}{:}\Tinstr_{I'})^\ast~~\text{end}~~\Tid^? + \\ &&&\qquad \Rightarrow\quad \TRYTABLE~\X{bt}~c^\ast~\X{in}^\ast~~\END + \qquad\qquad (\iff \Tid^? = \epsilon \vee \Tid^? = \Tlabel) \\ + \production{catch clause} & \Tcatch_I & + \begin{array}[t]{@{}c@{}} ::= \\ | \\ | \\ | \\ \end{array} + & + \begin{array}[t]{@{}lcll@{}} + \text{(}~\text{catch}~~x{:}\Ttagidx_I~~l{:}\Tlabelidx_I~\text{)} + &\Rightarrow& \CATCH~x~l \\ + \text{(}~\text{catch\_ref}~~x{:}\Ttagidx_I~~l{:}\Tlabelidx_I~\text{)} + &\Rightarrow& \CATCHREF~x~l \\ + \text{(}~\text{catch\_all}~~l{:}\Tlabelidx_I~\text{)} + &\Rightarrow& \CATCHALL~l \\ + \text{(}~\text{catch\_all\_ref}~~l{:}\Tlabelidx_I~\text{)} + &\Rightarrow& \CATCHALLREF~l \\ + \end{array} \\ \end{array} .. note:: @@ -109,7 +116,7 @@ However, the special case of a type use that is syntactically empty or consists .. _text-nop: .. _text-unreachable: .. _text-throw: -.. _text-rethrow: +.. _text-throw_ref: .. _text-br: .. _text-br_if: .. _text-br_table: @@ -125,7 +132,7 @@ All other control instruction are represented verbatim. \text{unreachable} &\Rightarrow& \UNREACHABLE \\ &&|& \text{nop} &\Rightarrow& \NOP \\ &&|& \text{throw}~~x{:}\Ttagidx_I &\Rightarrow& \THROW~x \\ &&|& - \text{rethrow}~~l{:}\Tlabelidx_I &\Rightarrow& \RETHROW~l \\ &&|& + \text{throw\_ref} &\Rightarrow& \THROWREF \\ &&|& \text{br}~~l{:}\Tlabelidx_I &\Rightarrow& \BR~l \\ &&|& \text{br\_if}~~l{:}\Tlabelidx_I &\Rightarrow& \BRIF~l \\ &&|& \text{br\_table}~~l^\ast{:}\Tvec(\Tlabelidx_I)~~l_N{:}\Tlabelidx_I @@ -940,16 +947,9 @@ Such a folded instruction can appear anywhere a regular instruction can. \quad\equiv \\ &\qquad \Tfoldedinstr^\ast~~\text{if}~~\Tlabel &\hspace{-12ex} \Tblocktype~~\Tinstr_1^\ast~~\text{else}~~(\Tinstr_2^\ast)^?~\text{end} \\ & - \text{(}~\text{try}~~\Tlabel~~\Tblocktype~~\text{(}~\text{do} &\hspace{-8ex} \Tinstr_1^\ast~\text{)}~~ - (\text{(}~\text{catch}~~x{:}\Ttagidx_I~~\Tinstr_2^\ast~\text{)})^\ast \\ &\quad - (\text{(}~\text{catch\_all}~~\Tinstr_3^\ast~\text{)})^?~\text{)} - \quad\equiv \\ &\qquad - \text{try}~~\Tlabel~~\Tblocktype~~\Tinstr_1^\ast - &\hspace{-5ex} (\text{catch}~~x{:}\Ttagidx_I~~\Tinstr_2^\ast)^\ast~~(\text{catch\_all}~~\Tinstr_3^\ast)^?~~\text{end} \\ & - \text{(}~\text{try}~~\Tlabel~~\Tblocktype~~\text{(}~\text{do} &\hspace{-8ex} \Tinstr^\ast~\text{)}~~ - \text{(}~\text{delegate}~~l{:}\Tlabelidx~~\text{)}~\text{)} + \text{(}~\text{try\_table}~~\Tlabel~~\Tblocktype~~\Tcatch^\ast~~\Tinstr^\ast~\text{)} \quad\equiv \\ &\qquad - \text{try}~~\Tlabel~~\Tblocktype~~\Tinstr^\ast &\hspace{-5ex} \text{delegate}~~l{:}\Tlabelidx \\ + \text{try\_table}~~\Tlabel~~\Tblocktype~~\Tcatch^\ast~~\Tinstr^\ast~~\text{end} \\ \end{array} diff --git a/document/core/text/modules.rst b/document/core/text/modules.rst index 9f354cec..5bf0e209 100644 --- a/document/core/text/modules.rst +++ b/document/core/text/modules.rst @@ -17,6 +17,7 @@ Modules .. _text-funcidx: .. _text-tableidx: .. _text-memidx: +.. _text-tagidx: .. _text-elemidx: .. _text-dataidx: .. _text-globalidx: diff --git a/document/core/text/types.rst b/document/core/text/types.rst index 7705cc57..685a3657 100644 --- a/document/core/text/types.rst +++ b/document/core/text/types.rst @@ -48,9 +48,11 @@ Reference Types \begin{array}{llcll@{\qquad\qquad}l} \production{reference type} & \Treftype &::=& \text{funcref} &\Rightarrow& \FUNCREF \\ &&|& + \text{exnref} &\Rightarrow& \EXNREF \\ &&|& \text{externref} &\Rightarrow& \EXTERNREF \\ \production{heap type} & \Theaptype &::=& \text{func} &\Rightarrow& \FUNCREF \\ &&|& + \text{exn} &\Rightarrow& \EXNREF \\ &&|& \text{extern} &\Rightarrow& \EXTERNREF \\ \end{array} diff --git a/document/core/util/macros.def b/document/core/util/macros.def index eae5e93f..f2e71072 100644 --- a/document/core/util/macros.def +++ b/document/core/util/macros.def @@ -176,6 +176,7 @@ .. Types, terminals .. |to| mathdef:: \xref{syntax/types}{syntax-functype}{\rightarrow} +.. |toF| mathdef:: \xref{syntax/types}{syntax-functype}{\rightarrow} .. |I8| mathdef:: \xref{exec/runtime}{syntax-storagetype}{\K{i8}} .. |I16| mathdef:: \xref{exec/runtime}{syntax-storagetype}{\K{i16}} @@ -194,6 +195,7 @@ .. |FUNCREF| mathdef:: \xref{syntax/types}{syntax-reftype}{\K{funcref}} .. |EXTERNREF| mathdef:: \xref{syntax/types}{syntax-reftype}{\K{externref}} +.. |EXNREF| mathdef:: \xref{syntax/types}{syntax-reftype}{\K{exnref}} .. |MVAR| mathdef:: \xref{syntax/types}{syntax-mut}{\K{var}} .. |MCONST| mathdef:: \xref{syntax/types}{syntax-mut}{\K{const}} @@ -377,12 +379,13 @@ .. |RETURN| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{return}} .. |CALL| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{call}} .. |CALLINDIRECT| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{call\_indirect}} -.. |TRY| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{try}} +.. |TRYTABLE| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{try\_table}} .. |CATCH| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{catch}} +.. |CATCHREF| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{catch\_ref}} .. |CATCHALL| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{catch\_all}} -.. |DELEGATE| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{delegate}} +.. |CATCHALLREF| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{catch\_all\_ref}} .. |THROW| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{throw}} -.. |RETHROW| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{rethrow}} +.. |THROWREF| mathdef:: \xref{syntax/instructions}{syntax-instr-control}{\K{throw\_ref}} .. |DROP| mathdef:: \xref{syntax/instructions}{syntax-instr-parametric}{\K{drop}} .. |SELECT| mathdef:: \xref{syntax/instructions}{syntax-instr-parametric}{\K{select}} @@ -560,6 +563,7 @@ .. |blocktype| mathdef:: \xref{syntax/instructions}{syntax-blocktype}{\X{blocktype}} .. |instr| mathdef:: \xref{syntax/instructions}{syntax-instr}{\X{instr}} +.. |catch| mathdef:: \xref{syntax/instructions}{syntax-catch}{\X{catch}} .. |expr| mathdef:: \xref{syntax/instructions}{syntax-expr}{\X{expr}} @@ -689,6 +693,7 @@ .. |Bblocktype| mathdef:: \xref{binary/instructions}{binary-blocktype}{\B{blocktype}} .. |Binstr| mathdef:: \xref{binary/instructions}{binary-instr}{\B{instr}} +.. |Bcatch| mathdef:: \xref{binary/instructions}{binary-catch}{\B{catch}} .. |Bexpr| mathdef:: \xref{binary/instructions}{binary-expr}{\B{expr}} .. |Blaneidx| mathdef:: \xref{binary/instructions}{binary-laneidx}{\B{laneidx}} @@ -861,6 +866,7 @@ .. |Tplaininstr| mathdef:: \xref{text/instructions}{text-plaininstr}{\T{plaininstr}} .. |Tblockinstr| mathdef:: \xref{text/instructions}{text-blockinstr}{\T{blockinstr}} .. |Tfoldedinstr| mathdef:: \xref{text/instructions}{text-foldedinstr}{\T{foldedinstr}} +.. |Tcatch| mathdef:: \xref{text/instructions}{text-catch}{\T{catch}} .. |Texpr| mathdef:: \xref{text/instructions}{text-expr}{\T{expr}} @@ -913,7 +919,6 @@ .. |CLABELS| mathdef:: \xref{valid/conventions}{context}{\K{labels}} .. |CRETURN| mathdef:: \xref{valid/conventions}{context}{\K{return}} .. |CREFS| mathdef:: \xref{valid/conventions}{context}{\K{refs}} -.. |LCATCH| mathdef:: \xref{valid/conventions}{context}{\K{catch}} .. Contexts, non-terminals @@ -933,6 +938,7 @@ .. |vdashinstr| mathdef:: \xref{valid/instructions}{valid-instr}{\vdash} .. |vdashinstrseq| mathdef:: \xref{valid/instructions}{valid-instr-seq}{\vdash} +.. |vdashcatch| mathdef:: \xref{valid/instructions}{valid-catch}{\vdash} .. |vdashexpr| mathdef:: \xref{valid/instructions}{valid-expr}{\vdash} .. |vdashexprconst| mathdef:: \xref{valid/instructions}{valid-constant}{\vdash} .. |vdashinstrconst| mathdef:: \xref{valid/instructions}{valid-constant}{\vdash} @@ -994,6 +1000,7 @@ .. |globaladdr| mathdef:: \xref{exec/runtime}{syntax-globaladdr}{\X{globaladdr}} .. |elemaddr| mathdef:: \xref{exec/runtime}{syntax-elemaddr}{\X{elemaddr}} .. |dataaddr| mathdef:: \xref{exec/runtime}{syntax-dataaddr}{\X{dataaddr}} +.. |exnaddr| mathdef:: \xref{exec/runtime}{syntax-exnaddr}{\X{exnaddr}} .. |externaddr| mathdef:: \xref{exec/runtime}{syntax-externaddr}{\X{externaddr}} .. Instances, terminals @@ -1022,6 +1029,9 @@ .. |EINAME| mathdef:: \xref{exec/runtime}{syntax-exportinst}{\K{name}} .. |EIVALUE| mathdef:: \xref{exec/runtime}{syntax-exportinst}{\K{value}} +.. |EITAG| mathdef:: \xref{exec/runtime}{syntax-exninst}{\K{tag}} +.. |EIFIELDS| mathdef:: \xref{exec/runtime}{syntax-exninst}{\K{fields}} + .. |EVFUNC| mathdef:: \xref{exec/runtime}{syntax-externval}{\K{func}} .. |EVTABLE| mathdef:: \xref{exec/runtime}{syntax-externval}{\K{table}} .. |EVMEM| mathdef:: \xref{exec/runtime}{syntax-externval}{\K{mem}} @@ -1052,6 +1062,7 @@ .. |eleminst| mathdef:: \xref{exec/runtime}{syntax-eleminst}{\X{eleminst}} .. |datainst| mathdef:: \xref{exec/runtime}{syntax-datainst}{\X{datainst}} .. |exportinst| mathdef:: \xref{exec/runtime}{syntax-exportinst}{\X{exportinst}} +.. |exninst| mathdef:: \xref{exec/runtime}{syntax-exninst}{\X{exninst}} .. |hostfunc| mathdef:: \xref{exec/runtime}{syntax-hostfunc}{\X{hostfunc}} @@ -1074,6 +1085,7 @@ .. |SGLOBALS| mathdef:: \xref{exec/runtime}{syntax-store}{\K{globals}} .. |SELEMS| mathdef:: \xref{exec/runtime}{syntax-store}{\K{elems}} .. |SDATAS| mathdef:: \xref{exec/runtime}{syntax-store}{\K{datas}} +.. |SEXNS| mathdef:: \xref{exec/runtime}{syntax-store}{\K{exns}} .. Store, non-terminals @@ -1094,7 +1106,6 @@ .. |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}} -.. |exn| mathdef:: \xref{exec/runtime}{syntax-exn}{\X{exn}} .. Stack, meta functions @@ -1103,13 +1114,12 @@ .. Administrative Instructions, terminals -.. |REFFUNCADDR| mathdef:: \xref{exec/runtime}{syntax-ref}{\K{ref}} -.. |REFEXTERNADDR| mathdef:: \xref{exec/runtime}{syntax-ref.extern}{\K{ref{.}extern}} +.. |REFFUNCADDR| mathdef:: \xref{exec/runtime}{syntax-ref.func-addr}{\K{ref}} +.. |REFEXTERNADDR| mathdef:: \xref{exec/runtime}{syntax-ref.extern-addr}{\K{ref{.}extern}} +.. |REFEXNADDR| mathdef:: \xref{exec/runtime}{syntax-ref.exn-addr}{\K{ref{.}exn}} .. |TRAP| mathdef:: \xref{exec/runtime}{syntax-trap}{\K{trap}} .. |INVOKE| mathdef:: \xref{exec/runtime}{syntax-invoke}{\K{invoke}} -.. |THROWadm| mathdef:: \xref{exec/runtime}{syntax-throwadm}{\K{throw}} -.. |HANDLERadm| mathdef:: \xref{exec/runtime}{syntax-handleradm}{\K{handler}} -.. |CAUGHTadm| mathdef:: \xref{exec/runtime}{syntax-caughtadm}{\K{caught}} +.. |HANDLER| mathdef:: \xref{exec/runtime}{syntax-handler}{\K{handler}} .. Values & Results, non-terminals @@ -1270,7 +1280,7 @@ .. |vdashadmininstr| mathdef:: \xref{appendix/properties}{valid-instr-admin}{\vdash} -.. |vdashval| mathdef:: \xref{appendix/properties}{valid-val}{\vdash} +.. |vdashval| mathdef:: \xref{exec/modules}{valid-val}{\vdash} .. |vdashresult| mathdef:: \xref{appendix/properties}{valid-result}{\vdash} .. |vdashfuncinst| mathdef:: \xref{appendix/properties}{valid-funcinst}{\vdash} @@ -1280,6 +1290,7 @@ .. |vdashglobalinst| mathdef:: \xref{appendix/properties}{valid-globalinst}{\vdash} .. |vdasheleminst| mathdef:: \xref{appendix/properties}{valid-eleminst}{\vdash} .. |vdashdatainst| mathdef:: \xref{appendix/properties}{valid-datainst}{\vdash} +.. |vdashexninst| mathdef:: \xref{appendix/properties}{valid-exninst}{\vdash} .. |vdashexportinst| mathdef:: \xref{appendix/properties}{valid-exportinst}{\vdash} .. |vdashmoduleinst| mathdef:: \xref{appendix/properties}{valid-moduleinst}{\vdash} @@ -1295,6 +1306,7 @@ .. |vdashglobalinstextends| mathdef:: \xref{appendix/properties}{extend-globalinst}{\vdash} .. |vdasheleminstextends| mathdef:: \xref{appendix/properties}{extend-eleminst}{\vdash} .. |vdashdatainstextends| mathdef:: \xref{appendix/properties}{extend-datainst}{\vdash} +.. |vdashexninstextends| mathdef:: \xref{appendix/properties}{extend-exninst}{\vdash} .. |vdashstoreextends| mathdef:: \xref{appendix/properties}{extend-store}{\vdash} diff --git a/document/core/valid/conventions.rst b/document/core/valid/conventions.rst index fdcf5e96..544a8133 100644 --- a/document/core/valid/conventions.rst +++ b/document/core/valid/conventions.rst @@ -26,7 +26,6 @@ The skeleton of a sound and complete algorithm for type-checking instruction seq .. index:: ! context, function type, table type, memory type, tag type, global type, value type, result type, index space, module, function, tag, label type .. _context: -.. _syntax-labeltype: Contexts ~~~~~~~~ @@ -43,7 +42,7 @@ which collects relevant information about the surrounding :ref:`module ` accessible from the current position, represented by their :ref:`result type `. * *Return*: the return type of the current function, represented as an optional result type that is absent when no return is allowed, as in free-standing expressions. * *References*: the list of :ref:`function indices ` that occur in the module outside functions and can hence be used to form references inside them. @@ -56,19 +55,18 @@ More concretely, contexts are defined as :ref:`records ` :math: .. math:: \begin{array}{llll} - \production{labeltype} & \labeltype & ::= & \LCATCH^?~\resulttype\\ \production{context} & C &::=& \begin{array}[t]{l@{~}ll} \{ & \CTYPES & \functype^\ast, \\ & \CFUNCS & \functype^\ast, \\ & \CTABLES & \tabletype^\ast, \\ & \CMEMS & \memtype^\ast, \\ - & \CTAGS & \tagtype^\ast, \\ + & \CTAGS & \tagtype^\ast, \\ & \CGLOBALS & \globaltype^\ast, \\ & \CELEMS & \reftype^\ast, \\ & \CDATAS & {\ok}^\ast, \\ & \CLOCALS & \valtype^\ast, \\ - & \CLABELS & \labeltype^\ast, \\ + & \CLABELS & \resulttype^\ast, \\ & \CRETURN & \resulttype^?, \\ & \CREFS & \funcidx^\ast ~\} \\ \end{array} diff --git a/document/core/valid/instructions.rst b/document/core/valid/instructions.rst index c6b83eee..2b9a937e 100644 --- a/document/core/valid/instructions.rst +++ b/document/core/valid/instructions.rst @@ -1234,7 +1234,7 @@ Memory Instructions } -.. index:: control instructions, structured control, label, block, branch, block type, label index, label type, function index, type index, tag index, vector, polymorphism, context +.. index:: control instructions, structured control, label, block, branch, block type, label index, result type, function index, type index, tag index, vector, polymorphism, context pair: validation; instruction single: abstract syntax; instruction .. _valid-label: @@ -1281,7 +1281,7 @@ Control Instructions * The :ref:`block type ` must be :ref:`valid ` as some :ref:`function type ` :math:`[t_1^\ast] \to [t_2^\ast]`. -* Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with the :ref:`label type ` :math:`[t_2^\ast]` prepended to the |CLABELS| vector. +* Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with the :ref:`result type ` :math:`[t_2^\ast]` prepended to the |CLABELS| vector. * Under context :math:`C'`, the instruction sequence :math:`\instr^\ast` must be :ref:`valid ` with type :math:`[t_1^\ast] \to [t_2^\ast]`. @@ -1308,7 +1308,7 @@ Control Instructions * The :ref:`block type ` must be :ref:`valid ` as some :ref:`function type ` :math:`[t_1^\ast] \to [t_2^\ast]`. -* Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with the :ref:`label type ` :math:`[t_1^\ast]` prepended to the |CLABELS| vector. +* Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with the :ref:`result type ` :math:`[t_1^\ast]` prepended to the |CLABELS| vector. * Under context :math:`C'`, the instruction sequence :math:`\instr^\ast` must be :ref:`valid ` with type :math:`[t_1^\ast] \to [t_2^\ast]`. @@ -1335,7 +1335,7 @@ Control Instructions * The :ref:`block type ` must be :ref:`valid ` as some :ref:`function type ` :math:`[t_1^\ast] \to [t_2^\ast]`. -* Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with the :ref:`label type ` :math:`[t_2^\ast]` prepended to the |CLABELS| vector. +* Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with the :ref:`result type ` :math:`[t_2^\ast]` prepended to the |CLABELS| vector. * Under context :math:`C'`, the instruction sequence :math:`\instr_1^\ast` must be :ref:`valid ` with type :math:`[t_1^\ast] \to [t_2^\ast]`. @@ -1361,86 +1361,121 @@ Control Instructions -.. _valid-try-catch: +.. _valid-try_table: -:math:`\TRY~\blocktype~\instr_1^\ast~(\CATCH~x~\instr_2^\ast)^\ast~(\CATCHALL~\instr_3^\ast)^?~\END` -.................................................................................................... +:math:`\TRYTABLE~\blocktype~\catch^\ast~\instr^\ast~\END` +......................................................... * The :ref:`block type ` must be :ref:`valid ` as some :ref:`function type ` :math:`[t_1^\ast] \to [t_2^\ast]`. -* Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with the :ref:`label type ` :math:`[t_2^\ast]` prepended to the |CLABELS| vector. +* For every :ref:`catch clause ` :math:`\catch_i` in :math:`\catch^\ast`, :math:`\catch_i` must be :ref:`valid `. + +* Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with the :ref:`result type ` :math:`[t_2^\ast]` prepended to the |CLABELS| vector. * Under context :math:`C'`, - the instruction sequence :math:`\instr_1^\ast` must be :ref:`valid ` with type :math:`[t_1^\ast] \to [t_2^\ast]`. + the instruction sequence :math:`\instr^\ast` must be :ref:`valid ` with type :math:`[t_1^\ast] \to [t_2^\ast]`. -* Let :math:`C''` be the same :ref:`context ` as :math:`C`, but with the :ref:`label type ` :math:`\LCATCH~[t_2^\ast]` prepended to the |CLABELS| vector. +* Then the compound instruction is valid with type :math:`[t_1^\ast] \to [t_2^\ast]`. -* For every :math:`x_i` and :math:`\instr_{2i}^\ast` in :math:`(\CATCH~x~\instr_2^\ast)^\ast`: - * The tag :math:`C.\CTAGS[x_i]` must be defined in the context :math:`C`. +.. math:: + \frac{ + \begin{array}{c} + C \vdashblocktype \blocktype : [t_1^\ast] \to [t_2^\ast] + \qquad + (C \vdashcatch \catch \ok)^\ast + \qquad + C,\CLABELS\,[t_2^\ast] \vdashinstrseq \instr^\ast : [t_1^\ast] \to [t_2^\ast] \\ + \end{array} + }{ + C \vdashinstr \TRYTABLE~\blocktype~\catch^\ast~\instr^\ast~\END : [t_1^\ast] \to [t_2^\ast] + } - * Let :math:`[t_{3i}^\ast] \to [t_{4i}^\ast]` be the :ref:`tag type ` :math:`C.\CTAGS[x_i]`. +.. note:: + The :ref:`notation ` :math:`C,\CLABELS\,[t^\ast]` inserts the new label type at index :math:`0`, shifting all others. - * The :ref:`result type ` :math:`[t_{4i}^\ast]` must be empty. - * Under context :math:`C''`, - the instruction sequence :math:`\instr_{2i}^\ast` must be :ref:`valid ` with type :math:`[t_{3i}^\ast] \to [t_2^\ast]`. +.. _valid-catch: -* If :math:`(\CATCHALL~\instr_3^\ast)^?` is not empty, then: +:math:`\CATCH~x~l` +.................. - * Under context :math:`C''`, - the instruction sequence :math:`\instr_3^\ast` must be :ref:`valid ` with type :math:`[] \to [t_2^\ast]`. +* The tag :math:`C.\CTAGS[x]` must be defined in the context. -* Then the compound instruction is valid with type :math:`[t_1^\ast] \to [t_2^\ast]`. +* Let :math:`[t^\ast] \to [{t'}^\ast]` be the :ref:`tag type ` :math:`C.\CTAGS[x]`. + +* The :ref:`result type ` :math:`[{t'}^\ast]` must be empty. + +* The label :math:`C.\CLABELS[l]` must be defined in the context. + +* The :ref:`result type ` :math:`[t^\ast]` must be the same as :math:`C.\CLABELS[l]`. + +* Then the catch clause is valid. .. math:: \frac{ - \begin{array}{c} - C \vdashblocktype \blocktype : [t_1^\ast] \to [t_2^\ast] + C.\CTAGS[x] = [t^\ast] \toF [] \qquad - C,\CLABELS\,[t_2^\ast] \vdashinstrseq \instr_1^\ast : [t_1^\ast] \to [t_2^\ast] \\ - (C.\CTAGS[x] = [t^\ast] \to [] \\ - C,\CLABELS\,(\LCATCH~[t_2^\ast]) \vdashinstrseq \instr_2^\ast : [t^\ast] \to [t_2^\ast])^\ast \\ - (C,\CLABELS\,(\LCATCH~[t_2^\ast]) \vdashinstrseq \instr_3^\ast : [] \to [t_2^\ast])^? - \end{array} + C.\CLABELS[l] = [t^\ast] }{ - C \vdashinstr \TRY~\blocktype~\instr_1^\ast~(\CATCH~x~\instr_2^\ast)^\ast~(\CATCHALL~\instr_3^\ast)^?~\END : [t_1^\ast] \to [t_2^\ast] + C \vdashcatch \CATCH~x~l \ok } +:math:`\CATCHREF~x~l` +..................... -.. note:: - The :ref:`notation ` :math:`C,\CLABELS\,(\LCATCH^?~[t^\ast])` inserts the new label type at index :math:`0`, shifting all others. - +* The tag :math:`C.\CTAGS[x]` must be defined in the context. -.. _valid-try-delegate: +* Let :math:`[t^\ast] \to [{t'}^\ast]` be the :ref:`tag type ` :math:`C.\CTAGS[x]`. -:math:`\TRY~\blocktype~\instr^\ast~\DELEGATE~l` -............................................... +* The :ref:`result type ` :math:`[{t'}^\ast]` must be empty. * The label :math:`C.\CLABELS[l]` must be defined in the context. -* The :ref:`block type ` must be :ref:`valid ` as some :ref:`function type ` :math:`[t_1^\ast] \to [t_2^\ast]`. +* The :ref:`result type ` :math:`[t^\ast]` must be the same as :math:`C.\CLABELS[l]` with |EXNREF| appended. -* Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with the :ref:`result type ` :math:`[t_2^\ast]` prepended to the |CLABELS| vector. +* Then the catch clause is valid. -* Under context :math:`C'`, - the instruction sequence :math:`\instr^\ast` must be :ref:`valid ` with type :math:`[t_1^\ast] \to [t_2^\ast]`. +.. math:: + \frac{ + C.\CTAGS[x] = [t^\ast] \toF [] + \qquad + C.\CLABELS[l] = [t^\ast~\EXNREF] + }{ + C \vdashcatch \CATCHREF~x~l \ok + } -* Then the compound instruction is valid with type :math:`[t_1^\ast] \to [t_2^\ast]`. +:math:`\CATCHALL~l` +................... + +* The label :math:`C.\CLABELS[l]` must be defined in the context. + +* The :ref:`result type ` :math:`C.\CLABELS[l]` must be empty. + +* Then the catch clause is valid. .. math:: \frac{ - C \vdashblocktype \blocktype : [t_1^\ast] \to [t_2^\ast] - \qquad - C,\CLABELS\,[t_2^\ast] \vdashinstrseq \instr^\ast : [t_1^\ast]\to[t_2^\ast] - \qquad - C.\CLABELS[l] = [t_0^\ast] + C.\CLABELS[l] = [] }{ - C \vdashinstrseq \TRY~\blocktype~\instr^\ast~\DELEGATE~l : [t_1^\ast]\to[t_2^\ast] + C \vdashcatch \CATCHALL~l \ok } -.. note:: - The :ref:`label index ` space in the :ref:`context ` :math:`C` contains the most recent label first, so that :math:`C.\CLABELS[l]` performs a relative lookup as expected. +:math:`\CATCHALLREF~l` +...................... + +* The label :math:`C.\CLABELS[l]` must be defined in the context. + +* The :ref:`result type ` :math:`C.\CLABELS[l] must be :math:`[\EXNREF]`. + +* Then the catch clause is valid. + +.. math:: + \frac{ + C.\CLABELS[l] = [\EXNREF] + }{ + C \vdashcatch \CATCHALLREF~l \ok + } .. _valid-throw: @@ -1450,7 +1485,9 @@ Control Instructions * The tag :math:`C.\CTAGS[x]` must be defined in the context. -* Let :math:`[t^\ast] \to []` be its :ref:`tag type `. +* Let :math:`[t^\ast] \to [{t'}^\ast]` be the :ref:`tag type ` :math:`C.\CTAGS[x]`. + +* The :ref:`result type ` :math:`[{t'}^\ast]` must be empty. * Then the instruction is valid with type :math:`[t_1^\ast t^\ast] \to [t_2^\ast]`, for any sequences of :ref:`value types ` :math:`t_1^\ast` and :math:`t_2^\ast`. @@ -1458,7 +1495,7 @@ Control Instructions \frac{ C.\CTAGS[x] = [t^\ast] \to [] }{ - C \vdashinstr \THROW~x : [t_1^\ast t^\ast] \to [t_2^\ast] + C \vdashinstr \THROW~x : [t_1^\ast~t^\ast] \to [t_2^\ast] } @@ -1466,30 +1503,23 @@ Control Instructions The |THROW| instruction is :ref:`stack-polymorphic `. -.. _valid-rethrow: - -:math:`\RETHROW~l` -.................. - -* The label :math:`C.\CLABELS[l]` must be defined in the context. - -* Let :math:`(\LCATCH^?~[t^\ast])` be the :ref:`label type ` :math:`C.\CLABELS[l]`. +.. _valid-throw_ref: -* The |LCATCH| must be present in the :ref:`label type ` :math:`C.\CLABELS[l]`. +:math:`\THROWREF` +................. -* Then the instruction is valid with type :math:`[t_1^\ast] \to [t_2^\ast]`, for any sequences of :ref:`value types ` :math:`t_1^\ast` and :math:`t_2^\ast`. +* The instruction is valid with type :math:`[t_1^\ast~\EXNREF] \to [t_2^\ast]`, for any sequences of :ref:`value types ` :math:`t_1^\ast` and :math:`t_2^\ast`. .. math:: \frac{ - C.\CLABELS[l] = \LCATCH~[t^\ast] }{ - C \vdashinstr \RETHROW~l : [t_1^\ast] \to [t_2^\ast] + C \vdashinstr \THROWREF : [t_1^\ast~\EXNREF] \to [t_2^\ast] } .. note:: - The |RETHROW| instruction is :ref:`stack-polymorphic `. + The |THROWREF| instruction is :ref:`stack-polymorphic `. @@ -1500,13 +1530,13 @@ Control Instructions * The label :math:`C.\CLABELS[l]` must be defined in the context. -* Let :math:`\LCATCH^?~[t^\ast]` be the :ref:`label type ` :math:`C.\CLABELS[l]`. +* Let :math:`[t^\ast]` be the :ref:`result type ` :math:`C.\CLABELS[l]`. * Then the instruction is valid with type :math:`[t_1^\ast~t^\ast] \to [t_2^\ast]`, for any sequences of :ref:`operand types ` :math:`t_1^\ast` and :math:`t_2^\ast`. .. math:: \frac{ - C.\CLABELS[l] = \LCATCH^?~[t^\ast] + C.\CLABELS[l] = [t^\ast] }{ C \vdashinstr \BR~l : [t_1^\ast~t^\ast] \to [t_2^\ast] } @@ -1524,13 +1554,13 @@ Control Instructions * The label :math:`C.\CLABELS[l]` must be defined in the context. -* Let :math:`\LCATCH^?~[t^\ast]` be the :ref:`label type ` :math:`C.\CLABELS[l]`. +* Let :math:`[t^\ast]` be the :ref:`result type ` :math:`C.\CLABELS[l]`. * Then the instruction is valid with type :math:`[t^\ast~\I32] \to [t^\ast]`. .. math:: \frac{ - C.\CLABELS[l] = \LCATCH^?~[t^\ast] + C.\CLABELS[l] = [t^\ast] }{ C \vdashinstr \BRIF~l : [t^\ast~\I32] \to [t^\ast] } diff --git a/document/core/valid/modules.rst b/document/core/valid/modules.rst index 16f7871a..8404d2fd 100644 --- a/document/core/valid/modules.rst +++ b/document/core/valid/modules.rst @@ -29,7 +29,7 @@ Functions :math:`\func` are classified by :ref:`function types * |CLOCALS| set to the sequence of :ref:`value types ` :math:`t_1^\ast~t^\ast`, concatenating parameters and locals, - * |CLABELS| set to the singular sequence containing only :ref:`label type ` :math:`[t_2^\ast]`. + * |CLABELS| set to the singular sequence containing only :ref:`result type ` :math:`[t_2^\ast]`. * |CRETURN| set to the :ref:`result type ` :math:`[t_2^\ast]`. diff --git a/document/index.html b/document/index.html index 37eed976..79a2a0cf 100644 --- a/document/index.html +++ b/document/index.html @@ -49,19 +49,32 @@

Embedder specifications

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

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

+

Legacy Extensions

+ +

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

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

    + +
  • +
+ +

Source for these documents is available here. diff --git a/document/js-api/index.bs b/document/js-api/index.bs index e7db1407..1519c049 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -111,6 +111,7 @@ urlPrefix: https://webassembly.github.io/exception-handling/core/; spec: WebAsse url: syntax/types.html#syntax-reftype text: reftype text: funcref + text: exnref text: externref url: syntax/values.html#syntax-float text: +โˆž @@ -804,6 +805,9 @@ Each {{Table}} object has a \[[Table]] internal slot, which is a [=table address The get(|index|) method, when invoked, performs the following steps: 1. Let |tableaddr| be **this**.\[[Table]]. 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. + 1. Let (limits, |elementType|) be [=table_type=](|store|, |tableaddr|). + 1. If |elementType| is [=exnref=], + 1. [=Throw=] a {{TypeError}} exception. 1. Let |result| be [=table_read=](|store|, |tableaddr|, |index|). 1. If |result| is [=error=], throw a {{RangeError}} exception. 1. Return [=ToJSValue=](|result|). @@ -812,12 +816,14 @@ Each {{Table}} object has a \[[Table]] internal slot, which is a [=table address

The set(|index|, |value|) method, when invoked, performs the following steps: 1. Let |tableaddr| be **this**.\[[Table]]. - 1. Let (limits, |elementType|) be [=table_type=](|tableaddr|). + 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. + 1. Let (limits, |elementType|) be [=table_type=](|store|, |tableaddr|). + 1. If |elementType| is [=exnref=], + 1. [=Throw=] a {{TypeError}} exception. 1. If |value| is missing, 1. Let |ref| be [=DefaultValue=](|elementType|). 1. Otherwise, 1. Let |ref| be [=?=] [=ToWebAssemblyValue=](|value|, |elementType|). - 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. 1. Let |store| be [=table_write=](|store|, |tableaddr|, |index|, |ref|). 1. If |store| is [=error=], throw a {{RangeError}} exception. 1. Set the [=surrounding agent=]'s [=associated store=] to |store|. @@ -904,7 +910,7 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each The Global(|descriptor|, |v|) constructor, when invoked, performs the following steps: 1. Let |mutable| be |descriptor|["mutable"]. 1. Let |valuetype| be [=ToValueType=](|descriptor|["value"]). - 1. If |valuetype| is [=v128=], + 1. If |valuetype| is [=v128=] or [=exnref=], 1. Throw a {{TypeError}} exception. 1. If |v| is missing, 1. Let |value| be [=DefaultValue=](|valuetype|). @@ -922,7 +928,7 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each 1. Let |store| be the current agent's [=associated store=]. 1. Let |globaladdr| be |global|.\[[Global]]. 1. Let |globaltype| be [=global_type=](|store|, |globaladdr|). - 1. If |globaltype| is of the form mut [=v128=], throw a {{TypeError}}. + 1. If |globaltype| is of the form mut |valuetype| where |valuetype| is [=v128=] or [=exnref=], throw a {{TypeError}}. 1. Let |value| be [=global_read=](|store|, |globaladdr|). 1. Return [=ToJSValue=](|value|).
@@ -935,7 +941,7 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each 1. Let |store| be the current agent's [=associated store=]. 1. Let |globaladdr| be **this**.\[[Global]]. 1. Let |mut| |valuetype| be [=global_type=](|store|, |globaladdr|). - 1. If |valuetype| is [=v128=], throw a {{TypeError}}. + 1. If |valuetype| is [=v128=] or [=exnref=], throw a {{TypeError}}. 1. If |mut| is [=const=], throw a {{TypeError}}. 1. Let |value| be [=ToWebAssemblyValue=](**the given value**, |valuetype|). 1. Let |store| be [=global_write=](|store|, |globaladdr|, |value|). @@ -994,7 +1000,7 @@ This slot holds a [=function address=] relative to the [=surrounding agent=]'s [ 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. 1. Let |functype| be [=func_type=](|store|, |funcaddr|). 1. Let [|parameters|] โ†’ [|results|] be |functype|. - 1. If |parameters| or |results| contain [=v128=], throw a {{TypeError}}. + 1. If |parameters| or |results| contain [=v128=] or [=exnref=], throw a {{TypeError}}. Note: the above error is thrown each time the \[[Call]] method is invoked. 1. Let |args| be ยซ ยป. @@ -1032,7 +1038,7 @@ Note: Exported Functions do not have a \[[Construct]] method and thus it is not To run a host function from the JavaScript object |func|, type |functype|, and [=list=] of [=WebAssembly values=] |arguments|, perform the following steps: 1. Let [|parameters|] โ†’ [|results|] be |functype|. - 1. If |parameters| or |results| contain [=v128=], throw a {{TypeError}}. + 1. If |parameters| or |results| contain [=v128=] or [=exnref=], throw a {{TypeError}}. 1. Let |jsArguments| be ยซ ยป. 1. [=list/iterate|For each=] |arg| of |arguments|, 1. [=list/Append=] [=!=] [=ToJSValue=](|arg|) to |jsArguments|. @@ -1086,6 +1092,7 @@ Note: Exported Functions do not have a \[[Construct]] method and thus it is not The algorithm ToJSValue(|w|) coerces a [=WebAssembly value=] to a JavaScript value by performing the following steps: 1. Assert: |w| is not of the form [=v128.const=] v128. +1. Assert: |w| is not of the form [=ref.exn=] exnaddr. 1. If |w| is of the form [=i64.const=] |i64|, 1. Let |v| be [=signed_64=](|i64|). 1. Return [=โ„ค=](|v| interpreted as a mathematical value). @@ -1119,6 +1126,7 @@ For retrieving an extern value from an [=extern address=] |externaddr The algorithm ToWebAssemblyValue(|v|, |type|) coerces a JavaScript value to a [=WebAssembly value=] by performing the following steps: 1. Assert: |type| is not [=v128=]. +1. Assert: |type| is not [=exnref=]. 1. If |type| is [=i64=], 1. Let |i64| be [=?=] [$ToBigInt64$](|v|). 1. Return [=i64.const=] |i64|. diff --git a/document/legacy/exceptions/.gitignore b/document/legacy/exceptions/.gitignore new file mode 100644 index 00000000..b932ec28 --- /dev/null +++ b/document/legacy/exceptions/.gitignore @@ -0,0 +1,3 @@ +_build +_static +document/*.pyc diff --git a/document/legacy/exceptions/LICENSE b/document/legacy/exceptions/LICENSE new file mode 100644 index 00000000..795b406e --- /dev/null +++ b/document/legacy/exceptions/LICENSE @@ -0,0 +1,50 @@ +W3C SOFTWARE AND DOCUMENT NOTICE AND LICENSE + +This work is being provided by the copyright holders under the following +license. + + +LICENSE + +By obtaining and/or copying this work, you (the licensee) agree that you have +read, understood, and will comply with the following terms and conditions. + +Permission to copy, modify, and distribute this work, with or without +modification, for any purpose and without fee or royalty is hereby granted, +provided that you include the following on ALL copies of the work or portions +thereof, including modifications: + +* The full text of this NOTICE in a location viewable to users of the + redistributed or derivative work. + +* Any pre-existing intellectual property disclaimers, notices, or terms and + conditions. If none exist, the W3C Software and Document Short Notice + (https://www.w3.org/Consortium/Legal/copyright-software-short-notice) should + be included. + +* Notice of any changes or modifications, through a copyright statement on the + new code or document such as "This software or document includes material + copied from or derived from [title and URI of the W3C document]. Copyright ยฉ [YEAR] W3Cยฎ (MIT, ERCIM, Keio, Beihang)." + + +DISCLAIMERS + +THIS WORK IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS +OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, WARRANTIES OF +MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE +SOFTWARE OR DOCUMENT WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, +TRADEMARKS OR OTHER RIGHTS. + +COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENT. + +The name and trademarks of copyright holders may NOT be used in advertising or +publicity pertaining to the work without specific, written prior permission. +Title to copyright in this work will at all times remain with copyright +holders. + + +NOTES + +This version: +http://www.w3.org/Consortium/Legal/2015/copyright-software-and-document diff --git a/document/legacy/exceptions/Makefile b/document/legacy/exceptions/Makefile new file mode 100644 index 00000000..56b9560a --- /dev/null +++ b/document/legacy/exceptions/Makefile @@ -0,0 +1,358 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = a4 +BUILDDIR = _build +STATICDIR = _static +DOWNLOADDIR = _download +NAME = WebAssembly + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: usage +usage: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " pdf to make standalone PDF file" + @echo " bikeshed to make a bikeshed wrapped single large HTML file" + @echo " diff to make a diff of the bikeshed HTML file with the latest TR" + @echo " WD-tar generate tar file for updating the Working Draft" + @echo " WD-echidna publish the Working Draft tar file via Echidna" + @echo " all to make all 3" + @echo " publish to make all and push to gh-pages" + @echo " help to see more options" + +.PHONY: help +help: + @echo "Usage: \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " pdf to make standalone PDF file" + @echo " bikeshed to make a bikeshed wrapped single large HTML file" + @echo " all to make all 3" + @echo " publish to make all and push to gh-pages" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " applehelp to make an Apple Help Book" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " epub3 to make an epub3" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + @echo " coverage to run coverage check of the documentation (if enabled)" + @echo " dummy to check syntax errors of document sources" + +.PHONY: deploy +deploy: + (cd ../..; make dir-core deploy-core) + +.PHONY: publish +publish: clean all deploy + +.PHONY: publish-main +publish-main: clean main bikeshed-keep deploy + +.PHONY: all +all: pdf html bikeshed + +.PHONY: main +main: pdf html + +# Dirty hack to avoid rebuilding the Bikeshed version for every push. +.PHONY: bikeshed-keep +bikeshed-keep: + test -e $(BUILDDIR)/html/bikeshed || \ + wget -r -nH --cut-dirs=2 -P $(BUILDDIR)/html --no-check-certificate \ + https://webassembly.github.io/spec/core/bikeshed || \ + echo Downloaded Bikeshed. + + +GENERATED = appendix/index-instructions.rst +.INTERMEDIATE: $(GENERATED) + +%.rst: %.py + (cd `dirname $@`; ./`basename $^`) + +.PHONY: pdf +pdf: $(GENERATED) latexpdf + mkdir -p $(BUILDDIR)/html/$(DOWNLOADDIR) + ln -f $(BUILDDIR)/latex/$(NAME).pdf $(BUILDDIR)/html/$(DOWNLOADDIR)/$(NAME).pdf + + +.PHONY: clean +clean: + rm -rf $(BUILDDIR) + rm -rf $(STATICDIR) + rm -f $(GENERATED) + +.PHONY: html +html: $(GENERATED) + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + for file in `ls $(BUILDDIR)/html/*.html`; \ + do \ + sed s:BASEDIR:.:g <$$file >$$file.out; \ + mv -f $$file.out $$file; \ + done + for file in `ls $(BUILDDIR)/html/*/*.html`; \ + do \ + sed s:BASEDIR:..:g <$$file >$$file.out; \ + mv -f $$file.out $$file; \ + done + @echo + @echo "Build finished. The HTML pages are in `pwd`/$(BUILDDIR)/html/." + +.PHONY: dirhtml +dirhtml: $(GENERATED) + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +.PHONY: singlehtml +singlehtml: $(GENERATED) + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +.PHONY: bikeshed +bikeshed: $(GENERATED) + $(SPHINXBUILD) -b singlehtml -c util/bikeshed \ + $(ALLSPHINXOPTS) $(BUILDDIR)/bikeshed_singlehtml + python3 util/bikeshed_fixup.py $(BUILDDIR)/bikeshed_singlehtml/index.html \ + >$(BUILDDIR)/bikeshed_singlehtml/index_fixed.html + @echo ==== Showing contents of _build/bikeshed_singlehtml/index_fixed.html ==== + @head -n10 _build/bikeshed_singlehtml/index_fixed.html + @echo ... skipping $$(expr `cat _build/bikeshed_singlehtml/index_fixed.html | wc -l` - 20) lines ... + @tail -n10 _build/bikeshed_singlehtml/index_fixed.html + @echo + @echo ========================================================================= + mkdir -p $(BUILDDIR)/bikeshed_mathjax/ + bikeshed spec index.bs $(BUILDDIR)/bikeshed_mathjax/index.html + mkdir -p $(BUILDDIR)/html/bikeshed/ + (cd util/katex/ && yarn && yarn build && npm install --only=prod) + python3 util/mathjax2katex.py $(BUILDDIR)/bikeshed_mathjax/index.html \ + >$(BUILDDIR)/html/bikeshed/index.html + mkdir -p $(BUILDDIR)/html/bikeshed/katex/dist/ + cp -r util/katex/dist/* $(BUILDDIR)/html/bikeshed/katex/dist/ + patch -p0 $(BUILDDIR)/html/bikeshed/katex/dist/katex.css \ + < util/katex_fix.patch + cp $(BUILDDIR)/bikeshed_singlehtml/_static/pygments.css \ + $(BUILDDIR)/html/bikeshed/ + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/html/bikeshed/." + +.PHONY: WD-tar +WD-tar: bikeshed + @echo "Building tar file..." + tar cvf \ + $(BUILDDIR)/WD.tar \ + --transform='s|$(BUILDDIR)/html/bikeshed/||' \ + --transform='s|index.html|Overview.html|' \ + $(BUILDDIR)/html/bikeshed/index.html \ + $(BUILDDIR)/html/bikeshed/pygments.css \ + $(BUILDDIR)/html/bikeshed/katex/dist/katex.css \ + $(BUILDDIR)/html/bikeshed/katex/dist/fonts + @echo "Built $(BUILDDIR)/WD.tar." + +.PHONY: WD-echidna +WD-echidna: WD-tar + @if [ -z $(W3C_USERNAME) ] || \ + [ -z $(W3C_PASSWORD) ] || \ + [ -z $(DECISION_URL) ] ; then \ + echo "Must provide W3C_USERNAME, W3C_PASSWORD, and DECISION_URL environment variables"; \ + exit 1; \ + fi + curl 'https://labs.w3.org/echidna/api/request' \ + --user '$(W3C_USERNAME):$(W3C_PASSWORD)' \ + -F "tar=@$(BUILDDIR)/WD.tar" \ + -F "decision=$(DECISION_URL)" | tee $(BUILDDIR)/WD-echidna-id.txt + @echo + @echo "Published working draft. Check its status at https://labs.w3.org/echidna/api/status?id=`cat $(BUILDDIR)/WD-echidna-id.txt`" + +.PHONY: diff +diff: bikeshed + @echo "Downloading the old single-file html spec..." + curl `grep "^TR" index.bs | cut -d' ' -f2` -o $(BUILDDIR)/html/bikeshed/old.html + @echo "Done." + @echo "Diffing new against old (go get a coffee)..." + perl ../util/htmldiff.pl $(BUILDDIR)/html/bikeshed/old.html $(BUILDDIR)/html/bikeshed/index.html $(BUILDDIR)/html/bikeshed/diff.html + @echo "Done. The diff is at $(BUILDDIR)/html/bikeshed/diff.html" + +.PHONY: pickle +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +.PHONY: json +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +.PHONY: htmlhelp +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +.PHONY: qthelp +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/WebAssembly.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/WebAssembly.qhc" + +.PHONY: applehelp +applehelp: + $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp + @echo + @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." + @echo "N.B. You won't be able to view it unless you put it in" \ + "~/Library/Documentation/Help or install it in your application" \ + "bundle." + +.PHONY: devhelp +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/WebAssembly" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/WebAssembly" + @echo "# devhelp" + +.PHONY: epub +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +.PHONY: epub3 +epub3: + $(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3 + @echo + @echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3." + +.PHONY: latex +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +.PHONY: latexpdf +latexpdf: $(GENERATED) + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex LATEXMKOPTS=" $(BUILDDIR)/latex/LOG 2>&1 || cat $(BUILDDIR)/latex/LOG + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +.PHONY: latexpdfja +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +.PHONY: text +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +.PHONY: man +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +.PHONY: texinfo +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +.PHONY: info +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +.PHONY: gettext +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +.PHONY: changes +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +.PHONY: linkcheck +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +.PHONY: doctest +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +.PHONY: coverage +coverage: + $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage + @echo "Testing of coverage in the sources finished, look at the " \ + "results in $(BUILDDIR)/coverage/python.txt." + +.PHONY: xml +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +.PHONY: pseudoxml +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." + +.PHONY: dummy +dummy: + $(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy + @echo + @echo "Build finished. Dummy builder generates no files." diff --git a/document/legacy/exceptions/README.md b/document/legacy/exceptions/README.md new file mode 100644 index 00000000..06d07523 --- /dev/null +++ b/document/legacy/exceptions/README.md @@ -0,0 +1,25 @@ +# WebAssembly Core Specification Addendum: Legacy Exception Handling + +This is the official WebAssembly "language" specification. + +It uses [Sphinx](http://www.sphinx-doc.org/). To install that: +``` +pip install sphinx +``` +To make HTML (result in `_build/html`): +``` +make html +``` +To make PDF (result in `_build/latex`, requires LaTeX): +``` +make pdf +``` +To make all: +``` +make all +``` +Finally, to make all and update webassembly.github.io/spec with it: +``` +make publish +``` +Please make sure to only use that once a change has approval. diff --git a/document/legacy/exceptions/appendix/index-instructions.py b/document/legacy/exceptions/appendix/index-instructions.py new file mode 100755 index 00000000..ea315469 --- /dev/null +++ b/document/legacy/exceptions/appendix/index-instructions.py @@ -0,0 +1,116 @@ +#!/usr/bin/env python3 + +# This script generates the `index-instructions.rst` file. The table in that +# file is particularly annoying to update by hand, since the Restructured Text +# format requires the header and columns to line up properly. This is +# especially tedious when merging changes from the upstream spec, or merging a +# proposal back to the spec when it is standardized. + +import os + +SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) +INDEX_INSTRUCTIONS_RST = os.path.join(SCRIPT_DIR, 'index-instructions.rst') + +HEADER = """\ +.. DO NOT EDIT: This file is auto-generated by the index-instructions.py script. + +.. _appendix: + +Appendix +======== + +.. index:: instruction +.. _index-instr: + +Index of Instructions +--------------------- +""" + +FOOTER = """\ + +.. note:: + Multi-byte opcodes are given with the shortest possible encoding in the table. + However, what is following the first byte is actually a :ref:`u32 ` with variable-length encoding + and consequently has multiple possible representations.\ +""" + +COLUMNS = [ + 'Instruction', + 'Binary Opcode', + 'Type', + 'Validation', + 'Execution', +] + + +def MathWrap(s, default=''): + if s is None: + return default + else: + return f':math:`{s}`' + + +def RefWrap(s, kind): + if s is None: + return '' + else: + return f':ref:`{kind} <{s}>`' + + +def Instruction(name, opcode, type=None, validation=None, execution=None, operator=None, validation2=None, execution2=None): + if operator: + execution_str = ', '.join([RefWrap(execution, 'execution'), + RefWrap(operator, 'operator')]) + elif execution2: + execution_str = ', '.join([RefWrap(execution, 'execution'), + RefWrap(execution, 'execution')]) + + else: + execution_str = RefWrap(execution, 'execution') + + if validation2: + validation_str = ', '.join([RefWrap(validation, 'validation'), + RefWrap(validation2, 'validation')]) + else: + validation_str = RefWrap(validation, 'validation') + + return ( + MathWrap(name, '(reserved)'), + MathWrap(opcode), + MathWrap(type), + validation_str, + execution_str + ) + + +INSTRUCTIONS = [ + Instruction(r'\TRY~\X{bt}', r'\hex{06}', r'[t_1^\ast] \to [t_2^\ast]', r'valid-try-catch', r'exec-try-catch', None, r'valid-try-delegate', r'exec-try-delegate'), + Instruction(r'\CATCH~x', r'\hex{07}', None, r'valid-try-catch', r'exec-try-catch'), + Instruction(r'\RETHROW~n', r'\hex{09}', r'[t_1^\ast] \to [t_2^\ast]', r'valid-rethrow', r'exec-rethrow'), + Instruction(r'\DELEGATE~l', r'\hex{18}', None, r'valid-try-delegate', r'exec-try-delegate'), + Instruction(r'\CATCHALL', r'\hex{19}', None, r'valid-try-catch', r'exec-try-catch'), +] + + +def ColumnWidth(n): + return max([len(instr[n]) for instr in INSTRUCTIONS]) + +COLUMN_WIDTHS = [ColumnWidth(i) for i in range(len(COLUMNS))] +DIVIDER = ' '.join('=' * width for width in COLUMN_WIDTHS) + +def Row(columns): + return ' '.join(('{:%d}' % COLUMN_WIDTHS[i]).format(column) + for i, column in enumerate(columns)) + +if __name__ == '__main__': + with open(INDEX_INSTRUCTIONS_RST, 'w') as f: + print(HEADER, file=f) + print(DIVIDER, file=f) + print(Row(COLUMNS), file=f) + print(DIVIDER, file=f) + + for instr in INSTRUCTIONS: + print(Row(instr), file=f) + + print(DIVIDER, file=f) + print(FOOTER, file=f) diff --git a/document/legacy/exceptions/binary.rst b/document/legacy/exceptions/binary.rst new file mode 100644 index 00000000..68ea09df --- /dev/null +++ b/document/legacy/exceptions/binary.rst @@ -0,0 +1,31 @@ +.. _binary: + +Binary Format +============= + +.. index:: instruction +.. _binary-instr: + +Instructions +------------ + +.. _binary-instr-control: + +Control Instructions +~~~~~~~~~~~~~~~~~~~~ + +.. _binary-try: +.. _binary-rethrow: + +.. math:: + \begin{array}{llcllll} + \production{instruction} & \Binstr &::=& \dots \\ &&|& + \hex{06}~~\X{bt}{:}\Bblocktype~~(\X{in}_1{:}\Binstr)^\ast~~ + (\hex{07}~~x{:}\Btagidx~~(\X{in}_2{:}\Binstr)^\ast)^\ast~~ + (\hex{19}~~(\X{in}_3{:}\Binstr)^\ast)^?~~\hex{0B} + &\Rightarrow& \TRY~\X{bt}~\X{in}_1^\ast~(\CATCH~x~\X{in}_2^\ast)^\ast~ + (\CATCHALL~\X{in}_3^\ast)^?\END \\ &&|& + \hex{06}~~\X{bt}{:}\Bblocktype~~(\X{in}{:}\Binstr)^\ast~~\hex{18}~~l{:}\Blabelidx + &\Rightarrow& \TRY~\X{bt}~\X{in}^\ast~\DELEGATE~l \\ &&|& + \hex{09}~~l{:}\Blabelidx &\Rightarrow& \RETHROW~l \\ + \end{array} diff --git a/document/legacy/exceptions/conf.py b/document/legacy/exceptions/conf.py new file mode 100644 index 00000000..ebd159bd --- /dev/null +++ b/document/legacy/exceptions/conf.py @@ -0,0 +1,498 @@ +# -*- coding: utf-8 -*- +# +# WebAssembly documentation build configuration file, created by +# sphinx-quickstart on Mon Nov 21 11:32:49 2016. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +import os +import sys +from datetime import date + +pwd = os.path.abspath('.') +sys.path.insert(0, pwd) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +# +needs_sphinx = '2.3' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.todo', + 'sphinx.ext.coverage', + 'sphinx.ext.mathjax', + 'sphinx.ext.ifconfig', + 'sphinx.ext.githubpages', + 'util.mathdef', + 'util.pseudo-lexer' +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +source_suffix = ['.rst'] + +# The encoding of source files. +# +# source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +name = 'WebAssembly' +project = u'WebAssembly' +title = u'WebAssembly Specification Addendum: Legacy Exception Handling' +copyright = u'2023, WebAssembly Community Group' +author = u'WebAssembly Community Group' +editor = u'Andreas Rossberg (editor)' +logo = 'static/webassembly.png' + +# The name of the GitHub repository this resides in +repo = 'spec' + +# The draft version string (clear out for release cuts) +draft = ' (Draft ' + date.today().strftime("%Y-%m-%d") + ')' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = u'0.1' +# The full version, including alpha/beta/rc tags. +release = version + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = 'en' + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +# +# today = '' +# +# Else, today_fmt is used as the format for a strftime call. +# +# today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This patterns also effect to html_static_path and html_extra_path +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +# +# default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +# +# add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +# +# add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +# +# show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +# modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +# keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = True + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'alabaster' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +html_theme_options = { + 'logo': logo, + 'logo_name': 'WebAssembly', + 'description': 'WebAssembly Specification', + 'fixed_sidebar': True, + 'sidebar_width': '260px', + 'sidebar_collapse': True, + 'show_powered_by': False, + 'extra_nav_links': { + 'Index': 'BASEDIR/genindex.html', + 'Download as PDF': 'BASEDIR/_download/' + name + '.pdf' + }, +} + +html_sidebars = { + '**': [ + # 'about.html', + 'navigation.html', + # 'relations.html', + 'searchbox.html', + ] +} + + +# Add any paths that contain custom themes here, relative to this directory. +# html_theme_path = [] + +# The name for this set of Sphinx documents. +# " v documentation" by default. +# +html_title = project + u' ' + release + +# A shorter title for the navigation bar. Default is the same as html_title. +# +# html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +# +html_logo = logo + +# The name of an image file (relative to this directory) to use as a favicon of +# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +# +# html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['static/custom.css'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +# +# html_extra_path = [] + +# If not None, a 'Last updated on:' timestamp is inserted at every page +# bottom, using the given strftime format. +# The empty string is equivalent to '%b %d, %Y'. +# +# html_last_updated_fmt = None + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +# +# html_use_smartypants = True + +# Additional templates that should be rendered to pages, maps page names to +# template names. +# +# html_additional_pages = {} + +# If false, no module index is generated. +# +html_domain_indices = False + +# If false, no index is generated. +# +html_use_index = True + +# If true, the index is split into individual pages for each letter. +# +html_split_index = False + +# If true, the reST sources are included in the HTML build as _sources/name. The default is True. +# +html_copy_source = False + +# If true, links to the reST sources are added to the pages. +# +html_show_sourcelink = False + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +# +html_show_sphinx = False + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +# +html_show_copyright = True + +# If this is not None, a โ€˜Last updated on:โ€™ timestamp is inserted at every +# page bottom, using the given strftime() format. +# +html_last_updated_fmt = '%Y-%m-%d' + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +# +# html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +# +# html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr', 'zh' +# +# html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# 'ja' uses this config value. +# 'zh' user can custom change `jieba` dictionary path. +# +# html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +# +# html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +# +htmlhelp_basename = 'WebAssemblydoc' + + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { + # The paper size ('a4paper' or 'letterpaper'). + 'papersize': 'a4paper', + + # The font size ('10pt', '11pt' or '12pt'). + 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # Don't type-set cross references with emphasis. + 'preamble': '\\renewcommand\\sphinxcrossref[1]{#1}\n', + + # Latex figure (float) alignment + 'figure_align': 'htbp', + + # Fancy chapters [Bjarne, Sonny, Lenny, Glenn, Conny, Rejne] + 'fncychap': '\\usepackage[Sonny]{fncychap}', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + ( master_doc, + name + '.tex', + title, + author + '\\\\ \\hfill\\large ' + editor, + 'manual' + ), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +# +latex_logo = logo + +# For "manual" documents [part, chapter, or section]. +# +latex_toplevel_sectioning = 'section' + +# If true, show page references after internal links. +# +latex_show_pagerefs = False + +# How to show URL addresses after external links [no, footnote, inline]. +# +latex_show_urls = 'footnote' + +# Documents to append as an appendix to all manuals. +# +# latex_appendices = [] + +# It false, will not define \strong, \code, \titleref, \crossref ... but only +# \sphinxstrong, ..., \sphinxtitleref, ... To help avoid clash with user added +# packages. +# +# latex_keep_old_macro_names = True + +# If false, no module index is generated. +# +latex_domain_indices = False + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ( master_doc, + name, + title, + [author], + 1 + ) +] + +# If true, show URL addresses after external links. +# +# man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ( master_doc, + name, + title, + author, + name, + 'A portable low-level execution format.', + 'Virtual Machine' + ), +] + +# Documents to append as an appendix to all manuals. +# +# texinfo_appendices = [] + +# If false, no module index is generated. +# +texinfo_domain_indices = False + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +# +# texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +# +# texinfo_no_detailmenu = False + + +# -- Options for Epub output ---------------------------------------------- + +# Bibliographic Dublin Core info. +epub_title = project +epub_author = author +epub_publisher = author +epub_copyright = copyright + +# The basename for the epub file. It defaults to the project name. +# epub_basename = project + +# The HTML theme for the epub output. Since the default themes are not +# optimized for small screen space, using the same theme for HTML and epub +# output is usually not wise. This defaults to 'epub', a theme designed to save +# visual space. +# +# epub_theme = 'epub' + +# The language of the text. It defaults to the language option +# or 'en' if the language is not set. +# +# epub_language = '' + +# The scheme of the identifier. Typical schemes are ISBN or URL. +# epub_scheme = '' + +# The unique identifier of the text. This can be a ISBN number +# or the project homepage. +# +# epub_identifier = '' + +# A unique identification for the text. +# +# epub_uid = '' + +# A tuple containing the cover image and cover page html template filenames. +# +# epub_cover = () + +# A sequence of (type, uri, title) tuples for the guide element of content.opf. +# +# epub_guide = () + +# HTML files that should be inserted before the pages created by sphinx. +# The format is a list of tuples containing the path and title. +# +# epub_pre_files = [] + +# HTML files that should be inserted after the pages created by sphinx. +# The format is a list of tuples containing the path and title. +# +# epub_post_files = [] + +# A list of files that should not be packed into the epub file. +epub_exclude_files = ['search.html'] + +# The depth of the table of contents in toc.ncx. +# +# epub_tocdepth = 3 + +# Allow duplicate toc entries. +# +# epub_tocdup = True + +# Choose between 'default' and 'includehidden'. +# +# epub_tocscope = 'default' + +# Fix unsupported image types using the Pillow. +# +# epub_fix_images = False + +# Scale large images. +# +# epub_max_image_width = 0 + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +# +# epub_show_urls = 'inline' + +# If false, no index is generated. +# +# epub_use_index = True + +# Macros +rst_prolog = """ +.. |issuelink| replace:: https://github.com/webassembly/""" + repo + """/issues/ +.. |pagelink| replace:: https://webassembly.github.io/""" + repo + """/core/ +.. include:: /""" + pwd + """/util/macros.def +""" + +# https://www.sphinx-doc.org/en/master/usage/extensions/math.html#confval-mathjax3_config +# https://docs.mathjax.org/en/latest/web/configuration.html#configuration +# https://docs.mathjax.org/en/latest/options/input/tex.html#tex-maxbuffer +mathjax3_config = { + 'tex': { 'maxBuffer': 30*1024 }, +} diff --git a/document/legacy/exceptions/exec.rst b/document/legacy/exceptions/exec.rst new file mode 100644 index 00000000..a935eaca --- /dev/null +++ b/document/legacy/exceptions/exec.rst @@ -0,0 +1,351 @@ +.. _exec: + +Execution +========= + +.. _syntax-runtime: + +Runtime Structure +----------------- + +.. _handler: +.. _stack: + +Stack +~~~~~ + +.. _syntax-handler: + +Exception Handlers +.................. + +Legacy exception handlers are installed by |TRY| instructions. +Instead of branch labels, their catch clauses have instruction blocks associated with them. +Furthermore, a |DELEGATE| handler is associated with a label index to implicitly rewthrow to: + +.. math:: + \begin{array}{llllll} + \production{catch} & \catch &::=& \dots \\ &&|& + \CATCH~\tagidx~\instr^\ast \\ &&|& + \CATCHALL~\tagidx~\instr^\ast \\ &&|& + \DELEGATE~\labelidx \\ + \end{array} + + +.. _syntax-caught: +.. _syntax-instr-admin: + +Administrative Instructions +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Administrative instructions are extended with the |CAUGHT| instruction that models exceptions caught by legacy exception handlers. + +.. math:: + \begin{array}{llcl} + \production{administrative instruction} & \instr &::=& \dots \\ &&|& + \CAUGHT_n\{\exnaddr\}~\instr^\ast~\END \\ + \end{array} + + +.. _syntax-ctxt-block: + +Block Contexts +.............. + +Block contexts are extended to include |CAUGHT| instructions: + +.. math:: + \begin{array}{llll} + \production{block contexts} & \XB^k &::=& \dots \\ &&|& + \CAUGHT_n~\{\exnaddr\}~\XB^k~\END \\ + \end{array} + + +.. _syntax-ctxt-throw: + +Throw Contexts +.............. + +Throw contexts are also extended to include |CAUGHT| instructions: + +.. math:: + \begin{array}{llll} + \production{throw contexts} & \XT &::=& \dots \\ &&|& + \CAUGHT_n\{\exnaddr\}~\XT~\END \\ + \end{array} + + +.. _exec-instr: + +Instructions +------------ + +.. _exec-instr-control: + +Control Instructions +~~~~~~~~~~~~~~~~~~~~ + +.. _exec-try-catch: + +:math:`\TRY~\blocktype~\instr_1^\ast~(\CATCH~x~\instr_2^\ast)^\ast~(\CATCHALL~\instr_3^\ast)^?~\END` +.................................................................................................... + +1. Assert: due to :ref:`validation `, :math:`\expand_F(\blocktype)` is defined. + +2. Let :math:`[t_1^m] \to [t_2^n]` be the :ref:`function type ` :math:`\expand_F(\blocktype)`. + +3. Let :math:`L` be the label whose arity is :math:`n` and whose continuation is the end of the |TRY| instruction. + +4. Assert: due to :ref:`validation `, there are at least :math:`m` values on the top of the stack. + +5. Pop the values :math:`\val^m` from the stack. + +6. Let :math:`F` be the :ref:`current ` :ref:`frame `. + +7. For each catch clause :math:`(\CATCH~x_i~\instr_{2i}^\ast)` do: + + a. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MITAGS[x_i]` exists. + + b. Let :math:`a_i` be the tag address :math:`F.\AMODULE.\MITAGS[x_i]`. + + c. Let :math:`\catch_i` be the catch clause :math:`(\CATCH~a_i~\instr_{2i}^\ast)`. + +8. If there is a catch-all clause :math:`(\CATCHALL~\instr_3^\ast)`, then: + + a. Let :math:`\catch'^?` be the handler :math:`(\CATCHALL~\instr_3^\ast)`. + +9. Else: + + a. Let :math:`\catch'^?` be empty. + +10. Let :math:`\catch^\ast` be the concatenation of :math:`\catch_i` and :math:`\catch'^?`. + +11. :ref:`Enter ` the block :math:`\val^m~\instr_1^\ast` with label :math:`L` and exception handler :math:`\HANDLER_n\{\catch^\ast\}^\ast`. + +.. math:: + ~\\[-1ex] + \begin{array}{l} + F; \val^m~(\TRY~\X{bt}~\instr_1^\ast~(\CATCH~x~\instr_2^\ast)^\ast~(\CATCHALL~\instr_3^\ast)^?~\END + \quad \stepto \\ + \qquad F; \LABEL_n\{\epsilon\}~(\HANDLER_n\{(\CATCH~a_x~\instr_2^\ast)^\ast~(\CATCHALL~\instr_3^\ast)^?\}~\val^m~\instr_1^\ast~\END)~\END \\ + (\iff \expand_F(\X{bt}) = [t_1^m] \to [t_2^n] \land (F.\AMODULE.\MITAGS[x]=a_x)^\ast) + \end{array} + + +.. _exec-try-delegate: + +:math:`\TRY~\blocktype~\instr^\ast~\DELEGATE~l` +............................................... + +1. Assert: due to :ref:`validation `, :math:`\expand_F(\blocktype)` is defined. + +2. Let :math:`[t_1^m] \to [t_2^n]` be the :ref:`function type ` :math:`\expand_F(\blocktype)`. + +3. Let :math:`L` be the label whose arity is :math:`n` and whose continuation is the end of the |TRY| instruction. + +4. Let :math:`H` be the :ref:`exception handler ` :math:`l`, targeting the :math:`l`-th surrounding block. + +5. Assert: due to :ref:`validation `, there are at least :math:`m` values on the top of the stack. + +6. Pop the values :math:`\val^m` from the stack. + +7. :ref:`Enter ` the block :math:`\val^m~\instr^\ast` with label :math:`L` and exception handler `\HANDLER_n\{\DELEGATE~l\}`. + +.. math:: + ~\\[-1ex] + \begin{array}{lcl} + F; \val^m~(\TRY~\X{bt}~\instr^\ast~\DELEGATE~l) &\stepto& + F; \LABEL_n\{\epsilon\}~(\HANDLER_n\{\DELEGATE~l\}~\val^m~\instr^\ast~\END)~\END \\ + && (\iff \expand_F(\X{bt}) = [t_1^m] \to [t_2^n]) + \end{array} + + +.. _exec-throw_ref: + +:math:`\THROWREF` +................. + +1. Let :math:`F` be the :ref:`current ` :ref:`frame `. + +2. Assert: due to :ref:`validation `, a :ref:`reference ` is on the top of the stack. + +3. Pop the reference :math:`\reff` from the stack. + +4. If :math:`\reff` is :math:`\REFNULL~\X{ht}`, then: + + a. Trap. + +5. Assert: due to :ref:`validation `, :math:`\reff` is an :ref:`exception reference `. + +6. Let :math:`\REFEXNADDR~\X{ea}` be :math:`\reff`. + +7. Assert: due to :ref:`validation `, :math:`S.\SEXNS[\X{ea}]` exists. + +8. Let :math:`\X{exn}` be the :ref:`exception instance ` :math:`S.\SEXNS[\X{ea}]`. + +9. Let :math:`a` be the :ref:`tag address ` :math:`\X{exn}.\EITAG`. + +10. While the stack is not empty and the top of the stack is not an :ref:`exception handler `, do: + + a. Pop the top element from the stack. + +11. Assert: the stack is now either empty, or there is an exception handler on the top of the stack. + +12. If the stack is empty, then: + + a. Return the exception :math:`(\REFEXNADDR~a)` as a :ref:`result `. + +13. Assert: there is an :ref:`exception handler ` on the top of the stack. + +14. Pop the exception handler :math:`\HANDLER_n\{\catch^\ast\}` from the stack. + +15. If :math:`\catch^\ast` is empty, then: + + a. Push the exception reference :math:`\REFEXNADDR~\X{ea}` back to the stack. + + b. Execute the instruction |THROWREF| again. + +16. Else: + + a. Let :math:`\catch_1` be the first :ref:`catch clause ` in :math:`\catch^\ast` and :math:`{\catch'}^\ast` the remaining clauses. + + b. If :math:`\catch_1` is of the form :math:`\CATCH~x~l` and the :ref:`exception address ` :math:`a` equals :math:`F.\AMODULE.\MITAGS[x]`, then: + + i. Push the values :math:`\X{exn}.\EIFIELDS` to the stack. + + ii. Execute the instruction :math:`\BR~l`. + + c. Else if :math:`\catch_1` is of the form :math:`\CATCHREF~x~l` and the :ref:`exception address ` :math:`a` equals :math:`F.\AMODULE.\MITAGS[x]`, then: + + i. Push the values :math:`\X{exn}.\EIFIELDS` to the stack. + + ii. Push the exception reference :math:`\REFEXNADDR~\X{ea}` to the stack. + + iii. Execute the instruction :math:`\BR~l`. + + d. Else if :math:`\catch_1` is of the form :math:`\CATCHALL~l`, then: + + i. Execute the instruction :math:`\BR~l`. + + e. Else if :math:`\catch_1` is of the form :math:`\CATCHALLREF~l`, then: + + i. Push the exception reference :math:`\REFEXNADDR~\X{ea}` to the stack. + + ii. Execute the instruction :math:`\BR~l`. + + f. Else if :math:`\catch_1` is of the form :math:`\CATCH~x~\instr^\ast` and the :ref:`exception address ` :math:`a` equals :math:`F.\AMODULE.\MITAGS[x]`, then: + + i. Push the caught exception :math:`\CAUGHT_n\{\X{ea}\}` to the stack. + + ii. Push the values :math:`\X{exn}.\EIFIELDS` to the stack. + + iii. :ref:`Enter ` the catch block :math:`\instr^\ast`. + + g. Else if :math:`\catch_1` is of the form :math:`\CATCHALL~\instr^\ast`, then: + + i. Push the caught exception :math:`\CAUGHT_n\{\X{ea}\}` to the stack. + + ii. :ref:`Enter ` the catch block :math:`\instr^\ast`. + + h. Else if :math:`\catch_1` is of the form :math:`\DELEGATE~l`, then: + + i. Assert: due to :ref:`validation `, the stack contains at least :math:`l` labels. + + ii. Repeat :math:`l` times: + + * While the top of the stack is not a label, do: + + - Pop the top element from the stack. + + iii. Assert: due to :ref:`validation `, the top of the stack now is a label. + + iv. Pop the label from the stack. + + v. Push the exception reference :math:`\REFEXNADDR~\X{ea}` back to the stack. + + vi. Execute the instruction :math:`\THROWREF` again. + + i. Else: + + 1. Push the modified handler :math:`\HANDLER_n\{{\catch'}^\ast\}` back to the stack. + + 2. Push the exception reference :math:`\REFEXNADDR~\X{ea}` back to the stack. + + 3. Execute the instruction :math:`\THROWREF` again. + +.. math:: + ~\\[-1ex] + \begin{array}{rcl} + \dots \\ + \HANDLER_n\{(\CATCH~x~\instr^\ast)~\catch^\ast\}~\XT[(\REFEXNADDR~a)~\THROWREF]~\END &\stepto& + \CAUGHT_n\{a\}~\X{exn}.\EIFIELDS~\instr^\ast~\END \\ && + (\begin{array}[t]{@{}r@{~}l@{}} + \iff & \X{exn} = S.\SEXNS[a] \\ + \land & \X{exn}.\EITAG = F.\AMODULE.\MITAGS[x]) \\ + \end{array} \\ + \HANDLER_n\{(\CATCHALL~\instr^\ast)~\catch^\ast\}~\XT[(\REFEXNADDR~a)~\THROWREF]~\END &\stepto& + \CAUGHT_n\{a\}~\instr^\ast~\END \\ + \XB^l[\HANDLER_n\{(\DELEGATE~l)~\catch^\ast\}~\XT[(\REFEXNADDR~a)~\THROWREF]~\END] &\stepto& + (\REFEXNADDR~a)~\THROWREF \\ + \end{array} + + +.. _exec-rethrow: + +:math:`\RETHROW~l` +.................. + +1. Assert: due to :ref:`validation `, the stack contains at least :math:`l+1` labels. + +2. Let :math:`L` be the :math:`l`-th label appearing on the stack, starting from the top and counting from zero. + +3. Assert: due to :ref:`validation `, :math:`L` is a catch label, i.e., a label of the form :math:`(\LCATCH~[t^\ast])`, which is a label followed by a caught exception in an active catch clause. + +4. Let :math:`a` be the caught exception address. + +5. Push the value :math:`\REFEXNADDR~a` onto the stack. + +6. Execute the instruction |THROWREF|. + +.. math:: + ~\\[-1ex] + \begin{array}{lclr@{\qquad}} + \CAUGHT_n\{a\}~\XB^l[\RETHROW~l]~\END &\stepto& + \CAUGHT_n\{a\}~\XB^l[(\REFEXNADDR~a)~\THROWREF]~\END \\ + \end{array} + + +.. _exec-caught-enter: + +Entering a catch block +...................... + +1. Jump to the start of the instruction sequence :math:`\instr^\ast`. + + +.. _exec-caught-exit: + +Exiting a catch block +..................... + +When the |END| of a catch block is reached without a jump, thrown exception, or trap, then the following steps are performed. + +1. Let :math:`\val^m` be the values on the top of the stack. + +2. Pop the values :math:`\val^m` from the stack. + +3. Assert: due to :ref:`validation `, a caught exception is now on the top of the stack. + +4. Pop the caught exception from the stack. + +5. Push :math:`\val^m` back to the stack. + +6. Jump to the position after the |END| of the administrative instruction associated with the caught exception. + +.. math:: + \begin{array}{rcl} + \CAUGHT_n\{a\}~\val^m~\END &\stepto& \val^m + \end{array} + +.. note:: + A caught exception can only be rethrown from the scope of the administrative instruction associated with it, i.e., from the scope of the |CATCH| or |CATCHALL| block of a legacy |TRY| instruction. Upon exit from that block, the caught exception is discarded. diff --git a/document/legacy/exceptions/index.rst b/document/legacy/exceptions/index.rst new file mode 100644 index 00000000..b6428fb7 --- /dev/null +++ b/document/legacy/exceptions/index.rst @@ -0,0 +1,22 @@ +WebAssembly Specification Addendum: Legacy Exception Handling +============================================================= + +.. only:: html + + | Release |release| + + | Editor: Andreas Rossberg + + | Latest Draft: |WasmDraft| + | Issue Tracker: |WasmIssues| + +.. toctree:: + :maxdepth: 1 + + intro + syntax + valid + exec + binary + text + appendix/index-instructions diff --git a/document/legacy/exceptions/intro.rst b/document/legacy/exceptions/intro.rst new file mode 100644 index 00000000..b8d8c57c --- /dev/null +++ b/document/legacy/exceptions/intro.rst @@ -0,0 +1,8 @@ +.. _intro: + +Introduction +============ + +This document describes an extension of the official WebAssembly standard +developed by its `W3C Community Group `_ with additional instructions for exception handling. +These instructions were never standardized and are deprecated, but they may still be available in some engines, especially in web browsers. diff --git a/document/legacy/exceptions/static/custom.css b/document/legacy/exceptions/static/custom.css new file mode 100644 index 00000000..33bb863d --- /dev/null +++ b/document/legacy/exceptions/static/custom.css @@ -0,0 +1,78 @@ +a { + color: #004BAB; + text-decoration: none; +} + +a.reference { + border-bottom: none; +} + +a.reference:hover { + border-bottom: 1px dotted #004BAB; +} + +body { + font-size: 15px; +} + +div.document { width: 1000px; } +div.bodywrapper { margin: 0 0 0 200px; } +div.body { padding: 0 10px 0 10px; } +div.footer { width: 1000px; } + +div.body h1 { font-size: 200%; } +div.body h2 { font-size: 150%; } +div.body h3 { font-size: 120%; } +div.body h4 { font-size: 110%; } + +div.note { + border: 0px; + font-size: 90%; + background-color: #F6F8FF; +} + +div.admonition { + padding: 10px; +} + +div.admonition p.admonition-title { + margin: 0px 0px 0px 0px; + font-size: 100%; + font-weight: bold; +} + +div.math { + background-color: #F0F0F0; + padding: 3px 0 3px 0; + overflow-x: auto; + overflow-y: hidden; +} + +div.relations { + display: block; +} + +div.sphinxsidebar { + z-index: 1; + background: #FFF; + margin-top: -30px; + font-size: 13px; + width: 200px; + height: 100%; +} + +div.sphinxsidebarwrapper p.logo { + padding: 30px 40px 10px 0px; +} + +div.sphinxsidebar h3 { + font-size: 0px; +} + +div.sphinxsidebar a { + border-bottom: 0px; +} + +div.sphinxsidebar a:hover { + border-bottom: 1px dotted; +} diff --git a/document/legacy/exceptions/static/webassembly.png b/document/legacy/exceptions/static/webassembly.png new file mode 100644 index 0000000000000000000000000000000000000000..f9edc61098a6f6957903d4e67d92c81269c22e49 GIT binary patch literal 43955 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/legacy/exceptions/util/pseudo-lexer.py b/document/legacy/exceptions/util/pseudo-lexer.py new file mode 100644 index 00000000..fd3a251d --- /dev/null +++ b/document/legacy/exceptions/util/pseudo-lexer.py @@ -0,0 +1,32 @@ +from pygments.lexer import RegexLexer +from pygments.token import * +from sphinx.highlighting import lexers + +class PseudoLexer(RegexLexer): + name = 'Pseudo' + aliases = ['pseudo'] + filenames = ['*.pseudo'] + + tokens = { + 'root': [ + (r"(?` must be :ref:`valid ` as some :ref:`function type ` :math:`[t_1^\ast] \to [t_2^\ast]`. + +* Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with the :ref:`label type ` :math:`[t_2^\ast]` prepended to the |CLABELS| vector. + +* Under context :math:`C'`, + the instruction sequence :math:`\instr_1^\ast` must be :ref:`valid ` with type :math:`[t_1^\ast] \to [t_2^\ast]`. + +* Let :math:`C''` be the same :ref:`context ` as :math:`C`, but with the :ref:`label type ` :math:`\LCATCH~[t_2^\ast]` prepended to the |CLABELS| vector. + +* For every :math:`x_i` and :math:`\instr_{2i}^\ast` in :math:`(\CATCH~x~\instr_2^\ast)^\ast`: + + * The tag :math:`C.\CTAGS[x_i]` must be defined in the context :math:`C`. + + * Let :math:`[t_{3i}^\ast] \to [t_{4i}^\ast]` be the :ref:`tag type ` :math:`C.\CTAGS[x_i]`. + + * The :ref:`result type ` :math:`[t_{4i}^\ast]` must be empty. + + * Under context :math:`C''`, + the instruction sequence :math:`\instr_{2i}^\ast` must be :ref:`valid ` with type :math:`[t_{3i}^\ast] \to [t_2^\ast]`. + +* If :math:`(\CATCHALL~\instr_3^\ast)^?` is not empty, then: + + * Under context :math:`C''`, + the instruction sequence :math:`\instr_3^\ast` must be :ref:`valid ` with type :math:`[] \to [t_2^\ast]`. + +* Then the compound instruction is valid with type :math:`[t_1^\ast] \to [t_2^\ast]`. + +.. math:: + \frac{ + \begin{array}{c} + C \vdashblocktype \blocktype : [t_1^\ast] \to [t_2^\ast] + \qquad + C,\CLABELS\,[t_2^\ast] \vdashinstrseq \instr_1^\ast : [t_1^\ast] \to [t_2^\ast] \\ + (C.\CTAGS[x] = [t^\ast] \to [])^\ast \\ + C,\CLABELS\,(\LCATCH~[t_2^\ast]) \vdashinstrseq \instr_2^\ast : [t^\ast] \to [t_2^\ast])^\ast \\ + (C,\CLABELS\,(\LCATCH~[t_2^\ast]) \vdashinstrseq \instr_3^\ast : [] \to [t_2^\ast])^? + \end{array} + }{ + C \vdashinstr \TRY~\blocktype~\instr_1^\ast~(\CATCH~x~\instr_2^\ast)^\ast~(\CATCHALL~\instr_3^\ast)^?~\END : [t_1^\ast] \to [t_2^\ast] + } + + +.. note:: + The :ref:`notation ` :math:`C,\CLABELS\,(\LCATCH^?~[t^\ast])` inserts the new label type at index :math:`0`, shifting all others. + + +.. _valid-try-delegate: + +:math:`\TRY~\blocktype~\instr^\ast~\DELEGATE~l` +............................................... + +* The label :math:`C.\CLABELS[l]` must be defined in the context. + +* The :ref:`block type ` must be :ref:`valid ` as some :ref:`function type ` :math:`[t_1^\ast] \to [t_2^\ast]`. + +* Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with the :ref:`result type ` :math:`[t_2^\ast]` prepended to the |CLABELS| vector. + +* Under context :math:`C'`, + the instruction sequence :math:`\instr^\ast` must be :ref:`valid ` with type :math:`[t_1^\ast] \to [t_2^\ast]`. + +* Then the compound instruction is valid with type :math:`[t_1^\ast] \to [t_2^\ast]`. + +.. math:: + \frac{ + C \vdashblocktype \blocktype : [t_1^\ast] \to [t_2^\ast] + \qquad + C,\CLABELS\,[t_2^\ast] \vdashinstrseq \instr^\ast : [t_1^\ast]\to[t_2^\ast] + \qquad + C.\CLABELS[l] = [t_0^\ast] + }{ + C \vdashinstrseq \TRY~\blocktype~\instr^\ast~\DELEGATE~l : [t_1^\ast]\to[t_2^\ast] + } + +.. note:: + The :ref:`label index ` space in the :ref:`context ` :math:`C` contains the most recent label first, so that :math:`C.\CLABELS[l]` performs a relative lookup as expected. + + +.. _valid-rethrow: + +:math:`\RETHROW~l` +.................. + +* The label :math:`C.\CLABELS[l]` must be defined in the context. + +* Let :math:`(\LCATCH^?~[t^\ast])` be the :ref:`label type ` :math:`C.\CLABELS[l]`. + +* The |LCATCH| must be present in the :ref:`label type ` :math:`C.\CLABELS[l]`. + +* Then the instruction is valid with type :math:`[t_1^\ast] \to [t_2^\ast]`, for any sequences of :ref:`value types ` :math:`t_1^\ast` and :math:`t_2^\ast`. + + +.. math:: + \frac{ + C.\CLABELS[l] = \LCATCH~[t^\ast] + }{ + C \vdashinstr \RETHROW~l : [t_1^\ast] \to [t_2^\ast] + } + + +.. note:: + The |RETHROW| instruction is stack-polymorphic. diff --git a/interpreter/README.md b/interpreter/README.md index 30e044af..e7999896 100644 --- a/interpreter/README.md +++ b/interpreter/README.md @@ -232,8 +232,7 @@ expr: ( loop ? * ) ( if ? ( then * ) ( else * )? ) ( if ? + ( then * ) ( else * )? ) ;; = + (if ? (then *) (else *)?) - ( try ? ( do * ) ( catch * )* ( catch_all * )? ) - ( try ? ( do * ) ( delegate ) ) + ( try_table ? * * ) instr: @@ -242,9 +241,7 @@ instr: loop ? * end ? ;; = (loop ? *) if ? * end ? ;; = (if ? (then *)) if ? * else ? * end ? ;; = (if ? (then *) (else *)) - try ? * (catch ? *)* (catch_all ? *)? end ? - ;; = (try ? (do *) (catch *)* (catch_all *)?) - try ? * delegate ;; = (try ? (do *) (delegate )) + try_table ? * * end ? ;; = (try_table ? * *) op: unreachable @@ -286,7 +283,7 @@ op: ref.is_null ref.func throw - rethrow + throw_ref .const . . @@ -306,6 +303,12 @@ op: .extract_lane(_)? .replace_lane +catch: + catch + catch_ref + catch_all + catch_all_ref + func: ( func ? * * ) ( func ? ( export ) <...> ) ;; = (export (func )) (func ? <...>) ( func ? ( import ) ) ;; = (import (func ? )) diff --git a/interpreter/binary/decode.ml b/interpreter/binary/decode.ml index 88551a15..a677c405 100644 --- a/interpreter/binary/decode.ml +++ b/interpreter/binary/decode.ml @@ -164,6 +164,7 @@ let ref_type s = match s7 s with | -0x10 -> FuncRefType | -0x11 -> ExternRefType + | -0x17 -> ExnRefType | _ -> error s (pos s - 1) "malformed reference type" let value_type s = @@ -264,30 +265,10 @@ let rec instr s = end | 0x05 -> error s pos "misplaced ELSE opcode" - | 0x06 -> - let bt = block_type s in - let es = instr_block s in - let ct = catch_list s in - let ca = - if peek s = Some 0x19 then begin - ignore (byte s); - Some (instr_block s) - end else - None - in - if ct <> [] || ca <> None then begin - end_ s; - try_catch bt es ct ca - end else begin - match op s with - | 0x0b -> try_catch bt es [] None - | 0x18 -> try_delegate bt es (at var s) - | b -> illegal s pos b - end - | 0x07 -> error s pos "misplaced CATCH opcode" + | 0x06 | 0x07 as b -> illegal s pos b | 0x08 -> throw (at var s) - | 0x09 -> rethrow (at var s) - | 0x0a as b -> illegal s pos b + | 0x09 as b -> illegal s pos b + | 0x0a -> throw_ref | 0x0b -> error s pos "misplaced END opcode" | 0x0c -> br (at var s) @@ -309,16 +290,20 @@ let rec instr s = let x = at var s in return_call_indirect x y - | 0x14 | 0x15 | 0x16 | 0x17 as b -> illegal s pos b - - | 0x18 -> error s pos "misplaced DELEGATE opcode" - | 0x19 -> error s pos "misplaced CATCH_ALL opcode" + | 0x14 | 0x15 | 0x16 | 0x17 | 0x18 | 0x19 as b -> illegal s pos b | 0x1a -> drop | 0x1b -> select None | 0x1c -> select (Some (vec value_type s)) - | 0x1d | 0x1e | 0x1f as b -> illegal s pos b + | 0x1d | 0x1e as b -> illegal s pos b + + | 0x1f -> + let bt = block_type s in + let cs = vec (at catch) s in + let es = instr_block s in + end_ s; + try_table bt cs es | 0x20 -> local_get (at var s) | 0x21 -> local_set (at var s) @@ -813,19 +798,25 @@ let rec instr s = and instr_block s = List.rev (instr_block' s []) and instr_block' s es = match peek s with - | None | Some (0x05 | 0x07 | 0x0a | 0x0b | 0x18 | 0x19) -> es + | None | Some (0x05 | 0x0b) -> es | _ -> let pos = pos s in let e' = instr s in instr_block' s ((e' @@ region s pos pos) :: es) -and catch_list s = - if peek s = Some 0x07 then begin - ignore (byte s); - let tag = at var s in - let instrs = instr_block s in - (tag, instrs) :: catch_list s - end else - [] + +and catch s = + match byte s with + | 0x00 -> + let x1 = at var s in + let x2 = at var s in + Operators.catch x1 x2 + | 0x01 -> + let x1 = at var s in + let x2 = at var s in + catch_ref x1 x2 + | 0x02 -> catch_all (at var s) + | 0x03 -> catch_all_ref (at var s) + | _ -> error s (pos s - 1) "malformed catch clause" let const s = let c = at instr_block s in diff --git a/interpreter/binary/encode.ml b/interpreter/binary/encode.ml index 50ee0000..fb93d743 100644 --- a/interpreter/binary/encode.ml +++ b/interpreter/binary/encode.ml @@ -77,7 +77,7 @@ struct let string bs = len (String.length bs); put_string s bs let name n = string (Utf8.encode n) let list f xs = List.iter f xs - let opt f xo = Lib.Option.app f xo + let opt f xo = Option.iter f xo let vec f xs = len (List.length xs); list f xs let gap32 () = let p = pos s in word32 0l; byte 0; p @@ -109,6 +109,7 @@ struct let ref_type = function | FuncRefType -> s7 (-0x10) + | ExnRefType -> s7 (-0x17) | ExternRefType -> s7 (-0x11) let value_type = function @@ -167,20 +168,8 @@ struct op 0x04; block_type bt; list instr es1; if es2 <> [] then op 0x05; list instr es2; end_ () - | TryCatch (bt, es, ct, ca) -> - op 0x06; block_type bt; list instr es; - let catch (tag, es) = - op 0x07; var tag; list instr es - in - list catch ct; - begin match ca with - | None -> () - | Some es -> op 0x19; list instr es - end; - end_ () - | TryDelegate (bt, es, x) -> - op 0x06; block_type bt; list instr es; - op 0x18; var x + | TryTable (bt, cs, es) -> + op 0x1f; block_type bt; vec catch cs; list instr es; end_ () | Br x -> op 0x0c; var x | BrIf x -> op 0x0d; var x | BrTable (xs, x) -> op 0x0e; vec var xs; var x @@ -190,7 +179,7 @@ struct | ReturnCall x -> op 0x12; var x | ReturnCallIndirect (x, y) -> op 0x13; var y; var x | Throw x -> op 0x08; var x - | Rethrow x -> op 0x09; var x + | ThrowRef -> op 0x0a | Drop -> op 0x1a | Select None -> op 0x1b @@ -746,6 +735,13 @@ struct | VecReplace (V128 (F32x4 (V128Op.Replace i))) -> vecop 0x20l; byte i | VecReplace (V128 (F64x2 (V128Op.Replace i))) -> vecop 0x22l; byte i + and catch c = + match c.it with + | Catch (x1, x2) -> byte 0x00; var x1; var x2 + | CatchRef (x1, x2) -> byte 0x01; var x1; var x2 + | CatchAll x -> byte 0x02; var x + | CatchAllRef x -> byte 0x03; var x + let const c = list instr c.it; end_ () diff --git a/interpreter/exec/eval.ml b/interpreter/exec/eval.ml index 56834621..13f82a9d 100644 --- a/interpreter/exec/eval.ml +++ b/interpreter/exec/eval.ml @@ -66,13 +66,9 @@ and admin_instr' = | ReturningInvoke of value stack * func_inst | Breaking of int32 * value stack | Throwing of Tag.t * value stack - | Rethrowing of int32 * (admin_instr -> admin_instr) | Label of int32 * instr list * code | Frame of int32 * frame * code - | Catch of int32 * (Tag.t * instr list) list * instr list option * code - | Caught of int32 * Tag.t * value stack * code - | Delegate of int32 * code - | Delegating of int32 * Tag.t * value stack + | Handler of int32 * catch list * code type config = { @@ -237,23 +233,18 @@ let rec step (c : config) : config = let args, vs' = take n vs e.at, drop n vs e.at in vs', [Throwing (t, args) @@ e.at] - | Rethrow x, vs -> - vs, [Rethrowing (x.it, fun e -> e) @@ e.at] + | ThrowRef, Ref (NullRef _) :: vs -> + vs, [Trapping "null exception reference" @@ e.at] - | TryCatch (bt, es', cts, ca), vs -> - let FuncType (ts1, ts2) = block_type frame.inst bt in - let n1 = Lib.List32.length ts1 in - let n2 = Lib.List32.length ts2 in - let args, vs' = take n1 vs e.at, drop n1 vs e.at in - let cts' = List.map (fun (x, es'') -> ((tag frame.inst x), es'')) cts in - vs', [Label (n2, [], ([], [Catch (n2, cts', ca, (args, List.map plain es')) @@ e.at])) @@ e.at] + | ThrowRef, Ref (ExnRef (t, args)) :: vs -> + vs, [Throwing (t, args) @@ e.at] - | TryDelegate (bt, es', x), vs -> + | TryTable (bt, cs, es'), vs -> let FuncType (ts1, ts2) = block_type frame.inst bt in let n1 = Lib.List32.length ts1 in let n2 = Lib.List32.length ts2 in let args, vs' = take n1 vs e.at, drop n1 vs e.at in - vs', [Label (n2, [], ([], [Delegate (x.it, (args, List.map plain es')) @@ e.at])) @@ e.at] + vs', [Handler (n2, cs, (args, [Label (n2, [], ([], List.map plain es')) @@ e.at])) @@ e.at] | Drop, v :: vs' -> vs', [] @@ -655,12 +646,6 @@ let rec step (c : config) : config = | Throwing _, _ -> assert false - | Rethrowing _, _ -> - Crash.error e.at "undefined catch label" - - | Delegating _, _ -> - Crash.error e.at "undefined delegate label" - | Label (n, es0, (vs', [])), vs -> vs' @ vs, [] @@ -682,15 +667,6 @@ let rec step (c : config) : config = | Label (n, es0, (vs', {it = Throwing (a, vs0); at} :: es')), vs -> vs, [Throwing (a, vs0) @@ at] - | Label (n, es0, (vs', {it = Delegating (0l, a, vs0); at} :: es')), vs -> - vs, [Throwing (a, vs0) @@ at] - - | Label (n, es0, (vs', {it = Delegating (k, a, vs0); at} :: es')), vs -> - vs, [Delegating (Int32.sub k 1l, a, vs0) @@ at] - - | Label (n, es0, (vs', {it = Rethrowing (k, cont); at} :: es')), vs -> - vs, [Rethrowing (Int32.sub k 1l, (fun e -> Label (n, es0, (vs', cont e :: es')) @@ e.at)) @@ at] - | Label (n, es0, code'), vs -> let c' = step {c with code = code'} in vs, [Label (n, es0, c'.code) @@ e.at] @@ -715,59 +691,36 @@ let rec step (c : config) : config = let c' = step {frame = frame'; code = code'; budget = c.budget - 1} in vs, [Frame (n, c'.frame, c'.code) @@ e.at] - | Catch (n, cts, ca, (vs', [])), vs -> + | Handler (n, cs, (vs', [])), vs -> vs' @ vs, [] - | Catch (n, cts, ca, (vs', ({it = Trapping _ | Breaking _ | Returning _ | ReturningInvoke _ | Delegating _; at} as e) :: es')), vs -> + | Handler (n, cs, (vs', ({it = Trapping _ | Breaking _ | Returning _ | ReturningInvoke _; at} as e) :: es')), vs -> vs, [e] - | Catch (n, cts, ca, (vs', {it = Rethrowing (k, cont); at} :: es')), vs -> - vs, [Rethrowing (k, (fun e -> Catch (n, cts, ca, (vs', (cont e) :: es')) @@ e.at)) @@ at] - - | Catch (n, (a', es'') :: cts, ca, (vs', {it = Throwing (a, vs0); at} :: es')), vs -> - if a == a' then - vs, [Caught (n, a, vs0, (vs0, List.map plain es'')) @@ at] + | Handler (n, {it = Catch (x1, x2); _} :: cs, (vs', {it = Throwing (a, vs0); at} :: es')), vs -> + if a == tag frame.inst x1 then + vs0 @ vs, [Plain (Br x2) @@ e.at] else - vs, [Catch (n, cts, ca, (vs', {it = Throwing (a, vs0); at} :: es')) @@ e.at] - - | Catch (n, [], Some es'', (vs', {it = Throwing (a, vs0); at} :: es')), vs -> - vs, [Caught (n, a, vs0, (vs0, List.map plain es'')) @@ at] - - | Catch (n, [], None, (vs', {it = Throwing (a, vs0); at} :: es')), vs -> - vs, [Throwing (a, vs0) @@ at] + vs, [Handler (n, cs, (vs', {it = Throwing (a, vs0); at} :: es')) @@ e.at] - | Catch (n, cts, ca, code'), vs -> - let c' = step {c with code = code'} in - vs, [Catch (n, cts, ca, c'.code) @@ e.at] - - | Caught (n, a, vs0, (vs', [])), vs -> - vs' @ vs, [] - - | Caught (n, a, vs0, (vs', ({it = Trapping _ | Breaking _ | Returning _ | ReturningInvoke _ | Throwing _ | Delegating _; at} as e) :: es')), vs -> - vs, [e] - - | Caught (n, a, vs0, (vs', {it = Rethrowing (0l, cont); at} :: es')), vs -> - vs, [Caught (n, a, vs0, (vs', (cont (Throwing (a, vs0) @@ at)) :: es')) @@ e.at] - - | Caught (n, a, vs0, (vs', {it = Rethrowing (k, cont); at} :: es')), vs -> - vs, [Rethrowing (k, (fun e -> Caught (n, a, vs0, (vs', (cont e) :: es')) @@ e.at)) @@ at] - - | Caught (n, a, vs0, code'), vs -> - let c' = step {c with code = code'} in - vs, [Caught (n, a, vs0, c'.code) @@ e.at] + | Handler (n, {it = CatchRef (x1, x2); _} :: cs, (vs', {it = Throwing (a, vs0); at} :: es')), vs -> + if a == tag frame.inst x1 then + Ref (ExnRef (a, vs0)) :: vs0 @ vs, [Plain (Br x2) @@ e.at] + else + vs, [Handler (n, cs, (vs', {it = Throwing (a, vs0); at} :: es')) @@ e.at] - | Delegate (l, (vs', [])), vs -> - vs' @ vs, [] + | Handler (n, {it = CatchAll x; _} :: cs, (vs', {it = Throwing (a, vs0); at} :: es')), vs -> + vs, [Plain (Br x) @@ e.at] - | Delegate (l, (vs', ({it = Trapping _ | Breaking _ | Returning _ | ReturningInvoke _ | Rethrowing _ | Delegating _; at} as e) :: es')), vs -> - vs, [e] + | Handler (n, {it = CatchAllRef x; _} :: cs, (vs', {it = Throwing (a, vs0); at} :: es')), vs -> + Ref (ExnRef (a, vs0)) :: vs, [Plain (Br x) @@ e.at] - | Delegate (l, (vs', {it = Throwing (a, vs0); at} :: es')), vs -> - vs, [Delegating (l, a, vs0) @@ e.at] + | Handler (n, [], (vs', {it = Throwing (a, vs0); at} :: es')), vs -> + vs, [Throwing (a, vs0) @@ at] - | Delegate (l, code'), vs -> + | Handler (n, cs, code'), vs -> let c' = step {c with code = code'} in - vs, [Delegate (l, c'.code) @@ e.at] + vs, [Handler (n, cs, c'.code) @@ e.at] | Invoke func, vs when c.budget = 0 -> Exhaustion.error e.at "call stack exhausted" diff --git a/interpreter/script/js.ml b/interpreter/script/js.ml index a1f27d03..3bcfeb12 100644 --- a/interpreter/script/js.ml +++ b/interpreter/script/js.ml @@ -375,6 +375,7 @@ let assert_return ress ts at = let is_ref_idx = match t with | FuncRefType -> is_funcref_idx + | ExnRefType -> assert false | ExternRefType -> is_externref_idx in [ Call (is_ref_idx @@ at) @@ at; diff --git a/interpreter/script/run.ml b/interpreter/script/run.ml index bb92d0b8..8ca9b7a8 100644 --- a/interpreter/script/run.ml +++ b/interpreter/script/run.ml @@ -409,6 +409,7 @@ let assert_ref_pat r p = match r, p with | r, RefPat r' -> r = r'.it | Instance.FuncRef _, RefTypePat Types.FuncRefType + | Values.ExnRef _, RefTypePat Types.ExnRefType | ExternRef _, RefTypePat Types.ExternRefType -> true | _ -> false diff --git a/interpreter/syntax/ast.ml b/interpreter/syntax/ast.ml index 4a717781..1ba2c2f5 100644 --- a/interpreter/syntax/ast.ml +++ b/interpreter/syntax/ast.ml @@ -185,13 +185,9 @@ and instr' = | Unary of unop (* unary numeric operator *) | Binary of binop (* binary numeric operator *) | Convert of cvtop (* conversion *) - | TryCatch of block_type * instr list * (* try *) - (var * instr list) list * (* catch exception with tag *) - instr list option (* catch_all *) - | TryDelegate of block_type * instr list * (* try *) - var (* delegate to outer handler *) + | TryTable of block_type * catch list * instr list (* handle exceptions *) | Throw of var (* throw exception *) - | Rethrow of var (* rethrow exception *) + | ThrowRef (* rethrow exception *) | VecConst of vec (* constant *) | VecTest of vec_testop (* vector test *) | VecCompare of vec_relop (* vector comparison *) @@ -208,6 +204,13 @@ and instr' = | VecExtract of vec_extractop (* extract lane from vector *) | VecReplace of vec_replaceop (* replace lane in vector *) +and catch = catch' Source.phrase +and catch' = + | Catch of var * var + | CatchRef of var * var + | CatchAll of var + | CatchAllRef of var + (* Globals & Functions *) diff --git a/interpreter/syntax/free.ml b/interpreter/syntax/free.ml index fdc5f363..650fca1c 100644 --- a/interpreter/syntax/free.ml +++ b/interpreter/syntax/free.ml @@ -82,6 +82,10 @@ let rec instr (e : instr) = | Call x | ReturnCall x -> funcs (var x) | CallIndirect (x, y) | ReturnCallIndirect (x, y) -> tables (var x) ++ types (var y) + | Throw x -> tags (var x) + | ThrowRef -> empty + | TryTable (bt, cs, es) -> + block_type bt ++ list catch cs ++ block es | LocalGet x | LocalSet x | LocalTee x -> locals (var x) | GlobalGet x | GlobalSet x -> globals (var x) | TableGet x | TableSet x | TableSize x | TableGrow x | TableFill x -> @@ -100,19 +104,15 @@ let rec instr (e : instr) = memories zero | MemoryInit x -> memories zero ++ datas (var x) | DataDrop x -> datas (var x) - | TryCatch (bt, es, ct, ca) -> - let catch (tag, es) = tags (var tag) ++ block es in - let catch_all = function - | None -> empty - | Some es -> block es in - block es ++ (list catch ct) ++ catch_all ca - | TryDelegate (bt, es, x) -> block es ++ tags (var x) - | Throw x -> tags (var x) - | Rethrow x -> labels (var x) and block (es : instr list) = let free = list instr es in {free with labels = shift free.labels} +and catch (c : catch) = + match c.it with + | Catch (x1, x2) | CatchRef (x1, x2) -> tags (var x1) ++ labels (var x2) + | CatchAll x | CatchAllRef x -> labels (var x) + let const (c : const) = block c.it let global (g : global) = const g.it.ginit diff --git a/interpreter/syntax/operators.ml b/interpreter/syntax/operators.ml index 487c3051..348207df 100644 --- a/interpreter/syntax/operators.ml +++ b/interpreter/syntax/operators.ml @@ -20,19 +20,23 @@ let select t = Select t let block bt es = Block (bt, es) let loop bt es = Loop (bt, es) let if_ bt es1 es2 = If (bt, es1, es2) -let try_catch bt es ct ca = TryCatch (bt, es, ct, ca) -let try_delegate bt es x = TryDelegate (bt, es, x) +let try_table bt cs es = TryTable (bt, cs, es) let br x = Br x let br_if x = BrIf x let br_table xs x = BrTable (xs, x) +let catch x1 x2 = Catch (x1, x2) +let catch_ref x1 x2 = CatchRef (x1, x2) +let catch_all x = CatchAll x +let catch_all_ref x = CatchAllRef x + let return = Return let call x = Call x let call_indirect x y = CallIndirect (x, y) let return_call x = ReturnCall x let return_call_indirect x y = ReturnCallIndirect (x, y) let throw x = Throw x -let rethrow x = Rethrow x +let throw_ref = ThrowRef let local_get x = LocalGet x let local_set x = LocalSet x diff --git a/interpreter/syntax/types.ml b/interpreter/syntax/types.ml index 5b40d8c3..cb153df9 100644 --- a/interpreter/syntax/types.ml +++ b/interpreter/syntax/types.ml @@ -2,7 +2,7 @@ type num_type = I32Type | I64Type | F32Type | F64Type type vec_type = V128Type -type ref_type = FuncRefType | ExternRefType +type ref_type = FuncRefType | ExnRefType | ExternRefType type value_type = NumType of num_type | VecType of vec_type | RefType of ref_type type result_type = value_type list type func_type = FuncType of result_type * result_type @@ -119,10 +119,12 @@ let string_of_vec_type = function let string_of_ref_type = function | FuncRefType -> "funcref" + | ExnRefType -> "exnref" | ExternRefType -> "externref" let string_of_refed_type = function | FuncRefType -> "func" + | ExnRefType -> "exn" | ExternRefType -> "extern" let string_of_value_type = function diff --git a/interpreter/syntax/values.ml b/interpreter/syntax/values.ml index eefe37d5..d4238a11 100644 --- a/interpreter/syntax/values.ml +++ b/interpreter/syntax/values.ml @@ -13,10 +13,12 @@ type num = (I32.t, I64.t, F32.t, F64.t) op type vec = (V128.t) vecop type ref_ = .. -type ref_ += NullRef of ref_type type value = Num of num | Vec of vec | Ref of ref_ +type ref_ += NullRef of ref_type +type ref_ += ExnRef of Tag.t * value list + (* Injection & projection *) @@ -96,7 +98,8 @@ let type_of_num = function let type_of_vec = function | V128 _ -> V128Type -let type_of_ref' = ref (function NullRef t -> t | _ -> assert false) +let type_of_ref' = + ref (function NullRef t -> t | ExnRef _ -> ExnRefType | _ -> assert false) let type_of_ref r = !type_of_ref' r let type_of_value = function @@ -114,6 +117,7 @@ let eq_vec v1 v2 = v1 = v2 let eq_ref' = ref (fun r1 r2 -> match r1, r2 with | NullRef _, NullRef _ -> true + | ExnRef _, ExnRef _ -> r1 == r2 | _, _ -> false ) @@ -169,7 +173,8 @@ let string_of_vec = function let hex_string_of_vec = function | V128 v -> V128.to_hex_string v -let string_of_ref' = ref (function NullRef t -> "null" | _ -> "ref") +let string_of_ref' = + ref (function NullRef t -> "null" | ExnRef _ -> "exn" | _ -> "ref") let string_of_ref r = !string_of_ref' r let string_of_value = function diff --git a/interpreter/text/arrange.ml b/interpreter/text/arrange.ml index ba3f2bcf..53c463f1 100644 --- a/interpreter/text/arrange.ml +++ b/interpreter/text/arrange.ml @@ -456,6 +456,10 @@ let rec instr e = | ReturnCall x -> "return_call " ^ var x, [] | ReturnCallIndirect (x, y) -> "return_call_indirect " ^ var x, [Node ("type " ^ var y, [])] + | Throw x -> "throw " ^ var x, [] + | ThrowRef -> "throw_ref", [] + | TryTable (bt, cs, es) -> + "try_table", block_type bt @ list catch cs @ list instr es | LocalGet x -> "local.get " ^ var x, [] | LocalSet x -> "local.set " ^ var x, [] | LocalTee x -> "local.tee " ^ var x, [] @@ -490,18 +494,6 @@ let rec instr e = | Unary op -> unop op, [] | Binary op -> binop op, [] | Convert op -> cvtop op, [] - | TryCatch (bt, es, ct, ca) -> - let catch (tag, es) = Node ("catch " ^ var tag, list instr es) in - let catch_all = match ca with - | Some es -> [Node ("catch_all", list instr es)] - | None -> [] in - let handler = list catch ct @ catch_all in - "try", block_type bt @ [Node ("do", list instr es)] @ handler - | TryDelegate (bt, es, x) -> - let delegate = [Node ("delegate " ^ var x, [])] in - "try", block_type bt @ [Node ("do", list instr es)] @ delegate - | Throw x -> "throw " ^ var x, [] - | Rethrow x -> "rethrow " ^ var x, [] | VecConst v -> vec_constop v.it ^ " " ^ vec v, [] | VecTest op -> vec_testop op, [] | VecUnary op -> vec_unop op, [] @@ -519,6 +511,13 @@ let rec instr e = | VecReplace op -> vec_replaceop op, [] in Node (head, inner) +and catch c = + match c.it with + | Catch (x1, x2) -> Node ("catch " ^ var x1 ^ " " ^ var x2, []) + | CatchRef (x1, x2) -> Node ("catch_ref " ^ var x1 ^ " " ^ var x2, []) + | CatchAll x -> Node ("catch_all " ^ var x, []) + | CatchAllRef x -> Node ("catch_all_ref " ^ var x, []) + let const head c = match c.it with | [e] -> instr e diff --git a/interpreter/text/lexer.mll b/interpreter/text/lexer.mll index 9a7a5482..f7d09144 100644 --- a/interpreter/text/lexer.mll +++ b/interpreter/text/lexer.mll @@ -147,7 +147,9 @@ rule token = parse | "f32x4" -> VEC_SHAPE (V128.F32x4 ()) | "f64x2" -> VEC_SHAPE (V128.F64x2 ()) + | "exn" -> EXN | "extern" -> EXTERN + | "exnref" -> EXNREF | "externref" -> EXTERNREF | "funcref" -> FUNCREF | "mut" -> MUT @@ -170,6 +172,13 @@ rule token = parse | "call_indirect" -> CALL_INDIRECT | "return_call" -> RETURN_CALL | "return_call_indirect" -> RETURN_CALL_INDIRECT + | "try_table" -> TRY_TABLE + | "catch" -> CATCH + | "catch_ref" -> CATCH_REF + | "catch_all" -> CATCH_ALL + | "catch_all_ref" -> CATCH_ALL_REF + | "throw" -> THROW + | "throw_ref" -> THROW_REF | "local.get" -> LOCAL_GET | "local.set" -> LOCAL_SET @@ -276,6 +285,7 @@ rule token = parse | "ref.null" -> REF_NULL | "ref.func" -> REF_FUNC + | "ref.exn" -> REF_EXN | "ref.extern" -> REF_EXTERN | "ref.is_null" -> REF_IS_NULL @@ -655,14 +665,6 @@ rule token = parse | "f32x4.replace_lane" -> VEC_REPLACE f32x4_replace_lane | "f64x2.replace_lane" -> VEC_REPLACE f64x2_replace_lane - | "try" -> TRY - | "do" -> DO - | "catch" -> CATCH - | "catch_all" -> CATCH_ALL - | "delegate" -> DELEGATE - | "throw" -> THROW - | "rethrow" -> RETHROW - | "type" -> TYPE | "func" -> FUNC | "param" -> PARAM diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly index 429c31c8..be41cd7a 100644 --- a/interpreter/text/parser.mly +++ b/interpreter/text/parser.mly @@ -144,9 +144,6 @@ let func_type (c : context) x = try (Lib.List32.nth c.types.list x.it).it with Failure _ -> error x.at ("unknown type " ^ Int32.to_string x.it) -let handlers (c : context) h = - List.map (fun (l, i) -> (l c tag, i c)) h - let anon category space n = let i = space.count in space.count <- Int32.add i n; @@ -214,10 +211,10 @@ let inline_type_explicit (c : context) x ft at = %token NUM_TYPE %token VEC_TYPE %token VEC_SHAPE -%token FUNCREF EXTERNREF EXTERN MUT +%token FUNCREF EXNREF EXTERNREF EXN EXTERN MUT %token UNREACHABLE NOP DROP SELECT -%token BLOCK END IF THEN ELSE LOOP BR BR_IF BR_TABLE TRY DO CATCH CATCH_ALL -%token DELEGATE +%token BLOCK END IF THEN ELSE LOOP BR BR_IF BR_TABLE +%token TRY_TABLE CATCH CATCH_REF CATCH_ALL CATCH_ALL_REF THROW THROW_REF %token CALL CALL_INDIRECT RETURN RETURN_CALL RETURN_CALL_INDIRECT %token LOCAL_GET LOCAL_SET LOCAL_TEE GLOBAL_GET GLOBAL_SET %token TABLE_GET TABLE_SET @@ -227,8 +224,7 @@ let inline_type_explicit (c : context) x ft at = %token OFFSET_EQ_NAT ALIGN_EQ_NAT %token Ast.instr' * Values.num> CONST %token UNARY BINARY TEST COMPARE CONVERT -%token REF_NULL REF_FUNC REF_EXTERN REF_IS_NULL -%token THROW RETHROW +%token REF_NULL REF_FUNC REF_EXN REF_EXTERN REF_IS_NULL %token Memory.offset -> Ast.instr'> VEC_LOAD VEC_STORE %token Memory.offset -> int -> Ast.instr'> VEC_LOAD_LANE VEC_STORE_LANE %token string Source.phrase list -> Source.region -> Ast.instr' * Values.vec> VEC_CONST @@ -267,10 +263,12 @@ string_list : ref_kind : | FUNC { FuncRefType } + | EXN { ExnRefType } | EXTERN { ExternRefType } ref_type : | FUNCREF { FuncRefType } + | EXNREF { ExnRefType } | EXTERNREF { ExternRefType } value_type : @@ -397,7 +395,7 @@ plain_instr : | CALL var { fun c -> call ($2 c func) } | RETURN_CALL var { fun c -> return_call ($2 c func) } | THROW var { fun c -> throw ($2 c tag) } - | RETHROW var { fun c -> rethrow ($2 c label) } + | THROW_REF { fun c -> throw_ref } | LOCAL_GET var { fun c -> local_get ($2 c local) } | LOCAL_SET var { fun c -> local_set ($2 c local) } | LOCAL_TEE var { fun c -> local_tee ($2 c local) } @@ -522,12 +520,9 @@ block_instr : | IF labeling_opt block ELSE labeling_end_opt instr_list END labeling_end_opt { fun c -> let c' = $2 c ($5 @ $8) in let ts, es1 = $3 c' in if_ ts es1 ($6 c') } - | TRY labeling_opt block handler_instr - { fun c -> let c' = $2 c [] in - let ts, es = $3 c' in $4 ts es c' } - | TRY labeling_opt block DELEGATE var - { fun c -> let c' = $2 c [] in - let ts, es = $3 c' in try_delegate ts es ($5 c label) } + | TRY_TABLE labeling_opt handler_block END labeling_end_opt + { fun c -> let c' = $2 c $5 in + let bt, (cs, es) = $3 c c' in try_table bt cs es } block : | type_use block_param_body @@ -557,43 +552,49 @@ block_result_body : { let FuncType (ins, out) = fst $5 in FuncType (ins, $3 @ out), snd $5 } -handler_instr : - | catch_list_instr END - { fun bt es c -> try_catch bt es (handlers c $1) None } - | catch_list_instr catch_all END - { fun bt es c -> try_catch bt es (handlers c $1) (Some ($2 c)) } - | catch_all END - { fun bt es c -> try_catch bt es [] (Some ($1 c)) } - | END { fun bt es c -> try_catch bt es [] None } - -catch_list_instr : - | catch catch_list_instr { $1 :: $2 } - | catch { [$1] } - -handler : - | catch_list - { fun bt es _ c' -> - let cs = (List.map (fun (l, i) -> (l c' tag, i c')) $1) in - try_catch bt es cs None } - | catch_list LPAR catch_all RPAR - { fun bt es _ c' -> - let cs = (List.map (fun (l, i) -> (l c' tag, i c')) $1) in - try_catch bt es cs (Some ($3 c')) } - | LPAR catch_all RPAR - { fun bt es _ c' -> try_catch bt es [] (Some ($2 c')) } - | LPAR DELEGATE var RPAR - { fun bt es c _ -> try_delegate bt es ($3 c label) } - | /* empty */ { fun bt es c _ -> try_catch bt es [] None } - -catch_list : - | catch_list LPAR catch RPAR { $1 @ [$3] } - | LPAR catch RPAR { [$2] } - -catch : - | CATCH var instr_list { ($2, $3) } - -catch_all : - | CATCH_ALL instr_list { $2 } + +handler_block : + | type_use handler_block_param_body + { let at1 = ati 1 in + fun c c' -> let ft, esh = $2 c c' in + VarBlockType (inline_type_explicit c ($1 c type_) ft at1), esh } + | handler_block_param_body /* Sugar */ + { let at = at () in + fun c c' -> let ft, esh = $1 c c' in + let bt = + match ft with + | FuncType ([], []) -> ValBlockType None + | FuncType ([], [t]) -> ValBlockType (Some t) + | ft -> VarBlockType (inline_type c ft at) + in bt, esh } + +handler_block_param_body : + | handler_block_result_body { $1 } + | LPAR PARAM value_type_list RPAR handler_block_param_body + { fun c c' -> let FuncType (ins, out), esh = $5 c c' in + FuncType ($3 @ ins, out), esh } + +handler_block_result_body : + | handler_block_body { fun c c' -> FuncType ([], []), $1 c c' } + | LPAR RESULT value_type_list RPAR handler_block_result_body + { fun c c' -> let FuncType (ins, out), esh = $5 c c' in + FuncType (ins, $3 @ out), esh } + +handler_block_body : + | instr_list + { fun c c' -> [], $1 c' } + | LPAR CATCH var var RPAR handler_block_body + { fun c c' -> let cs, es = $6 c c' in + (catch ($3 c tag) ($4 c label) @@ ati 2) :: cs, es } + | LPAR CATCH_REF var var RPAR handler_block_body + { fun c c' -> let cs, es = $6 c c' in + (catch_ref ($3 c tag) ($4 c label) @@ ati 2) :: cs, es } + | LPAR CATCH_ALL var RPAR handler_block_body + { fun c c' -> let cs, es = $5 c c' in + (catch_all ($3 c label) @@ ati 2) :: cs, es } + | LPAR CATCH_ALL_REF var RPAR handler_block_body + { fun c c' -> let cs, es = $5 c c' in + (catch_all_ref ($3 c label) @@ ati 2) :: cs, es } expr : /* Sugar */ @@ -621,8 +622,9 @@ expr1 : /* Sugar */ | IF labeling_opt if_block { fun c -> let c' = $2 c [] in let bt, (es, es1, es2) = $3 c c' in es, if_ bt es1 es2 } - | TRY labeling_opt try_block - { fun c -> let c' = $2 c [] in [], $3 c c' } + | TRY_TABLE labeling_opt try_block + { fun c -> let c' = $2 c [] in + let bt, (cs, es) = $3 c c' in [], try_table bt cs es } select_expr_results : | LPAR RESULT value_type_list RPAR select_expr_results @@ -692,37 +694,53 @@ if_ : | LPAR THEN instr_list RPAR /* Sugar */ { fun c c' -> [], $3 c', [] } + try_block : | type_use try_block_param_body { let at = at () in fun c c' -> - let bt = VarBlockType (inline_type_explicit c' ($1 c' type_) (fst $2) at) in - snd $2 bt c c' } + let ft, esh = $2 c c' in + let bt = VarBlockType (inline_type_explicit c' ($1 c' type_) ft at) in + bt, esh } | try_block_param_body /* Sugar */ { let at = at () in fun c c' -> + let ft, esh = $1 c c' in let bt = - match fst $1 with + match ft with | FuncType ([], []) -> ValBlockType None | FuncType ([], [t]) -> ValBlockType (Some t) - | ft -> VarBlockType (inline_type c' ft at) - in snd $1 bt c c' } + | _ -> VarBlockType (inline_type c' ft at) + in bt, esh } try_block_param_body : | try_block_result_body { $1 } | LPAR PARAM value_type_list RPAR try_block_param_body - { let FuncType (ins, out) = fst $5 in - FuncType ($3 @ ins, out), snd $5 } + { fun c c' -> let FuncType (ins, out), esh = $5 c c' in + FuncType ($3 @ ins, out), esh } try_block_result_body : - | try_ { FuncType ([], []), $1 } + | try_block_handler_body { fun c c' -> FuncType ([], []), $1 c c' } | LPAR RESULT value_type_list RPAR try_block_result_body - { let FuncType (ins, out) = fst $5 in - FuncType (ins, $3 @ out), snd $5 } + { fun c c' -> let FuncType (ins, out), esh = $5 c c' in + FuncType (ins, $3 @ out), esh } + +try_block_handler_body : + | instr_list + { fun c c' -> [], $1 c' } + | LPAR CATCH var var RPAR try_block_handler_body + { fun c c' -> let cs, es = $6 c c' in + (catch ($3 c tag) ($4 c label) @@ ati 2) :: cs, es } + | LPAR CATCH_REF var var RPAR try_block_handler_body + { fun c c' -> let cs, es = $6 c c' in + (catch_ref ($3 c tag) ($4 c label) @@ ati 2) :: cs, es } + | LPAR CATCH_ALL var RPAR try_block_handler_body + { fun c c' -> let cs, es = $5 c c' in + (catch_all ($3 c label) @@ ati 2) :: cs, es } + | LPAR CATCH_ALL_REF var RPAR try_block_handler_body + { fun c c' -> let cs, es = $5 c c' in + (catch_all_ref ($3 c label) @@ ati 2) :: cs, es } -try_ : - | LPAR DO instr_list RPAR handler - { fun bt c c' -> $5 bt ($3 c') c c' } expr_list : | /* empty */ { fun c -> [] } @@ -1242,6 +1260,7 @@ result : | LPAR CONST NAN RPAR { NumResult (NanPat (nanop $2 ($3 @@ ati 3))) @@ at () } | literal_ref { RefResult (RefPat ($1 @@ at ())) @@ at () } | LPAR REF_FUNC RPAR { RefResult (RefTypePat FuncRefType) @@ at () } +/*| LPAR REF_EXN RPAR { RefResult (RefTypePat ExnRefType) @@ at () }*/ | LPAR REF_EXTERN RPAR { RefResult (RefTypePat ExternRefType) @@ at () } | LPAR VEC_CONST VEC_SHAPE numpat_list RPAR { if V128.num_lanes $3 <> List.length $4 then diff --git a/interpreter/valid/valid.ml b/interpreter/valid/valid.ml index f6d8a921..1f177519 100644 --- a/interpreter/valid/valid.ml +++ b/interpreter/valid/valid.ml @@ -14,8 +14,6 @@ let require b at s = if not b then error at s (* Context *) -type label_kind = BlockLabel | CatchLabel - type context = { types : func_type list; @@ -28,7 +26,7 @@ type context = datas : unit list; locals : value_type list; results : value_type list; - labels : (label_kind * result_type) list; + labels : result_type list; refs : Free.t; } @@ -257,34 +255,34 @@ let rec check_instr (c : context) (e : instr) (s : infer_result_type) : op_type | Block (bt, es) -> let FuncType (ts1, ts2) as ft = check_block_type c bt in - check_block {c with labels = (BlockLabel, ts2) :: c.labels} es ft e.at; + check_block {c with labels = ts2 :: c.labels} es ft e.at; ts1 --> ts2 | Loop (bt, es) -> let FuncType (ts1, ts2) as ft = check_block_type c bt in - check_block {c with labels = (BlockLabel, ts1) :: c.labels} es ft e.at; + check_block {c with labels = ts1 :: c.labels} es ft e.at; ts1 --> ts2 | If (bt, es1, es2) -> let FuncType (ts1, ts2) as ft = check_block_type c bt in - check_block {c with labels = (BlockLabel, ts2) :: c.labels} es1 ft e.at; - check_block {c with labels = (BlockLabel, ts2) :: c.labels} es2 ft e.at; + check_block {c with labels = ts2 :: c.labels} es1 ft e.at; + check_block {c with labels = ts2 :: c.labels} es2 ft e.at; (ts1 @ [NumType I32Type]) --> ts2 | Br x -> - let (_, ts) = label c x in + let ts = label c x in ts -->... [] | BrIf x -> - let (_, ts) = label c x in + let ts = label c x in (ts @ [NumType I32Type]) --> ts | BrTable (xs, x) -> - let (_, ts) = label c x in + let ts = label c x in let n = List.length ts in let ts' = Lib.List.table n (fun i -> peek (n - i) s) in check_stack ts' (known ts) x.at; - List.iter (fun x' -> check_stack ts' (known (snd (label c x'))) x'.at) xs; + List.iter (fun x' -> check_stack ts' (known (label c x')) x'.at) xs; (ts' @ [Some (NumType I32Type)]) -~>... [] | Return -> @@ -318,24 +316,14 @@ let rec check_instr (c : context) (e : instr) (s : infer_result_type) : op_type let FuncType (ts1, _) = type_ c (y @@ e.at) in ts1 -->... [] - | Rethrow x -> - let (kind, _) = label c x in - require (kind = CatchLabel) e.at "invalid rethrow label"; - [] -->... [] - - | TryCatch (bt, es, cts, ca) -> - let FuncType (ts1, ts2) as ft = check_block_type c bt in - let c_try = {c with labels = (BlockLabel, ts2) :: c.labels} in - let c_catch = {c with labels = (CatchLabel, ts2) :: c.labels} in - check_block c_try es ft e.at; - List.iter (fun ct -> check_catch ct c_catch ft e.at) cts; - Lib.Option.app (fun es -> check_block c_catch es ft e.at) ca; - ts1 --> ts2 + | ThrowRef -> + [RefType ExnRefType] -->... [] - | TryDelegate (bt, es, x) -> + | TryTable (bt, cs, es) -> let FuncType (ts1, ts2) as ft = check_block_type c bt in - ignore (label c x); - check_block {c with labels = (BlockLabel, ts2) :: c.labels} es ft e.at; + let c' = {c with labels = ts2 :: c.labels} in + List.iter (fun ct -> check_catch c ct ts2 e.at) cs; + check_block c' es ft e.at; ts1 --> ts2 | LocalGet x -> @@ -577,12 +565,30 @@ and check_block (c : context) (es : instr list) (ft : func_type) at = ("type mismatch: block requires " ^ string_of_result_type ts2 ^ " but stack has " ^ string_of_infer_types (snd s)) -and check_catch (ct : var * instr list) (c : context) (ft : func_type) at = - let (x, es) = ct in - let TagType y = tag c x in - let FuncType (ts1, _) = type_ c (y @@ at) in - let FuncType (_, ts2) = ft in - check_block c es (FuncType (ts1, ts2)) at +and check_catch (c : context) (cc : catch) (ts : value_type list) at = + match cc.it with + | Catch (x1, x2) -> + let TagType y = tag c x1 in + let FuncType (ts1, _) = type_ c (y @@ at) in + require (label c x2 = ts1) at + ("type mismatch: catch handler requires " ^ string_of_result_type ts1 ^ + " but label has " ^ string_of_result_type (label c x2)) + | CatchRef (x1, x2) -> + let TagType y = tag c x1 in + let FuncType (ts1, _) = type_ c (y @@ at) in + require (label c x2 = ts1 @ [RefType ExnRefType]) at + ("type mismatch: catch handler requires " ^ + string_of_result_type (ts1 @ [RefType ExnRefType]) ^ + " but label has " ^ string_of_result_type (label c x2)) + | CatchAll x -> + require (label c x = []) at + ("type mismatch: catch handler requires " ^ string_of_result_type [] ^ + " but label has " ^ string_of_result_type (label c x)) + | CatchAllRef x -> + require (label c x = [RefType ExnRefType]) at + ("type mismatch: catch handler requires " ^ + string_of_result_type [RefType ExnRefType] ^ + " but label has " ^ string_of_result_type (label c x)) (* Types *) @@ -652,7 +658,7 @@ let check_type (t : type_) = let check_func (c : context) (f : func) = let {ftype; locals; body} = f.it in let FuncType (ts1, ts2) = type_ c ftype in - let c' = {c with locals = ts1 @ locals; results = ts2; labels = [(BlockLabel, ts2)]} in + let c' = {c with locals = ts1 @ locals; results = ts2; labels = [ts2]} in check_block c' body (FuncType ([], ts2)) f.at let check_tag (c : context) (t : tag) = diff --git a/proposals/exception-handling/Exceptions.md b/proposals/exception-handling/Exceptions.md index afaa78f3..76661c3f 100644 --- a/proposals/exception-handling/Exceptions.md +++ b/proposals/exception-handling/Exceptions.md @@ -36,7 +36,7 @@ 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 +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 @@ -86,62 +86,50 @@ 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 +2. Catch clauses use a tag to identify the thrown exception it + can catch. If it matches, it pushes the corresponding argument values of the exception onto the stack. -### Try-catch blocks +### Exception references + +When caught, an exception is reified into an _exception reference_, a value of the new type `exnref`. +Exception references can be used to rethrow the caught exception. + +### Try blocks A _try block_ defines a list of instructions that may need to process exceptions and/or clean up state when an exception is thrown. Like other higher-level -constructs, a try block begins with a `try` instruction, and ends with an `end` -instruction. That is, a try-catch block is sequence of instructions having the +constructs, a try block begins with a `try_table` instruction, and ends with an `end` +instruction. That is, a try block is sequence of instructions having the following form: ``` -try blocktype - instruction* -catch i - instruction* -catch j - instruction* -... -catch_all +try_table blocktype catch* instruction* end ``` -A try-catch block contains zero or more `catch` blocks and zero or one -`catch_all` block. All `catch` blocks must precede the `catch_all` block, if -any. The `catch`/`catch_all` instructions (within the try construct) are called -the _catching_ instructions. There may not be any `catch` or `catch_all` blocks -after a `try`, in which case the `try` block does not catch any exceptions. - -The _body_ of the try block is the list of instructions before the first -catching instruction. The _body_ of each catch block is the sequence of -instructions following the corresponding catching instruction before the next -catching instruction (or the `end` instruction if it is the last catching -block). - -The `catch` instruction has an exception tag associated with it. The tag -identifies what exceptions it can catch. That is, any exception created with the -corresponding exception tag. Catch blocks that begin with a `catch` instruction -are considered _tagged_ catch blocks. - -The last catching instruction of a try-catch block can be the `catch_all` -instruction. If it begins with the `catch_all` instruction, it defines the -_default_ catch block. The default catch block has no tag index, and is used to -catch all exceptions not caught by any of the tagged catch blocks. The term -'catch block' refers to both `catch` and `catch_all` blocks. - -When the program runs `br` within `catch` or `catch_all` blocks, the rest of -the catching blocks will not run and the program control will branch to the -destination, as in normal blocks. +A try block contains zero or more _catch clauses_. If there are no catch clauses, then the try block does not catch any exceptions. + +The _body_ of the try block is the list of instructions after the last +catch clause, if any. + +Each `catch` clause can be in one of 4 forms: +``` +catch tag label +catch_ref tag label +catch_all label +catch_all_ref label +``` +All forms have a label which is branched to when an exception is 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 block. -Because `try` and `end` instructions define a control-flow block, they can be +exception is thrown, or the exception is successfully caught by the catch clause. +Because `try_table` defines a control-flow block, it can be targets for branches (`br` and `br_if`) as well. ### Throwing an exception @@ -168,280 +156,40 @@ 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 +Then catch clauses are tried in the order +they appear in the catching try block, until one matches. If a matching catch clause is found, control is transferred to the label of that catch clause. +In case of `catch` or `catch_ref`, the arguments of the exception are pushed back onto the stack. +For `catch_ref` and `catch_all_ref`, an exception reference is then pushed to the stack, which represents the caught exception. -Otherwise, control is transferred to the body of the `catch_all` block, if any. -However, unlike tagged catch blocks, the constructor arguments are not copied -back onto the operand stack. +If no catch clauses were matched, the exception is implicitly rethrown. -If no tagged catch blocks were matched, and the catching try block doesn't have -a `catch_all` block, the exception is rethrown. - -If control is transferred to the body of a catch block, and the last instruction -in the body is executed, control then exits the try block. - -If the selected catch block does not throw an exception, it must yield the -value(s) specified by the type annotation on the corresponding catching try -block. - -Note that a caught exception can be rethrown using the `rethrow` instruction. +Note that a caught exception can be rethrown explicitly using the `exnref` and the `throw_ref` instruction. ### Rethrowing an exception -The `rethrow` instruction can only appear in the body of a catch/catch_all -block. It always re-throws the exception caught by an enclosing catch block. - -Associated with the `rethrow` instruction is a _label_. The label is used to -disambiguate which exception is to be rethrown, when inside nested catch blocks. -The label is the relative block depth to the corresponding try block for which -the catching block appears. - -For example consider the following: - -``` -try $l1 - ... -catch ;; $l1 - ... - block - ... - try $l2 - ... - catch ;; $l2 - ... - try $l3 - ... - catch ;; $l3 - ... - rethrow N ;; (or label) - end - end - end - ... -end -``` - -In this example, `N` is used to disambiguate which caught exception is being -rethrown. It could rethrow any of the three caught expceptions. Hence, `rethrow -0` corresponds to the exception caught by `catch 3`, `rethrow 1` corresponds to -the exception caught by `catch 2`, and `rethrow 3` corresponds to the exception -caught by `catch 1`. In wat format, the argument for the `rethrow` instructions -can also be written as a label, like branches. So `rethrow 0` in the example -above can also be written as `rethrow $l3`. - -Note that `rethrow 2` is not allowed because it does not refer to a `try` label -from within its catch block. Rather, it references a `block` instruction, so it -will result in a validation failure. - -Note that the example below is a validation failure: -``` -try $l1 - try $l2 - rethrow $l2 ;; (= rethrow 0) - catch - end -catch -end -``` -The `rethrow` here references `try $l2`, but the `rethrow` is not within its -`catch` block. - -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 -) -``` +The `throw_ref` takes an operand of type `exnref` and re-throws the corresponding caught exception. +If the operand is null, a trap occurs. ### JS API #### Traps -The `catch`/`catch_all` instruction catches exceptions generated by the `throw` -instruction, but does not catch traps. The rationale for this is that in general +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-catch. +scopes like try blocks. -The `catch` instruction catches foreign exceptions generated from calls to +The `try_table` instruction catches foreign exceptions generated from calls to function imports as well, including JavaScript exceptions, with a few exceptions: 1. In order to be consistent before and after a trap reaches a JavaScript frame, - the `catch` instruction does not catch exceptions generated from traps. -1. The `catch` instruction does not catch JavaScript exceptions generated from + the `try_table` instruction does not catch exceptions generated from traps. +1. The `try_table` instruction does not catch JavaScript exceptions generated from stack overflow and out of memory. Filtering these exceptions should be based on a predicate that is not observable @@ -498,8 +246,8 @@ When `ExceptionOption` is not provided or it does not contain `traceStack` entry, `traceStack` is considered `false` by default. To preserve stack trace info when crossing the JS to Wasm boundary, exceptions -can internally contain a stack trace, which is propagated when caught by `catch` -and rethrown by `rethrow`. +can internally contain a stack trace, which is propagated when caught by a `catch[_all]_ref` clause +and rethrown by `throw_ref`. More formally, the added interfaces look like the following: @@ -542,17 +290,16 @@ document](https://github.com/WebAssembly/spec/blob/master/document/core/text/ins The following rules are added to *instructions*: ``` - try blocktype instruction* (catch tag_index instruction*)* (catch_all instruction*)? end | - try blocktype instruction* delegate label | - throw tag_index argument* | - rethrow label | + try_table blocktype catch* instruction* end | + throw tag_index | + throw_ref label | ``` -Like the `block`, `loop`, and `if` instructions, the `try` instruction is +Like the `block`, `loop`, and `if` instructions, the `try_table` instruction is *structured* control flow instruction, and can be labeled. This allows branch instructions to exit try blocks. -The `tag_index` of the `throw` and `catch` instructions denotes the exception +The `tag_index` of the `throw` and `catch[_ref]` clauses denotes the exception tag to use when creating/extract from an exception. See [tag index space](#tag-index-space) for further clarification of exception tags. @@ -580,6 +327,10 @@ document](https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md). #### Other Types +##### exnref + +The type `exnref` is represented by the type opcode `-0x17`. + ##### tag_type We reserve a bit to denote the exception attribute: @@ -679,19 +430,25 @@ follows: The tag names subsection is a `name_map` which assigns names to a subset of the tag indices (Used for both imports and module-defined). -### Control flow operators +### Control flow instructions -The control flow operators are extended to define try blocks, catch blocks, -throws, and rethrows as follows: +The control flow instructions are extended to define try blocks and +throws as follows: | Name | Opcode | Immediates | Description | | ---- | ---- | ---- | ---- | -| `try` | `0x06` | sig : `blocktype` | begins a block which can handle thrown exceptions | -| `catch` | `0x07` | index : `varint32` | begins the catch block of the try block | -| `catch_all` | `0x19` | | begins the catch_all block of the try block | -| `delegate` | `0x18` | relative_depth : `varuint32` | begins the delegate block of the try block | -| `throw` | `0x08` | index : `varint32` | Creates an exception defined by the tag and then throws it | -| `rethrow` | `0x09` | relative_depth : `varuint32` | Pops the `exnref` on top of the stack and throws it | - -The *sig* fields of `block`, `if`, and `try` operators are block signatures +| `try_table` | `0x1f` | sig : `blocktype`, n : `varuint32`, catch : `catch^n` | begins a block which can handle thrown exceptions | +| `throw` | `0x08` | index : `varuint32` | Creates an exception defined by the tag and then throws it | +| `throw_ref` | `0x0a` | | Pops an `exnref` from the stack and throws it | + +The *sig* fields of `block`, `if`, and `try_table` instructions are block types which describe their use of the operand stack. + +A `catch` handler is a pair of tag and label index: + +| Name | Opcode | Immediates | +| ------- | ------ | ----------- | +| `catch` | `0x00` | tag : `varuint32`, label : `varuint32` | +| `catch_ref` | `0x01` | tag : `varuint32`, label : `varuint32` | +| `catch_all` | `0x02` | label : `varuint32` | +| `catch_all_ref` | `0x02` | label : `varuint32` | diff --git a/test/core/binary.wast b/test/core/binary.wast index df176126..7e437317 100644 --- a/test/core/binary.wast +++ b/test/core/binary.wast @@ -118,7 +118,7 @@ ;; Missing end marker here "\0a\04\01\02\00\0b" ;; Code section: 1 function ) - "illegal opcode" + "unexpected end of section or function" ) ;; memory.grow reserved byte equal to zero. diff --git a/test/core/ref_null.wast b/test/core/ref_null.wast index b88b0888..eb4a3163 100644 --- a/test/core/ref_null.wast +++ b/test/core/ref_null.wast @@ -1,10 +1,13 @@ (module (func (export "externref") (result externref) (ref.null extern)) + (func (export "exnref") (result exnref) (ref.null exn)) (func (export "funcref") (result funcref) (ref.null func)) (global externref (ref.null extern)) + (global exnref (ref.null exn)) (global funcref (ref.null func)) ) (assert_return (invoke "externref") (ref.null extern)) +(assert_return (invoke "exnref") (ref.null exn)) (assert_return (invoke "funcref") (ref.null func)) diff --git a/test/core/throw.wast b/test/core/throw.wast index 2148d5ea..dc1aa4a9 100644 --- a/test/core/throw.wast +++ b/test/core/throw.wast @@ -26,15 +26,12 @@ (func $throw-1-2 (i32.const 1) (i32.const 2) (throw $e-i32-i32)) (func (export "test-throw-1-2") - (try - (do (call $throw-1-2)) - (catch $e-i32-i32 - (i32.const 2) - (if (i32.ne) (then (unreachable))) - (i32.const 1) - (if (i32.ne) (then (unreachable))) - ) + (block $h (result i32 i32) + (try_table (catch $e-i32-i32 $h) (call $throw-1-2)) + (return) ) + (if (i32.ne (i32.const 2)) (then (unreachable))) + (if (i32.ne (i32.const 1)) (then (unreachable))) ) ) diff --git a/test/core/throw_ref.wast b/test/core/throw_ref.wast new file mode 100644 index 00000000..f59710a1 --- /dev/null +++ b/test/core/throw_ref.wast @@ -0,0 +1,118 @@ +;; Test throw_ref instruction. + +(module + (tag $e0) + (tag $e1) + + (func (export "catch-throw_ref-0") + (block $h (result exnref) + (try_table (catch_ref $e0 $h) (throw $e0)) + (unreachable) + ) + (throw_ref) + ) + + (func (export "catch-throw_ref-1") (param i32) (result i32) + (block $h (result exnref) + (try_table (result i32) (catch_ref $e0 $h) (throw $e0)) + (return) + ) + (if (param exnref) (i32.eqz (local.get 0)) + (then (throw_ref)) + (else (drop)) + ) + (i32.const 23) + ) + + (func (export "catchall-throw_ref-0") + (block $h (result exnref) + (try_table (result exnref) (catch_all_ref $h) (throw $e0)) + ) + (throw_ref) + ) + + (func (export "catchall-throw_ref-1") (param i32) (result i32) + (block $h (result exnref) + (try_table (result i32) (catch_all_ref $h) (throw $e0)) + (return) + ) + (if (param exnref) (i32.eqz (local.get 0)) + (then (throw_ref)) + (else (drop)) + ) + (i32.const 23) + ) + + (func (export "throw_ref-nested") (param i32) (result i32) + (local $exn1 exnref) + (local $exn2 exnref) + (block $h1 (result exnref) + (try_table (result i32) (catch_ref $e1 $h1) (throw $e1)) + (return) + ) + (local.set $exn1) + (block $h2 (result exnref) + (try_table (result i32) (catch_ref $e0 $h2) (throw $e0)) + (return) + ) + (local.set $exn2) + (if (i32.eq (local.get 0) (i32.const 0)) + (then (throw_ref (local.get $exn1))) + ) + (if (i32.eq (local.get 0) (i32.const 1)) + (then (throw_ref (local.get $exn2))) + ) + (i32.const 23) + ) + + (func (export "throw_ref-recatch") (param i32) (result i32) + (local $e exnref) + (block $h1 (result exnref) + (try_table (result i32) (catch_ref $e0 $h1) (throw $e0)) + (return) + ) + (local.set $e) + (block $h2 (result exnref) + (try_table (result i32) (catch_ref $e0 $h2) + (if (i32.eqz (local.get 0)) + (then (throw_ref (local.get $e))) + ) + (i32.const 42) + ) + (return) + ) + (drop) (i32.const 23) + ) + + (func (export "throw_ref-stack-polymorphism") + (local $e exnref) + (block $h (result exnref) + (try_table (result f64) (catch_ref $e0 $h) (throw $e0)) + (unreachable) + ) + (local.set $e) + (i32.const 1) + (throw_ref (local.get $e)) + ) +) + +(assert_exception (invoke "catch-throw_ref-0")) + +(assert_exception (invoke "catch-throw_ref-1" (i32.const 0))) +(assert_return (invoke "catch-throw_ref-1" (i32.const 1)) (i32.const 23)) + +(assert_exception (invoke "catchall-throw_ref-0")) + +(assert_exception (invoke "catchall-throw_ref-1" (i32.const 0))) +(assert_return (invoke "catchall-throw_ref-1" (i32.const 1)) (i32.const 23)) +(assert_exception (invoke "throw_ref-nested" (i32.const 0))) +(assert_exception (invoke "throw_ref-nested" (i32.const 1))) +(assert_return (invoke "throw_ref-nested" (i32.const 2)) (i32.const 23)) + +(assert_return (invoke "throw_ref-recatch" (i32.const 0)) (i32.const 23)) +(assert_return (invoke "throw_ref-recatch" (i32.const 1)) (i32.const 42)) + +(assert_exception (invoke "throw_ref-stack-polymorphism")) + +(assert_invalid (module (func (throw_ref))) "type mismatch") +(assert_invalid (module (func (block (throw_ref)))) "type mismatch") diff --git a/test/core/try_table.wast b/test/core/try_table.wast new file mode 100644 index 00000000..e64b6c18 --- /dev/null +++ b/test/core/try_table.wast @@ -0,0 +1,372 @@ +;; Test try-catch blocks. + +(module + (tag $e0 (export "e0")) + (func (export "throw") (throw $e0)) +) + +(register "test") + +(module + (tag $imported-e0 (import "test" "e0")) + (func $imported-throw (import "test" "throw")) + (tag $e0) + (tag $e1) + (tag $e2) + (tag $e-i32 (param i32)) + (tag $e-f32 (param f32)) + (tag $e-i64 (param i64)) + (tag $e-f64 (param f64)) + + (func $throw-if (param i32) (result i32) + (local.get 0) + (i32.const 0) (if (i32.ne) (then (throw $e0))) + (i32.const 0) + ) + + (func (export "simple-throw-catch") (param i32) (result i32) + (block $h + (try_table (result i32) (catch $e0 $h) + (if (i32.eqz (local.get 0)) (then (throw $e0)) (else)) + (i32.const 42) + ) + (return) + ) + (i32.const 23) + ) + + (func (export "unreachable-not-caught") + (block $h + (try_table (catch_all $h) (unreachable)) + (return) + ) + ) + + (func $div (param i32 i32) (result i32) + (local.get 0) (local.get 1) (i32.div_u) + ) + (func (export "trap-in-callee") (param i32 i32) (result i32) + (block $h + (try_table (result i32) (catch_all $h) + (call $div (local.get 0) (local.get 1)) + ) + (return) + ) + (i32.const 11) + ) + + (func (export "catch-complex-1") (param i32) (result i32) + (block $h1 + (try_table (result i32) (catch $e1 $h1) + (block $h0 + (try_table (result i32) (catch $e0 $h0) + (if (i32.eqz (local.get 0)) + (then (throw $e0)) + (else + (if (i32.eq (local.get 0) (i32.const 1)) + (then (throw $e1)) + (else (throw $e2)) + ) + ) + ) + (i32.const 2) + ) + (br 1) + ) + (i32.const 3) + ) + (return) + ) + (i32.const 4) + ) + + (func (export "catch-complex-2") (param i32) (result i32) + (block $h0 + (block $h1 + (try_table (result i32) (catch $e0 $h0) (catch $e1 $h1) + (if (i32.eqz (local.get 0)) + (then (throw $e0)) + (else + (if (i32.eq (local.get 0) (i32.const 1)) + (then (throw $e1)) + (else (throw $e2)) + ) + ) + ) + (i32.const 2) + ) + (return) + ) + (return (i32.const 4)) + ) + (i32.const 3) + ) + + (func (export "throw-catch-param-i32") (param i32) (result i32) + (block $h (result i32) + (try_table (result i32) (catch $e-i32 $h) + (throw $e-i32 (local.get 0)) + (i32.const 2) + ) + (return) + ) + (return) + ) + + (func (export "throw-catch-param-f32") (param f32) (result f32) + (block $h (result f32) + (try_table (result f32) (catch $e-f32 $h) + (throw $e-f32 (local.get 0)) + (f32.const 0) + ) + (return) + ) + (return) + ) + + (func (export "throw-catch-param-i64") (param i64) (result i64) + (block $h (result i64) + (try_table (result i64) (catch $e-i64 $h) + (throw $e-i64 (local.get 0)) + (i64.const 2) + ) + (return) + ) + (return) + ) + + (func (export "throw-catch-param-f64") (param f64) (result f64) + (block $h (result f64) + (try_table (result f64) (catch $e-f64 $h) + (throw $e-f64 (local.get 0)) + (f64.const 0) + ) + (return) + ) + (return) + ) + + (func (export "throw-catch_ref-param-i32") (param i32) (result i32) + (block $h (result i32 exnref) + (try_table (result i32) (catch_ref $e-i32 $h) + (throw $e-i32 (local.get 0)) + (i32.const 2) + ) + (return) + ) + (drop) (return) + ) + + (func (export "throw-catch_ref-param-f32") (param f32) (result f32) + (block $h (result f32 exnref) + (try_table (result f32) (catch_ref $e-f32 $h) + (throw $e-f32 (local.get 0)) + (f32.const 0) + ) + (return) + ) + (drop) (return) + ) + + (func (export "throw-catch_ref-param-i64") (param i64) (result i64) + (block $h (result i64 exnref) + (try_table (result i64) (catch_ref $e-i64 $h) + (throw $e-i64 (local.get 0)) + (i64.const 2) + ) + (return) + ) + (drop) (return) + ) + + (func (export "throw-catch_ref-param-f64") (param f64) (result f64) + (block $h (result f64 exnref) + (try_table (result f64) (catch_ref $e-f64 $h) + (throw $e-f64 (local.get 0)) + (f64.const 0) + ) + (return) + ) + (drop) (return) + ) + + (func $throw-param-i32 (param i32) (throw $e-i32 (local.get 0))) + (func (export "catch-param-i32") (param i32) (result i32) + (block $h (result i32) + (try_table (result i32) (catch $e-i32 $h) + (i32.const 0) + (call $throw-param-i32 (local.get 0)) + ) + (return) + ) + ) + + (func (export "catch-imported") (result i32) + (block $h + (try_table (result i32) (catch $imported-e0 $h) + (call $imported-throw (i32.const 1)) + ) + (return) + ) + (i32.const 2) + ) + + (func (export "catchless-try") (param i32) (result i32) + (block $h + (try_table (result i32) (catch $e0 $h) + (try_table (result i32) (call $throw-if (local.get 0))) + ) + (return) + ) + (i32.const 1) + ) + + (func $throw-void (throw $e0)) + (func (export "return-call-in-try-catch") + (block $h + (try_table (catch $e0 $h) + (return_call $throw-void) + ) + ) + ) + + (table funcref (elem $throw-void)) + (func (export "return-call-indirect-in-try-catch") + (block $h + (try_table (catch $e0 $h) + (return_call_indirect (i32.const 0)) + ) + ) + ) +) + +(assert_return (invoke "simple-throw-catch" (i32.const 0)) (i32.const 23)) +(assert_return (invoke "simple-throw-catch" (i32.const 1)) (i32.const 42)) + +(assert_trap (invoke "unreachable-not-caught") "unreachable") + +(assert_return (invoke "trap-in-callee" (i32.const 7) (i32.const 2)) (i32.const 3)) +(assert_trap (invoke "trap-in-callee" (i32.const 1) (i32.const 0)) "integer divide by zero") + +(assert_return (invoke "catch-complex-1" (i32.const 0)) (i32.const 3)) +(assert_return (invoke "catch-complex-1" (i32.const 1)) (i32.const 4)) +(assert_exception (invoke "catch-complex-1" (i32.const 2))) + +(assert_return (invoke "catch-complex-2" (i32.const 0)) (i32.const 3)) +(assert_return (invoke "catch-complex-2" (i32.const 1)) (i32.const 4)) +(assert_exception (invoke "catch-complex-2" (i32.const 2))) + +(assert_return (invoke "throw-catch-param-i32" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "throw-catch-param-i32" (i32.const 1)) (i32.const 1)) +(assert_return (invoke "throw-catch-param-i32" (i32.const 10)) (i32.const 10)) + +(assert_return (invoke "throw-catch-param-f32" (f32.const 5.0)) (f32.const 5.0)) +(assert_return (invoke "throw-catch-param-f32" (f32.const 10.5)) (f32.const 10.5)) + +(assert_return (invoke "throw-catch-param-i64" (i64.const 5)) (i64.const 5)) +(assert_return (invoke "throw-catch-param-i64" (i64.const 0)) (i64.const 0)) +(assert_return (invoke "throw-catch-param-i64" (i64.const -1)) (i64.const -1)) + +(assert_return (invoke "throw-catch-param-f64" (f64.const 5.0)) (f64.const 5.0)) +(assert_return (invoke "throw-catch-param-f64" (f64.const 10.5)) (f64.const 10.5)) + +(assert_return (invoke "throw-catch_ref-param-i32" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "throw-catch_ref-param-i32" (i32.const 1)) (i32.const 1)) +(assert_return (invoke "throw-catch_ref-param-i32" (i32.const 10)) (i32.const 10)) + +(assert_return (invoke "throw-catch_ref-param-f32" (f32.const 5.0)) (f32.const 5.0)) +(assert_return (invoke "throw-catch_ref-param-f32" (f32.const 10.5)) (f32.const 10.5)) + +(assert_return (invoke "throw-catch_ref-param-i64" (i64.const 5)) (i64.const 5)) +(assert_return (invoke "throw-catch_ref-param-i64" (i64.const 0)) (i64.const 0)) +(assert_return (invoke "throw-catch_ref-param-i64" (i64.const -1)) (i64.const -1)) + +(assert_return (invoke "throw-catch_ref-param-f64" (f64.const 5.0)) (f64.const 5.0)) +(assert_return (invoke "throw-catch_ref-param-f64" (f64.const 10.5)) (f64.const 10.5)) + +(assert_return (invoke "catch-param-i32" (i32.const 5)) (i32.const 5)) + +(assert_return (invoke "catch-imported") (i32.const 2)) + +(assert_return (invoke "catchless-try" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "catchless-try" (i32.const 1)) (i32.const 1)) + +(assert_exception (invoke "return-call-in-try-catch")) +(assert_exception (invoke "return-call-indirect-in-try-catch")) + +(module + (func $imported-throw (import "test" "throw")) + (tag $e0) + + (func (export "imported-mismatch") (result i32) + (block $h + (try_table (result i32) (catch_all $h) + (block $h0 + (try_table (result i32) (catch $e0 $h0) + (i32.const 1) + (call $imported-throw) + ) + (return) + ) + (i32.const 2) + ) + (return) + ) + (i32.const 3) + ) +) + +(assert_return (invoke "imported-mismatch") (i32.const 3)) + +(assert_malformed + (module quote "(module (func (catch_all)))") + "unexpected token" +) + +(assert_malformed + (module quote "(module (tag $e) (func (catch $e)))") + "unexpected token" +) + +(module + (tag $e) + (func (try_table (catch $e 0) (catch $e 0))) + (func (try_table (catch_all 0) (catch $e 0))) + (func (try_table (catch_all 0) (catch_all 0))) + (func (result exnref) (try_table (catch_ref $e 0) (catch_ref $e 0)) (unreachable)) + (func (result exnref) (try_table (catch_all_ref 0) (catch_ref $e 0)) (unreachable)) + (func (result exnref) (try_table (catch_all_ref 0) (catch_all_ref 0)) (unreachable)) +) + +(assert_invalid + (module (func (result i32) (try_table (result i32)))) + "type mismatch" +) +(assert_invalid + (module (func (result i32) (try_table (result i32) (i64.const 42)))) + "type mismatch" +) + +(assert_invalid + (module (tag) (func (try_table (catch_ref 0 0)))) + "type mismatch" +) +(assert_invalid + (module (tag) (func (result exnref) (try_table (catch 0 0)) (unreachable))) + "type mismatch" +) +(assert_invalid + (module (func (try_table (catch_all_ref 0)))) + "type mismatch" +) +(assert_invalid + (module (func (result exnref) (try_table (catch_all 0)) (unreachable))) + "type mismatch" +) +(assert_invalid + (module + (tag (param i64)) + (func (result i32 exnref) (try_table (result i32) (catch_ref 0 0) (i32.const 42))) + ) + "type mismatch" +) diff --git a/test/core/rethrow.wast b/test/legacy/exceptions/rethrow.wast similarity index 100% rename from test/core/rethrow.wast rename to test/legacy/exceptions/rethrow.wast diff --git a/test/legacy/exceptions/throw.wast b/test/legacy/exceptions/throw.wast new file mode 100644 index 00000000..d53b5b55 --- /dev/null +++ b/test/legacy/exceptions/throw.wast @@ -0,0 +1,51 @@ +;; Test throw instruction. + +(module + (tag $e0) + (tag $e-i32 (param i32)) + (tag $e-f32 (param f32)) + (tag $e-i64 (param i64)) + (tag $e-f64 (param f64)) + (tag $e-i32-i32 (param i32 i32)) + + (func $throw-if (export "throw-if") (param i32) (result i32) + (local.get 0) + (i32.const 0) (if (i32.ne) (then (throw $e0))) + (i32.const 0) + ) + + (func (export "throw-param-f32") (param f32) (local.get 0) (throw $e-f32)) + + (func (export "throw-param-i64") (param i64) (local.get 0) (throw $e-i64)) + + (func (export "throw-param-f64") (param f64) (local.get 0) (throw $e-f64)) + + (func $throw-1-2 (i32.const 1) (i32.const 2) (throw $e-i32-i32)) + (func (export "test-throw-1-2") + (try + (do (call $throw-1-2)) + (catch $e-i32-i32 + (i32.const 2) + (if (i32.ne) (then (unreachable))) + (i32.const 1) + (if (i32.ne) (then (unreachable))) + ) + ) + ) +) + +(assert_return (invoke "throw-if" (i32.const 0)) (i32.const 0)) +(assert_exception (invoke "throw-if" (i32.const 10))) +(assert_exception (invoke "throw-if" (i32.const -1))) + +(assert_exception (invoke "throw-param-f32" (f32.const 5.0))) +(assert_exception (invoke "throw-param-i64" (i64.const 5))) +(assert_exception (invoke "throw-param-f64" (f64.const 5.0))) + +(assert_return (invoke "test-throw-1-2")) + +(assert_invalid (module (func (throw 0))) "unknown tag 0") +(assert_invalid (module (tag (param i32)) (func (throw 0))) + "type mismatch: instruction requires [i32] but stack has []") +(assert_invalid (module (tag (param i32)) (func (i64.const 5) (throw 0))) + "type mismatch: instruction requires [i32] but stack has [i64]") diff --git a/test/core/try_catch.wast b/test/legacy/exceptions/try_catch.wast similarity index 100% rename from test/core/try_catch.wast rename to test/legacy/exceptions/try_catch.wast diff --git a/test/core/try_delegate.wast b/test/legacy/exceptions/try_delegate.wast similarity index 100% rename from test/core/try_delegate.wast rename to test/legacy/exceptions/try_delegate.wast diff --git a/test/legacy/run.py b/test/legacy/run.py new file mode 100755 index 00000000..f727aeef --- /dev/null +++ b/test/legacy/run.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python3 + +from __future__ import print_function +import argparse +import os +import os.path +import unittest +import subprocess +import glob +import sys + + +ownDir = os.path.dirname(os.path.abspath(sys.argv[0])) +inputDir = ownDir +outputDir = os.path.join(inputDir, "_output") + +parser = argparse.ArgumentParser() +parser.add_argument("--wasm", metavar="", default=os.path.join(os.getcwd(), "wasm")) +parser.add_argument("--js", metavar="") +parser.add_argument("--generate-js-only", action='store_true') +parser.add_argument("--out", metavar="", default=outputDir) +parser.add_argument("file", nargs='*') +arguments = parser.parse_args() +sys.argv = sys.argv[:1] + +exceptions_test_files = glob.glob(os.path.join(inputDir, "exceptions", "*.wast")) + +wasmCommand = arguments.wasm +jsCommand = arguments.js +generateJsOnly = arguments.generate_js_only +outputDir = arguments.out +inputFiles = arguments.file if arguments.file else exceptions_test_files + +if not os.path.exists(wasmCommand): + sys.stderr.write("""\ +Error: The executable '%s' does not exist. +Provide the correct path with the '--wasm' flag. + +""" % (wasmCommand)) + parser.print_help() + sys.exit(1) + + +class RunTests(unittest.TestCase): + def _runCommand(self, command, logPath, expectedExitCode = 0): + with open(logPath, 'w+') as out: + exitCode = subprocess.call(command, shell=True, stdout=out, stderr=subprocess.STDOUT) + self.assertEqual(expectedExitCode, exitCode, "failed with exit code %i (expected %i) for %s" % (exitCode, expectedExitCode, command)) + + def _auxFile(self, path): + if os.path.exists(path): + os.remove(path) + return path + + def _compareFile(self, expectFile, actualFile): + if os.path.exists(expectFile): + with open(expectFile) as expect: + with open(actualFile) as actual: + expectText = expect.read() + actualText = actual.read() + self.assertEqual(expectText, actualText) + + def _runTestFile(self, inputPath): + dir, inputFile = os.path.split(inputPath) + outputPath = os.path.join(outputDir, inputFile) + + # Generate JS first, then return early if we are only generating JS. + jsPath = self._auxFile(outputPath.replace(".wast", ".js")) + logPath = self._auxFile(jsPath + ".log") + self._runCommand(('%s -d "%s" -o "%s"') % (wasmCommand, inputPath, jsPath), logPath) + + if generateJsOnly: + return + + # Run original file + expectedExitCode = 1 if ".fail." in inputFile else 0 + logPath = self._auxFile(outputPath + ".log") + self._runCommand(('%s "%s"') % (wasmCommand, inputPath), logPath, expectedExitCode) + + if expectedExitCode != 0: + return + + # Convert to binary and run again + wasmPath = self._auxFile(outputPath + ".bin.wast") + logPath = self._auxFile(wasmPath + ".log") + self._runCommand(('%s -d "%s" -o "%s"') % (wasmCommand, inputPath, wasmPath), logPath) + self._runCommand(('%s "%s"') % (wasmCommand, wasmPath), logPath) + + # Convert back to text and run again + wastPath = self._auxFile(wasmPath + ".wast") + logPath = self._auxFile(wastPath + ".log") + self._runCommand(('%s -d "%s" -o "%s"') % (wasmCommand, wasmPath, wastPath), logPath) + self._runCommand(('%s "%s"') % (wasmCommand, wastPath), logPath) + + # Convert back to binary once more and compare + wasm2Path = self._auxFile(wastPath + ".bin.wast") + logPath = self._auxFile(wasm2Path + ".log") + self._runCommand(('%s -d "%s" -o "%s"') % (wasmCommand, wastPath, wasm2Path), logPath) + self._compareFile(wasmPath, wasm2Path) + + # Convert back to text once more and compare + wast2Path = self._auxFile(wasm2Path + ".wast") + logPath = self._auxFile(wast2Path + ".log") + self._runCommand(('%s -d "%s" -o "%s"') % (wasmCommand, wasm2Path, wast2Path), logPath) + self._compareFile(wastPath, wast2Path) + + if jsCommand != None: + self._runCommand(('%s "%s"') % (jsCommand, jsPath), logPath) + + +if __name__ == "__main__": + if not os.path.exists(outputDir): + os.makedirs(outputDir) + for fileName in inputFiles: + testName = 'test ' + os.path.basename(fileName) + setattr(RunTests, testName, lambda self, file=fileName: self._runTestFile(file)) + unittest.main() From 96842a89948c12292f7585826a15f4d2fd4a4c86 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Fri, 10 Nov 2023 08:30:48 +0100 Subject: [PATCH 088/132] Fix CI to build legacy exn spec --- .github/workflows/ci-spec.yml | 24 ++++++++++++++++++++++++ document/index.html | 1 + document/legacy/exceptions/Makefile | 2 +- document/legacy/exceptions/conf.py | 8 ++++---- document/legacy/exceptions/index.rst | 2 -- 5 files changed, 30 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci-spec.yml b/.github/workflows/ci-spec.yml index 354dfbd4..c212b29f 100644 --- a/.github/workflows/ci-spec.yml +++ b/.github/workflows/ci-spec.yml @@ -41,6 +41,25 @@ 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/core/_build/html + build-js-api-spec: runs-on: ubuntu-latest steps: @@ -84,6 +103,11 @@ 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/core - name: Download JS API spec artifact uses: actions/download-artifact@v2 with: diff --git a/document/index.html b/document/index.html index 79a2a0cf..848776fd 100644 --- a/document/index.html +++ b/document/index.html @@ -70,6 +70,7 @@

Legacy Extensions

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

  • diff --git a/document/legacy/exceptions/Makefile b/document/legacy/exceptions/Makefile index 56b9560a..eb2611ac 100644 --- a/document/legacy/exceptions/Makefile +++ b/document/legacy/exceptions/Makefile @@ -8,7 +8,7 @@ PAPER = a4 BUILDDIR = _build STATICDIR = _static DOWNLOADDIR = _download -NAME = WebAssembly +NAME = WebAssembly-Legacy-Exceptions # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 diff --git a/document/legacy/exceptions/conf.py b/document/legacy/exceptions/conf.py index ebd159bd..bec9b1c5 100644 --- a/document/legacy/exceptions/conf.py +++ b/document/legacy/exceptions/conf.py @@ -57,8 +57,8 @@ master_doc = 'index' # General information about the project. -name = 'WebAssembly' -project = u'WebAssembly' +name = 'WebAssembly-Legacy-Exceptions' +project = u'WebAssembly-Legacy-Exceptions' title = u'WebAssembly Specification Addendum: Legacy Exception Handling' copyright = u'2023, WebAssembly Community Group' author = u'WebAssembly Community Group' @@ -76,7 +76,7 @@ # built documents. # # The short X.Y version. -version = u'0.1' +version = u'1.0' # The full version, including alpha/beta/rc tags. release = version @@ -174,7 +174,7 @@ # The name for this set of Sphinx documents. # " v documentation" by default. # -html_title = project + u' ' + release +html_title = u'WebAssembly Legacy Exceptions' # A shorter title for the navigation bar. Default is the same as html_title. # diff --git a/document/legacy/exceptions/index.rst b/document/legacy/exceptions/index.rst index b6428fb7..22b03d28 100644 --- a/document/legacy/exceptions/index.rst +++ b/document/legacy/exceptions/index.rst @@ -3,8 +3,6 @@ WebAssembly Specification Addendum: Legacy Exception Handling .. only:: html - | Release |release| - | Editor: Andreas Rossberg | Latest Draft: |WasmDraft| From c4403aee0f8aa961f00b88365098c917c927ed89 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Fri, 10 Nov 2023 08:35:42 +0100 Subject: [PATCH 089/132] Fix CI dependencies --- .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 c212b29f..d49022b0 100644 --- a/.github/workflows/ci-spec.yml +++ b/.github/workflows/ci-spec.yml @@ -92,7 +92,7 @@ jobs: publish-spec: runs-on: ubuntu-latest - needs: [build-core-spec, build-js-api-spec, build-web-api-spec] + needs: [build-core-spec, build-legacy-exceptions-spec, build-js-api-spec, build-web-api-spec] steps: - name: Checkout repo uses: actions/checkout@v2 From 81621ded31c29a817a915b9764ef030930551246 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Fri, 10 Nov 2023 08:53:59 +0100 Subject: [PATCH 090/132] Fix CI paths --- .github/workflows/ci-spec.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-spec.yml b/.github/workflows/ci-spec.yml index d49022b0..08b093cc 100644 --- a/.github/workflows/ci-spec.yml +++ b/.github/workflows/ci-spec.yml @@ -58,7 +58,7 @@ jobs: uses: actions/upload-artifact@v2 with: name: legacy-exceptions-rendered - path: document/core/_build/html + path: document/legacy/exceptions/_build/html build-js-api-spec: runs-on: ubuntu-latest @@ -107,7 +107,7 @@ jobs: uses: actions/download-artifact@v2 with: name: legacy-exceptions-rendered - path: _output/core + path: _output/legacy/exceptions - name: Download JS API spec artifact uses: actions/download-artifact@v2 with: From 8702bf43f3e8ab2b1c2f65636d6ba81c9ff44514 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Fri, 10 Nov 2023 09:03:37 +0100 Subject: [PATCH 091/132] Fix link --- document/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/document/index.html b/document/index.html index 848776fd..a5766fac 100644 --- a/document/index.html +++ b/document/index.html @@ -70,7 +70,7 @@

    Legacy Extensions

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

  • From d4d10c45212e56c3a22a7e4577de798692caea49 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Fri, 10 Nov 2023 09:20:38 +0100 Subject: [PATCH 092/132] Remove pointless version and index --- document/legacy/exceptions/appendix/index-instructions.py | 1 - document/legacy/exceptions/binary.rst | 1 - document/legacy/exceptions/conf.py | 5 ++--- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/document/legacy/exceptions/appendix/index-instructions.py b/document/legacy/exceptions/appendix/index-instructions.py index ea315469..d839a299 100755 --- a/document/legacy/exceptions/appendix/index-instructions.py +++ b/document/legacy/exceptions/appendix/index-instructions.py @@ -19,7 +19,6 @@ Appendix ======== -.. index:: instruction .. _index-instr: Index of Instructions diff --git a/document/legacy/exceptions/binary.rst b/document/legacy/exceptions/binary.rst index 68ea09df..f605c566 100644 --- a/document/legacy/exceptions/binary.rst +++ b/document/legacy/exceptions/binary.rst @@ -3,7 +3,6 @@ Binary Format ============= -.. index:: instruction .. _binary-instr: Instructions diff --git a/document/legacy/exceptions/conf.py b/document/legacy/exceptions/conf.py index bec9b1c5..5be09c13 100644 --- a/document/legacy/exceptions/conf.py +++ b/document/legacy/exceptions/conf.py @@ -76,7 +76,7 @@ # built documents. # # The short X.Y version. -version = u'1.0' +version = '' # The full version, including alpha/beta/rc tags. release = version @@ -153,7 +153,6 @@ 'sidebar_collapse': True, 'show_powered_by': False, 'extra_nav_links': { - 'Index': 'BASEDIR/genindex.html', 'Download as PDF': 'BASEDIR/_download/' + name + '.pdf' }, } @@ -224,7 +223,7 @@ # If false, no index is generated. # -html_use_index = True +html_use_index = False # If true, the index is split into individual pages for each letter. # From 7d69731db63fa40fc8b44739892347ae776750ab Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Fri, 10 Nov 2023 10:04:19 +0100 Subject: [PATCH 093/132] Tweak layout --- .../exceptions/appendix/index-instructions.py | 5 ----- document/legacy/exceptions/binary.rst | 10 ++++++---- document/legacy/exceptions/conf.py | 5 ++++- document/legacy/exceptions/exec.rst | 3 +-- document/legacy/exceptions/text.rst | 13 +++++++------ document/legacy/exceptions/valid.rst | 1 - 6 files changed, 18 insertions(+), 19 deletions(-) diff --git a/document/legacy/exceptions/appendix/index-instructions.py b/document/legacy/exceptions/appendix/index-instructions.py index d839a299..bc7f7ff4 100755 --- a/document/legacy/exceptions/appendix/index-instructions.py +++ b/document/legacy/exceptions/appendix/index-instructions.py @@ -26,11 +26,6 @@ """ FOOTER = """\ - -.. note:: - Multi-byte opcodes are given with the shortest possible encoding in the table. - However, what is following the first byte is actually a :ref:`u32 ` with variable-length encoding - and consequently has multiple possible representations.\ """ COLUMNS = [ diff --git a/document/legacy/exceptions/binary.rst b/document/legacy/exceptions/binary.rst index f605c566..f5c95be2 100644 --- a/document/legacy/exceptions/binary.rst +++ b/document/legacy/exceptions/binary.rst @@ -17,14 +17,16 @@ Control Instructions .. _binary-rethrow: .. math:: - \begin{array}{llcllll} + \begin{array}{@{}llcllll} \production{instruction} & \Binstr &::=& \dots \\ &&|& - \hex{06}~~\X{bt}{:}\Bblocktype~~(\X{in}_1{:}\Binstr)^\ast~~ - (\hex{07}~~x{:}\Btagidx~~(\X{in}_2{:}\Binstr)^\ast)^\ast~~ + \hex{06}~~\X{bt}{:}\Bblocktype~~ + (\X{in}_1{:}\Binstr)^\ast~~ \\&&& + (\hex{07}~~x{:}\Btagidx~~(\X{in}_2{:}\Binstr)^\ast)^\ast~~ \\&&& (\hex{19}~~(\X{in}_3{:}\Binstr)^\ast)^?~~\hex{0B} &\Rightarrow& \TRY~\X{bt}~\X{in}_1^\ast~(\CATCH~x~\X{in}_2^\ast)^\ast~ (\CATCHALL~\X{in}_3^\ast)^?\END \\ &&|& - \hex{06}~~\X{bt}{:}\Bblocktype~~(\X{in}{:}\Binstr)^\ast~~\hex{18}~~l{:}\Blabelidx + \hex{06}~~\X{bt}{:}\Bblocktype~~(\X{in}{:}\Binstr)^\ast~~ \\&&& + \hex{18}~~l{:}\Blabelidx &\Rightarrow& \TRY~\X{bt}~\X{in}^\ast~\DELEGATE~l \\ &&|& \hex{09}~~l{:}\Blabelidx &\Rightarrow& \RETHROW~l \\ \end{array} diff --git a/document/legacy/exceptions/conf.py b/document/legacy/exceptions/conf.py index 5be09c13..e774aafe 100644 --- a/document/legacy/exceptions/conf.py +++ b/document/legacy/exceptions/conf.py @@ -301,6 +301,9 @@ # 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 @@ -311,7 +314,7 @@ name + '.tex', title, author + '\\\\ \\hfill\\large ' + editor, - 'manual' + 'howto' ), ] diff --git a/document/legacy/exceptions/exec.rst b/document/legacy/exceptions/exec.rst index a935eaca..e2c9b239 100644 --- a/document/legacy/exceptions/exec.rst +++ b/document/legacy/exceptions/exec.rst @@ -16,8 +16,7 @@ Stack .. _syntax-handler: -Exception Handlers -.................. +**Exception Handlers** Legacy exception handlers are installed by |TRY| instructions. Instead of branch labels, their catch clauses have instruction blocks associated with them. diff --git a/document/legacy/exceptions/text.rst b/document/legacy/exceptions/text.rst index 0bf0a30d..1968c112 100644 --- a/document/legacy/exceptions/text.rst +++ b/document/legacy/exceptions/text.rst @@ -21,15 +21,16 @@ The label identifier on a structured control instruction may optionally be repea pseudo instructions, to indicate the matching delimiters. .. math:: - \begin{array}{llclll} + \begin{array}{@{}llclll} \production{block instruction} & \Tblockinstr_I &::=& \dots \\ &&|& - \text{try}~~I'{:}\Tlabel_I~~\X{bt}{:}\Tblocktype~~(\X{in}_1{:}\Tinstr_{I'})^\ast~~ - (\text{catch}~~\Tid_1^?~~x{:}\Ttagidx_I~~(\X{in}_2{:}\Tinstr_{I'})^\ast)^\ast~~ - \\ &&&\qquad\qquad (\text{catch\_all}~~\Tid_1^?~~(\X{in}_3{:}\Tinstr_{I'})^\ast)^?~~\text{end}~~\Tid_2^? + \text{try}~~I'{:}\Tlabel_I~~\X{bt}{:}\Tblocktype~~(\X{in}_1{:}\Tinstr_{I'})^\ast~~\\&&& + (\text{catch}~~\Tid_1^?~~x{:}\Ttagidx_I~~(\X{in}_2{:}\Tinstr_{I'})^\ast)^\ast~~ \\&&& + (\text{catch\_all}~~\Tid_1^?~~(\X{in}_3{:}\Tinstr_{I'})^\ast)^?~~ \\&&& + \text{end}~~\Tid_2^? \\ &&&\qquad \Rightarrow\quad \TRY~\X{bt}~\X{in}_1^\ast~(\CATCH~x~\X{in}_2^\ast)^\ast~(\CATCHALL~\X{in}_3^\ast)^?~\END \\ &&&\qquad\qquad (\iff \Tid_1^? = \epsilon \vee \Tid_1^? = \Tlabel, \Tid_2^? = \epsilon \vee \Tid_2^? = \Tlabel) \\ &&|& - \text{try}~~I'{:}\Tlabel_I~~\X{bt}{:}\Tblocktype~~(\X{in}_1{:}\Tinstr_{I'})^\ast - ~~\text{delegate}~~l{:}\Tlabelidx_I~~\X{l}{:}\Tlabelidx_I + \text{try}~~I'{:}\Tlabel_I~~\X{bt}{:}\Tblocktype~~(\X{in}_1{:}\Tinstr_{I'})^\ast~~ \\&&& + \text{delegate}~~l{:}\Tlabelidx_I~~\X{l}{:}\Tlabelidx_I \\ &&&\qquad \Rightarrow\quad \TRY~\X{bt}~\X{in}_1^\ast~\DELEGATE~l \qquad\quad~~ (\iff \Tid^? = \epsilon \vee \Tid^? = \Tlabel) \\ \production{plain instruction} & \Tplaininstr_I &::=& \dots \\ &&|& diff --git a/document/legacy/exceptions/valid.rst b/document/legacy/exceptions/valid.rst index 80e11636..03f337d5 100644 --- a/document/legacy/exceptions/valid.rst +++ b/document/legacy/exceptions/valid.rst @@ -36,7 +36,6 @@ Existing typing rules are adjusted as follows: Instructions ------------ - .. _valid-instr-control: Control Instructions From e64d1c30dc5e6121db96888a957defd3ec8fff87 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Fri, 10 Nov 2023 10:09:41 +0100 Subject: [PATCH 094/132] Spacing --- document/legacy/exceptions/exec.rst | 2 +- document/legacy/exceptions/valid.rst | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/document/legacy/exceptions/exec.rst b/document/legacy/exceptions/exec.rst index e2c9b239..15d30b1b 100644 --- a/document/legacy/exceptions/exec.rst +++ b/document/legacy/exceptions/exec.rst @@ -126,7 +126,7 @@ Control Instructions \begin{array}{l} F; \val^m~(\TRY~\X{bt}~\instr_1^\ast~(\CATCH~x~\instr_2^\ast)^\ast~(\CATCHALL~\instr_3^\ast)^?~\END \quad \stepto \\ - \qquad F; \LABEL_n\{\epsilon\}~(\HANDLER_n\{(\CATCH~a_x~\instr_2^\ast)^\ast~(\CATCHALL~\instr_3^\ast)^?\}~\val^m~\instr_1^\ast~\END)~\END \\ + \qquad F; \LABEL_n\{\epsilon\}~(\HANDLER_n\{(\CATCH~a_x~\instr_2^\ast)^\ast~(\CATCHALL~\instr_3^\ast)^?\}~\val^m~\instr_1^\ast~\END)~\END \\ \qquad (\iff \expand_F(\X{bt}) = [t_1^m] \to [t_2^n] \land (F.\AMODULE.\MITAGS[x]=a_x)^\ast) \end{array} diff --git a/document/legacy/exceptions/valid.rst b/document/legacy/exceptions/valid.rst index 03f337d5..8a13ee93 100644 --- a/document/legacy/exceptions/valid.rst +++ b/document/legacy/exceptions/valid.rst @@ -27,7 +27,7 @@ Existing typing rules are adjusted as follows: * All rules that extend the context with new labels use an absent |LCATCH| flag. -* All rules that inspect the context for a label ignore the presence of an |LCATCH| flag. +* All rules that inspect the context for a label ignore the presence of a |LCATCH| flag. .. note:: This flag is used to distinguish labels bound by catch clauses, which can be targeted by |RETHROW|. @@ -74,6 +74,7 @@ Control Instructions * Then the compound instruction is valid with type :math:`[t_1^\ast] \to [t_2^\ast]`. .. math:: + ~\\ \frac{ \begin{array}{c} C \vdashblocktype \blocktype : [t_1^\ast] \to [t_2^\ast] @@ -89,7 +90,7 @@ Control Instructions .. note:: - The :ref:`notation ` :math:`C,\CLABELS\,(\LCATCH^?~[t^\ast])` inserts the new label type at index :math:`0`, shifting all others. + The :ref:`notation ` :math:`C,\CLABELS\,(\LCATCH~[t^\ast])` inserts the new label type at index :math:`0`, shifting all others. .. _valid-try-delegate: @@ -109,6 +110,7 @@ Control Instructions * Then the compound instruction is valid with type :math:`[t_1^\ast] \to [t_2^\ast]`. .. math:: + ~\\ \frac{ C \vdashblocktype \blocktype : [t_1^\ast] \to [t_2^\ast] \qquad @@ -138,6 +140,7 @@ Control Instructions .. math:: + ~\\ \frac{ C.\CLABELS[l] = \LCATCH~[t^\ast] }{ From 98e4eb60dea8136286fb639bde70cc5f1ae456d6 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Fri, 10 Nov 2023 15:34:52 +0100 Subject: [PATCH 095/132] Tweaks to Addendum --- document/legacy/exceptions/appendix/index-instructions.py | 6 +----- document/legacy/exceptions/conf.py | 2 +- document/legacy/exceptions/index.rst | 5 ++--- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/document/legacy/exceptions/appendix/index-instructions.py b/document/legacy/exceptions/appendix/index-instructions.py index bc7f7ff4..2c8d3407 100755 --- a/document/legacy/exceptions/appendix/index-instructions.py +++ b/document/legacy/exceptions/appendix/index-instructions.py @@ -15,14 +15,10 @@ .. DO NOT EDIT: This file is auto-generated by the index-instructions.py script. .. _appendix: - -Appendix -======== - .. _index-instr: Index of Instructions ---------------------- +===================== """ FOOTER = """\ diff --git a/document/legacy/exceptions/conf.py b/document/legacy/exceptions/conf.py index e774aafe..39b20491 100644 --- a/document/legacy/exceptions/conf.py +++ b/document/legacy/exceptions/conf.py @@ -59,7 +59,7 @@ # General information about the project. name = 'WebAssembly-Legacy-Exceptions' project = u'WebAssembly-Legacy-Exceptions' -title = u'WebAssembly Specification Addendum: Legacy Exception Handling' +title = u'WebAssembly Spec Addendum: Legacy Exception Handling' copyright = u'2023, WebAssembly Community Group' author = u'WebAssembly Community Group' editor = u'Andreas Rossberg (editor)' diff --git a/document/legacy/exceptions/index.rst b/document/legacy/exceptions/index.rst index 22b03d28..a83254bb 100644 --- a/document/legacy/exceptions/index.rst +++ b/document/legacy/exceptions/index.rst @@ -1,11 +1,10 @@ -WebAssembly Specification Addendum: Legacy Exception Handling -============================================================= +WebAssembly Addendum: Legacy Exception Handling +=============================================== .. only:: html | Editor: Andreas Rossberg - | Latest Draft: |WasmDraft| | Issue Tracker: |WasmIssues| .. toctree:: From 84663dc3c2d3e04ecf89ba7c018010ff745c10ab Mon Sep 17 00:00:00 2001 From: YAMAMOTO Takashi Date: Thu, 25 Jan 2024 15:04:17 +0900 Subject: [PATCH 096/132] Fix catch_all_ref opcode in the overview (#291) --- 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 76661c3f..08c484a6 100644 --- a/proposals/exception-handling/Exceptions.md +++ b/proposals/exception-handling/Exceptions.md @@ -451,4 +451,4 @@ A `catch` handler is a pair of tag and label index: | `catch` | `0x00` | tag : `varuint32`, label : `varuint32` | | `catch_ref` | `0x01` | tag : `varuint32`, label : `varuint32` | | `catch_all` | `0x02` | label : `varuint32` | -| `catch_all_ref` | `0x02` | label : `varuint32` | +| `catch_all_ref` | `0x03` | label : `varuint32` | From 7a97c6b4c0d99e6a0dba45e5cc9224c1cf88d61b Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Thu, 25 Jan 2024 23:50:57 +0100 Subject: [PATCH 097/132] [spec] Update algorithm (#290) --- document/core/appendix/algorithm.rst | 34 +++++++++++++++------------ document/core/syntax/instructions.rst | 6 ++--- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/document/core/appendix/algorithm.rst b/document/core/appendix/algorithm.rst index 4aa26672..6b6985e8 100644 --- a/document/core/appendix/algorithm.rst +++ b/document/core/appendix/algorithm.rst @@ -25,7 +25,7 @@ Types are representable as an enumeration. .. code-block:: pseudo - type val_type = I32 | I64 | F32 | F64 | V128 | Funcref | Externref + type val_type = I32 | I64 | F32 | F64 | V128 | Funcref | Exnref | Externref func is_num(t : val_type | Unknown) : bool = return t = I32 || t = I64 || t = F32 || t = F64 || t = Unknown @@ -34,7 +34,7 @@ Types are representable as an enumeration. return t = V128 || t = Unknown func is_ref(t : val_type | Unknown) : bool = - return t = Funcref || t = Externref || t = Unknown + return t = Funcref || t = Exnref || t = Externref || t = Unknown The algorithm uses two separate stacks: the *value stack* and the *control stack*. The former tracks the :ref:`types ` of operand values on the :ref:`stack `, @@ -212,22 +212,26 @@ Other instructions are checked in a similar manner. error_if(frame.opcode =/= if) push_ctrl(else, frame.start_types, frame.end_types) - case (try t1*->t2*) + case (try_table t1*->t2* handler*) pop_vals([t1*]) - push_ctrl(try, [t1*], [t2*]) - - case (catch x) - let frame = pop_ctrl() - error_if(frame.opcode =/= try || frame.opcode =/= catch) - push_ctrl(catch, tags[x].type.params, frame.end_types) - - case (catch_all) - let frame = pop_ctrl() - error_if(frame.opcode =/= try || frame.opcode =/= catch) - push_ctrl(catch_all, [], frame.end_types) + foreach (handler in handler*) + error_if(ctrls.size() < handler.label) + push_ctrl(catch, [], label_types(ctrls[handler.label])) + switch (handler.clause) + case (catch x) + push_vals(tags[x].type.params) + case (catch_ref x) + push_vals(tags[x].type.params) + push_val(Exnref) + case (catch_all) + skip + case (catch_all_ref) + push_val(Exnref) + pop_ctrl() + push_ctrl(try_table, [t1*], [t2*]) case (throw x) - pop.vals(tags[x].type.params) + pop_vals(tags[x].type.params) unreachable() case (br n) diff --git a/document/core/syntax/instructions.rst b/document/core/syntax/instructions.rst index fa835ebf..2d58b6e2 100644 --- a/document/core/syntax/instructions.rst +++ b/document/core/syntax/instructions.rst @@ -621,11 +621,9 @@ The |DATADROP| instruction prevents further use of a passive data segment. This .. _syntax-block: .. _syntax-loop: .. _syntax-if: -.. _syntax-try: -.. _syntax-try-catch: -.. _syntax-try-delegate: +.. _syntax-try_table: .. _syntax-throw: -.. _syntax-rethrow: +.. _syntax-throw_ref: .. _syntax-br: .. _syntax-br_if: .. _syntax-br_table: From 38f1611e41954a643092381c750cfa36869ea94b Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Sun, 28 Jan 2024 11:25:27 +0100 Subject: [PATCH 098/132] Fix Latex --- document/core/appendix/index-instructions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/document/core/appendix/index-instructions.py b/document/core/appendix/index-instructions.py index e3a55f53..75b9430c 100755 --- a/document/core/appendix/index-instructions.py +++ b/document/core/appendix/index-instructions.py @@ -89,7 +89,7 @@ def Instruction(name, opcode, type=None, validation=None, execution=None, operat Instruction(None, r'\hex{07}'), Instruction(r'\THROW~x', r'\hex{08}', r'[t_1^\ast~t_x^\ast] \to [t_2^\ast]', r'valid-throw', r'exec-throw'), Instruction(None, r'\hex{09}'), - Instruction(r'\THROWREF', r'\hex{0A}', r'[t_1^\ast~(\REF~\NULL~\EXN)] \to [t_2^\ast]', r'valid-throw_ref', r'exec-throw_ref'), + Instruction(r'\THROWREF', r'\hex{0A}', r'[t_1^\ast~\EXNREF] \to [t_2^\ast]', r'valid-throw_ref', r'exec-throw_ref'), Instruction(r'\END', r'\hex{0B}'), Instruction(r'\BR~l', r'\hex{0C}', r'[t_1^\ast~t^\ast] \to [t_2^\ast]', r'valid-br', r'exec-br'), Instruction(r'\BRIF~l', r'\hex{0D}', r'[t^\ast~\I32] \to [t^\ast]', r'valid-br_if', r'exec-br_if'), From cecb8d6f4b461bcbf763ee0e63e961023f657cd9 Mon Sep 17 00:00:00 2001 From: YAMAMOTO Takashi Date: Mon, 29 Jan 2024 19:35:19 +0900 Subject: [PATCH 099/132] Add implementation limits for tags and exceptions (#293) --- document/core/appendix/implementation.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/document/core/appendix/implementation.rst b/document/core/appendix/implementation.rst index 4ffbe0e7..d9658165 100644 --- a/document/core/appendix/implementation.rst +++ b/document/core/appendix/implementation.rst @@ -46,6 +46,7 @@ An implementation may impose restrictions on the following dimensions of a modul * the number of results in a :ref:`function type ` * the number of parameters in a :ref:`block type ` * the number of results in a :ref:`block type ` +* the number of parameters in a :ref:`tag type ` * the number of :ref:`locals ` in a :ref:`function ` * the size of a :ref:`function ` body * the size of a :ref:`structured control instruction ` @@ -126,6 +127,7 @@ Restrictions on the following dimensions may be imposed during :ref:`execution < * the number of allocated :ref:`memory instances ` * the number of allocated :ref:`tag instances ` * the number of allocated :ref:`global instances ` +* the number of allocated :ref:`exception instances ` * the size of a :ref:`table instance ` * the size of a :ref:`memory instance ` * the number of :ref:`frames ` on the :ref:`stack ` From 25632dd92d125b4f88b1cad4a63110787e46b0b2 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Wed, 21 Feb 2024 09:51:34 +0100 Subject: [PATCH 100/132] Add noexn type to overview (#298) --- proposals/exception-handling/Exceptions.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/proposals/exception-handling/Exceptions.md b/proposals/exception-handling/Exceptions.md index 08c484a6..9a2ddfb8 100644 --- a/proposals/exception-handling/Exceptions.md +++ b/proposals/exception-handling/Exceptions.md @@ -331,6 +331,18 @@ 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. + +The heap type `noexn` is a subtype of `exn`. +They are not in a subtype relation with any other type (except bottom), +such that they form a new disjoint hierarchy of heap types. + + ##### tag_type We reserve a bit to denote the exception attribute: From 3dbe24e37c938acdaaac7c67eae2ceea3dca513b Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Fri, 15 Mar 2024 17:24:37 -0700 Subject: [PATCH 101/132] 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 5d19010c..175dc07c 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 102/132] 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 380794fe..173f60a2 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 175dc07c..5d1b766b 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 a43f55e9..2a52bc96 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 f2e71072..ed0da332 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 c97651fb6fe4bebab70581bcbe6a6bddb8f067cf Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Thu, 11 Apr 2024 11:17:41 -0700 Subject: [PATCH 103/132] 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 1519c049..ba25a4cc 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 104/132] 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 ba25a4cc..d3464d92 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 e0de08969c3fa9a7e44e2ac53fb71050b217d603 Mon Sep 17 00:00:00 2001
    From: Heejin Ahn 
    Date: Thu, 23 May 2024 13:44:06 -0700
    Subject: [PATCH 105/132] 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 9a2ddfb8..bc508eff 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 00000000..74270f88
    --- /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 a5ca40df..c48fa64e 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 7372ef02..08a1a5e0 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 8c9ce8ed..32400e9a 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 233f2852..4ab9eb5f 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 106/132] 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 08b093cc..fecb9365 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 629d5f51..1a9625c1 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 00000000..84ba5d3a
    --- /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 00000000..e7db1407
    --- /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 107/132] 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 2a0e9ff6..07399f3a 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 aae3a301..39ee09a2 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 108/132] 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 a5766fac..b23262bd 100644 --- a/document/index.html +++ b/document/index.html @@ -69,8 +69,17 @@

    Legacy Extensions

    From 87ae341cae5d09f4a46f8d25257396ccbf716ce7 Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Mon, 10 Jun 2024 18:24:11 -0400 Subject: [PATCH 109/132] [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 f727aeef..b2f6c314 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 110/132] 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 d3464d92..6f96f240 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 111/132] [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 7ad08e18..a46d1816 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 4b72c61f..6d56ac8c 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 e28a88a3..840d00bf 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 00e801a6..6885cf0d 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 ac468947..7936810a 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 40a3935a..0d62725a 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 de63e7bf..54edf8c8 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 ad9a4ba1..76fff0fe 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 9d2f0de1..58c96078 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 d0f9e78b..58b616f0 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 acf644f9..9b82d2ea 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 e431197d..0cdb41d2 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 112/132] 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 bc508eff..37cb994c 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 113/132] 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 37cb994c..d982592c 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 114/132] [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 58b616f0..b23cea5f 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 9b82d2ea..c57c79cc 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 0cdb41d2..36651c7d 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 115/132] [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 00000000..c57c79cc --- /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 00000000..36651c7d --- /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 cfb909da069ae6904406fc1c799d60cafc9ea184 Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Thu, 27 Jun 2024 17:37:46 -0700 Subject: [PATCH 116/132] 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 6f96f240..0bf129e6 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 583775527f151276b60876aab99162da14226283 Mon Sep 17 00:00:00 2001 From: YAMAMOTO Takashi Date: Thu, 4 Jul 2024 16:24:35 +0900 Subject: [PATCH 117/132] [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 13f82a9d..17baad84 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 e64b6c18..43ae52cc 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 118/132] [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 c57c79cc..09f8479a 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 36651c7d..802e7053 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 c57c79cc..81478529 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 119/132] [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 00000000..c5db5537 --- /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 24be4255901e9db4c9aab23b838f2bcc46d9c6e4 Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Mon, 15 Jul 2024 22:42:43 -0700 Subject: [PATCH 120/132] 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 0bf129e6..9586c48e 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 58c96078..00000000
    --- 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 7e2c27cf90b6faddc3fd83093fe88e6fca7dba0c Mon Sep 17 00:00:00 2001
    From: YAMAMOTO Takashi 
    Date: Fri, 30 Aug 2024 09:23:38 +0900
    Subject: [PATCH 121/132] add a test case (#326)
    
    some runtimes implement tag matching as the equality of tag indexes.
    (cf. https://github.com/bytecodealliance/wasm-micro-runtime/issues/3109)
    i believe it's a wrong interpreteation of the spec.
    this test case ensures a failure on such implementations.
    ---
     test/core/try_table.wast | 12 ++++++++++++
     1 file changed, 12 insertions(+)
    
    diff --git a/test/core/try_table.wast b/test/core/try_table.wast
    index 43ae52cc..e94a3b27 100644
    --- a/test/core/try_table.wast
    +++ b/test/core/try_table.wast
    @@ -9,6 +9,7 @@
     
     (module
       (tag $imported-e0 (import "test" "e0"))
    +  (tag $imported-e0-alias (import "test" "e0"))
       (func $imported-throw (import "test" "throw"))
       (tag $e0)
       (tag $e1)
    @@ -211,6 +212,16 @@
         (i32.const 2)
       )
     
    +  (func (export "catch-imported-alias") (result i32)
    +    (block $h
    +      (try_table (result i32) (catch $imported-e0 $h)
    +        (throw $imported-e0-alias (i32.const 1))
    +      )
    +      (return)
    +    )
    +    (i32.const 2)
    +  )
    +
       (func (export "catchless-try") (param i32) (result i32)
         (block $h
           (try_table (result i32) (catch $e0 $h)
    @@ -291,6 +302,7 @@
     (assert_return (invoke "catch-param-i32" (i32.const 5)) (i32.const 5))
     
     (assert_return (invoke "catch-imported") (i32.const 2))
    +(assert_return (invoke "catch-imported-alias") (i32.const 2))
     
     (assert_return (invoke "catchless-try" (i32.const 0)) (i32.const 0))
     (assert_return (invoke "catchless-try" (i32.const 1)) (i32.const 1))
    
    From 67436f2aa469c5a056397d90f90520bdee80228a Mon Sep 17 00:00:00 2001
    From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
    Date: Wed, 4 Sep 2024 11:03:03 +0200
    Subject: [PATCH 122/132] [ci] Bump upload/download-artifact to v4 (#327)
    
    ---
     .github/workflows/ci-spec.yml | 20 ++++++++++----------
     1 file changed, 10 insertions(+), 10 deletions(-)
    
    diff --git a/.github/workflows/ci-spec.yml b/.github/workflows/ci-spec.yml
    index fecb9365..e24a3cb5 100644
    --- a/.github/workflows/ci-spec.yml
    +++ b/.github/workflows/ci-spec.yml
    @@ -36,7 +36,7 @@ jobs:
           #- name: Run Bikeshed
           #  run: cd document/core && make bikeshed
           - name: Upload artifact
    -        uses: actions/upload-artifact@v2
    +        uses: actions/upload-artifact@v4
             with:
               name: core-rendered
               path: document/core/_build/html
    @@ -51,7 +51,7 @@ jobs:
           - name: Run Bikeshed
             run: bikeshed spec "document/js-api/index.bs" "document/js-api/index.html"
           - name: Upload artifact
    -        uses: actions/upload-artifact@v2
    +        uses: actions/upload-artifact@v4
             with:
               name: js-api-rendered
               path: document/js-api/index.html
    @@ -66,7 +66,7 @@ jobs:
           - name: Run Bikeshed
             run: bikeshed spec "document/web-api/index.bs" "document/web-api/index.html"
           - name: Upload artifact
    -        uses: actions/upload-artifact@v2
    +        uses: actions/upload-artifact@v4
             with:
               name: web-api-rendered
               path: document/web-api/index.html
    @@ -85,7 +85,7 @@ jobs:
           - name: Build main spec
             run: cd document/legacy/exceptions/core && make main
           - name: Upload artifact
    -        uses: actions/upload-artifact@v2
    +        uses: actions/upload-artifact@v4
             with:
               name: legacy-exceptions-core-rendered
               path: document/legacy/exceptions/core/_build/html
    @@ -100,7 +100,7 @@ jobs:
           - 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
    +        uses: actions/upload-artifact@v4
             with:
               name: legacy-exceptions-js-api-rendered
               path: document/legacy/exceptions/js-api/index.html
    @@ -114,27 +114,27 @@ jobs:
           - name: Create output directory
             run: mkdir _output && cp document/index.html _output/index.html
           - name: Download core spec artifact
    -        uses: actions/download-artifact@v2
    +        uses: actions/download-artifact@v4
             with:
               name: core-rendered
               path: _output/core
           - name: Download JS API spec artifact
    -        uses: actions/download-artifact@v2
    +        uses: actions/download-artifact@v4
             with:
               name: js-api-rendered
               path: _output/js-api
           - name: Download Web API spec artifact
    -        uses: actions/download-artifact@v2
    +        uses: actions/download-artifact@v4
             with:
               name: web-api-rendered
               path: _output/web-api
           - name: Download legacy exceptions core spec artifact
    -        uses: actions/download-artifact@v2
    +        uses: actions/download-artifact@v4
             with:
               name: legacy-exceptions-core-rendered
               path: _output/legacy/exceptions/core
           - name: Download legacy exceptions JS API spec artifact
    -        uses: actions/download-artifact@v2
    +        uses: actions/download-artifact@v4
             with:
               name: legacy-exceptions-js-api-rendered
               path: _output/legacy/exceptions/js-api
    
    From 79323b5fcc19aab5600e8072f34e3855fdad5a68 Mon Sep 17 00:00:00 2001
    From: CharlieTap 
    Date: Fri, 13 Sep 2024 07:51:35 +0100
    Subject: [PATCH 123/132] Fix order of handler entrance (#329)
    
    ---
     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 5d1b766b..520291e7 100644
    --- a/document/core/exec/instructions.rst
    +++ b/document/core/exec/instructions.rst
    @@ -3145,9 +3145,9 @@ The following auxiliary rules define the semantics of entering and exiting |TRYT
     Entering :math:`\instr^\ast` with label :math:`L` and exception handler :math:`H`
     .................................................................................
     
    -1. Push :math:`L` to the stack.
    +1. Push :math:`H` to the stack.
     
    -2. Push :math:`H` onto the stack.
    +2. Push :math:`L` onto the stack.
     
     3. Jump to the start of the instruction sequence :math:`\instr^\ast`.
     
    
    From 24f0819ff8bb238d45dac52f72b9c9e8f323a551 Mon Sep 17 00:00:00 2001
    From: CharlieTap 
    Date: Fri, 13 Sep 2024 09:12:10 +0100
    Subject: [PATCH 124/132] Fix throwref execution prose (#330)
    
    ---
     document/core/exec/instructions.rst | 46 ++++++++++++++---------------
     1 file changed, 23 insertions(+), 23 deletions(-)
    
    diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst
    index 520291e7..0fa0e86f 100644
    --- a/document/core/exec/instructions.rst
    +++ b/document/core/exec/instructions.rst
    @@ -2757,57 +2757,57 @@ Control Instructions
     :math:`\THROWREF`
     .................
     
    -1. Let :math:`F` be the :ref:`current ` :ref:`frame `.
    -
    -2. Assert: due to :ref:`validation `, a :ref:`reference ` is on the top of the stack.
    +1. Assert: due to :ref:`validation `, a :ref:`reference ` is on the top of the stack.
     
    -3. Pop the reference :math:`\reff` from the stack.
    +2. Pop the reference :math:`\reff` from the stack.
     
    -4. If :math:`\reff` is :math:`\REFNULL~\X{ht}`, then:
    +3. If :math:`\reff` is :math:`\REFNULL~\X{ht}`, then:
     
        a. Trap.
     
    -5. Assert: due to :ref:`validation `, :math:`\reff` is an :ref:`exception reference `.
    +4. Assert: due to :ref:`validation `, :math:`\reff` is an :ref:`exception reference `.
     
    -6. Let :math:`\REFEXNADDR~\X{ea}` be :math:`\reff`.
    +5. Let :math:`\REFEXNADDR~\X{ea}` be :math:`\reff`.
     
    -7. Assert: due to :ref:`validation `, :math:`S.\SEXNS[\X{ea}]` exists.
    +6. Assert: due to :ref:`validation `, :math:`S.\SEXNS[\X{ea}]` exists.
     
    -8. Let :math:`\X{exn}` be the :ref:`exception instance ` :math:`S.\SEXNS[\X{ea}]`.
    +7. Let :math:`\X{exn}` be the :ref:`exception instance ` :math:`S.\SEXNS[\X{ea}]`.
     
    -9. Let :math:`a` be the :ref:`tag address ` :math:`\X{exn}.\EITAG`.
    +8. Let :math:`a` be the :ref:`tag address ` :math:`\X{exn}.\EITAG`.
     
    -10. While the stack is not empty and the top of the stack is not an :ref:`exception handler `, do:
    +9. While the stack is not empty and the top of the stack is not an :ref:`exception handler `, do:
     
        a. Pop the top element from the stack.
     
    -11. Assert: the stack is now either empty, or there is an exception handler on the top of the stack.
    +10. Assert: the stack is now either empty, or there is an exception handler on the top of the stack.
     
    -12. If the stack is empty, then:
    +11. If the stack is empty, then:
     
        a. Return the exception :math:`(\REFEXNADDR~a)` as a :ref:`result `.
     
    -13. Assert: there is an :ref:`exception handler ` on the top of the stack.
    +12. Assert: there is an :ref:`exception handler ` on the top of the stack.
     
    -14. Pop the exception handler  :math:`\HANDLER_n\{\catch^\ast\}` from the stack.
    +13. Pop the exception handler  :math:`\HANDLER_n\{\catch^\ast\}` from the stack.
     
    -15. If :math:`\catch^\ast` is empty, then:
    +14. If :math:`\catch^\ast` is empty, then:
     
         a. Push the exception reference :math:`\REFEXNADDR~\X{ea}` back to the stack.
     
         b. Execute the instruction |THROWREF| again.
     
    -16. Else:
    +15. Else:
    +
    +    a. Let :math:`F` be the :ref:`current ` :ref:`frame `.
     
    -    a. Let :math:`\catch_1` be the first :ref:`catch clause ` in :math:`\catch^\ast` and :math:`{\catch'}^\ast` the remaining clauses.
    +    b. 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:`tag address ` :math:`a` equals :math:`F.\AMODULE.\MITAGS[x]`, then:
    +    c. If :math:`\catch_1` is of the form :math:`\CATCH~x~l` and the :ref:`tag address ` :math:`a` equals :math:`F.\AMODULE.\MITAGS[x]`, then:
     
            i. Push the values :math:`\X{exn}.\EIFIELDS` to the stack.
     
            ii. Execute the instruction :math:`\BR~l`.
     
    -    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:
    +    d. Else if :math:`\catch_1` is of the form :math:`\CATCHREF~x~l` and the :ref:`tag address ` :math:`a` equals :math:`F.\AMODULE.\MITAGS[x]`, then:
     
            i. Push the values :math:`\X{exn}.\EIFIELDS` to the stack.
     
    @@ -2815,17 +2815,17 @@ Control Instructions
     
            iii. Execute the instruction :math:`\BR~l`.
     
    -    d. Else if :math:`\catch_1` is of the form :math:`\CATCHALL~l`, then:
    +    e. Else if :math:`\catch_1` is of the form :math:`\CATCHALL~l`, then:
     
            i. Execute the instruction :math:`\BR~l`.
     
    -    e. Else if :math:`\catch_1` is of the form :math:`\CATCHALLREF~l`, then:
    +    f. Else if :math:`\catch_1` is of the form :math:`\CATCHALLREF~l`, then:
     
            i. Push the exception reference :math:`\REFEXNADDR~\X{ea}` to the stack.
     
            ii. Execute the instruction :math:`\BR~l`.
     
    -    f. Else:
    +    g. Else:
     
            1. Push the modified handler  :math:`\HANDLER_n\{{\catch'}^\ast\}` back to the stack.
     
    
    From bb0dac3e007d25cc9ef873db8f546788a7968eda Mon Sep 17 00:00:00 2001
    From: Andreas Rossberg 
    Date: Fri, 13 Sep 2024 10:24:21 +0200
    Subject: [PATCH 125/132] Fix syntax of tag imports
    
    ---
     document/core/syntax/modules.rst | 2 +-
     interpreter/binary/decode.ml     | 1 +
     2 files changed, 2 insertions(+), 1 deletion(-)
    
    diff --git a/document/core/syntax/modules.rst b/document/core/syntax/modules.rst
    index 25690168..b2d61a1c 100644
    --- a/document/core/syntax/modules.rst
    +++ b/document/core/syntax/modules.rst
    @@ -424,7 +424,7 @@ The |MIMPORTS| component of a module defines a set of *imports* that are require
          \IDFUNC~\typeidx \\&&|&
          \IDTABLE~\tabletype \\&&|&
          \IDMEM~\memtype \\&&|&
    -     \IDTAG~\tagtype \\&&|&
    +     \IDTAG~\typeidx \\&&|&
          \IDGLOBAL~\globaltype \\
        \end{array}
     
    diff --git a/interpreter/binary/decode.ml b/interpreter/binary/decode.ml
    index a677c405..8a805bd6 100644
    --- a/interpreter/binary/decode.ml
    +++ b/interpreter/binary/decode.ml
    @@ -213,6 +213,7 @@ let global_type s =
     let tag_type s =
       zero s; at var s
     
    +
     (* Instructions *)
     
     open Ast
    
    From 12f0bc25bec753fee8dc49f060a1f8b430320977 Mon Sep 17 00:00:00 2001
    From: Andreas Rossberg 
    Date: Fri, 13 Sep 2024 10:54:02 +0200
    Subject: [PATCH 126/132] Add proposal name to spec
    
    ---
     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 3952701b..d6e5eb5a 100644
    --- a/document/core/conf.py
    +++ b/document/core/conf.py
    @@ -66,10 +66,10 @@
     logo = 'static/webassembly.png'
     
     # The name of the GitHub repository this resides in
    -repo = 'spec'
    +repo = 'exception-handling'
     
     # The name of the proposal it represents, if any
    -proposal = ''
    +proposal = 'exception handling'
     
     # The draft version string (clear out for release cuts)
     draft = ' (Draft ' + date.today().strftime("%Y-%m-%d") + ')'
    
    From 6ca331004b4c4ebcb1c00f450a79bcd688860e7a Mon Sep 17 00:00:00 2001
    From: Andreas Rossberg 
    Date: Fri, 13 Sep 2024 10:59:09 +0200
    Subject: [PATCH 127/132] Fix index.rst
    
    ---
     document/core/index.rst | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/document/core/index.rst b/document/core/index.rst
    index d8095d48..0179df7b 100644
    --- a/document/core/index.rst
    +++ b/document/core/index.rst
    @@ -3,7 +3,7 @@ WebAssembly Specification
     
     .. only:: html
     
    -   | Release |release| + exception handling (Draft, |today|)
    +   | Release |release|
     
        | Editor: Andreas Rossberg
     
    
    From da1e90701f649bfe6a65b30d104d576a875315d7 Mon Sep 17 00:00:00 2001
    From: Thibaud Michaud 
    Date: Mon, 7 Oct 2024 20:33:30 +0200
    Subject: [PATCH 128/132] Handle negative type codes in wasm-module-builder.js
     (#335)
    
    ---
     test/js-api/wasm-module-builder.js | 8 ++++----
     1 file changed, 4 insertions(+), 4 deletions(-)
    
    diff --git a/test/js-api/wasm-module-builder.js b/test/js-api/wasm-module-builder.js
    index b23cea5f..1f6c9190 100644
    --- a/test/js-api/wasm-module-builder.js
    +++ b/test/js-api/wasm-module-builder.js
    @@ -981,7 +981,7 @@ class WasmModuleBuilder {
                 section.emit_u32v(imp.initial); // initial
                 if (has_max) section.emit_u32v(imp.maximum); // maximum
               } else if (imp.kind == kExternalTable) {
    -            section.emit_u8(imp.type);
    +            section.emit_type(imp.type);
                 var has_max = (typeof imp.maximum) != "undefined";
                 section.emit_u8(has_max ? 1 : 0); // flags
                 section.emit_u32v(imp.initial); // initial
    @@ -1013,7 +1013,7 @@ class WasmModuleBuilder {
           binary.emit_section(kTableSectionCode, section => {
             section.emit_u32v(wasm.tables.length);
             for (let table of wasm.tables) {
    -          section.emit_u8(table.type);
    +          section.emit_type(table.type);
               section.emit_u8(table.has_max);
               section.emit_u32v(table.initial_size);
               if (table.has_max) section.emit_u32v(table.max_size);
    @@ -1045,7 +1045,7 @@ class WasmModuleBuilder {
           binary.emit_section(kGlobalSectionCode, section => {
             section.emit_u32v(wasm.globals.length);
             for (let global of wasm.globals) {
    -          section.emit_u8(global.type);
    +          section.emit_type(global.type);
               section.emit_u8(global.mutable);
               if ((typeof global.init_index) == "undefined") {
                 // Emit a constant initializer.
    @@ -1219,7 +1219,7 @@ class WasmModuleBuilder {
               header.emit_u32v(local_decls.length);
               for (let decl of local_decls) {
                 header.emit_u32v(decl.count);
    -            header.emit_u8(decl.type);
    +            header.emit_type(decl.type);
               }
     
               section.emit_u32v(header.length + func.body.length);
    
    From e7c7c313d26f6b0fe8f1bda33cd6ab5e9edd838b Mon Sep 17 00:00:00 2001
    From: Matthias Liedtke 
    Date: Thu, 21 Nov 2024 22:32:17 +0100
    Subject: [PATCH 129/132] Clarify descriptions of control flow operators (#340)
    
    ---
     proposals/exception-handling/legacy/Exceptions.md | 6 +++---
     1 file changed, 3 insertions(+), 3 deletions(-)
    
    diff --git a/proposals/exception-handling/legacy/Exceptions.md b/proposals/exception-handling/legacy/Exceptions.md
    index 74270f88..a214ee21 100644
    --- a/proposals/exception-handling/legacy/Exceptions.md
    +++ b/proposals/exception-handling/legacy/Exceptions.md
    @@ -703,9 +703,9 @@ throws, and rethrows as follows:
     | `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 |
    +| `delegate` | `0x18` | relative_depth : `varuint32` | ends the current try block and delegates any exceptions to the block at `relative_depth` |
    +| `throw` | `0x08` | index : `varint32` | creates an exception defined by the tag and then throws it |
    +| `rethrow` | `0x09` | relative_depth : `varuint32` | throws the exception caught by the catch block at `relative_depth` |
     
     The *sig* fields of `block`, `if`, and `try` operators are block signatures
     which describe their use of the operand stack.
    
    From c713e44aa0ce5b0e440c8d6bebc9164d6b3b47a2 Mon Sep 17 00:00:00 2001
    From: =?UTF-8?q?=C3=96mer=20Sinan=20A=C4=9Facan?= 
    Date: Thu, 6 Mar 2025 21:16:54 +0000
    Subject: [PATCH 130/132] Fix text format of throw_ref in explainer (#341)
    
    ---
     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 d982592c..c00f4e8c 100644
    --- a/proposals/exception-handling/Exceptions.md
    +++ b/proposals/exception-handling/Exceptions.md
    @@ -295,7 +295,7 @@ The following rules are added to *instructions*:
     ```
       try_table blocktype catch* instruction* end |
       throw tag_index |
    -  throw_ref label |
    +  throw_ref |
     ```
     
     Like the `block`, `loop`, and `if` instructions, the `try_table` instruction is
    
    From ad19491ff6d13f9ef3dc56182e48576df31ea4be Mon Sep 17 00:00:00 2001
    From: Heejin Ahn 
    Date: Tue, 11 Mar 2025 17:28:49 -0700
    Subject: [PATCH 131/132] Add link to legacy proposal in explainer (#342)
    
    I found that the legacy and pre-legacy proposals have links to their
    immediate predecessor and successor but the current proposal does not
    have a link to its (immediate) predecessor. Given that the current
    proposal is not yet supported without flags in many browsers, it would
    help people who want to look at the legacy proposal but don't know there
    is a separate `legacy/` directory.
    ---
     proposals/exception-handling/Exceptions.md | 4 ++++
     1 file changed, 4 insertions(+)
    
    diff --git a/proposals/exception-handling/Exceptions.md b/proposals/exception-handling/Exceptions.md
    index c00f4e8c..47d8ae55 100644
    --- a/proposals/exception-handling/Exceptions.md
    +++ b/proposals/exception-handling/Exceptions.md
    @@ -3,6 +3,10 @@
     This explainer reflects the up-to-date version of the exception handling
     proposal agreed on [Oct 2023 CG
     meeting](https://github.com/WebAssembly/meetings/blob/main/main/2023/CG-10.md#exception-handling-vote-on-proposal-to-re-introduce-exnref).
    +See the [legacy
    +proposal](https://github.com/WebAssembly/exception-handling/blob/main/proposals/exception-handling/legacy/Exceptions.md)
    +for the previous version of the proposal that is still supported in several
    +browsers.
     
     ---
     
    
    From af287a73d8f3bf7ea216c10592f9e350b947c4f2 Mon Sep 17 00:00:00 2001
    From: =?UTF-8?q?=C3=96mer=20Sinan=20A=C4=9Facan?= 
    Date: Thu, 20 Mar 2025 12:55:09 +0000
    Subject: [PATCH 132/132] Add missing backquote in catch_all_ref validation
     section (#343)
    
    ---
     document/core/valid/instructions.rst | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/document/core/valid/instructions.rst b/document/core/valid/instructions.rst
    index 2b9a937e..44c40087 100644
    --- a/document/core/valid/instructions.rst
    +++ b/document/core/valid/instructions.rst
    @@ -1466,7 +1466,7 @@ Control Instructions
     
     * The label :math:`C.\CLABELS[l]` must be defined in the context.
     
    -* The :ref:`result type ` :math:`C.\CLABELS[l] must be :math:`[\EXNREF]`.
    +* The :ref:`result type ` :math:`C.\CLABELS[l]` must be :math:`[\EXNREF]`.
     
     * Then the catch clause is valid.