From 7fa2f20a6df4cf1c114582c8cb60f5bfcdbf1be1 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Wed, 10 Mar 2021 20:06:38 +0100 Subject: [PATCH] [spec/interpreter/test] Land bulk instructions & reference types proposals (#1287) --- document/core/appendix/algorithm.rst | 121 +- document/core/appendix/embedding.rst | 80 +- .../core/appendix/gen-index-instructions.py | 40 +- document/core/appendix/index-instructions.rst | 538 +- document/core/appendix/index-rules.rst | 24 +- document/core/appendix/index-types.rst | 15 +- document/core/appendix/properties.rst | 274 +- document/core/binary/conventions.rst | 3 + document/core/binary/instructions.rst | 76 +- document/core/binary/modules.rst | 131 +- document/core/binary/types.rst | 61 +- document/core/exec/instructions.rst | 924 ++- document/core/exec/modules.rst | 484 +- document/core/exec/runtime.rst | 156 +- document/core/syntax/conventions.rst | 4 + document/core/syntax/instructions.rst | 97 +- document/core/syntax/modules.rst | 83 +- document/core/syntax/types.rst | 84 +- document/core/text/conventions.rst | 4 + document/core/text/instructions.rst | 94 +- document/core/text/modules.rst | 104 +- document/core/text/types.rst | 55 +- document/core/util/macros.def | 140 +- document/core/valid/conventions.rst | 8 +- document/core/valid/instructions.rst | 423 +- document/core/valid/modules.rst | 176 +- document/core/valid/types.rst | 137 +- document/js-api/index.bs | 100 +- interpreter/Makefile | 22 +- interpreter/README.md | 86 +- interpreter/binary/decode.ml | 209 +- interpreter/binary/encode.ml | 113 +- interpreter/exec/eval.ml | 450 +- interpreter/exec/eval_numeric.ml | 162 +- interpreter/exec/eval_numeric.mli | 12 +- interpreter/host/env.ml | 6 +- interpreter/host/spectest.ml | 36 +- interpreter/runtime/global.ml | 19 +- interpreter/runtime/instance.ml | 23 +- interpreter/runtime/memory.ml | 46 +- interpreter/runtime/memory.mli | 15 +- interpreter/runtime/table.ml | 52 +- interpreter/runtime/table.mli | 18 +- interpreter/script/js.ml | 168 +- interpreter/script/run.ml | 39 +- interpreter/script/script.ml | 23 +- interpreter/syntax/ast.ml | 65 +- interpreter/syntax/free.ml | 144 + interpreter/syntax/free.mli | 36 + interpreter/syntax/operators.ml | 28 +- interpreter/syntax/types.ml | 57 +- interpreter/syntax/values.ml | 90 +- interpreter/text/arrange.ml | 117 +- interpreter/text/lexer.mll | 36 +- interpreter/text/parser.mly | 265 +- interpreter/util/lib.ml | 13 + interpreter/util/lib.mli | 5 + interpreter/util/source.ml | 1 + interpreter/util/source.mli | 1 + interpreter/valid/valid.ml | 257 +- proposals/bulk-memory-operations/Overview.md | 453 ++ proposals/reference-types/Overview.md | 292 + test/core/binary-leb128.wast | 5 +- test/core/binary.wast | 889 ++- test/core/br_table.wast | 38 + test/core/bulk.wast | 351 ++ test/core/call_indirect.wast | 46 + test/core/custom.wast | 10 + test/core/data.wast | 115 +- test/core/elem.wast | 157 +- test/core/exports.wast | 12 +- test/core/global.wast | 25 + test/core/imports.wast | 52 +- test/core/linking.wast | 139 +- test/core/memory_copy.wast | 5578 +++++++++++++++++ test/core/memory_fill.wast | 686 ++ test/core/memory_grow.wast | 46 +- test/core/memory_init.wast | 967 +++ test/core/ref_func.wast | 115 + test/core/ref_is_null.wast | 58 + test/core/ref_null.wast | 10 + test/core/select.wast | 221 +- test/core/table-sub.wast | 21 + test/core/table.wast | 4 +- test/core/table_copy.wast | 3082 +++++++++ test/core/table_fill.wast | 153 + test/core/table_get.wast | 88 + test/core/table_grow.wast | 173 + test/core/table_init.wast | 2143 +++++++ test/core/table_set.wast | 119 + test/core/table_size.wast | 86 + test/core/unreached-invalid.wast | 14 - test/harness/async_index.js | 54 +- test/harness/sync_index.js | 50 +- test/js-api/limits.any.js | 2 +- test/meta/Makefile | 32 + test/meta/README.md | 1 + test/meta/common.js | 29 + test/meta/generate_memory_copy.js | 768 +++ test/meta/generate_memory_fill.js | 157 + test/meta/generate_memory_init.js | 313 + test/meta/generate_table_copy.js | 359 ++ test/meta/generate_table_init.js | 387 ++ test/meta/noderun.sh | 16 + 104 files changed, 23371 insertions(+), 1995 deletions(-) create mode 100644 interpreter/syntax/free.ml create mode 100644 interpreter/syntax/free.mli create mode 100644 proposals/bulk-memory-operations/Overview.md create mode 100644 proposals/reference-types/Overview.md create mode 100644 test/core/bulk.wast create mode 100644 test/core/memory_copy.wast create mode 100644 test/core/memory_fill.wast create mode 100644 test/core/memory_init.wast create mode 100644 test/core/ref_func.wast create mode 100644 test/core/ref_is_null.wast create mode 100644 test/core/ref_null.wast create mode 100644 test/core/table-sub.wast create mode 100644 test/core/table_copy.wast create mode 100644 test/core/table_fill.wast create mode 100644 test/core/table_get.wast create mode 100644 test/core/table_grow.wast create mode 100644 test/core/table_init.wast create mode 100644 test/core/table_set.wast create mode 100644 test/core/table_size.wast create mode 100644 test/meta/Makefile create mode 100644 test/meta/README.md create mode 100644 test/meta/common.js create mode 100644 test/meta/generate_memory_copy.js create mode 100644 test/meta/generate_memory_fill.js create mode 100644 test/meta/generate_memory_init.js create mode 100644 test/meta/generate_table_copy.js create mode 100644 test/meta/generate_table_init.js create mode 100755 test/meta/noderun.sh diff --git a/document/core/appendix/algorithm.rst b/document/core/appendix/algorithm.rst index 488eca36e1..bd86ee4f18 100644 --- a/document/core/appendix/algorithm.rst +++ b/document/core/appendix/algorithm.rst @@ -21,15 +21,25 @@ The algorithm is expressed in typed pseudo code whose semantics is intended to b Data Structures ~~~~~~~~~~~~~~~ -The algorithm uses two separate stacks: the *operand stack* and the *control stack*. +Types are representable as an enumeration. + +.. code-block:: pseudo + + type val_type = I32 | I64 | F32 | F64 | Funcref | Externref + + func is_num(t : val_type | Unknown) : bool = + return t = I32 || t = I64 || t = F32 || t = F64 || t = Unknown + + func is_ref(t : val_type | Unknown) : bool = + return t = Funcref || 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 `, the latter surrounding :ref:`structured control instructions ` and their associated :ref:`blocks `. .. code-block:: pseudo - type val_type = I32 | I64 | F32 | F64 - - type opd_stack = stack(val_type | Unknown) + type val_stack = stack(val_type | Unknown) type ctrl_stack = stack(ctrl_frame) type ctrl_frame = { @@ -40,7 +50,7 @@ the latter surrounding :ref:`structured control instructions `, or :code:`Unknown` when the type is not known. +For each value, the value stack records its :ref:`value type `, or :code:`Unknown` when the type is not known. For each entered block, the control stack records a *control frame* with the originating opcode, the types on the top of the operand stack at the start and end of the block (used to check its result as well as branches), the height of the operand stack at the start of the block (used to check that operands do not underflow the current block), and a flag recording whether the remainder of the block is unreachable (used to handle :ref:`stack-polymorphic ` typing after branches). @@ -48,47 +58,50 @@ For the purpose of presenting the algorithm, the operand and control stacks are .. code-block:: pseudo - var opds : opd_stack + var vals : val_stack var ctrls : ctrl_stack However, these variables are not manipulated directly by the main checking function, but through a set of auxiliary functions: .. code-block:: pseudo - func push_opd(type : val_type | Unknown) = - opds.push(type) + func push_val(type : val_type | Unknown) = + vals.push(type) - func pop_opd() : val_type | Unknown = - if (opds.size() = ctrls[0].height && ctrls[0].unreachable) return Unknown - error_if(opds.size() = ctrls[0].height) - return opds.pop() + func pop_val() : val_type | Unknown = + if (vals.size() = ctrls[0].height && ctrls[0].unreachable) return Unknown + error_if(vals.size() = ctrls[0].height) + return vals.pop() - func pop_opd(expect : val_type | Unknown) : val_type | Unknown = - let actual = pop_opd() + func pop_val(expect : val_type | Unknown) : val_type | Unknown = + let actual = pop_val() if (actual = Unknown) return expect if (expect = Unknown) return actual error_if(actual =/= expect) return actual - func push_opds(types : list(val_type)) = foreach (t in types) push_opd(t) - func pop_opds(types : list(val_type)) = foreach (t in reverse(types)) pop_opd(t) + func push_vals(types : list(val_type)) = foreach (t in types) push_val(t) + func pop_vals(types : list(val_type)) : list(val_type) = + var popped := [] + foreach (t in reverse(types)) popped.append(pop_val(t)) + return popped -Pushing an operand simply pushes the respective type to the operand stack. +Pushing an operand value simply pushes the respective type to the value stack. -Popping an operand checks that the operand stack does not underflow the current block and then removes one type. -But first, a special case is handled where the block contains no known operands, but has been marked as unreachable. +Popping an operand value checks that the value stack does not underflow the current block and then removes one type. +But first, a special case is handled where the block contains no known values, but has been marked as unreachable. That can occur after an unconditional branch, when the stack is typed :ref:`polymorphically `. In that case, an unknown type is returned. -A second function for popping an operand takes an expected type, which the actual operand type is checked against. +A second function for popping an operand value takes an expected type, which the actual operand type is checked against. The types may differ in case one of them is Unknown. -The more specific type is returned. +The function returns the actual type popped from the stack. Finally, there are accumulative functions for pushing or popping multiple operand types. .. note:: The notation :code:`stack[i]` is meant to index the stack from the top, - so that :code:`ctrls[0]` accesses the element pushed last. + so that, e.g., :code:`ctrls[0]` accesses the element pushed last. The control stack is likewise manipulated through auxiliary functions: @@ -96,15 +109,15 @@ The control stack is likewise manipulated through auxiliary functions: .. code-block:: pseudo func push_ctrl(opcode : opcode, in : list(val_type), out : list(val_type)) = -  let frame = ctrl_frame(opcode, in, out, opds.size(), false) +  let frame = ctrl_frame(opcode, in, out, vals.size(), false)   ctrls.push(frame) - push_opds(in) + push_vals(in) func pop_ctrl() : ctrl_frame =  error_if(ctrls.is_empty())  let frame = ctrls[0] -   pop_opds(frame.end_types) -   error_if(opds.size() =/= frame.height) +   pop_vals(frame.end_types) +   error_if(vals.size() =/= frame.height) ctrls.pop()   return frame @@ -112,7 +125,7 @@ The control stack is likewise manipulated through auxiliary functions: return (if frame.opcode == loop then frame.start_types else frame.end_types) func unreachable() = -   opds.resize(ctrls[0].height) +   vals.resize(ctrls[0].height)   ctrls[0].unreachable := true Pushing a control frame takes the types of the label and result values. @@ -125,7 +138,7 @@ Afterwards, it checks that the stack has shrunk back to its initial height. The type of the :ref:`label ` associated with a control frame is either that of the stack at the start or the end of the frame, determined by the opcode that it originates from. Finally, the current frame can be marked as unreachable. -In that case, all existing operand types are purged from the operand stack, in order to allow for the :ref:`stack-polymorphism ` logic in :code:`pop_opd` to take effect. +In that case, all existing operand types are purged from the value stack, in order to allow for the :ref:`stack-polymorphism ` logic in :code:`pop_val` to take effect. .. note:: Even with the unreachable flag set, consecutive operands are still pushed to and popped from the operand stack. @@ -150,38 +163,46 @@ Other instructions are checked in a similar manner. func validate(opcode) = switch (opcode) case (i32.add) - pop_opd(I32) - pop_opd(I32) - push_opd(I32) + pop_val(I32) + pop_val(I32) + push_val(I32) case (drop) - pop_opd() + pop_val() case (select) - pop_opd(I32) - let t1 = pop_opd() - let t2 = pop_opd(t1) - push_opd(t2) + pop_val(I32) + let t1 = pop_val() + let t2 = pop_val() + error_if(not (is_num(t1) && is_num(t2))) + error_if(t1 =/= t2 && t1 =/= Unknown && t2 =/= Unknown) + push_val(if (t1 = Unknown) t2 else t1) + + case (select t) + pop_val(I32) + pop_val(t) + pop_val(t) + push_val(t)    case (unreachable)       unreachable() case (block t1*->t2*) - pop_opds([t1*]) + pop_vals([t1*]) push_ctrl(block, [t1*], [t2*]) case (loop t1*->t2*) - pop_opds([t1*]) + pop_vals([t1*]) push_ctrl(loop, [t1*], [t2*]) case (if t1*->t2*) - pop_opd(I32) - pop_opds([t1*]) + pop_val(I32) + pop_vals([t1*]) push_ctrl(if, [t1*], [t2*]) case (end) let frame = pop_ctrl() - push_opds(frame.end_types) + push_vals(frame.end_types) case (else) let frame = pop_ctrl() @@ -190,23 +211,27 @@ Other instructions are checked in a similar manner. case (br n)      error_if(ctrls.size() < n) -       pop_opds(label_types(ctrls[n])) +       pop_vals(label_types(ctrls[n]))       unreachable() case (br_if n)      error_if(ctrls.size() < n) - pop_opd(I32) -       pop_opds(label_types(ctrls[n])) -       push_opds(label_types(ctrls[n])) + pop_val(I32) +       pop_vals(label_types(ctrls[n])) +       push_vals(label_types(ctrls[n]))    case (br_table n* m) + pop_val(I32)       error_if(ctrls.size() < m) + let arity = label_types(ctrls[m]).size()       foreach (n in n*) -         error_if(ctrls.size() < n || label_types(ctrls[n]) =/= label_types(ctrls[m])) - pop_opd(I32) -       pop_opds(label_types(ctrls[m])) +         error_if(ctrls.size() < n) +         error_if(label_types(ctrls[n]).size() =/= arity) + push_vals(pop_vals(label_types(ctrls[n]))) + pop_vals(label_types(ctrls[m]))       unreachable() + .. note:: It is an invariant under the current WebAssembly instruction set that an operand of :code:`Unknown` type is never duplicated on the stack. This would change if the language were extended with stack instructions like :code:`dup`. diff --git a/document/core/appendix/embedding.rst b/document/core/appendix/embedding.rst index 70866c7203..db83ae26be 100644 --- a/document/core/appendix/embedding.rst +++ b/document/core/appendix/embedding.rst @@ -280,15 +280,13 @@ Functions :math:`\F{func\_type}(\store, \funcaddr) : \functype` ..................................................... -1. Assert: the :ref:`external value ` :math:`\EVFUNC~\funcaddr` is :ref:`valid ` with :ref:`external type ` :math:`\ETFUNC~\functype`. +1. Return :math:`S.\SFUNCS[a].\FITYPE`. -2. Return :math:`\functype`. - -3. Post-condition: :math:`\functype` is :ref:`valid `. +2. Post-condition: the returned :ref:`function type ` is :ref:`valid `. .. math:: \begin{array}{lclll} - \F{func\_type}(S, a) &=& \X{ft} && (\iff S \vdashexternval \EVFUNC~a : \ETFUNC~\X{ft}) \\ + \F{func\_type}(S, a) &=& S.\SFUNCS[a].\FITYPE \\ \end{array} @@ -325,18 +323,18 @@ Tables .. _embed-table-alloc: -:math:`\F{table\_alloc}(\store, \tabletype) : (\store, \tableaddr)` -................................................................... +:math:`\F{table\_alloc}(\store, \tabletype) : (\store, \tableaddr, \reff)` +.......................................................................... 1. Pre-condition: :math:`\tabletype` is :math:`valid `. -2. Let :math:`\tableaddr` be the result of :ref:`allocating a table ` in :math:`\store` with :ref:`table type ` :math:`\tabletype`. +2. Let :math:`\tableaddr` be the result of :ref:`allocating a table ` in :math:`\store` with :ref:`table type ` :math:`\tabletype` and initialization value :math:`\reff`. 3. Return the new store paired with :math:`\tableaddr`. .. math:: \begin{array}{lclll} - \F{table\_alloc}(S, \X{tt}) &=& (S', \X{a}) && (\iff \alloctable(S, \X{tt}) = S', \X{a}) \\ + \F{table\_alloc}(S, \X{tt}, r) &=& (S', \X{a}) && (\iff \alloctable(S, \X{tt}, r) = S', \X{a}) \\ \end{array} @@ -345,53 +343,51 @@ Tables :math:`\F{table\_type}(\store, \tableaddr) : \tabletype` ........................................................ -1. Assert: the :ref:`external value ` :math:`\EVTABLE~\tableaddr` is :ref:`valid ` with :ref:`external type ` :math:`\ETTABLE~\tabletype`. - -2. Return :math:`\tabletype`. +1. Return :math:`S.\STABLES[a].\TITYPE`. -3. Post-condition: :math:`\tabletype` is :math:`valid `. +2. Post-condition: the returned :ref:`table type ` is :math:`valid `. .. math:: \begin{array}{lclll} - \F{table\_type}(S, a) &=& \X{tt} && (\iff S \vdashexternval \EVTABLE~a : \ETTABLE~\X{tt}) \\ + \F{table\_type}(S, a) &=& S.\STABLES[a].\TITYPE \\ \end{array} .. _embed-table-read: -:math:`\F{table\_read}(\store, \tableaddr, i:\u32) : \funcaddr^? ~|~ \error` -............................................................................ +:math:`\F{table\_read}(\store, \tableaddr, i:\u32) : \reff ~|~ \error` +...................................................................... 1. Let :math:`\X{ti}` be the :ref:`table instance ` :math:`\store.\STABLES[\tableaddr]`. 2. If :math:`i` is larger than or equal to the length of :math:`\X{ti}.\TIELEM`, then return :math:`\ERROR`. -3. Else, return :math:`\X{ti}.\TIELEM[i]`. +3. Else, return the :ref:`reference value ` :math:`\X{ti}.\TIELEM[i]`. .. math:: \begin{array}{lclll} - \F{table\_read}(S, a, i) &=& \X{fa}^? && (\iff S.\STABLES[a].\TIELEM[i] = \X{fa}^?) \\ + \F{table\_read}(S, a, i) &=& r && (\iff S.\STABLES[a].\TIELEM[i] = r) \\ \F{table\_read}(S, a, i) &=& \ERROR && (\otherwise) \\ \end{array} .. _embed-table-write: -:math:`\F{table\_write}(\store, \tableaddr, i:\u32, \funcaddr^?) : \store ~|~ \error` -....................................................................................... +:math:`\F{table\_write}(\store, \tableaddr, i:\u32, \reff) : \store ~|~ \error` +............................................................................... 1. Let :math:`\X{ti}` be the :ref:`table instance ` :math:`\store.\STABLES[\tableaddr]`. 2. If :math:`i` is larger than or equal to the length of :math:`\X{ti}.\TIELEM`, then return :math:`\ERROR`. -3. Replace :math:`\X{ti}.\TIELEM[i]` with the optional :ref:`function address ` :math:`\X{fa}^?`. +3. Replace :math:`\X{ti}.\TIELEM[i]` with the :ref:`reference value ` :math:`\reff`. 4. Return the updated store. .. math:: \begin{array}{lclll} - \F{table\_write}(S, a, i, \X{fa}^?) &=& S' && (\iff S' = S \with \STABLES[a].\TIELEM[i] = \X{fa}^?) \\ - \F{table\_write}(S, a, i, \X{fa}^?) &=& \ERROR && (\otherwise) \\ + \F{table\_write}(S, a, i, r) &=& S' && (\iff S' = S \with \STABLES[a].\TIELEM[i] = r) \\ + \F{table\_write}(S, a, i, r) &=& \ERROR && (\otherwise) \\ \end{array} @@ -413,10 +409,10 @@ Tables .. _embed-table-grow: -:math:`\F{table\_grow}(\store, \tableaddr, n:\u32) : \store ~|~ \error` -....................................................................... +:math:`\F{table\_grow}(\store, \tableaddr, n:\u32, \reff) : \store ~|~ \error` +.............................................................................. -1. Try :ref:`growing ` the :ref:`table instance ` :math:`\store.\STABLES[\tableaddr]` by :math:`n` elements: +1. Try :ref:`growing ` the :ref:`table instance ` :math:`\store.\STABLES[\tableaddr]` by :math:`n` elements with initialization value :math:`\reff`: a. If it succeeds, return the updated store. @@ -425,9 +421,9 @@ Tables .. math:: ~ \\ \begin{array}{lclll} - \F{table\_grow}(S, a, n) &=& S' && - (\iff S' = S \with \STABLES[a] = \growtable(S.\STABLES[a], n)) \\ - \F{table\_grow}(S, a, n) &=& \ERROR && (\otherwise) \\ + \F{table\_grow}(S, a, n, r) &=& S' && + (\iff S' = S \with \STABLES[a] = \growtable(S.\STABLES[a], n, r)) \\ + \F{table\_grow}(S, a, n, r) &=& \ERROR && (\otherwise) \\ \end{array} @@ -459,15 +455,13 @@ Memories :math:`\F{mem\_type}(\store, \memaddr) : \memtype` .................................................. -1. Assert: the :ref:`external value ` :math:`\EVMEM~\memaddr` is :ref:`valid ` with :ref:`external type ` :math:`\ETMEM~\memtype`. +1. Return :math:`S.\SMEMS[a].\MITYPE`. -2. Return :math:`\memtype`. - -3. Post-condition: :math:`\memtype` is :math:`valid `. +2. Post-condition: the returned :ref:`memory type ` is :math:`valid `. .. math:: \begin{array}{lclll} - \F{mem\_type}(S, a) &=& \X{mt} && (\iff S \vdashexternval \EVMEM~a : \ETMEM~\X{mt}) \\ + \F{mem\_type}(S, a) &=& S.\SMEMS[a].\MITYPE \\ \end{array} @@ -574,15 +568,13 @@ Globals :math:`\F{global\_type}(\store, \globaladdr) : \globaltype` ........................................................... -1. Assert: the :ref:`external value ` :math:`\EVGLOBAL~\globaladdr` is :ref:`valid ` with :ref:`external type ` :math:`\ETGLOBAL~\globaltype`. - -2. Return :math:`\globaltype`. +1. Return :math:`S.\SGLOBALS[a].\GITYPE`. -3. Post-condition: :math:`\globaltype` is :math:`valid `. +2. Post-condition: the returned :ref:`global type ` is :math:`valid `. .. math:: \begin{array}{lclll} - \F{global\_type}(S, a) &=& \X{gt} && (\iff S \vdashexternval \EVGLOBAL~a : \ETGLOBAL~\X{gt}) \\ + \F{global\_type}(S, a) &=& S.\SGLOBALS[a].\GITYPE \\ \end{array} @@ -608,15 +600,17 @@ Globals 1. Let :math:`\X{gi}` be the :ref:`global instance ` :math:`\store.\SGLOBALS[\globaladdr]`. -2. If :math:`\X{gi}.\GIMUT` is not :math:`\MVAR`, then return :math:`\ERROR`. +2. Let :math:`\mut~t` be the structure of the :ref:`global type ` :math:`\X{gi}.\GITYPE`. -3. Replace :math:`\X{gi}.\GIVALUE` with the :ref:`value ` :math:`\val`. +3. If :math:`\mut` is not :math:`\MVAR`, then return :math:`\ERROR`. -4. Return the updated store. +4. Replace :math:`\X{gi}.\GIVALUE` with the :ref:`value ` :math:`\val`. + +5. Return the updated store. .. math:: ~ \\ \begin{array}{lclll} - \F{global\_write}(S, a, v) &=& S' && (\iff S.\SGLOBALS[a].\GIMUT = \MVAR \wedge S' = S \with \SGLOBALS[a].\GIVALUE = v) \\ + \F{global\_write}(S, a, v) &=& S' && (\iff S.\SGLOBALS[a].\GITYPE = \MVAR~t \wedge S' = S \with \SGLOBALS[a].\GIVALUE = v) \\ \F{global\_write}(S, a, v) &=& \ERROR && (\otherwise) \\ \end{array} diff --git a/document/core/appendix/gen-index-instructions.py b/document/core/appendix/gen-index-instructions.py index bc1b9e23e9..dc3574702f 100755 --- a/document/core/appendix/gen-index-instructions.py +++ b/document/core/appendix/gen-index-instructions.py @@ -78,7 +78,7 @@ def Instruction(name, opcode, type=None, validation=None, execution=None, operat Instruction(r'\BRTABLE~l^\ast~l', r'\hex{0E}', r'[t_1^\ast~t^\ast~\I32] \to [t_2^\ast]', r'valid-br_table', r'exec-br_table'), Instruction(r'\RETURN', r'\hex{0F}', r'[t_1^\ast~t^\ast] \to [t_2^\ast]', r'valid-return', r'exec-return'), Instruction(r'\CALL~x', r'\hex{10}', r'[t_1^\ast] \to [t_2^\ast]', r'valid-call', r'exec-call'), - Instruction(r'\CALLINDIRECT~x', r'\hex{11}', r'[t_1^\ast~\I32] \to [t_2^\ast]', r'valid-call_indirect', r'exec-call_indirect'), + Instruction(r'\CALLINDIRECT~x~y', r'\hex{11}', r'[t_1^\ast~\I32] \to [t_2^\ast]', r'valid-call_indirect', r'exec-call_indirect'), Instruction(None, r'\hex{12}'), Instruction(None, r'\hex{13}'), Instruction(None, r'\hex{14}'), @@ -89,7 +89,7 @@ def Instruction(name, opcode, type=None, validation=None, execution=None, operat 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(None, r'\hex{1C}'), + 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}'), @@ -98,8 +98,8 @@ def Instruction(name, opcode, type=None, validation=None, execution=None, operat Instruction(r'\LOCALTEE~x', r'\hex{22}', r'[t] \to [t]', r'valid-local.tee', r'exec-local.tee'), Instruction(r'\GLOBALGET~x', r'\hex{23}', r'[] \to [t]', r'valid-global.get', r'exec-global.get'), Instruction(r'\GLOBALSET~x', r'\hex{24}', r'[t] \to []', r'valid-global.set', r'exec-global.set'), - Instruction(None, r'\hex{25}'), - Instruction(None, r'\hex{26}'), + Instruction(r'\TABLEGET~x', r'\hex{25}', r'[\I32] \to [t]', r'valid-table.get', r'exec-table.get'), + Instruction(r'\TABLESET~x', r'\hex{26}', r'[\I32~t] \to []', r'valid-table.set', r'exec-table.set'), Instruction(None, r'\hex{27}'), Instruction(r'\I32.\LOAD~\memarg', r'\hex{28}', r'[\I32] \to [\I32]', r'valid-load', r'exec-load'), Instruction(r'\I64.\LOAD~\memarg', r'\hex{29}', r'[\I32] \to [\I64]', r'valid-load', r'exec-load'), @@ -269,9 +269,9 @@ def Instruction(name, opcode, type=None, validation=None, execution=None, operat Instruction(None, r'\hex{CD}'), Instruction(None, r'\hex{CE}'), Instruction(None, r'\hex{CF}'), - Instruction(None, r'\hex{D0}'), - Instruction(None, r'\hex{D1}'), - Instruction(None, r'\hex{D2}'), + Instruction(r'\REFNULL~t', r'\hex{D0}', r'[] \to [t]', r'valid-ref.null', r'exec-ref.null'), + Instruction(r'\REFISNULL', r'\hex{D1}', r'[t] \to [\I32]', r'valid-ref.is_null', r'exec-ref.is_null'), + Instruction(r'\REFFUNC~x', r'\hex{D2}', r'[] \to [\FUNCREF]', r'valid-ref.func', r'exec-ref.func'), Instruction(None, r'\hex{D3}'), Instruction(None, r'\hex{D4}'), Instruction(None, r'\hex{D5}'), @@ -313,14 +313,24 @@ def Instruction(name, opcode, type=None, validation=None, execution=None, operat Instruction(None, r'\hex{F9}'), Instruction(None, r'\hex{FA}'), Instruction(None, r'\hex{FB}'), - Instruction(r'\I32.\TRUNC\K{\_sat\_}\F32\K{\_s}', r'\hex{FC}~~0', r'[\F32] \to [\I32]', r'valid-cvtop', r'exec-cvtop', r'op-trunc_sat_s'), - Instruction(r'\I32.\TRUNC\K{\_sat\_}\F32\K{\_u}', r'\hex{FC}~~1', r'[\F32] \to [\I32]', r'valid-cvtop', r'exec-cvtop', r'op-trunc_sat_u'), - Instruction(r'\I32.\TRUNC\K{\_sat\_}\F64\K{\_s}', r'\hex{FC}~~2', r'[\F64] \to [\I32]', r'valid-cvtop', r'exec-cvtop', r'op-trunc_sat_s'), - Instruction(r'\I32.\TRUNC\K{\_sat\_}\F64\K{\_u}', r'\hex{FC}~~3', r'[\F64] \to [\I32]', r'valid-cvtop', r'exec-cvtop', r'op-trunc_sat_u'), - Instruction(r'\I64.\TRUNC\K{\_sat\_}\F32\K{\_s}', r'\hex{FC}~~4', r'[\F32] \to [\I64]', r'valid-cvtop', r'exec-cvtop', r'op-trunc_sat_s'), - Instruction(r'\I64.\TRUNC\K{\_sat\_}\F32\K{\_u}', r'\hex{FC}~~5', r'[\F32] \to [\I64]', r'valid-cvtop', r'exec-cvtop', r'op-trunc_sat_u'), - Instruction(r'\I64.\TRUNC\K{\_sat}\_\F64\K{\_s}', r'\hex{FC}~~6', r'[\F64] \to [\I64]', r'valid-cvtop', r'exec-cvtop', r'op-trunc_sat_s'), - Instruction(r'\I64.\TRUNC\K{\_sat\_}\F64\K{\_u}', r'\hex{FC}~~7', r'[\F64] \to [\I64]', r'valid-cvtop', r'exec-cvtop', r'op-trunc_sat_u'), + Instruction(r'\I32.\TRUNC\K{\_sat\_}\F32\K{\_s}', r'\hex{FC}~\hex{00}', r'[\F32] \to [\I32]', r'valid-cvtop', r'exec-cvtop', r'op-trunc_sat_s'), + Instruction(r'\I32.\TRUNC\K{\_sat\_}\F32\K{\_u}', r'\hex{FC}~\hex{01}', r'[\F32] \to [\I32]', r'valid-cvtop', r'exec-cvtop', r'op-trunc_sat_u'), + Instruction(r'\I32.\TRUNC\K{\_sat\_}\F64\K{\_s}', r'\hex{FC}~\hex{02}', r'[\F64] \to [\I32]', r'valid-cvtop', r'exec-cvtop', r'op-trunc_sat_s'), + Instruction(r'\I32.\TRUNC\K{\_sat\_}\F64\K{\_u}', r'\hex{FC}~\hex{03}', r'[\F64] \to [\I32]', r'valid-cvtop', r'exec-cvtop', r'op-trunc_sat_u'), + Instruction(r'\I64.\TRUNC\K{\_sat\_}\F32\K{\_s}', r'\hex{FC}~\hex{04}', r'[\F32] \to [\I64]', r'valid-cvtop', r'exec-cvtop', r'op-trunc_sat_s'), + Instruction(r'\I64.\TRUNC\K{\_sat\_}\F32\K{\_u}', r'\hex{FC}~\hex{05}', r'[\F32] \to [\I64]', r'valid-cvtop', r'exec-cvtop', r'op-trunc_sat_u'), + Instruction(r'\I64.\TRUNC\K{\_sat\_}\F64\K{\_s}', r'\hex{FC}~\hex{06}', r'[\F64] \to [\I64]', r'valid-cvtop', r'exec-cvtop', r'op-trunc_sat_s'), + Instruction(r'\I64.\TRUNC\K{\_sat\_}\F64\K{\_u}', r'\hex{FC}~\hex{07}', r'[\F64] \to [\I64]', r'valid-cvtop', r'exec-cvtop', r'op-trunc_sat_u'), + Instruction(r'\MEMORYINIT', r'\hex{FC}~\hex{08}', r'[\I32~\I32~\I32] \to []', r'valid-memory.init', r'exec-memory.init'), + Instruction(r'\DATADROP', r'\hex{FC}~\hex{09}', r'[] \to []', r'valid-data.drop', r'exec-data.drop'), + Instruction(r'\MEMORYCOPY', r'\hex{FC}~\hex{0A}', r'[\I32~\I32~\I32] \to []', r'valid-memory.copy', r'exec-memory.copy'), + Instruction(r'\MEMORYFILL', r'\hex{FC}~\hex{0B}', r'[\I32~\I32~\I32] \to []', r'valid-memory.fill', r'exec-memory.fill'), + Instruction(r'\TABLEINIT', r'\hex{FC}~\hex{0C}', r'[\I32~\I32~\I32] \to []', r'valid-table.init', r'exec-table.init'), + Instruction(r'\ELEMDROP', r'\hex{FC}~\hex{0D}', r'[] \to []', r'valid-elem.drop', r'exec-elem.drop'), + Instruction(r'\TABLECOPY', r'\hex{FC}~\hex{0E}', r'[\I32~\I32~\I32] \to []', r'valid-table.copy', r'exec-table.copy'), + Instruction(r'\TABLEGROW', r'\hex{FC}~\hex{0F}', r'[t~\I32] \to []', r'valid-table.grow', r'exec-table.grow'), + Instruction(r'\TABLESIZE', r'\hex{FC}~\hex{10}', r'[] \to []', r'valid-table.size', r'exec-table.size'), + Instruction(r'\TABLEFILL', r'\hex{FC}~\hex{11}', r'[\I32~t~\I32] \to []', r'valid-table.fill', r'exec-table.fill'), ] def ColumnWidth(n): diff --git a/document/core/appendix/index-instructions.rst b/document/core/appendix/index-instructions.rst index cb988b288e..d2be487a7c 100644 --- a/document/core/appendix/index-instructions.rst +++ b/document/core/appendix/index-instructions.rst @@ -6,267 +6,277 @@ 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] \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` :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 ` -(reserved) :math:`\hex{1C}` -(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 ` -(reserved) :math:`\hex{25}` -(reserved) :math:`\hex{26}` -(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}` -(reserved) :math:`\hex{D0}` -(reserved) :math:`\hex{D1}` -(reserved) :math:`\hex{D2}` -(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}~~0` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_sat\_}\F32\K{\_u}` :math:`\hex{FC}~~1` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_sat\_}\F64\K{\_s}` :math:`\hex{FC}~~2` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_sat\_}\F64\K{\_u}` :math:`\hex{FC}~~3` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_sat\_}\F32\K{\_s}` :math:`\hex{FC}~~4` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_sat\_}\F32\K{\_u}` :math:`\hex{FC}~~5` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_sat}\_\F64\K{\_s}` :math:`\hex{FC}~~6` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_sat\_}\F64\K{\_u}` :math:`\hex{FC}~~7` :math:`[\F64] \to [\I64]` :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] \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` :math:`\hex{FC}~\hex{08}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\DATADROP` :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` :math:`\hex{FC}~\hex{0C}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\ELEMDROP` :math:`\hex{FC}~\hex{0D}` :math:`[] \to []` :ref:`validation ` :ref:`execution ` +:math:`\TABLECOPY` :math:`\hex{FC}~\hex{0E}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\TABLEGROW` :math:`\hex{FC}~\hex{0F}` :math:`[t~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\TABLESIZE` :math:`\hex{FC}~\hex{10}` :math:`[] \to []` :ref:`validation ` :ref:`execution ` +:math:`\TABLEFILL` :math:`\hex{FC}~\hex{11}` :math:`[\I32~t~\I32] \to []` :ref:`validation ` :ref:`execution ` +========================================= ========================= ============================================= ======================================= =============================================================== diff --git a/document/core/appendix/index-rules.rst b/document/core/appendix/index-rules.rst index eb35c60713..0da084123c 100644 --- a/document/core/appendix/index-rules.rst +++ b/document/core/appendix/index-rules.rst @@ -20,15 +20,17 @@ Construct Judgement :ref:`Memory type ` :math:`\vdashmemtype \memtype \ok` :ref:`Global type ` :math:`\vdashglobaltype \globaltype \ok` :ref:`External type ` :math:`\vdashexterntype \externtype \ok` -:ref:`Instruction ` :math:`S;C \vdashinstr \instr : \functype` -:ref:`Instruction sequence ` :math:`S;C \vdashinstrseq \instr^\ast : \functype` +:ref:`Instruction ` :math:`S;C \vdashinstr \instr : \stacktype` +:ref:`Instruction sequence ` :math:`S;C \vdashinstrseq \instr^\ast : \stacktype` :ref:`Expression ` :math:`C \vdashexpr \expr : \resulttype` :ref:`Function ` :math:`C \vdashfunc \func : \functype` :ref:`Table ` :math:`C \vdashtable \table : \tabletype` :ref:`Memory ` :math:`C \vdashmem \mem : \memtype` :ref:`Global ` :math:`C \vdashglobal \global : \globaltype` -:ref:`Element segment ` :math:`C \vdashelem \elem \ok` +:ref:`Element segment ` :math:`C \vdashelem \elem : \reftype` +:ref:`Element mode ` :math:`C \vdashelemmode \elemmode : \reftype` :ref:`Data segment ` :math:`C \vdashdata \data \ok` +:ref:`Data mode ` :math:`C \vdashdatamode \datamode \ok` :ref:`Start function ` :math:`C \vdashstart \start \ok` :ref:`Export ` :math:`C \vdashexport \export : \externtype` :ref:`Export description ` :math:`C \vdashexportdesc \exportdesc : \externtype` @@ -46,13 +48,15 @@ Typing of Runtime Constructs =============================================== =============================================================================== Construct Judgement =============================================== =============================================================================== -:ref:`Value ` :math:`\vdashval \val : \valtype` -:ref:`Result ` :math:`\vdashresult \result : \resulttype` +:ref:`Value ` :math:`S \vdashval \val : \valtype` +:ref:`Result ` :math:`S \vdashresult \result : \resulttype` :ref:`External value ` :math:`S \vdashexternval \externval : \externtype` :ref:`Function instance ` :math:`S \vdashfuncinst \funcinst : \functype` :ref:`Table instance ` :math:`S \vdashtableinst \tableinst : \tabletype` :ref:`Memory instance ` :math:`S \vdashmeminst \meminst : \memtype` :ref:`Global instance ` :math:`S \vdashglobalinst \globalinst : \globaltype` +:ref:`Element instance ` :math:`S \vdasheleminst \eleminst \ok` +:ref:`Data instance ` :math:`S \vdashdatainst \datainst \ok` :ref:`Export instance ` :math:`S \vdashexportinst \exportinst \ok` :ref:`Module instance ` :math:`S \vdashmoduleinst \moduleinst : C` :ref:`Store ` :math:`\vdashstore \store \ok` @@ -73,14 +77,14 @@ Construct Judgement =============================================== =============================================================================== -Import Matching -~~~~~~~~~~~~~~~ +Matching +~~~~~~~~ =============================================== =============================================================================== Construct Judgement =============================================== =============================================================================== -:ref:`Limits ` :math:`\vdashlimitsmatch \limits_1 \matches \limits_2` -:ref:`External type ` :math:`\vdashexterntypematch \externtype_1 \matches \externtype_2` +:ref:`External type ` :math:`\vdashexterntypematch \externtype_1 \matchesexterntype \externtype_2` +:ref:`Limits ` :math:`\vdashlimitsmatch \limits_1 \matcheslimits \limits_2` =============================================== =============================================================================== @@ -94,6 +98,8 @@ Construct Judgement :ref:`Table instance ` :math:`\vdashtableinstextends \tableinst_1 \extendsto \tableinst_2` :ref:`Memory instance ` :math:`\vdashmeminstextends \meminst_1 \extendsto \meminst_2` :ref:`Global instance ` :math:`\vdashglobalinstextends \globalinst_1 \extendsto \globalinst_2` +:ref:`Element instance ` :math:`\vdasheleminstextends \eleminst_1 \extendsto \eleminst_2` +:ref:`Data instance ` :math:`\vdashdatainstextends \datainst_1 \extendsto \datainst_2` :ref:`Store ` :math:`\vdashstoreextends \store_1 \extendsto \store_2` =============================================== =============================================================================== diff --git a/document/core/appendix/index-types.rst b/document/core/appendix/index-types.rst index 55787782f3..fd38fe205d 100644 --- a/document/core/appendix/index-types.rst +++ b/document/core/appendix/index-types.rst @@ -8,17 +8,18 @@ Index of Types Category Constructor Binary Opcode ======================================== =========================================== =============================================================================== :ref:`Type index ` :math:`x` (positive number as |Bs32| or |Bu32|) -:ref:`Value type ` |I32| :math:`\hex{7F}` (-1 as |Bs7|) -:ref:`Value type ` |I64| :math:`\hex{7E}` (-2 as |Bs7|) -:ref:`Value type ` |F32| :math:`\hex{7D}` (-3 as |Bs7|) -:ref:`Value type ` |F64| :math:`\hex{7C}` (-4 as |Bs7|) +:ref:`Number type ` |I32| :math:`\hex{7F}` (-1 as |Bs7|) +:ref:`Number type ` |I64| :math:`\hex{7E}` (-2 as |Bs7|) +:ref:`Number type ` |F32| :math:`\hex{7D}` (-3 as |Bs7|) +:ref:`Number type ` |F64| :math:`\hex{7C}` (-4 as |Bs7|) (reserved) :math:`\hex{7B}` .. :math:`\hex{71}` -:ref:`Element type ` |FUNCREF| :math:`\hex{70}` (-16 as |Bs7|) -(reserved) :math:`\hex{6F}` .. :math:`\hex{61}` +: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}` :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|) -:ref:`Table type ` :math:`\limits~\elemtype` (none) +:ref:`Table type ` :math:`\limits~\reftype` (none) :ref:`Memory type ` :math:`\limits` (none) :ref:`Global type ` :math:`\mut~\valtype` (none) ======================================== =========================================== =============================================================================== diff --git a/document/core/appendix/properties.rst b/document/core/appendix/properties.rst index 9ed38ba633..30cb620c95 100644 --- a/document/core/appendix/properties.rst +++ b/document/core/appendix/properties.rst @@ -21,25 +21,12 @@ In order to state and prove soundness precisely, the typing rules must be extend .. index:: value, value type, result, result type, trap -.. _valid-val: .. _valid-result: -Values and Results -~~~~~~~~~~~~~~~~~~ - -:ref:`Values ` and :ref:`results ` can be classified by :ref:`value types ` and :ref:`result types ` as follows. - -:ref:`Values ` :math:`t.\CONST~c` -............................................. - -* The value is valid with :ref:`value type ` :math:`t`. - -.. math:: - \frac{ - }{ - \vdashval t.\CONST~c : t - } +Results +~~~~~~~ +:ref:`Results ` can be classified by :ref:`result types ` as follows. :ref:`Results ` :math:`\val^\ast` ................................................ @@ -54,9 +41,9 @@ Values and Results .. math:: \frac{ - (\vdashval \val : t)^\ast + (S \vdashval \val : t)^\ast }{ - \vdashresult \val^\ast : [t^\ast] + S \vdashresult \val^\ast : [t^\ast] } @@ -68,7 +55,7 @@ Values and Results .. math:: \frac{ }{ - \vdashresult \TRAP : [t^\ast] + S \vdashresult \TRAP : [t^\ast] } @@ -100,6 +87,10 @@ Module instances are classified by *module contexts*, which are regular :ref:`co * Each :ref:`global instance ` :math:`\globalinst_i` in :math:`S.\SGLOBALS` must be :ref:`valid ` with some :ref:`global type ` :math:`\globaltype_i`. +* Each :ref:`element instance ` :math:`\eleminst_i` in :math:`S.\SELEMS` must be :ref:`valid `. + +* Each :ref:`data instance ` :math:`\datainst_i` in :math:`S.\SDATAS` must be :ref:`valid `. + * Then the store is valid. .. math:: @@ -114,11 +105,17 @@ Module instances are classified by *module contexts*, which are regular :ref:`co \qquad (S \vdashglobalinst \globalinst : \globaltype)^\ast \\ + (S \vdasheleminst \eleminst \ok)^\ast + \qquad + (S \vdashdatainst \datainst \ok)^\ast + \\ S = \{ \SFUNCS~\funcinst^\ast, \STABLES~\tableinst^\ast, \SMEMS~\meminst^\ast, - \SGLOBALS~\globalinst^\ast \} + \SGLOBALS~\globalinst^\ast, + \SELEMS~\eleminst^\ast, + \SDATAS~\datainst^\ast \} \end{array} }{ \vdashstore S \ok @@ -183,7 +180,7 @@ Module instances are classified by *module contexts*, which are regular :ref:`co \forall S_1, \val^\ast,~ {\vdashstore S_1 \ok} \wedge {\vdashstoreextends S \extendsto S_1} \wedge - {\vdashresult \val^\ast : [t_1^\ast]} + {S_1 \vdashresult \val^\ast : [t_1^\ast]} \Longrightarrow {} \\ \qquad \X{hf}(S_1; \val^\ast) \supset \emptyset \wedge {} \\ \qquad \forall R \in \X{hf}(S_1; \val^\ast),~ @@ -191,7 +188,7 @@ Module instances are classified by *module contexts*, which are regular :ref:`co \exists S_2, \result,~ {\vdashstore S_2 \ok} \wedge {\vdashstoreextends S_1 \extendsto S_2} \wedge - {\vdashresult \result : [t_2^\ast]} \wedge + {S_2 \vdashresult \result : [t_2^\ast]} \wedge R = (S_2; \result) \end{array} }{ @@ -209,59 +206,107 @@ Module instances are classified by *module contexts*, which are regular :ref:`co .. index:: table type, table instance, limits, function address .. _valid-tableinst: -:ref:`Table Instances ` :math:`\{ \TIELEM~(\X{fa}^?)^n, \TIMAX~m^? \}` -.............................................................................................. +:ref:`Table Instances ` :math:`\{ \TITYPE~(\limits~t), \TIELEM~\reff^\ast \}` +............................................................................................... -* For each optional :ref:`function address ` :math:`\X{fa}^?_i` in the table elements :math:`(\X{fa}^?)^n`: +* The :ref:`table type ` :math:`\limits~t` must be :ref:`valid `. - * Either :math:`\X{fa}^?_i` is empty. +* The length of :math:`\reff^\ast` must equal :math:`\limits.\LMIN`. - * Or the :ref:`external value ` :math:`\EVFUNC~\X{fa}` must be :ref:`valid ` with some :ref:`external type ` :math:`\ETFUNC~\X{ft}`. +* For each :ref:`reference ` :math:`\reff_i` in the table's elements :math:`\reff^n`: -* The :ref:`limits ` :math:`\{\LMIN~n, \LMAX~m^?\}` must be :ref:`valid ` within range :math:`2^{32}`. + * The :ref:`reference ` :math:`\reff_i` must be :ref:`valid ` with :ref:`reference type ` :math:`t`. -* Then the table instance is valid with :ref:`table type ` :math:`\{\LMIN~n, \LMAX~m^?\}~\FUNCREF`. +* Then the table instance is valid with :ref:`table type ` :math:`\limits~t`. .. math:: \frac{ - ((S \vdash \EVFUNC~\X{fa} : \ETFUNC~\functype)^?)^n + \vdashtabletype \limits~t \ok \qquad - \vdashlimits \{\LMIN~n, \LMAX~m^?\} : 2^{32} + n = \limits.\LMIN + \qquad + (S \vdash \reff : t)^n }{ - S \vdashtableinst \{ \TIELEM~(\X{fa}^?)^n, \TIMAX~m^? \} : \{\LMIN~n, \LMAX~m^?\}~\FUNCREF + S \vdashtableinst \{ \TITYPE~(\limits~t), \TIELEM~\reff^n \} : \limits~t } .. index:: memory type, memory instance, limits, byte .. _valid-meminst: -:ref:`Memory Instances ` :math:`\{ \MIDATA~b^n, \MIMAX~m^? \}` -.............................................................................. +:ref:`Memory Instances ` :math:`\{ \MITYPE~\limits, \MIDATA~b^\ast \}` +...................................................................................... + +* The :ref:`memory type ` :math:`\{\LMIN~n, \LMAX~m^?\}` must be :ref:`valid `. -* The :ref:`limits ` :math:`\{\LMIN~n, \LMAX~m^?\}` must be :ref:`valid ` within range :math:`2^{16}`. +* The length of :math:`b^\ast` must equal :math:`\limits.\LMIN` multiplied by the :ref:`page size ` :math:`64\,\F{Ki}`. -* Then the memory instance is valid with :ref:`memory type ` :math:`\{\LMIN~n, \LMAX~m^?\}`. +* Then the memory instance is valid with :ref:`memory type ` :math:`\limits`. .. math:: \frac{ - \vdashlimits \{\LMIN~n, \LMAX~m^?\} : 2^{16} + \vdashmemtype \limits \ok + \qquad + n = \limits.\LMIN \cdot 64\,\F{Ki} }{ - S \vdashmeminst \{ \MIDATA~b^n, \MIMAX~m^? \} : \{\LMIN~n, \LMAX~m^?\} + S \vdashmeminst \{ \MITYPE~\limits, \MIDATA~b^n \} : \limits } .. index:: global type, global instance, value, mutability .. _valid-globalinst: -:ref:`Global Instances ` :math:`\{ \GIVALUE~(t.\CONST~c), \GIMUT~\mut \}` -............................................................................................ +:ref:`Global Instances ` :math:`\{ \GITYPE~(\mut~t), \GIVALUE~\val \}` +......................................................................................... + +* The :ref:`global type ` :math:`\mut~t` must be :ref:`valid `. + +* The :ref:`value ` :math:`\val` must be :ref:`valid ` with :ref:`value type ` :math:`t`. + +* Then the global instance is valid with :ref:`global type ` :math:`\mut~t`. + +.. math:: + \frac{ + \vdashglobaltype \mut~t \ok + \qquad + S \vdashval \val : t + }{ + S \vdashglobalinst \{ \GITYPE~(\mut~t), \GIVALUE~\val \} : \mut~t + } + + +.. index:: element instance, reference +.. _valid-eleminst: + +:ref:`Element Instances ` :math:`\{ \EIELEM~\X{fa}^\ast \}` +............................................................................ + +* For each :ref:`reference ` :math:`\reff_i` in the elements :math:`\reff^n`: + + * The :ref:`reference ` :math:`\reff_i` must be :ref:`valid ` with :ref:`reference type ` :math:`t`. + +* Then the table instance is valid. + +.. math:: + \frac{ + (S \vdash \reff : t)^\ast + }{ + S \vdasheleminst \{ \EITYPE~t, \EIELEM~\reff^\ast \} \ok + } + -* The global instance is valid with :ref:`global type ` :math:`\mut~t`. +.. index:: data instance, byte +.. _valid-datainst: + +:ref:`Data Instances ` :math:`\{ \DIDATA~b^\ast \}` +.................................................................... + +* The data instance is valid. .. math:: \frac{ }{ - S \vdashglobalinst \{ \GIVALUE~(t.\CONST~c), \GIMUT~\mut \} : \mut~t + S \vdashdatainst \{ \DIDATA~b^\ast \} \ok } @@ -299,6 +344,10 @@ Module instances are classified by *module contexts*, which are regular :ref:`co * For each :ref:`global address ` :math:`\globaladdr_i` in :math:`\moduleinst.\MIGLOBALS`, the :ref:`external value ` :math:`\EVGLOBAL~\globaladdr_i` must be :ref:`valid ` with some :ref:`external type ` :math:`\ETGLOBAL~\globaltype_i`. +* For each :ref:`element address ` :math:`\elemaddr_i` in :math:`\moduleinst.\MIELEMS`, the :ref:`element instance ` :math:`S.\SELEMS[\elemaddr_i]` must be :ref:`valid `. + +* For each :ref:`data address ` :math:`\dataaddr_i` in :math:`\moduleinst.\MIDATAS`, the :ref:`data instance ` :math:`S.\SDATAS[\dataaddr_i]` must be :ref:`valid `. + * Each :ref:`export instance ` :math:`\exportinst_i` in :math:`\moduleinst.\MIEXPORTS` must be :ref:`valid `. * For each :ref:`export instance ` :math:`\exportinst_i` in :math:`\moduleinst.\MIEXPORTS`, the :ref:`name ` :math:`\exportinst_i.\EINAME` must be different from any other name occurring in :math:`\moduleinst.\MIEXPORTS`. @@ -327,6 +376,10 @@ Module instances are classified by *module contexts*, which are regular :ref:`co \qquad (S \vdashexternval \EVGLOBAL~\globaladdr : \ETGLOBAL~\globaltype)^\ast \\ + (S \vdasheleminst S.\SELEMS[\elemaddr] \ok)^\ast + \qquad + (S \vdashdatainst S.\SDATAS[\dataaddr] \ok)^\ast + \\ (S \vdashexportinst \exportinst \ok)^\ast \qquad (\exportinst.\EINAME)^\ast ~\mbox{disjoint} @@ -338,7 +391,9 @@ Module instances are classified by *module contexts*, which are regular :ref:`co \MIFUNCS & \funcaddr^\ast, \\ \MITABLES & \tableaddr^\ast, \\ \MIMEMS & \memaddr^\ast, \\ - \MIGLOBALS & \globaladdr^\ast \\ + \MIGLOBALS & \globaladdr^\ast, \\ + \MIELEMS & \elemaddr^\ast, \\ + \MIDATAS & \dataaddr^\ast, \\ \MIEXPORTS & \exportinst^\ast ~\} : \{ \begin{array}[t]{@{}l@{~}l@{}} \CTYPES & \functype^\ast, \\ @@ -437,7 +492,7 @@ Finally, :ref:`frames ` are classified with *frame contexts*, whic \frac{ S \vdashmoduleinst \moduleinst : C \qquad - (\vdashval \val : t)^\ast + (S \vdashval \val : t)^\ast }{ S \vdashframe \{\ALOCALS~\val^\ast, \AMODULE~\moduleinst\} : (C, \CLOCALS~t^\ast) } @@ -468,68 +523,51 @@ To that end, all previous typing judgements :math:`C \vdash \X{prop}` are genera } -.. index:: function address, extern value, extern type, function type - -:math:`\INVOKE~\funcaddr` -......................... +.. index:: extern address -* The :ref:`external function value ` :math:`\EVFUNC~\funcaddr` must be :ref:`valid ` with :ref:`external function type ` :math:`\ETFUNC ([t_1^\ast] \to [t_2^\ast])`. +:math:`\REFEXTERNADDR~\externaddr` +.................................. -* Then the instruction is valid with type :math:`[t_1^\ast] \to [t_2^\ast]`. +* The instruction is valid with type :math:`[] \to [\EXTERNREF]`. .. math:: \frac{ - S \vdashexternval \EVFUNC~\funcaddr : \ETFUNC~[t_1^\ast] \to [t_2^\ast] }{ - S; C \vdashadmininstr \INVOKE~\funcaddr : [t_1^\ast] \to [t_2^\ast] + S; C \vdashadmininstr \REFEXTERNADDR~\externaddr : [] \to [\EXTERNREF] } -.. index:: element, table, table address, module instance, function index - -:math:`\INITELEM~\tableaddr~o~x^n` -.................................. - -* The :ref:`external table value ` :math:`\EVTABLE~\tableaddr` must be :ref:`valid ` with some :ref:`external table type ` :math:`\ETTABLE~\limits~\FUNCREF`. - -* The index :math:`o + n` must be smaller than or equal to :math:`\limits.\LMIN`. +.. index:: function address, extern value, extern type, function type -* The :ref:`module instance ` :math:`\moduleinst` must be :ref:`valid ` with some :ref:`context ` :math:`C`. +:math:`\REFFUNCADDR~\funcaddr` +.............................. -* Each :ref:`function index ` :math:`x_i` in :math:`x^n` must be defined in the context :math:`C`. +* 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. +* Then the instruction is valid with type :math:`[] \to [\FUNCREF]`. .. math:: \frac{ - S \vdashexternval \EVTABLE~\tableaddr : \ETTABLE~\limits~\FUNCREF - \qquad - o + n \leq \limits.\LMIN - \qquad - (C.\CFUNCS[x] = \functype)^n + S \vdashexternval \EVFUNC~\funcaddr : \ETFUNC~\functype }{ - S; C \vdashadmininstr \INITELEM~\tableaddr~o~x^n \ok + S; C \vdashadmininstr \REFFUNCADDR~\funcaddr : [] \to [\FUNCREF] } -.. index:: data, memory, memory address, byte - -:math:`\INITDATA~\memaddr~o~b^n` -................................ +.. index:: function address, extern value, extern type, function type -* The :ref:`external memory value ` :math:`\EVMEM~\memaddr` must be :ref:`valid ` with some :ref:`external memory type ` :math:`\ETMEM~\limits`. +:math:`\INVOKE~\funcaddr` +......................... -* The index :math:`o + n` must be smaller than or equal to :math:`\limits.\LMIN` divided by the :ref:`page size ` :math:`64\,\F{Ki}`. +* The :ref:`external function value ` :math:`\EVFUNC~\funcaddr` must be :ref:`valid ` with :ref:`external function type ` :math:`\ETFUNC ([t_1^\ast] \to [t_2^\ast])`. -* Then the instruction is valid. +* Then the instruction is valid with type :math:`[t_1^\ast] \to [t_2^\ast]`. .. math:: \frac{ - S \vdashexternval \EVMEM~\memaddr : \ETMEM~\limits - \qquad - o + n \leq \limits.\LMIN \cdot 64\,\F{Ki} + S \vdashexternval \EVFUNC~\funcaddr : \ETFUNC~[t_1^\ast] \to [t_2^\ast] }{ - S; C \vdashadmininstr \INITDATA~\memaddr~o~b^n \ok + S; C \vdashadmininstr \INVOKE~\funcaddr : [t_1^\ast] \to [t_2^\ast] } @@ -608,6 +646,10 @@ a store state :math:`S'` extends state :math:`S`, written :math:`S \extendsto S' * The length of :math:`S.\SGLOBALS` must not shrink. +* The length of :math:`S.\SELEMS` must not shrink. + +* The length of :math:`S.\SDATAS` 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. @@ -616,21 +658,31 @@ 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:`data instance ` :math:`\datainst_i` in the original :math:`S.\SDATAS`, the new global instance must be an :ref:`extension ` of the old. + .. math:: \frac{ \begin{array}{@{}ccc@{}} S_1.\SFUNCS = \funcinst_1^\ast & S_2.\SFUNCS = {\funcinst'_1}^\ast~\funcinst_2^\ast & - (\funcinst_1 \extendsto \funcinst'_1)^\ast \\ + (\vdashfuncinstextends \funcinst_1 \extendsto \funcinst'_1)^\ast \\ S_1.\STABLES = \tableinst_1^\ast & S_2.\STABLES = {\tableinst'_1}^\ast~\tableinst_2^\ast & - (\tableinst_1 \extendsto \tableinst'_1)^\ast \\ + (\vdashtableinstextends \tableinst_1 \extendsto \tableinst'_1)^\ast \\ S_1.\SMEMS = \meminst_1^\ast & S_2.\SMEMS = {\meminst'_1}^\ast~\meminst_2^\ast & - (\meminst_1 \extendsto \meminst'_1)^\ast \\ + (\vdashmeminstextends \meminst_1 \extendsto \meminst'_1)^\ast \\ S_1.\SGLOBALS = \globalinst_1^\ast & S_2.\SGLOBALS = {\globalinst'_1}^\ast~\globalinst_2^\ast & - (\globalinst_1 \extendsto \globalinst'_1)^\ast \\ + (\vdashglobalinstextends \globalinst_1 \extendsto \globalinst'_1)^\ast \\ + S_1.\SELEMS = \eleminst_1^\ast & + S_2.\SELEMS = {\eleminst'_1}^\ast~\eleminst_2^\ast & + (\vdasheleminstextends \eleminst_1 \extendsto \eleminst'_1)^\ast \\ + S_1.\SDATAS = \datainst_1^\ast & + S_2.\SDATAS = {\datainst'_1}^\ast~\datainst_2^\ast & + (\vdashdatainstextends \datainst_1 \extendsto \datainst'_1)^\ast \\ \end{array} }{ \vdashstoreextends S_1 \extendsto S_2 @@ -658,15 +710,15 @@ a store state :math:`S'` extends state :math:`S`, written :math:`S \extendsto S' :ref:`Table Instance ` :math:`\tableinst` ........................................................... -* The length of :math:`\tableinst.\TIELEM` must not shrink. +* The :ref:`table type ` :math:`\tableinst.\TITYPE` must remain unchanged. -* The value of :math:`\tableinst.\TIMAX` must remain unchanged. +* The length of :math:`\tableinst.\TIELEM` must not shrink. .. math:: \frac{ n_1 \leq n_2 }{ - \vdashtableinstextends \{\TIELEM~(\X{fa}_1^?)^{n_1}, \TIMAX~m\} \extendsto \{\TIELEM~(\X{fa}_2^?)^{n_2}, \TIMAX~m\} + \vdashtableinstextends \{\TITYPE~\X{tt}, \TIELEM~(\X{fa}_1^?)^{n_1}\} \extendsto \{\TITYPE~\X{tt}, \TIELEM~(\X{fa}_2^?)^{n_2}\} } @@ -676,15 +728,15 @@ a store state :math:`S'` extends state :math:`S`, written :math:`S \extendsto S' :ref:`Memory Instance ` :math:`\meminst` ........................................................ -* The length of :math:`\meminst.\MIDATA` must not shrink. +* The :ref:`memory type ` :math:`\meminst.\MITYPE` must remain unchanged. -* The value of :math:`\meminst.\MIMAX` must remain unchanged. +* The length of :math:`\meminst.\MIDATA` must not shrink. .. math:: \frac{ n_1 \leq n_2 }{ - \vdashmeminstextends \{\MIDATA~b_1^{n_1}, \MIMAX~m\} \extendsto \{\MIDATA~b_2^{n_2}, \MIMAX~m\} + \vdashmeminstextends \{\MITYPE~\X{mt}, \MIDATA~b_1^{n_1}\} \extendsto \{\MITYPE~\X{mt}, \MIDATA~b_2^{n_2}\} } @@ -694,17 +746,49 @@ a store state :math:`S'` extends state :math:`S`, written :math:`S \extendsto S' :ref:`Global Instance ` :math:`\globalinst` .............................................................. -* The :ref:`mutability ` :math:`\globalinst.\GIMUT` must remain unchanged. +* The :ref:`global type ` :math:`\globalinst.\GITYPE` must remain unchanged. + +* Let :math:`\mut~t` be the structure of :math:`\globalinst.\GITYPE`. + +* If :math:`\mut` is |MCONST|, then the :ref:`value ` :math:`\globalinst.\GIVALUE` must remain unchanged. + +.. math:: + \frac{ + \mut = \MVAR \vee \val_1 = \val_2 + }{ + \vdashglobalinstextends \{\GITYPE~(\mut~t), \GIVALUE~\val_1\} \extendsto \{\GITYPE~(\mut~t), \GIVALUE~\val_2\} + } + -* The :ref:`value type ` of the :ref:`value ` :math:`\globalinst.\GIVALUE` must remain unchanged. +.. index:: element instance +.. _extend-eleminst: + +:ref:`Element Instance ` :math:`\eleminst` +........................................................... + +* The vector :math:`\eleminst.\EIELEM` must either remain unchanged or shrink to length :math:`0`. + +.. math:: + \frac{ + \X{fa}_1^\ast = \X{fa}_2^\ast \vee \X{fa}_2^\ast = \epsilon + }{ + \vdasheleminstextends \{\EIELEM~\X{fa}_1^\ast\} \extendsto \{\EIELEM~\X{fa}_2^\ast\} + } + + +.. index:: data instance +.. _extend-datainst: + +:ref:`Data Instance ` :math:`\datainst` +........................................................ -* If :math:`\globalinst.\GIMUT` is |MCONST|, then the :ref:`value ` :math:`\globalinst.\GIVALUE` must remain unchanged. +* The vector :math:`\datainst.\DIDATA` must either remain unchanged or shrink to length :math:`0`. .. math:: \frac{ - \mut = \MVAR \vee c_1 = c_2 + b_1^\ast = b_2^\ast \vee b_2^\ast = \epsilon }{ - \vdashglobalinstextends \{\GIVALUE~(t.\CONST~c_1), \GIMUT~\mut\} \extendsto \{\GIVALUE~(t.\CONST~c_2), \GIMUT~\mut\} + \vdashdatainstextends \{\DIDATA~b_1^\ast\} \extendsto \{\DIDATA~b_2^\ast\} } diff --git a/document/core/binary/conventions.rst b/document/core/binary/conventions.rst index 8d38399773..cacd25134b 100644 --- a/document/core/binary/conventions.rst +++ b/document/core/binary/conventions.rst @@ -59,6 +59,9 @@ In order to distinguish symbols of the binary syntax from symbols of the abstrac * Some productions are augmented by side conditions in parentheses, which restrict the applicability of the production. They provide a shorthand for a combinatorial expansion of the production into many separate cases. +* If the same meta variable or non-terminal symbol appears multiple times in a production (in the syntax or in an attribute), then all those occurrences must have the same instantiation. + (This is a shorthand for a side condition requiring multiple different variables to be equal.) + .. note:: For example, the :ref:`binary grammar ` for :ref:`value types ` is given as follows: diff --git a/document/core/binary/instructions.rst b/document/core/binary/instructions.rst index 0c481b73f8..17aa5f439f 100644 --- a/document/core/binary/instructions.rst +++ b/document/core/binary/instructions.rst @@ -62,7 +62,7 @@ Control Instructions &\Rightarrow& \BRTABLE~l^\ast~l_N \\ &&|& \hex{0F} &\Rightarrow& \RETURN \\ &&|& \hex{10}~~x{:}\Bfuncidx &\Rightarrow& \CALL~x \\ &&|& - \hex{11}~~x{:}\Btypeidx~~\hex{00} &\Rightarrow& \CALLINDIRECT~x \\ + \hex{11}~~y{:}\Btypeidx~~x{:}\Btableidx &\Rightarrow& \CALLINDIRECT~x~y \\ \end{array} .. note:: @@ -75,14 +75,38 @@ Control Instructions of the |CALLINDIRECT| instruction may be used to index additional tables. -.. index:: value type, polymorphism +.. index:: reference instruction + pair: binary format; instruction +.. _binary-instr-ref: + +Reference Instructions +~~~~~~~~~~~~~~~~~~~~~~ + +:ref:`Reference instructions ` are represented by single byte codes. + +.. _binary-ref.null: +.. _binary-ref.isnull: + +.. math:: + \begin{array}{llclll} + \production{instruction} & \Binstr &::=& \dots \\ &&|& + \hex{D0}~~t{:}\Breftype &\Rightarrow& \REFNULL~t \\ &&|& + \hex{D1} &\Rightarrow& \REFISNULL \\ &&|& + \hex{D2}~~x{:}\Bfuncidx &\Rightarrow& \REFFUNC~x \\ + \end{array} + +.. note:: + These opcode assignments are preliminary. + + +.. index:: parametric instruction, value type, polymorphism pair: binary format; instruction .. _binary-instr-parametric: Parametric Instructions ~~~~~~~~~~~~~~~~~~~~~~~ -:ref:`Parametric instructions ` are represented by single byte codes. +:ref:`Parametric instructions ` are represented by single byte codes, possibly followed by a type annotation. .. _binary-drop: .. _binary-select: @@ -91,7 +115,8 @@ Parametric Instructions \begin{array}{llclll} \production{instruction} & \Binstr &::=& \dots \\ &&|& \hex{1A} &\Rightarrow& \DROP \\ &&|& - \hex{1B} &\Rightarrow& \SELECT \\ + \hex{1B} &\Rightarrow& \SELECT \\ &&|& + \hex{1C}~~t^\ast{:}\Bvec(\Bvaltype) &\Rightarrow& \SELECT~t^\ast \\ \end{array} @@ -121,6 +146,37 @@ Variable Instructions \end{array} +.. index:: table instruction, table index + pair: binary format; instruction +.. _binary-instr-table: +.. _binary-table.get: +.. _binary-table.set: +.. _binary-table.size: +.. _binary-table.grow: +.. _binary-table.fill: +.. _binary-table.copy: +.. _binary-table.init: +.. _binary-elem.drop: + +Table Instructions +~~~~~~~~~~~~~~~~~~ + +:ref:`Table instructions ` are represented by either single byte or two byte codes. + +.. math:: + \begin{array}{llclll} + \production{instruction} & \Binstr &::=& \dots \\ &&|& + \hex{25}~~x{:}\Btableidx &\Rightarrow& \TABLEGET~x \\ &&|& + \hex{26}~~x{:}\Btableidx &\Rightarrow& \TABLESET~x \\ &&|& + \hex{FC}~~12{:}\Bu32~~y{:}\Belemidx~~x{:}\Btableidx &\Rightarrow& \TABLEINIT~x~y \\ &&|& + \hex{FC}~~13{:}\Bu32~~x{:}\Belemidx &\Rightarrow& \ELEMDROP~x \\ &&|& + \hex{FC}~~14{:}\Bu32~~x{:}\Btableidx~~y{:}\Btableidx &\Rightarrow& \TABLECOPY~x~y \\ &&|& + \hex{FC}~~15{:}\Bu32~~x{:}\Btableidx &\Rightarrow& \TABLEGROW~x \\ &&|& + \hex{FC}~~16{:}\Bu32~~x{:}\Btableidx &\Rightarrow& \TABLESIZE~x \\ &&|& + \hex{FC}~~17{:}\Bu32~~x{:}\Btableidx &\Rightarrow& \TABLEFILL~x \\ + \end{array} + + .. index:: memory instruction, memory index pair: binary format; instruction .. _binary-instr-memory: @@ -137,6 +193,10 @@ Each variant of :ref:`memory instruction ` is encoded with .. _binary-storen: .. _binary-memory.size: .. _binary-memory.grow: +.. _binary-memory.fill: +.. _binary-memory.copy: +.. _binary-memory.init: +.. _binary-data.drop: .. math:: \begin{array}{llclll} @@ -167,11 +227,15 @@ Each variant of :ref:`memory instruction ` is encoded with \hex{3D}~~m{:}\Bmemarg &\Rightarrow& \I64.\STORE\K{16}~m \\ &&|& \hex{3E}~~m{:}\Bmemarg &\Rightarrow& \I64.\STORE\K{32}~m \\ &&|& \hex{3F}~~\hex{00} &\Rightarrow& \MEMORYSIZE \\ &&|& - \hex{40}~~\hex{00} &\Rightarrow& \MEMORYGROW \\ + \hex{40}~~\hex{00} &\Rightarrow& \MEMORYGROW \\ &&|& + \hex{FC}~~8{:}\Bu32~~x{:}\Bdataidx~\hex{00} &\Rightarrow& \MEMORYINIT~x \\ &&|& + \hex{FC}~~9{:}\Bu32~~x{:}\Bdataidx &\Rightarrow& \DATADROP~x \\ &&|& + \hex{FC}~~10{:}\Bu32~~\hex{00}~~\hex{00} &\Rightarrow& \MEMORYCOPY \\ &&|& + \hex{FC}~~11{:}\Bu32~~\hex{00} &\Rightarrow& \MEMORYFILL \\ \end{array} .. note:: - In future versions of WebAssembly, the additional zero bytes occurring in the encoding of the |MEMORYSIZE| and |MEMORYGROW| instructions may be used to index additional memories. + In future versions of WebAssembly, the additional zero bytes occurring in the encoding of the |MEMORYSIZE|, |MEMORYGROW|, |MEMORYCOPY|, and |MEMORYFILL| instructions may be used to index additional memories. .. index:: numeric instruction diff --git a/document/core/binary/modules.rst b/document/core/binary/modules.rst index e3eba15ccf..8ff6e9d8be 100644 --- a/document/core/binary/modules.rst +++ b/document/core/binary/modules.rst @@ -9,12 +9,14 @@ except that :ref:`function definitions ` are split into two section This separation enables *parallel* and *streaming* compilation of the functions in a module. -.. index:: index, type index, function index, table index, memory index, global index, local index, label index +.. index:: index, type index, function index, table index, memory index, global index, element index, data index, local index, label index pair: binary format; type index pair: binary format; function index pair: binary format; table index pair: binary format; memory index pair: binary format; global index + pair: binary format; element index + pair: binary format; data index pair: binary format; local index pair: binary format; label index .. _binary-typeidx: @@ -22,6 +24,8 @@ except that :ref:`function definitions ` are split into two section .. _binary-tableidx: .. _binary-memidx: .. _binary-globalidx: +.. _binary-elemidx: +.. _binary-dataidx: .. _binary-localidx: .. _binary-labelidx: .. _binary-index: @@ -38,6 +42,8 @@ All :ref:`indices ` are encoded with their respective value. \production{table index} & \Btableidx &::=& x{:}\Bu32 &\Rightarrow& x \\ \production{memory index} & \Bmemidx &::=& x{:}\Bu32 &\Rightarrow& x \\ \production{global index} & \Bglobalidx &::=& x{:}\Bu32 &\Rightarrow& x \\ + \production{element index} & \Belemidx &::=& x{:}\Bu32 &\Rightarrow& x \\ + \production{data index} & \Bdataidx &::=& x{:}\Bu32 &\Rightarrow& x \\ \production{local index} & \Blocalidx &::=& x{:}\Bu32 &\Rightarrow& x \\ \production{label index} & \Blabelidx &::=& l{:}\Bu32 &\Rightarrow& l \\ \end{array} @@ -78,22 +84,23 @@ In these cases, the empty result :math:`\epsilon` is interpreted as the empty ve The following section ids are used: -== ======================================== -Id Section -== ======================================== - 0 :ref:`custom section ` - 1 :ref:`type section ` - 2 :ref:`import section ` - 3 :ref:`function section ` - 4 :ref:`table section ` - 5 :ref:`memory section ` - 6 :ref:`global section ` - 7 :ref:`export section ` - 8 :ref:`start section ` - 9 :ref:`element section ` -10 :ref:`code section ` -11 :ref:`data section ` -== ======================================== +== =============================================== +Id Section +== =============================================== + 0 :ref:`custom section ` + 1 :ref:`type section ` + 2 :ref:`import section ` + 3 :ref:`function section ` + 4 :ref:`table section ` + 5 :ref:`memory section ` + 6 :ref:`global section ` + 7 :ref:`export section ` + 8 :ref:`start section ` + 9 :ref:`element section ` +10 :ref:`code section ` +11 :ref:`data section ` +12 :ref:`data count section ` +== =============================================== .. index:: ! custom section @@ -307,22 +314,47 @@ It decodes into an optional :ref:`start function ` that represents single: element; segment .. _binary-elem: .. _binary-elemsec: +.. _binary-elemkind: Element Section ~~~~~~~~~~~~~~~ The *element section* has the id 9. -It decodes into a vector of :ref:`element segments ` that represent the |MELEM| component of a :ref:`module `. +It decodes into a vector of :ref:`element segments ` that represent the |MELEMS| component of a :ref:`module `. .. math:: \begin{array}{llclll} \production{element section} & \Belemsec &::=& \X{seg}^\ast{:}\Bsection_9(\Bvec(\Belem)) &\Rightarrow& \X{seg} \\ \production{element segment} & \Belem &::=& - x{:}\Btableidx~~e{:}\Bexpr~~y^\ast{:}\Bvec(\Bfuncidx) - &\Rightarrow& \{ \ETABLE~x, \EOFFSET~e, \EINIT~y^\ast \} \\ + \hex{00}~~e{:}\Bexpr~~y^\ast{:}\Bvec(\Bfuncidx) + &\Rightarrow& \{ \ETYPE~\FUNCREF, \EINIT~((\REFFUNC~y)~\END)^\ast, \EMODE~\EACTIVE~\{ \ETABLE~0, \EOFFSET~e \} \} \\ &&|& + \hex{01}~~\X{et}:\Belemkind~~y^\ast{:}\Bvec(\Bfuncidx) + &\Rightarrow& \{ \ETYPE~\X{et}, \EINIT~((\REFFUNC~y)~\END)^\ast, \EMODE~\EPASSIVE \} \\ &&|& + \hex{02}~~x{:}\Btableidx~~e{:}\Bexpr~~\X{et}:\Belemkind~~y^\ast{:}\Bvec(\Bfuncidx) + &\Rightarrow& \{ \ETYPE~\X{et}, \EINIT~((\REFFUNC~y)~\END)^\ast, \EMODE~\EACTIVE~\{ \ETABLE~x, \EOFFSET~e \} \} \\ &&|& + \hex{03}~~\X{et}:\Belemkind~~y^\ast{:}\Bvec(\Bfuncidx) + &\Rightarrow& \{ \ETYPE~\X{et}, \EINIT~((\REFFUNC~y)~\END)^\ast, \EMODE~\EDECLARATIVE \} \\ &&|& + \hex{04}~~e{:}\Bexpr~~\X{el}^\ast{:}\Bvec(\Bexpr) + &\Rightarrow& \{ \ETYPE~\FUNCREF, \EINIT~\X{el}^\ast, \EMODE~\EACTIVE~\{ \ETABLE~0, \EOFFSET~e \} \} \\ &&|& + \hex{05}~~\X{et}:\Breftype~~\X{el}^\ast{:}\Bvec(\Bexpr) + &\Rightarrow& \{ \ETYPE~et, \EINIT~\X{el}^\ast, \EMODE~\EPASSIVE \} \\ &&|& + \hex{06}~~x{:}\Btableidx~~e{:}\Bexpr~~\X{et}:\Breftype~~\X{el}^\ast{:}\Bvec(\Bexpr) + &\Rightarrow& \{ \ETYPE~et, \EINIT~\X{el}^\ast, \EMODE~\EACTIVE~\{ \ETABLE~x, \EOFFSET~e \} \} \\ &&|& + \hex{07}~~\X{et}:\Breftype~~\X{el}^\ast{:}\Bvec(\Bexpr) + &\Rightarrow& \{ \ETYPE~et, \EINIT~\X{el}^\ast, \EMODE~\EDECLARATIVE \} \\ + \production{element kind} & \Belemkind &::=& + \hex{00} &\Rightarrow& \FUNCREF \\ \end{array} +.. note:: + The initial byte can be interpreted as a bitfield. + Bit 0 indicates a passive or declarative segment, + bit 1 indicates the presence of an explicit table index for an active segment and otherwise distinguishes passive from declarative segments, + bit 2 indicates the use of element type and element :ref:`expressions ` instead of element kind and element indices. + + Additional element kinds may be added in future versions of WebAssembly. + .. index:: ! code section, function, local, type index, function type pair: binary format; function @@ -393,17 +425,56 @@ Data Section ~~~~~~~~~~~~ The *data section* has the id 11. -It decodes into a vector of :ref:`data segments ` that represent the |MDATA| component of a :ref:`module `. +It decodes into a vector of :ref:`data segments ` that represent the |MDATAS| component of a :ref:`module `. .. math:: \begin{array}{llclll} \production{data section} & \Bdatasec &::=& \X{seg}^\ast{:}\Bsection_{11}(\Bvec(\Bdata)) &\Rightarrow& \X{seg} \\ \production{data segment} & \Bdata &::=& - x{:}\Bmemidx~~e{:}\Bexpr~~b^\ast{:}\Bvec(\Bbyte) - &\Rightarrow& \{ \DMEM~x, \DOFFSET~e, \DINIT~b^\ast \} \\ + \hex{00}~~e{:}\Bexpr~~b^\ast{:}\Bvec(\Bbyte) + &\Rightarrow& \{ \DINIT~b^\ast, \DMODE~\DACTIVE~\{ \DMEM~0, \DOFFSET~e \} \} \\ &&|& + \hex{01}~~b^\ast{:}\Bvec(\Bbyte) + &\Rightarrow& \{ \DINIT~b^\ast, \DMODE~\DPASSIVE \} \\ &&|& + \hex{02}~~x{:}\Bmemidx~~e{:}\Bexpr~~b^\ast{:}\Bvec(\Bbyte) + &\Rightarrow& \{ \DINIT~b^\ast, \DMODE~\DACTIVE~\{ \DMEM~x, \DOFFSET~e \} \} \\ + \end{array} + +.. note:: + The initial byte can be interpreted as a bitfield. + Bit 0 indicates a passive segment, + bit 1 indicates the presence of an explicit memory index for an active segment. + + In the current version of WebAssembly, at most one memory may be defined or + imported in a single module, so all valid :ref:`active ` data + segments have a |DMEM| value of :math:`0`. + + +.. index:: ! data count section, data count, data segment + pair: binary format; data count + pair: section; data count +.. _binary-datacountsec: + +Data Count Section +~~~~~~~~~~~~~~~~~~ + +The *data count section* has the id 12. +It decodes into an optional :ref:`u32 ` that represents the number of :ref:`data segments ` in the :ref:`data section `. If this count does not match the length of the data segment vector, the module is malformed. + +.. math:: + \begin{array}{llclll} + \production{data count section} & \Bdatacountsec &::=& + \X{n}^?{:}\Bsection_{12}(\Bu32) &\Rightarrow& \X{n}^? \\ \end{array} +.. note:: + The data count section is used to simplify single-pass validation. Since the + data section occurs after the code section, the :math:`\MEMORYINIT` and + :math:`\DATADROP` instructions would not be able to check whether the data + segment index is valid until the data section is read. The data count section + occurs before the code section, so a single-pass validator can use this count + instead of deferring validation. + .. index:: module, section, type definition, function type, function, table, memory, global, element, data, start function, import, export, context, version pair: binary format; module @@ -424,6 +495,9 @@ All sections can be empty. The lengths of vectors produced by the (possibly empty) :ref:`function ` and :ref:`code ` section must match up. +Similarly, the optional data count must match the length of the :ref:`data segment ` vector. +Furthermore, it must be present if any :math:`data index ` occurs in the code section. + .. math:: \begin{array}{llcllll} \production{magic} & \Bmagic &::=& @@ -452,9 +526,11 @@ The lengths of vectors produced by the (possibly empty) :ref:`function `. + Thus, the binary format for types corresponds to the encodings of small negative :math:`\xref{binary/values}{binary-sint}{\sN}` values, so that they can coexist with (positive) type indices in the future. + + +.. index:: number type + pair: binary format; number type +.. _binary-numtype: + +Number Types +~~~~~~~~~~~~ + +:ref:`Number types ` are encoded by a single byte. + +.. math:: + \begin{array}{llclll@{\qquad\qquad}l} + \production{number type} & \Bnumtype &::=& + \hex{7F} &\Rightarrow& \I32 \\ &&|& + \hex{7E} &\Rightarrow& \I64 \\ &&|& + \hex{7D} &\Rightarrow& \F32 \\ &&|& + \hex{7C} &\Rightarrow& \F64 \\ + \end{array} + + +.. index:: reference type + pair: binary format; reference type +.. _binary-reftype: + +Reference Types +~~~~~~~~~~~~~~~ + +:ref:`Reference types ` are also encoded by a single byte. + +.. math:: + \begin{array}{llclll@{\qquad\qquad}l} + \production{reference type} & \Breftype &::=& + \hex{70} &\Rightarrow& \FUNCREF \\ &&|& + \hex{6F} &\Rightarrow& \EXTERNREF \\ + \end{array} + + +.. index:: value type, number type, reference type pair: binary format; value type .. _binary-valtype: Value Types ~~~~~~~~~~~ -:ref:`Value types ` are encoded by a single byte. +:ref:`Value types ` are encoded with their respective encoding as a :ref:`number type ` or :ref:`reference type `. .. math:: \begin{array}{llclll@{\qquad\qquad}l} \production{value type} & \Bvaltype &::=& - \hex{7F} &\Rightarrow& \I32 \\ &&|& - \hex{7E} &\Rightarrow& \I64 \\ &&|& - \hex{7D} &\Rightarrow& \F32 \\ &&|& - \hex{7C} &\Rightarrow& \F64 \\ + t{:}\Bnumtype &\Rightarrow& t \\ &&|& + t{:}\Breftype &\Rightarrow& t \\ \end{array} .. note:: @@ -94,23 +133,19 @@ Memory Types \end{array} -.. index:: table type, element type, limits +.. index:: table type, reference type, limits pair: binary format; table type - pair: binary format; element type -.. _binary-elemtype: .. _binary-tabletype: Table Types ~~~~~~~~~~~ -:ref:`Table types ` are encoded with their :ref:`limits ` and a constant byte indicating their :ref:`element type `. +:ref:`Table types ` are encoded with their :ref:`limits ` and the encoding of their element :ref:`reference type `. .. math:: \begin{array}{llclll} \production{table type} & \Btabletype &::=& - \X{et}{:}\Belemtype~~\X{lim}{:}\Blimits &\Rightarrow& \X{lim}~\X{et} \\ - \production{element type} & \Belemtype &::=& - \hex{70} &\Rightarrow& \FUNCREF \\ + \X{et}{:}\Breftype~~\X{lim}{:}\Blimits &\Rightarrow& \X{lim}~\X{et} \\ \end{array} diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index c54a8fc94f..26f845a66e 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -51,7 +51,7 @@ Where the underlying operators are non-deterministic, because they may return on 1. Push the value :math:`t.\CONST~c` to the stack. .. note:: - No formal reduction rule is required for this instruction, since |CONST| instructions coincide with :ref:`values `. + No formal reduction rule is required for this instruction, since |CONST| instructions already are :ref:`values `. .. _exec-unop: @@ -182,6 +182,71 @@ Where the underlying operators are non-deterministic, because they may return on \end{array} +.. index:: reference instructions, reference + pair: execution; instruction + single: abstract syntax; instruction +.. _exec-instr-ref: + +Reference Instructions +~~~~~~~~~~~~~~~~~~~~~~ + +.. _exec-ref.null: + +:math:`\REFNULL~t` +.................. + +1. Push the value :math:`\REFNULL~t` to the stack. + +.. note:: + No formal reduction rule is required for this instruction, since the |REFNULL| instruction is already a :ref:`value `. + + +.. _exec-ref.is_null: + +:math:`\REFISNULL` +.................. + +1. Assert: due to :ref:`validation `, a :ref:`reference value ` is on the top of the stack. + +2. Pop the value :math:`\val` from the stack. + +3. If :math:`\val` is :math:`\REFNULL~t`, then: + + a. Push the value :math:`\I32.\CONST~1` to the stack. + +4. Else: + + a. Push the value :math:`\I32.\CONST~0` to the stack. + +.. math:: + \begin{array}{lcl@{\qquad}l} + \val~\REFISNULL &\stepto& \I32.\CONST~1 + & (\iff \val = \REFNULL~t) \\ + \val~\REFISNULL &\stepto& \I32.\CONST~0 + & (\otherwise) \\ + \end{array} + + +.. _exec-ref.func: + +:math:`\REFFUNC~x` +.................. + +1. Let :math:`F` be the :ref:`current ` :ref:`frame `. + +2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MIFUNCS[x]` exists. + +3. Let :math:`a` be the :ref:`function address ` :math:`F.\AMODULE.\MIFUNCS[x]`. + +4. Push the value :math:`\REFFUNCADDR~a` to the stack. + +.. math:: + \begin{array}{lcl@{\qquad}l} + F; \REFFUNC~x &\stepto& F; \REFFUNCADDR~a + & (\iff a = F.\AMODULE.\MIFUNCS[x]) \\ + \end{array} + + .. index:: parametric instructions, value pair: execution; instruction single: abstract syntax; instruction @@ -207,8 +272,8 @@ Parametric Instructions .. _exec-select: -:math:`\SELECT` -............... +:math:`\SELECT~(t^\ast)^?` +.......................... 1. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. @@ -230,12 +295,15 @@ Parametric Instructions .. math:: \begin{array}{lcl@{\qquad}l} - \val_1~\val_2~(\I32\K{.}\CONST~c)~\SELECT &\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 &\stepto& \val_2 + \val_1~\val_2~(\I32\K{.}\CONST~c)~\SELECT~t^? &\stepto& \val_2 & (\iff c = 0) \\ \end{array} +.. note:: + In future versions of WebAssembly, |SELECT| may allow more than one value per choice. + .. index:: variable instructions, local index, global index, address, global address, global instance, store, frame, value pair: execution; instruction @@ -371,7 +439,501 @@ Variable Instructions :ref:`Validation ` ensures that the global is, in fact, marked as mutable. -.. index:: memory instruction, memory index, store, frame, address, memory address, memory instance, store, frame, value, integer, limits, value type, bit width +.. index:: table instruction, table index, store, frame, address, table address, table instance, element address, element instance, value, integer, limits, reference, reference type + pair: execution; instruction + single: abstract syntax; instruction +.. _exec-instr-table: + +Table Instructions +~~~~~~~~~~~~~~~~~~ + +.. _exec-table.get: + +:math:`\TABLEGET~x` +................... + +1. Let :math:`F` be the :ref:`current ` :ref:`frame `. + +2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MITABLES[x]` exists. + +3. Let :math:`a` be the :ref:`table address ` :math:`F.\AMODULE.\MITABLES[x]`. + +4. Assert: due to :ref:`validation `, :math:`S.\STABLES[a]` exists. + +5. Let :math:`\X{tab}` be the :ref:`table instance ` :math:`S.\STABLES[a]`. + +6. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +7. Pop the value :math:`\I32.\CONST~i` from the stack. + +8. If :math:`i` is not smaller than the length of :math:`\X{tab}.\TIELEM`, then: + + a. Trap. + +9. Let :math:`\val` be the value :math:`\X{tab}.\TIELEM[i]`. + +10. Push the value :math:`\val` to the stack. + +.. math:: + ~\\[-1ex] + \begin{array}{l} + \begin{array}{lcl@{\qquad}l} + S; F; (\I32.\CONST~i)~(\TABLEGET~x) &\stepto& S; F; \val + \end{array} + \\ \qquad + (\iff S.\STABLES[F.\AMODULE.\MITABLES[x]].\TIELEM[i] = \val) \\ + \begin{array}{lcl@{\qquad}l} + S; F; (\I32.\CONST~i)~(\TABLEGET~x) &\stepto& S; F; \TRAP + \end{array} + \\ \qquad + (\otherwise) \\ + \end{array} + + +.. _exec-table.set: + +:math:`\TABLESET` +................. + +1. Let :math:`F` be the :ref:`current ` :ref:`frame `. + +2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MITABLES[x]` exists. + +3. Let :math:`a` be the :ref:`table address ` :math:`F.\AMODULE.\MITABLES[x]`. + +4. Assert: due to :ref:`validation `, :math:`S.\STABLES[a]` exists. + +5. Let :math:`\X{tab}` be the :ref:`table instance ` :math:`S.\STABLES[a]`. + +6. Assert: due to :ref:`validation `, a :ref:`reference value ` is on the top of the stack. + +7. Pop the value :math:`\val` from the stack. + +8. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +9. Pop the value :math:`\I32.\CONST~i` from the stack. + +10. If :math:`i` is not smaller than the length of :math:`\X{tab}.\TIELEM`, then: + + a. Trap. + +11. Replace the element :math:`\X{tab}.\TIELEM[i]` with :math:`\val`. + +.. math:: + ~\\[-1ex] + \begin{array}{l} + \begin{array}{lcl@{\qquad}l} + S; F; (\I32.\CONST~i)~\val~(\TABLESET~x) &\stepto& S'; F; \epsilon + \end{array} + \\ \qquad + (\iff S' = S \with \STABLES[F.\AMODULE.\MITABLES[x]].\TIELEM[i] = \val) \\ + \begin{array}{lcl@{\qquad}l} + S; F; (\I32.\CONST~i)~\val~(\TABLESET~x) &\stepto& S; F; \TRAP + \end{array} + \\ \qquad + (\otherwise) \\ + \end{array} + + +.. _exec-table.size: + +:math:`\TABLESIZE~x` +.................... + +1. Let :math:`F` be the :ref:`current ` :ref:`frame `. + +2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MITABLES[x]` exists. + +3. Let :math:`a` be the :ref:`table address ` :math:`F.\AMODULE.\MITABLES[x]`. + +4. Assert: due to :ref:`validation `, :math:`S.\STABLES[a]` exists. + +5. Let :math:`\X{tab}` be the :ref:`table instance ` :math:`S.\STABLES[a]`. + +6. Let :math:`\X{sz}` be the length of :math:`\X{tab}.\TIELEM`. + +7. Push the value :math:`\I32.\CONST~\X{sz}` to the stack. + +.. math:: + \begin{array}{l} + \begin{array}{lcl@{\qquad}l} + S; F; \TABLESIZE~x &\stepto& S; F; (\I32.\CONST~\X{sz}) + \end{array} + \\ \qquad + (\iff |S.\STABLES[F.\AMODULE.\MITABLES[x]].\TIELEM| = \X{sz}) \\ + \end{array} + + +.. _exec-table.grow: + +:math:`\TABLEGROW~x` +.................... + +1. Let :math:`F` be the :ref:`current ` :ref:`frame `. + +2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MITABLES[x]` exists. + +3. Let :math:`a` be the :ref:`table address ` :math:`F.\AMODULE.\MITABLES[x]`. + +4. Assert: due to :ref:`validation `, :math:`S.\STABLES[a]` exists. + +5. Let :math:`\X{tab}` be the :ref:`table instance ` :math:`S.\STABLES[a]`. + +6. Let :math:`\X{sz}` be the length of :math:`S.\STABLES[a]`. + +7. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +8. Pop the value :math:`\I32.\CONST~n` from the stack. + +9. Assert: due to :ref:`validation `, a :ref:`reference value ` is on the top of the stack. + +10. Pop the value :math:`\val` from the stack. + +11. Either, try :ref:`growing ` :math:`\X{table}` by :math:`n` entries with initialization value :math:`\val`: + + a. If it succeeds, push the value :math:`\I32.\CONST~\X{sz}` to the stack. + + b. Else, push the value :math:`\I32.\CONST~(-1)` to the stack. + +12. Or, push the value :math:`\I32.\CONST~(-1)` to the stack. + +.. math:: + ~\\[-1ex] + \begin{array}{l} + \begin{array}{lcl@{\qquad}l} + S; F; \val~(\I32.\CONST~n)~\TABLEGROW~x &\stepto& S'; F; (\I32.\CONST~\X{sz}) + \end{array} + \\ \qquad + \begin{array}[t]{@{}r@{~}l@{}} + (\iff & F.\AMODULE.\MITABLES[x] = a \\ + \wedge & \X{sz} = |S.\STABLES[a].\TIELEM| \\ + \wedge & S' = S \with \STABLES[a] = \growtable(S.\STABLES[a], n, \val)) \\ + \end{array} + \\[1ex] + \begin{array}{lcl@{\qquad}l} + S; F; (\I32.\CONST~n)~\TABLEGROW~x &\stepto& S; F; (\I32.\CONST~{-1}) + \end{array} + \end{array} + +.. note:: + The |TABLEGROW| instruction is non-deterministic. + It may either succeed, returning the old table size :math:`\X{sz}`, + or fail, returning :math:`{-1}`. + Failure *must* occur if the referenced table instance has a maximum size defined that would be exceeded. + However, failure *can* occur in other cases as well. + In practice, the choice depends on the :ref:`resources ` available to the :ref:`embedder `. + + +.. _exec-table.fill: + +:math:`\TABLEFILL~x` +.................... + +1. Let :math:`F` be the :ref:`current ` :ref:`frame `. + +2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MITABLES[x]` exists. + +3. Let :math:`\X{ta}` be the :ref:`table address ` :math:`F.\AMODULE.\MITABLES[x]`. + +4. Assert: due to :ref:`validation `, :math:`S.\STABLES[\X{ta}]` exists. + +5. Let :math:`\X{tab}` be the :ref:`table instance ` :math:`S.\STABLES[\X{ta}]`. + +6. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +7. Pop the value :math:`\I32.\CONST~n` from the stack. + +8. Assert: due to :ref:`validation `, a :ref:`reference value ` is on the top of the stack. + +9. Pop the value :math:`\val` from the stack. + +10. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +11. Pop the value :math:`\I32.\CONST~i` from the stack. + +12. If :math:`i + n` is larger than the length of :math:`\X{tab}.\TIELEM`, then: + + a. Trap. + +12. If :math:`n` is :math:`0`, then: + + a. Return. + +13. Push the value :math:`\I32.CONST~i` to the stack. + +14. Push the value :math:`\val` to the stack. + +15. Execute the instruction :math:`\TABLESET~x`. + +16. Push the value :math:`\I32.CONST~(i+1)` to the stack. + +17. Push the value :math:`\val` to the stack. + +18. Push the value :math:`\I32.CONST~(n-1)` to the stack. + +19. Execute the instruction :math:`\TABLEFILL~x`. + +.. math:: + \begin{array}{l} + S; F; (\I32.\CONST~i)~\val~(\I32.\CONST~n)~(\TABLEFILL~x) + \quad\stepto\quad S; F; \TRAP + \\ \qquad + \begin{array}[t]{@{}r@{~}l@{}} + (\iff & i + n > |S.\STABLES[F.\AMODULE.\MITABLES[x]].\TIELEM|) \\ + \end{array} + \\[1ex] + S; F; (\I32.\CONST~i)~\val~(\I32.\CONST~0)~(\TABLEFILL~x) + \quad\stepto\quad S; F; \epsilon + \\ \qquad + (\otherwise) + \\[1ex] + S; F; (\I32.\CONST~i)~\val~(\I32.\CONST~n+1)~(\TABLEFILL~x) + \quad\stepto\quad S; F; + \begin{array}[t]{@{}l@{}} + (\I32.\CONST~i)~\val~(\TABLESET~x) \\ + (\I32.\CONST~i+1)~\val~(\I32.\CONST~n)~(\TABLEFILL~x) \\ + \end{array} + \\ \qquad + (\otherwise) \\ + \end{array} + + +.. _exec-table.copy: + +:math:`\TABLECOPY~x~y` +...................... + +1. Let :math:`F` be the :ref:`current ` :ref:`frame `. + +2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MITABLES[x]` exists. + +3. Let :math:`\X{ta}_x` be the :ref:`table address ` :math:`F.\AMODULE.\MITABLES[x]`. + +4. Assert: due to :ref:`validation `, :math:`S.\STABLES[\X{ta}_x]` exists. + +5. Let :math:`\X{tab}_x` be the :ref:`table instance ` :math:`S.\STABLES[\X{ta}_x]`. + +6. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MITABLES[y]` exists. + +7. Let :math:`\X{ta}_y` be the :ref:`table address ` :math:`F.\AMODULE.\MITABLES[y]`. + +8. Assert: due to :ref:`validation `, :math:`S.\STABLES[\X{ta}_y]` exists. + +9. Let :math:`\X{tab}_y` be the :ref:`table instance ` :math:`S.\STABLES[\X{ta}_y]`. + +10. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +11. Pop the value :math:`\I32.\CONST~n` from the stack. + +12. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +13. Pop the value :math:`\I32.\CONST~s` from the stack. + +14. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +15. Pop the value :math:`\I32.\CONST~d` from the stack. + +16. If :math:`s + n` is larger than the length of :math:`\X{tab}_y.\TIELEM` or :math:`d + n` is larger than the length of :math:`\X{tab}_x.\TIELEM`, then: + + a. Trap. + +17. If :math:`n = 0`, then: + + a. Return. + +18. If :math:`d \leq s`, then: + + a. Push the value :math:`\I32.\CONST~d` to the stack. + + b. Push the value :math:`\I32.\CONST~s` to the stack. + + c. Execute the instruction :math:`\TABLEGET~y`. + + d. Execute the instruction :math:`\TABLESET~x`. + + e. Assert: due to the earlier check against the table size, :math:`d+1 < 2^{32}`. + + f. Push the value :math:`\I32.\CONST~(d+1)` to the stack. + + g. Assert: due to the earlier check against the table size, :math:`s+1 < 2^{32}`. + + h. Push the value :math:`\I32.\CONST~(s+1)` to the stack. + +19. Else: + + a. Assert: due to the earlier check against the table size, :math:`d+n-1 < 2^{32}`. + + b. Push the value :math:`\I32.\CONST~(d+n-1)` to the stack. + + c. Assert: due to the earlier check against the table size, :math:`s+n-1 < 2^{32}`. + + d. Push the value :math:`\I32.\CONST~(s+n-1)` to the stack. + + c. Execute the instruction :math:`\TABLEGET~y`. + + f. Execute the instruction :math:`\TABLESET~x`. + + g. Push the value :math:`\I32.\CONST~d` to the stack. + + h. Push the value :math:`\I32.\CONST~s` to the stack. + +20. Push the value :math:`\I32.\CONST~(n-1)` to the stack. + +21. Execute the instruction :math:`\TABLECOPY~x~y`. + +.. math:: + ~\\[-1ex] + \begin{array}{l} + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n)~(\TABLECOPY~x~y) + \quad\stepto\quad S; F; \TRAP + \\ \qquad + \begin{array}[t]{@{}r@{~}l@{}} + (\iff & s + n > |S.\STABLES[F.\AMODULE.\MITABLES[y]].\TIELEM| \\ + \vee & d + n > |S.\STABLES[F.\AMODULE.\MITABLES[x]].\TIELEM|) \\ + \end{array} + \\[1ex] + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~0)~(\TABLECOPY~x~y) + \quad\stepto\quad S; F; \epsilon + \\ \qquad + (\otherwise) + \\[1ex] + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n+1)~(\TABLECOPY~x~y) + \quad\stepto\quad S; F; + \begin{array}[t]{@{}l@{}} + (\I32.\CONST~d)~(\I32.\CONST~s)~(\TABLEGET~y)~(\TABLESET~x) \\ + (\I32.\CONST~d+1)~(\I32.\CONST~s+1)~(\I32.\CONST~n)~(\TABLECOPY~x~y) \\ + \end{array} + \\ \qquad + (\otherwise, \iff d \leq s) + \\[1ex] + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n+1)~(\TABLECOPY~x~y) + \quad\stepto\quad S; F; + \begin{array}[t]{@{}l@{}} + (\I32.\CONST~d+n-1)~(\I32.\CONST~s+n-1)~(\TABLEGET~y)~(\TABLESET~x) \\ + (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n)~(\TABLECOPY~x~y) \\ + \end{array} + \\ \qquad + (\otherwise, \iff d > s) \\ + \end{array} + + +.. _exec-table.init: + +:math:`\TABLEINIT~x~y` +...................... + +1. Let :math:`F` be the :ref:`current ` :ref:`frame `. + +2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MITABLES[x]` exists. + +3. Let :math:`\X{ta}` be the :ref:`table address ` :math:`F.\AMODULE.\MITABLES[x]`. + +4. Assert: due to :ref:`validation `, :math:`S.\STABLES[\X{ta}]` exists. + +5. Let :math:`\X{tab}` be the :ref:`table instance ` :math:`S.\STABLES[\X{ta}]`. + +6. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MIELEMS[y]` exists. + +7. Let :math:`\X{ea}` be the :ref:`element address ` :math:`F.\AMODULE.\MIELEMS[y]`. + +8. Assert: due to :ref:`validation `, :math:`S.\SELEMS[\X{ea}]` exists. + +9. Let :math:`\X{elem}` be the :ref:`element instance ` :math:`S.\SELEMS[\X{ea}]`. + +10. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +11. Pop the value :math:`\I32.\CONST~n` from the stack. + +12. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +13. Pop the value :math:`\I32.\CONST~s` from the stack. + +14. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +15. Pop the value :math:`\I32.\CONST~d` from the stack. + +16. If :math:`s + n` is larger than the length of :math:`\X{elem}.\EIELEM` or :math:`d + n` is larger than the length of :math:`\X{tab}.\TIELEM`, then: + + a. Trap. + +17. If :math:`n = 0`, then: + + a. Return. + +18. Let :math:`\val` be the :ref:`reference value ` :math:`\X{elem}.\EIELEM[s]`. + +19. Push the value :math:`\I32.\CONST~d` to the stack. + +20. Push the value :math:`\val` to the stack. + +21. Execute the instruction :math:`\TABLESET~x`. + +22. Assert: due to the earlier check against the table size, :math:`d+1 < 2^{32}`. + +23. Push the value :math:`\I32.\CONST~(d+1)` to the stack. + +24. Assert: due to the earlier check against the segment size, :math:`s+1 < 2^{32}`. + +25. Push the value :math:`\I32.\CONST~(s+1)` to the stack. + +26. Push the value :math:`\I32.\CONST~(n-1)` to the stack. + +27. Execute the instruction :math:`\TABLEINIT~x~y`. + +.. math:: + ~\\[-1ex] + \begin{array}{l} + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n)~(\TABLEINIT~x~y) + \quad\stepto\quad S; F; \TRAP + \\ \qquad + \begin{array}[t]{@{}r@{~}l@{}} + (\iff & s + n > |S.\SELEMS[F.\AMODULE.\MIELEMS[y]].\EIELEM| \\ + \vee & d + n > |S.\STABLES[F.\AMODULE.\MITABLES[x]].\TIELEM|) \\ + \end{array} + \\[1ex] + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~0)~(\TABLEINIT~x~y) + \quad\stepto\quad S; F; \epsilon + \\ \qquad + (\otherwise) + \\[1ex] + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n+1)~(\TABLEINIT~x~y) + \quad\stepto\quad S; F; + \begin{array}[t]{@{}l@{}} + (\I32.\CONST~d)~\val~(\TABLESET~x) \\ + (\I32.\CONST~d+1)~(\I32.\CONST~s+1)~(\I32.\CONST~n)~(\TABLEINIT~x~y) \\ + \end{array} + \\ \qquad + (\otherwise, \iff \val = S.\SELEMS[F.\AMODULE.\MIELEMS[x]].\EIELEM[s]) \\ + \end{array} + + +.. _exec-elem.drop: + +:math:`\ELEMDROP~x` +................... + +1. Let :math:`F` be the :ref:`current ` :ref:`frame `. + +2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MIELEMS[x]` exists. + +3. Let :math:`a` be the :ref:`element address ` :math:`F.\AMODULE.\MIELEMS[x]`. + +4. Assert: due to :ref:`validation `, :math:`S.\SELEMS[a]` exists. + +5. Replace :math:`S.\SELEMS[a]` with the :ref:`element instance ` :math:`\{\EIELEM~\epsilon\}`. + +.. math:: + ~\\[-1ex] + \begin{array}{l} + \begin{array}{lcl@{\qquad}l} + S; F; (\ELEMDROP~x) &\stepto& S'; F; \epsilon + \end{array} + \\ \qquad + (\iff S' = S \with \SELEMS[F.\AMODULE.\MIELEMS[x]] = \{ \EIELEM~\epsilon \}) \\ + \end{array} + + +.. index:: memory instruction, memory index, store, frame, address, memory address, memory instance, value, integer, limits, value type, bit width pair: execution; instruction single: abstract syntax; instruction .. _exec-memarg: @@ -520,7 +1082,7 @@ Memory Instructions \begin{array}[t]{@{}r@{~}l@{}} (\iff & \X{ea} = i + \memarg.\OFFSET \\ \wedge & \X{ea} + |t|/8 \leq |S.\SMEMS[F.\AMODULE.\MIMEMS[0]].\MIDATA| \\ - \wedge & S' = S \with \SMEMS[F.\AMODULE.\MIMEMS[0]].\MIDATA[\X{ea} \slice |t|/8] = \bytes_t(c) + \wedge & S' = S \with \SMEMS[F.\AMODULE.\MIMEMS[0]].\MIDATA[\X{ea} \slice |t|/8] = \bytes_t(c)) \end{array} \\[1ex] \begin{array}{lcl@{\qquad}l} @@ -628,6 +1190,312 @@ Memory Instructions In practice, the choice depends on the :ref:`resources ` available to the :ref:`embedder `. +.. _exec-memory.fill: + +:math:`\MEMORYFILL` +................... + +1. Let :math:`F` be the :ref:`current ` :ref:`frame `. + +2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MIMEMS[0]` exists. + +3. Let :math:`\X{ma}` be the :ref:`memory address ` :math:`F.\AMODULE.\MIMEMS[0]`. + +4. Assert: due to :ref:`validation `, :math:`S.\SMEMS[\X{ma}]` exists. + +5. Let :math:`\X{mem}` be the :ref:`memory instance ` :math:`S.\SMEMS[\X{ma}]`. + +6. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +7. Pop the value :math:`\I32.\CONST~n` from the stack. + +8. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +9. Pop the value :math:`\val` from the stack. + +10. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +11. Pop the value :math:`\I32.\CONST~d` from the stack. + +12. If :math:`d + n` is larger than the length of :math:`\X{mem}.\MIDATA`, then: + + a. Trap. + +13. If :math:`n = 0`, then: + + a. Return. + +14. Push the value :math:`\I32.\CONST~d` to the stack. + +15. Push the value :math:`\val` to the stack. + +16. Execute the instruction :math:`\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}`. + +17. Assert: due to the earlier check against the memory size, :math:`d+1 < 2^{32}`. + +18. Push the value :math:`\I32.\CONST~(d+1)` to the stack. + +19. Push the value :math:`\val` to the stack. + +20. Push the value :math:`\I32.\CONST~(n-1)` to the stack. + +21. Execute the instruction :math:`\MEMORYFILL`. + +.. math:: + ~\\[-1ex] + \begin{array}{l} + 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|) \\ + \\[1ex] + S; F; (\I32.\CONST~d)~\val~(\I32.\CONST~0)~\MEMORYFILL + \quad\stepto\quad S; F; \epsilon + \\ \qquad + (\otherwise) + \\[1ex] + S; F; (\I32.\CONST~d)~\val~(\I32.\CONST~n+1)~\MEMORYFILL + \quad\stepto\quad S; F; + \begin{array}[t]{@{}l@{}} + (\I32.\CONST~d)~\val~(\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}) \\ + (\I32.\CONST~d+1)~\val~(\I32.\CONST~n)~\MEMORYFILL \\ + \end{array} + \\ \qquad + (\otherwise) \\ + \end{array} + + +.. _exec-memory.copy: + +:math:`\MEMORYCOPY` +................... + +1. Let :math:`F` be the :ref:`current ` :ref:`frame `. + +2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MIMEMS[0]` exists. + +3. Let :math:`\X{ma}` be the :ref:`memory address ` :math:`F.\AMODULE.\MIMEMS[0]`. + +4. Assert: due to :ref:`validation `, :math:`S.\SMEMS[\X{ma}]` exists. + +5. Let :math:`\X{mem}` be the :ref:`memory instance ` :math:`S.\SMEMS[\X{ma}]`. + +6. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +7. Pop the value :math:`\I32.\CONST~n` from the stack. + +8. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +9. Pop the value :math:`\I32.\CONST~s` from the stack. + +10. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +11. Pop the value :math:`\I32.\CONST~d` from the stack. + +12. If :math:`s + n` is larger than the length of :math:`\X{mem}.\MIDATA` or :math:`d + n` is larger than the length of :math:`\X{mem}.\MIDATA`, then: + + a. Trap. + +13. If :math:`n = 0`, then: + + a. Return. + +14. If :math:`d \leq s`, then: + + a. Push the value :math:`\I32.\CONST~d` to the stack. + + b. Push the value :math:`\I32.\CONST~s` to the stack. + + c. Execute the instruction :math:`\I32\K{.}\LOAD\K{8\_u}~\{ \OFFSET~0, \ALIGN~0 \}`. + + d. Execute the instruction :math:`\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}`. + + e. Assert: due to the earlier check against the memory size, :math:`d+1 < 2^{32}`. + + f. Push the value :math:`\I32.\CONST~(d+1)` to the stack. + + g. Assert: due to the earlier check against the memory size, :math:`s+1 < 2^{32}`. + + h. Push the value :math:`\I32.\CONST~(s+1)` to the stack. + +15. Else: + + a. Assert: due to the earlier check against the memory size, :math:`d+n-1 < 2^{32}`. + + b. Push the value :math:`\I32.\CONST~(d+n-1)` to the stack. + + c. Assert: due to the earlier check against the memory size, :math:`s+n-1 < 2^{32}`. + + d. Push the value :math:`\I32.\CONST~(s+n-1)` to the stack. + + e. Execute the instruction :math:`\I32\K{.}\LOAD\K{8\_u}~\{ \OFFSET~0, \ALIGN~0 \}`. + + f. Execute the instruction :math:`\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}`. + + g. Push the value :math:`\I32.\CONST~d` to the stack. + + h. Push the value :math:`\I32.\CONST~s` to the stack. + +16. Push the value :math:`\I32.\CONST~(n-1)` to the stack. + +17. Execute the instruction :math:`\MEMORYCOPY`. + +.. math:: + ~\\[-1ex] + \begin{array}{l} + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n)~\MEMORYCOPY + \quad\stepto\quad S; F; \TRAP + \\ \qquad + \begin{array}[t]{@{}r@{~}l@{}} + (\iff & s + n > |S.\SMEMS[F.\AMODULE.\MIMEMS[0]].\MIDATA| \\ + \vee & d + n > |S.\SMEMS[F.\AMODULE.\MIMEMS[0]].\MIDATA|) \\ + \end{array} + \\[1ex] + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~0)~\MEMORYCOPY + \quad\stepto\quad S; F; \epsilon + \\ \qquad + (\otherwise) + \\[1ex] + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n+1)~\MEMORYCOPY + \quad\stepto\quad S; F; + \begin{array}[t]{@{}l@{}} + (\I32.\CONST~d) \\ + (\I32.\CONST~s)~(\I32\K{.}\LOAD\K{8\_u}~\{ \OFFSET~0, \ALIGN~0 \}) \\ + (\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}) \\ + (\I32.\CONST~d+1)~(\I32.\CONST~s+1)~(\I32.\CONST~n)~\MEMORYCOPY \\ + \end{array} + \\ \qquad + (\otherwise, \iff d \leq s) + \\[1ex] + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n+1)~\MEMORYCOPY + \quad\stepto\quad S; F; + \begin{array}[t]{@{}l@{}} + (\I32.\CONST~d+n-1) \\ + (\I32.\CONST~s+n-1)~(\I32\K{.}\LOAD\K{8\_u}~\{ \OFFSET~0, \ALIGN~0 \}) \\ + (\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}) \\ + (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n)~\MEMORYCOPY \\ + \end{array} + \\ \qquad + (\otherwise, \iff d > s) \\ + \end{array} + + +.. _exec-memory.init: + +:math:`\MEMORYINIT~x` +..................... + +1. Let :math:`F` be the :ref:`current ` :ref:`frame `. + +2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MIMEMS[0]` exists. + +3. Let :math:`\X{ma}` be the :ref:`memory address ` :math:`F.\AMODULE.\MIMEMS[0]`. + +4. Assert: due to :ref:`validation `, :math:`S.\SMEMS[\X{ma}]` exists. + +5. Let :math:`\X{mem}` be the :ref:`memory instance ` :math:`S.\SMEMS[\X{ma}]`. + +6. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MIDATAS[x]` exists. + +7. Let :math:`\X{da}` be the :ref:`data address ` :math:`F.\AMODULE.\MIDATAS[x]`. + +8. Assert: due to :ref:`validation `, :math:`S.\SDATAS[\X{da}]` exists. + +9. Let :math:`\X{data}` be the :ref:`data instance ` :math:`S.\SDATAS[\X{da}]`. + +10. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +11. Pop the value :math:`\I32.\CONST~cnt` from the stack. + +12. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +13. Pop the value :math:`\I32.\CONST~src` from the stack. + +14. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +15. Pop the value :math:`\I32.\CONST~dst` from the stack. + +16. If :math:`s + n` is larger than the length of :math:`\X{data}.\DIDATA` or :math:`d + n` is larger than the length of :math:`\X{mem}.\MIDATA`, then: + + a. Trap. + +17. If :math:`n = 0`, then: + + a. Return. + +18. Let :math:`b` be the byte :math:`\X{data}.\DIDATA[s]`. + +19. Push the value :math:`\I32.\CONST~d` to the stack. + +20. Push the value :math:`\I32.\CONST~b` to the stack. + +21. Execute the instruction :math:`\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}`. + +22. Assert: due to the earlier check against the memory size, :math:`d+1 < 2^{32}`. + +23. Push the value :math:`\I32.\CONST~(d+1)` to the stack. + +24. Assert: due to the earlier check against the memory size, :math:`s+1 < 2^{32}`. + +25. Push the value :math:`\I32.\CONST~(s+1)` to the stack. + +26. Push the value :math:`\I32.\CONST~(n-1)` to the stack. + +27. Execute the instruction :math:`\MEMORYINIT~x`. + +.. math:: + ~\\[-1ex] + \begin{array}{l} + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n)~(\MEMORYINIT~x) + \quad\stepto\quad S; F; \TRAP + \\ \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|) \\ + \end{array} + \\[1ex] + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~0)~(\MEMORYINIT~x) + \quad\stepto\quad S; F; \epsilon + \\ \qquad + (\otherwise) + \\[1ex] + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n+1)~(\MEMORYINIT~x) + \quad\stepto\quad S; F; + \begin{array}[t]{@{}l@{}} + (\I32.\CONST~d)~(\I32.\CONST~b)~(\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}) \\ + (\I32.\CONST~d+1)~(\I32.\CONST~s+1)~(\I32.\CONST~n)~(\MEMORYINIT~x) \\ + \end{array} + \\ \qquad + (\otherwise, \iff b = S.\SDATAS[F.\AMODULE.\MIDATAS[x]].\DIDATA[s]) \\ + \end{array} + + +.. _exec-data.drop: + +:math:`\DATADROP~x` +................... + +1. Let :math:`F` be the :ref:`current ` :ref:`frame `. + +2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MIDATAS[x]` exists. + +3. Let :math:`a` be the :ref:`data address ` :math:`F.\AMODULE.\MIDATAS[x]`. + +4. Assert: due to :ref:`validation `, :math:`S.\SDATAS[a]` exists. + +5. Replace :math:`S.\SDATAS[a]` with the :ref:`data instance ` :math:`\{\DIDATA~\epsilon\}`. + +.. math:: + ~\\[-1ex] + \begin{array}{l} + \begin{array}{lcl@{\qquad}l} + S; F; (\DATADROP~x) &\stepto& S'; F; \epsilon + \end{array} + \\ \qquad + (\iff S' = S \with \SDATAS[F.\AMODULE.\MIDATAS[x]] = \{ \DIDATA~\epsilon \}) \\ + \end{array} + + .. index:: control instructions, structured control, label, block, branch, result type, label index, function index, type index, vector, address, table address, table instance, store, frame pair: execution; instruction single: abstract syntax; instruction @@ -902,22 +1770,22 @@ Control Instructions .. _exec-call_indirect: -:math:`\CALLINDIRECT~x` -....................... +:math:`\CALLINDIRECT~x~y` +......................... 1. Let :math:`F` be the :ref:`current ` :ref:`frame `. -2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MITABLES[0]` exists. +2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MITABLES[x]` exists. -3. Let :math:`\X{ta}` be the :ref:`table address ` :math:`F.\AMODULE.\MITABLES[0]`. +3. Let :math:`\X{ta}` be the :ref:`table address ` :math:`F.\AMODULE.\MITABLES[x]`. 4. Assert: due to :ref:`validation `, :math:`S.\STABLES[\X{ta}]` exists. 5. Let :math:`\X{tab}` be the :ref:`table instance ` :math:`S.\STABLES[\X{ta}]`. -6. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MITYPES[x]` exists. +6. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MITYPES[y]` exists. -7. Let :math:`\X{ft}_{\F{expect}}` be the :ref:`function type ` :math:`F.\AMODULE.\MITYPES[x]`. +7. Let :math:`\X{ft}_{\F{expect}}` be the :ref:`function type ` :math:`F.\AMODULE.\MITYPES[y]`. 8. Assert: due to :ref:`validation `, a value with :ref:`value type ` |I32| is on the top of the stack. @@ -927,39 +1795,43 @@ Control Instructions a. Trap. -11. If :math:`\X{tab}.\TIELEM[i]` is uninitialized, then: +11. Let :math:`r` be the :ref:`reference ` :math:`\X{tab}.\TIELEM[i]`. + +12. If :math:`r` is :math:`\REFNULL~t`, then: a. Trap. -12. Let :math:`a` be the :ref:`function address ` :math:`\X{tab}.\TIELEM[i]`. +13. Assert: due to :ref:`validation of table mutation `, :math:`r` is a :ref:`function reference `. + +14. Let :math:`\REFFUNCADDR~a` be the :ref:`function reference ` :math:`r`. -13. Assert: due to :ref:`validation `, :math:`S.\SFUNCS[a]` exists. +15. Assert: due to :ref:`validation of table mutation `, :math:`S.\SFUNCS[a]` exists. -14. Let :math:`\X{f}` be the :ref:`function instance ` :math:`S.\SFUNCS[a]`. +16. Let :math:`\X{f}` be the :ref:`function instance ` :math:`S.\SFUNCS[a]`. -15. Let :math:`\X{ft}_{\F{actual}}` be the :ref:`function type ` :math:`\X{f}.\FITYPE`. +17. Let :math:`\X{ft}_{\F{actual}}` be the :ref:`function type ` :math:`\X{f}.\FITYPE`. -16. If :math:`\X{ft}_{\F{actual}}` and :math:`\X{ft}_{\F{expect}}` differ, then: +18. If :math:`\X{ft}_{\F{actual}}` and :math:`\X{ft}_{\F{expect}}` differ, then: a. Trap. -17. :ref:`Invoke ` the function instance at address :math:`a`. +19. :ref:`Invoke ` the function instance at address :math:`a`. .. math:: ~\\[-1ex] \begin{array}{l} \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~i)~(\CALLINDIRECT~x) &\stepto& S; F; (\INVOKE~a) + S; F; (\I32.\CONST~i)~(\CALLINDIRECT~x~y) &\stepto& S; F; (\INVOKE~a) \end{array} \\ \qquad \begin{array}[t]{@{}r@{~}l@{}} - (\iff & S.\STABLES[F.\AMODULE.\MITABLES[0]].\TIELEM[i] = a \\ + (\iff & S.\STABLES[F.\AMODULE.\MITABLES[x]].\TIELEM[i] = \REFFUNCADDR~a \\ \wedge & S.\SFUNCS[a] = f \\ - \wedge & F.\AMODULE.\MITYPES[x] = f.\FITYPE) + \wedge & F.\AMODULE.\MITYPES[y] = f.\FITYPE) \end{array} \\[1ex] \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~i)~(\CALLINDIRECT~x) &\stepto& S; F; \TRAP + S; F; (\I32.\CONST~i)~(\CALLINDIRECT~x~y) &\stepto& S; F; \TRAP \end{array} \\ \qquad (\otherwise) @@ -1051,7 +1923,7 @@ Invocation of :ref:`function address ` :math:`a` 8. Let :math:`\val_0^\ast` be the list of zero values of types :math:`t^\ast`. -9. Let :math:`F` be the :ref:`frame ` :math:`\{ \AMODULE~f.\FIMODULE, \ALOCALS~\val^n~\val_0^\ast \}`. +9. Let :math:`F` be the :ref:`frame ` :math:`\{ \AMODULE~f.\FIMODULE, \ALOCALS~\val^n~(\default_t)^\ast \}`. 10. Push the activation of :math:`F` with arity :math:`m` to the stack. @@ -1070,7 +1942,7 @@ Invocation of :ref:`function address ` :math:`a` (\iff & S.\SFUNCS[a] = f \\ \wedge & f.\FITYPE = [t_1^n] \to [t_2^m] \\ \wedge & f.\FICODE = \{ \FTYPE~x, \FLOCALS~t^k, \FBODY~\instr^\ast~\END \} \\ - \wedge & F = \{ \AMODULE~f.\FIMODULE, ~\ALOCALS~\val^n~(t.\CONST~0)^k \}) + \wedge & F = \{ \AMODULE~f.\FIMODULE, ~\ALOCALS~\val^n~(\default_t)^k \}) \end{array} \\ \end{array} diff --git a/document/core/exec/modules.rst b/document/core/exec/modules.rst index 7f40cf6acf..48d6b03fc8 100644 --- a/document/core/exec/modules.rst +++ b/document/core/exec/modules.rst @@ -23,51 +23,48 @@ The following auxiliary typing rules specify this typing relation relative to a :math:`\EVFUNC~a` ................. -* The store entry :math:`S.\SFUNCS[a]` must be a :ref:`function instance ` :math:`\{\FITYPE~\functype, \dots\}`. +* The store entry :math:`S.\SFUNCS[a]` must exist. -* Then :math:`\EVFUNC~a` is valid with :ref:`external type ` :math:`\ETFUNC~\functype`. +* Then :math:`\EVFUNC~a` is valid with :ref:`external type ` :math:`\ETFUNC~S.\SFUNCS[a].\FITYPE`. .. math:: \frac{ - S.\SFUNCS[a] = \{\FITYPE~\functype, \dots\} }{ - S \vdashexternval \EVFUNC~a : \ETFUNC~\functype + S \vdashexternval \EVFUNC~a : \ETFUNC~S.\SFUNCS[a].\FITYPE } -.. index:: table type, table address, limits +.. index:: table type, table address .. _valid-externval-table: :math:`\EVTABLE~a` .................. -* The store entry :math:`S.\STABLES[a]` must be a :ref:`table instance ` :math:`\{\TIELEM~(\X{fa}^?)^n, \TIMAX~m^?\}`. +* The store entry :math:`S.\STABLES[a]` must exist. -* Then :math:`\EVTABLE~a` is valid with :ref:`external type ` :math:`\ETTABLE~(\{\LMIN~n, \LMAX~m^?\}~\FUNCREF)`. +* Then :math:`\EVTABLE~a` is valid with :ref:`external type ` :math:`\ETTABLE~S.\STABLES[a].\TITYPE`. .. math:: \frac{ - S.\STABLES[a] = \{ \TIELEM~(\X{fa}^?)^n, \TIMAX~m^? \} }{ - S \vdashexternval \EVTABLE~a : \ETTABLE~(\{\LMIN~n, \LMAX~m^?\}~\FUNCREF) + S \vdashexternval \EVTABLE~a : \ETTABLE~S.\STABLES[a].\TITYPE } -.. index:: memory type, memory address, limits +.. index:: memory type, memory address .. _valid-externval-mem: :math:`\EVMEM~a` ................ -* The store entry :math:`S.\SMEMS[a]` must be a :ref:`memory instance ` :math:`\{\MIDATA~b^{n\cdot64\,\F{Ki}}, \MIMAX~m^?\}`, for some :math:`n`. +* The store entry :math:`S.\SMEMS[a]` must exist. -* Then :math:`\EVMEM~a` is valid with :ref:`external type ` :math:`\ETMEM~(\{\LMIN~n, \LMAX~m^?\})`. +* Then :math:`\EVMEM~a` is valid with :ref:`external type ` :math:`\ETMEM~S.\SMEMS[a].\MITYPE`. .. math:: \frac{ - S.\SMEMS[a] = \{ \MIDATA~b^{n\cdot64\,\F{Ki}}, \MIMAX~m^? \} }{ - S \vdashexternval \EVMEM~a : \ETMEM~\{\LMIN~n, \LMAX~m^?\} + S \vdashexternval \EVMEM~a : \ETMEM~S.\SMEMS[a].\MITYPE } @@ -77,140 +74,78 @@ The following auxiliary typing rules specify this typing relation relative to a :math:`\EVGLOBAL~a` ................... -* The store entry :math:`S.\SGLOBALS[a]` must be a :ref:`global instance ` :math:`\{\GIVALUE~(t.\CONST~c), \GIMUT~\mut\}`. +* The store entry :math:`S.\SGLOBALS[a]` must exist. -* Then :math:`\EVGLOBAL~a` is valid with :ref:`external type ` :math:`\ETGLOBAL~(\mut~t)`. +* Then :math:`\EVGLOBAL~a` is valid with :ref:`external type ` :math:`\ETGLOBAL~S.\SGLOBALS[a].\GITYPE`. .. math:: \frac{ - S.\SGLOBALS[a] = \{ \GIVALUE~(t.\CONST~c), \GIMUT~\mut \} }{ - S \vdashexternval \EVGLOBAL~a : \ETGLOBAL~(\mut~t) + S \vdashexternval \EVGLOBAL~a : \ETGLOBAL~S.\SGLOBALS[a].\GITYPE } -.. index:: ! matching, external type -.. _exec-import: -.. _match: - -Import Matching -~~~~~~~~~~~~~~~ - -When :ref:`instantiating ` a module, -:ref:`external values ` must be provided whose :ref:`types ` are *matched* against the respective :ref:`external types ` classifying each import. -In some cases, this allows for a simple form of subtyping, as defined below. - - -.. index:: limits -.. _match-limits: +.. index:: value, value type, validation +.. _valid-val: -Limits -...... +Value Typing +~~~~~~~~~~~~ -:ref:`Limits ` :math:`\{ \LMIN~n_1, \LMAX~m_1^? \}` match limits :math:`\{ \LMIN~n_2, \LMAX~m_2^? \}` if and only if: +For the purpose of checking argument :ref:`values ` against the parameter types of exported :ref:`functions `, +values are classified by :ref:`value types `. +The following auxiliary typing rules specify this typing relation relative to a :ref:`store ` :math:`S` in which possibly referenced addresses live. -* :math:`n_1` is larger than or equal to :math:`n_2`. +.. _valid-num: -* Either: +:ref:`Numeric Values ` :math:`t.\CONST~c` +..................................................... - * :math:`m_2^?` is empty. - -* Or: - - * Both :math:`m_1^?` and :math:`m_2^?` are non-empty. - - * :math:`m_1` is smaller than or equal to :math:`m_2`. +* The value is valid with :ref:`number type ` :math:`t`. .. math:: - ~\\[-1ex] - \frac{ - n_1 \geq n_2 - }{ - \vdashlimitsmatch \{ \LMIN~n_1, \LMAX~m_1^? \} \matches \{ \LMIN~n_2, \LMAX~\epsilon \} - } - \quad \frac{ - n_1 \geq n_2 - \qquad - m_1 \leq m_2 }{ - \vdashlimitsmatch \{ \LMIN~n_1, \LMAX~m_1 \} \matches \{ \LMIN~n_2, \LMAX~m_2 \} + S \vdashval t.\CONST~c : t } +.. _valid-ref: -.. _match-externtype: - -.. index:: function type -.. _match-functype: +:ref:`Null References ` :math:`\REFNULL~t` +...................................................... -Functions -......... - -An :ref:`external type ` :math:`\ETFUNC~\functype_1` matches :math:`\ETFUNC~\functype_2` if and only if: - -* Both :math:`\functype_1` and :math:`\functype_2` are the same. +* The value is valid with :ref:`reference type ` :math:`t`. .. math:: - ~\\[-1ex] \frac{ }{ - \vdashexterntypematch \ETFUNC~\functype \matches \ETFUNC~\functype + S \vdashval \REFNULL~t : t } -.. index:: table type, limits, element type -.. _match-tabletype: +:ref:`Function References ` :math:`\REFFUNCADDR~a` +.............................................................. -Tables -...... +* The :ref:`external value ` :math:`\EVFUNC~a` must be :ref:`valid `. -An :ref:`external type ` :math:`\ETTABLE~(\limits_1~\elemtype_1)` matches :math:`\ETTABLE~(\limits_2~\elemtype_2)` if and only if: - -* Limits :math:`\limits_1` :ref:`match ` :math:`\limits_2`. - -* Both :math:`\elemtype_1` and :math:`\elemtype_2` are the same. +* Then the value is valid with :ref:`reference type ` :math:`\FUNCREF`. .. math:: \frac{ - \vdashlimitsmatch \limits_1 \matches \limits_2 - }{ - \vdashexterntypematch \ETTABLE~(\limits_1~\elemtype) \matches \ETTABLE~(\limits_2~\elemtype) - } - - -.. index:: memory type, limits -.. _match-memtype: - -Memories -........ - -An :ref:`external type ` :math:`\ETMEM~\limits_1` matches :math:`\ETMEM~\limits_2` if and only if: - -* Limits :math:`\limits_1` :ref:`match ` :math:`\limits_2`. - -.. math:: - \frac{ - \vdashlimitsmatch \limits_1 \matches \limits_2 + S \vdashexternval \EVFUNC~a : \ETFUNC~\functype }{ - \vdashexterntypematch \ETMEM~\limits_1 \matches \ETMEM~\limits_2 + S \vdashval \REFFUNCADDR~a : \FUNCREF } -.. index:: global type, value type, mutability -.. _match-globaltype: - -Globals -....... +:ref:`External References ` :math:`\REFEXTERNADDR~a` +....................................................................... -An :ref:`external type ` :math:`\ETGLOBAL~\globaltype_1` matches :math:`\ETGLOBAL~\globaltype_2` if and only if: - -* Both :math:`\globaltype_1` and :math:`\globaltype_2` are the same. +* The value is valid with :ref:`reference type ` :math:`\EXTERNREF`. .. math:: - ~\\[-1ex] \frac{ }{ - \vdashexterntypematch \ETGLOBAL~\globaltype \matches \ETGLOBAL~\globaltype + S \vdashval \REFEXTERNADDR~a : \EXTERNREF } @@ -290,13 +225,13 @@ New instances of :ref:`functions `, :ref:`tables ` ................................ -1. Let :math:`\tabletype` be the :ref:`table type ` to allocate. +1. Let :math:`\tabletype` be the :ref:`table type ` to allocate and :math:`\reff` the initialization value. -2. Let :math:`(\{\LMIN~n, \LMAX~m^?\}~\elemtype)` be the structure of :ref:`table type ` :math:`\tabletype`. +2. Let :math:`(\{\LMIN~n, \LMAX~m^?\}~\reftype)` be the structure of :ref:`table type ` :math:`\tabletype`. 3. Let :math:`a` be the first free :ref:`table address ` in :math:`S`. -4. Let :math:`\tableinst` be the :ref:`table instance ` :math:`\{ \TIELEM~(\epsilon)^n, \TIMAX~m^? \}` with :math:`n` empty elements. +4. Let :math:`\tableinst` be the :ref:`table instance ` :math:`\{ \TITYPE~\tabletype, \TIELEM~\reff^n \}` with :math:`n` elements set to :math:`\reff`. 5. Append :math:`\tableinst` to the |STABLES| of :math:`S`. @@ -304,11 +239,11 @@ New instances of :ref:`functions `, :ref:`tables `, :ref:`tables ` in :math:`S`. -4. Let :math:`\meminst` be the :ref:`memory instance ` :math:`\{ \MIDATA~(\hex{00})^{n \cdot 64\,\F{Ki}}, \MIMAX~m^? \}` that contains :math:`n` pages of zeroed :ref:`bytes `. +4. Let :math:`\meminst` be the :ref:`memory instance ` :math:`\{ \MITYPE~\memtype, \MIDATA~(\hex{00})^{n \cdot 64\,\F{Ki}} \}` that contains :math:`n` pages of zeroed :ref:`bytes `. 5. Append :math:`\meminst` to the |SMEMS| of :math:`S`. @@ -337,7 +272,7 @@ New instances of :ref:`functions `, :ref:`tables `, :ref:`tables ` to allocate and :math:`\val` the :ref:`value ` to initialize the global with. -2. Let :math:`\mut~t` be the structure of :ref:`global type ` :math:`\globaltype`. +2. Let :math:`a` be the first free :ref:`global address ` in :math:`S`. -3. Let :math:`a` be the first free :ref:`global address ` in :math:`S`. +3. Let :math:`\globalinst` be the :ref:`global instance ` :math:`\{ \GITYPE~\globaltype, \GIVALUE~\val \}`. -4. Let :math:`\globalinst` be the :ref:`global instance ` :math:`\{ \GIVALUE~\val, \GIMUT~\mut \}`. +4. Append :math:`\globalinst` to the |SGLOBALS| of :math:`S`. -5. Append :math:`\globalinst` to the |SGLOBALS| of :math:`S`. - -6. Return :math:`a`. +5. Return :math:`a`. .. math:: \begin{array}{rlll} \allocglobal(S, \globaltype, \val) &=& S', \globaladdr \\[1ex] \mbox{where:} \hfill \\ - \globaltype &=& \mut~t \\ \globaladdr &=& |S.\SGLOBALS| \\ - \globalinst &=& \{ \GIVALUE~\val, \GIMUT~\mut \} \\ + \globalinst &=& \{ \GITYPE~\globaltype, \GIVALUE~\val \} \\ S' &=& S \compose \{\SGLOBALS~\globalinst\} \\ \end{array} +.. index:: element, element instance, element address +.. _alloc-elem: + +:ref:`Element segments ` +......................................... + +1. Let :math:`\reftype` be the elements' type and :math:`\reff^\ast` the vector of :ref:`references ` to allocate. + +2. Let :math:`a` be the first free :ref:`element address ` in :math:`S`. + +3. Let :math:`\eleminst` be the :ref:`element instance ` :math:`\{ \EITYPE~t, \EIELEM~\reff^\ast \}`. + +4. Append :math:`\eleminst` to the |SELEMS| of :math:`S`. + +5. Return :math:`a`. + +.. math:: + \begin{array}{rlll} + \allocelem(S, \reftype, \reff^\ast) &=& S', \elemaddr \\[1ex] + \mbox{where:} \hfill \\ + \elemaddr &=& |S.\SELEMS| \\ + \eleminst &=& \{ \EITYPE~\reftype, \EIELEM~\reff^\ast \} \\ + S' &=& S \compose \{\SELEMS~\eleminst\} \\ + \end{array} + + +.. index:: data, data instance, data address +.. _alloc-data: + +:ref:`Data segments ` +...................................... + +1. Let :math:`\bytes` 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 \}`. + +4. Append :math:`\datainst` to the |SDATAS| of :math:`S`. + +5. Return :math:`a`. + +.. math:: + \begin{array}{rlll} + \allocdata(S, \bytes) &=& S', \dataaddr \\[1ex] + \mbox{where:} \hfill \\ + \dataaddr &=& |S.\SDATAS| \\ + \datainst &=& \{ \DIDATA~\bytes \} \\ + S' &=& S \compose \{\SDATAS~\datainst\} \\ + \end{array} + + .. index:: table, table instance, table address, grow, limits .. _grow-table: Growing :ref:`tables ` ........................................ -1. Let :math:`\tableinst` be the :ref:`table instance ` to grow and :math:`n` the number of elements by which to grow it. +1. Let :math:`\tableinst` be the :ref:`table instance ` to grow, :math:`n` the number of elements by which to grow it, and :math:`\reff` the initialization value. 2. Let :math:`\X{len}` be :math:`n` added to the length of :math:`\tableinst.\TIELEM`. 3. If :math:`\X{len}` is larger than or equal to :math:`2^{32}`, then fail. -4. If :math:`\tableinst.\TIMAX` is not empty and its value is smaller than :math:`\X{len}`, then fail. +4. Let :math:`\limits~t` be the structure of :ref:`table type ` :math:`\tableinst.\TITYPE`. + +5. Let :math:`\limits'` be :math:`\limits` with :math:`\LMIN` updated to :math:`\X{len}`. + +6. If :math:`\limits'` is not :ref:`valid `, then fail. -5. Append :math:`n` empty elements to :math:`\tableinst.\TIELEM`. +7. Append :math:`\reff^n` to :math:`\tableinst.\TIELEM`. + +8. Set :math:`\tableinst.\TITYPE` to the :ref:`table type ` :math:`\limits'~t`. .. math:: \begin{array}{rllll} - \growtable(\tableinst, n) &=& \tableinst \with \TIELEM = \tableinst.\TIELEM~(\epsilon)^n \\ + \growtable(\tableinst, n, \reff) &=& \tableinst \with \TITYPE = \limits'~t \with \TIELEM = \tableinst.\TIELEM~\reff^n \\ && ( \begin{array}[t]{@{}r@{~}l@{}} \iff & \X{len} = n + |\tableinst.\TIELEM| \\ \wedge & \X{len} < 2^{32} \\ - \wedge & (\tableinst.\TIMAX = \epsilon \vee \X{len} \leq \tableinst.\TIMAX)) \\ + \wedge & \limits~t = \tableinst.\TITYPE \\ + \wedge & \limits' = \limits \with \LMIN = \X{len} \\ + \wedge & \vdashlimits \limits' \ok \\ \end{array} \\ \end{array} @@ -413,18 +405,26 @@ Growing :ref:`memories ` 4. If :math:`\X{len}` is larger than :math:`2^{16}`, then fail. -5. If :math:`\meminst.\MIMAX` is not empty and its value is smaller than :math:`\X{len}`, then fail. +5. Let :math:`\limits` be the structure of :ref:`memory type ` :math:`\meminst.\MITYPE`. + +6. Let :math:`\limits'` be :math:`\limits` with :math:`\LMIN` updated to :math:`\X{len}`. + +7. If :math:`\limits'` is not :ref:`valid `, then fail. -6. Append :math:`n` times :math:`64\,\F{Ki}` :ref:`bytes ` with value :math:`\hex{00}` to :math:`\meminst.\MIDATA`. +8. Append :math:`n` times :math:`64\,\F{Ki}` :ref:`bytes ` with value :math:`\hex{00}` to :math:`\meminst.\MIDATA`. + +9. Set :math:`\meminst.\MITYPE` to the :ref:`memory type ` :math:`\limits'`. .. math:: \begin{array}{rllll} - \growmem(\meminst, n) &=& \meminst \with \MIDATA = \meminst.\MIDATA~(\hex{00})^{n \cdot 64\,\F{Ki}} \\ + \growmem(\meminst, n) &=& \meminst \with \MITYPE = \limits' \with \MIDATA = \meminst.\MIDATA~(\hex{00})^{n \cdot 64\,\F{Ki}} \\ && ( \begin{array}[t]{@{}r@{~}l@{}} \iff & \X{len} = n + |\meminst.\MIDATA| / 64\,\F{Ki} \\ \wedge & \X{len} \leq 2^{16} \\ - \wedge & (\meminst.\MIMAX = \epsilon \vee \X{len} \leq \meminst.\MIMAX)) \\ + \wedge & \limits = \meminst.\MITYPE \\ + \wedge & \limits' = \limits \with \LMIN = \X{len} \\ + \wedge & \vdashlimits \limits' \ok \\ \end{array} \\ \end{array} @@ -436,10 +436,10 @@ Growing :ref:`memories ` .................................. The allocation function for :ref:`modules ` requires a suitable list of :ref:`external values ` that are assumed to :ref:`match ` the :ref:`import ` vector of the module, -and a list of initialization :ref:`values ` for the module's :ref:`globals `. +a list of initialization :ref:`values ` for the module's :ref:`globals `, +and list of :ref:`reference ` vectors for the module's :ref:`element segments `. -1. Let :math:`\module` be the :ref:`module ` to allocate and :math:`\externval_{\F{im}}^\ast` the vector of :ref:`external values ` providing the module's imports, -and :math:`\val^\ast` the initialization :ref:`values ` of the module's :ref:`globals `. +1. Let :math:`\module` be the :ref:`module ` to allocate and :math:`\externval_{\F{im}}^\ast` the vector of :ref:`external values ` providing the module's imports, :math:`\val^\ast` the initialization :ref:`values ` of the module's :ref:`globals `, and :math:`(\reff^\ast)^\ast` the :ref:`reference ` vectors of the module's :ref:`element segments `. 2. For each :ref:`function ` :math:`\func_i` in :math:`\module.\MFUNCS`, do: @@ -447,7 +447,10 @@ and :math:`\val^\ast` the initialization :ref:`values ` of the modul 3. For each :ref:`table ` :math:`\table_i` in :math:`\module.\MTABLES`, do: - a. Let :math:`\tableaddr_i` be the :ref:`table address ` resulting from :ref:`allocating ` :math:`\table_i.\TTYPE`. + 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`. 4. For each :ref:`memory ` :math:`\mem_i` in :math:`\module.\MMEMS`, do: @@ -457,23 +460,35 @@ and :math:`\val^\ast` the initialization :ref:`values ` of the modul a. Let :math:`\globaladdr_i` be the :ref:`global address ` resulting from :ref:`allocating ` :math:`\global_i.\GTYPE` with initializer value :math:`\val^\ast[i]`. -6. Let :math:`\funcaddr^\ast` be the the concatenation of the :ref:`function addresses ` :math:`\funcaddr_i` in index order. +6. For each :ref:`element segment ` :math:`\elem_i` in :math:`\module.\MELEMS`, do: -7. Let :math:`\tableaddr^\ast` be the the concatenation of the :ref:`table addresses ` :math:`\tableaddr_i` in index order. + a. Let :math:`\elemaddr_i` be the :ref:`element address ` resulting from :ref:`allocating ` a :ref:`element instance ` of :ref:`reference type ` :math:`\elem_i.\ETYPE` with contents :math:`(\reff^\ast)^\ast[i]`. -8. Let :math:`\memaddr^\ast` be the the concatenation of the :ref:`memory addresses ` :math:`\memaddr_i` in index order. +7. For each :ref:`data segment ` :math:`\data_i` in :math:`\module.\MDATAS`, do: -9. Let :math:`\globaladdr^\ast` be the the concatenation of the :ref:`global addresses ` :math:`\globaladdr_i` in index order. + a. Let :math:`\dataaddr_i` be the :ref:`data address ` resulting from :ref:`allocating ` a :ref:`data instance ` with contents :math:`\data_i.\DINIT`. -10. Let :math:`\funcaddr_{\F{mod}}^\ast` be the list of :ref:`function addresses ` extracted from :math:`\externval_{\F{im}}^\ast`, concatenated with :math:`\funcaddr^\ast`. +8. Let :math:`\funcaddr^\ast` be the the concatenation of the :ref:`function addresses ` :math:`\funcaddr_i` in index order. -11. Let :math:`\tableaddr_{\F{mod}}^\ast` be the list of :ref:`table addresses ` extracted from :math:`\externval_{\F{im}}^\ast`, concatenated with :math:`\tableaddr^\ast`. +9. Let :math:`\tableaddr^\ast` be the the concatenation of the :ref:`table addresses ` :math:`\tableaddr_i` in index order. -12. Let :math:`\memaddr_{\F{mod}}^\ast` be the list of :ref:`memory addresses ` extracted from :math:`\externval_{\F{im}}^\ast`, concatenated with :math:`\memaddr^\ast`. +10. Let :math:`\memaddr^\ast` be the the concatenation of the :ref:`memory addresses ` :math:`\memaddr_i` in index order. -13. Let :math:`\globaladdr_{\F{mod}}^\ast` be the list of :ref:`global addresses ` extracted from :math:`\externval_{\F{im}}^\ast`, concatenated with :math:`\globaladdr^\ast`. +11. Let :math:`\globaladdr^\ast` be the the concatenation of the :ref:`global addresses ` :math:`\globaladdr_i` in index order. -14. For each :ref:`export ` :math:`\export_i` in :math:`\module.\MEXPORTS`, do: +12. Let :math:`\elemaddr^\ast` be the the concatenation of the :ref:`element addresses ` :math:`\elemaddr_i` in index order. + +13. Let :math:`\dataaddr^\ast` be the the concatenation of the :ref:`data addresses ` :math:`\dataaddr_i` in index order. + +14. Let :math:`\funcaddr_{\F{mod}}^\ast` be the list of :ref:`function addresses ` extracted from :math:`\externval_{\F{im}}^\ast`, concatenated with :math:`\funcaddr^\ast`. + +15. Let :math:`\tableaddr_{\F{mod}}^\ast` be the list of :ref:`table addresses ` extracted from :math:`\externval_{\F{im}}^\ast`, concatenated with :math:`\tableaddr^\ast`. + +16. Let :math:`\memaddr_{\F{mod}}^\ast` be the list of :ref:`memory addresses ` extracted from :math:`\externval_{\F{im}}^\ast`, concatenated with :math:`\memaddr^\ast`. + +17. Let :math:`\globaladdr_{\F{mod}}^\ast` be the list of :ref:`global addresses ` extracted from :math:`\externval_{\F{im}}^\ast`, concatenated with :math:`\globaladdr^\ast`. + +18. For each :ref:`export ` :math:`\export_i` in :math:`\module.\MEXPORTS`, do: a. If :math:`\export_i` is a function export for :ref:`function index ` :math:`x`, then let :math:`\externval_i` be the :ref:`external value ` :math:`\EVFUNC~(\funcaddr_{\F{mod}}^\ast[x])`. @@ -485,17 +500,18 @@ and :math:`\val^\ast` the initialization :ref:`values ` of the modul e. Let :math:`\exportinst_i` be the :ref:`export instance ` :math:`\{\EINAME~(\export_i.\ENAME), \EIVALUE~\externval_i\}`. -15. Let :math:`\exportinst^\ast` be the the concatenation of the :ref:`export instances ` :math:`\exportinst_i` in index order. +19. Let :math:`\exportinst^\ast` be the the concatenation of the :ref:`export instances ` :math:`\exportinst_i` in index order. -16. Let :math:`\moduleinst` be the :ref:`module instance ` :math:`\{\MITYPES~(\module.\MTYPES),` :math:`\MIFUNCS~\funcaddr_{\F{mod}}^\ast,` :math:`\MITABLES~\tableaddr_{\F{mod}}^\ast,` :math:`\MIMEMS~\memaddr_{\F{mod}}^\ast,` :math:`\MIGLOBALS~\globaladdr_{\F{mod}}^\ast,` :math:`\MIEXPORTS~\exportinst^\ast\}`. +20. Let :math:`\moduleinst` be the :ref:`module instance ` :math:`\{\MITYPES~(\module.\MTYPES),` :math:`\MIFUNCS~\funcaddr_{\F{mod}}^\ast,` :math:`\MITABLES~\tableaddr_{\F{mod}}^\ast,` :math:`\MIMEMS~\memaddr_{\F{mod}}^\ast,` :math:`\MIGLOBALS~\globaladdr_{\F{mod}}^\ast,` :math:`\MIEXPORTS~\exportinst^\ast\}`. -17. Return :math:`\moduleinst`. +21. Return :math:`\moduleinst`. .. math:: ~\\ \begin{array}{rlll} - \allocmodule(S, \module, \externval_{\F{im}}^\ast, \val^\ast) &=& S', \moduleinst \end{array} + \allocmodule(S, \module, \externval_{\F{im}}^\ast, \val^\ast, (\reff^\ast)^\ast) &=& S', \moduleinst + \end{array} where: @@ -508,15 +524,22 @@ where: \MITABLES~\evtables(\externval_{\F{im}}^\ast)~\tableaddr^\ast, \\ \MIMEMS~\evmems(\externval_{\F{im}}^\ast)~\memaddr^\ast, \\ \MIGLOBALS~\evglobals(\externval_{\F{im}}^\ast)~\globaladdr^\ast, \\ + \MIELEMS~\elemaddr^\ast, \\ + \MIDATAS~\dataaddr^\ast, \\ \MIEXPORTS~\exportinst^\ast ~\} \end{array} \\[1ex] S_1, \funcaddr^\ast &=& \allocfunc^\ast(S, \module.\MFUNCS, \moduleinst) \\ - S_2, \tableaddr^\ast &=& \alloctable^\ast(S_1, (\table.\TTYPE)^\ast) - \qquad\qquad\qquad~ (\where \table^\ast = \module.\MTABLES) \\ + S_2, \tableaddr^\ast &=& \alloctable^\ast(S_1, (\table.\TTYPE)^\ast, \REFNULL~t) + \qquad\qquad\qquad~ (\where \table^\ast = \module.\MTABLES \\ && + \qquad\qquad\qquad~~ \wedge (\table.\TTYPE)^\ast = (\limits~t)^\ast) \\ S_3, \memaddr^\ast &=& \allocmem^\ast(S_2, (\mem.\MTYPE)^\ast) \qquad\qquad\qquad~ (\where \mem^\ast = \module.\MMEMS) \\ - S', \globaladdr^\ast &=& \allocglobal^\ast(S_3, (\global.\GTYPE)^\ast, \val^\ast) + S_4, \globaladdr^\ast &=& \allocglobal^\ast(S_3, (\global.\GTYPE)^\ast, \val^\ast) \qquad\quad~ (\where \global^\ast = \module.\MGLOBALS) \\ + S_5, \elemaddr^\ast &=& \allocelem^\ast(S_4, (\elem.\ETYPE)^\ast, (\reff^\ast)^\ast) \\ + \qquad\quad~ (\where \elem^\ast = \module.\MELEMS) \\ + S', \dataaddr^\ast &=& \allocdata^\ast(S_5, (\data.\DINIT)^\ast) + \qquad\qquad\qquad~ (\where \data^\ast = \module.\MDATAS) \\ \exportinst^\ast &=& \{ \EINAME~(\export.\ENAME), \EIVALUE~\externval_{\F{ex}} \}^\ast \quad (\where \export^\ast = \module.\MEXPORTS) \\[1ex] \evfuncs(\externval_{\F{ex}}^\ast) &=& (\moduleinst.\MIFUNCS[x])^\ast @@ -591,147 +614,130 @@ It is up to the :ref:`embedder ` to define how such conditions are rep .. _exec-initvals: -5. Let :math:`\val^\ast` be the vector of :ref:`global ` initialization :ref:`values ` determined by :math:`\module` and :math:`\externval^n`. These may be calculated as follows. +5. Let :math:`\moduleinst_{\F{init}}` be the auxiliary module :ref:`instance ` :math:`\{\MIGLOBALS~\evglobals(\externval^n), \MIFUNCS~\moduleinst.\MIFUNCS\}` that only consists of the imported globals and the imported and allocated functions from the final module instance :math:`\moduleinst`, defined below. - a. Let :math:`\moduleinst_{\F{im}}` be the auxiliary module :ref:`instance ` :math:`\{\MIGLOBALS~\evglobals(\externval^n)\}` that only consists of the imported globals. +6. Let :math:`F_{\F{init}}` be the auxiliary :ref:`frame ` :math:`\{ \AMODULE~\moduleinst_{\F{init}}, \ALOCALS~\epsilon \}`. - b. Let :math:`F_{\F{im}}` be the auxiliary :ref:`frame ` :math:`\{ \AMODULE~\moduleinst_{\F{im}}, \ALOCALS~\epsilon \}`. +7. Push the frame :math:`F_{\F{init}}` to the stack. - c. Push the frame :math:`F_{\F{im}}` to the stack. +8. Let :math:`\val^\ast` be the vector of :ref:`global ` initialization :ref:`values ` determined by :math:`\module` and :math:`\externval^n`. These may be calculated as follows. - d. For each :ref:`global ` :math:`\global_i` in :math:`\module.\MGLOBALS`, do: + a. For each :ref:`global ` :math:`\global_i` in :math:`\module.\MGLOBALS`, do: i. Let :math:`\val_i` be the result of :ref:`evaluating ` the initializer expression :math:`\global_i.\GINIT`. - e. Assert: due to :ref:`validation `, the frame :math:`F_{\F{im}}` is now on the top of the stack. - - f. Pop the frame :math:`F_{\F{im}}` from the stack. - -6. Let :math:`\moduleinst` be a new module instance :ref:`allocated ` from :math:`\module` in store :math:`S` with imports :math:`\externval^n` and global initializer values :math:`\val^\ast`, and let :math:`S'` be the extended store produced by module allocation. - -7. Let :math:`F` be the :ref:`frame ` :math:`\{ \AMODULE~\moduleinst, \ALOCALS~\epsilon \}`. - -8. Push the frame :math:`F` to the stack. + b. Assert: due to :ref:`validation `, the frame :math:`F_{\F{init}}` is now on the top of the stack. -9. For each :ref:`element segment ` :math:`\elem_i` in :math:`\module.\MELEM`, do: + c. Let :math:`\val^\ast` be the conatenation of :math:`\val_i` in index order. - a. Let :math:`\X{eoval}_i` be the result of :ref:`evaluating ` the expression :math:`\elem_i.\EOFFSET`. +9. Let :math:`(\reff^\ast)^\ast` be the list of :ref:`reference ` vectors determined by the :ref:`element segments ` in :math:`\module`. These may be calculated as follows. - b. Assert: due to :ref:`validation `, :math:`\X{eoval}_i` is of the form :math:`\I32.\CONST~\X{eo}_i`. + a. For each :ref:`element segment ` :math:`\elem_i` in :math:`\module.\MELEMS`, and for each element :ref:`expression ` :math:`\expr_{ij}` in :math:`\elem_i.\EINIT`, do: - c. Let :math:`\tableidx_i` be the :ref:`table index ` :math:`\elem_i.\ETABLE`. + i. Let :math:`\reff_{ij}` be the result of :ref:`evaluating ` the initializer expression :math:`\expr_{ij}`. - d. Assert: due to :ref:`validation `, :math:`\moduleinst.\MITABLES[\tableidx_i]` exists. + b. Let :math:`\reff^\ast_i` be the concatenation of function elements :math:`\reff_{ij}` in order of index :math:`j`. - e. Let :math:`\tableaddr_i` be the :ref:`table address ` :math:`\moduleinst.\MITABLES[\tableidx_i]`. + c. Let :math:`(\reff^\ast)^\ast` be the concatenation of function element vectors :math:`\reff^\ast_i` in order of index :math:`i`. - f. Assert: due to :ref:`validation `, :math:`S'.\STABLES[\tableaddr_i]` exists. +10. Pop the frame :math:`F_{\F{init}}` from the stack. - g. Let :math:`\tableinst_i` be the :ref:`table instance ` :math:`S'.\STABLES[\tableaddr_i]`. +11. Let :math:`\moduleinst` be a new module instance :ref:`allocated ` from :math:`\module` in store :math:`S` with imports :math:`\externval^n`, global initializer values :math:`\val^\ast`, and element segment contents :math:`(\reff^\ast)^\ast`, and let :math:`S'` be the extended store produced by module allocation. - h. Let :math:`\X{eend}_i` be :math:`\X{eo}_i` plus the length of :math:`\elem_i.\EINIT`. +12. Let :math:`F` be the auxiliary :ref:`frame ` :math:`\{ \AMODULE~\moduleinst, \ALOCALS~\epsilon \}`. - i. If :math:`\X{eend}_i` is larger than the length of :math:`\tableinst_i.\TIELEM`, then: +13. Push the frame :math:`F` to the stack. - i. Fail. +14. For each :ref:`element segment ` :math:`\elem_i` in :math:`\module.\MELEMS` whose :ref:`mode ` is of the form :math:`\EACTIVE~\{ \ETABLE~\tableidx_i, \EOFFSET~\X{einstr}^\ast_i~\END \}`, do: -10. For each :ref:`data segment ` :math:`\data_i` in :math:`\module.\MDATA`, do: + a. Assert: :math:`\tableidx_i` is :math:`0`. - a. Let :math:`\X{doval}_i` be the result of :ref:`evaluating ` the expression :math:`\data_i.\DOFFSET`. + b. Let :math:`n` be the length of the vector :math:`\elem_i.\EINIT`. - b. Assert: due to :ref:`validation `, :math:`\X{doval}_i` is of the form :math:`\I32.\CONST~\X{do}_i`. + c. :ref:`Execute ` the instruction sequence :math:`\X{einstr}^\ast_i`. - c. Let :math:`\memidx_i` be the :ref:`memory index ` :math:`\data_i.\DMEM`. + d. :ref:`Execute ` the instruction :math:`\I32.\CONST~0`. - d. Assert: due to :ref:`validation `, :math:`\moduleinst.\MIMEMS[\memidx_i]` exists. + e. :ref:`Execute ` the instruction :math:`\I32.\CONST~n`. - e. Let :math:`\memaddr_i` be the :ref:`memory address ` :math:`\moduleinst.\MIMEMS[\memidx_i]`. + f. :ref:`Execute ` the instruction :math:`\TABLEINIT~i`. - f. Assert: due to :ref:`validation `, :math:`S'.\SMEMS[\memaddr_i]` exists. + g. :ref:`Execute ` the instruction :math:`\ELEMDROP~i`. - g. Let :math:`\meminst_i` be the :ref:`memory instance ` :math:`S'.\SMEMS[\memaddr_i]`. +15. For each :ref:`data segment ` :math:`\data_i` in :math:`\module.\MDATAS` whose :ref:`mode ` is of the form :math:`\DACTIVE~\{ \DMEM~\memidx_i, \DOFFSET~\X{dinstr}^\ast_i~\END \}`, do: - h. Let :math:`\X{dend}_i` be :math:`\X{do}_i` plus the length of :math:`\data_i.\DINIT`. + a. Assert: :math:`\memidx_i` is :math:`0`. - i. If :math:`\X{dend}_i` is larger than the length of :math:`\meminst_i.\MIDATA`, then: + b. Let :math:`n` be the length of the vector :math:`\data_i.\DINIT`. - i. Fail. + c. :ref:`Execute ` the instruction sequence :math:`\X{dinstr}^\ast_i`. -11. Assert: due to :ref:`validation `, the frame :math:`F` is now on the top of the stack. + d. :ref:`Execute ` the instruction :math:`\I32.\CONST~0`. -12. Pop the frame from the stack. + e. :ref:`Execute ` the instruction :math:`\I32.\CONST~n`. -13. For each :ref:`element segment ` :math:`\elem_i` in :math:`\module.\MELEM`, do: + f. :ref:`Execute ` the instruction :math:`\MEMORYINIT~i`. - a. For each :ref:`function index ` :math:`\funcidx_{ij}` in :math:`\elem_i.\EINIT` (starting with :math:`j = 0`), do: + g. :ref:`Execute ` the instruction :math:`\DATADROP~i`. - i. Assert: due to :ref:`validation `, :math:`\moduleinst.\MIFUNCS[\funcidx_{ij}]` exists. +16. If the :ref:`start function ` :math:`\module.\MSTART` is not empty, then: - ii. Let :math:`\funcaddr_{ij}` be the :ref:`function address ` :math:`\moduleinst.\MIFUNCS[\funcidx_{ij}]`. + a. Let :math:`\start` be the :ref:`start function ` :math:`\module.\MSTART`. - iii. Replace :math:`\tableinst_i.\TIELEM[\X{eo}_i + j]` with :math:`\funcaddr_{ij}`. + b. :ref:`Execute ` the instruction :math:`\CALL~\start.\SFUNC`. -14. For each :ref:`data segment ` :math:`\data_i` in :math:`\module.\MDATA`, do: +17. Assert: due to :ref:`validation `, the frame :math:`F` is now on the top of the stack. - a. For each :ref:`byte ` :math:`b_{ij}` in :math:`\data_i.\DINIT` (starting with :math:`j = 0`), do: - - i. Replace :math:`\meminst_i.\MIDATA[\X{do}_i + j]` with :math:`b_{ij}`. - -15. If the :ref:`start function ` :math:`\module.\MSTART` is not empty, then: - - a. Assert: due to :ref:`validation `, :math:`\moduleinst.\MIFUNCS[\module.\MSTART.\SFUNC]` exists. - - b. Let :math:`\funcaddr` be the :ref:`function address ` :math:`\moduleinst.\MIFUNCS[\module.\MSTART.\SFUNC]`. - - c. :ref:`Invoke ` the function instance at :math:`\funcaddr`. +18. Pop the frame :math:`F` from the stack. .. math:: ~\\ \begin{array}{@{}rcll} - \instantiate(S, \module, \externval^n) &=& S'; F; + \instantiate(S, \module, \externval^k) &=& S'; F; \begin{array}[t]{@{}l@{}} - (\INITELEM~\tableaddr~\X{eo}~\elem.\EINIT)^\ast \\ - (\INITDATA~\memaddr~\X{do}~\data.\DINIT)^\ast \\ - (\INVOKE~\funcaddr)^? \\ + \F{runelem}_0(\elem^n[0])~\dots~\F{runelem}_{n-1}(\elem^n[n-1]) \\ + \F{rundata}_0(\data^m[0])~\dots~\F{rundata}_{m-1}(\data^m[m-1]) \\ + (\CALL~\start.\SFUNC)^? \\ \end{array} \\ &(\iff - & \vdashmodule \module : \externtype_{\F{im}}^n \to \externtype_{\F{ex}}^\ast \\ - &\wedge& (S \vdashexternval \externval : \externtype)^n \\ - &\wedge& (\vdashexterntypematch \externtype \matches \externtype_{\F{im}})^n \\[1ex] + & \vdashmodule \module : \externtype_{\F{im}}^k \to \externtype_{\F{ex}}^\ast \\ + &\wedge& (S \vdashexternval \externval : \externtype)^k \\ + &\wedge& (\vdashexterntypematch \externtype \matchesexterntype \externtype_{\F{im}})^k \\[1ex] &\wedge& \module.\MGLOBALS = \global^\ast \\ - &\wedge& \module.\MELEM = \elem^\ast \\ - &\wedge& \module.\MDATA = \data^\ast \\ - &\wedge& \module.\MSTART = \start^? \\[1ex] - &\wedge& S', \moduleinst = \allocmodule(S, \module, \externval^n, \val^\ast) \\ + &\wedge& \module.\MELEMS = \elem^n \\ + &\wedge& \module.\MDATAS = \data^m \\ + &\wedge& \module.\MSTART = \start^? \\ + &\wedge& (\expr_{\F{g}} = \global.GINIT)^\ast \\ + &\wedge& (\expr_{\F{e}}^\ast = \elem.EINIT)^n \\[1ex] + &\wedge& S', \moduleinst = \allocmodule(S, \module, \externval^k, \val^\ast, (\reff^\ast)^n) \\ &\wedge& F = \{ \AMODULE~\moduleinst, \ALOCALS~\epsilon \} \\[1ex] - &\wedge& (S'; F; \global.\GINIT \stepto^\ast S'; F; \val~\END)^\ast \\ - &\wedge& (S'; F; \elem.\EOFFSET \stepto^\ast S'; F; \I32.\CONST~\X{eo}~\END)^\ast \\ - &\wedge& (S'; F; \data.\DOFFSET \stepto^\ast S'; F; \I32.\CONST~\X{do}~\END)^\ast \\[1ex] - &\wedge& (\X{eo} + |\elem.\EINIT| \leq |S'.\STABLES[\tableaddr].\TIELEM|)^\ast \\ - &\wedge& (\X{do} + |\data.\DINIT| \leq |S'.\SMEMS[\memaddr].\MIDATA|)^\ast - \\[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])^?) - \\[2ex] - S; F; \INITELEM~a~i~\epsilon &\stepto& - S; F; \epsilon \\ - S; F; \INITELEM~a~i~(x_0~x^\ast) &\stepto& - S'; F; \INITELEM~a~(i+1)~x^\ast \\ && - (\iff S' = S \with \STABLES[a].\TIELEM[i] = F.\AMODULE.\MIFUNCS[x_0]) - \\[1ex] - S; F; \INITDATA~a~i~\epsilon &\stepto& - S; F; \epsilon \\ - S; F; \INITDATA~a~i~(b_0~b^\ast) &\stepto& - S'; F; \INITDATA~a~(i+1)~b^\ast \\ && - (\iff S' = S \with \SMEMS[a].\MIDATA[i] = b_0) + \end{array} + +where: + +.. math:: + \begin{array}{@{}l} + \F{runelem}_i(\{\ETYPE~\X{et}, \EINIT~\reff^n, \EMODE~\EPASSIVE\}) \quad=\quad \epsilon \\ + \F{runelem}_i(\{\ETYPE~\X{et}, \EINIT~\reff^n, \EMODE~\EACTIVE \{\ETABLE~0, \EOFFSET~\instr^\ast~\END\}\}) \quad=\\ \qquad + \instr^\ast~(\I32.\CONST~0)~(\I32.\CONST~n)~(\TABLEINIT~i)~(\ELEMDROP~i) \\ + \F{runelem}_i(\{\ETYPE~\X{et}, \EINIT~\reff^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 + \instr^\ast~(\I32.\CONST~0)~(\I32.\CONST~n)~(\MEMORYINIT~i)~(\DATADROP~i) \\ \end{array} .. note:: - Module :ref:`allocation ` and the :ref:`evaluation ` of :ref:`global ` initializers are mutually recursive because the global initialization :ref:`values ` :math:`\val^\ast` are passed to the module allocator but depend on the store :math:`S'` and module instance :math:`\moduleinst` returned by allocation. + Module :ref:`allocation ` and the :ref:`evaluation ` of :ref:`global ` initializers and :ref:`element segments ` are mutually recursive because the global initialization :ref:`values ` :math:`\val^\ast` and element segment contents :math:`(\reff^\ast)^\ast` are passed to the module allocator while depending on the module instance :math:`\moduleinst` and store :math:`S'` returned by allocation. However, this recursion is just a specification device. - Due to :ref:`validation `, the initialization values can easily :ref:`be determined ` from a simple pre-pass that evaluates global initializers in the initial store. + In practice, the initialization values can :ref:`be determined ` beforehand by staging module allocation such that first, the module's own :math:`function instances ` are pre-allocated in the store, then the initializer expressions are evaluated, then the rest of the module instance is allocated, and finally the new function instances' :math:`\AMODULE` fields are set to that module instance. + This is possible because :ref:`validation ` ensures that initialization expressions cannot actually call a function, only take their reference. All failure conditions are checked before any observable mutation of the store takes place. Store mutation is not atomic; @@ -769,7 +775,7 @@ The following steps are performed: 5. For each :ref:`value type ` :math:`t_i` in :math:`t_1^n` and corresponding :ref:`value ` :math:`val_i` in :math:`\val^\ast`, do: - a. If :math:`\val_i` is not :math:`t_i.\CONST~c_i` for some :math:`c_i`, then: + a. If :math:`\val_i` is not :ref:`valid ` with value type :math:`t_i`, then: i. Fail. @@ -794,6 +800,6 @@ The values :math:`\val_{\F{res}}^m` are returned as the results of the invocatio \begin{array}{@{}lcl} \invoke(S, \funcaddr, \val^n) &=& S; F; \val^n~(\INVOKE~\funcaddr) \\ &(\iff & S.\SFUNCS[\funcaddr].\FITYPE = [t_1^n] \to [t_2^m] \\ - &\wedge& \val^n = (t_1.\CONST~c)^n \\ + &\wedge& (S \vdashval \val : t_1)^n \\ &\wedge& F = \{ \AMODULE~\{\}, \ALOCALS~\epsilon \}) \\ \end{array} diff --git a/document/core/exec/runtime.rst b/document/core/exec/runtime.rst index fc0771d911..c1b65f69da 100644 --- a/document/core/exec/runtime.rst +++ b/document/core/exec/runtime.rst @@ -7,29 +7,62 @@ Runtime Structure :ref:`Store `, :ref:`stack `, and other *runtime structure* forming the WebAssembly abstract machine, such as :ref:`values ` or :ref:`module instances `, are made precise in terms of additional auxiliary syntax. -.. index:: ! value, constant, value type, integer, floating-point +.. index:: ! value, number, reference, constant, number type, reference type, ! host address, value type, integer, floating-point, ! default value pair: abstract syntax; value +.. _syntax-num: +.. _syntax-ref: +.. _syntax-ref.extern: .. _syntax-val: Values ~~~~~~ -WebAssembly computations manipulate *values* of the four basic :ref:`value types `: :ref:`integers ` and :ref:`floating-point data ` of 32 or 64 bit width each, respectively. +WebAssembly computations manipulate *values* of either the four basic :ref:`number types `, i.e., :ref:`integers ` and :ref:`floating-point data ` of 32 or 64 bit width each, or of :ref:`reference type `. In most places of the semantics, values of different types can occur. In order to avoid ambiguities, values are therefore represented with an abstract syntax that makes their type explicit. -It is convenient to reuse the same notation as for the |CONST| :ref:`instructions ` producing them: +It is convenient to reuse the same notation as for the |CONST| :ref:`instructions ` and |REFNULL| producing them. + +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. .. math:: \begin{array}{llcl} - \production{(value)} & \val &::=& + \production{(number)} & \num &::=& \I32.\CONST~\i32 \\&&|& \I64.\CONST~\i64 \\&&|& \F32.\CONST~\f32 \\&&|& - \F64.\CONST~\f64 + \F64.\CONST~\f64 \\ + \production{(reference)} & \reff &::=& + \REFNULL~t \\&&|& + \REFFUNCADDR~\funcaddr \\&&|& + \REFEXTERNADDR~\externaddr \\ + \production{(value)} & \val &::=& + \num ~|~ \reff \\ + \end{array} + +.. note:: + Future versions of WebAssembly may add additional forms of reference. + +.. _default-val: + +Each :ref:`value type ` has an associated *default value*; +it is the respective value :math:`0` for :ref:`number types ` and null for :ref:`reference types `. + +.. math:: + \begin{array}{lcl@{\qquad}l} + \default_t &=& t{.}\CONST~0 & (\iff t = \numtype) \\ + \default_t &=& \REFNULL~t & (\iff t = \reftype) \\ \end{array} +Convention +.......... + +* The meta variable :math:`r` ranges over reference values where clear from context. + + .. index:: ! result, value, trap pair: abstract syntax; result .. _syntax-result: @@ -60,7 +93,9 @@ 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 `, and :ref:`globals ` 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 `, 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 is an invariant of the semantics that no element or data instance is :ref:`addressed ` from anywhere else but the owning module instances. Syntactically, the store is defined as a :ref:`record ` listing the existing instances of each category: @@ -71,7 +106,9 @@ Syntactically, the store is defined as a :ref:`record ` listing \SFUNCS & \funcinst^\ast, \\ \STABLES & \tableinst^\ast, \\ \SMEMS & \meminst^\ast, \\ - \SGLOBALS & \globalinst^\ast ~\} \\ + \SGLOBALS & \globalinst^\ast, \\ + \SELEMS & \eleminst^\ast, \\ + \SDATAS & \datainst^\ast ~\} \\ \end{array} \end{array} @@ -87,26 +124,36 @@ Convention * The meta variable :math:`S` ranges over stores where clear from context. -.. index:: ! address, store, function instance, table instance, memory instance, global instance, embedder +.. index:: ! address, store, function instance, table instance, memory instance, global instance, element instance, data instance, embedder pair: abstract syntax; function address pair: abstract syntax; table address pair: abstract syntax; memory address pair: abstract syntax; global address + pair: abstract syntax; element address + pair: abstract syntax; data address + pair: abstract syntax; host address pair: function; address pair: table; address pair: memory; address pair: global; address + pair: element; address + pair: data; address + pair: host; address .. _syntax-funcaddr: .. _syntax-tableaddr: .. _syntax-memaddr: .. _syntax-globaladdr: +.. _syntax-elemaddr: +.. _syntax-dataaddr: +.. _syntax-externaddr: .. _syntax-addr: Addresses ~~~~~~~~~ -:ref:`Function instances `, :ref:`table instances `, :ref:`memory instances `, and :ref:`global instances ` in the :ref:`store ` are referenced with abstract *addresses*. +:ref:`Function instances `, :ref:`table instances `, :ref:`memory instances `, and :ref:`global instances `, :ref:`element instances `, and :ref:`data 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*. .. math:: \begin{array}{llll} @@ -120,6 +167,12 @@ These are simply indices into the respective store component. \addr \\ \production{(global address)} & \globaladdr &::=& \addr \\ + \production{(element address)} & \elemaddr &::=& + \addr \\ + \production{(data address)} & \dataaddr &::=& + \addr \\ + \production{(extern address)} & \externaddr &::=& + \addr \\ \end{array} An :ref:`embedder ` may assign identity to :ref:`exported ` store objects corresponding to their addresses, @@ -137,7 +190,7 @@ even where this identity is not observable from within WebAssembly code itself hence logical addresses can be arbitrarily large natural numbers. -.. index:: ! instance, function type, function instance, table instance, memory instance, global instance, export instance, table address, memory address, global address, index, name +.. index:: ! instance, function type, function instance, table instance, memory instance, global instance, element instance, data instance, export instance, table address, memory address, global address, element address, data address, index, name pair: abstract syntax; module instance pair: module; instance .. _syntax-moduleinst: @@ -158,6 +211,8 @@ and collects runtime representations of all entities that are imported, defined, \MITABLES & \tableaddr^\ast, \\ \MIMEMS & \memaddr^\ast, \\ \MIGLOBALS & \globaladdr^\ast, \\ + \MIELEMS & \elemaddr^\ast, \\ + \MIDATAS & \dataaddr^\ast, \\ \MIEXPORTS & \exportinst^\ast ~\} \\ \end{array} \end{array} @@ -203,30 +258,24 @@ but within certain :ref:`constraints ` that ensure the integri .. index:: ! table instance, table, function address, table type, embedder, element segment pair: abstract syntax; table instance pair: table; instance -.. _syntax-funcelem: .. _syntax-tableinst: Table Instances ~~~~~~~~~~~~~~~ A *table instance* is the runtime representation of a :ref:`table `. -It holds a vector of *function elements* and an optional maximum size, if one was specified in the :ref:`table type ` at the table's definition site. - -Each function element is either empty, representing an uninitialized table entry, or a :ref:`function address `. -Function elements can be mutated through the execution of an :ref:`element segment ` or by external means provided by the :ref:`embedder `. +It records its :ref:`type ` and holds a vector of :ref:`reference values `. .. math:: \begin{array}{llll} \production{(table instance)} & \tableinst &::=& - \{ \TIELEM~\vec(\funcelem), \TIMAX~\u32^? \} \\ - \production{(function element)} & \funcelem &::=& - \funcaddr^? \\ + \{ \TITYPE~\tabletype, \TIELEM~\vec(\reff) \} \\ \end{array} -It is an invariant of the semantics that the length of the element vector never exceeds the maximum size, if present. +Table elements can be mutated through :ref:`table instructions `, the execution of an active :ref:`element segment `, or by external means provided by the :ref:`embedder `. -.. note:: - Other table elements may be added in future versions of WebAssembly. +It is an invariant of the semantics that all table elements have a type equal to the element type of :math:`\tabletype`. +It also is an invariant that the length of the element vector never exceeds the maximum size of :math:`\tabletype`, if present. .. index:: ! memory instance, memory, byte, ! page size, memory type, embedder, data segment, instruction @@ -239,20 +288,19 @@ Memory Instances ~~~~~~~~~~~~~~~~ A *memory instance* is the runtime representation of a linear :ref:`memory `. -It holds a vector of :ref:`bytes ` and an optional maximum size, if one was specified at the definition site of the memory. +It records its :ref:`type ` and holds a vector of :ref:`bytes `. .. math:: \begin{array}{llll} \production{(memory instance)} & \meminst &::=& - \{ \MIDATA~\vec(\byte), \MIMAX~\u32^? \} \\ + \{ \MITYPE~\memtype, \MIDATA~\vec(\byte) \} \\ \end{array} The length of the vector always is a multiple of the WebAssembly *page size*, which is defined to be the constant :math:`65536` -- abbreviated :math:`64\,\F{Ki}`. -Like in a :ref:`memory type `, the maximum size in a memory instance is given in units of this page size. -The bytes can be mutated through :ref:`memory instructions `, the execution of a :ref:`data segment `, or by external means provided by the :ref:`embedder `. +The bytes can be mutated through :ref:`memory instructions `, the execution of an active :ref:`data segment `, or by external means provided by the :ref:`embedder `. -It is an invariant of the semantics that the length of the byte vector, divided by page size, never exceeds the maximum size, if present. +It is an invariant of the semantics that the length of the byte vector, divided by page size, never exceeds the maximum size of :math:`\memtype`, if present. .. index:: ! global instance, global, value, mutability, instruction, embedder @@ -264,16 +312,54 @@ Global Instances ~~~~~~~~~~~~~~~~ A *global instance* is the runtime representation of a :ref:`global ` variable. -It holds an individual :ref:`value ` and a flag indicating whether it is mutable. +It records its :ref:`type ` and holds an individual :ref:`value `. .. math:: \begin{array}{llll} \production{(global instance)} & \globalinst &::=& - \{ \GIVALUE~\val, \GIMUT~\mut \} \\ + \{ \GITYPE~\valtype, \GIVALUE~\val \} \\ \end{array} The value of mutable globals can be mutated through :ref:`variable instructions ` or by external means provided by the :ref:`embedder `. +It is an invariant of the semantics that the value has a type equal to the :ref:`value type ` of :math:`\globaltype`. + + +.. index:: ! element instance, element segment, embedder, element expression + pair: abstract syntax; element instance + pair: element; instance +.. _syntax-eleminst: + +Element Instances +~~~~~~~~~~~~~~~~~ + +An *element instance* is the runtime representation of an :ref:`element segment `. +It holds a vector of references and their common :ref:`type `. + +.. math:: + \begin{array}{llll} + \production{(element instance)} & \eleminst &::=& + \{ \EITYPE~\reftype, \EIELEM~\vec(\reff) \} \\ + \end{array} + + +.. index:: ! data instance, data segment, embedder, byte + pair: abstract syntax; data instance + pair: data; instance +.. _syntax-datainst: + +Data Instances +~~~~~~~~~~~~~~ + +An *data instance* is the runtime representation of a :ref:`data segment `. +It holds a vector of :ref:`bytes `. + +.. math:: + \begin{array}{llll} + \production{(data instance)} & \datainst &::=& + \{ \DIDATA~\vec(\byte) \} \\ + \end{array} + .. index:: ! export instance, export, name, external value pair: abstract syntax; export instance @@ -429,9 +515,8 @@ Conventions .. index:: ! administrative instructions, function, function instance, function address, label, frame, instruction, trap, call, memory, memory instance, table, table instance, element, data, segment pair:: abstract syntax; administrative instruction .. _syntax-trap: +.. _syntax-reffuncaddr: .. _syntax-invoke: -.. _syntax-init_elem: -.. _syntax-init_data: .. _syntax-instr-admin: Administrative Instructions @@ -447,9 +532,9 @@ In order to express the reduction of :ref:`traps `, :ref:`calls `, :ref:`calls `. Similarly, |REFEXTERNADDR| represents :ref:`external references `. + 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 |INITELEM| and |INITDATA| instructions perform initialization of :ref:`element ` and :ref:`data ` segments during module :ref:`instantiation `. - -.. note:: - The reason for splitting instantiation into individual reduction steps is to provide a semantics that is compatible with future extensions like threads. - The |LABEL| and |FRAME| instructions model :ref:`labels ` and :ref:`frames ` :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. diff --git a/document/core/syntax/conventions.rst b/document/core/syntax/conventions.rst index c0890ba98f..979d6bc4e3 100644 --- a/document/core/syntax/conventions.rst +++ b/document/core/syntax/conventions.rst @@ -41,6 +41,9 @@ The following conventions are adopted in defining grammar rules for abstract syn * Some productions are augmented with side conditions in parentheses, ":math:`(\iff \X{condition})`", that provide a shorthand for a combinatorial expansion of the production into many separate cases. +* If the same meta variable or non-terminal symbol appears multiple times in a production, then all those occurrences must have the same instantiation. + (This is a shorthand for a side condition requiring multiple different variables to be equal.) + .. _notation-epsilon: .. _notation-length: @@ -82,6 +85,7 @@ Moreover, the following conventions are employed: (similarly for :math:`x^\ast`, :math:`x^+`, :math:`x^?`). This implicitly expresses a form of mapping syntactic constructions over a sequence. + Productions of the following form are interpreted as *records* that map a fixed set of fields :math:`\K{field}_i` to "values" :math:`A_i`, respectively: .. math:: diff --git a/document/core/syntax/instructions.rst b/document/core/syntax/instructions.rst index 30f3cda133..039d4cfb2f 100644 --- a/document/core/syntax/instructions.rst +++ b/document/core/syntax/instructions.rst @@ -171,6 +171,30 @@ Occasionally, it is convenient to group operators together according to the foll \end{array} +.. index:: ! reference instruction, reference, null + pair: abstract syntax; instruction +.. _syntax-ref.null: +.. _syntax-ref.is_null: +.. _syntax-ref.func: +.. _syntax-instr-ref: + +Reference Instructions +~~~~~~~~~~~~~~~~~~~~~~ + +Instructions in this group are concerned with accessing :ref:`references `. + +.. math:: + \begin{array}{llcl} + \production{instruction} & \instr &::=& + \dots \\&&|& + \REFNULL~\reftype \\&&|& + \REFISNULL \\&&|& + \REFFUNC~\funcidx \\ + \end{array} + +These instruction produce a null value, check for a null value, or produce a reference to a given function, respectively. + + .. index:: ! parametric instruction, value type pair: abstract syntax; instruction .. _syntax-instr-parametric: @@ -185,12 +209,16 @@ Instructions in this group can operate on operands of any :ref:`value type ` determining the type of these operands. If missing, the operands must be of :ref:`numeric type `. + +.. note:: + In future versions of WebAssembly, the type annotation on |SELECT| may allow for more than a single value being selected at the same time. .. index:: ! variable instruction, local, global, local index, global index @@ -217,6 +245,49 @@ These instructions get or set the values of variables, respectively. The |LOCALTEE| instruction is like |LOCALSET| but also returns its argument. +.. index:: ! table instruction, table, table index, trap + pair: abstract syntax; instruction +.. _syntax-instr-table: +.. _syntax-table.get: +.. _syntax-table.set: +.. _syntax-table.size: +.. _syntax-table.grow: +.. _syntax-table.fill: + +Table Instructions +~~~~~~~~~~~~~~~~~~ + +Instructions in this group are concerned with tables :ref:`table `. + +.. math:: + \begin{array}{llcl} + \production{instruction} & \instr &::=& + \dots \\&&|& + \TABLEGET~\tableidx \\&&|& + \TABLESET~\tableidx \\&&|& + \TABLESIZE~\tableidx \\&&|& + \TABLEGROW~\tableidx \\&&|& + \TABLEFILL~\tableidx \\&&|& + \TABLECOPY~\tableidx~\tableidx \\&&|& + \TABLEINIT~\tableidx~\elemidx \\&&|& + \ELEMDROP~\elemidx \\ + \end{array} + +The |TABLEGET| and |TABLESET| instructions load or store an element in a table, respectively. + +The |TABLESIZE| instruction returns the current size of a table. +The |TABLEGROW| instruction grows table by a given delta and returns the previous size, or :math:`-1` if enough space cannot be allocated. +It also takes an initialization value for the newly allocated entries. + +The |TABLEFILL| instruction sets all entries in a range to a given value. + +The |TABLECOPY| instruction copies elements from a source table region to a possibly overlapping destination region; the first index denotes the destination. +The |TABLEINIT| instruction copies elements from a :ref:`passive element segment ` into a table. +The |ELEMDROP| instruction prevents further use of a passive element segment. This instruction is intended to be used as an optimization hint. After an element segment is dropped its elements can no longer be retrieved, so the memory used by this segment may be freed. + +An additional instruction that accesses a table is the :ref:`control instruction ` |CALLINDIRECT|. + + .. index:: ! memory instruction, memory, memory index, page size, little endian, trap pair: abstract syntax; instruction .. _syntax-loadn: @@ -246,7 +317,11 @@ Instructions in this group are concerned with linear :ref:`memory `. \K{i}\X{nn}\K{.}\STORE\K{16}~\memarg ~|~ \K{i64.}\STORE\K{32}~\memarg \\&&|& \MEMORYSIZE \\&&|& - \MEMORYGROW \\ + \MEMORYGROW \\&&|& + \MEMORYFILL \\&&|& + \MEMORYCOPY \\&&|& + \MEMORYINIT~\dataidx \\&&|& + \DATADROP~\dataidx \\ \end{array} Memory is accessed with |LOAD| and |STORE| instructions for the different :ref:`value types `. @@ -265,6 +340,11 @@ The |MEMORYSIZE| instruction returns the current size of a memory. The |MEMORYGROW| instruction grows memory by a given delta and returns the previous size, or :math:`-1` if enough memory cannot be allocated. Both instructions operate in units of :ref:`page size `. +The |MEMORYFILL| instruction sets all values in a region to a given byte. +The |MEMORYCOPY| instruction copies data from a source memory region to a possibly overlapping destination region. +The |MEMORYINIT| instruction copies data from a :ref:`passive data segment ` into a memory. +The |DATADROP| instruction prevents further use of a passive data segment. This instruction is intended to be used as an optimization hint. After a data segment is dropped its data can no longer be retrieved, so the memory used by this segment may be freed. + .. note:: In the current version of WebAssembly, all memory instructions implicitly operate on :ref:`memory ` :ref:`index ` :math:`0`. @@ -311,7 +391,7 @@ Instructions in this group affect the flow of control. \BRTABLE~\vec(\labelidx)~\labelidx \\&&|& \RETURN \\&&|& \CALL~\funcidx \\&&|& - \CALLINDIRECT~\typeidx \\ + \CALLINDIRECT~\tableidx~\typeidx \\ \end{array} The |NOP| instruction does nothing. @@ -354,14 +434,9 @@ Forward branches require operands according to the output of the targeted block' Backward branches require operands according to the input of the targeted block's type, i.e., represent the values consumed by the restarted block. The |CALL| instruction invokes another :ref:`function `, consuming the necessary arguments from the stack and returning the result values of the call. -The |CALLINDIRECT| instruction calls a function indirectly through an operand indexing into a :ref:`table `. -Since tables may contain function elements of heterogeneous type |FUNCREF|, -the callee is dynamically checked against the :ref:`function type ` indexed by the instruction's immediate, and the call aborted with a :ref:`trap ` if it does not match. - -.. note:: - In the current version of WebAssembly, - |CALLINDIRECT| implicitly operates on :ref:`table ` :ref:`index ` :math:`0`. - This restriction may be lifted in future versions. +The |CALLINDIRECT| instruction calls a function indirectly through an operand indexing into a :ref:`table ` that is denoted by a :ref:`table index ` and must have type |FUNCREF|. +Since it may contain functions of heterogeneous type, +the callee is dynamically checked against the :ref:`function type ` indexed by the instruction's second immediate, and the call is aborted with a :ref:`trap ` if it does not match. .. index:: ! expression, constant, global, offset, element, data, instruction diff --git a/document/core/syntax/modules.rst b/document/core/syntax/modules.rst index 7935fcae6b..f0973d814e 100644 --- a/document/core/syntax/modules.rst +++ b/document/core/syntax/modules.rst @@ -9,7 +9,7 @@ WebAssembly programs are organized into *modules*, which are the unit of deployment, loading, and compilation. A module collects definitions for :ref:`types `, :ref:`functions `, :ref:`tables `, :ref:`memories `, and :ref:`globals `. In addition, it can declare :ref:`imports ` and :ref:`exports ` -and provide initialization logic in the form of :ref:`data ` and :ref:`element ` segments or a :ref:`start function `. +and provide initialization in the form of :ref:`data ` and :ref:`element ` segments, or a :ref:`start function `. .. math:: \begin{array}{lllll} @@ -19,8 +19,8 @@ and provide initialization logic in the form of :ref:`data ` and :r \MTABLES~\vec(\table), \\&&&& \MMEMS~\vec(\mem), \\&&&& \MGLOBALS~\vec(\global), \\&&&& - \MELEM~\vec(\elem), \\&&&& - \MDATA~\vec(\data), \\&&&& + \MELEMS~\vec(\elem), \\&&&& + \MDATAS~\vec(\data), \\&&&& \MSTART~\start^?, \\&&&& \MIMPORTS~\vec(\import), \\&&&& \MEXPORTS~\vec(\export) \quad\} \\ @@ -29,12 +29,14 @@ and provide initialization logic in the form of :ref:`data ` and :r Each of the vectors -- and thus the entire module -- may be empty. -.. index:: ! index, ! index space, ! type index, ! function index, ! table index, ! memory index, ! global index, ! local index, ! label index, function, global, table, memory, local, parameter, import +.. index:: ! index, ! index space, ! type index, ! function index, ! table index, ! memory index, ! global index, ! local index, ! label index, ! element index, ! data index, function, global, table, memory, element, data, local, parameter, import pair: abstract syntax; type index pair: abstract syntax; function index pair: abstract syntax; table index pair: abstract syntax; memory index pair: abstract syntax; global index + pair: abstract syntax; element index + pair: abstract syntax; data index pair: abstract syntax; local index pair: abstract syntax; label index pair: type; index @@ -42,6 +44,8 @@ Each of the vectors -- and thus the entire module -- may be empty. pair: table; index pair: memory; index pair: global; index + pair: element; index + pair: data; index pair: local; index pair: label; index .. _syntax-typeidx: @@ -49,6 +53,8 @@ Each of the vectors -- and thus the entire module -- may be empty. .. _syntax-tableidx: .. _syntax-memidx: .. _syntax-globalidx: +.. _syntax-elemidx: +.. _syntax-dataidx: .. _syntax-localidx: .. _syntax-labelidx: .. _syntax-index: @@ -66,6 +72,8 @@ Each class of definition has its own *index space*, as distinguished by the foll \production{table index} & \tableidx &::=& \u32 \\ \production{memory index} & \memidx &::=& \u32 \\ \production{global index} & \globalidx &::=& \u32 \\ + \production{element index} & \elemidx &::=& \u32 \\ + \production{data index} & \dataidx &::=& \u32 \\ \production{local index} & \localidx &::=& \u32 \\ \production{label index} & \labelidx &::=& \u32 \\ \end{array} @@ -73,11 +81,24 @@ Each class of definition has its own *index space*, as distinguished by the foll The index space for :ref:`functions `, :ref:`tables `, :ref:`memories ` and :ref:`globals ` includes respective :ref:`imports ` declared in the same module. The indices of these imports precede the indices of other definitions in the same index space. +Element indices reference :ref:`element segments ` and data indices reference :ref:`data segments `. + The index space for :ref:`locals ` is only accessible inside a :ref:`function ` and includes the parameters of that function, which precede the local variables. Label indices reference :ref:`structured control instructions ` inside an instruction sequence. +.. _free-typeidx: +.. _free-funcidx: +.. _free-tableidx: +.. _free-memidx: +.. _free-globalidx: +.. _free-elemidx: +.. _free-dataidx: +.. _free-localidx: +.. _free-labelidx: +.. _free-index: + Conventions ........... @@ -85,6 +106,11 @@ Conventions * The meta variables :math:`x, y` range over indices in any of the other index spaces. +* The notation :math:`\F{idx}(A)` denotes the set of indices from index space :math:`\X{idx}` occurring free in :math:`A`. We sometimes reinterpret this set as the :ref:`vector ` of its elements. + +.. note:: + For example, if :math:`\instr^\ast` is :math:`(\DATADROP~x) (\MEMORYINIT~y)`, then :math:`\freedataidx(\instr^\ast) = \{x, y\}`, or equivalently, the vector :math:`x~y`. + .. index:: ! type definition, type index, function type pair: abstract syntax; type definition @@ -147,7 +173,7 @@ The |MTABLES| component of a module defines a vector of *tables* described by th \{ \TTYPE~\tabletype \} \\ \end{array} -A table is a vector of opaque values of a particular table :ref:`element type `. +A table is a vector of opaque values of a particular :ref:`reference type `. The |LMIN| size in the :ref:`limits ` of the table type specifies the initial size of that table, while its |LMAX|, if present, restricts the size to which it can grow later. Tables can be initialized through :ref:`element segments `. @@ -216,50 +242,75 @@ Globals are referenced through :ref:`global indices `, starting with the smallest index not referencing a global :ref:`import `. -.. index:: ! element, table, table index, expression, constant, function index, vector +.. index:: ! element, ! element mode, ! active, ! passive, ! declarative, element index, table, table index, expression, constant, function index, vector pair: abstract syntax; element + pair: abstract syntax; element mode single: table; element single: element; segment + single: element; mode .. _syntax-elem: +.. _syntax-elemmode: Element Segments ~~~~~~~~~~~~~~~~ -The initial contents of a table is uninitialized. -The |MELEM| component of a module defines a vector of *element segments* that initialize a subrange of a table, at a given offset, from a static :ref:`vector ` of elements. +The initial contents of a table is uninitialized. *Element segments* can be used to initialize a subrange of a table from a static :ref:`vector ` of elements. + +The |MELEMS| component of a module defines a vector of element segments. +Each element segment defines an :ref:`reference type ` and a corresponding list of :ref:`constant ` element :ref:`expressions `. + +Element segments have a mode that identifies them as either *passive*, *active*, or *declarative*. +A passive element segment's elements can be copied to a table using the |TABLEINIT| instruction. +An active element segment copies its elements into a table during :ref:`instantiation `, as specified by a :ref:`table index ` and a :ref:`constant ` :ref:`expression ` defining an offset into that table. +A declarative element segment is not available at runtime but merely serves to forward-declare references that are formed in code with instructions like :math:`REFFUNC`. .. math:: \begin{array}{llll} \production{element segment} & \elem &::=& - \{ \ETABLE~\tableidx, \EOFFSET~\expr, \EINIT~\vec(\funcidx) \} \\ + \{ \ETYPE~\reftype, \EINIT~\vec(\expr), \EMODE~\elemmode \} \\ + \production{element segment mode} & \elemmode &::=& + \EPASSIVE \\&&|& + \EACTIVE~\{ \ETABLE~\tableidx, \EOFFSET~\expr \} \\&&|& + \EDECLARATIVE \\ \end{array} The |EOFFSET| is given by a :ref:`constant ` :ref:`expression `. +Element segments are referenced through :ref:`element indices `. + .. note:: - In the current version of WebAssembly, at most one table is allowed in a module. - Consequently, the only valid |tableidx| is :math:`0`. + In the current version of WebAssembly, only tables of element type |FUNCREF| can be initialized with an element segment. + This limitation may be lifted in the future. -.. index:: ! data, memory, memory index, expression, constant, byte, vector +.. index:: ! data, active, passive, data index, memory, memory index, expression, constant, byte, vector pair: abstract syntax; data single: memory; data single: data; segment .. _syntax-data: +.. _syntax-datamode: Data Segments ~~~~~~~~~~~~~ -The initial contents of a :ref:`memory ` are zero-valued bytes. -The |MDATA| component of a module defines a vector of *data segments* that initialize a range of memory, at a given offset, with a static :ref:`vector ` of :ref:`bytes `. +The initial contents of a :ref:`memory ` are zero bytes. *Data segments* can be used to initialize a range of memory from a static :ref:`vector ` of :ref:`bytes `. + +The |MDATAS| component of a module defines a vector of data segments. + +Like element segments, data segments have a mode that identifies them as either *passive* or *active*. +A passive data segment's contents can be copied into a memory using the |MEMORYINIT| instruction. +An active data segment copies its contents into a memory during :ref:`instantiation `, as specified by a :ref:`memory index ` and a :ref:`constant ` :ref:`expression ` defining an offset into that memory. .. math:: \begin{array}{llll} \production{data segment} & \data &::=& - \{ \DMEM~\memidx, \DOFFSET~\expr, \DINIT~\vec(\byte) \} \\ + \{ \DINIT~\vec(\byte), \DMODE~\datamode \} \\ + \production{data segment mode} & \datamode &::=& + \DPASSIVE \\&&|& + \DACTIVE~\{ \DMEM~\memidx, \DOFFSET~\expr \} \\ \end{array} -The |DOFFSET| is given by a :ref:`constant ` :ref:`expression `. +Data segments are referenced through :ref:`data indices `. .. note:: In the current version of WebAssembly, at most one memory is allowed in a module. diff --git a/document/core/syntax/types.rst b/document/core/syntax/types.rst index 2310a6ef1f..e354ee9d15 100644 --- a/document/core/syntax/types.rst +++ b/document/core/syntax/types.rst @@ -9,19 +9,19 @@ Various entities in WebAssembly are classified by types. Types are checked during :ref:`validation `, :ref:`instantiation `, and possibly :ref:`execution `. -.. index:: ! value type, integer, floating-point, IEEE 754, bit width - pair: abstract syntax; value type - pair: value; type -.. _syntax-valtype: +.. index:: ! number type, integer, floating-point, IEEE 754, bit width, memory + pair: abstract syntax; number type + pair: number; type +.. _syntax-numtype: -Value Types -~~~~~~~~~~~ +Number Types +~~~~~~~~~~~~ -*Value types* classify the individual values that WebAssembly code can compute with and the values that a variable accepts. +*Number types* classify numeric values. .. math:: \begin{array}{llll} - \production{value type} & \valtype &::=& + \production{number type} & \numtype &::=& \I32 ~|~ \I64 ~|~ \F32 ~|~ \F64 \\ \end{array} @@ -31,15 +31,63 @@ Integers are not inherently signed or unsigned, their interpretation is determin The types |F32| and |F64| classify 32 and 64 bit floating-point data, respectively. They correspond to the respective binary floating-point representations, also known as *single* and *double* precision, as defined by the |IEEE754|_ standard (Section 3.3). +Number types are *transparent*, meaning that their bit patterns can be observed. +Values of number type can be stored in :ref:`memories `. + Conventions ........... -* The meta variable :math:`t` ranges over value types where clear from context. - -* The notation :math:`|t|` denotes the *bit width* of a value type. +* The notation :math:`|t|` denotes the *bit width* of a number type :math:`t`. That is, :math:`|\I32| = |\F32| = 32` and :math:`|\I64| = |\F64| = 64`. +.. index:: ! reference type, reference, table, function, function type, null + pair: abstract syntax; reference type + pair: reference; type +.. _syntax-reftype: + +Reference Types +~~~~~~~~~~~~~~~ + +*Reference types* classify first-class references to objects in the runtime :ref:`store `. + +.. math:: + \begin{array}{llll} + \production{reference type} & \reftype &::=& + \FUNCREF ~|~ \EXTERNREF \\ + \end{array} + +The type |FUNCREF| denotes the infinite union of all references to :ref:`functions `, regardless of their :ref:`function 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. +Values of reference type can be stored in :ref:`tables `. + + +.. index:: ! value type, number type, reference type + pair: abstract syntax; value type + pair: value; type +.. _syntax-valtype: + +Value Types +~~~~~~~~~~~ + +*Value types* classify the individual values that WebAssembly code can compute with and the values that a variable accepts. +They are either :ref:`number types ` or :ref:`reference types `. + +.. math:: + \begin{array}{llll} + \production{value type} & \valtype &::=& + \numtype ~|~ \reftype \\ + \end{array} + +Conventions +........... + +* The meta variable :math:`t` ranges over value types or subclasses thereof where clear from context. + + .. index:: ! result type, value type, instruction, execution, function pair: abstract syntax; result type pair: result; type @@ -118,34 +166,26 @@ The limits constrain the minimum and optionally the maximum size of a memory. The limits are given in units of :ref:`page size `. -.. index:: ! table type, ! element type, limits, table, element +.. index:: ! table type, reference type, limits, table, element pair: abstract syntax; table type - pair: abstract syntax; element type pair: table; type pair: table; limits - pair: element; type -.. _syntax-elemtype: .. _syntax-tabletype: Table Types ~~~~~~~~~~~ -*Table types* classify :ref:`tables ` over elements of *element types* within a size range. +*Table types* classify :ref:`tables ` over elements of :ref:`reference type ` within a size range. .. math:: \begin{array}{llll} \production{table type} & \tabletype &::=& - \limits~\elemtype \\ - \production{element type} & \elemtype &::=& - \FUNCREF \\ + \limits~\reftype \\ \end{array} Like memories, tables are constrained by limits for their minimum and optionally maximum size. The limits are given in numbers of entries. -The element type |FUNCREF| is the infinite union of all :ref:`function types `. -A table of that type thus contains references to functions of heterogeneous type. - .. note:: In future versions of WebAssembly, additional element types may be introduced. diff --git a/document/core/text/conventions.rst b/document/core/text/conventions.rst index c73e9c000a..ea62cc4b77 100644 --- a/document/core/text/conventions.rst +++ b/document/core/text/conventions.rst @@ -54,6 +54,8 @@ In order to distinguish symbols of the textual syntax from symbols of the abstra * Some productions are augmented by side conditions in parentheses, which restrict the applicability of the production. They provide a shorthand for a combinatorial expansion of the production into many separate cases. +* If the same meta variable or non-terminal symbol appears multiple times in a production (in the syntax or in an attribute), then all those occurrences must have the same instantiation. + .. _text-syntactic: * A distinction is made between *lexical* and *syntactic* productions. For the latter, arbitrary :ref:`white space ` is allowed in any place where the grammar contains spaces. The productions defining :ref:`lexical syntax ` and the syntax of :Ref:`values ` are considered lexical, all others are syntactic. @@ -122,6 +124,8 @@ It is convenient to define identifier contexts as :ref:`records ` may be omitted from table instructions, defaulting to :math:`0`. + +.. math:: + \begin{array}{llclll} + \production{instruction} & + \text{table.get} &\equiv& \text{table.get}~~\text{0} \\ &&|& + \text{table.set} &\equiv& \text{table.set}~~\text{0} \\ &&|& + \text{table.size} &\equiv& \text{table.size}~~\text{0} \\ &&|& + \text{table.grow} &\equiv& \text{table.grow}~~\text{0} \\ &&|& + \text{table.fill} &\equiv& \text{table.fill}~~\text{0} \\ &&|& + \text{table.copy} &\equiv& \text{table.copy}~~\text{0}~~\text{0} \\ &&|& + \text{table.init}~~x{:}\Telemidx_I &\equiv& \text{table.init}~~\text{0}~~x{:}\Telemidx_I \\ &&|& + \end{array} + + .. index:: memory instruction, memory index pair: text format; instruction .. _text-instr-memory: @@ -190,6 +268,10 @@ Memory Instructions .. _text-storen: .. _text-memory.size: .. _text-memory.grow: +.. _text-memory.fill: +.. _text-memory.copy: +.. _text-memory.init: +.. _text-data.drop: The offset and alignment immediates to memory instructions are optional. The offset defaults to :math:`\T{0}`, the alignment to the storage size of the respective memory access, which is its *natural alignment*. @@ -230,7 +312,11 @@ Lexically, an |Toffset| or |Talign| phrase is considered a single :ref:`keyword \text{i64.store16}~~m{:}\Tmemarg_2 &\Rightarrow& \I64.\STORE\K{16}~m \\ &&|& \text{i64.store32}~~m{:}\Tmemarg_4 &\Rightarrow& \I64.\STORE\K{32}~m \\ &&|& \text{memory.size} &\Rightarrow& \MEMORYSIZE \\ &&|& - \text{memory.grow} &\Rightarrow& \MEMORYGROW \\ + \text{memory.grow} &\Rightarrow& \MEMORYGROW \\ &&|& + \text{memory.fill} &\Rightarrow& \MEMORYFILL \\ &&|& + \text{memory.copy} &\Rightarrow& \MEMORYCOPY \\ &&|& + \text{memory.init}~~x{:}\Tdataidx_I &\Rightarrow& \MEMORYINIT~x \\ &&|& + \text{data.drop}~~x{:}\Tdataidx_I &\Rightarrow& \DATADROP~x \\ \end{array} diff --git a/document/core/text/modules.rst b/document/core/text/modules.rst index 12c8e309d1..9ae3b2d114 100644 --- a/document/core/text/modules.rst +++ b/document/core/text/modules.rst @@ -2,12 +2,14 @@ Modules ------- -.. index:: index, type index, function index, table index, memory index, global index, local index, label index +.. index:: index, type index, function index, table index, memory index, global index, element index, data index, local index, label index pair: text format; type index pair: text format; function index pair: text format; table index pair: text format; memory index pair: text format; global index + pair: text format; element index + pair: text format; data index pair: text format; local index pair: text format; label index .. _text-typeidx: @@ -42,6 +44,12 @@ Such identifiers are looked up in the suitable space of the :ref:`identifier con \production{global index} & \Tglobalidx_I &::=& x{:}\Tu32 &\Rightarrow& x \\&&|& v{:}\Tid &\Rightarrow& x & (\iff I.\IGLOBALS[x] = v) \\ + \production{element index} & \Telemidx_I &::=& + x{:}\Tu32 &\Rightarrow& x \\&&|& + v{:}\Tid &\Rightarrow& x & (\iff I.\IELEM[x] = v) \\ + \production{data index} & \Tdataidx_I &::=& + x{:}\Tu32 &\Rightarrow& x \\&&|& + v{:}\Tid &\Rightarrow& x & (\iff I.\IDATA[x] = v) \\ \production{local index} & \Tlocalidx_I &::=& x{:}\Tu32 &\Rightarrow& x \\&&|& v{:}\Tid &\Rightarrow& x & (\iff I.\ILOCALS[x] = v) \\ @@ -278,9 +286,19 @@ An :ref:`element segment ` can be given inline with a table definitio .. math:: \begin{array}{llclll} \production{module field} & - \text{(}~\text{table}~~\Tid^?~~\Telemtype~~\text{(}~\text{elem}~~x^n{:}\Tvec(\Tfuncidx)~\text{)}~~\text{)} \quad\equiv \\ & \qquad - \text{(}~\text{table}~~\Tid'~~n~~n~~\Telemtype~\text{)}~~ - \text{(}~\text{elem}~~\Tid'~~\text{(}~\text{i32.const}~~\text{0}~\text{)}~~\Tvec(\Tfuncidx)~\text{)} + \text{(}~\text{table}~~\Tid^?~~\Treftype~~\text{(}~\text{elem}~~\Telemlist~\text{)} \quad\equiv \\ & \qquad + \text{(}~\text{table}~~\Tid'~~n~~n~~\Treftype~\text{)}~~ + \text{(}~\text{elem}~~\text{(}~\text{table}~~\Tid'~\text{)}~~\text{(}~\text{i32.const}~~\text{0}~\text{)}~~\Telemlist~\text{)} + \\ & \qquad\qquad + (\iff \Tid' = \Tid^? \neq \epsilon \vee \Tid' \idfresh) \\ + \end{array} + +.. math:: + \begin{array}{llclll} + \production{module field} & + \text{(}~\text{table}~~\Tid^?~~\Treftype~~\text{(}~\text{elem}~~x^n{:}\Tvec(\Texpr)~\text{)}~~\text{)} \quad\equiv \\ & \qquad + \text{(}~\text{table}~~\Tid'~~n~~n~~\Treftype~\text{)}~~ + \text{(}~\text{elem}~~\Tid'~~\text{(}~\text{i32.const}~~\text{0}~\text{)}~~\Tvec(\Texpr)~\text{)} \\ & \qquad\qquad (\iff \Tid' = \Tid^? \neq \epsilon \vee \Tid' \idfresh) \\ \end{array} @@ -339,7 +357,7 @@ A :ref:`data segment ` can be given inline with a memory definition, \production{module field} & \text{(}~\text{memory}~~\Tid^?~~\text{(}~\text{data}~~b^n{:}\Tdatastring~\text{)}~~\text{)} \quad\equiv \\ & \qquad \text{(}~\text{memory}~~\Tid'~~m~~m~\text{)}~~ - \text{(}~\text{data}~~\Tid'~~\text{(}~\text{i32.const}~~\text{0}~\text{)}~~\Tdatastring~\text{)} + \text{(}~\text{data}~~\text{(}~\text{memory}~~\Tid'~\text{)}~~\text{(}~\text{i32.const}~~\text{0}~\text{)}~~\Tdatastring~\text{)} \\ & \qquad\qquad (\iff \Tid' = \Tid^? \neq \epsilon \vee \Tid' \idfresh, m = \F{ceil}(n / 64\F{Ki})) \\ \end{array} @@ -466,6 +484,9 @@ A :ref:`start function ` is defined in terms of its index. single: table; element single: element; segment .. _text-elem: +.. _text-elemlist: +.. _text-elemexpr: +.. _text-tableuse: Element Segments ~~~~~~~~~~~~~~~~ @@ -475,35 +496,58 @@ Element segments allow for an optional :ref:`table index ` to ide .. math:: \begin{array}{llclll} \production{element segment} & \Telem_I &::=& - \text{(}~\text{elem}~~x{:}\Ttableidx_I~~\text{(}~\text{offset}~~e{:}\Texpr_I~\text{)}~~y^\ast{:}\Tvec(\Tfuncidx_I)~\text{)} \\ &&& \qquad - \Rightarrow\quad \{ \ETABLE~x, \EOFFSET~e, \EINIT~y^\ast \} \\ + \text{(}~\text{elem}~~\Tid^?~~(et, y^\ast){:}\Telemlist~\text{)} \\ &&& \qquad + \Rightarrow\quad \{ \ETYPE~et, \EINIT~y^\ast, \EMODE~\EPASSIVE \} \\ &&|& + \text{(}~\text{elem}~~\Tid^?~~x{:}\Ttableuse_I~~\text{(}~\text{offset}~~e{:}\Texpr_I~\text{)}~~(et, y^\ast){:}\Telemlist~\text{)} \\ &&& \qquad + \Rightarrow\quad \{ \ETYPE~et, \EINIT~y^\ast, \EMODE~\EACTIVE~\{ \ETABLE~x, \EOFFSET~e \} \} \\ &&& + \text{(}~\text{elem}~~\Tid^?~~\text{declare}~~(et, y^\ast){:}\Telemlist~\text{)} \\ &&& \qquad + \Rightarrow\quad \{ \ETYPE~et, \EINIT~y^\ast, \EMODE~\EDECLARATIVE \} \\ + \production{element list} & \Telemlist &::=& + t{:}\Treftype~~y^\ast{:}\Tvec(\Telemexpr_I) \qquad\Rightarrow\quad ( \ETYPE~t, \EINIT~y^\ast ) \\ + \production{element expression} & \Telemexpr &::=& + \text{(}~\text{item}~~e{:}\Texpr~\text{)} + \quad\Rightarrow\quad e \\ + \production{table use} & \Ttableuse_I &::=& + \text{(}~\text{table}~~x{:}\Ttableidx_I ~\text{)} + \quad\Rightarrow\quad x \\ \end{array} -.. note:: - In the current version of WebAssembly, the only valid table index is 0 - or a symbolic :ref:`table identifier ` resolving to the same value. - Abbreviations ............. -As an abbreviation, a single instruction may occur in place of the offset: +As an abbreviation, a single instruction may occur in place of the offset of an active element segment or as an element expression: .. math:: \begin{array}{llcll} \production{element offset} & \Tinstr &\equiv& - \text{(}~\text{offset}~~\Tinstr~\text{)} + \text{(}~\text{offset}~~\Tinstr~\text{)} \\ + \production{element item} & + \Tinstr &\equiv& + \text{(}~\text{item}~~\Tinstr~\text{)} \\ \end{array} -Also, the table index can be omitted, defaulting to :math:`\T{0}`. +Also, the element list may be written as just a sequence of :ref:`function indices `: + +.. math:: + \begin{array}{llcll} + \production{element list} & + \text{func}~~\Tvec(\Tfuncidx_I) &\equiv& + \text{funcref}~~\Tvec(\text{(}~\text{ref.func}~~\Tfuncidx_I~\text{)}) + \end{array} + +A table use can be omitted, defaulting to :math:`\T{0}`. +Furthermore, for backwards compatibility with earlier versions of WebAssembly, if the table use is omitted, the :math:`\text{func}` keyword can be omitted as well. .. math:: \begin{array}{llclll} + \production{table use} & + \epsilon &\equiv& \text{(}~\text{table}~~\text{0}~\text{)} \\ \production{element segment} & - \text{(}~\text{elem}~~\text{(}~\text{offset}~~\Texpr_I~\text{)}~~\dots~\text{)} + \text{(}~\text{elem}~~\Tid^?~~\text{(}~\text{offset}~~\Texpr_I~\text{)}~~\Tvec(\Tfuncidx_I)~\text{)} &\equiv& - \text{(}~\text{elem}~~0~~\text{(}~\text{offset}~~\Texpr_I~\text{)}~~\dots~\text{)} + \text{(}~\text{elem}~~\Tid^?~~\text{(}~\text{table}~~\text{0}~\text{)}~~\text{(}~\text{offset}~~\Texpr_I~\text{)}~~\text{func}~~\Tvec(\Tfuncidx_I)~\text{)} \end{array} As another abbreviation, element segments may also be specified inline with :ref:`table ` definitions; see the respective section. @@ -515,6 +559,7 @@ As another abbreviation, element segments may also be specified inline with :ref single: data; segment .. _text-datastring: .. _text-data: +.. _test-memuse: Data Segments ~~~~~~~~~~~~~ @@ -525,10 +570,15 @@ The data is written as a :ref:`string `, which may be split up into .. math:: \begin{array}{llclll} \production{data segment} & \Tdata_I &::=& - \text{(}~\text{data}~~x{:}\Tmemidx_I~~\text{(}~\text{offset}~~e{:}\Texpr_I~\text{)}~~b^\ast{:}\Tdatastring~\text{)} \\ &&& \qquad - \Rightarrow\quad \{ \DMEM~x', \DOFFSET~e, \DINIT~b^\ast \} \\[1ex] + \text{(}~\text{data}~~\Tid^?~~b^\ast{:}\Tdatastring~\text{)} \\ &&& \qquad + \Rightarrow\quad \{ \DINIT~b^\ast, \DMODE~\DPASSIVE \} \\ &&|& + \text{(}~\text{data}~~\Tid^?~~x{:}\Tmemuse_I~~\text{(}~\text{offset}~~e{:}\Texpr_I~\text{)}~~b^\ast{:}\Tdatastring~\text{)} \\ &&& \qquad + \Rightarrow\quad \{ \DINIT~b^\ast, \DMODE~\DACTIVE~\{ \DMEM~x', \DOFFSET~e \} \} \\ \production{data string} & \Tdatastring &::=& (b^\ast{:}\Tstring)^\ast \quad\Rightarrow\quad \concat((b^\ast)^\ast) \\ + \production{memory use} & \Tmemuse_I &::=& + \text{(}~\text{memory}~~x{:}\Tmemidx_I ~\text{)} + \quad\Rightarrow\quad x \\ \end{array} .. note:: @@ -539,7 +589,7 @@ The data is written as a :ref:`string `, which may be split up into Abbreviations ............. -As an abbreviation, a single instruction may occur in place of the offset: +As an abbreviation, a single instruction may occur in place of the offset of an active data segment: .. math:: \begin{array}{llcll} @@ -548,14 +598,12 @@ As an abbreviation, a single instruction may occur in place of the offset: \text{(}~\text{offset}~~\Tinstr~\text{)} \end{array} -Also, the memory index can be omitted, defaulting to :math:`\T{0}`. +Also, a memory use can be omitted, defaulting to :math:`\T{0}`. .. math:: \begin{array}{llclll} - \production{data segment} & - \text{(}~\text{data}~~\text{(}~\text{offset}~~\Texpr_I~\text{)}~~\dots~\text{)} - &\equiv& - \text{(}~\text{data}~~0~~\text{(}~\text{offset}~~\Texpr_I~\text{)}~~\dots~\text{)} + \production{memory use} & + \epsilon &\equiv& \text{(}~\text{memory}~~\text{0}~\text{)} \\ \end{array} As another abbreviation, data segments may also be specified inline with :ref:`memory ` definitions; see the respective section. @@ -599,8 +647,8 @@ The name serves a documentary role only. \X{gl}{:}\Tglobal_I &\Rightarrow& \{\MGLOBALS~\X{gl}\} \\ |& \X{ex}{:}\Texport_I &\Rightarrow& \{\MEXPORTS~\X{ex}\} \\ |& \X{st}{:}\Tstart_I &\Rightarrow& \{\MSTART~\X{st}\} \\ |& - \X{el}{:}\Telem_I &\Rightarrow& \{\MELEM~\X{el}\} \\ |& - \X{da}{:}\Tdata_I &\Rightarrow& \{\MDATA~\X{da}\} \\ + \X{el}{:}\Telem_I &\Rightarrow& \{\MELEMS~\X{el}\} \\ |& + \X{da}{:}\Tdata_I &\Rightarrow& \{\MDATAS~\X{da}\} \\ \end{array} \end{array} @@ -631,6 +679,10 @@ The definition of the initial :ref:`identifier context ` :math:`I` \{\IMEMS~(\Tid^?)\} \\ \F{idc}(\text{(}~\text{global}~\Tid^?~\dots~\text{)}) &=& \{\IGLOBALS~(\Tid^?)\} \\ + \F{idc}(\text{(}~\text{elem}~\Tid^?~\dots~\text{)}) &=& + \{\IELEM~(\Tid^?)\} \\ + \F{idc}(\text{(}~\text{data}~\Tid^?~\dots~\text{)}) &=& + \{\IDATA~(\Tid^?)\} \\ \F{idc}(\text{(}~\text{import}~\dots~\text{(}~\text{func}~\Tid^?~\dots~\text{)}~\text{)}) &=& \{\IFUNCS~(\Tid^?)\} \\ \F{idc}(\text{(}~\text{import}~\dots~\text{(}~\text{table}~\Tid^?~\dots~\text{)}~\text{)}) &=& diff --git a/document/core/text/types.rst b/document/core/text/types.rst index 01714835cc..6d4ee37582 100644 --- a/document/core/text/types.rst +++ b/document/core/text/types.rst @@ -5,7 +5,43 @@ Types ----- -.. index:: value type +.. index:: number type + pair: text format; number type +.. _text-numtype: + +Number Types +~~~~~~~~~~~~ + +.. math:: + \begin{array}{llcll@{\qquad\qquad}l} + \production{number type} & \Tnumtype &::=& + \text{i32} &\Rightarrow& \I32 \\ &&|& + \text{i64} &\Rightarrow& \I64 \\ &&|& + \text{f32} &\Rightarrow& \F32 \\ &&|& + \text{f64} &\Rightarrow& \F64 \\ + \end{array} + + +.. index:: reference type + pair: text format; reference type +.. _text-reftype: +.. _text-heaptype: + +Reference Types +~~~~~~~~~~~~~~~ + +.. math:: + \begin{array}{llcll@{\qquad\qquad}l} + \production{reference type} & \Treftype &::=& + \text{funcref} &\Rightarrow& \FUNCREF \\ &&|& + \text{externref} &\Rightarrow& \EXTERNREF \\ + \production{heap type} & \Theaptype &::=& + \text{func} &\Rightarrow& \FUNCREF \\ &&|& + \text{extern} &\Rightarrow& \EXTERNREF \\ + \end{array} + + +.. index:: value type, number type, reference type pair: text format; value type .. _text-valtype: @@ -15,10 +51,8 @@ Value Types .. math:: \begin{array}{llcll@{\qquad\qquad}l} \production{value type} & \Tvaltype &::=& - \text{i32} &\Rightarrow& \I32 \\ &&|& - \text{i64} &\Rightarrow& \I64 \\ &&|& - \text{f32} &\Rightarrow& \F32 \\ &&|& - \text{f64} &\Rightarrow& \F64 \\ + t{:}\Tnumtype &\Rightarrow& t \\ &&|& + t{:}\Treftype &\Rightarrow& t \\ \end{array} @@ -90,10 +124,8 @@ Memory Types \end{array} -.. index:: table type, element type, limits +.. index:: table type, reference type, limits pair: text format; table type - pair: text format; element type -.. _text-elemtype: .. _text-tabletype: Table Types @@ -102,14 +134,9 @@ Table Types .. math:: \begin{array}{llclll} \production{table type} & \Ttabletype &::=& - \X{lim}{:}\Tlimits~~\X{et}{:}\Telemtype &\Rightarrow& \X{lim}~\X{et} \\ - \production{element type} & \Telemtype &::=& - \text{funcref} &\Rightarrow& \FUNCREF \\ + \X{lim}{:}\Tlimits~~\X{et}{:}\Treftype &\Rightarrow& \X{lim}~\X{et} \\ \end{array} -.. note:: - Additional element types may be introduced in future versions of WebAssembly. - .. index:: global type, mutability, value type pair: text format; global type diff --git a/document/core/util/macros.def b/document/core/util/macros.def index 44a8743f5f..82928c6f80 100644 --- a/document/core/util/macros.def +++ b/document/core/util/macros.def @@ -3,20 +3,20 @@ .. External Standards .. ------------------ -.. |WasmDraft| replace:: http://webassembly.github.io/spec/core/ -.. _WasmDraft: http://webassembly.github.io/spec/core/ +.. |WasmDraft| replace:: https://webassembly.github.io/spec/core/ +.. _WasmDraft: https://webassembly.github.io/spec/core/ -.. |WasmIssues| replace:: http://github.com/webassembly/spec/issues/ -.. _WasmIssues: http://github.com/webassembly/spec/issues/ +.. |WasmIssues| replace:: https://github.com/webassembly/spec/issues/ +.. _WasmIssues: https://github.com/webassembly/spec/issues/ .. |IEEE754| replace:: IEEE 754-2019 .. _IEEE754: https://ieeexplore.ieee.org/document/8766229 .. |Unicode| replace:: Unicode -.. _Unicode: http://www.unicode.org/versions/latest/ +.. _Unicode: https://www.unicode.org/versions/latest/ .. |ASCII| replace:: ASCII -.. _ASCII: http://webstore.ansi.org/RecordDetail.aspx?sku=INCITS+4-1986%5bR2012%5d +.. _ASCII: https://webstore.ansi.org/RecordDetail.aspx?sku=INCITS+4-1986%5bR2012%5d .. External Definitions @@ -177,7 +177,8 @@ .. |F32| mathdef:: \xref{syntax/types}{syntax-valtype}{\K{f32}} .. |F64| mathdef:: \xref{syntax/types}{syntax-valtype}{\K{f64}} -.. |FUNCREF| mathdef:: \xref{syntax/types}{syntax-elemtype}{\K{funcref}} +.. |FUNCREF| mathdef:: \xref{syntax/types}{syntax-reftype}{\K{funcref}} +.. |EXTERNREF| mathdef:: \xref{syntax/types}{syntax-reftype}{\K{externref}} .. |MVAR| mathdef:: \xref{syntax/types}{syntax-mut}{\K{var}} .. |MCONST| mathdef:: \xref{syntax/types}{syntax-mut}{\K{const}} @@ -193,13 +194,14 @@ .. Types, non-terminals +.. |numtype| mathdef:: \xref{syntax/types}{syntax-numtype}{\X{numtype}} +.. |reftype| mathdef:: \xref{syntax/types}{syntax-reftype}{\X{reftype}} .. |valtype| mathdef:: \xref{syntax/types}{syntax-valtype}{\X{valtype}} .. |resulttype| mathdef:: \xref{syntax/types}{syntax-resulttype}{\X{resulttype}} .. |functype| mathdef:: \xref{syntax/types}{syntax-functype}{\X{functype}} .. |globaltype| mathdef:: \xref{syntax/types}{syntax-globaltype}{\X{globaltype}} .. |tabletype| mathdef:: \xref{syntax/types}{syntax-tabletype}{\X{tabletype}} -.. |elemtype| mathdef:: \xref{syntax/types}{syntax-elemtype}{\X{elemtype}} .. |memtype| mathdef:: \xref{syntax/types}{syntax-memtype}{\X{memtype}} .. |limits| mathdef:: \xref{syntax/types}{syntax-limits}{\X{limits}} @@ -207,6 +209,9 @@ .. |externtype| mathdef:: \xref{syntax/types}{syntax-externtype}{\X{externtype}} +.. |stacktype| mathdef:: \xref{syntax/types}{syntax-stacktype}{\X{stacktype}} +.. |opdtype| mathdef:: \xref{syntax/types}{syntax-opdtype}{\X{opdtype}} + .. Types, meta functions @@ -223,10 +228,25 @@ .. |tableidx| mathdef:: \xref{syntax/modules}{syntax-tableidx}{\X{tableidx}} .. |memidx| mathdef:: \xref{syntax/modules}{syntax-memidx}{\X{memidx}} .. |globalidx| mathdef:: \xref{syntax/modules}{syntax-globalidx}{\X{globalidx}} +.. |elemidx| mathdef:: \xref{syntax/modules}{syntax-elemidx}{\X{elemidx}} +.. |dataidx| mathdef:: \xref{syntax/modules}{syntax-dataidx}{\X{dataidx}} .. |localidx| mathdef:: \xref{syntax/modules}{syntax-localidx}{\X{localidx}} .. |labelidx| mathdef:: \xref{syntax/modules}{syntax-labelidx}{\X{labelidx}} +.. Indices, meta functions + +.. |freetypeidx| mathdef:: \xref{syntax/modules}{syntax-typeidx}{\F{typeidx}} +.. |freefuncidx| mathdef:: \xref{syntax/modules}{syntax-funcidx}{\F{funcidx}} +.. |freetableidx| mathdef:: \xref{syntax/modules}{syntax-tableidx}{\F{tableidx}} +.. |freememidx| mathdef:: \xref{syntax/modules}{syntax-memidx}{\F{memidx}} +.. |freeglobalidx| mathdef:: \xref{syntax/modules}{syntax-globalidx}{\F{globalidx}} +.. |freeelemidx| mathdef:: \xref{syntax/modules}{syntax-elemidx}{\F{elemidx}} +.. |freedataidx| mathdef:: \xref{syntax/modules}{syntax-dataidx}{\F{dataidx}} +.. |freelocalidx| mathdef:: \xref{syntax/modules}{syntax-localidx}{\F{localidx}} +.. |freelabelidx| mathdef:: \xref{syntax/modules}{syntax-labelidx}{\F{labelidx}} + + .. Modules, terminals .. |MTYPES| mathdef:: \xref{syntax/modules}{syntax-module}{\K{types}} @@ -236,8 +256,8 @@ .. |MGLOBALS| mathdef:: \xref{syntax/modules}{syntax-module}{\K{globals}} .. |MIMPORTS| mathdef:: \xref{syntax/modules}{syntax-module}{\K{imports}} .. |MEXPORTS| mathdef:: \xref{syntax/modules}{syntax-module}{\K{exports}} -.. |MDATA| mathdef:: \xref{syntax/modules}{syntax-module}{\K{data}} -.. |MELEM| mathdef:: \xref{syntax/modules}{syntax-module}{\K{elem}} +.. |MDATAS| mathdef:: \xref{syntax/modules}{syntax-module}{\K{datas}} +.. |MELEMS| mathdef:: \xref{syntax/modules}{syntax-module}{\K{elems}} .. |MSTART| mathdef:: \xref{syntax/modules}{syntax-module}{\K{start}} .. |FTYPE| mathdef:: \xref{syntax/modules}{syntax-func}{\K{type}} @@ -251,13 +271,21 @@ .. |GTYPE| mathdef:: \xref{syntax/modules}{syntax-global}{\K{type}} .. |GINIT| mathdef:: \xref{syntax/modules}{syntax-global}{\K{init}} +.. |ETYPE| mathdef:: \xref{syntax/modules}{syntax-elem}{\K{type}} +.. |EINIT| mathdef:: \xref{syntax/modules}{syntax-elem}{\K{init}} +.. |EMODE| mathdef:: \xref{syntax/modules}{syntax-elem}{\K{mode}} +.. |EPASSIVE| mathdef:: \xref{syntax/modules}{syntax-elemmode}{\K{passive}} +.. |EACTIVE| mathdef:: \xref{syntax/modules}{syntax-elemmode}{\K{active}} +.. |EDECLARATIVE| mathdef:: \xref{syntax/modules}{syntax-elemmode}{\K{declarative}} .. |ETABLE| mathdef:: \xref{syntax/modules}{syntax-elem}{\K{table}} .. |EOFFSET| mathdef:: \xref{syntax/modules}{syntax-elem}{\K{offset}} -.. |EINIT| mathdef:: \xref{syntax/modules}{syntax-elem}{\K{init}} -.. |DMEM| mathdef:: \xref{syntax/modules}{syntax-data}{\K{data}} -.. |DOFFSET| mathdef:: \xref{syntax/modules}{syntax-data}{\K{offset}} .. |DINIT| mathdef:: \xref{syntax/modules}{syntax-data}{\K{init}} +.. |DMODE| mathdef:: \xref{syntax/modules}{syntax-data}{\K{mode}} +.. |DPASSIVE| mathdef:: \xref{syntax/modules}{syntax-data}{\K{passive}} +.. |DACTIVE| mathdef:: \xref{syntax/modules}{syntax-data}{\K{active}} +.. |DMEM| mathdef:: \xref{syntax/modules}{syntax-data}{\K{memory}} +.. |DOFFSET| mathdef:: \xref{syntax/modules}{syntax-data}{\K{offset}} .. |SFUNC| mathdef:: \xref{syntax/modules}{syntax-start}{\K{func}} @@ -290,7 +318,9 @@ .. |importdesc| mathdef:: \xref{syntax/modules}{syntax-importdesc}{\X{importdesc}} .. |exportdesc| mathdef:: \xref{syntax/modules}{syntax-exportdesc}{\X{exportdesc}} .. |elem| mathdef:: \xref{syntax/modules}{syntax-elem}{\X{elem}} +.. |elemmode| mathdef:: \xref{syntax/modules}{syntax-elemmode}{\X{elemmode}} .. |data| mathdef:: \xref{syntax/modules}{syntax-data}{\X{data}} +.. |datamode| mathdef:: \xref{syntax/modules}{syntax-datamode}{\X{datamode}} .. |start| mathdef:: \xref{syntax/modules}{syntax-start}{\X{start}} @@ -330,10 +360,27 @@ .. |GLOBALGET| mathdef:: \xref{syntax/instructions}{syntax-instr-variable}{\K{global.get}} .. |GLOBALSET| mathdef:: \xref{syntax/instructions}{syntax-instr-variable}{\K{global.set}} +.. |TABLEGET| mathdef:: \xref{syntax/instructions}{syntax-instr-table}{\K{table.get}} +.. |TABLESET| mathdef:: \xref{syntax/instructions}{syntax-instr-table}{\K{table.set}} +.. |TABLESIZE| mathdef:: \xref{syntax/instructions}{syntax-instr-table}{\K{table.size}} +.. |TABLEGROW| mathdef:: \xref{syntax/instructions}{syntax-instr-table}{\K{table.grow}} +.. |TABLEFILL| mathdef:: \xref{syntax/instructions}{syntax-instr-table}{\K{table.fill}} +.. |TABLECOPY| mathdef:: \xref{syntax/instructions}{syntax-instr-table}{\K{table.copy}} +.. |TABLEINIT| mathdef:: \xref{syntax/instructions}{syntax-instr-table}{\K{table.init}} +.. |ELEMDROP| mathdef:: \xref{syntax/instructions}{syntax-instr-table}{\K{elem.drop}} + .. |LOAD| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{load}} .. |STORE| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{store}} .. |MEMORYSIZE| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{memory.size}} .. |MEMORYGROW| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{memory.grow}} +.. |MEMORYFILL| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{memory.fill}} +.. |MEMORYCOPY| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{memory.copy}} +.. |MEMORYINIT| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{memory.init}} +.. |DATADROP| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{data.drop}} + +.. |REFNULL| mathdef:: \xref{syntax/instructions}{syntax-instr-ref}{\K{ref{.}null}} +.. |REFISNULL| mathdef:: \xref{syntax/instructions}{syntax-instr-ref}{\K{ref{.}is\_null}} +.. |REFFUNC| mathdef:: \xref{syntax/instructions}{syntax-instr-ref}{\K{ref{.}func}} .. |CONST| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{const}} .. |EQZ| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{eqz}} @@ -453,12 +500,13 @@ .. Types, non-terminals +.. |Bnumtype| mathdef:: \xref{binary/types}{binary-numtype}{\B{numtype}} +.. |Breftype| mathdef:: \xref{binary/types}{binary-reftype}{\B{reftype}} .. |Bvaltype| mathdef:: \xref{binary/types}{binary-valtype}{\B{valtype}} .. |Bresulttype| mathdef:: \xref{binary/types}{binary-resulttype}{\B{resulttype}} .. |Bfunctype| mathdef:: \xref{binary/types}{binary-functype}{\B{functype}} .. |Bglobaltype| mathdef:: \xref{binary/types}{binary-globaltype}{\B{globaltype}} .. |Btabletype| mathdef:: \xref{binary/types}{binary-tabletype}{\B{tabletype}} -.. |Belemtype| mathdef:: \xref{binary/types}{binary-elemtype}{\B{elemtype}} .. |Bmemtype| mathdef:: \xref{binary/types}{binary-memtype}{\B{memtype}} .. |Blimits| mathdef:: \xref{binary/types}{binary-limits}{\B{limits}} .. |Bmut| mathdef:: \xref{binary/types}{binary-mut}{\B{mut}} @@ -472,6 +520,8 @@ .. |Btableidx| mathdef:: \xref{binary/modules}{binary-tableidx}{\B{tableidx}} .. |Bmemidx| mathdef:: \xref{binary/modules}{binary-memidx}{\B{memidx}} .. |Bglobalidx| mathdef:: \xref{binary/modules}{binary-globalidx}{\B{globalidx}} +.. |Belemidx| mathdef:: \xref{binary/modules}{binary-elemidx}{\B{elemidx}} +.. |Bdataidx| mathdef:: \xref{binary/modules}{binary-dataidx}{\B{dataidx}} .. |Blocalidx| mathdef:: \xref{binary/modules}{binary-localidx}{\B{localidx}} .. |Blabelidx| mathdef:: \xref{binary/modules}{binary-labelidx}{\B{labelidx}} @@ -495,6 +545,7 @@ .. |Belemsec| mathdef:: \xref{binary/modules}{binary-elemsec}{\B{elemsec}} .. |Bdatasec| mathdef:: \xref{binary/modules}{binary-datasec}{\B{datasec}} .. |Bstartsec| mathdef:: \xref{binary/modules}{binary-startsec}{\B{startsec}} +.. |Bdatacountsec| mathdef:: \xref{binary/modules}{binary-datacountsec}{\B{datacountsec}} .. |Bcustom| mathdef:: \xref{binary/modules}{binary-customsec}{\B{custom}} .. |Btype| mathdef:: \xref{binary/modules}{binary-typedef}{\B{type}} @@ -507,6 +558,7 @@ .. |Bimportdesc| mathdef:: \xref{binary/modules}{binary-importdesc}{\B{importdesc}} .. |Bexportdesc| mathdef:: \xref{binary/modules}{binary-exportdesc}{\B{exportdesc}} .. |Belem| mathdef:: \xref{binary/modules}{binary-elem}{\B{elem}} +.. |Belemkind| mathdef:: \xref{binary/modules}{binary-elemkind}{\B{elemkind}} .. |Bcode| mathdef:: \xref{binary/modules}{binary-code}{\B{code}} .. |Blocal| mathdef:: \xref{binary/modules}{binary-local}{\B{local}} .. |Blocals| mathdef:: \xref{binary/modules}{binary-local}{\B{locals}} @@ -609,12 +661,14 @@ .. Types, non-terminals +.. |Tnumtype| mathdef:: \xref{text/types}{text-numtype}{\T{numtype}} +.. |Treftype| mathdef:: \xref{text/types}{text-reftype}{\T{reftype}} +.. |Theaptype| mathdef:: \xref{text/types}{text-heaptype}{\T{heaptype}} .. |Tvaltype| mathdef:: \xref{text/types}{text-valtype}{\T{valtype}} .. |Tfunctype| mathdef:: \xref{text/types}{text-functype}{\T{functype}} .. |Tglobaltype| mathdef:: \xref{text/types}{text-globaltype}{\T{globaltype}} .. |Ttabletype| mathdef:: \xref{text/types}{text-tabletype}{\T{tabletype}} -.. |Telemtype| mathdef:: \xref{text/types}{text-elemtype}{\T{elemtype}} .. |Tmemtype| mathdef:: \xref{text/types}{text-memtype}{\T{memtype}} .. |Tlimits| mathdef:: \xref{text/types}{text-limits}{\T{limits}} @@ -629,6 +683,8 @@ .. |Ttableidx| mathdef:: \xref{text/modules}{text-tableidx}{\T{tableidx}} .. |Tmemidx| mathdef:: \xref{text/modules}{text-memidx}{\T{memidx}} .. |Tglobalidx| mathdef:: \xref{text/modules}{text-globalidx}{\T{globalidx}} +.. |Telemidx| mathdef:: \xref{text/modules}{text-elemidx}{\T{elemidx}} +.. |Tdataidx| mathdef:: \xref{text/modules}{text-dataidx}{\T{dataidx}} .. |Tlocalidx| mathdef:: \xref{text/modules}{text-localidx}{\T{localidx}} .. |Tlabelidx| mathdef:: \xref{text/modules}{text-labelidx}{\T{labelidx}} @@ -657,11 +713,15 @@ .. |Timportdesc| mathdef:: \xref{text/modules}{text-importdesc}{\T{importdesc}} .. |Texportdesc| mathdef:: \xref{text/modules}{text-exportdesc}{\T{exportdesc}} .. |Telem| mathdef:: \xref{text/modules}{text-elem}{\T{elem}} +.. |Telemlist| mathdef:: \xref{text/modules}{text-elemlist}{\T{elemlist}} +.. |Telemexpr| mathdef:: \xref{text/modules}{text-elemexpr}{\X{elemexpr}} +.. |Ttableuse| mathdef:: \xref{text/modules}{text-tableuse}{\T{tableuse}} .. |Tcode| mathdef:: \xref{text/modules}{text-code}{\T{code}} .. |Tlocal| mathdef:: \xref{text/modules}{text-local}{\T{local}} .. |Tlocals| mathdef:: \xref{text/modules}{text-local}{\T{locals}} .. |Tdata| mathdef:: \xref{text/modules}{text-data}{\T{data}} .. |Tdatastring| mathdef:: \xref{text/modules}{text-datastring}{\T{datastring}} +.. |Tmemuse| mathdef:: \xref{text/modules}{text-memuse}{\T{memuse}} .. |Tstart| mathdef:: \xref{text/modules}{text-start}{\T{start}} @@ -693,6 +753,8 @@ .. |ITABLES| mathdef:: \xref{text/conventions}{text-context}{\K{tables}} .. |IMEMS| mathdef:: \xref{text/conventions}{text-context}{\K{mems}} .. |IGLOBALS| mathdef:: \xref{text/conventions}{text-context}{\K{globals}} +.. |IELEM| mathdef:: \xref{text/conventions}{text-context}{\K{elem}} +.. |IDATA| mathdef:: \xref{text/conventions}{text-context}{\K{data}} .. |ILOCALS| mathdef:: \xref{text/conventions}{text-context}{\K{locals}} .. |ILABELS| mathdef:: \xref{text/conventions}{text-context}{\K{labels}} @@ -721,9 +783,12 @@ .. |CTABLES| mathdef:: \xref{valid/conventions}{context}{\K{tables}} .. |CMEMS| mathdef:: \xref{valid/conventions}{context}{\K{mems}} .. |CGLOBALS| mathdef:: \xref{valid/conventions}{context}{\K{globals}} +.. |CELEMS| mathdef:: \xref{valid/conventions}{context}{\K{elems}} +.. |CDATAS| mathdef:: \xref{valid/conventions}{context}{\K{datas}} .. |CLOCALS| mathdef:: \xref{valid/conventions}{context}{\K{locals}} .. |CLABELS| mathdef:: \xref{valid/conventions}{context}{\K{labels}} .. |CRETURN| mathdef:: \xref{valid/conventions}{context}{\K{return}} +.. |CREFS| mathdef:: \xref{valid/conventions}{context}{\K{refs}} .. Judgments @@ -747,7 +812,9 @@ .. |vdashmem| mathdef:: \xref{valid/modules}{valid-mem}{\vdash} .. |vdashglobal| mathdef:: \xref{valid/modules}{valid-global}{\vdash} .. |vdashelem| mathdef:: \xref{valid/modules}{valid-elem}{\vdash} +.. |vdashelemmode| mathdef:: \xref{valid/modules}{valid-elemmode}{\vdash} .. |vdashdata| mathdef:: \xref{valid/modules}{valid-data}{\vdash} +.. |vdashdatamode| mathdef:: \xref{valid/modules}{valid-datamode}{\vdash} .. |vdashstart| mathdef:: \xref{valid/modules}{valid-start}{\vdash} .. |vdashexport| mathdef:: \xref{valid/modules}{valid-export}{\vdash} .. |vdashexportdesc| mathdef:: \xref{valid/modules}{valid-exportdesc}{\vdash} @@ -763,7 +830,8 @@ .. |stepto| mathdef:: \xref{exec/conventions}{formal-notation}{\hookrightarrow} .. |extendsto| mathdef:: \xref{appendix/properties}{extend}{\preceq} -.. |matches| mathdef:: \xref{exec/modules}{match}{\leq} +.. |matchesexterntype| mathdef:: \xref{exec/modules}{match-externtype}{\leq} +.. |matcheslimits| mathdef:: \xref{exec/modules}{match-limits}{\leq} .. Allocation @@ -773,6 +841,8 @@ .. |alloctable| mathdef:: \xref{exec/modules}{alloc-table}{\F{alloctable}} .. |allocmem| mathdef:: \xref{exec/modules}{alloc-mem}{\F{allocmem}} .. |allocglobal| mathdef:: \xref{exec/modules}{alloc-global}{\F{allocglobal}} +.. |allocelem| mathdef:: \xref{exec/modules}{alloc-elem}{\F{allocelem}} +.. |allocdata| mathdef:: \xref{exec/modules}{alloc-data}{\F{allocdata}} .. |allocmodule| mathdef:: \xref{exec/modules}{alloc-module}{\F{allocmodule}} .. |growtable| mathdef:: \xref{exec/modules}{grow-table}{\F{growtable}} @@ -786,7 +856,9 @@ .. |tableaddr| mathdef:: \xref{exec/runtime}{syntax-tableaddr}{\X{tableaddr}} .. |memaddr| mathdef:: \xref{exec/runtime}{syntax-memaddr}{\X{memaddr}} .. |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}} +.. |externaddr| mathdef:: \xref{exec/runtime}{syntax-externaddr}{\X{externaddr}} .. Instances, terminals @@ -795,14 +867,19 @@ .. |FICODE| mathdef:: \xref{exec/runtime}{syntax-funcinst}{\K{code}} .. |FIHOSTCODE| mathdef:: \xref{exec/runtime}{syntax-funcinst}{\K{hostcode}} +.. |TITYPE| mathdef:: \xref{exec/runtime}{syntax-tableinst}{\K{type}} .. |TIELEM| mathdef:: \xref{exec/runtime}{syntax-tableinst}{\K{elem}} -.. |TIMAX| mathdef:: \xref{exec/runtime}{syntax-tableinst}{\K{max}} +.. |MITYPE| mathdef:: \xref{exec/runtime}{syntax-meminst}{\K{type}} .. |MIDATA| mathdef:: \xref{exec/runtime}{syntax-meminst}{\K{data}} -.. |MIMAX| mathdef:: \xref{exec/runtime}{syntax-meminst}{\K{max}} +.. |GITYPE| mathdef:: \xref{exec/runtime}{syntax-globalinst}{\K{type}} .. |GIVALUE| mathdef:: \xref{exec/runtime}{syntax-globalinst}{\K{value}} -.. |GIMUT| mathdef:: \xref{exec/runtime}{syntax-globalinst}{\K{mut}} + +.. |EITYPE| mathdef:: \xref{exec/runtime}{syntax-eleminst}{\K{type}} +.. |EIELEM| mathdef:: \xref{exec/runtime}{syntax-eleminst}{\K{elem}} + +.. |DIDATA| mathdef:: \xref{exec/runtime}{syntax-datainst}{\K{data}} .. |EINAME| mathdef:: \xref{exec/runtime}{syntax-exportinst}{\K{name}} .. |EIVALUE| mathdef:: \xref{exec/runtime}{syntax-exportinst}{\K{value}} @@ -817,6 +894,8 @@ .. |MITABLES| mathdef:: \xref{exec/runtime}{syntax-moduleinst}{\K{tableaddrs}} .. |MIMEMS| mathdef:: \xref{exec/runtime}{syntax-moduleinst}{\K{memaddrs}} .. |MIGLOBALS| mathdef:: \xref{exec/runtime}{syntax-moduleinst}{\K{globaladdrs}} +.. |MIELEMS| mathdef:: \xref{exec/runtime}{syntax-moduleinst}{\K{elemaddrs}} +.. |MIDATAS| mathdef:: \xref{exec/runtime}{syntax-moduleinst}{\K{dataaddrs}} .. |MIEXPORTS| mathdef:: \xref{exec/runtime}{syntax-moduleinst}{\K{exports}} @@ -827,9 +906,10 @@ .. |moduleinst| mathdef:: \xref{exec/runtime}{syntax-moduleinst}{\X{moduleinst}} .. |funcinst| mathdef:: \xref{exec/runtime}{syntax-funcinst}{\X{funcinst}} .. |tableinst| mathdef:: \xref{exec/runtime}{syntax-tableinst}{\X{tableinst}} -.. |funcelem| mathdef:: \xref{exec/runtime}{syntax-funcelem}{\X{funcelem}} .. |meminst| mathdef:: \xref{exec/runtime}{syntax-meminst}{\X{meminst}} .. |globalinst| mathdef:: \xref{exec/runtime}{syntax-globalinst}{\X{globalinst}} +.. |eleminst| mathdef:: \xref{exec/runtime}{syntax-eleminst}{\X{eleminst}} +.. |datainst| mathdef:: \xref{exec/runtime}{syntax-datainst}{\X{datainst}} .. |exportinst| mathdef:: \xref{exec/runtime}{syntax-exportinst}{\X{exportinst}} .. |hostfunc| mathdef:: \xref{exec/runtime}{syntax-hostfunc}{\X{hostfunc}} @@ -849,7 +929,8 @@ .. |STABLES| mathdef:: \xref{exec/runtime}{syntax-store}{\K{tables}} .. |SMEMS| mathdef:: \xref{exec/runtime}{syntax-store}{\K{mems}} .. |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}} .. Store, non-terminals @@ -878,18 +959,25 @@ .. Administrative Instructions, terminals +.. |REFFUNCADDR| mathdef:: \xref{exec/runtime}{syntax-ref}{\K{ref}} +.. |REFEXTERNADDR| mathdef:: \xref{exec/runtime}{syntax-ref.extern}{\K{ref{.}extern}} .. |TRAP| mathdef:: \xref{exec/runtime}{syntax-trap}{\K{trap}} .. |INVOKE| mathdef:: \xref{exec/runtime}{syntax-invoke}{\K{invoke}} -.. |INITELEM| mathdef:: \xref{exec/runtime}{syntax-init_elem}{\K{init\_elem}} -.. |INITDATA| mathdef:: \xref{exec/runtime}{syntax-init_data}{\K{init\_data}} .. Values & Results, non-terminals +.. |num| mathdef:: \xref{exec/runtime}{syntax-num}{\X{num}} +.. |reff| mathdef:: \xref{exec/runtime}{syntax-ref}{\X{ref}} .. |val| mathdef:: \xref{exec/runtime}{syntax-val}{\X{val}} .. |result| mathdef:: \xref{exec/runtime}{syntax-result}{\X{result}} +.. Values, meta-functions + +.. |default| mathdef:: \xref{exec/runtime}{default-val}{\F{default}} + + .. Administrative Instructions, non-terminals .. |XB| mathdef:: \xref{exec/runtime}{syntax-ctxt-block}{B} @@ -1015,6 +1103,8 @@ .. |vdashtableinst| mathdef:: \xref{appendix/properties}{valid-tableinst}{\vdash} .. |vdashmeminst| mathdef:: \xref{appendix/properties}{valid-meminst}{\vdash} .. |vdashglobalinst| mathdef:: \xref{appendix/properties}{valid-globalinst}{\vdash} +.. |vdasheleminst| mathdef:: \xref{appendix/properties}{valid-eleminst}{\vdash} +.. |vdashdatainst| mathdef:: \xref{appendix/properties}{valid-datainst}{\vdash} .. |vdashexportinst| mathdef:: \xref{appendix/properties}{valid-exportinst}{\vdash} .. |vdashmoduleinst| mathdef:: \xref{appendix/properties}{valid-moduleinst}{\vdash} @@ -1027,6 +1117,8 @@ .. |vdashtableinstextends| mathdef:: \xref{appendix/properties}{extend-tableinst}{\vdash} .. |vdashmeminstextends| mathdef:: \xref{appendix/properties}{extend-meminst}{\vdash} .. |vdashglobalinstextends| mathdef:: \xref{appendix/properties}{extend-globalinst}{\vdash} +.. |vdasheleminstextends| mathdef:: \xref{appendix/properties}{extend-eleminst}{\vdash} +.. |vdashdatainstextends| mathdef:: \xref{appendix/properties}{extend-datainst}{\vdash} .. |vdashstoreextends| mathdef:: \xref{appendix/properties}{extend-store}{\vdash} diff --git a/document/core/valid/conventions.rst b/document/core/valid/conventions.rst index fb4c3e7539..b6a49b0cd3 100644 --- a/document/core/valid/conventions.rst +++ b/document/core/valid/conventions.rst @@ -38,9 +38,12 @@ which collects relevant information about the surrounding :ref:`module ` that occur in the module outside functions and can hence be used to form references inside them. In other words, a context contains a sequence of suitable :ref:`types ` for each :ref:`index space `, describing each defined entry in that space. @@ -58,9 +61,12 @@ More concretely, contexts are defined as :ref:`records ` :math: & \CTABLES & \tabletype^\ast, \\ & \CMEMS & \memtype^\ast, \\ & \CGLOBALS & \globaltype^\ast, \\ + & \CELEMS & \reftype^\ast, \\ + & \CDATAS & {\ok}^\ast, \\ & \CLOCALS & \valtype^\ast, \\ & \CLABELS & \resulttype^\ast, \\ - & \CRETURN & \resulttype^? ~\} \\ + & \CRETURN & \resulttype^?, \\ + & \CREFS & \funcidx^\ast ~\} \\ \end{array} \end{array} diff --git a/document/core/valid/instructions.rst b/document/core/valid/instructions.rst index 91c52f21c0..dac9c72903 100644 --- a/document/core/valid/instructions.rst +++ b/document/core/valid/instructions.rst @@ -1,13 +1,39 @@ -.. index:: instruction, function type, context, value, operand stack, ! polymorphism +.. index:: instruction, function type, context, value, operand stack, ! polymorphism, ! bottom type .. _valid-instr: +.. _syntax-stacktype: +.. _syntax-opdtype: Instructions ------------ -:ref:`Instructions ` are classified by :ref:`function types ` :math:`[t_1^\ast] \to [t_2^\ast]` -that describe how they manipulate the :ref:`operand stack `. -The types describe the required input stack with argument values of types :math:`t_1^\ast` that an instruction pops off +:ref:`Instructions ` are classified by *stack types* :math:`[t_1^\ast] \to [t_2^\ast]` that describe how instructions manipulate the :ref:`operand stack `. + +.. math:: + \begin{array}{llll} + \production{stack type} & \stacktype &::=& + [\opdtype^\ast] \to [\opdtype^\ast] \\ + \production{operand type} & \opdtype &::=& + \valtype ~|~ \bot \\ + \end{array} + +The types describe the required input stack with *operand types* :math:`t_1^\ast` that an instruction pops off and the provided output stack with result values of types :math:`t_2^\ast` that it pushes back. +Stack types are akin to :ref:`function types `, +except that they allow individual operands to be classified as :math:`\bot` (*bottom*), indicating that the type is unconstrained. +As an auxiliary notion, an operand type :math:`t_1` *matches* another operand type :math:`t_2`, if :math:`t_1` is either :math:`\bot` or equal to :math:`t_2`. + +.. _match-opdtype: + +.. math:: + \frac{ + }{ + \vdash t \leq t + } + \qquad + \frac{ + }{ + \vdash \bot \leq t + } .. note:: For example, the instruction :math:`\I32.\ADD` has type :math:`[\I32~\I32] \to [\I32]`, @@ -35,7 +61,7 @@ Two degrees of polymorphism can be distinguished: In both cases, the unconstrained types or type sequences can be chosen arbitrarily, as long as they meet the constraints imposed for the surrounding parts of the program. .. note:: - For example, the |SELECT| instruction is valid with type :math:`[t~t~\I32] \to [t]`, for any possible :ref:`value type ` :math:`t`. Consequently, both instruction sequences + For example, the |SELECT| instruction is valid with type :math:`[t~t~\I32] \to [t]`, for any possible :ref:`number type ` :math:`t`. Consequently, both instruction sequences .. math:: (\I32.\CONST~1)~~(\I32.\CONST~2)~~(\I32.\CONST~3)~~\SELECT{} @@ -61,6 +87,8 @@ In both cases, the unconstrained types or type sequences can be chosen arbitrari is invalid, because there is no possible type to pick for the |UNREACHABLE| instruction that would make the sequence well-typed. +The :ref:`Appendix ` describes a type checking :ref:`algorithm ` that efficiently implements validation of instruction sequences as prescribed by the rules given here. + .. index:: numeric instruction pair: validation; instruction @@ -154,6 +182,65 @@ Numeric Instructions } +.. index:: reference instructions, reference type + pair: validation; instruction + single: abstract syntax; instruction +.. _valid-instr-ref: + +Reference Instructions +~~~~~~~~~~~~~~~~~~~~~~ + +.. _valid-ref.null: + +:math:`\REFNULL~t` +.................. + +* The instruction is valid with type :math:`[] \to [t]`. + +.. math:: + \frac{ + }{ + C \vdashinstr \REFNULL~t : [] \to [t] + } + +.. note:: + In future versions of WebAssembly, there may be reference types for which no null reference is allowed. + +.. _valid-ref.is_null: + +:math:`\REFISNULL` +.................. + +* The instruction is valid with type :math:`[t] \to [\I32]`, for any :ref:`reference type ` :math:`t`. + +.. math:: + \frac{ + t = \reftype + }{ + C \vdashinstr \REFISNULL : [t] \to [\I32] + } + +.. _valid-ref.func: + +:math:`\REFFUNC~x` +.................. + +* The function :math:`C.\CFUNCS[x]` must be defined in the context. + +* The :ref:`function index ` :math:`x` must be contained in :math:`C.\CREFS`. + +* The instruction is valid with type :math:`[] \to [\FUNCREF]`. + +.. math:: + \frac{ + C.\CFUNCS[x] = \functype + \qquad + x \in C.\CREFS + }{ + C \vdashinstr \REFFUNC~x : [] \to [\FUNCREF] + } + + .. index:: parametric instructions, value type, polymorphism pair: validation; instruction single: abstract syntax; instruction @@ -175,22 +262,40 @@ Parametric Instructions C \vdashinstr \DROP : [t] \to [] } +.. note:: + Both |DROP| and |SELECT| without annotation are :ref:`value-polymorphic ` instructions. + + .. _valid-select: -:math:`\SELECT` -............... +:math:`\SELECT~(t^\ast)^?` +.......................... -* The instruction is valid with type :math:`[t~t~\I32] \to [t]`, for any :ref:`value type ` :math:`t`. +* If :math:`t^\ast` is present, then: + + * The length of :math:`t^\ast` must be :math:`1`. + + * Then the instruction is valid with type :math:`[t^\ast~t^\ast~\I32] \to [t^\ast]`. + +* Else: + + * The instruction is valid with type :math:`[t~t~\I32] \to [t]`, for any :ref:`operand type ` :math:`t` that :ref:`matches ` some :ref:`number type `. .. math:: \frac{ + }{ + C \vdashinstr \SELECT~t : [t~t~\I32] \to [t] + } + \qquad + \frac{ + \vdash t \leq \numtype }{ C \vdashinstr \SELECT : [t~t~\I32] \to [t] } .. note:: - Both |DROP| and |SELECT| are :ref:`value-polymorphic ` instructions. + In future versions of WebAssembly, |SELECT| may allow more than one value per choice. .. index:: variable instructions, local index, global index, context @@ -298,6 +403,178 @@ Variable Instructions } +.. index:: table instruction, table index, context + pair: validation; instruction + single: abstract syntax; instruction +.. _valid-instr-table: + +Table Instructions +~~~~~~~~~~~~~~~~~~ + +.. _valid-table.get: + +:math:`\TABLEGET~x` +................... + +* The table :math:`C.\CTABLES[x]` must be defined in the context. + +* Let :math:`\limits~t` be the :ref:`table type ` :math:`C.\CTABLES[x]`. + +* Then the instruction is valid with type :math:`[\I32] \to [t]`. + +.. math:: + \frac{ + C.\CTABLES[x] = \limits~t + }{ + C \vdashinstr \TABLEGET~x : [\I32] \to [t] + } + + +.. _valid-table.set: + +:math:`\TABLESET~x` +................... + +* The table :math:`C.\CTABLES[x]` must be defined in the context. + +* Let :math:`\limits~t` be the :ref:`table type ` :math:`C.\CTABLES[x]`. + +* Then the instruction is valid with type :math:`[\I32~t] \to []`. + +.. math:: + \frac{ + C.\CTABLES[x] = t + }{ + C \vdashinstr \TABLESET~x : [\I32~t] \to [] + } + + +.. _valid-table.size: + +:math:`\TABLESIZE~x` +.................... + +* The table :math:`C.\CTABLES[x]` must be defined in the context. + +* Then the instruction is valid with type :math:`[] \to [\I32]`. + +.. math:: + \frac{ + C.\CTABLES[x] = \tabletype + }{ + C \vdashinstr \TABLESIZE~x : [] \to [\I32] + } + + +.. _valid-table.grow: + +:math:`\TABLEGROW~x` +.................... + +* The table :math:`C.\CTABLES[x]` must be defined in the context. + +* Let :math:`\limits~t` be the :ref:`table type ` :math:`C.\CTABLES[x]`. + +* Then the instruction is valid with type :math:`[t~\I32] \to [\I32]`. + +.. math:: + \frac{ + C.\CTABLES[x] = \limits~t + }{ + C \vdashinstr \TABLEGROW~x : [t~\I32] \to [\I32] + } + + +.. _valid-table.fill: + +:math:`\TABLEFILL~x` +.................... + +* The table :math:`C.\CTABLES[x]` must be defined in the context. + +* Let :math:`\limits~t` be the :ref:`table type ` :math:`C.\CTABLES[x]`. + +* Then the instruction is valid with type :math:`[\I32~t~\I32] \to []`. + +.. math:: + \frac{ + C.\CTABLES[x] = \limits~t + }{ + C \vdashinstr \TABLEFILL~x : [\I32~t~\I32] \to [] + } + + +.. _valid-table.copy: + +:math:`\TABLECOPY~x~y` +...................... + +* The table :math:`C.\CTABLES[x]` must be defined in the context. + +* Let :math:`\limits_1~t_1` be the :ref:`table type ` :math:`C.\CTABLES[x]`. + +* The table :math:`C.\CTABLES[y]` must be defined in the context. + +* Let :math:`\limits_2~t_2` be the :ref:`table type ` :math:`C.\CTABLES[y]`. + +* The :ref:`reference type ` :math:`t_1` must be the same as :math:`t_2`. + +* Then the instruction is valid with type :math:`[\I32~\I32~\I32] \to []`. + +.. math:: + \frac{ + C.\CTABLES[x] = \limits_1~t + \qquad + C.\CTABLES[x] = \limits_2~t + }{ + C \vdashinstr \TABLECOPY~x~y : [\I32~\I32~\I32] \to [] + } + + +.. _valid-table.init: + +:math:`\TABLEINIT~x~y` +...................... + +* The table :math:`C.\CTABLES[x]` must be defined in the context. + +* Let :math:`\limits~t_1` be the :ref:`table type ` :math:`C.\CTABLES[x]`. + +* The element segment :math:`C.\CELEMS[y]` must be defined in the context. + +* Let :math:`t_2` be the :ref:`reference type ` :math:`C.\CELEMS[y]`. + +* The :ref:`reference type ` :math:`t_1` must be the same as :math:`t_2`. + +* Then the instruction is valid with type :math:`[\I32~\I32~\I32] \to []`. + +.. math:: + \frac{ + C.\CTABLES[x] = \limits_1~t + \qquad + C.\CELEMS[y] = t + }{ + C \vdashinstr \TABLEINIT~x~y : [\I32~\I32~\I32] \to [] + } + + +.. _valid-elem.drop: + +:math:`\ELEMDROP~x` +................... + +* The element segment :math:`C.\CELEMS[x]` must be defined in the context. + +* Then the instruction is valid with type :math:`[] \to []`. + +.. math:: + \frac{ + C.\CELEMS[x] = t + }{ + C \vdashinstr \ELEMDROP~x : [] \to [] + } + + .. index:: memory instruction, memory index, context pair: validation; instruction single: abstract syntax; instruction @@ -423,7 +700,79 @@ Memory Instructions } -.. index:: control instructions, structured control, label, block, branch, block type, result type, label index, function index, type index, vector, polymorphism, context +.. _valid-memory.fill: + +:math:`\MEMORYFILL` +................... + +* The memory :math:`C.\CMEMS[0]` must be defined in the context. + +* Then the instruction is valid with type :math:`[\I32~\I32~\I32] \to []`. + +.. math:: + \frac{ + C.\CMEMS[0] = \memtype + }{ + C \vdashinstr \MEMORYFILL : [\I32~\I32~\I32] \to [] + } + + +.. _valid-memory.copy: + +:math:`\MEMORYCOPY` +................... + +* The memory :math:`C.\CMEMS[0]` must be defined in the context. + +* Then the instruction is valid with type :math:`[\I32~\I32~\I32] \to []`. + +.. math:: + \frac{ + C.\CMEMS[0] = \memtype + }{ + C \vdashinstr \MEMORYCOPY : [\I32~\I32~\I32] \to [] + } + + +.. _valid-memory.init: + +:math:`\MEMORYINIT~x` +..................... + +* The memory :math:`C.\CMEMS[0]` must be defined in the context. + +* The data segment :math:`C.\CDATAS[x]` must be defined in the context. + +* Then the instruction is valid with type :math:`[\I32~\I32~\I32] \to []`. + +.. math:: + \frac{ + C.\CMEMS[0] = \memtype + \qquad + C.\CDATAS[x] = {\ok} + }{ + C \vdashinstr \MEMORYINIT~x : [\I32~\I32~\I32] \to [] + } + + +.. _valid-data.drop: + +:math:`\DATADROP~x` +................... + +* The data segment :math:`C.\CDATAS[x]` must be defined in the context. + +* Then the instruction is valid with type :math:`[] \to []`. + +.. math:: + \frac{ + C.\CDATAS[x] = {\ok} + }{ + C \vdashinstr \DATADROP~x : [] \to [] + } + + +.. index:: control instructions, structured control, label, block, branch, block type, label index, function index, type index, vector, polymorphism, context pair: validation; instruction single: abstract syntax; instruction .. _valid-label: @@ -672,28 +1021,28 @@ Control Instructions .. _valid-call_indirect: -:math:`\CALLINDIRECT~x` -....................... +:math:`\CALLINDIRECT~x~y` +......................... -* The table :math:`C.\CTABLES[0]` must be defined in the context. +* The table :math:`C.\CTABLES[x]` must be defined in the context. -* Let :math:`\limits~\elemtype` be the :ref:`table type ` :math:`C.\CTABLES[0]`. +* Let :math:`\limits~t` be the :ref:`table type ` :math:`C.\CTABLES[x]`. -* The :ref:`element type ` :math:`\elemtype` must be |FUNCREF|. +* The :ref:`reference type ` :math:`t` must be |FUNCREF|. -* The type :math:`C.\CTYPES[x]` must be defined in the context. +* The type :math:`C.\CTYPES[y]` must be defined in the context. -* Let :math:`[t_1^\ast] \to [t_2^\ast]` be the :ref:`function type ` :math:`C.\CTYPES[x]`. +* Let :math:`[t_1^\ast] \to [t_2^\ast]` be the :ref:`function type ` :math:`C.\CTYPES[y]`. * Then the instruction is valid with type :math:`[t_1^\ast~\I32] \to [t_2^\ast]`. .. math:: \frac{ - C.\CTABLES[0] = \limits~\FUNCREF + C.\CTABLES[x] = \limits~\FUNCREF \qquad - C.\CTYPES[x] = [t_1^\ast] \to [t_2^\ast] + C.\CTYPES[y] = [t_1^\ast] \to [t_2^\ast] }{ - C \vdashinstr \CALLINDIRECT~x : [t_1^\ast~\I32] \to [t_2^\ast] + C \vdashinstr \CALLINDIRECT~x~y : [t_1^\ast~\I32] \to [t_2^\ast] } @@ -710,7 +1059,7 @@ Empty Instruction Sequence: :math:`\epsilon` ............................................ * The empty instruction sequence is valid with type :math:`[t^\ast] \to [t^\ast]`, - for any sequence of :ref:`value types ` :math:`t^\ast`. + for any sequence of :ref:`operand types ` :math:`t^\ast`. .. math:: \frac{ @@ -729,13 +1078,17 @@ Non-empty Instruction Sequence: :math:`\instr^\ast~\instr_N` for some sequences of :ref:`value types ` :math:`t^\ast` and :math:`t_3^\ast`. * There must be a sequence of :ref:`value types ` :math:`t_0^\ast`, - such that :math:`t_2^\ast = t_0^\ast~t^\ast`. + such that :math:`t_2^\ast = t_0^\ast~{t'}^\ast` where the type sequence :math:`{t'}^\ast` is as long as :math:`t^\ast`. + +* For each :ref:`operand type ` :math:`t'_i` in :math:`{t'}^\ast` and corresponding type :math:`t_i` in :math:`t^\ast`, :math:`t'_i` :ref:`matches ` :math:`t_i`. * Then the combined instruction sequence is valid with type :math:`[t_1^\ast] \to [t_0^\ast~t_3^\ast]`. .. math:: \frac{ - C \vdashinstrseq \instr^\ast : [t_1^\ast] \to [t_0^\ast~t^\ast] + C \vdashinstrseq \instr^\ast : [t_1^\ast] \to [t_0^\ast~{t'}^\ast] + \qquad + (\vdash t' \leq t)^\ast \qquad C \vdashinstr \instr_N : [t^\ast] \to [t_3^\ast] }{ @@ -758,14 +1111,17 @@ Expressions :math:`\expr` are classified by :ref:`result types ` with type :math:`[] \to [t^\ast]`, - for some :ref:`result type ` :math:`[t^\ast]`. +* The instruction sequence :math:`\instr^\ast` must be :ref:`valid ` with some :ref:`stack type ` :math:`[] \to [t'^\ast]`. + +* For each :ref:`operand type ` :math:`t'_i` in :math:`{t'}^\ast` and corresponding :ref:`value type ` type :math:`t_i` in :math:`t^\ast`, :math:`t'_i` :ref:`matches ` :math:`t_i`. * Then the expression is valid with :ref:`result type ` :math:`[t^\ast]`. .. math:: \frac{ - C \vdashinstrseq \instr^\ast : [] \to [t^\ast] + C \vdashinstrseq \instr^\ast : [] \to [{t'}^\ast] + \qquad + (\vdash t' \leq t)^\ast }{ C \vdashexpr \instr^\ast~\END : [t^\ast] } @@ -783,6 +1139,10 @@ Constant Expressions * either of the form :math:`t.\CONST~c`, + * or of the form :math:`\REFNULL`, + + * or of the form :math:`\REFFUNC~x`, + * or of the form :math:`\GLOBALGET~x`, in which case :math:`C.\CGLOBALS[x]` must be a :ref:`global type ` of the form :math:`\CONST~t`. .. math:: @@ -798,6 +1158,17 @@ Constant Expressions C \vdashinstrconst t.\CONST~c \const } \qquad + \frac{ + }{ + C \vdashinstrconst \REFNULL \const + } + \qquad + \frac{ + }{ + C \vdashinstrconst \REFFUNC~x \const + } + +.. math:: \frac{ C.\CGLOBALS[x] = \CONST~t }{ diff --git a/document/core/valid/modules.rst b/document/core/valid/modules.rst index d08c70f8b3..eeed38f3a0 100644 --- a/document/core/valid/modules.rst +++ b/document/core/valid/modules.rst @@ -142,41 +142,87 @@ Globals :math:`\global` are classified by :ref:`global types Element Segments ~~~~~~~~~~~~~~~~ -Element segments :math:`\elem` are not classified by a type. +Element segments :math:`\elem` are classified by the :ref:`reference type ` of their elements. -:math:`\{ \ETABLE~x, \EOFFSET~\expr, \EINIT~y^\ast \}` -...................................................... +:math:`\{ \ETYPE~t, \EINIT~e^\ast, \EMODE~\elemmode \}` +....................................................... -* The table :math:`C.\CTABLES[x]` must be defined in the context. +* For each :math:`e_i` in :math:`e^\ast`, -* Let :math:`\limits~\elemtype` be the :ref:`table type ` :math:`C.\CTABLES[x]`. + * The expression :math:`e_i` must be :ref:`valid `. -* The :ref:`element type ` :math:`\elemtype` must be |FUNCREF|. + * The expression :math:`e_i` must be :ref:`constant `. -* The expression :math:`\expr` must be :ref:`valid ` with :ref:`result type ` :math:`[\I32]`. +* The element mode :math:`\elemmode` must be valid with :ref:`reference type ` :math:`t`. + +* Then the element segment is valid with :ref:`reference type ` :math:`t`. + + +.. math:: + \frac{ + (C \vdashexpr e \ok)^\ast + \qquad + (C \vdashexprconst e \const)^\ast + \qquad + C \vdashelemmode \elemmode : t + }{ + C \vdashelem \{ \ETYPE~t, \EINIT~e^\ast, \EMODE~\elemmode \} : t + } -* The expression :math:`\expr` must be :ref:`constant `. -* For each :math:`y_i` in :math:`y^\ast`, - the function :math:`C.\CFUNCS[y]` must be defined in the context. +.. _valid-elemmode: -* Then the element segment is valid. +:math:`\EPASSIVE` +................. +* The element mode is valid with any :ref:`reference type `. .. math:: \frac{ - C.\CTABLES[x] = \limits~\FUNCREF - \qquad + }{ + C \vdashelemmode \EPASSIVE : \reftype + } + + +:math:`\EACTIVE~\{ \ETABLE~x, \EOFFSET~\expr \}` +................................................ + +* The table :math:`C.\CTABLES[x]` must be defined in the context. + +* Let :math:`\limits~t` be the :ref:`table type ` :math:`C.\CTABLES[x]`. + +* The expression :math:`\expr` must be :ref:`valid ` with :ref:`result type ` :math:`[\I32]`. + +* The expression :math:`\expr` must be :ref:`constant `. + +* Then the element mode is valid with :ref:`reference type ` :math:`t`. + +.. math:: + \frac{ + \begin{array}{@{}c@{}} + C.\CTABLES[x] = \limits~t + \\ C \vdashexpr \expr : [\I32] \qquad C \vdashexprconst \expr \const - \qquad - (C.\CFUNCS[y] = \functype)^\ast + \end{array} + }{ + C \vdashelemmode \EACTIVE~\{ \ETABLE~x, \EOFFSET~\expr \} : t + } + +:math:`\EDECLARATIVE` +..................... + +* The element mode is valid with any :ref:`reference type `. + +.. math:: + \frac{ }{ - C \vdashelem \{ \ETABLE~x, \EOFFSET~\expr, \EINIT~y^\ast \} \ok + C \vdashelemmode \EDECLARATIVE : \reftype } + .. index:: data, memory, memory index, expression, byte pair: validation; data single: abstract syntax; data @@ -187,19 +233,47 @@ Element segments :math:`\elem` are not classified by a type. Data Segments ~~~~~~~~~~~~~ -Data segments :math:`\data` are not classified by any type. +Data segments :math:`\data` are not classified by any type but merely checked for well-formedness. -:math:`\{ \DMEM~x, \DOFFSET~\expr, \DINIT~b^\ast \}` +:math:`\{ \DINIT~b^\ast, \DMODE~\datamode \}` .................................................... +* The data mode :math:`\datamode` must be valid. + +* Then the data segment is valid. + +.. math:: + \frac{ + C \vdashdatamode \datamode \ok + }{ + C \vdashdata \{ \DINIT~b^\ast, \DMODE~\datamode \} \ok + } + + +.. _valid-datamode: + +:math:`\DPASSIVE` +................. + +* The data mode is valid. + +.. math:: + \frac{ + }{ + C \vdashdatamode \DPASSIVE \ok + } + + +:math:`\DACTIVE~\{ \DMEM~x, \DOFFSET~\expr \}` +.............................................. + * The memory :math:`C.\CMEMS[x]` must be defined in the context. * The expression :math:`\expr` must be :ref:`valid ` with :ref:`result type ` :math:`[\I32]`. * The expression :math:`\expr` must be :ref:`constant `. -* Then the data segment is valid. - +* Then the data mode is valid. .. math:: \frac{ @@ -209,7 +283,7 @@ Data segments :math:`\data` are not classified by any type. \qquad C \vdashexprconst \expr \const }{ - C \vdashdata \{ \DMEM~x, \DOFFSET~\expr, \DINIT~b^\ast \} \ok + C \vdashdatamode \DACTIVE~\{ \DMEM~x, \DOFFSET~\expr \} \ok } @@ -450,13 +524,27 @@ Instead, the context :math:`C` for validation of the module's content is constru * :math:`C.\CGLOBALS` is :math:`\etglobals(\X{it}^\ast)` concatenated with :math:`\X{gt}^\ast`, with the import's :ref:`external types ` :math:`\X{it}^\ast` and the internal :ref:`global types ` :math:`\X{gt}^\ast` as determined below, + * :math:`C.\CELEMS` is :math:`{\X{rt}}^\ast` as determined below, + + * :math:`C.\CDATAS` is :math:`{\ok}^n`, where :math:`n` is the length of the vector :math:`\module.\MDATAS`, + * :math:`C.\CLOCALS` is empty, * :math:`C.\CLABELS` is empty, * :math:`C.\CRETURN` is empty. -* Let :math:`C'` be the :ref:`context ` where :math:`C'.\CGLOBALS` is the sequence :math:`\etglobals(\X{it}^\ast)` and all other fields are empty. + * :math:`C.\CREFS` is the set :math:`\freefuncidx(\module \with \MFUNCS = \epsilon \with \MSTART = \epsilon)`, i.e., the set of :ref:`function indices ` occurring in the module, except in its :ref:`functions ` or :ref:`start function `. + +* Let :math:`C'` be the :ref:`context ` where: + + * :math:`C'.\CGLOBALS` is the sequence :math:`\etglobals(\X{it}^\ast)`, + + * :math:`C'.\CFUNCS` is the same as :math:`C.\CFUNCS`, + + * :math:`C'.\CREFS` is the same as :math:`C.\CREFS`, + + * all other fields are empty. * Under the context :math:`C`: @@ -477,10 +565,10 @@ Instead, the context :math:`C` for validation of the module's content is constru * Under the context :math:`C'`, the definition :math:`\global_i` must be :ref:`valid ` with a :ref:`global type ` :math:`\X{gt}_i`. - * For each :math:`\elem_i` in :math:`\module.\MELEM`, - the segment :math:`\elem_i` must be :ref:`valid `. + * For each :math:`\elem_i` in :math:`\module.\MELEMS`, + the segment :math:`\elem_i` must be :ref:`valid ` with :ref:`reference type ` :math:`\X{rt}_i`. - * For each :math:`\data_i` in :math:`\module.\MDATA`, + * For each :math:`\data_i` in :math:`\module.\MDATAS`, the segment :math:`\data_i` must be :ref:`valid `. * If :math:`\module.\MSTART` is non-empty, @@ -492,8 +580,6 @@ Instead, the context :math:`C` for validation of the module's content is constru * For each :math:`\export_i` in :math:`\module.\MEXPORTS`, the segment :math:`\export_i` must be :ref:`valid ` with :ref:`external type ` :math:`\X{et}_i`. -* The length of :math:`C.\CTABLES` must not be larger than :math:`1`. - * The length of :math:`C.\CMEMS` must not be larger than :math:`1`. * All export names :math:`\export_i.\ENAME` must be different. @@ -506,6 +592,8 @@ Instead, the context :math:`C` for validation of the module's content is constru * Let :math:`\X{gt}^\ast` be the concatenation of the internal :ref:`global types ` :math:`\X{gt}_i`, in index order. +* Let :math:`\X{rt}^\ast` be the concatenation of the :ref:`reference types ` :math:`\X{rt}_i`, in index order. + * Let :math:`\X{it}^\ast` be the concatenation of :ref:`external types ` :math:`\X{it}_i` of the imports, in index order. * Let :math:`\X{et}^\ast` be the concatenation of :ref:`external types ` :math:`\X{et}_i` of the exports, in index order. @@ -515,7 +603,7 @@ Instead, the context :math:`C` for validation of the module's content is constru .. math:: \frac{ \begin{array}{@{}c@{}} - (\vdashfunctype \functype \ok)^\ast + (\vdashfunctype \type \ok)^\ast \quad (C \vdashfunc \func : \X{ft})^\ast \quad @@ -525,9 +613,9 @@ Instead, the context :math:`C` for validation of the module's content is constru \quad (C' \vdashglobal \global : \X{gt})^\ast \\ - (C \vdashelem \elem \ok)^\ast + (C \vdashelem \elem : \X{rt})^\ast \quad - (C \vdashdata \data \ok)^\ast + (C \vdashdata \data \ok)^n \quad (C \vdashstart \start \ok)^? \quad @@ -543,30 +631,32 @@ Instead, the context :math:`C` for validation of the module's content is constru \qquad \X{igt}^\ast = \etglobals(\X{it}^\ast) \\ - C = \{ \CTYPES~\functype^\ast, \CFUNCS~\X{ift}^\ast~\X{ft}^\ast, \CTABLES~\X{itt}^\ast~\X{tt}^\ast, \CMEMS~\X{imt}^\ast~\X{mt}^\ast, \CGLOBALS~\X{igt}^\ast~\X{gt}^\ast \} + x^\ast = \freefuncidx(\module \with \MFUNCS = \epsilon \with \MSTART = \epsilon) \\ - C' = \{ \CGLOBALS~\X{igt}^\ast \} - \qquad - |C.\CTABLES| \leq 1 + C = \{ \CTYPES~\type^\ast, \CFUNCS~\X{ift}^\ast\,\X{ft}^\ast, \CTABLES~\X{itt}^\ast\,\X{tt}^\ast, \CMEMS~\X{imt}^\ast\,\X{mt}^\ast, \CGLOBALS~\X{igt}^\ast\,\X{gt}^\ast, \CELEMS~\X{rt}^\ast, \CDATAS~{\ok}^n, \CREFS~x^\ast \} + \\ + C' = \{ \CGLOBALS~\X{igt}^\ast, \CFUNCS~(C.\CFUNCS), \CREFS~(C.\CREFS) \} \qquad |C.\CMEMS| \leq 1 \qquad (\export.\ENAME)^\ast ~\F{disjoint} - \end{array} - }{ - \vdashmodule \{ + \\ + \module = \{ \begin{array}[t]{@{}l@{}} - \MTYPES~\functype^\ast, + \MTYPES~\type^\ast, \MFUNCS~\func^\ast, \MTABLES~\table^\ast, \MMEMS~\mem^\ast, \MGLOBALS~\global^\ast, \\ - \MELEM~\elem^\ast, - \MDATA~\data^\ast, + \MELEMS~\elem^\ast, + \MDATAS~\data^n, \MSTART~\start^?, \MIMPORTS~\import^\ast, - \MEXPORTS~\export^\ast \} : \X{it}^\ast \to \X{et}^\ast \\ + \MEXPORTS~\export^\ast \} \end{array} + \end{array} + }{ + \vdashmodule \module : \X{it}^\ast \to \X{et}^\ast } .. note:: @@ -578,7 +668,7 @@ Instead, the context :math:`C` for validation of the module's content is constru All types needed to construct :math:`C` can easily be determined from a simple pre-pass over the module that does not perform any actual validation. Globals, however, are not recursive. - The effect of defining the limited context :math:`C'` for validating the module's globals is that their initialization expressions can only access imported globals and nothing else. + The effect of defining the limited context :math:`C'` for validating the module's globals is that their initialization expressions can only access functions and imported globals and nothing else. .. note:: - The restriction on the number of tables and memories may be lifted in future versions of WebAssembly. + The restriction on the number of memories may be lifted in future versions of WebAssembly. diff --git a/document/core/valid/types.rst b/document/core/valid/types.rst index 45395f6a53..214014564c 100644 --- a/document/core/valid/types.rst +++ b/document/core/valid/types.rst @@ -100,7 +100,7 @@ Function Types } -.. index:: table type, element type, limits +.. index:: table type, reference type, limits pair: validation; table type single: abstract syntax; table type .. _valid-tabletype: @@ -108,18 +108,18 @@ Function Types Table Types ~~~~~~~~~~~ -:math:`\limits~\elemtype` -......................... +:math:`\limits~\reftype` +........................ -* The limits :math:`\limits` must be :ref:`valid ` within range :math:`2^{32}`. +* The limits :math:`\limits` must be :ref:`valid ` within range :math:`2^{32}-1`. * Then the table type is valid. .. math:: \frac{ - \vdashlimits \limits : 2^{32} + \vdashlimits \limits : 2^{32} - 1 }{ - \vdashtabletype \limits~\elemtype \ok + \vdashtabletype \limits~\reftype \ok } @@ -229,3 +229,128 @@ External Types }{ \vdashexterntype \ETGLOBAL~\globaltype \ok } + + +.. index:: ! matching, external type +.. _exec-import: +.. _match: + +Import Subtyping +~~~~~~~~~~~~~~~~ + +When :ref:`instantiating ` a module, +:ref:`external values ` must be provided whose :ref:`types ` are *matched* against the respective :ref:`external types ` classifying each import. +In some cases, this allows for a simple form of subtyping, as defined here. + + +.. index:: limits +.. _match-limits: + +Limits +...... + +:ref:`Limits ` :math:`\{ \LMIN~n_1, \LMAX~m_1^? \}` match limits :math:`\{ \LMIN~n_2, \LMAX~m_2^? \}` if and only if: + +* :math:`n_1` is larger than or equal to :math:`n_2`. + +* Either: + + * :math:`m_2^?` is empty. + +* Or: + + * Both :math:`m_1^?` and :math:`m_2^?` are non-empty. + + * :math:`m_1` is smaller than or equal to :math:`m_2`. + +.. math:: + ~\\[-1ex] + \frac{ + n_1 \geq n_2 + }{ + \vdashlimitsmatch \{ \LMIN~n_1, \LMAX~m_1^? \} \matcheslimits \{ \LMIN~n_2, \LMAX~\epsilon \} + } + \quad + \frac{ + n_1 \geq n_2 + \qquad + m_1 \leq m_2 + }{ + \vdashlimitsmatch \{ \LMIN~n_1, \LMAX~m_1 \} \matcheslimits \{ \LMIN~n_2, \LMAX~m_2 \} + } + + +.. _match-externtype: + +.. index:: function type +.. _match-functype: + +Functions +......... + +An :ref:`external type ` :math:`\ETFUNC~\functype_1` matches :math:`\ETFUNC~\functype_2` if and only if: + +* Both :math:`\functype_1` and :math:`\functype_2` are the same. + +.. math:: + ~\\[-1ex] + \frac{ + }{ + \vdashexterntypematch \ETFUNC~\functype \matchesexterntype \ETFUNC~\functype + } + + +.. index:: table type, limits, element type +.. _match-tabletype: + +Tables +...... + +An :ref:`external type ` :math:`\ETTABLE~(\limits_1~\reftype_1)` matches :math:`\ETTABLE~(\limits_2~\reftype_2)` if and only if: + +* Limits :math:`\limits_1` :ref:`match ` :math:`\limits_2`. + +* Both :math:`\reftype_1` and :math:`\reftype_2` are the same. + +.. math:: + \frac{ + \vdashlimitsmatch \limits_1 \matcheslimits \limits_2 + }{ + \vdashexterntypematch \ETTABLE~(\limits_1~\reftype) \matchesexterntype \ETTABLE~(\limits_2~\reftype) + } + + +.. index:: memory type, limits +.. _match-memtype: + +Memories +........ + +An :ref:`external type ` :math:`\ETMEM~\limits_1` matches :math:`\ETMEM~\limits_2` if and only if: + +* Limits :math:`\limits_1` :ref:`match ` :math:`\limits_2`. + +.. math:: + \frac{ + \vdashlimitsmatch \limits_1 \matcheslimits \limits_2 + }{ + \vdashexterntypematch \ETMEM~\limits_1 \matchesexterntype \ETMEM~\limits_2 + } + + +.. index:: global type, value type, mutability +.. _match-globaltype: + +Globals +....... + +An :ref:`external type ` :math:`\ETGLOBAL~\globaltype_1` matches :math:`\ETGLOBAL~\globaltype_2` if and only if: + +* Both :math:`\globaltype_1` and :math:`\globaltype_2` are the same. + +.. math:: + ~\\[-1ex] + \frac{ + }{ + \vdashexterntypematch \ETGLOBAL~\globaltype \matchesexterntype \ETGLOBAL~\globaltype + } diff --git a/document/js-api/index.bs b/document/js-api/index.bs index 91fc509859..1e4aa51d37 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -93,7 +93,7 @@ urlPrefix: https://tc39.github.io/ecma262/; spec: ECMASCRIPT text: BigInt; url: #sec-ecmascript-language-types-bigint-type type: abstract-op text: CreateMethodProperty; url: sec-createmethodproperty -urlPrefix: https://webassembly.github.io/spec/core/; spec: WebAssembly; type: dfn +urlPrefix: https://webassembly.github.io/reference-types/core/; spec: WebAssembly; type: dfn url: valid/modules.html#valid-module text: valid text: WebAssembly module validation @@ -110,6 +110,9 @@ urlPrefix: https://webassembly.github.io/spec/core/; spec: WebAssembly; type: df text: i32.const text: f32.const text: f64.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 @@ -145,11 +148,16 @@ urlPrefix: https://webassembly.github.io/spec/core/; spec: WebAssembly; type: df 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 - url: syntax/types.html#syntax-valtype + text: extern address; url: exec/runtime.html#syntax-externaddr + url: syntax/types.html#syntax-numtype text: i32 text: i64 text: f32 text: f64 + url: syntax/types.html#syntax-reftype + text: reftype + text: funcref + text: externref 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 @@ -259,6 +267,7 @@ Each [=agent=] is associated with the following [=ordered map=]s: * 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 WebAssembly Namespace

@@ -710,6 +719,7 @@ Immediately after a WebAssembly [=memory.grow=] instruction executes, perform th
 enum TableKind {
+  "externref",
   "anyfunc",
   // Note: More values may be added in future iterations,
   // e.g., typed function references, typed GC references
@@ -723,10 +733,10 @@ dictionary TableDescriptor {
 
 [LegacyNamespace=WebAssembly, Exposed=(Window,Worker,Worklet)]
 interface Table {
-  constructor(TableDescriptor descriptor);
-  unsigned long grow([EnforceRange] unsigned long delta);
-  Function? get([EnforceRange] unsigned long index);
-  undefined set([EnforceRange] unsigned long index, Function? value);
+  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;
 };
 
@@ -754,23 +764,35 @@ Each {{Table}} object has a \[[Table]] internal slot, which is a [=table address
- The Table(|descriptor|) constructor, when invoked, performs the following steps: + 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. Let |type| be the [=table type=] {[=table type|min=] |initial|, [=table type|max=] |maximum|} [=table type|anyfunc=]. + 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|ma𝗑=] |maximum|} |elementType|. 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. - 1. Let (|store|, |tableaddr|) be [=table_alloc=](|store|, |type|). + 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|) method, when invoked, performs the following steps: + 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 |result| be [=table_grow=](|store|, |tableaddr|, |delta|). + 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. @@ -792,20 +814,19 @@ 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 |result| be [=table_read=](|store|, |tableaddr|, |index|). 1. If |result| is [=error=], throw a {{RangeError}} exception. - 1. If |result| is ε, return null. - 1. Let |function| be the result of creating [=a new Exported Function=] from |result|. - 1. Return |function|. + 1. Return [=ToJSValue=](|result|).
The set(|index|, |value|) method, when invoked, performs the following steps: 1. Let |tableaddr| be **this**.\[[Table]]. - 1. If |value| is null, let |funcaddr| be ε. + 1. Let (limits, |elementType|) be [=table_type=](|tableaddr|). + 1. If |value| is missing, + 1. Let |ref| be [=DefaultValue=](|elementType|). 1. Otherwise, - 1. If |value| does not have a \[[FunctionAddress]] internal slot, throw a {{TypeError}} exception. - 1. Let |funcaddr| be |value|.\[[FunctionAddress]]. + 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|, |funcaddr|). + 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|.
@@ -817,7 +838,9 @@ enum ValueType { "i32", "i64", "f32", - "f64" + "f64", + "externref", + "anyfunc", }; @@ -867,6 +890,9 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each 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 "anyfunc", return [=funcref=]. + 1. If |s| equals "externref", return [=externref=]. + 1. Assert: This step is not reached.
@@ -875,6 +901,8 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each 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.
@@ -882,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 |v| is undefined, + 1. If |v| is missing, 1. Let |value| be [=DefaultValue=](|valuetype|). 1. Otherwise, 1. Let |value| be [=ToWebAssemblyValue=](|v|, |valuetype|). @@ -1046,12 +1074,24 @@ The algorithm ToJSValue(|w|) coerces a [=WebAssembly value=] to a Jav 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. If |w| is of the form [=ref.null=] t, return null. +1. If |w| is of the form [=ref.func=] |funcaddr|, return the result of creating [=a new Exported Function=] from |funcaddr|. +1. If |w| is of the form [=ref.extern=] |externaddr|, return the result of [=retrieving an extern value=] from |externaddr|. Note: Number values which are equal to NaN may have various observable NaN payloads; see [=NumberToRawBytes=] for details.
+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. If |type| is [=i64=], @@ -1066,6 +1106,23 @@ The algorithm ToWebAssemblyValue(|v|, |type|) coerces a JavaScript va 1. If |type| is [=f64=], 1. Let |f64| be ? [=ToNumber=](|v|). 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.
@@ -1147,7 +1204,8 @@ In practice, an implementation may run out of resources for valid modules below
  • 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 1.
  • +
  • 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 number of memories, including declared or imported memories, is 1.
  • diff --git a/interpreter/Makefile b/interpreter/Makefile index c745311b9d..2cf0a4febd 100644 --- a/interpreter/Makefile +++ b/interpreter/Makefile @@ -20,7 +20,8 @@ WINMAKE = winmake.bat DIRS = util syntax binary text valid runtime exec script host main LIBS = bigarray FLAGS = -lexflags -ml -cflags '-w +a-4-27-42-44-45 -warn-error +a-3' -OCB = ocamlbuild $(FLAGS) $(DIRS:%=-I %) $(LIBS:%=-libs %) +OCBA = ocamlbuild $(FLAGS) $(DIRS:%=-I %) +OCB = $(OCBA) $(LIBS:%=-libs %) JS = # set to JS shell command to run JS tests @@ -32,8 +33,8 @@ default: opt debug: unopt opt: $(OPT) unopt: $(UNOPT) -libopt: _build/$(LIB).cmx -libunopt: _build/$(LIB).cmo +libopt: _build/$(LIB).cmx _build/$(LIB).cmxa +libunopt: _build/$(LIB).cmo _build/$(LIB).cma jslib: $(JSLIB) all: unopt opt libunopt libopt test land: $(WINMAKE) all @@ -68,6 +69,7 @@ main.native: _tags # Building library +FILES = $(shell ls $(DIRS:%=%/*.ml*)) PACK = $(shell echo `echo $(LIB) | sed 's/^\(.\).*$$/\\1/g' | tr [:lower:] [:upper:]``echo $(LIB) | sed 's/^.\(.*\)$$/\\1/g'`) .INTERMEDIATE: $(LIB).mlpack @@ -78,12 +80,22 @@ $(LIB).mlpack: $(DIRS) | sort | uniq \ >$@ -_build/$(LIB).cmo: $(LIB).mlpack _tags +.INTERMEDIATE: $(LIB).mllib +$(LIB).mllib: + echo Wasm >$@ + +_build/$(LIB).cmo: $(FILES) $(LIB).mlpack _tags Makefile $(OCB) -quiet $(LIB).cmo -_build/$(LIB).cmx: $(LIB).mlpack _tags +_build/$(LIB).cmx: $(FILES) $(LIB).mlpack _tags Makefile $(OCB) -quiet $(LIB).cmx +_build/$(LIB).cma: $(FILES) $(LIB).mlpack _tags Makefile + $(OCBA) -quiet $(LIB).cma + +_build/$(LIB).cmxa: $(FILES) $(LIB).mlpack _tags Makefile + $(OCBA) -quiet $(LIB).cmxa + # Building JavaScript library diff --git a/interpreter/README.md b/interpreter/README.md index feb99bd0d9..ed300410e8 100644 --- a/interpreter/README.md +++ b/interpreter/README.md @@ -175,23 +175,25 @@ float: .?(e|E )? | 0x.?(p|P )? name: $( | | _ | . | + | - | * | / | \ | ^ | ~ | = | < | > | ! | ? | @ | # | $ | % | & | | | : | ' | `)+ string: "( | \n | \t | \\ | \' | \" | \ | \u{+})*" -value: | -var: | +num: | +var: | unop: ctz | clz | popcnt | ... binop: add | sub | mul | ... relop: eq | ne | lt | ... -sign: s|u +sign: s | u offset: offset= align: align=(1|2|4|8|...) cvtop: trunc | extend | wrap | ... -val_type: i32 | i64 | f32 | f64 -elem_type: funcref +num_type: i32 | i64 | f32 | f64 +ref_kind: func | extern +ref_type: funcref | externref +val_type: num_type | ref_type block_type : ( result * )* func_type: ( type )? * * global_type: | ( mut ) -table_type: ? +table_type: ? memory_type: ? expr: @@ -218,7 +220,7 @@ op: br_table + return call - call_indirect + call_indirect ? drop select local.get @@ -226,16 +228,31 @@ op: local.tee global.get global.set - .load((8|16|32)_)? ? ? - .store(8|16|32)? ? ? + table.get ? + table.set ? + table.size ? + table.grow ? + table.fill ? + table.copy ? ? + table.init ? + elem.drop + .load((8|16|32)_)? ? ? + .store(8|16|32)? ? ? memory.size memory.grow - .const - . - . - . - . - ._(_)? + memory.fill + memory.copy + memory.init + data.drop + ref.null + ref.is_null + ref.func + .const + . + . + . + . + ._(_)? func: ( func ? * * ) ( func ? ( export ) <...> ) ;; = (export (func )) (func ? <...>) @@ -250,15 +267,23 @@ global: ( global ? * ) table: ( table ? ) ( table ? ( export ) <...> ) ;; = (export (table )) (table ? <...>) ( table ? ( import ) ) ;; = (import (table ? )) - ( table ? ( export )* ( elem * ) ) ;; = (table ? ( export )* ) (elem (i32.const 0) *) + ( table ? ( export )* ( elem * ) ) ;; = (table ? ( export )* ) (elem (i32.const 0) *) elem: ( elem ? (offset * ) * ) ( elem ? * ) ;; = (elem ? (offset ) *) + ( elem ? declare * ) +elem: ( elem ? ( table )? * ) + ( elem ? ( table )? func * ) ;; = (elem ? ( table )? funcref (ref.func )*) + ( elem ? declare? * ) + ( elem ? declare? func * ) ;; = (elem ? declare? funcref (ref.func )*) +offset: ( offset * ) + ;; = ( offset ) +item: ( item * ) + ;; = ( item ) memory: ( memory ? ) ( memory ? ( export ) <...> ) ;; = (export (memory ))+ (memory ? <...>) ( memory ? ( import ) ) ;; = (import (memory ? )) ( memory ? ( export )* ( data * ) ) ;; = (memory ? ( export )* ) (data (i32.const 0) *) -data: ( data ? ( offset * ) * ) - ( data ? * ) ;; = (data ? (offset ) *) +data: ( data ? ( memory )? * ) start: ( start ) @@ -275,9 +300,9 @@ exkind: ( func ) ( table ) ( memory ) -module: ( module ? * * * * ? ? * * * ? ) - * * * *
    ? ? * * * ? ;; = - ( module * * * *
    ? ? * * * ? ) +module: ( module ? * * * *
    * ? * * * ? ) + * * * *
    * ? * * * ? ;; = + ( module * * * *
    * ? * * * ? ) ``` Here, productions marked with respective comments are abbreviation forms for equivalent expansions (see the explanation of the AST below). @@ -322,9 +347,14 @@ module: ( module ? quote * ) ;; module quoted in text (may be malformed) action: - ( invoke ? * ) ;; invoke function export + ( invoke ? * ) ;; invoke function export ( get ? ) ;; get global export +const: + ( .const ) ;; number value + ( ref.null ) ;; null reference + ( ref.host ) ;; host reference + assertion: ( assert_return * ) ;; assert action has expected results ( assert_trap ) ;; assert action traps with given failure string @@ -335,9 +365,11 @@ assertion: ( assert_trap ) ;; assert module traps on instantiation result: - ( .const ) + ( .const ) + ( ref.extern ) + ( ref.func ) -numpat: +num_pat: ;; literal result nan:canonical ;; NaN in canonical form nan:arithmetic ;; NaN with 1 in MSB of payload @@ -422,9 +454,11 @@ assertion: ( assert_trap ) ;; assert module traps on instantiation result: - ( .const ) + ( .const ) + ( ref.extern ) + ( ref.func ) -numpat: +num_pat: ;; literal result nan:canonical ;; NaN in canonical form nan:arithmetic ;; NaN with 1 in MSB of payload diff --git a/interpreter/binary/decode.ml b/interpreter/binary/decode.ml index 4e110c211d..29293ea288 100644 --- a/interpreter/binary/decode.ml +++ b/interpreter/binary/decode.ml @@ -30,6 +30,7 @@ module Code = Error.Make () exception Code = Code.Error let string_of_byte b = Printf.sprintf "%02x" b +let string_of_multi n = Printf.sprintf "%02lx" n let position s pos = Source.({file = s.name; line = -1; column = pos}) let region s left right = @@ -47,6 +48,8 @@ let skip n = guard (skip n) let expect b s msg = require (guard get s = b) s (pos s - 1) msg let illegal s pos b = error s pos ("illegal opcode " ^ string_of_byte b) +let illegal2 s pos b n = + error s pos ("illegal opcode " ^ string_of_byte b ^ " " ^ string_of_multi n) let at f s = let left = pos s in @@ -132,18 +135,24 @@ let sized f s = open Types -let value_type s = +let num_type s = match vs7 s with | -0x01 -> I32Type | -0x02 -> I64Type | -0x03 -> F32Type | -0x04 -> F64Type - | _ -> error s (pos s - 1) "malformed value type" + | _ -> error s (pos s - 1) "malformed number type" -let elem_type s = +let ref_type s = match vs7 s with | -0x10 -> FuncRefType - | _ -> error s (pos s - 1) "malformed element type" + | -0x11 -> ExternRefType + | _ -> error s (pos s - 1) "malformed reference type" + +let value_type s = + match peek s with + | Some n when n > 0x70 -> NumType (num_type s) + | _ -> RefType (ref_type s) let stack_type s = vec value_type s let func_type s = @@ -161,7 +170,7 @@ let limits vu s = {min; max} let table_type s = - let t = elem_type s in + let t = ref_type s in let lim = limits vu32 s in TableType (lim, t) @@ -190,6 +199,7 @@ let var s = vu32 s let op s = u8 s let end_ s = expect 0x0b s "END opcode expected" +let zero s = expect 0x00 s "zero byte expected" let memop s = let align = vu32 s in @@ -203,19 +213,6 @@ let block_type s = | Some b when b land 0xc0 = 0x40 -> ValBlockType (Some (value_type s)) | _ -> VarBlockType (at vs33 s) -let math_prefix s = - let pos = pos s in - match vu32 s with - | 0x00l -> i32_trunc_sat_f32_s - | 0x01l -> i32_trunc_sat_f32_u - | 0x02l -> i32_trunc_sat_f64_s - | 0x03l -> i32_trunc_sat_f64_u - | 0x04l -> i64_trunc_sat_f32_s - | 0x05l -> i64_trunc_sat_f32_u - | 0x06l -> i64_trunc_sat_f64_s - | 0x07l -> i64_trunc_sat_f64_u - | n -> illegal s pos (I32.to_int_u n) - let rec instr s = let pos = pos s in match op s with @@ -259,24 +256,27 @@ let rec instr s = | 0x10 -> call (at var s) | 0x11 -> + let y = at var s in let x = at var s in - expect 0x00 s "zero flag expected"; - call_indirect x + call_indirect x y | 0x12 | 0x13 | 0x14 | 0x15 | 0x16 | 0x17 | 0x18 | 0x19 as b -> illegal s pos b | 0x1a -> drop - | 0x1b -> select + | 0x1b -> select None + | 0x1c -> select (Some (vec value_type s)) - | 0x1c | 0x1d | 0x1e | 0x1f as b -> illegal s pos b + | 0x1d | 0x1e | 0x1f as b -> illegal s pos b | 0x20 -> local_get (at var s) | 0x21 -> local_set (at var s) | 0x22 -> local_tee (at var s) | 0x23 -> global_get (at var s) | 0x24 -> global_set (at var s) + | 0x25 -> table_get (at var s) + | 0x26 -> table_set (at var s) - | 0x25 | 0x26 | 0x27 as b -> illegal s pos b + | 0x27 as b -> illegal s pos b | 0x28 -> let a, o = memop s in i32_load a o | 0x29 -> let a, o = memop s in i64_load a o @@ -303,12 +303,8 @@ let rec instr s = | 0x3d -> let a, o = memop s in i64_store16 a o | 0x3e -> let a, o = memop s in i64_store32 a o - | 0x3f -> - expect 0x00 s "zero flag expected"; - memory_size - | 0x40 -> - expect 0x00 s "zero flag expected"; - memory_grow + | 0x3f -> zero s; memory_size + | 0x40 -> zero s; memory_grow | 0x41 -> i32_const (at vs32 s) | 0x42 -> i64_const (at vs64 s) @@ -454,7 +450,46 @@ let rec instr s = | 0xc3 -> i64_extend16_s | 0xc4 -> i64_extend32_s - | 0xfc -> math_prefix s + | 0xc5 | 0xc6 | 0xc7 | 0xc8 | 0xc9 | 0xca | 0xcb + | 0xcc | 0xcd | 0xce | 0xcf as b -> illegal s pos b + + | 0xd0 -> ref_null (ref_type s) + | 0xd1 -> ref_is_null + | 0xd2 -> ref_func (at var s) + + | 0xfc as b -> + (match vu32 s with + | 0x00l -> i32_trunc_sat_f32_s + | 0x01l -> i32_trunc_sat_f32_u + | 0x02l -> i32_trunc_sat_f64_s + | 0x03l -> i32_trunc_sat_f64_u + | 0x04l -> i64_trunc_sat_f32_s + | 0x05l -> i64_trunc_sat_f32_u + | 0x06l -> i64_trunc_sat_f64_s + | 0x07l -> i64_trunc_sat_f64_u + + | 0x08l -> + let x = at var s in + zero s; memory_init x + | 0x09l -> data_drop (at var s) + | 0x0al -> zero s; zero s; memory_copy + | 0x0bl -> zero s; memory_fill + + | 0x0cl -> + let y = at var s in + let x = at var s in + table_init x y + | 0x0dl -> elem_drop (at var s) + | 0x0el -> + let x = at var s in + let y = at var s in + table_copy x y + | 0x0fl -> table_grow (at var s) + | 0x10l -> table_size (at var s) + | 0x11l -> table_fill (at var s) + + | n -> illegal2 s pos b n + ) | b -> illegal s pos b @@ -491,6 +526,7 @@ let id s = | 9 -> `ElemSection | 10 -> `CodeSection | 11 -> `DataSection + | 12 -> `DataCountSection | _ -> error s (pos s) "malformed section id" ) bo @@ -561,8 +597,8 @@ let memory_section s = let global s = let gtype = global_type s in - let value = const s in - {gtype; value} + let ginit = const s in + {gtype; ginit} let global_section s = section `GlobalSection (vec (at global)) [] s @@ -617,26 +653,106 @@ let code_section s = (* Element section *) -let segment dat s = +let passive s = + Passive + +let active s = let index = at var s in let offset = const s in - let init = dat s in - {index; offset; init} + Active {index; offset} + +let active_zero s = + let index = Source.(0l @@ Source.no_region) in + let offset = const s in + Active {index; offset} + +let declarative s = + Declarative -let table_segment s = - segment (vec (at var)) s +let elem_index s = + let x = at var s in + [Source.(ref_func x @@ x.at)] + +let elem_kind s = + match u8 s with + | 0x00 -> FuncRefType + | _ -> error s (pos s - 1) "malformed element kind" + +let elem s = + match vu32 s with + | 0x00l -> + let emode = at active_zero s in + let einit = vec (at elem_index) s in + {etype = FuncRefType; einit; emode} + | 0x01l -> + let emode = at passive s in + let etype = elem_kind s in + let einit = vec (at elem_index) s in + {etype; einit; emode} + | 0x02l -> + let emode = at active s in + let etype = elem_kind s in + let einit = vec (at elem_index) s in + {etype; einit; emode} + | 0x03l -> + let emode = at declarative s in + let etype = elem_kind s in + let einit = vec (at elem_index) s in + {etype; einit; emode} + | 0x04l -> + let emode = at active_zero s in + let einit = vec const s in + {etype = FuncRefType; einit; emode} + | 0x05l -> + let emode = at passive s in + let etype = ref_type s in + let einit = vec const s in + {etype; einit; emode} + | 0x06l -> + let emode = at active s in + let etype = ref_type s in + let einit = vec const s in + {etype; einit; emode} + | 0x07l -> + let emode = at declarative s in + let etype = ref_type s in + let einit = vec const s in + {etype; einit; emode} + | _ -> error s (pos s - 1) "malformed elements segment kind" let elem_section s = - section `ElemSection (vec (at table_segment)) [] s + section `ElemSection (vec (at elem)) [] s (* Data section *) -let memory_segment s = - segment string s +let data s = + match vu32 s with + | 0x00l -> + let dmode = at active_zero s in + let dinit = string s in + {dinit; dmode} + | 0x01l -> + let dmode = at passive s in + let dinit = string s in + {dinit; dmode} + | 0x02l -> + let dmode = at active s in + let dinit = string s in + {dinit; dmode} + | _ -> error s (pos s - 1) "malformed data segment kind" let data_section s = - section `DataSection (vec (at memory_segment)) [] s + section `DataSection (vec (at data)) [] s + + +(* DataCount section *) + +let data_count s = + Some (vu32 s) + +let data_count_section s = + section `DataCountSection data_count None s (* Custom section *) @@ -679,17 +795,24 @@ let module_ s = iterate custom_section s; let elems = elem_section s in iterate custom_section s; + let data_count = data_count_section s in + iterate custom_section s; let func_bodies = code_section s in iterate custom_section s; - let data = data_section s in + let datas = data_section s in iterate custom_section s; require (pos s = len s) s (len s) "junk after last section"; require (List.length func_types = List.length func_bodies) s (len s) "function and code section have inconsistent lengths"; + require (data_count = None || data_count = Some (Lib.List32.length datas)) + s (len s) "data count and data section have inconsistent lengths"; + require (data_count <> None || + List.for_all Free.(fun f -> (func f).datas = Set.empty) func_bodies) + s (len s) "data count section required"; let funcs = List.map2 Source.(fun t f -> {f.it with ftype = t} @@ f.at) func_types func_bodies - in {types; tables; memories; globals; funcs; imports; exports; elems; data; start} + in {types; tables; memories; globals; funcs; imports; exports; elems; datas; start} let decode name bs = at module_ (stream name bs) diff --git a/interpreter/binary/encode.ml b/interpreter/binary/encode.ml index 6e797edab7..4485966bb4 100644 --- a/interpreter/binary/encode.ml +++ b/interpreter/binary/encode.ml @@ -91,24 +91,29 @@ let encode m = open Types - let value_type = function + let num_type = function | I32Type -> vs7 (-0x01) | I64Type -> vs7 (-0x02) | F32Type -> vs7 (-0x03) | F64Type -> vs7 (-0x04) - let elem_type = function + let ref_type = function | FuncRefType -> vs7 (-0x10) + | ExternRefType -> vs7 (-0x11) + + let value_type = function + | NumType t -> num_type t + | RefType t -> ref_type t - let stack_type = vec value_type let func_type = function - | FuncType (ins, out) -> vs7 (-0x20); stack_type ins; stack_type out + | FuncType (ts1, ts2) -> + vs7 (-0x20); vec value_type ts1; vec value_type ts2 let limits vu {min; max} = bool (max <> None); vu min; opt vu max let table_type = function - | TableType (lim, t) -> elem_type t; limits vu32 lim + | TableType (lim, t) -> ref_type t; limits vu32 lim let memory_type = function | MemoryType lim -> limits vu32 lim @@ -155,10 +160,11 @@ let encode m = | BrTable (xs, x) -> op 0x0e; vec var xs; var x | Return -> op 0x0f | Call x -> op 0x10; var x - | CallIndirect x -> op 0x11; var x; u8 0x00 + | CallIndirect (x, y) -> op 0x11; var y; var x | Drop -> op 0x1a - | Select -> op 0x1b + | Select None -> op 0x1b + | Select (Some ts) -> op 0x1c; vec value_type ts | LocalGet x -> op 0x20; var x | LocalSet x -> op 0x21; var x @@ -166,6 +172,15 @@ let encode m = | GlobalGet x -> op 0x23; var x | GlobalSet x -> op 0x24; var x + | TableGet x -> op 0x25; var x + | TableSet x -> op 0x26; var x + | TableSize x -> op 0xfc; vu32 0x10l; var x + | TableGrow x -> op 0xfc; vu32 0x0fl; var x + | TableFill x -> op 0xfc; vu32 0x11l; var x + | TableCopy (x, y) -> op 0xfc; vu32 0x0el; var x; var y + | TableInit (x, y) -> op 0xfc; vu32 0x0cl; var y; var x + | ElemDrop x -> op 0xfc; vu32 0x0dl; var x + | Load ({ty = I32Type; sz = None; _} as mo) -> op 0x28; memop mo | Load ({ty = I64Type; sz = None; _} as mo) -> op 0x29; memop mo | Load ({ty = F32Type; sz = None; _} as mo) -> op 0x2a; memop mo @@ -209,6 +224,14 @@ let encode m = | MemorySize -> op 0x3f; u8 0x00 | MemoryGrow -> op 0x40; u8 0x00 + | MemoryFill -> op 0xfc; vu32 0x0bl; u8 0x00 + | MemoryCopy -> op 0xfc; vu32 0x0al; u8 0x00; u8 0x00 + | MemoryInit x -> op 0xfc; vu32 0x08l; var x; u8 0x00 + | DataDrop x -> op 0xfc; vu32 0x09l; var x + + | RefNull t -> op 0xd0; ref_type t + | RefIsNull -> op 0xd1 + | RefFunc x -> op 0xd2; var x | Const {it = I32 c; _} -> op 0x41; vs32 c | Const {it = I64 c; _} -> op 0x42; vs64 c @@ -435,8 +458,8 @@ let encode m = (* Global section *) let global g = - let {gtype; value} = g.it in - global_type gtype; const value + let {gtype; ginit} = g.it in + global_type gtype; const ginit let global_section gs = section 6 (vec global) gs (gs <> []) @@ -482,25 +505,72 @@ let encode m = section 10 (vec code) fs (fs <> []) (* Element section *) - let segment dat seg = - let {index; offset; init} = seg.it in - var index; const offset; dat init + let is_elem_kind = function + | FuncRefType -> true + | _ -> false + + let elem_kind = function + | FuncRefType -> u8 0x00 + | _ -> assert false - let table_segment seg = - segment (vec var) seg + let is_elem_index e = + match e.it with + | [{it = RefFunc _; _}] -> true + | _ -> false + + let elem_index e = + match e.it with + | [{it = RefFunc x; _}] -> var x + | _ -> assert false + + let elem seg = + let {etype; einit; emode} = seg.it in + if is_elem_kind etype && List.for_all is_elem_index einit then + match emode.it with + | Passive -> + vu32 0x01l; elem_kind etype; vec elem_index einit + | Active {index; offset} when index.it = 0l && etype = FuncRefType -> + vu32 0x00l; const offset; vec elem_index einit + | Active {index; offset} -> + vu32 0x02l; + var index; const offset; elem_kind etype; vec elem_index einit + | Declarative -> + vu32 0x03l; elem_kind etype; vec elem_index einit + else + match emode.it with + | Passive -> + vu32 0x05l; ref_type etype; vec const einit + | Active {index; offset} when index.it = 0l && etype = FuncRefType -> + vu32 0x04l; const offset; vec const einit + | Active {index; offset} -> + vu32 0x06l; var index; const offset; ref_type etype; vec const einit + | Declarative -> + vu32 0x07l; ref_type etype; vec const einit let elem_section elems = - section 9 (vec table_segment) elems (elems <> []) + section 9 (vec elem) elems (elems <> []) (* Data section *) - let memory_segment seg = - segment string seg + let data seg = + let {dinit; dmode} = seg.it in + match dmode.it with + | Passive -> + vu32 0x01l; string dinit + | Active {index; offset} when index.it = 0l -> + vu32 0x00l; const offset; string dinit + | Active {index; offset} -> + vu32 0x02l; var index; const offset; string dinit + | Declarative -> + assert false - let data_section data = - section 11 (vec memory_segment) data (data <> []) + let data_section datas = + section 11 (vec data) datas (datas <> []) - (* Module *) + (* Data count section *) + let data_count_section datas m = + section 12 len (List.length datas) Free.((module_ m).datas <> Set.empty) + (* Module *) let module_ m = u32 0x6d736100l; u32 version; @@ -513,7 +583,8 @@ let encode m = export_section m.it.exports; start_section m.it.start; elem_section m.it.elems; + data_count_section m.it.datas m; code_section m.it.funcs; - data_section m.it.data + data_section m.it.datas end in E.module_ m; to_string s diff --git a/interpreter/exec/eval.ml b/interpreter/exec/eval.ml index 6687dec930..4a0134dd94 100644 --- a/interpreter/exec/eval.ml +++ b/interpreter/exec/eval.ml @@ -17,6 +17,13 @@ exception Trap = Trap.Error exception Crash = Crash.Error (* failure that cannot happen in valid code *) exception Exhaustion = Exhaustion.Error +let table_error at = function + | Table.Bounds -> "out of bounds table access" + | Table.SizeOverflow -> "table size overflow" + | Table.SizeLimit -> "table size limit reached" + | Table.Type -> Crash.error at "type mismatch at table access" + | exn -> raise exn + let memory_error at = function | Memory.Bounds -> "out of bounds memory access" | Memory.SizeOverflow -> "memory size overflow" @@ -30,8 +37,8 @@ let numeric_error at = function | Numeric_error.InvalidConversionToInteger -> "invalid conversion to integer" | Eval_numeric.TypeError (i, v, t) -> Crash.error at - ("type error, expected " ^ Types.string_of_value_type t ^ " as operand " ^ - string_of_int i ^ ", got " ^ Types.string_of_value_type (type_of v)) + ("type error, expected " ^ Types.string_of_num_type t ^ " as operand " ^ + string_of_int i ^ ", got " ^ Types.string_of_num_type (type_of_num v)) | exn -> raise exn @@ -50,6 +57,7 @@ type code = value stack * admin_instr list and admin_instr = admin_instr' phrase and admin_instr' = | Plain of instr' + | Refer of ref_ | Invoke of func_inst | Trapping of string | Returning of value stack @@ -78,19 +86,18 @@ let func (inst : module_inst) x = lookup "function" inst.funcs x let table (inst : module_inst) x = lookup "table" inst.tables x let memory (inst : module_inst) x = lookup "memory" inst.memories x let global (inst : module_inst) x = lookup "global" inst.globals x +let elem (inst : module_inst) x = lookup "element segment" inst.elems x +let data (inst : module_inst) x = lookup "data segment" inst.datas x let local (frame : frame) x = lookup "local" frame.locals x -let elem inst x i at = - match Table.load (table inst x) i with - | Table.Uninitialized -> - Trap.error at ("uninitialized element " ^ Int32.to_string i) - | f -> f - | exception Table.Bounds -> +let any_ref inst x i at = + try Table.load (table inst x) i with Table.Bounds -> Trap.error at ("undefined element " ^ Int32.to_string i) -let func_elem inst x i at = - match elem inst x i at with - | FuncElem f -> f +let func_ref inst x i at = + match any_ref inst x i at with + | FuncRef f -> f + | NullRef _ -> Trap.error at ("uninitialized element " ^ Int32.to_string i) | _ -> Crash.error at ("type mismatch for element " ^ Int32.to_string i) let func_type_of = function @@ -121,6 +128,22 @@ let drop n (vs : 'a stack) at = * c : config *) +let mem_oob frame x i n = + I64.gt_u (I64.add (I64_convert.extend_i32_u i) (I64_convert.extend_i32_u n)) + (Memory.bound (memory frame.inst x)) + +let data_oob frame x i n = + I64.gt_u (I64.add (I64_convert.extend_i32_u i) (I64_convert.extend_i32_u n)) + (I64.of_int_u (String.length !(data frame.inst x))) + +let table_oob frame x i n = + I64.gt_u (I64.add (I64_convert.extend_i32_u i) (I64_convert.extend_i32_u n)) + (I64_convert.extend_i32_u (Table.size (table frame.inst x))) + +let elem_oob frame x i n = + I64.gt_u (I64.add (I64_convert.extend_i32_u i) (I64_convert.extend_i32_u n)) + (I64.of_int_u (List.length !(elem frame.inst x))) + let rec step (c : config) : config = let {frame; code = vs, es; _} = c in let e = List.hd es in @@ -147,26 +170,26 @@ let rec step (c : config) : config = let args, vs' = take n1 vs e.at, drop n1 vs e.at in vs', [Label (n1, [e' @@ e.at], (args, List.map plain es')) @@ e.at] - | If (bt, es1, es2), I32 0l :: vs' -> - vs', [Plain (Block (bt, es2)) @@ e.at] - - | If (bt, es1, es2), I32 i :: vs' -> - vs', [Plain (Block (bt, es1)) @@ e.at] + | If (bt, es1, es2), Num (I32 i) :: vs' -> + if i = 0l then + vs', [Plain (Block (bt, es2)) @@ e.at] + else + vs', [Plain (Block (bt, es1)) @@ e.at] | Br x, vs -> [], [Breaking (x.it, vs) @@ e.at] - | BrIf x, I32 0l :: vs' -> - vs', [] - - | BrIf x, I32 i :: vs' -> - vs', [Plain (Br x) @@ e.at] - - | BrTable (xs, x), I32 i :: vs' when I32.ge_u i (Lib.List32.length xs) -> - vs', [Plain (Br x) @@ e.at] + | BrIf x, Num (I32 i) :: vs' -> + if i = 0l then + vs', [] + else + vs', [Plain (Br x) @@ e.at] - | BrTable (xs, x), I32 i :: vs' -> - vs', [Plain (Br (Lib.List32.nth xs i)) @@ e.at] + | BrTable (xs, x), Num (I32 i) :: vs' -> + if I32.ge_u i (Lib.List32.length xs) then + vs', [Plain (Br x) @@ e.at] + else + vs', [Plain (Br (Lib.List32.nth xs i)) @@ e.at] | Return, vs -> [], [Returning vs @@ e.at] @@ -174,9 +197,9 @@ let rec step (c : config) : config = | Call x, vs -> vs, [Invoke (func frame.inst x) @@ e.at] - | CallIndirect x, I32 i :: vs -> - let func = func_elem frame.inst (0l @@ e.at) i e.at in - if type_ frame.inst x <> Func.type_of func then + | CallIndirect (x, y), Num (I32 i) :: vs -> + let func = func_ref frame.inst x i e.at in + if type_ frame.inst y <> Func.type_of func then vs, [Trapping "indirect call type mismatch" @@ e.at] else vs, [Invoke func @@ e.at] @@ -184,11 +207,11 @@ let rec step (c : config) : config = | Drop, v :: vs' -> vs', [] - | Select, I32 0l :: v2 :: v1 :: vs' -> - v2 :: vs', [] - - | Select, I32 i :: v2 :: v1 :: vs' -> - v1 :: vs', [] + | Select _, Num (I32 i) :: v2 :: v1 :: vs' -> + if i = 0l then + v2 :: vs', [] + else + v1 :: vs', [] | LocalGet x, vs -> !(local frame x) :: vs, [] @@ -209,70 +232,246 @@ let rec step (c : config) : config = with Global.NotMutable -> Crash.error e.at "write to immutable global" | Global.Type -> Crash.error e.at "type mismatch at global write") - | Load {offset; ty; sz; _}, I32 i :: vs' -> + | TableGet x, Num (I32 i) :: vs' -> + (try Ref (Table.load (table frame.inst x) i) :: vs', [] + with exn -> vs', [Trapping (table_error e.at exn) @@ e.at]) + + | TableSet x, Ref r :: Num (I32 i) :: vs' -> + (try Table.store (table frame.inst x) i r; vs', [] + with exn -> vs', [Trapping (table_error e.at exn) @@ e.at]) + + | TableSize x, vs -> + Num (I32 (Table.size (table frame.inst x))) :: vs, [] + + | TableGrow x, Num (I32 delta) :: Ref r :: vs' -> + let tab = table frame.inst x in + let old_size = Table.size tab in + let result = + try Table.grow tab delta r; old_size + with Table.SizeOverflow | Table.SizeLimit | Table.OutOfMemory -> -1l + in Num (I32 result) :: vs', [] + + | TableFill x, Num (I32 n) :: Ref r :: Num (I32 i) :: vs' -> + if table_oob frame x i n then + vs', [Trapping (table_error e.at Table.Bounds) @@ e.at] + else if n = 0l then + vs', [] + else + let _ = assert (I32.lt_u i 0xffff_ffffl) in + vs', List.map (at e.at) [ + Plain (Const (I32 i @@ e.at)); + Refer r; + Plain (TableSet x); + Plain (Const (I32 (I32.add i 1l) @@ e.at)); + Refer r; + Plain (Const (I32 (I32.sub n 1l) @@ e.at)); + Plain (TableFill x); + ] + + | TableCopy (x, y), Num (I32 n) :: Num (I32 s) :: Num (I32 d) :: vs' -> + if table_oob frame x d n || table_oob frame y s n then + vs', [Trapping (table_error e.at Table.Bounds) @@ e.at] + else if n = 0l then + vs', [] + else if I32.le_u d s then + vs', List.map (at e.at) [ + Plain (Const (I32 d @@ e.at)); + Plain (Const (I32 s @@ e.at)); + Plain (TableGet y); + Plain (TableSet x); + Plain (Const (I32 (I32.add d 1l) @@ e.at)); + Plain (Const (I32 (I32.add s 1l) @@ e.at)); + Plain (Const (I32 (I32.sub n 1l) @@ e.at)); + Plain (TableCopy (x, y)); + ] + else (* d > s *) + vs', List.map (at e.at) [ + Plain (Const (I32 (I32.add d 1l) @@ e.at)); + Plain (Const (I32 (I32.add s 1l) @@ e.at)); + Plain (Const (I32 (I32.sub n 1l) @@ e.at)); + Plain (TableCopy (x, y)); + Plain (Const (I32 d @@ e.at)); + Plain (Const (I32 s @@ e.at)); + Plain (TableGet y); + Plain (TableSet x); + ] + + | TableInit (x, y), Num (I32 n) :: Num (I32 s) :: Num (I32 d) :: vs' -> + if table_oob frame x d n || elem_oob frame y s n then + vs', [Trapping (table_error e.at Table.Bounds) @@ e.at] + else if n = 0l then + vs', [] + else + let seg = !(elem frame.inst y) in + vs', List.map (at e.at) [ + Plain (Const (I32 d @@ e.at)); + Refer (List.nth seg (Int32.to_int s)); + Plain (TableSet x); + Plain (Const (I32 (I32.add d 1l) @@ e.at)); + Plain (Const (I32 (I32.add s 1l) @@ e.at)); + Plain (Const (I32 (I32.sub n 1l) @@ e.at)); + Plain (TableInit (x, y)); + ] + + | ElemDrop x, vs -> + let seg = elem frame.inst x in + seg := []; + vs, [] + + | Load {offset; ty; sz; _}, Num (I32 i) :: vs' -> let mem = memory frame.inst (0l @@ e.at) in - let addr = I64_convert.extend_i32_u i in + let a = I64_convert.extend_i32_u i in (try - let v = + let n = match sz with - | None -> Memory.load_value mem addr offset ty - | Some (sz, ext) -> Memory.load_packed sz ext mem addr offset ty - in v :: vs', [] + | None -> Memory.load_num mem a offset ty + | Some (sz, ext) -> Memory.load_packed sz ext mem a offset ty + in Num n :: vs', [] with exn -> vs', [Trapping (memory_error e.at exn) @@ e.at]) - | Store {offset; sz; _}, v :: I32 i :: vs' -> + | Store {offset; sz; _}, Num n :: Num (I32 i) :: vs' -> let mem = memory frame.inst (0l @@ e.at) in - let addr = I64_convert.extend_i32_u i in + let a = I64_convert.extend_i32_u i in (try (match sz with - | None -> Memory.store_value mem addr offset v - | Some sz -> Memory.store_packed sz mem addr offset v + | None -> Memory.store_num mem a offset n + | Some sz -> Memory.store_packed sz mem a offset n ); vs', [] with exn -> vs', [Trapping (memory_error e.at exn) @@ e.at]); - | MemorySize, vs -> let mem = memory frame.inst (0l @@ e.at) in - I32 (Memory.size mem) :: vs, [] + Num (I32 (Memory.size mem)) :: vs, [] - | MemoryGrow, I32 delta :: vs' -> + | MemoryGrow, Num (I32 delta) :: vs' -> let mem = memory frame.inst (0l @@ e.at) in let old_size = Memory.size mem in let result = try Memory.grow mem delta; old_size with Memory.SizeOverflow | Memory.SizeLimit | Memory.OutOfMemory -> -1l - in I32 result :: vs', [] + in Num (I32 result) :: vs', [] - | Const v, vs -> - v.it :: vs, [] + | MemoryFill, Num (I32 n) :: Num k :: Num (I32 i) :: vs' -> + if mem_oob frame (0l @@ e.at) i n then + vs', [Trapping (memory_error e.at Memory.Bounds) @@ e.at] + else if n = 0l then + vs', [] + else + vs', List.map (at e.at) [ + Plain (Const (I32 i @@ e.at)); + Plain (Const (k @@ e.at)); + Plain (Store + {ty = I32Type; align = 0; offset = 0l; sz = Some Pack8}); + Plain (Const (I32 (I32.add i 1l) @@ e.at)); + Plain (Const (k @@ e.at)); + Plain (Const (I32 (I32.sub n 1l) @@ e.at)); + Plain (MemoryFill); + ] + + | MemoryCopy, Num (I32 n) :: Num (I32 s) :: Num (I32 d) :: vs' -> + if mem_oob frame (0l @@ e.at) s n || mem_oob frame (0l @@ e.at) d n then + vs', [Trapping (memory_error e.at Memory.Bounds) @@ e.at] + else if n = 0l then + vs', [] + else if I32.le_u d s then + vs', List.map (at e.at) [ + Plain (Const (I32 d @@ e.at)); + Plain (Const (I32 s @@ e.at)); + Plain (Load + {ty = I32Type; align = 0; offset = 0l; sz = Some (Pack8, ZX)}); + Plain (Store + {ty = I32Type; align = 0; offset = 0l; sz = Some Pack8}); + Plain (Const (I32 (I32.add d 1l) @@ e.at)); + Plain (Const (I32 (I32.add s 1l) @@ e.at)); + Plain (Const (I32 (I32.sub n 1l) @@ e.at)); + Plain (MemoryCopy); + ] + else (* d > s *) + vs', List.map (at e.at) [ + Plain (Const (I32 (I32.add d 1l) @@ e.at)); + Plain (Const (I32 (I32.add s 1l) @@ e.at)); + Plain (Const (I32 (I32.sub n 1l) @@ e.at)); + Plain (MemoryCopy); + Plain (Const (I32 d @@ e.at)); + Plain (Const (I32 s @@ e.at)); + Plain (Load + {ty = I32Type; align = 0; offset = 0l; sz = Some (Pack8, ZX)}); + Plain (Store + {ty = I32Type; align = 0; offset = 0l; sz = Some Pack8}); + ] + + | MemoryInit x, Num (I32 n) :: Num (I32 s) :: Num (I32 d) :: vs' -> + if mem_oob frame (0l @@ e.at) d n || data_oob frame x s n then + vs', [Trapping (memory_error e.at Memory.Bounds) @@ e.at] + else if n = 0l then + vs', [] + else + let seg = !(data frame.inst x) in + let b = Int32.of_int (Char.code seg.[Int32.to_int s]) in + vs', List.map (at e.at) [ + Plain (Const (I32 d @@ e.at)); + Plain (Const (I32 b @@ e.at)); + Plain (Store + {ty = I32Type; align = 0; offset = 0l; sz = Some Pack8}); + Plain (Const (I32 (I32.add d 1l) @@ e.at)); + Plain (Const (I32 (I32.add s 1l) @@ e.at)); + Plain (Const (I32 (I32.sub n 1l) @@ e.at)); + Plain (MemoryInit x); + ] + + | DataDrop x, vs -> + let seg = data frame.inst x in + seg := ""; + vs, [] - | Test testop, v :: vs' -> - (try value_of_bool (Eval_numeric.eval_testop testop v) :: vs', [] + | RefNull t, vs' -> + Ref (NullRef t) :: vs', [] + + | RefIsNull, Ref r :: vs' -> + (match r with + | NullRef _ -> + Num (I32 1l) :: vs', [] + | _ -> + Num (I32 0l) :: vs', [] + ) + + | RefFunc x, vs' -> + let f = func frame.inst x in + Ref (FuncRef f) :: vs', [] + + | Const n, vs -> + Num n.it :: vs, [] + + | Test testop, Num n :: vs' -> + (try value_of_bool (Eval_numeric.eval_testop testop n) :: vs', [] with exn -> vs', [Trapping (numeric_error e.at exn) @@ e.at]) - | Compare relop, v2 :: v1 :: vs' -> - (try value_of_bool (Eval_numeric.eval_relop relop v1 v2) :: vs', [] + | Compare relop, Num n2 :: Num n1 :: vs' -> + (try value_of_bool (Eval_numeric.eval_relop relop n1 n2) :: vs', [] with exn -> vs', [Trapping (numeric_error e.at exn) @@ e.at]) - | Unary unop, v :: vs' -> - (try Eval_numeric.eval_unop unop v :: vs', [] + | Unary unop, Num n :: vs' -> + (try Num (Eval_numeric.eval_unop unop n) :: vs', [] with exn -> vs', [Trapping (numeric_error e.at exn) @@ e.at]) - | Binary binop, v2 :: v1 :: vs' -> - (try Eval_numeric.eval_binop binop v1 v2 :: vs', [] + | Binary binop, Num n2 :: Num n1 :: vs' -> + (try Num (Eval_numeric.eval_binop binop n1 n2) :: vs', [] with exn -> vs', [Trapping (numeric_error e.at exn) @@ e.at]) - | Convert cvtop, v :: vs' -> - (try Eval_numeric.eval_cvtop cvtop v :: vs', [] + | Convert cvtop, Num n :: vs' -> + (try Num (Eval_numeric.eval_cvtop cvtop n) :: vs', [] with exn -> vs', [Trapping (numeric_error e.at exn) @@ e.at]) | _ -> let s1 = string_of_values (List.rev vs) in - let s2 = string_of_value_types (List.map type_of (List.rev vs)) in + let s2 = string_of_value_types (List.map type_of_value (List.rev vs)) in Crash.error e.at ("missing or ill-typed operand on stack (" ^ s1 ^ " : " ^ s2 ^ ")") ) + | Refer r, vs -> + Ref r :: vs, [] + | Trapping msg, vs -> assert false @@ -350,10 +549,12 @@ let rec eval (c : config) : value stack = (* Functions & Constants *) let invoke (func : func_inst) (vs : value list) : value list = - let at = match func with Func.AstFunc (_,_, f) -> f.at | _ -> no_region in + let at = match func with Func.AstFunc (_, _, f) -> f.at | _ -> no_region in let FuncType (ins, out) = Func.type_of func in - if List.map Values.type_of vs <> ins then - Crash.error at "wrong number or types of arguments"; + if List.length vs <> List.length ins then + Crash.error at "wrong number of arguments"; + if not (List.for_all2 (fun v -> (=) (type_of_value v)) vs ins) then + Crash.error at "wrong types of arguments"; let c = config empty_module_inst (List.rev vs) [Invoke func @@ at] in try List.rev (eval c) with Stack_overflow -> Exhaustion.error at "call stack exhausted" @@ -364,11 +565,6 @@ let eval_const (inst : module_inst) (const : const) : value = | [v] -> v | vs -> Crash.error const.at "wrong number of results on stack" -let i32 (v : value) at = - match v with - | I32 i -> i - | _ -> Crash.error at "type error: i32 value expected" - (* Modules *) @@ -377,15 +573,16 @@ let create_func (inst : module_inst) (f : func) : func_inst = let create_table (inst : module_inst) (tab : table) : table_inst = let {ttype} = tab.it in - Table.alloc ttype + let TableType (_lim, t) = ttype in + Table.alloc ttype (NullRef t) let create_memory (inst : module_inst) (mem : memory) : memory_inst = let {mtype} = mem.it in Memory.alloc mtype let create_global (inst : module_inst) (glob : global) : global_inst = - let {gtype; value} = glob.it in - let v = eval_const inst value in + let {gtype; ginit} = glob.it in + let v = eval_const inst ginit in Global.alloc gtype v let create_export (inst : module_inst) (ex : export) : export_inst = @@ -396,51 +593,73 @@ let create_export (inst : module_inst) (ex : export) : export_inst = | TableExport x -> ExternTable (table inst x) | MemoryExport x -> ExternMemory (memory inst x) | GlobalExport x -> ExternGlobal (global inst x) - in name, ext + in (name, ext) +let create_elem (inst : module_inst) (seg : elem_segment) : elem_inst = + let {etype; einit; _} = seg.it in + ref (List.map (fun c -> as_ref (eval_const inst c)) einit) -let init_func (inst : module_inst) (func : func_inst) = - match func with - | Func.AstFunc (_, inst_ref, _) -> inst_ref := inst - | _ -> assert false - -let init_table (inst : module_inst) (seg : table_segment) = - let {index; offset = const; init} = seg.it in - let tab = table inst index in - let offset = i32 (eval_const inst const) const.at in - let end_ = Int32.(add offset (of_int (List.length init))) in - let bound = Table.size tab in - if I32.lt_u bound end_ || I32.lt_u end_ offset then - Link.error seg.at "elements segment does not fit table"; - fun () -> - Table.blit tab offset (List.map (fun x -> FuncElem (func inst x)) init) - -let init_memory (inst : module_inst) (seg : memory_segment) = - let {index; offset = const; init} = seg.it in - let mem = memory inst index in - let offset' = i32 (eval_const inst const) const.at in - let offset = I64_convert.extend_i32_u offset' in - let end_ = Int64.(add offset (of_int (String.length init))) in - let bound = Memory.bound mem in - if I64.lt_u bound end_ || I64.lt_u end_ offset then - Link.error seg.at "data segment does not fit memory"; - fun () -> Memory.store_bytes mem offset init +let create_data (inst : module_inst) (seg : data_segment) : data_inst = + let {dinit; _} = seg.it in + ref dinit let add_import (m : module_) (ext : extern) (im : import) (inst : module_inst) : module_inst = if not (match_extern_type (extern_type_of ext) (import_type m im)) then - Link.error im.at "incompatible import type"; + Link.error im.at ("incompatible import type for " ^ + "\"" ^ Utf8.encode im.it.module_name ^ "\" " ^ + "\"" ^ Utf8.encode im.it.item_name ^ "\": " ^ + "expected " ^ Types.string_of_extern_type (import_type m im) ^ + ", got " ^ Types.string_of_extern_type (extern_type_of ext)); match ext with | ExternFunc func -> {inst with funcs = func :: inst.funcs} | ExternTable tab -> {inst with tables = tab :: inst.tables} | ExternMemory mem -> {inst with memories = mem :: inst.memories} | ExternGlobal glob -> {inst with globals = glob :: inst.globals} +let init_func (inst : module_inst) (func : func_inst) = + match func with + | Func.AstFunc (_, inst_ref, _) -> inst_ref := inst + | _ -> assert false + +let run_elem i elem = + let at = elem.it.emode.at in + let x = i @@ at in + match elem.it.emode.it with + | Passive -> [] + | Active {index; offset} -> + offset.it @ [ + Const (I32 0l @@ at) @@ at; + Const (I32 (Lib.List32.length elem.it.einit) @@ at) @@ at; + TableInit (index, x) @@ at; + ElemDrop x @@ at + ] + | Declarative -> + [ElemDrop x @@ at] + +let run_data i data = + let at = data.it.dmode.at in + let x = i @@ at in + match data.it.dmode.it with + | Passive -> [] + | Active {index; offset} -> + assert (index.it = 0l); + offset.it @ [ + Const (I32 0l @@ at) @@ at; + Const (I32 (Int32.of_int (String.length data.it.dinit)) @@ at) @@ at; + MemoryInit x @@ at; + DataDrop x @@ at + ] + | Declarative -> assert false + +let run_start start = + [Call start @@ start.at] + let init (m : module_) (exts : extern list) : module_inst = let { imports; tables; memories; globals; funcs; types; - exports; elems; data; start + exports; elems; datas; start } = m.it in if List.length exts <> List.length imports then @@ -450,19 +669,24 @@ let init (m : module_) (exts : extern list) : module_inst = types = List.map (fun type_ -> type_.it) types } in let fs = List.map (create_func inst0) funcs in - let inst1 = - { inst0 with - funcs = inst0.funcs @ fs; - tables = inst0.tables @ List.map (create_table inst0) tables; - memories = inst0.memories @ List.map (create_memory inst0) memories; - globals = inst0.globals @ List.map (create_global inst0) globals; + let inst1 = {inst0 with funcs = inst0.funcs @ fs} in + let inst2 = + { inst1 with + tables = inst1.tables @ List.map (create_table inst1) tables; + memories = inst1.memories @ List.map (create_memory inst1) memories; + globals = inst1.globals @ List.map (create_global inst1) globals; + } + in + let inst = + { inst2 with + exports = List.map (create_export inst2) exports; + elems = List.map (create_elem inst2) elems; + datas = List.map (create_data inst2) datas; } in - let inst = {inst1 with exports = List.map (create_export inst1) exports} in List.iter (init_func inst) fs; - let init_elems = List.map (init_table inst) elems in - let init_datas = List.map (init_memory inst) data in - List.iter (fun f -> f ()) init_elems; - List.iter (fun f -> f ()) init_datas; - Lib.Option.app (fun x -> ignore (invoke (func inst x) [])) start; + let es_elem = List.concat (Lib.List32.mapi run_elem elems) in + let es_data = List.concat (Lib.List32.mapi run_data datas) in + let es_start = Lib.Option.get (Lib.Option.map run_start start) [] in + ignore (eval (config inst [] (List.map plain (es_elem @ es_data @ es_start)))); inst diff --git a/interpreter/exec/eval_numeric.ml b/interpreter/exec/eval_numeric.ml index 7257e66a6c..3caf4d45e7 100644 --- a/interpreter/exec/eval_numeric.ml +++ b/interpreter/exec/eval_numeric.ml @@ -2,22 +2,52 @@ open Types open Values -(* Runtime type errors *) +(* Injection & projection *) -exception TypeError of int * value * value_type +exception TypeError of int * num * num_type -let of_arg f n v = - try f v with Value t -> raise (TypeError (n, v, t)) +module type NumType = +sig + type t + val to_num : t -> num + val of_num : int -> num -> t +end + +module I32Num = +struct + type t = I32.t + let to_num i = I32 i + let of_num n = function I32 i -> i | v -> raise (TypeError (n, v, I32Type)) +end + +module I64Num = +struct + type t = I64.t + let to_num i = I64 i + let of_num n = function I64 i -> i | v -> raise (TypeError (n, v, I64Type)) +end + +module F32Num = +struct + type t = F32.t + let to_num i = F32 i + let of_num n = function F32 z -> z | v -> raise (TypeError (n, v, F32Type)) +end + +module F64Num = +struct + type t = F64.t + let to_num i = F64 i + let of_num n = function F64 z -> z | v -> raise (TypeError (n, v, F64Type)) +end (* Int operators *) -module IntOp (IXX : Int.S) (Value : ValueType with type t = IXX.t) = +module IntOp (IXX : Int.S) (Num : NumType with type t = IXX.t) = struct open Ast.IntOp - - let to_value = Value.to_value - let of_value = of_arg Value.of_value + open Num let unop op = let f = match op with @@ -25,7 +55,7 @@ struct | Ctz -> IXX.ctz | Popcnt -> IXX.popcnt | ExtendS sz -> IXX.extend_s (8 * packed_size sz) - in fun v -> to_value (f (of_value 1 v)) + in fun v -> to_num (f (of_num 1 v)) let binop op = let f = match op with @@ -44,12 +74,12 @@ struct | ShrS -> IXX.shr_s | Rotl -> IXX.rotl | Rotr -> IXX.rotr - in fun v1 v2 -> to_value (f (of_value 1 v1) (of_value 2 v2)) + in fun v1 v2 -> to_num (f (of_num 1 v1) (of_num 2 v2)) let testop op = let f = match op with | Eqz -> IXX.eqz - in fun v -> f (of_value 1 v) + in fun v -> f (of_num 1 v) let relop op = let f = match op with @@ -63,21 +93,19 @@ struct | GtU -> IXX.gt_u | GeS -> IXX.ge_s | GeU -> IXX.ge_u - in fun v1 v2 -> f (of_value 1 v1) (of_value 2 v2) + in fun v1 v2 -> f (of_num 1 v1) (of_num 2 v2) end -module I32Op = IntOp (I32) (Values.I32Value) -module I64Op = IntOp (I64) (Values.I64Value) +module I32Op = IntOp (I32) (I32Num) +module I64Op = IntOp (I64) (I64Num) (* Float operators *) -module FloatOp (FXX : Float.S) (Value : ValueType with type t = FXX.t) = +module FloatOp (FXX : Float.S) (Num : NumType with type t = FXX.t) = struct open Ast.FloatOp - - let to_value = Value.to_value - let of_value = of_arg Value.of_value + open Num let unop op = let f = match op with @@ -88,7 +116,7 @@ struct | Floor -> FXX.floor | Trunc -> FXX.trunc | Nearest -> FXX.nearest - in fun v -> to_value (f (of_value 1 v)) + in fun v -> to_num (f (of_num 1 v)) let binop op = let f = match op with @@ -99,7 +127,7 @@ struct | Min -> FXX.min | Max -> FXX.max | CopySign -> FXX.copysign - in fun v1 v2 -> to_value (f (of_value 1 v1) (of_value 2 v2)) + in fun v1 v2 -> to_num (f (of_num 1 v1) (of_num 2 v2)) let testop op = assert false @@ -111,11 +139,11 @@ struct | Le -> FXX.le | Gt -> FXX.gt | Ge -> FXX.ge - in fun v1 v2 -> f (of_value 1 v1) (of_value 2 v2) + in fun v1 v2 -> f (of_num 1 v1) (of_num 2 v2) end -module F32Op = FloatOp (F32) (Values.F32Value) -module F64Op = FloatOp (F64) (Values.F64Value) +module F32Op = FloatOp (F32) (F32Num) +module F64Op = FloatOp (F64) (F64Num) (* Conversion operators *) @@ -125,19 +153,20 @@ struct open Ast.IntOp let cvtop op v = - match op with - | WrapI64 -> I32 (I32_convert.wrap_i64 (I64Op.of_value 1 v)) - | TruncSF32 -> I32 (I32_convert.trunc_f32_s (F32Op.of_value 1 v)) - | TruncUF32 -> I32 (I32_convert.trunc_f32_u (F32Op.of_value 1 v)) - | TruncSF64 -> I32 (I32_convert.trunc_f64_s (F64Op.of_value 1 v)) - | TruncUF64 -> I32 (I32_convert.trunc_f64_u (F64Op.of_value 1 v)) - | TruncSatSF32 -> I32 (I32_convert.trunc_sat_f32_s (F32Op.of_value 1 v)) - | TruncSatUF32 -> I32 (I32_convert.trunc_sat_f32_u (F32Op.of_value 1 v)) - | TruncSatSF64 -> I32 (I32_convert.trunc_sat_f64_s (F64Op.of_value 1 v)) - | TruncSatUF64 -> I32 (I32_convert.trunc_sat_f64_u (F64Op.of_value 1 v)) - | ReinterpretFloat -> I32 (I32_convert.reinterpret_f32 (F32Op.of_value 1 v)) - | ExtendSI32 -> raise (TypeError (1, v, I32Type)) - | ExtendUI32 -> raise (TypeError (1, v, I32Type)) + let i = match op with + | WrapI64 -> I32_convert.wrap_i64 (I64Num.of_num 1 v) + | TruncUF32 -> I32_convert.trunc_f32_u (F32Num.of_num 1 v) + | TruncSF32 -> I32_convert.trunc_f32_s (F32Num.of_num 1 v) + | TruncUF64 -> I32_convert.trunc_f64_u (F64Num.of_num 1 v) + | TruncSF64 -> I32_convert.trunc_f64_s (F64Num.of_num 1 v) + | TruncSatUF32 -> I32_convert.trunc_sat_f32_u (F32Num.of_num 1 v) + | TruncSatSF32 -> I32_convert.trunc_sat_f32_s (F32Num.of_num 1 v) + | TruncSatUF64 -> I32_convert.trunc_sat_f64_u (F64Num.of_num 1 v) + | TruncSatSF64 -> I32_convert.trunc_sat_f64_s (F64Num.of_num 1 v) + | ReinterpretFloat -> I32_convert.reinterpret_f32 (F32Num.of_num 1 v) + | ExtendUI32 -> raise (TypeError (1, v, I32Type)) + | ExtendSI32 -> raise (TypeError (1, v, I32Type)) + in I32Num.to_num i end module I64CvtOp = @@ -145,19 +174,20 @@ struct open Ast.IntOp let cvtop op v = - match op with - | ExtendSI32 -> I64 (I64_convert.extend_i32_s (I32Op.of_value 1 v)) - | ExtendUI32 -> I64 (I64_convert.extend_i32_u (I32Op.of_value 1 v)) - | TruncSF32 -> I64 (I64_convert.trunc_f32_s (F32Op.of_value 1 v)) - | TruncUF32 -> I64 (I64_convert.trunc_f32_u (F32Op.of_value 1 v)) - | TruncSF64 -> I64 (I64_convert.trunc_f64_s (F64Op.of_value 1 v)) - | TruncUF64 -> I64 (I64_convert.trunc_f64_u (F64Op.of_value 1 v)) - | TruncSatSF32 -> I64 (I64_convert.trunc_sat_f32_s (F32Op.of_value 1 v)) - | TruncSatUF32 -> I64 (I64_convert.trunc_sat_f32_u (F32Op.of_value 1 v)) - | TruncSatSF64 -> I64 (I64_convert.trunc_sat_f64_s (F64Op.of_value 1 v)) - | TruncSatUF64 -> I64 (I64_convert.trunc_sat_f64_u (F64Op.of_value 1 v)) - | ReinterpretFloat -> I64 (I64_convert.reinterpret_f64 (F64Op.of_value 1 v)) - | WrapI64 -> raise (TypeError (1, v, I64Type)) + let i = match op with + | ExtendUI32 -> I64_convert.extend_i32_u (I32Num.of_num 1 v) + | ExtendSI32 -> I64_convert.extend_i32_s (I32Num.of_num 1 v) + | TruncUF32 -> I64_convert.trunc_f32_u (F32Num.of_num 1 v) + | TruncSF32 -> I64_convert.trunc_f32_s (F32Num.of_num 1 v) + | TruncUF64 -> I64_convert.trunc_f64_u (F64Num.of_num 1 v) + | TruncSF64 -> I64_convert.trunc_f64_s (F64Num.of_num 1 v) + | TruncSatUF32 -> I64_convert.trunc_sat_f32_u (F32Num.of_num 1 v) + | TruncSatSF32 -> I64_convert.trunc_sat_f32_s (F32Num.of_num 1 v) + | TruncSatUF64 -> I64_convert.trunc_sat_f64_u (F64Num.of_num 1 v) + | TruncSatSF64 -> I64_convert.trunc_sat_f64_s (F64Num.of_num 1 v) + | ReinterpretFloat -> I64_convert.reinterpret_f64 (F64Num.of_num 1 v) + | WrapI64 -> raise (TypeError (1, v, I64Type)) + in I64Num.to_num i end module F32CvtOp = @@ -165,14 +195,15 @@ struct open Ast.FloatOp let cvtop op v = - match op with - | DemoteF64 -> F32 (F32_convert.demote_f64 (F64Op.of_value 1 v)) - | ConvertSI32 -> F32 (F32_convert.convert_i32_s (I32Op.of_value 1 v)) - | ConvertUI32 -> F32 (F32_convert.convert_i32_u (I32Op.of_value 1 v)) - | ConvertSI64 -> F32 (F32_convert.convert_i64_s (I64Op.of_value 1 v)) - | ConvertUI64 -> F32 (F32_convert.convert_i64_u (I64Op.of_value 1 v)) - | ReinterpretInt -> F32 (F32_convert.reinterpret_i32 (I32Op.of_value 1 v)) - | PromoteF32 -> raise (TypeError (1, v, F32Type)) + let z = match op with + | DemoteF64 -> F32_convert.demote_f64 (F64Num.of_num 1 v) + | ConvertSI32 -> F32_convert.convert_i32_s (I32Num.of_num 1 v) + | ConvertUI32 -> F32_convert.convert_i32_u (I32Num.of_num 1 v) + | ConvertSI64 -> F32_convert.convert_i64_s (I64Num.of_num 1 v) + | ConvertUI64 -> F32_convert.convert_i64_u (I64Num.of_num 1 v) + | ReinterpretInt -> F32_convert.reinterpret_i32 (I32Num.of_num 1 v) + | PromoteF32 -> raise (TypeError (1, v, F32Type)) + in F32Num.to_num z end module F64CvtOp = @@ -180,14 +211,15 @@ struct open Ast.FloatOp let cvtop op v = - match op with - | PromoteF32 -> F64 (F64_convert.promote_f32 (F32Op.of_value 1 v)) - | ConvertSI32 -> F64 (F64_convert.convert_i32_s (I32Op.of_value 1 v)) - | ConvertUI32 -> F64 (F64_convert.convert_i32_u (I32Op.of_value 1 v)) - | ConvertSI64 -> F64 (F64_convert.convert_i64_s (I64Op.of_value 1 v)) - | ConvertUI64 -> F64 (F64_convert.convert_i64_u (I64Op.of_value 1 v)) - | ReinterpretInt -> F64 (F64_convert.reinterpret_i64 (I64Op.of_value 1 v)) - | DemoteF64 -> raise (TypeError (1, v, F64Type)) + let z = match op with + | PromoteF32 -> F64_convert.promote_f32 (F32Num.of_num 1 v) + | ConvertSI32 -> F64_convert.convert_i32_s (I32Num.of_num 1 v) + | ConvertUI32 -> F64_convert.convert_i32_u (I32Num.of_num 1 v) + | ConvertSI64 -> F64_convert.convert_i64_s (I64Num.of_num 1 v) + | ConvertUI64 -> F64_convert.convert_i64_u (I64Num.of_num 1 v) + | ReinterpretInt -> F64_convert.reinterpret_i64 (I64Num.of_num 1 v) + | DemoteF64 -> raise (TypeError (1, v, F64Type)) + in F64Num.to_num z end diff --git a/interpreter/exec/eval_numeric.mli b/interpreter/exec/eval_numeric.mli index 7435b3c6bb..969e447490 100644 --- a/interpreter/exec/eval_numeric.mli +++ b/interpreter/exec/eval_numeric.mli @@ -1,9 +1,9 @@ open Values -exception TypeError of int * value * Types.value_type +exception TypeError of int * num * Types.num_type -val eval_unop : Ast.unop -> value -> value -val eval_binop : Ast.binop -> value -> value -> value -val eval_testop : Ast.testop -> value -> bool -val eval_relop : Ast.relop -> value -> value -> bool -val eval_cvtop : Ast.cvtop -> value -> value +val eval_unop : Ast.unop -> num -> num +val eval_binop : Ast.binop -> num -> num -> num +val eval_testop : Ast.testop -> num -> bool +val eval_relop : Ast.relop -> num -> num -> bool +val eval_cvtop : Ast.cvtop -> num -> num diff --git a/interpreter/host/env.ml b/interpreter/host/env.ml index a23838c503..58239d10bc 100644 --- a/interpreter/host/env.ml +++ b/interpreter/host/env.ml @@ -14,7 +14,7 @@ let error msg = raise (Eval.Crash (Source.no_region, msg)) let type_error v t = error ("type error, expected " ^ string_of_value_type t ^ - ", got " ^ string_of_value_type (type_of v)) + ", got " ^ string_of_value_type (type_of_value v)) let empty = function | [] -> () @@ -26,8 +26,8 @@ let single = function | vs -> error "type error, too many arguments" let int = function - | I32 i -> Int32.to_int i - | v -> type_error v I32Type + | Num (I32 i) -> Int32.to_int i + | v -> type_error v (NumType I32Type) let abort vs = diff --git a/interpreter/host/spectest.ml b/interpreter/host/spectest.ml index 9d6ff9a434..77b7116015 100644 --- a/interpreter/host/spectest.ml +++ b/interpreter/host/spectest.ml @@ -10,19 +10,23 @@ open Instance let global (GlobalType (t, _) as gt) = let v = match t with - | I32Type -> I32 666l - | I64Type -> I64 666L - | F32Type -> F32 (F32.of_float 666.6) - | F64Type -> F64 (F64.of_float 666.6) + | NumType I32Type -> Num (I32 666l) + | NumType I64Type -> Num (I64 666L) + | NumType F32Type -> Num (F32 (F32.of_float 666.6)) + | NumType F64Type -> Num (F64 (F64.of_float 666.6)) + | RefType t -> Ref (NullRef t) in Global.alloc gt v -let table = Table.alloc (TableType ({min = 10l; max = Some 20l}, FuncRefType)) +let table = + Table.alloc (TableType ({min = 10l; max = Some 20l}, FuncRefType)) + (NullRef FuncRefType) let memory = Memory.alloc (MemoryType {min = 1l; max = Some 2l}) let func f t = Func.alloc_host t (f t) let print_value v = Printf.printf "%s : %s\n" - (Values.string_of_value v) (Types.string_of_value_type (Values.type_of v)) + (Values.string_of_value v) + (Types.string_of_value_type (Values.type_of_value v)) let print (FuncType (_, out)) vs = List.iter print_value vs; @@ -33,18 +37,18 @@ let print (FuncType (_, out)) vs = let lookup name t = match Utf8.encode name, t with | "print", _ -> ExternFunc (func print (FuncType ([], []))) - | "print_i32", _ -> ExternFunc (func print (FuncType ([I32Type], []))) - | "print_i64", _ -> ExternFunc (func print (FuncType ([I64Type], []))) - | "print_f32", _ -> ExternFunc (func print (FuncType ([F32Type], []))) - | "print_f64", _ -> ExternFunc (func print (FuncType ([F64Type], []))) + | "print_i32", _ -> ExternFunc (func print (FuncType ([NumType I32Type], []))) + | "print_i64", _ -> ExternFunc (func print (FuncType ([NumType I64Type], []))) + | "print_f32", _ -> ExternFunc (func print (FuncType ([NumType F32Type], []))) + | "print_f64", _ -> ExternFunc (func print (FuncType ([NumType F64Type], []))) | "print_i32_f32", _ -> - ExternFunc (func print (FuncType ([I32Type; F32Type], []))) + ExternFunc (func print (FuncType ([NumType I32Type; NumType F32Type], []))) | "print_f64_f64", _ -> - ExternFunc (func print (FuncType ([F64Type; F64Type], []))) - | "global_i32", _ -> ExternGlobal (global (GlobalType (I32Type, Immutable))) - | "global_i64", _ -> ExternGlobal (global (GlobalType (I64Type, Immutable))) - | "global_f32", _ -> ExternGlobal (global (GlobalType (F32Type, Immutable))) - | "global_f64", _ -> ExternGlobal (global (GlobalType (F64Type, Immutable))) + ExternFunc (func print (FuncType ([NumType F64Type; NumType F64Type], []))) + | "global_i32", _ -> ExternGlobal (global (GlobalType (NumType I32Type, Immutable))) + | "global_i64", _ -> ExternGlobal (global (GlobalType (NumType I64Type, Immutable))) + | "global_f32", _ -> ExternGlobal (global (GlobalType (NumType F32Type, Immutable))) + | "global_f64", _ -> ExternGlobal (global (GlobalType (NumType F64Type, Immutable))) | "table", _ -> ExternTable table | "memory", _ -> ExternMemory memory | _ -> raise Not_found diff --git a/interpreter/runtime/global.ml b/interpreter/runtime/global.ml index c5375d7384..5e1729950a 100644 --- a/interpreter/runtime/global.ml +++ b/interpreter/runtime/global.ml @@ -1,21 +1,24 @@ open Types open Values -type global = {mutable content : value; mut : mutability} +type global = {ty : global_type; mutable content : value} type t = global exception Type exception NotMutable -let alloc (GlobalType (t, mut)) v = - if type_of v <> t then raise Type; - {content = v; mut = mut} +let alloc (GlobalType (t, _) as ty) v = + if type_of_value v <> t then raise Type; + {ty; content = v} let type_of glob = - GlobalType (type_of glob.content, glob.mut) + glob.ty + +let load glob = + glob.content -let load glob = glob.content let store glob v = - if glob.mut <> Mutable then raise NotMutable; - if Values.type_of v <> Values.type_of glob.content then raise Type; + let GlobalType (t, mut) = glob.ty in + if mut <> Mutable then raise NotMutable; + if type_of_value v <> t then raise Type; glob.content <- v diff --git a/interpreter/runtime/instance.ml b/interpreter/runtime/instance.ml index 6ac583742d..efc230e0f9 100644 --- a/interpreter/runtime/instance.ml +++ b/interpreter/runtime/instance.ml @@ -8,6 +8,8 @@ type module_inst = memories : memory_inst list; globals : global_inst list; exports : export_inst list; + elems : elem_inst list; + datas : data_inst list; } and func_inst = module_inst ref Func.t @@ -15,6 +17,8 @@ and table_inst = Table.t and memory_inst = Memory.t and global_inst = Global.t and export_inst = Ast.name * extern +and elem_inst = Values.ref_ list ref +and data_inst = string ref and extern = | ExternFunc of func_inst @@ -22,14 +26,29 @@ and extern = | ExternMemory of memory_inst | ExternGlobal of global_inst -type Table.elem += FuncElem of func_inst + +(* Reference types *) + +type Values.ref_ += FuncRef of func_inst + +let () = + let type_of_ref' = !Values.type_of_ref' in + Values.type_of_ref' := function + | FuncRef _ -> FuncRefType + | r -> type_of_ref' r + +let () = + let string_of_ref' = !Values.string_of_ref' in + Values.string_of_ref' := function + | FuncRef _ -> "func" + | r -> string_of_ref' r (* Auxiliary functions *) let empty_module_inst = { types = []; funcs = []; tables = []; memories = []; globals = []; - exports = [] } + exports = []; elems = []; datas = [] } let extern_type_of = function | ExternFunc func -> ExternFuncType (Func.type_of func) diff --git a/interpreter/runtime/memory.ml b/interpreter/runtime/memory.ml index 15794033f8..263c9687ab 100644 --- a/interpreter/runtime/memory.ml +++ b/interpreter/runtime/memory.ml @@ -6,9 +6,10 @@ open Values type size = int32 (* number of pages *) type address = int64 type offset = int32 +type count = int32 type memory' = (int, int8_unsigned_elt, c_layout) Array1.t -type memory = {mutable content : memory'; max : size option} +type memory = {mutable ty : memory_type; mutable content : memory'} type t = memory exception Type @@ -19,9 +20,10 @@ exception OutOfMemory let page_size = 0x10000L (* 64 KiB *) -let within_limits n = function +let valid_limits {min; max} = + match max with | None -> true - | Some max -> I32.le_u n max + | Some m -> I32.le_u min m let create n = if I32.gt_u n 0x10000l then raise SizeOverflow else @@ -32,9 +34,9 @@ let create n = mem with Out_of_memory -> raise OutOfMemory -let alloc (MemoryType {min; max}) = - assert (within_limits min max); - {content = create min; max} +let alloc (MemoryType lim as ty) = + if not (valid_limits lim) then raise Type; + {ty; content = create lim.min} let bound mem = Array1_64.dim mem.content @@ -43,16 +45,20 @@ let size mem = Int64.(to_int32 (div (bound mem) page_size)) let type_of mem = - MemoryType {min = size mem; max = mem.max} + mem.ty let grow mem delta = - let old_size = size mem in + let MemoryType lim = mem.ty in + assert (lim.min = size mem); + let old_size = lim.min in let new_size = Int32.add old_size delta in if I32.gt_u old_size new_size then raise SizeOverflow else - if not (within_limits new_size mem.max) then raise SizeLimit else + let lim' = {lim with min = new_size} in + if not (valid_limits lim') then raise SizeLimit else let after = create new_size in let dim = Array1_64.dim mem.content in Array1.blit (Array1_64.sub mem.content 0L dim) (Array1_64.sub after 0L dim); + mem.ty <- MemoryType lim'; mem.content <- after let load_byte mem a = @@ -96,7 +102,7 @@ let storen mem a o n x = end in loop (effective_address a o) n x -let load_value mem a o t = +let load_num mem a o t = let n = loadn mem a o (Types.size t) in match t with | I32Type -> I32 (Int64.to_int32 n) @@ -104,14 +110,14 @@ let load_value mem a o t = | F32Type -> F32 (F32.of_bits (Int64.to_int32 n)) | F64Type -> F64 (F64.of_bits n) -let store_value mem a o v = +let store_num mem a o n = let x = - match v with + match n with | I32 x -> Int64.of_int32 x | I64 x -> x | F32 x -> Int64.of_int32 (F32.to_bits x) | F64 x -> F64.to_bits x - in storen mem a o (Types.size (Values.type_of v)) x + in storen mem a o (Types.size (Values.type_of_num n)) x let extend x n = function | ZX -> x @@ -119,19 +125,19 @@ let extend x n = function let load_packed sz ext mem a o t = assert (packed_size sz <= Types.size t); - let n = packed_size sz in - let x = extend (loadn mem a o n) n ext in + let w = packed_size sz in + let x = extend (loadn mem a o w) w ext in match t with | I32Type -> I32 (Int64.to_int32 x) | I64Type -> I64 x | _ -> raise Type -let store_packed sz mem a o v = - assert (packed_size sz <= Types.size (Values.type_of v)); - let n = packed_size sz in +let store_packed sz mem a o n = + assert (packed_size sz <= Types.size (Values.type_of_num n)); + let w = packed_size sz in let x = - match v with + match n with | I32 x -> Int64.of_int32 x | I64 x -> x | _ -> raise Type - in storen mem a o n x + in storen mem a o w x diff --git a/interpreter/runtime/memory.mli b/interpreter/runtime/memory.mli index f611e46477..2ed721e89f 100644 --- a/interpreter/runtime/memory.mli +++ b/interpreter/runtime/memory.mli @@ -7,6 +7,7 @@ type t = memory type size = int32 (* number of pages *) type address = int64 type offset = int32 +type count = int32 exception Type exception Bounds @@ -16,7 +17,7 @@ exception OutOfMemory val page_size : int64 -val alloc : memory_type -> memory (* raises SizeOverflow, OutOfMemory *) +val alloc : memory_type -> memory (* raises Type, SizeOverflow, OutOfMemory *) val type_of : memory -> memory_type val size : memory -> size val bound : memory -> address @@ -28,13 +29,13 @@ val store_byte : memory -> address -> int -> unit (* raises Bounds *) val load_bytes : memory -> address -> int -> string (* raises Bounds *) val store_bytes : memory -> address -> string -> unit (* raises Bounds *) -val load_value : - memory -> address -> offset -> value_type -> value (* raises Bounds *) -val store_value : - memory -> address -> offset -> value -> unit (* raises Bounds *) +val load_num : + memory -> address -> offset -> num_type -> num (* raises Bounds *) +val store_num : + memory -> address -> offset -> num -> unit (* raises Bounds *) val load_packed : - pack_size -> extension -> memory -> address -> offset -> value_type -> value + pack_size -> extension -> memory -> address -> offset -> num_type -> num (* raises Type, Bounds *) val store_packed : - pack_size -> memory -> address -> offset -> value -> unit + pack_size -> memory -> address -> offset -> num -> unit (* raises Type, Bounds *) diff --git a/interpreter/runtime/table.ml b/interpreter/runtime/table.ml index f48004d6cf..bb10cab8b3 100644 --- a/interpreter/runtime/table.ml +++ b/interpreter/runtime/table.ml @@ -1,54 +1,60 @@ open Types +open Values type size = int32 type index = int32 +type count = int32 -type elem = .. -type elem += Uninitialized - -type table' = elem array -type table = - {mutable content : table'; max : size option; elem_type : elem_type} +type table = {mutable ty : table_type; mutable content : ref_ array} type t = table +exception Type exception Bounds exception SizeOverflow exception SizeLimit +exception OutOfMemory -let within_limits size = function +let valid_limits {min; max} = + match max with | None -> true - | Some max -> I32.le_u size max + | Some m -> I32.le_u min m -let create size = - try Lib.Array32.make size Uninitialized - with Invalid_argument _ -> raise Out_of_memory +let create size r = + try Lib.Array32.make size r + with Out_of_memory | Invalid_argument _ -> raise OutOfMemory -let alloc (TableType ({min; max}, elem_type)) = - assert (within_limits min max); - {content = create min; max; elem_type} +let alloc (TableType (lim, _) as ty) r = + if not (valid_limits lim) then raise Type; + {ty; content = create lim.min r} let size tab = Lib.Array32.length tab.content let type_of tab = - TableType ({min = size tab; max = tab.max}, tab.elem_type) + tab.ty -let grow tab delta = - let old_size = size tab in +let grow tab delta r = + let TableType (lim, t) = tab.ty in + assert (lim.min = size tab); + let old_size = lim.min in let new_size = Int32.add old_size delta in if I32.gt_u old_size new_size then raise SizeOverflow else - if not (within_limits new_size tab.max) then raise SizeLimit else - let after = create new_size in + let lim' = {lim with min = new_size} in + if not (valid_limits lim') then raise SizeLimit else + let after = create new_size r in Array.blit tab.content 0 after 0 (Array.length tab.content); + tab.ty <- TableType (lim', t); tab.content <- after let load tab i = try Lib.Array32.get tab.content i with Invalid_argument _ -> raise Bounds -let store tab i v = - try Lib.Array32.set tab.content i v with Invalid_argument _ -> raise Bounds +let store tab i r = + let TableType (lim, t) = tab.ty in + if type_of_ref r <> t then raise Type; + try Lib.Array32.set tab.content i r with Invalid_argument _ -> raise Bounds -let blit tab offset elems = - let data = Array.of_list elems in +let blit tab offset rs = + let data = Array.of_list rs in try Lib.Array32.blit data 0l tab.content offset (Lib.Array32.length data) with Invalid_argument _ -> raise Bounds diff --git a/interpreter/runtime/table.mli b/interpreter/runtime/table.mli index 7956d986d2..cf424e3572 100644 --- a/interpreter/runtime/table.mli +++ b/interpreter/runtime/table.mli @@ -1,23 +1,25 @@ open Types +open Values type table type t = table type size = int32 type index = int32 +type count = int32 -type elem = .. -type elem += Uninitialized - +exception Type exception Bounds exception SizeOverflow exception SizeLimit +exception OutOfMemory -val alloc : table_type -> table +val alloc : table_type -> ref_ -> table (* raises Type, OutOfMemory *) val type_of : table -> table_type val size : table -> size -val grow : table -> size -> unit (* raises SizeOverflow, SizeLimit *) +val grow : table -> size -> ref_ -> unit + (* raises SizeOverflow, SizeLimit, OutOfMemory *) -val load : table -> index -> elem (* raises Bounds *) -val store : table -> index -> elem -> unit (* raises Bounds *) -val blit : table -> index -> elem list -> unit (* raises Bounds *) +val load : table -> index -> ref_ (* raises Bounds *) +val store : table -> index -> ref_ -> unit (* raises Type, Bounds *) +val blit : table -> index -> ref_ list -> unit (* raises Bounds *) diff --git a/interpreter/script/js.ml b/interpreter/script/js.ml index eef31ee579..827c97a6e2 100644 --- a/interpreter/script/js.ml +++ b/interpreter/script/js.ml @@ -10,7 +10,31 @@ let harness = {| 'use strict'; +let externrefs = {}; +let externsym = Symbol("externref"); +function externref(s) { + if (! (s in externrefs)) externrefs[s] = {[externsym]: s}; + return externrefs[s]; +} +function is_externref(x) { + return (x !== null && externsym in x) ? 1 : 0; +} +function is_funcref(x) { + return typeof x === "function" ? 1 : 0; +} +function eq_externref(x, y) { + return x === y ? 1 : 0; +} +function eq_funcref(x, y) { + return x === y ? 1 : 0; +} + let spectest = { + externref: externref, + is_externref: is_externref, + is_funcref: is_funcref, + eq_externref: eq_externref, + eq_funcref: eq_funcref, print: console.log.bind(console), print_i32: console.log.bind(console), print_i32_f32: console.log.bind(console), @@ -24,6 +48,7 @@ let spectest = { table: new WebAssembly.Table({initial: 10, maximum: 20, element: 'anyfunc'}), memory: new WebAssembly.Memory({initial: 1, maximum: 2}) }; + let handler = { get(target, prop) { return (prop in target) ? target[prop] : {}; @@ -66,8 +91,8 @@ function get(instance, name) { return (v instanceof WebAssembly.Global) ? v.value : v; } -function exports(name, instance) { - return {[name]: instance.exports}; +function exports(instance) { + return {module: instance.exports, spectest: spectest}; } function run(action) { @@ -142,6 +167,16 @@ function assert_return(action, ...expected) { throw new Error("Wasm return value NaN expected, got " + actual[i]); }; return; + case "ref.func": + if (typeof actual[i] !== "function") { + throw new Error("Wasm function return value expected, got " + actual[i]); + }; + return; + case "ref.extern": + if (actual[i] === null) { + throw new Error("Wasm reference return value expected, got " + actual[i]); + }; + return; default: if (!Object.is(actual[i], expected[i])) { throw new Error("Wasm return value " + expected[i] + " expected, got " + actual[i]); @@ -191,6 +226,14 @@ let lookup (mods : modules) x_opt name at = (* Wrappers *) +let subject_idx = 0l +let externref_idx = 1l +let is_externref_idx = 2l +let is_funcref_idx = 3l +let eq_externref_idx = 4l +let _eq_funcref_idx = 5l +let subject_type_idx = 6l + let eq_of = function | I32Type -> Values.I32 I32Op.Eq | I64Type -> Values.I64 I64Op.Eq @@ -215,12 +258,20 @@ let abs_mask_of = function | I32Type | F32Type -> Values.I32 Int32.max_int | I64Type | F64Type -> Values.I64 Int64.max_int -let invoke ft lits at = - [ft @@ at], FuncImport (1l @@ at) @@ at, - List.map (fun lit -> Const lit @@ at) lits @ [Call (0l @@ at) @@ at] +let value v = + match v.it with + | Values.Num num -> [Const (num @@ v.at) @@ v.at] + | Values.Ref (Values.NullRef t) -> [RefNull t @@ v.at] + | Values.Ref (ExternRef n) -> + [Const (Values.I32 n @@ v.at) @@ v.at; Call (externref_idx @@ v.at) @@ v.at] + | Values.Ref _ -> assert false + +let invoke ft vs at = + [ft @@ at], FuncImport (subject_type_idx @@ at) @@ at, + List.concat (List.map value vs) @ [Call (subject_idx @@ at) @@ at] let get t at = - [], GlobalImport t @@ at, [GlobalGet (0l @@ at) @@ at] + [], GlobalImport t @@ at, [GlobalGet (subject_idx @@ at) @@ at] let run ts at = [], [] @@ -228,14 +279,26 @@ let run ts at = let assert_return ress ts at = let test res = match res.it with - | LitResult lit -> - let t', reinterpret = reinterpret_of (Values.type_of lit.it) in + | LitResult {it = Values.Num num; at = at'} -> + let t', reinterpret = reinterpret_of (Values.type_of_num num) in [ reinterpret @@ at; - Const lit @@ at; + Const (num @@ at') @@ at; reinterpret @@ at; Compare (eq_of t') @@ at; Test (Values.I32 I32Op.Eqz) @@ at; BrIf (0l @@ at) @@ at ] + | LitResult {it = Values.Ref (Values.NullRef t); _} -> + [ RefIsNull @@ at; + Test (Values.I32 I32Op.Eqz) @@ at; + BrIf (0l @@ at) @@ at ] + | LitResult {it = Values.Ref (ExternRef n); _} -> + [ Const (Values.I32 n @@ at) @@ at; + Call (externref_idx @@ at) @@ at; + Call (eq_externref_idx @@ at) @@ at; + Test (Values.I32 I32Op.Eqz) @@ at; + BrIf (0l @@ at) @@ at ] + | LitResult {it = Values.Ref _; _} -> + assert false | NanResult nanop -> let nan = match nanop.it with @@ -247,7 +310,7 @@ let assert_return ress ts at = | CanonicalNan -> abs_mask_of (* must only differ from the canonical NaN in its sign bit *) | ArithmeticNan -> canonical_nan_of (* can be any NaN that's one everywhere the canonical NaN is one *) in - let t = Values.type_of nanop.it in + let t = Values.type_of_num nanop.it in let t', reinterpret = reinterpret_of t in [ reinterpret @@ at; Const (nan_bitmask_of t' @@ at) @@ at; @@ -256,14 +319,48 @@ let assert_return ress ts at = Compare (eq_of t') @@ at; Test (Values.I32 I32Op.Eqz) @@ at; BrIf (0l @@ at) @@ at ] + | RefResult t -> + let is_ref_idx = + match t with + | FuncRefType -> is_funcref_idx + | ExternRefType -> is_externref_idx + in + [ Call (is_ref_idx @@ at) @@ at; + Test (Values.I32 I32Op.Eqz) @@ at; + BrIf (0l @@ at) @@ at ] in [], List.flatten (List.rev_map test ress) -let wrap module_name item_name wrap_action wrap_assertion at = +let wrap item_name wrap_action wrap_assertion at = let itypes, idesc, action = wrap_action at in let locals, assertion = wrap_assertion at in - let types = (FuncType ([], []) @@ at) :: itypes in - let imports = [{module_name; item_name; idesc} @@ at] in - let item = (match idesc.it with FuncImport _ -> 1l | _ -> 0l) @@ at in + let types = + (FuncType ([], []) @@ at) :: + (FuncType ([NumType I32Type], [RefType ExternRefType]) @@ at) :: + (FuncType ([RefType ExternRefType], [NumType I32Type]) @@ at) :: + (FuncType ([RefType FuncRefType], [NumType I32Type]) @@ at) :: + (FuncType ([RefType ExternRefType; RefType ExternRefType], [NumType I32Type]) @@ at) :: + (FuncType ([RefType FuncRefType; RefType FuncRefType], [NumType I32Type]) @@ at) :: + itypes + in + let imports = + [ {module_name = Utf8.decode "module"; item_name; idesc} @@ at; + {module_name = Utf8.decode "spectest"; item_name = Utf8.decode "externref"; + idesc = FuncImport (1l @@ at) @@ at} @@ at; + {module_name = Utf8.decode "spectest"; item_name = Utf8.decode "is_externref"; + idesc = FuncImport (2l @@ at) @@ at} @@ at; + {module_name = Utf8.decode "spectest"; item_name = Utf8.decode "is_funcref"; + idesc = FuncImport (3l @@ at) @@ at} @@ at; + {module_name = Utf8.decode "spectest"; item_name = Utf8.decode "eq_externref"; + idesc = FuncImport (4l @@ at) @@ at} @@ at; + {module_name = Utf8.decode "spectest"; item_name = Utf8.decode "eq_funcref"; + idesc = FuncImport (5l @@ at) @@ at} @@ at ] + in + let item = + List.fold_left + (fun i im -> + match im.it.idesc.it with FuncImport _ -> Int32.add i 1l | _ -> i + ) 0l imports @@ at + in let edesc = FuncExport item @@ at in let exports = [{name = Utf8.decode "run"; edesc} @@ at] in let body = @@ -275,10 +372,14 @@ let wrap module_name item_name wrap_action wrap_assertion at = Encode.encode m -let is_js_value_type = function +let is_js_num_type = function | I32Type -> true | I64Type | F32Type | F64Type -> false +let is_js_value_type = function + | NumType t -> is_js_num_type t + | RefType t -> true + let is_js_global_type = function | GlobalType (t, mut) -> is_js_value_type t && mut = Immutable @@ -310,7 +411,6 @@ let of_string_with iter add_char s = Buffer.contents buf let of_bytes = of_string_with String.iter add_hex_char -let of_string = of_string_with String.iter add_char let of_name = of_string_with List.iter add_unicode_char let of_float z = @@ -321,24 +421,30 @@ let of_float z = | "-inf" -> "-Infinity" | s -> s -let of_literal lit = - match lit.it with - | Values.I32 i -> I32.to_string_s i - | Values.I64 i -> "int64(\"" ^ I64.to_string_s i ^ "\")" - | Values.F32 z -> of_float (F32.to_float z) - | Values.F64 z -> of_float (F64.to_float z) +let of_value v = + let open Values in + match v.it with + | Num (I32 i) -> I32.to_string_s i + | Num (I64 i) -> "int64(\"" ^ I64.to_string_s i ^ "\")" + | Num (F32 z) -> of_float (F32.to_float z) + | Num (F64 z) -> of_float (F64.to_float z) + | Ref (NullRef _) -> "null" + | Ref (ExternRef n) -> "externref(" ^ Int32.to_string n ^ ")" + | _ -> assert false let of_nan = function - | CanonicalNan -> "nan:canonical" - | ArithmeticNan -> "nan:arithmetic" + | CanonicalNan -> "\"nan:canonical\"" + | ArithmeticNan -> "\"nan:arithmetic\"" let of_result res = match res.it with - | LitResult lit -> of_literal lit + | LitResult value -> of_value value | NanResult nanop -> - match nanop.it with + (match nanop.it with | Values.I32 _ | Values.I64 _ -> assert false | Values.F32 n | Values.F64 n -> of_nan n + ) + | RefResult t -> "\"ref." ^ string_of_refed_type t ^ "\"" let rec of_definition def = match def.it with @@ -350,19 +456,19 @@ let rec of_definition def = let of_wrapper mods x_opt name wrap_action wrap_assertion at = let x = of_var_opt mods x_opt in - let bs = wrap (Utf8.decode x) name wrap_action wrap_assertion at in + let bs = wrap name wrap_action wrap_assertion at in "call(instance(" ^ of_bytes bs ^ ", " ^ - "exports(" ^ of_string x ^ ", " ^ x ^ ")), " ^ " \"run\", [])" + "exports(" ^ x ^ ")), " ^ " \"run\", [])" let of_action mods act = match act.it with - | Invoke (x_opt, name, lits) -> + | Invoke (x_opt, name, vs) -> "call(" ^ of_var_opt mods x_opt ^ ", " ^ of_name name ^ ", " ^ - "[" ^ String.concat ", " (List.map of_literal lits) ^ "])", + "[" ^ String.concat ", " (List.map of_value vs) ^ "])", (match lookup mods x_opt name act.at with | ExternFuncType ft when not (is_js_func_type ft) -> let FuncType (_, out) = ft in - Some (of_wrapper mods x_opt name (invoke ft lits), out) + Some (of_wrapper mods x_opt name (invoke ft vs), out) | _ -> None ) | Get (x_opt, name) -> diff --git a/interpreter/script/run.ml b/interpreter/script/run.ml index 9520628553..3eacaccafa 100644 --- a/interpreter/script/run.ml +++ b/interpreter/script/run.ml @@ -4,6 +4,7 @@ open Source (* Errors & Tracing *) +module Script = Error.Make () module Abort = Error.Make () module Assert = Error.Make () module IO = Error.Make () @@ -112,6 +113,7 @@ let input_from get_script run = | Eval.Exhaustion (at, msg) -> error at "resource exhaustion" msg | Eval.Crash (at, msg) -> error at "runtime crash" msg | Encode.Code (at, msg) -> error at "encoding error" msg + | Script.Error (at, msg) -> error at "script error" msg | IO (at, msg) -> error at "i/o error" msg | Assert (at, msg) -> error at "assertion failure" msg | Abort _ -> false @@ -239,7 +241,7 @@ let print_module x_opt m = flush_all () let print_values vs = - let ts = List.map Values.type_of vs in + let ts = List.map Values.type_of_value vs in Printf.printf "%s : %s\n" (Values.string_of_values vs) (Types.string_of_value_types ts); flush_all () @@ -250,16 +252,19 @@ let string_of_nan = function let type_of_result r = match r with - | LitResult v -> Values.type_of v.it - | NanResult n -> Values.type_of n.it + | LitResult v -> Values.type_of_value v.it + | NanResult n -> Types.NumType (Values.type_of_num n.it) + | RefResult t -> Types.RefType t let string_of_result r = match r with | LitResult v -> Values.string_of_value v.it | NanResult nanop -> - match nanop.it with + (match nanop.it with | Values.I32 _ | Values.I64 _ -> assert false | Values.F32 n | Values.F64 n -> string_of_nan n + ) + | RefResult t -> Types.string_of_refed_type t let string_of_results = function | [r] -> string_of_result r @@ -326,6 +331,13 @@ let run_action act : Values.value list = let inst = lookup_instance x_opt act.at in (match Instance.export inst name with | Some (Instance.ExternFunc f) -> + let Types.FuncType (ins, out) = Func.type_of f in + if List.length vs <> List.length ins then + Script.error act.at "wrong number of arguments"; + List.iter2 (fun v t -> + if Values.type_of_value v.it <> t then + Script.error v.at "wrong type of argument" + ) vs ins; Eval.invoke f (List.map (fun v -> v.it) vs) | Some _ -> Assert.error act.at "export is not a function" | None -> Assert.error act.at "undefined export" @@ -348,16 +360,25 @@ let assert_result at got expect = match r with | LitResult v' -> v <> v'.it | NanResult nanop -> - match nanop.it, v with - | F32 CanonicalNan, F32 z -> z <> F32.pos_nan && z <> F32.neg_nan - | F64 CanonicalNan, F64 z -> z <> F64.pos_nan && z <> F64.neg_nan - | F32 ArithmeticNan, F32 z -> + (match nanop.it, v with + | F32 CanonicalNan, Num (F32 z) -> + z <> F32.pos_nan && z <> F32.neg_nan + | F64 CanonicalNan, Num (F64 z) -> + z <> F64.pos_nan && z <> F64.neg_nan + | F32 ArithmeticNan, Num (F32 z) -> let pos_nan = F32.to_bits F32.pos_nan in Int32.logand (F32.to_bits z) pos_nan <> pos_nan - | F64 ArithmeticNan, F64 z -> + | F64 ArithmeticNan, Num (F64 z) -> let pos_nan = F64.to_bits F64.pos_nan in Int64.logand (F64.to_bits z) pos_nan <> pos_nan | _, _ -> false + ) + | RefResult t -> + (match t, v with + | Types.FuncRefType, Ref (Instance.FuncRef _) + | Types.ExternRefType, Ref (ExternRef _) -> false + | _ -> true + ) ) got expect then begin print_string "Result: "; print_values got; diff --git a/interpreter/script/script.ml b/interpreter/script/script.ml index bd4e73ea3d..6fe11950cc 100644 --- a/interpreter/script/script.ml +++ b/interpreter/script/script.ml @@ -1,5 +1,8 @@ type var = string Source.phrase +type Values.ref_ += ExternRef of int32 +type literal = Values.value Source.phrase + type definition = definition' Source.phrase and definition' = | Textual of Ast.module_ @@ -8,17 +11,18 @@ and definition' = type action = action' Source.phrase and action' = - | Invoke of var option * Ast.name * Ast.literal list + | Invoke of var option * Ast.name * literal list | Get of var option * Ast.name type nanop = nanop' Source.phrase -and nanop' = (unit, unit, nan, nan) Values.op +and nanop' = (Lib.void, Lib.void, nan, nan) Values.op and nan = CanonicalNan | ArithmeticNan type result = result' Source.phrase and result' = - | LitResult of Ast.literal + | LitResult of literal | NanResult of nanop + | RefResult of Types.ref_type type assertion = assertion' Source.phrase and assertion' = @@ -47,3 +51,16 @@ and meta' = and script = command list exception Syntax of Source.region * string + + +let () = + let type_of_ref' = !Values.type_of_ref' in + Values.type_of_ref' := function + | ExternRef _ -> Types.ExternRefType + | r -> type_of_ref' r + +let () = + let string_of_ref' = !Values.string_of_ref' in + Values.string_of_ref' := function + | ExternRef n -> "ref " ^ Int32.to_string n + | r -> string_of_ref' r diff --git a/interpreter/syntax/ast.ml b/interpreter/syntax/ast.ml index 5e6b244723..d258986ea6 100644 --- a/interpreter/syntax/ast.ml +++ b/interpreter/syntax/ast.ml @@ -56,8 +56,7 @@ type testop = (I32Op.testop, I64Op.testop, F32Op.testop, F64Op.testop) Values.op type relop = (I32Op.relop, I64Op.relop, F32Op.relop, F64Op.relop) Values.op type cvtop = (I32Op.cvtop, I64Op.cvtop, F32Op.cvtop, F64Op.cvtop) Values.op -type 'a memop = - {ty : value_type; align : int; offset : Memory.offset; sz : 'a option} +type 'a memop = {ty : num_type; align : int; offset : int32; sz : 'a option} type loadop = (pack_size * extension) memop type storeop = pack_size memop @@ -65,7 +64,7 @@ type storeop = pack_size memop (* Expressions *) type var = int32 Source.phrase -type literal = Values.value Source.phrase +type num = Values.num Source.phrase type name = int list type block_type = VarBlockType of var | ValBlockType of value_type option @@ -75,7 +74,7 @@ and instr' = | Unreachable (* trap unconditionally *) | Nop (* do nothing *) | Drop (* forget a value *) - | Select (* branchless conditional *) + | Select of value_type list option (* branchless conditional *) | Block of block_type * instr list (* execute in sequence *) | Loop of block_type * instr list (* loop header *) | If of block_type * instr list * instr list (* conditional *) @@ -84,17 +83,32 @@ and instr' = | BrTable of var list * var (* indexed break *) | Return (* break from function body *) | Call of var (* call function *) - | CallIndirect of var (* call function through table *) + | CallIndirect of var * var (* 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 *) | GlobalGet of var (* read global variable *) | GlobalSet of var (* write global variable *) + | TableGet of var (* read table element *) + | TableSet of var (* write table element *) + | TableSize of var (* size of table *) + | TableGrow of var (* grow table *) + | TableFill of var (* fill table range with value *) + | TableCopy of var * var (* copy table range *) + | TableInit of var * var (* initialize table range from segment *) + | ElemDrop of var (* drop passive element segment *) | Load of loadop (* read memory at address *) | Store of storeop (* write memory at address *) - | MemorySize (* size of linear memory *) - | MemoryGrow (* grow linear memory *) - | Const of literal (* constant *) + | MemorySize (* size of memory *) + | MemoryGrow (* grow memory *) + | MemoryFill (* fill memory range with value *) + | MemoryCopy (* copy memory ranges *) + | MemoryInit of var (* initialize memory range from segment *) + | DataDrop of var (* drop passive data segment *) + | RefNull of ref_type (* null reference *) + | RefFunc of var (* function reference *) + | RefIsNull (* null test *) + | Const of num (* constant *) | Test of testop (* numeric test *) | Compare of relop (* numeric comparison *) | Unary of unop (* unary numeric operator *) @@ -110,7 +124,7 @@ type global = global' Source.phrase and global' = { gtype : global_type; - value : const; + ginit : const; } type func = func' Source.phrase @@ -136,16 +150,26 @@ and memory' = mtype : memory_type; } -type 'data segment = 'data segment' Source.phrase -and 'data segment' = +type segment_mode = segment_mode' Source.phrase +and segment_mode' = + | Passive + | Active of {index : var; offset : const} + | Declarative + +type elem_segment = elem_segment' Source.phrase +and elem_segment' = { - index : var; - offset : const; - init : 'data; + etype : ref_type; + einit : const list; + emode : segment_mode; } -type table_segment = var list segment -type memory_segment = string segment +type data_segment = data_segment' Source.phrase +and data_segment' = +{ + dinit : string; + dmode : segment_mode; +} (* Modules *) @@ -190,8 +214,8 @@ and module_' = memories : memory list; funcs : func list; start : var option; - elems : var list segment list; - data : string segment list; + elems : elem_segment list; + datas : data_segment list; imports : import list; exports : export list; } @@ -207,8 +231,8 @@ let empty_module = memories = []; funcs = []; start = None; - elems = []; - data = []; + elems = []; + datas = []; imports = []; exports = []; } @@ -258,3 +282,4 @@ let string_of_name n = in List.iter escape n; Buffer.contents b + diff --git a/interpreter/syntax/free.ml b/interpreter/syntax/free.ml new file mode 100644 index 0000000000..60d5803340 --- /dev/null +++ b/interpreter/syntax/free.ml @@ -0,0 +1,144 @@ +open Source +open Ast + +module Set = Set.Make(Int32) + +type t = +{ + types : Set.t; + globals : Set.t; + tables : Set.t; + memories : Set.t; + funcs : Set.t; + elems : Set.t; + datas : Set.t; + locals : Set.t; + labels : Set.t; +} + +let empty : t = +{ + types = Set.empty; + globals = Set.empty; + tables = Set.empty; + memories = Set.empty; + funcs = Set.empty; + elems = Set.empty; + datas = Set.empty; + locals = Set.empty; + labels = Set.empty; +} + +let union (s1 : t) (s2 : t) : t = +{ + types = Set.union s1.types s2.types; + globals = Set.union s1.globals s2.globals; + tables = Set.union s1.tables s2.tables; + memories = Set.union s1.memories s2.memories; + funcs = Set.union s1.funcs s2.funcs; + elems = Set.union s1.elems s2.elems; + datas = Set.union s1.datas s2.datas; + locals = Set.union s1.locals s2.locals; + labels = Set.union s1.labels s2.labels; +} + +let types s = {empty with types = s} +let globals s = {empty with globals = s} +let tables s = {empty with tables = s} +let memories s = {empty with memories = s} +let funcs s = {empty with funcs = s} +let elems s = {empty with elems = s} +let datas s = {empty with datas = s} +let locals s = {empty with locals = s} +let labels s = {empty with labels = s} + +let var x = Set.singleton x.it +let zero = Set.singleton 0l +let shift s = Set.map (Int32.add (-1l)) (Set.remove 0l s) + +let (++) = union +let list free xs = List.fold_left union empty (List.map free xs) + +let block_type = function + | VarBlockType x -> types (var x) + | ValBlockType _ -> empty + +let rec instr (e : instr) = + match e.it with + | Unreachable | Nop | Drop | Select _ -> empty + | RefNull _ | RefIsNull -> empty + | RefFunc x -> funcs (var x) + | Const _ | Test _ | Compare _ | Unary _ | Binary _ | Convert _ -> empty + | Block (bt, es) | Loop (bt, es) -> block_type bt ++ block es + | If (bt, es1, es2) -> block_type bt ++ block es1 ++ block es2 + | 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) + | 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 -> + tables (var x) + | TableCopy (x, y) -> tables (var x) ++ tables (var y) + | TableInit (x, y) -> tables (var x) ++ elems (var y) + | ElemDrop x -> elems (var x) + | Load _ | Store _ | MemorySize | MemoryGrow | MemoryCopy | MemoryFill -> + memories zero + | MemoryInit x -> memories zero ++ datas (var x) + | DataDrop x -> datas (var x) + +and block (es : instr list) = + let free = list instr es in {free with labels = shift free.labels} + +let const (c : const) = block c.it + +let global (g : global) = const g.it.ginit +let func (f : func) = {(block f.it.body) with locals = Set.empty} +let table (t : table) = empty +let memory (m : memory) = empty + +let segment_mode f (m : segment_mode) = + match m.it with + | Passive | Declarative -> empty + | Active {index; offset} -> f (var index) ++ const offset + +let elem (s : elem_segment) = + list const s.it.einit ++ segment_mode tables s.it.emode + +let data (s : data_segment) = + segment_mode memories s.it.dmode + +let type_ (t : type_) = empty + +let export_desc (d : export_desc) = + match d.it with + | FuncExport x -> funcs (var x) + | TableExport x -> tables (var x) + | MemoryExport x -> memories (var x) + | GlobalExport x -> globals (var x) + +let import_desc (d : import_desc) = + match d.it with + | FuncImport x -> types (var x) + | TableImport tt -> empty + | MemoryImport mt -> empty + | GlobalImport gt -> empty + +let export (e : export) = export_desc e.it.edesc +let import (i : import) = import_desc i.it.idesc + +let start (s : var option) = + funcs (Lib.Option.get (Lib.Option.map var s) Set.empty) + +let module_ (m : module_) = + list type_ m.it.types ++ + list global m.it.globals ++ + list table m.it.tables ++ + list memory m.it.memories ++ + list func m.it.funcs ++ + start m.it.start ++ + list elem m.it.elems ++ + list data m.it.datas ++ + list import m.it.imports ++ + list export m.it.exports diff --git a/interpreter/syntax/free.mli b/interpreter/syntax/free.mli new file mode 100644 index 0000000000..dc01edc02e --- /dev/null +++ b/interpreter/syntax/free.mli @@ -0,0 +1,36 @@ +module Set : Set.S with type elt = int32 + +type t = +{ + types : Set.t; + globals : Set.t; + tables : Set.t; + memories : Set.t; + funcs : Set.t; + elems : Set.t; + datas : Set.t; + locals : Set.t; + labels : Set.t; +} + +val empty : t +val union : t -> t -> t + +val instr : Ast.instr -> t +val block : Ast.instr list -> t +val const : Ast.const -> t + +val type_ : Ast.type_ -> t +val global : Ast.global -> t +val func : Ast.func -> t +val table : Ast.table -> t +val memory : Ast.memory -> t +val elem : Ast.elem_segment -> t +val data : Ast.data_segment -> t +val export : Ast.export -> t +val import : Ast.import -> t +val start : Ast.var option -> t + +val module_ : Ast.module_ -> t + +val list : ('a -> t) -> 'a list -> t diff --git a/interpreter/syntax/operators.ml b/interpreter/syntax/operators.ml index ceeb13ff49..d8467a5950 100644 --- a/interpreter/syntax/operators.ml +++ b/interpreter/syntax/operators.ml @@ -8,11 +8,13 @@ let i32_const n = Const (I32 n.it @@ n.at) let i64_const n = Const (I64 n.it @@ n.at) let f32_const n = Const (F32 n.it @@ n.at) let f64_const n = Const (F64 n.it @@ n.at) +let ref_null t = RefNull t +let ref_func x = RefFunc x let unreachable = Unreachable let nop = Nop let drop = Drop -let select = Select +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) @@ -22,7 +24,7 @@ let br_table xs x = BrTable (xs, x) let return = Return let call x = Call x -let call_indirect x = CallIndirect x +let call_indirect x y = CallIndirect (x, y) let local_get x = LocalGet x let local_set x = LocalSet x @@ -30,6 +32,15 @@ let local_tee x = LocalTee x let global_get x = GlobalGet x let global_set x = GlobalSet x +let table_get x = TableGet x +let table_set x = TableSet x +let table_size x = TableSize x +let table_grow x = TableGrow x +let table_fill x = TableFill x +let table_copy x y = TableCopy (x, y) +let table_init x y = TableInit (x, y) +let elem_drop x = ElemDrop x + let i32_load align offset = Load {ty = I32Type; align; offset; sz = None} let i64_load align offset = Load {ty = I64Type; align; offset; sz = None} let f32_load align offset = Load {ty = F32Type; align; offset; sz = None} @@ -70,6 +81,15 @@ let i64_store16 align offset = let i64_store32 align offset = Store {ty = I64Type; align; offset; sz = Some Pack32} +let memory_size = MemorySize +let memory_grow = MemoryGrow +let memory_fill = MemoryFill +let memory_copy = MemoryCopy +let memory_init x = MemoryInit x +let data_drop x = DataDrop x + +let ref_is_null = RefIsNull + let i32_clz = Unary (I32 I32Op.Clz) let i32_ctz = Unary (I32 I32Op.Ctz) let i32_popcnt = Unary (I32 I32Op.Popcnt) @@ -211,7 +231,3 @@ let i32_reinterpret_f32 = Convert (I32 I32Op.ReinterpretFloat) let i64_reinterpret_f64 = Convert (I64 I64Op.ReinterpretFloat) let f32_reinterpret_i32 = Convert (F32 F32Op.ReinterpretInt) let f64_reinterpret_i64 = Convert (F64 F64Op.ReinterpretInt) - -let memory_size = MemorySize -let memory_grow = MemoryGrow - diff --git a/interpreter/syntax/types.ml b/interpreter/syntax/types.ml index aeb398b021..6a80308ef7 100644 --- a/interpreter/syntax/types.ml +++ b/interpreter/syntax/types.ml @@ -1,13 +1,14 @@ (* Types *) -type value_type = I32Type | I64Type | F32Type | F64Type -type elem_type = FuncRefType +type num_type = I32Type | I64Type | F32Type | F64Type +type ref_type = FuncRefType | ExternRefType +type value_type = NumType of num_type | RefType of ref_type type stack_type = value_type list type func_type = FuncType of stack_type * stack_type type 'a limits = {min : 'a; max : 'a option} type mutability = Immutable | Mutable -type table_type = TableType of Int32.t limits * elem_type +type table_type = TableType of Int32.t limits * ref_type type memory_type = MemoryType of Int32.t limits type global_type = GlobalType of value_type * mutability type extern_type = @@ -31,6 +32,26 @@ let packed_size = function | Pack16 -> 2 | Pack32 -> 4 +let is_num_type = function + | NumType _ -> true + | RefType _ -> false + +let is_ref_type = function + | NumType _ -> false + | RefType _ -> true + + +(* Filters *) + +let funcs = + Lib.List.map_filter (function ExternFuncType t -> Some t | _ -> None) +let tables = + Lib.List.map_filter (function ExternTableType t -> Some t | _ -> None) +let memories = + Lib.List.map_filter (function ExternMemoryType t -> Some t | _ -> None) +let globals = + Lib.List.map_filter (function ExternGlobalType t -> Some t | _ -> None) + (* Subtyping *) @@ -62,32 +83,30 @@ let match_extern_type et1 et2 = | _, _ -> false -(* Filters *) - -let funcs = - Lib.List.map_filter (function ExternFuncType t -> Some t | _ -> None) -let tables = - Lib.List.map_filter (function ExternTableType t -> Some t | _ -> None) -let memories = - Lib.List.map_filter (function ExternMemoryType t -> Some t | _ -> None) -let globals = - Lib.List.map_filter (function ExternGlobalType t -> Some t | _ -> None) - - (* String conversion *) -let string_of_value_type = function +let string_of_num_type = function | I32Type -> "i32" | I64Type -> "i64" | F32Type -> "f32" | F64Type -> "f64" +let string_of_ref_type = function + | FuncRefType -> "funcref" + | ExternRefType -> "externref" + +let string_of_refed_type = function + | FuncRefType -> "func" + | ExternRefType -> "extern" + +let string_of_value_type = function + | NumType t -> string_of_num_type t + | RefType t -> string_of_ref_type t + let string_of_value_types = function | [t] -> string_of_value_type t | ts -> "[" ^ String.concat " " (List.map string_of_value_type ts) ^ "]" -let string_of_elem_type = function - | FuncRefType -> "funcref" let string_of_limits {min; max} = I32.to_string_u min ^ @@ -97,7 +116,7 @@ let string_of_memory_type = function | MemoryType lim -> string_of_limits lim let string_of_table_type = function - | TableType (lim, t) -> string_of_limits lim ^ " " ^ string_of_elem_type t + | TableType (lim, t) -> string_of_limits lim ^ " " ^ string_of_ref_type t let string_of_global_type = function | GlobalType (t, Immutable) -> string_of_value_type t diff --git a/interpreter/syntax/values.ml b/interpreter/syntax/values.ml index dedc14ab7c..634166092d 100644 --- a/interpreter/syntax/values.ml +++ b/interpreter/syntax/values.ml @@ -6,74 +6,74 @@ open Types type ('i32, 'i64, 'f32, 'f64) op = I32 of 'i32 | I64 of 'i64 | F32 of 'f32 | F64 of 'f64 -type value = (I32.t, I64.t, F32.t, F64.t) op +type num = (I32.t, I64.t, F32.t, F64.t) op + +type ref_ = .. +type ref_ += NullRef of ref_type + +type value = Num of num | Ref of ref_ (* Typing *) -let type_of = function +let type_of_num = function | I32 _ -> I32Type | I64 _ -> I64Type | F32 _ -> F32Type | F64 _ -> F64Type -let default_value = function +let type_of_ref' = ref (function NullRef t -> t | _ -> assert false) +let type_of_ref r = !type_of_ref' r + +let type_of_value = function + | Num n -> NumType (type_of_num n) + | Ref r -> RefType (type_of_ref r) + + +(* Projections *) + +let as_num = function + | Num n -> n + | Ref _ -> failwith "as_num" + +let as_ref = function + | Num _ -> failwith "as_ref" + | Ref r -> r + + +(* Defaults *) + +let default_num = function | I32Type -> I32 I32.zero | I64Type -> I64 I64.zero | F32Type -> F32 F32.zero | F64Type -> F64 F64.zero +let default_ref = function + | t -> NullRef t + +let default_value = function + | NumType t' -> Num (default_num t') + | RefType t' -> Ref (default_ref t') + (* Conversion *) -let value_of_bool b = I32 (if b then 1l else 0l) +let value_of_bool b = Num (I32 (if b then 1l else 0l)) -let string_of_value = function +let string_of_num = function | I32 i -> I32.to_string_s i | I64 i -> I64.to_string_s i | F32 z -> F32.to_string z | F64 z -> F64.to_string z +let string_of_ref' = ref (function NullRef t -> "null" | _ -> "ref") +let string_of_ref r = !string_of_ref' r + +let string_of_value = function + | Num n -> string_of_num n + | Ref r -> string_of_ref r + let string_of_values = function | [v] -> string_of_value v | vs -> "[" ^ String.concat " " (List.map string_of_value vs) ^ "]" - - -(* Injection & projection *) - -exception Value of value_type - -module type ValueType = -sig - type t - val to_value : t -> value - val of_value : value -> t (* raise Value *) -end - -module I32Value = -struct - type t = I32.t - let to_value i = I32 i - let of_value = function I32 i -> i | _ -> raise (Value I32Type) -end - -module I64Value = -struct - type t = I64.t - let to_value i = I64 i - let of_value = function I64 i -> i | _ -> raise (Value I64Type) -end - -module F32Value = -struct - type t = F32.t - let to_value i = F32 i - let of_value = function F32 z -> z | _ -> raise (Value F32Type) -end - -module F64Value = -struct - type t = F64.t - let to_value i = F64 i - let of_value = function F64 z -> z | _ -> raise (Value F64Type) -end diff --git a/interpreter/text/arrange.ml b/interpreter/text/arrange.ml index 961600a7b1..01e9c8adbd 100644 --- a/interpreter/text/arrange.ml +++ b/interpreter/text/arrange.ml @@ -55,10 +55,11 @@ let break_string s = (* Types *) +let num_type t = string_of_num_type t +let ref_type t = string_of_ref_type t +let refed_type t = string_of_refed_type t let value_type t = string_of_value_type t -let elem_type t = string_of_elem_type t - let decls kind ts = tab kind (atom value_type) ts let func_type (FuncType (ins, out)) = @@ -185,7 +186,7 @@ struct end let oper (intop, floatop) op = - value_type (type_of op) ^ "." ^ + num_type (type_of_num op) ^ "." ^ (match op with | I32 o -> intop "32" o | I64 o -> intop "64" o @@ -200,7 +201,7 @@ let relop = oper (IntOp.relop, FloatOp.relop) let cvtop = oper (IntOp.cvtop, FloatOp.cvtop) let memop name {ty; align; offset; _} sz = - value_type ty ^ "." ^ name ^ + num_type ty ^ "." ^ name ^ (if offset = 0l then "" else " offset=" ^ nat32 offset) ^ (if 1 lsl align = sz then "" else " align=" ^ nat (1 lsl align)) @@ -219,8 +220,8 @@ let storeop op = (* Expressions *) let var x = nat32 x.it -let value v = string_of_value v.it -let constop v = value_type (type_of v.it) ^ ".const" +let num v = string_of_num v.it +let constop v = num_type (type_of_num v.it) ^ ".const" let block_type = function | VarBlockType x -> [Node ("type " ^ var x, [])] @@ -232,7 +233,9 @@ let rec instr e = | Unreachable -> "unreachable", [] | Nop -> "nop", [] | Drop -> "drop", [] - | Select -> "select", [] + | Select None -> "select", [] + | Select (Some []) -> "select", [Node ("result", [])] + | Select (Some ts) -> "select", decls "result" ts | Block (bt, es) -> "block", block_type bt @ list instr es | Loop (bt, es) -> "loop", block_type bt @ list instr es | If (bt, es1, es2) -> @@ -244,17 +247,33 @@ let rec instr e = "br_table " ^ String.concat " " (list var (xs @ [x])), [] | Return -> "return", [] | Call x -> "call " ^ var x, [] - | CallIndirect x -> "call_indirect", [Node ("type " ^ var x, [])] + | CallIndirect (x, y) -> + "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, [] | GlobalGet x -> "global.get " ^ var x, [] | GlobalSet x -> "global.set " ^ var x, [] + | TableGet x -> "table.get " ^ var x, [] + | TableSet x -> "table.set " ^ var x, [] + | TableSize x -> "table.size " ^ var x, [] + | TableGrow x -> "table.grow " ^ var x, [] + | TableFill x -> "table.fill " ^ var x, [] + | TableCopy (x, y) -> "table.copy " ^ var x ^ " " ^ var y, [] + | TableInit (x, y) -> "table.init " ^ var x ^ " " ^ var y, [] + | ElemDrop x -> "elem.drop " ^ var x, [] | Load op -> loadop op, [] | Store op -> storeop op, [] | MemorySize -> "memory.size", [] | MemoryGrow -> "memory.grow", [] - | Const lit -> constop lit ^ " " ^ value lit, [] + | MemoryFill -> "memory.fill", [] + | MemoryCopy -> "memory.copy", [] + | MemoryInit x -> "memory.init " ^ var x, [] + | DataDrop x -> "data.drop " ^ var x, [] + | RefNull t -> "ref.null", [Atom (refed_type t)] + | RefIsNull -> "ref.is_null", [] + | RefFunc x -> "ref.func " ^ var x, [] + | Const n -> constop n ^ " " ^ num n, [] | Test op -> testop op, [] | Compare op -> relop op, [] | Unary op -> unop op, [] @@ -262,8 +281,10 @@ let rec instr e = | Convert op -> cvtop op, [] in Node (head, inner) -let const c = - list instr c.it +let const head c = + match c.it with + | [e] -> instr e + | es -> Node (head, list instr c.it) (* Functions *) @@ -290,22 +311,52 @@ let start x = Node ("start " ^ var x, []) let table off i tab = let {ttype = TableType (lim, t)} = tab.it in Node ("table $" ^ nat (off + i) ^ " " ^ limits nat32 lim, - [atom elem_type t] + [atom ref_type t] ) let memory off i mem = let {mtype = MemoryType lim} = mem.it in Node ("memory $" ^ nat (off + i) ^ " " ^ limits nat32 lim, []) -let segment head dat seg = - let {index; offset; init} = seg.it in - Node (head, atom var index :: Node ("offset", const offset) :: dat init) - -let elems seg = - segment "elem" (list (atom var)) seg +let is_elem_kind = function + | FuncRefType -> true + | _ -> false + +let elem_kind = function + | FuncRefType -> "func" + | _ -> assert false + +let is_elem_index e = + match e.it with + | [{it = RefFunc _; _}] -> true + | _ -> false + +let elem_index e = + match e.it with + | [{it = RefFunc x; _}] -> atom var x + | _ -> assert false + +let segment_mode category mode = + match mode.it with + | Passive -> [] + | Active {index; offset} -> + (if index.it = 0l then [] else [Node (category, [atom var index])]) @ + [const "offset" offset] + | Declarative -> [Atom "declare"] + +let elem i seg = + let {etype; einit; emode} = seg.it in + Node ("elem $" ^ nat i, + segment_mode "table" emode @ + if is_elem_kind etype && List.for_all is_elem_index einit then + atom elem_kind etype :: list elem_index einit + else + atom ref_type etype :: list (const "item") einit + ) -let data seg = - segment "data" break_bytes seg +let data i seg = + let {dinit; dmode} = seg.it in + Node ("data $" ^ nat i, segment_mode "memory" dmode @ break_bytes dinit) (* Modules *) @@ -342,8 +393,8 @@ let export ex = Node ("export", [atom name n; export_desc edesc]) let global off i g = - let {gtype; value} = g.it in - Node ("global $" ^ nat (off + i), global_type gtype :: const value) + let {gtype; ginit} = g.it in + Node ("global $" ^ nat (off + i), global_type gtype :: list instr ginit.it) (* Modules *) @@ -367,8 +418,8 @@ let module_with_var_opt x_opt m = listi (func_with_index !fx) m.it.funcs @ list export m.it.exports @ opt start m.it.start @ - list elems m.it.elems @ - list data m.it.data + listi elem m.it.elems @ + listi data m.it.datas ) let binary_module_with_var_opt x_opt bs = @@ -384,18 +435,24 @@ let module_ = module_with_var_opt None let literal mode lit = match lit.it with - | Values.I32 i -> + | Num (Values.I32 i) -> let f = if mode = `Binary then I32.to_hex_string else I32.to_string_s in Node ("i32.const " ^ f i, []) - | Values.I64 i -> + | Num (Values.I64 i) -> let f = if mode = `Binary then I64.to_hex_string else I64.to_string_s in Node ("i64.const " ^ f i, []) - | Values.F32 z -> + | Num (Values.F32 z) -> let f = if mode = `Binary then F32.to_hex_string else F32.to_string in Node ("f32.const " ^ f z, []) - | Values.F64 z -> + | Num (Values.F64 z) -> let f = if mode = `Binary then F64.to_hex_string else F64.to_string in Node ("f64.const " ^ f z, []) + | Ref (NullRef t) -> + Node ("ref.null " ^ refed_type t, []) + | Ref (ExternRef n) -> + Node ("ref.extern " ^ nat32 n, []) + | Ref _ -> + assert false let definition mode x_opt def = try @@ -440,10 +497,12 @@ let result mode res = match res.it with | LitResult lit -> literal mode lit | NanResult nanop -> - match nanop.it with + (match nanop.it with | Values.I32 _ | Values.I64 _ -> assert false | Values.F32 n -> Node ("f32.const " ^ nan n, []) | Values.F64 n -> Node ("f64.const " ^ nan n, []) + ) + | RefResult t -> Node ("ref." ^ refed_type t, []) let assertion mode ass = match ass.it with diff --git a/interpreter/text/lexer.mll b/interpreter/text/lexer.mll index ea85f53a00..a4e914014d 100644 --- a/interpreter/text/lexer.mll +++ b/interpreter/text/lexer.mll @@ -45,7 +45,7 @@ let string s = done; Buffer.contents b -let value_type = function +let num_type = function | "i32" -> Types.I32Type | "i64" -> Types.I64Type | "f32" -> Types.F32Type @@ -160,7 +160,12 @@ rule token = parse | '"'character*'\\'_ { error_nest (Lexing.lexeme_end_p lexbuf) lexbuf "illegal escape" } - | (nxx as t) { VALUE_TYPE (value_type t) } + | "extern" { EXTERN } + | "externref" { EXTERNREF } + | "funcref" { FUNCREF } + | (nxx as t) { NUM_TYPE (num_type t) } + | "mut" { MUT } + | (nxx as t)".const" { let open Source in CONST (numop t @@ -173,8 +178,10 @@ rule token = parse (fun s -> let n = F64.of_string s.it in f64_const (n @@ s.at), Values.F64 n)) } - | "funcref" { FUNCREF } - | "mut" { MUT } + | "ref.null" { REF_NULL } + | "ref.func" { REF_FUNC } + | "ref.extern" { REF_EXTERN } + | "ref.is_null" { REF_IS_NULL } | "nop" { NOP } | "unreachable" { UNREACHABLE } @@ -199,6 +206,22 @@ rule token = parse | "global.get" { GLOBAL_GET } | "global.set" { GLOBAL_SET } + | "table.get" { TABLE_GET } + | "table.set" { TABLE_SET } + | "table.size" { TABLE_SIZE } + | "table.grow" { TABLE_GROW } + | "table.fill" { TABLE_FILL } + | "table.copy" { TABLE_COPY } + | "table.init" { TABLE_INIT } + | "elem.drop" { ELEM_DROP } + + | "memory.size" { MEMORY_SIZE } + | "memory.grow" { MEMORY_GROW } + | "memory.fill" { MEMORY_FILL } + | "memory.copy" { MEMORY_COPY } + | "memory.init" { MEMORY_INIT } + | "data.drop" { DATA_DROP } + | (nxx as t)".load" { LOAD (fun a o -> numop t (i32_load (opt a 2)) (i64_load (opt a 3)) @@ -325,9 +348,6 @@ rule token = parse | "i32.reinterpret_f32" { CONVERT i32_reinterpret_f32 } | "i64.reinterpret_f64" { CONVERT i64_reinterpret_f64 } - | "memory.size" { MEMORY_SIZE } - | "memory.grow" { MEMORY_GROW } - | "type" { TYPE } | "func" { FUNC } | "start" { START } @@ -339,7 +359,9 @@ rule token = parse | "memory" { MEMORY } | "elem" { ELEM } | "data" { DATA } + | "declare" { DECLARE } | "offset" { OFFSET } + | "item" { ITEM } | "import" { IMPORT } | "export" { EXPORT } diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly index 7b9b3e7443..d423ee74ee 100644 --- a/interpreter/text/parser.mly +++ b/interpreter/text/parser.mly @@ -36,7 +36,7 @@ let ati i = (* Literals *) -let literal f s = +let num f s = try f s with Failure _ -> error s.at "constant out of range" let nanop f nan = @@ -73,12 +73,14 @@ let empty_types () = {space = empty (); list = []} type context = { types : types; tables : space; memories : space; funcs : space; locals : space; globals : space; + datas : space; elems : space; labels : int32 VarMap.t; deferred_locals : (unit -> unit) list ref } let empty_context () = { types = empty_types (); tables = empty (); memories = empty (); funcs = empty (); locals = empty (); globals = empty (); + datas = empty (); elems = empty (); labels = VarMap.empty; deferred_locals = ref [] } @@ -99,6 +101,8 @@ let local (c : context) x = force_locals c; lookup "local" c.locals x let global (c : context) x = lookup "global" c.globals x let table (c : context) x = lookup "table" c.tables x let memory (c : context) x = lookup "memory" c.memories x +let elem (c : context) x = lookup "elem segment" c.elems x +let data (c : context) x = lookup "data segment" c.datas x let label (c : context) x = try VarMap.find x.it c.labels with Not_found -> error x.at ("unknown label " ^ x.it) @@ -130,6 +134,8 @@ let bind_local (c : context) x = force_locals c; bind "local" c.locals x let bind_global (c : context) x = bind "global" c.globals x let bind_table (c : context) x = bind "table" c.tables x let bind_memory (c : context) x = bind "memory" c.memories x +let bind_elem (c : context) x = bind "elem segment" c.elems x +let bind_data (c : context) x = bind "data segment" c.datas x let bind_label (c : context) x = {c with labels = VarMap.add x.it 0l (VarMap.map (Int32.add 1l) c.labels)} @@ -144,6 +150,8 @@ let anon_locals (c : context) lazy_ts = let anon_global (c : context) = anon "global" c.globals 1l let anon_table (c : context) = anon "table" c.tables 1l let anon_memory (c : context) = anon "memory" c.memories 1l +let anon_elem (c : context) = anon "elem segment" c.elems 1l +let anon_data (c : context) = anon "data segment" c.datas 1l let anon_label (c : context) = {c with labels = VarMap.map (Int32.add 1l) c.labels} @@ -164,15 +172,21 @@ let inline_type_explicit (c : context) x ft at = %} -%token NAT INT FLOAT STRING VAR VALUE_TYPE FUNCREF MUT LPAR RPAR -%token NOP DROP BLOCK END IF THEN ELSE SELECT LOOP BR BR_IF BR_TABLE +%token LPAR RPAR +%token NAT INT FLOAT STRING VAR +%token NUM_TYPE FUNCREF EXTERNREF EXTERN MUT +%token UNREACHABLE NOP DROP SELECT +%token BLOCK END IF THEN ELSE LOOP BR BR_IF BR_TABLE %token CALL CALL_INDIRECT RETURN %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 +%token MEMORY_SIZE MEMORY_GROW MEMORY_FILL MEMORY_COPY MEMORY_INIT DATA_DROP %token LOAD STORE OFFSET_EQ_NAT ALIGN_EQ_NAT %token CONST UNARY BINARY TEST COMPARE CONVERT -%token UNREACHABLE MEMORY_SIZE MEMORY_GROW +%token REF_NULL REF_FUNC REF_EXTERN REF_IS_NULL %token FUNC START TYPE PARAM RESULT LOCAL GLOBAL -%token TABLE ELEM MEMORY DATA OFFSET IMPORT EXPORT TABLE +%token TABLE ELEM MEMORY DATA DECLARE OFFSET ITEM IMPORT EXPORT %token MODULE BIN QUOTE %token SCRIPT REGISTER INVOKE GET %token ASSERT_MALFORMED ASSERT_INVALID ASSERT_SOFT_INVALID ASSERT_UNLINKABLE @@ -186,8 +200,8 @@ let inline_type_explicit (c : context) x ft at = %token FLOAT %token STRING %token VAR -%token VALUE_TYPE -%token Ast.instr' * Values.value> CONST +%token NUM_TYPE +%token Ast.instr' * Values.num> CONST %token UNARY %token BINARY %token TEST @@ -222,16 +236,25 @@ string_list : /* Types */ -value_type_list : - | /* empty */ { [] } - | VALUE_TYPE value_type_list { $1 :: $2 } +ref_kind : + | FUNC { FuncRefType } + | EXTERN { ExternRefType } -elem_type : +ref_type : | FUNCREF { FuncRefType } + | EXTERNREF { ExternRefType } + +value_type : + | NUM_TYPE { NumType $1 } + | ref_type { RefType $1 } + +value_type_list : + | /* empty */ { [] } + | value_type value_type_list { $1 :: $2 } global_type : - | VALUE_TYPE { GlobalType ($1, Immutable) } - | LPAR MUT VALUE_TYPE RPAR { GlobalType ($3, Mutable) } + | value_type { GlobalType ($1, Immutable) } + | LPAR MUT value_type RPAR { GlobalType ($3, Mutable) } def_type : | LPAR FUNC func_type RPAR { $3 } @@ -245,11 +268,11 @@ func_type : FuncType (ins, $3 @ out) } | LPAR PARAM value_type_list RPAR func_type { let FuncType (ins, out) = $5 in FuncType ($3 @ ins, out) } - | LPAR PARAM bind_var VALUE_TYPE RPAR func_type /* Sugar */ + | LPAR PARAM bind_var value_type RPAR func_type /* Sugar */ { let FuncType (ins, out) = $6 in FuncType ($4 :: ins, out) } table_type : - | limits elem_type { TableType ($1, $2) } + | limits ref_type { TableType ($1, $2) } memory_type : | limits { MemoryType $1 } @@ -264,7 +287,7 @@ type_use : /* Immediates */ -literal : +num : | NAT { $1 @@ at () } | INT { $1 @@ at () } | FLOAT { $1 @@ at () } @@ -316,6 +339,7 @@ align_opt : instr : | 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 */ @@ -324,7 +348,6 @@ plain_instr : | UNREACHABLE { fun c -> unreachable } | NOP { fun c -> nop } | DROP { fun c -> drop } - | SELECT { fun c -> select } | BR var { fun c -> br ($2 c label) } | BR_IF var { fun c -> br_if ($2 c label) } | BR_TABLE var var_list @@ -337,11 +360,35 @@ plain_instr : | LOCAL_TEE var { fun c -> local_tee ($2 c local) } | GLOBAL_GET var { fun c -> global_get ($2 c global) } | GLOBAL_SET var { fun c -> global_set ($2 c global) } + | TABLE_GET var { fun c -> table_get ($2 c table) } + | TABLE_SET var { fun c -> table_set ($2 c table) } + | TABLE_SIZE var { fun c -> table_size ($2 c table) } + | TABLE_GROW var { fun c -> table_grow ($2 c table) } + | TABLE_FILL var { fun c -> table_fill ($2 c table) } + | TABLE_COPY var var { fun c -> table_copy ($2 c table) ($3 c table) } + | TABLE_INIT var var { fun c -> table_init ($2 c table) ($3 c elem) } + | TABLE_GET { let at = at () in fun c -> table_get (0l @@ at) } /* Sugar */ + | TABLE_SET { let at = at () in fun c -> table_set (0l @@ at) } /* Sugar */ + | TABLE_SIZE { let at = at () in fun c -> table_size (0l @@ at) } /* Sugar */ + | TABLE_GROW { let at = at () in fun c -> table_grow (0l @@ at) } /* Sugar */ + | TABLE_FILL { let at = at () in fun c -> table_fill (0l @@ at) } /* Sugar */ + | TABLE_COPY /* Sugar */ + { let at = at () in fun c -> table_copy (0l @@ at) (0l @@ at) } + | TABLE_INIT var /* Sugar */ + { let at = at () in fun c -> table_init (0l @@ at) ($2 c elem) } + | ELEM_DROP var { fun c -> elem_drop ($2 c elem) } | LOAD offset_opt align_opt { fun c -> $1 $3 $2 } | STORE offset_opt align_opt { fun c -> $1 $3 $2 } | MEMORY_SIZE { fun c -> memory_size } | MEMORY_GROW { fun c -> memory_grow } - | CONST literal { fun c -> fst (literal $1 $2) } + | MEMORY_FILL { fun c -> memory_fill } + | MEMORY_COPY { fun c -> memory_copy } + | MEMORY_INIT var { fun c -> memory_init ($2 c data) } + | DATA_DROP var { fun c -> data_drop ($2 c data) } + | REF_NULL ref_kind { fun c -> ref_null $2 } + | REF_IS_NULL { fun c -> ref_is_null } + | REF_FUNC var { fun c -> ref_func ($2 c func) } + | CONST num { fun c -> fst (num $1 $2) } | TEST { fun c -> $1 } | COMPARE { fun c -> $1 } | UNARY { fun c -> $1 } @@ -349,9 +396,35 @@ plain_instr : | CONVERT { fun c -> $1 } +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 + { 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_instr_results_instr : + | LPAR RESULT value_type_list RPAR select_instr_results_instr + { fun c -> let _, ts, es = $5 c in true, $3 @ ts, es } + | instr + { fun c -> false, [], $1 c } + + call_instr : - | CALL_INDIRECT call_instr_type - { let at = at () in fun c -> call_indirect ($2 c) @@ at } + | 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 @@ -377,9 +450,12 @@ call_instr_results : call_instr_instr : - | CALL_INDIRECT call_instr_type_instr + | CALL_INDIRECT var call_instr_type_instr + { 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 */ { let at1 = ati 1 in - fun c -> let x, es = $2 c in call_indirect 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 @@ -452,8 +528,13 @@ expr : /* Sugar */ expr1 : /* Sugar */ | plain_instr expr_list { fun c -> $2 c, $1 c } - | CALL_INDIRECT call_expr_type - { fun c -> let x, es = $2 c in es, call_indirect x } + | SELECT select_expr_results + { fun c -> let b, ts, es = $2 c in es, select (if b then (Some ts) else None) } + | CALL_INDIRECT var call_expr_type + { fun c -> let x, es = $3 c in es, call_indirect ($2 c table) x } + | 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 } | BLOCK labeling_opt block { fun c -> let c' = $2 c [] in let bt, es = $3 c' in [], block bt es } | LOOP labeling_opt block @@ -462,6 +543,12 @@ expr1 : /* Sugar */ { fun c -> let c' = $2 c [] in let bt, (es, es1, es2) = $3 c c' in es, if_ bt es1 es2 } +select_expr_results : + | LPAR RESULT value_type_list RPAR select_expr_results + { fun c -> let _, ts, es = $5 c in true, $3 @ ts, es } + | expr_list + { fun c -> false, [], $1 c } + call_expr_type : | type_use call_expr_params { let at1 = ati 1 in @@ -526,6 +613,7 @@ if_ : 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 } @@ -575,7 +663,7 @@ func_fields_import : /* Sugar */ | func_fields_import_result { $1 } | LPAR PARAM value_type_list RPAR func_fields_import { let FuncType (ins, out) = $5 in FuncType ($3 @ ins, out) } - | LPAR PARAM bind_var VALUE_TYPE RPAR func_fields_import /* Sugar */ + | LPAR PARAM bind_var value_type RPAR func_fields_import /* Sugar */ { let FuncType (ins, out) = $6 in FuncType ($4 :: ins, out) } func_fields_import_result : /* Sugar */ @@ -589,7 +677,7 @@ func_fields_body : { let FuncType (ins, out) = fst $5 in FuncType ($3 @ ins, out), fun c -> anon_locals c (lazy $3); snd $5 c } - | LPAR PARAM bind_var VALUE_TYPE RPAR func_fields_body /* Sugar */ + | LPAR PARAM bind_var value_type RPAR func_fields_body /* Sugar */ { let FuncType (ins, out) = fst $6 in FuncType ($4 :: ins, out), fun c -> ignore (bind_local c $3); snd $6 c } @@ -607,24 +695,75 @@ func_body : | LPAR LOCAL value_type_list RPAR func_body { fun c -> anon_locals c (lazy $3); let f = $5 c in {f with locals = $3 @ f.locals} } - | LPAR LOCAL bind_var VALUE_TYPE RPAR func_body /* Sugar */ + | LPAR LOCAL bind_var value_type RPAR func_body /* Sugar */ { fun c -> ignore (bind_local c $3); let f = $6 c in {f with locals = $4 :: f.locals} } /* Tables, Memories & Globals */ +table_use : + | LPAR TABLE var RPAR { fun c -> $3 c } + +memory_use : + | LPAR MEMORY var RPAR { fun c -> $3 c } + offset : | LPAR OFFSET const_expr RPAR { $3 } | expr { let at = at () in fun c -> $1 c @@ at } /* Sugar */ +elem_kind : + | FUNC { FuncRefType } + +elem_expr : + | LPAR ITEM const_expr RPAR { $3 } + | expr { let at = at () in fun c -> $1 c @@ at } /* Sugar */ + +elem_expr_list : + | /* empty */ { fun c -> [] } + | elem_expr elem_expr_list { fun c -> $1 c :: $2 c } + +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) } + +elem_list : + | elem_kind elem_var_list + { ($1, fun c -> $2 c func) } + | ref_type elem_expr_list + { ($1, fun c -> $2 c) } + + elem : - | LPAR ELEM var offset var_list RPAR + | LPAR ELEM bind_var_opt elem_list RPAR + { let at = at () in + fun c -> ignore ($3 c anon_elem bind_elem); + fun () -> + { etype = (fst $4); einit = (snd $4) c; emode = Passive @@ at } @@ at } + | LPAR ELEM bind_var_opt table_use offset elem_list RPAR + { let at = at () in + fun c -> ignore ($3 c anon_elem bind_elem); + fun () -> + { etype = (fst $6); einit = (snd $6) c; + emode = Active {index = $4 c table; offset = $5 c} @@ at } @@ at } + | LPAR ELEM bind_var_opt DECLARE elem_list RPAR { let at = at () in - fun c -> {index = $3 c table; offset = $4 c; init = $5 c func} @@ at } - | LPAR ELEM offset var_list RPAR /* Sugar */ + fun c -> ignore ($3 c anon_elem bind_elem); + fun () -> + { etype = (fst $5); einit = (snd $5) c; emode = Declarative @@ at } @@ at } + | LPAR ELEM bind_var_opt offset elem_list RPAR /* Sugar */ { let at = at () in - fun c -> {index = 0l @@ at; offset = $3 c; init = $4 c func} @@ at } + fun c -> ignore ($3 c anon_elem bind_elem); + fun () -> + { etype = (fst $5); einit = (snd $5) c; + emode = Active {index = 0l @@ at; offset = $4 c} @@ at } @@ at } + | LPAR ELEM bind_var_opt offset elem_var_list RPAR /* Sugar */ + { let at = at () in + fun c -> ignore ($3 c anon_elem bind_elem); + fun () -> + { etype = FuncRefType; einit = $5 c func; + emode = Active {index = 0l @@ at; offset = $4 c} @@ at } @@ at } table : | LPAR TABLE bind_var_opt table_fields RPAR @@ -643,20 +782,40 @@ 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 } - | elem_type LPAR ELEM var_list RPAR /* Sugar */ + | ref_type LPAR ELEM elem_var_list RPAR /* Sugar */ { fun c x at -> - let init = $4 c func in let size = Int32.of_int (List.length init) in + let offset = [i32_const (0l @@ at) @@ at] @@ at in + let einit = $4 c func 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], - [{index = x; offset = [i32_const (0l @@ at) @@ at] @@ at; init} @@ at], + [{etype = FuncRefType; einit; emode} @@ at], + [], [] } + | 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 = (fun c -> $4 c :: $5 c) 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], [], [] } data : - | LPAR DATA var offset string_list RPAR + | LPAR DATA bind_var_opt string_list RPAR + { let at = at () in + fun c -> ignore ($3 c anon_data bind_data); + fun () -> {dinit = $4; dmode = Passive @@ at} @@ at } + | LPAR DATA bind_var_opt memory_use offset string_list RPAR { let at = at () in - fun c -> {index = $3 c memory; offset = $4 c; init = $5} @@ at } - | LPAR DATA offset string_list RPAR /* Sugar */ + fun c -> ignore ($3 c anon_data bind_data); + fun () -> + {dinit = $6; dmode = Active {index = $4 c memory; offset = $5 c} @@ at} @@ at } + | LPAR DATA bind_var_opt offset string_list RPAR /* Sugar */ { let at = at () in - fun c -> {index = 0l @@ at; offset = $3 c; init = $4} @@ at } + fun c -> ignore ($3 c anon_data bind_data); + fun () -> + {dinit = $5; dmode = Active {index = 0l @@ at; offset = $4 c} @@ at} @@ at } memory : | LPAR MEMORY bind_var_opt memory_fields RPAR @@ -677,10 +836,10 @@ memory_fields : mems, data, ims, $1 (MemoryExport x) c :: exs } | LPAR DATA string_list RPAR /* Sugar */ { fun c x at -> + let offset = [i32_const (0l @@ at) @@ at] @@ at in let size = Int32.(div (add (of_int (String.length $3)) 65535l) 65536l) in [{mtype = MemoryType {min = size; max = Some size}} @@ at], - [{index = x; - offset = [i32_const (0l @@ at) @@ at] @@ at; init = $3} @@ at], + [{dinit = $3; dmode = Active {index = x; offset} @@ at} @@ at], [], [] } global : @@ -691,7 +850,7 @@ global : global_fields : | global_type const_expr - { fun c x at -> [{gtype = $1; value = $2 c} @@ at], [], [] } + { fun c x at -> [{gtype = $1; ginit = $2 c} @@ at], [], [] } | inline_import global_type /* Sugar */ { fun c x at -> [], @@ -789,7 +948,7 @@ module_fields1 : fun () -> let mems, data, ims, exs = mmf () in let m = mf () in if mems <> [] && m.imports <> [] then error (List.hd m.imports).at "import after memory definition"; - { m with memories = mems @ m.memories; data = data @ m.data; + { m with memories = mems @ m.memories; datas = data @ m.datas; imports = ims @ m.imports; exports = exs @ m.exports } } | func module_fields { fun c -> let ff = $1 c in let mf = $2 c in @@ -799,13 +958,13 @@ module_fields1 : { m with funcs = funcs @ m.funcs; imports = ims @ m.imports; exports = exs @ m.exports } } | elem module_fields - { fun c -> let mf = $2 c in - fun () -> let m = mf () in - {m with elems = $1 c :: m.elems} } + { fun c -> let ef = $1 c in let mf = $2 c in + fun () -> let elems = ef () in let m = mf () in + {m with elems = elems :: m.elems} } | data module_fields - { fun c -> let mf = $2 c in - fun () -> let m = mf () in - {m with data = $1 c :: m.data} } + { fun c -> let df = $1 c in let mf = $2 c in + fun () -> let data = df () in let m = mf () in + {m with datas = data :: m.datas} } | start module_fields { fun c -> let mf = $2 c in fun () -> let m = mf () in let x = $1 c in @@ -845,9 +1004,9 @@ script_var_opt : script_module : | module_ { $1 } | LPAR MODULE module_var_opt BIN string_list RPAR - { $3, Encoded ("binary", $5) @@ at() } + { $3, Encoded ("binary:" ^ string_of_pos (at()).left, $5) @@ at() } | LPAR MODULE module_var_opt QUOTE string_list RPAR - { $3, Quoted ("quote", $5) @@ at() } + { $3, Quoted ("quote:" ^ string_of_pos (at()).left, $5) @@ at() } action : | LPAR INVOKE module_var_opt name const_list RPAR @@ -886,7 +1045,9 @@ meta : | LPAR OUTPUT script_var_opt RPAR { Output ($3, None) @@ at () } const : - | LPAR CONST literal RPAR { snd (literal $2 $3) @@ ati 3 } + | LPAR CONST num RPAR { Values.Num (snd (num $2 $3)) @@ at () } + | LPAR REF_NULL ref_kind RPAR { Values.Ref (Values.NullRef $3) @@ at () } + | LPAR REF_EXTERN NAT RPAR { Values.Ref (ExternRef (nat32 $3 (ati 3))) @@ at () } const_list : | /* empty */ { [] } @@ -895,6 +1056,8 @@ const_list : result : | const { LitResult $1 @@ at () } | LPAR CONST NAN RPAR { NanResult (nanop $2 ($3 @@ ati 3)) @@ at () } + | LPAR REF_FUNC RPAR { RefResult FuncRefType @@ at () } + | LPAR REF_EXTERN RPAR { RefResult ExternRefType @@ at () } result_list : | /* empty */ { [] } diff --git a/interpreter/util/lib.ml b/interpreter/util/lib.ml index eb6eff259d..adf101eb7d 100644 --- a/interpreter/util/lib.ml +++ b/interpreter/util/lib.ml @@ -1,5 +1,8 @@ +type void + module Fun = struct + let id x = x let curry f x y = f (x, y) let uncurry f (x, y) = f x y @@ -137,6 +140,11 @@ struct | 0l, _ -> xs | n, _::xs' when n > 0l -> drop (Int32.sub n 1l) xs' | _ -> failwith "drop" + + let rec mapi f xs = mapi' f 0l xs + and mapi' f i = function + | [] -> [] + | x::xs -> f i x :: mapi' f (Int32.add i 1l) xs end module Array32 = @@ -188,6 +196,11 @@ struct | Some y -> y | None -> x + let force o = + match o with + | Some y -> y + | None -> raise (Invalid_argument "Option.force") + let map f = function | Some x -> Some (f x) | None -> None diff --git a/interpreter/util/lib.mli b/interpreter/util/lib.mli index f9c9182653..415a855e0d 100644 --- a/interpreter/util/lib.mli +++ b/interpreter/util/lib.mli @@ -1,7 +1,10 @@ (* Things that should be in the OCaml library... *) +type void + module Fun : sig + val id : 'a -> 'a val curry : ('a * 'b -> 'c) -> ('a -> 'b -> 'c) val uncurry : ('a -> 'b -> 'c) -> ('a * 'b -> 'c) @@ -31,6 +34,7 @@ sig val nth : 'a list -> int32 -> 'a (* raises Failure *) val take : int32 -> 'a list -> 'a list (* raises Failure *) val drop : int32 -> 'a list -> 'a list (* raises Failure *) + val mapi : (int32 -> 'a -> 'b) -> 'a list -> 'b list end module Array32 : @@ -59,6 +63,7 @@ end module Option : sig val get : 'a option -> 'a -> 'a + val force : 'a option -> 'a (* raises Invalid_argument *) val map : ('a -> 'b) -> 'a option -> 'b option val app : ('a -> unit) -> 'a option -> unit end diff --git a/interpreter/util/source.ml b/interpreter/util/source.ml index 0115825c87..f659f6f235 100644 --- a/interpreter/util/source.ml +++ b/interpreter/util/source.ml @@ -3,6 +3,7 @@ type region = {left : pos; right : pos} type 'a phrase = {at : region; it : 'a} let (@@) x region = {it = x; at = region} +let at region x = x @@ region (* Positions and regions *) diff --git a/interpreter/util/source.mli b/interpreter/util/source.mli index 8cab3db869..240fe64138 100644 --- a/interpreter/util/source.mli +++ b/interpreter/util/source.mli @@ -9,3 +9,4 @@ val string_of_pos : pos -> string val string_of_region : region -> string val (@@) : 'a -> region -> 'a phrase +val at : region -> 'a -> 'a phrase diff --git a/interpreter/valid/valid.ml b/interpreter/valid/valid.ml index 7dd573b541..67c46d6464 100644 --- a/interpreter/valid/valid.ml +++ b/interpreter/valid/valid.ml @@ -21,27 +21,42 @@ type context = tables : table_type list; memories : memory_type list; globals : global_type list; + elems : ref_type list; + datas : unit list; locals : value_type list; results : value_type list; labels : stack_type list; + refs : Free.t; } let empty_context = { types = []; funcs = []; tables = []; memories = []; - globals = []; locals = []; results = []; labels = [] } + globals = []; elems = []; datas = []; + locals = []; results = []; labels = []; + refs = Free.empty + } let lookup category list x = try Lib.List32.nth list x.it with Failure _ -> - error x.at ("unknown " ^ category ^ " " ^ Int32.to_string x.it) + error x.at ("unknown " ^ category ^ " " ^ I32.to_string_u x.it) let type_ (c : context) x = lookup "type" c.types x let func (c : context) x = lookup "function" c.funcs x let table (c : context) x = lookup "table" c.tables x let memory (c : context) x = lookup "memory" c.memories x let global (c : context) x = lookup "global" c.globals x +let elem (c : context) x = lookup "elem segment" c.elems x +let data (c : context) x = lookup "data segment" c.datas x let local (c : context) x = lookup "local" c.locals x let label (c : context) x = lookup "label" c.labels x +let refer category (s : Free.Set.t) x = + if not (Free.Set.mem x.it s) then + error x.at + ("undeclared " ^ category ^ " reference " ^ Int32.to_string x.it) + +let refer_func (c : context) x = refer "function" c.refs.Free.funcs x + (* Stack typing *) @@ -62,6 +77,7 @@ let known = List.map (fun t -> Some t) let stack ts = (NoEllipses, known ts) let (-~>) ts1 ts2 = {ins = NoEllipses, ts1; outs = NoEllipses, ts2} let (-->) ts1 ts2 = {ins = NoEllipses, known ts1; outs = NoEllipses, known ts2} +let (-~>...) ts1 ts2 = {ins = Ellipses, ts1; outs = Ellipses, ts2} let (-->...) ts1 ts2 = {ins = Ellipses, known ts1; outs = Ellipses, known ts2} let string_of_infer_type t = @@ -72,7 +88,7 @@ let string_of_infer_types ts = let eq_ty t1 t2 = (t1 = t2 || t1 = None || t2 = None) let check_stack ts1 ts2 at = require (List.length ts1 = List.length ts2 && List.for_all2 eq_ty ts1 ts2) at - ("type mismatch: operator requires " ^ string_of_infer_types ts1 ^ + ("type mismatch: instruction requires " ^ string_of_infer_types ts1 ^ " but stack has " ^ string_of_infer_types ts2) let pop (ell1, ts1) (ell2, ts2) at = @@ -94,11 +110,11 @@ let peek i (ell, ts) = (* Type Synthesis *) -let type_value = Values.type_of -let type_unop = Values.type_of -let type_binop = Values.type_of -let type_testop = Values.type_of -let type_relop = Values.type_of +let type_num = Values.type_of_num +let type_unop = Values.type_of_num +let type_binop = Values.type_of_num +let type_testop = Values.type_of_num +let type_relop = Values.type_of_num let type_cvtop at = function | Values.I32 cvtop -> @@ -145,11 +161,11 @@ let check_pack sz t at = let check_unop unop at = match unop with | Values.I32 (IntOp.ExtendS sz) | Values.I64 (IntOp.ExtendS sz) -> - check_pack sz (Values.type_of unop) at + check_pack sz (Values.type_of_num unop) at | _ -> () let check_memop (c : context) (memop : 'a memop) get_sz at = - ignore (memory c (0l @@ at)); + let _mt = memory c (0l @@ at) in let size = match get_sz memop.sz with | None -> size memop.ty @@ -198,9 +214,16 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = | Drop -> [peek 0 s] -~> [] - | Select -> + | Select None -> let t = peek 1 s in - [t; t; Some I32Type] -~> [t] + require (match t with None -> true | Some t -> is_num_type t) e.at + ("type mismatch: instruction requires numeric type" ^ + " but stack has " ^ string_of_infer_type t); + [t; t; Some (NumType I32Type)] -~> [t] + + | Select (Some ts) -> + require (List.length ts = 1) e.at "invalid result arity other than 1 is not (yet) allowed"; + (ts @ ts @ [NumType I32Type]) --> ts | Block (bt, es) -> let FuncType (ts1, ts2) as ft = check_block_type c bt in @@ -216,30 +239,35 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = let FuncType (ts1, ts2) as ft = check_block_type c bt in 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 @ [I32Type]) --> ts2 + (ts1 @ [NumType I32Type]) --> ts2 | Br x -> label c x -->... [] | BrIf x -> - (label c x @ [I32Type]) --> label c x + (label c x @ [NumType I32Type]) --> label c x | BrTable (xs, x) -> - let ts = label c x in - List.iter (fun x' -> check_stack (known ts) (known (label c x')) x'.at) xs; - (label c x @ [I32Type]) -->... [] + let n = List.length (label c x) in + let ts = Lib.List.table n (fun i -> peek (n - i) s) in + check_stack ts (known (label c x)) x.at; + List.iter (fun x' -> check_stack ts (known (label c x')) x'.at) xs; + (ts @ [Some (NumType I32Type)]) -~>... [] | Return -> c.results -->... [] | Call x -> - let FuncType (ins, out) = func c x in - ins --> out + let FuncType (ts1, ts2) = func c x in + ts1 --> ts2 - | CallIndirect x -> - ignore (table c (0l @@ e.at)); - let FuncType (ins, out) = type_ c x in - (ins @ [I32Type]) --> out + | CallIndirect (x, y) -> + let TableType (lim, t) = table c x in + let FuncType (ts1, ts2) = type_ c y in + require (t = FuncRefType) x.at + ("type mismatch: instruction requires table of functions" ^ + " but table has " ^ string_of_ref_type t); + (ts1 @ [NumType I32Type]) --> ts2 | LocalGet x -> [] --> [local c x] @@ -251,7 +279,7 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = [local c x] --> [local c x] | GlobalGet x -> - let GlobalType (t, mut) = global c x in + let GlobalType (t, _mut) = global c x in [] --> [t] | GlobalSet x -> @@ -259,46 +287,118 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = require (mut = Mutable) x.at "global is immutable"; [t] --> [] + | TableGet x -> + let TableType (_lim, t) = table c x in + [NumType I32Type] --> [RefType t] + + | TableSet x -> + let TableType (_lim, t) = table c x in + [NumType I32Type; RefType t] --> [] + + | TableSize x -> + let _tt = table c x in + [] --> [NumType I32Type] + + | TableGrow x -> + let TableType (_lim, t) = table c x in + [RefType t; NumType I32Type] --> [NumType I32Type] + + | TableFill x -> + let TableType (_lim, t) = table c x in + [NumType I32Type; RefType t; NumType I32Type] --> [] + + | TableCopy (x, y) -> + let TableType (_lim1, t1) = table c x in + let TableType (_lim2, t2) = table c y in + require (t1 = t2) x.at + ("type mismatch: source element type " ^ string_of_ref_type t1 ^ + " does not match destination element type " ^ string_of_ref_type t2); + [NumType I32Type; NumType I32Type; NumType I32Type] --> [] + + | TableInit (x, y) -> + let TableType (_lim1, t1) = table c x in + let t2 = elem c y in + require (t1 = t2) x.at + ("type mismatch: element segment's type " ^ string_of_ref_type t1 ^ + " does not match table's element type " ^ string_of_ref_type t2); + [NumType I32Type; NumType I32Type; NumType I32Type] --> [] + + | ElemDrop x -> + ignore (elem c x); + [] --> [] + | Load memop -> check_memop c memop (Lib.Option.map fst) e.at; - [I32Type] --> [memop.ty] + [NumType I32Type] --> [NumType memop.ty] | Store memop -> check_memop c memop (fun sz -> sz) e.at; - [I32Type; memop.ty] --> [] + [NumType I32Type; NumType memop.ty] --> [] | MemorySize -> - ignore (memory c (0l @@ e.at)); - [] --> [I32Type] + let _mt = memory c (0l @@ e.at) in + [] --> [NumType I32Type] | MemoryGrow -> + let _mt = memory c (0l @@ e.at) in + [NumType I32Type] --> [NumType I32Type] + + | MemoryFill -> + ignore (memory c (0l @@ e.at)); + [NumType I32Type; NumType I32Type; NumType I32Type] --> [] + + | MemoryCopy -> + ignore (memory c (0l @@ e.at)); + [NumType I32Type; NumType I32Type; NumType I32Type] --> [] + + | MemoryInit x -> ignore (memory c (0l @@ e.at)); - [I32Type] --> [I32Type] + ignore (data c x); + [NumType I32Type; NumType I32Type; NumType I32Type] --> [] + + | DataDrop x -> + ignore (data c x); + [] --> [] + + | RefNull t -> + [] --> [RefType t] + + | RefIsNull -> + let t = peek 0 s in + require (match t with None -> true | Some t -> is_ref_type t) e.at + ("type mismatch: instruction requires reference type" ^ + " but stack has " ^ string_of_infer_type t); + [t] -~> [Some (NumType I32Type)] + + | RefFunc x -> + let _ft = func c x in + refer_func c x; + [] --> [RefType FuncRefType] | Const v -> - let t = type_value v.it in + let t = NumType (type_num v.it) in [] --> [t] | Test testop -> - let t = type_testop testop in - [t] --> [I32Type] + let t = NumType (type_testop testop) in + [t] --> [NumType I32Type] | Compare relop -> - let t = type_relop relop in - [t; t] --> [I32Type] + let t = NumType (type_relop relop) in + [t; t] --> [NumType I32Type] | Unary unop -> check_unop unop e.at; - let t = type_unop unop in + let t = NumType (type_unop unop) in [t] --> [t] | Binary binop -> - let t = type_binop binop in + let t = NumType (type_binop binop) in [t; t] --> [t] | Convert cvtop -> let t1, t2 = type_cvtop e.at cvtop in - [t1] --> [t2] + [NumType t1] --> [NumType t2] and check_seq (c : context) (s : infer_stack_type) (es : instr list) : infer_stack_type = @@ -332,17 +432,26 @@ let check_limits {min; max} range at msg = require (I32.le_u min max) at "size minimum must not be greater than maximum" -let check_value_type (t : value_type) at = +let check_num_type (t : num_type) at = () +let check_ref_type (t : ref_type) at = + () + +let check_value_type (t : value_type) at = + match t with + | NumType t' -> check_num_type t' at + | RefType t' -> check_ref_type t' at + let check_func_type (ft : func_type) at = - let FuncType (ins, out) = ft in - List.iter (fun t -> check_value_type t at) ins; - List.iter (fun t -> check_value_type t at) out + let FuncType (ts1, ts2) = ft in + List.iter (fun t -> check_value_type t at) ts1; + List.iter (fun t -> check_value_type t at) ts2 let check_table_type (tt : table_type) at = - let TableType (lim, _) = tt in - check_limits lim 0xffff_ffffl at "table size must be at most 2^32-1" + let TableType (lim, t) = tt in + check_limits lim 0xffff_ffffl at "table size must be at most 2^32-1"; + check_ref_type t at let check_memory_type (mt : memory_type) at = let MemoryType lim = mt in @@ -374,13 +483,15 @@ let check_type (t : type_) = let check_func (c : context) (f : func) = let {ftype; locals; body} = f.it in - let FuncType (ins, out) = type_ c ftype in - let c' = {c with locals = ins @ locals; results = out; labels = [out]} in - check_block c' body (FuncType ([], out)) f.at + let FuncType (ts1, ts2) = type_ c ftype in + let c' = {c with locals = ts1 @ locals; results = ts2; labels = [ts2]} in + check_block c' body (FuncType ([], ts2)) f.at let is_const (c : context) (e : instr) = match e.it with + | RefNull _ + | RefFunc _ | Const _ -> true | GlobalGet x -> let GlobalType (_, mut) = global c x in mut = Immutable | _ -> false @@ -401,21 +512,38 @@ let check_memory (c : context) (mem : memory) = let {mtype} = mem.it in check_memory_type mtype mem.at -let check_elem (c : context) (seg : table_segment) = - let {index; offset; init} = seg.it in - check_const c offset I32Type; - ignore (table c index); - ignore (List.map (func c) init) - -let check_data (c : context) (seg : memory_segment) = - let {index; offset; init} = seg.it in - check_const c offset I32Type; - ignore (memory c index) +let check_elem_mode (c : context) (t : ref_type) (mode : segment_mode) = + match mode.it with + | Passive -> () + | Active {index; offset} -> + let TableType (_, et) = table c index in + require (t = et) mode.at + ("type mismatch: element segment's type " ^ string_of_ref_type t ^ + " does not match table's element type " ^ string_of_ref_type et); + check_const c offset (NumType I32Type) + | Declarative -> () + +let check_elem (c : context) (seg : elem_segment) = + let {etype; einit; emode} = seg.it in + List.iter (fun const -> check_const c const (RefType etype)) einit; + check_elem_mode c etype emode + +let check_data_mode (c : context) (mode : segment_mode) = + match mode.it with + | Passive -> () + | Active {index; offset} -> + ignore (memory c index); + check_const c offset (NumType I32Type) + | Declarative -> assert false + +let check_data (c : context) (seg : data_segment) = + let {dinit; dmode} = seg.it in + check_data_mode c dmode let check_global (c : context) (glob : global) = - let {gtype; value} = glob.it in + let {gtype; ginit} = glob.it in let GlobalType (t, mut) = gtype in - check_const c value t + check_const c ginit t (* Modules *) @@ -456,18 +584,23 @@ let check_export (c : context) (set : NameSet.t) (ex : export) : NameSet.t = let check_module (m : module_) = let - { types; imports; tables; memories; globals; funcs; start; elems; data; + { types; imports; tables; memories; globals; funcs; start; elems; datas; exports } = m.it in let c0 = List.fold_right check_import imports - {empty_context with types = List.map (fun ty -> ty.it) types} + { empty_context with + refs = Free.module_ ({m.it with funcs = []; start = None} @@ m.at); + types = List.map (fun ty -> ty.it) types; + } in let c1 = { c0 with funcs = c0.funcs @ List.map (fun f -> type_ c0 f.it.ftype) funcs; tables = c0.tables @ List.map (fun tab -> tab.it.ttype) tables; memories = c0.memories @ List.map (fun mem -> mem.it.mtype) memories; + elems = List.map (fun elem -> elem.it.etype) elems; + datas = List.map (fun _data -> ()) datas; } in let c = @@ -478,11 +611,9 @@ let check_module (m : module_) = List.iter (check_table c1) tables; List.iter (check_memory c1) memories; List.iter (check_elem c1) elems; - List.iter (check_data c1) data; + List.iter (check_data c1) datas; List.iter (check_func c) funcs; check_start c start; ignore (List.fold_left (check_export c) NameSet.empty exports); - require (List.length c.tables <= 1) m.at - "multiple tables are not allowed (yet)"; require (List.length c.memories <= 1) m.at "multiple memories are not allowed (yet)" diff --git a/proposals/bulk-memory-operations/Overview.md b/proposals/bulk-memory-operations/Overview.md new file mode 100644 index 0000000000..d843f00866 --- /dev/null +++ b/proposals/bulk-memory-operations/Overview.md @@ -0,0 +1,453 @@ +# Bulk Memory Operations and Conditional Segment Initialization + +## Motivation for Bulk Memory Operations + +Some people have mentioned that `memcpy` and `memmove` functions are hot +when profiling some WebAssembly benchmarks. Some examples: + +- https://github.com/WebAssembly/design/issues/236#issuecomment-283279499 + +> I've been looking at perf profiles for wasm unity benchmark a bit recently and see that some + of the hottest functions are doing memcpy or memset like things. If this is any indication of + normal wasm code patterns, I think we could see significant improvement with an intrinsic so + it may be worth prioritizing. + +- https://github.com/WebAssembly/design/issues/977#issue-204960079 + +> In a number of game engines I've been optimizing and benchmarking, interestingly the performance + of memcpy() does show up relatively high in profiles. (~2%-5% of total execution time) + +### Bulk Memory Operations Prototype + +I implemented a prototype implementation of a `memory.copy` instruction in v8 which just calls out +to v8's [`MemMove` function](https://cs.chromium.org/chromium/src/v8/src/utils.h?l=446). I compared +this to an implementation [generated by emscripten](https://gist.github.com/binji/c57dc945bba60985439ef8e5b574eee0) and currently used in the Unity demo. This implementation aligns then performs copies using `i32.load` and `i32.store`. I've also included performance achieved by unrolling this loop manually and increasing the size to `i64`. + +Each test copies `size` bytes from one address to another, non-overlapping. This is repeated `N` times. Each row copies a total of 1 Gib of data, and only touches 1 Mib of memory in the source and destination ranges. + +This is the core loop: + +```javascript + let mask = Mib - 1; + let start = performance.now(); + for (let i = 0; i < N; ++i) { + f(dst_base + dst, src_base + src, size); + dst = (dst + size) & mask; + src = (src + size) & mask; + } + let end = performance.now(); +``` + +The code for the benchmark can be found [here](https://gist.github.com/binji/b8e8bc0c0121235d9f1668bc447c7f8c). +Note that this will not run properly without a WebAssembly implementation of `memory.copy`. For my tests, I +hacked a version of v8 to replace any exported function called `memcpy` or `memmove` with a new function with +the following contents: + +```wasm +(func (param $dst i32) (param $src i32) (param $size i32) (result i32) + local.get $dst + local.get $src + local.get $size + memory.copy + local.get $dst) +``` + +Here are the results on my machine (x86_64, 2.9GHz, L1 32k, L2 256k, L3 256k): + +| | intrinsic | i64 load/store x 4 | i64 load/store x 2 | i32 load/store x 2 | i32 load/store | +| --- | --- | --- | --- | --- | --- | +| size=32b, N=33554432 | 1.382 Gib/s | 1.565 Gib/s | 1.493 Gib/s | 1.275 Gib/s | 1.166 Gib/s | +| size=64b, N=16777216 | 3.285 Gib/s | 2.669 Gib/s | 2.383 Gib/s | 1.861 Gib/s | 1.639 Gib/s | +| size=128b, N=8388608 | 6.162 Gib/s | 3.993 Gib/s | 3.480 Gib/s | 2.433 Gib/s | 2.060 Gib/s | +| size=256b, N=4194304 | 9.939 Gib/s | 5.323 Gib/s | 4.462 Gib/s | 2.724 Gib/s | 2.213 Gib/s | +| size=512b, N=2097152 | 15.777 Gib/s | 6.377 Gib/s | 4.913 Gib/s | 3.231 Gib/s | 2.457 Gib/s | +| size=1.0Kib, N=1048576 | 17.902 Gib/s | 7.010 Gib/s | 6.112 Gib/s | 3.568 Gib/s | 2.614 Gib/s | +| size=2.0Kib, N=524288 | 19.870 Gib/s | 8.248 Gib/s | 6.915 Gib/s | 3.764 Gib/s | 2.699 Gib/s | +| size=4.0Kib, N=262144 | 20.940 Gib/s | 9.145 Gib/s | 7.400 Gib/s | 3.871 Gib/s | 2.729 Gib/s | +| size=8.0Kib, N=131072 | 21.162 Gib/s | 9.258 Gib/s | 7.672 Gib/s | 3.925 Gib/s | 2.763 Gib/s | +| size=16.0Kib, N=65536 | 20.991 Gib/s | 9.758 Gib/s | 7.756 Gib/s | 3.945 Gib/s | 2.773 Gib/s | +| size=32.0Kib, N=32768 | 22.504 Gib/s | 9.956 Gib/s | 7.861 Gib/s | 3.966 Gib/s | 2.780 Gib/s | +| size=64.0Kib, N=16384 | 22.534 Gib/s | 10.088 Gib/s | 7.931 Gib/s | 3.974 Gib/s | 2.782 Gib/s | +| size=128.0Kib, N=8192 | 29.728 Gib/s | 10.032 Gib/s | 7.934 Gib/s | 3.975 Gib/s | 2.782 Gib/s | +| size=256.0Kib, N=4096 | 29.742 Gib/s | 10.116 Gib/s | 7.625 Gib/s | 3.886 Gib/s | 2.781 Gib/s | +| size=512.0Kib, N=2048 | 29.994 Gib/s | 10.090 Gib/s | 7.627 Gib/s | 3.985 Gib/s | 2.785 Gib/s | +| size=1.0Mib, N=1024 | 11.760 Gib/s | 10.091 Gib/s | 7.959 Gib/s | 3.989 Gib/s | 2.787 Gib/s | + + +## Motivation for Conditional Segment Initialization + +Under the current [threading proposal](https://github.com/WebAssembly/threads), +to share a module between multiple agents, the module must be instantiated +multiple times: once per agent. Instantiation initializes linear memory with +the contents in the module's data segments. If the memory is shared between +multiple agents, it will be initialized multiple times, potentially overwriting +stores that occurred after the previous initializations. + +For example: + +```webassembly +;; The module. +(module + (memory (export "memory") 1) + + ;; Some value used as a counter. + (data (i32.const 0) "\0") + + ;; Add one to the counter. + (func (export "addOne") + (i32.store8 + (i32.const 0) + (i32.add + (i32.load8_u (i32.const 0)) + (i32.const 1))) + ) +) +``` + +```javascript +// main.js +let moduleBytes = ...; + +WebAssembly.instantiate(moduleBytes).then( + ({module, instance}) => { + // Increment our counter. + instance.exports.addOne(); + + // Spawn a new Worker. + let worker = new Worker('worker.js'); + + // Send the module to the new Worker. + worker.postMessage(module); + }); + +// worker.js + +function onmessage(event) { + let module = event.data; + + // Use the module to create another instance. + WebAssembly.instantiate(module).then( + (instance) => { + // Oops, our counter has been clobbered. + }); +} + +``` + +This can be worked around by storing the data segments in a separate module +which is only instantiated once, then exporting this memory to be used by +another module that contains only code. This works, but it cumbersome since it +requires two modules where one should be enough. + + +## Motivation for combining Bulk Memory Operations + Conditional Segment Initialization Proposals + +When [discussing the design of Conditional Segment Initialization](https://github.com/WebAssembly/threads/issues/62), +we found that programmatic memory initialization from a read-only data segment +(via the `memory.init` instruction, described below) has similar behavior to the +proposed instruction to copy memory regions from linear memory (`memory.copy`, +also described below.) + +## Design + +Copying between regions in linear memory or a table is accomplished with the +new `*.copy` instructions: + +* `memory.copy`: copy from one region of linear memory to another +* `table.copy`: copy from one region of a table to another + +Filling a memory region can be accomplished with `memory.fill`: + +* `memory.fill`: fill a region of linear memory with a given byte value + +The [binary format for the data +section](https://webassembly.github.io/spec/core/binary/modules.html#binary-datasec) +currently has a collection of segments, each of which has a memory index, an +initializer expression for its offset, and its raw data. + +Since WebAssembly currently does not allow for multiple memories, the memory +index of each segment must be zero. We can repurpose this 32-bit integer as a +flags field where new meaning is attached to nonzero values. + +When the low bit of the new flags field is `1`, this segment is _passive_. A +passive segment will not be automatically copied into the memory or table on +instantiation, and must instead be applied manually using the following new +instructions: + +* `memory.init`: copy a region from a data segment +* `table.init`: copy a region from an element segment + +A passive segment has no initializer expression, since it will be specified +as an operand to `memory.init` or `table.init`. + +Segments can also be shrunk to size zero by using the following new instructions: + +* `data.drop`: discard the data in an data segment +* `elem.drop`: discard the data in an element segment + +An active segment is equivalent to a passive segment, but with an implicit +`memory.init` followed by a `data.drop` (or `table.init` followed by a +`elem.drop`) that is prepended to the module's start function. + +Additionally, the reference-types proposal introduces the notion of a function +reference (a function whose address is a program value). To support this, +element segments can have several encodings, and can also be used to +forward-declare functions whose address will be taken; see below. + +The reference-types proposal also introduces the bulk instructions `table.fill` +and `table.grow`, both of which take a function reference as an initializer +argument. + +### Data segments + +The meaning of the bits of the flag field (a `varuint32`) for data segments is: + +| Bit | Meaning | +| - | - | +| 0 | 0=is active, 1=is passive | +| 1 | if bit 0 clear: 0=memory 0, 1=has memory index | + +which yields this view, with the fields carried by each flag value: + +| Flags | Meaning | Memory index | Offset in memory | Count | Payload | +| - | - | - | - | - | - | +| 0 | Active | | `init_expr` | `varuint32` | `u8`* | +| 1 | Passive | | | `varuint32` | `u8`* | +| 2 | Active with memory index | `varuint32` | `init_expr` | `varuint32` | `u8`* | + +All other flag values are illegal. At present the memory index must be zero, +but the upcoming multi-memory proposal changes that. + + +### Element segments + +The meaning of the bits of the flag field (a `varuint32`) for element segments is: + +| Bit | Meaning | +| - | - | +| 0 | 0=is active, 1=is passive | +| 1 | if bit 0 clear: 0=table 0, 1=has table index | +| | if bit 0 set: 0=active, 1=declared | +| 2 | 0=carries indicies; 1=carries elemexprs | + +which yields this view, with the fields carried by each flag value: + +| Flag | Meaning | Table index | Offset in table | Encoding | Count | Payload | +| - | - | - | - | - | - | - | +| 0 | Legacy active, funcref externval | | `init_expr` | | `varuint32` | `idx`* | +| 1 | Passive, externval | | | `extern_kind` | `varuint32` | `idx`* | +| 2 | Active, externval | `varuint32` | `init_expr` | `extern_kind` | `varuint32` | `idx`* | +| 3 | Declared, externval | | | `extern_kind` | `varuint32` | `idx`* | +| 4 | Legacy active, funcref elemexpr | | `init_expr` | | `varuint32` | `elem_expr`* | +| 5 | Passive, elemexpr | | | `elem_type` | `varuint32` | `elem_expr`* | +| 6 | Active, elemexpr | `varuint32` | `init_expr` | `elem_type` | `varuint32` | `elem_expr`* | +| 7 | Declared, elemexpr | | | `elem_type` | `varuint32` | `elem_expr`* | + +All other flag values are illegal. Note that the "declared" attribute +is not used by this proposal, but is used by the reference-types +proposal. + +The `extern_kind` must be zero, signifying a function definition. An `idx` is a +`varuint32` that references an entity in the module, currently only its function +table. + +At present the table index must be zero, but the reference-types +proposal introduces a notion of multiple tables. + +An `elem_expr` is like an `init_expr`, but can only contain expressions of the following sequences: + +| Binary | Text | Description | +| - | - | - | +| `0xd0 0x0b` | `ref.null end` | Returns a null reference | +| `0xd2 varuint32 0x0b` | `ref.func $funcidx end` | Returns a reference to function `$funcidx` | + +### Segment Initialization + +In the MVP, segments are initialized during module instantiation. If any segment +would be initialized out-of-bounds, then the memory or table instance is not +modified. + +This behavior is changed in the bulk memory proposal: + +Each active segment is initialized in module-definition order. For +each segment, if reading the source or writing the destination would +go out of bounds, then instantiation fails at that point. Data that +had already been written for previous (in-bounds) segments stays +written. + +### `memory.init` instruction + +The `memory.init` instruction copies data from a given passive segment into a target +memory. The target memory and source segment are given as immediates. + +The instruction has the signature `[i32 i32 i32] -> []`. The parameters are, in order: + +- top-2: destination address +- top-1: offset into the source segment +- top-0: size of memory region in bytes + +It is a validation error to use `memory.init` with an out-of-bounds segment index. + +A trap occurs if: + +* the source offset plus size is greater than the length of the source data segment; + this includes the case that the segment has been dropped via `data.drop` +* the destination offset plus size is greater than the length of the target memory + +The order of writing is unspecified, though this is currently unobservable. + +Note that it is allowed to use `memory.init` on the same data segment more than +once. + +### `data.drop` instruction + +The `data.drop` instruction shrinks the size of the segment to zero. After a +data segment has been dropped, it can still be used in a `memory.init` +instruction, but only a zero-length access at offset zero will not trap. This +instruction is intended to be used as an optimization hint to the WebAssembly +implementation. After a memory segment is dropped its data can no longer be +retrieved, so the memory used by this segment may be freed. + +It is a validation error to use `data.drop` with an out-of-bounds segment index. + +### `memory.copy` instruction + +Copy data from a source memory region to destination region. The +regions are said to overlap if they are in the same memory and the +start address of one region is one of the addresses that's read or +written (by the copy operation) in the other region. + +This instruction has two immediate arguments: the source and +destination memory indices. They currently both must be zero. + +Copying takes place as if an intermediate buffer were used, allowing the +destination and source to overlap. + +The instruction has the signature `[i32 i32 i32] -> []`. The parameters are, in order: + +- top-2: destination address +- top-1: source address +- top-0: size of memory region in bytes + +A trap occurs if: + +* the source offset plus size is greater than the length of the source memory +* the destination offset plus size is greater than the length of the target memory + +The bounds check is performed before any data are written. + +### `memory.fill` instruction + +Set all bytes in a memory region to a given byte. This instruction has an +immediate argument of which memory to operate on, and it must be zero for now. + +The instruction has the signature `[i32 i32 i32] -> []`. The parameters are, in order: + +- top-2: destination address +- top-1: byte value to set +- top-0: size of memory region in bytes + +A trap occurs if: + +* the destination offset plus size is greater than the length of the target memory + +The bounds check is performed before any data are written. + + +### `table.init`, `elem.drop`, and `table.copy` instructions + +The `table.*` instructions behave similary to the `memory.*` instructions, with +the difference that they operate on element segments and tables, instead of +data segments and memories. The offset and length operands of `table.init` and +`table.copy` have element units instead of bytes as well. + +## Passive Segment Initialization Example + +Consider if there are two data sections, the first is always active and the +second is conditionally active if global 0 has a non-zero value. This could be +implemented as follows: + +```webassembly +(import "a" "global" (global i32)) ;; global 0 +(memory 1) +(data (i32.const 0) "hello") ;; data segment 0, is active so always copied +(data passive "goodbye") ;; data segment 1, is passive + +(func $start + (if (global.get 0) + + ;; copy data segment 1 into memory 0 (the 0 is implicit) + (memory.init 1 + (i32.const 16) ;; target offset + (i32.const 0) ;; source offset + (i32.const 7)) ;; length + + ;; The memory used by this segment is no longer needed, so this segment can + ;; be dropped. + (data.drop 1)) +) +``` + +### Instruction encoding + +All bulk memory instructions are encoded as a 0xfc prefix byte, followed by +another opcode, optionally followed by more immediates: + +``` +instr ::= ... + | 0xfc operation:uint8 ... +``` + +| Name | Opcode | Immediate | Description | +| ---- | ---- | ---- | ---- | +| `memory.init` | `0xfc 0x08` | `segment:varuint32`, `memory:0x00` | copy from a passive data segment to linear memory | +| `data.drop` | `0xfc 0x09` | `segment:varuint32` | prevent further use of passive data segment | +| `memory.copy` | `0xfc 0x0a` | `memory_dst:0x00` `memory_src:0x00` | copy from one region of linear memory to another region | +| `memory.fill` | `0xfc 0x0b` | `memory:0x00` | fill a region of linear memory with a given byte value | +| `table.init` | `0xfc 0x0c` | `segment:varuint32`, `table:0x00` | copy from a passive element segment to a table | +| `elem.drop` | `0xfc 0x0d` | `segment:varuint32` | prevent further use of a passive element segment | +| `table.copy` | `0xfc 0x0e` | `table_dst:0x00` `table_src:0x00` | copy from one region of a table to another region | + +### `DataCount` section + +The WebAssembly binary format is designed to be validated in a single pass. If +a section requires information to validate, it is guaranteed that this +information will be present in a previous section. + +The `memory.{init,drop}` instructions break this guarantee. Both of these +instructions are used in the `Code` section. They each have a data segment +index immediate, but the vector of data segments is not available until the +`Data` section is parsed, which occurs after the `Code` section. + +To keep single-pass validation, the number of data segments defined in the +`Data` section must be available before the `Code` section. This information is +provided in a new `DataCount` section with the code `12`. + +Like all sections, the `DataCount` section is optional. If present, it must +appear in the following order: + +| 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 | +| Global | `6` | Global declarations | +| Export | `7` | Exports | +| Start | `8` | Start function declaration | +| Element | `9` | Elements section | +| DataCount | `12` | Data segment count | +| Code | `10` | Function bodies (code) | +| Data | `11` | Data segments | + +The `DataCount` section has just one field that specifies the number of data +segments in the `Data` section: + +| Field | Type | Description | +| ----- | ---- | ----------- | +| count | `varuint32` | count of data segments in `Data` section | + +The binary is malformed if `count` is not equal to the number of data segments +in the `Data` section. The binary is also malformed if the `DataCount` section +is omitted and a `memory.init` or `data.drop` instruction is used. diff --git a/proposals/reference-types/Overview.md b/proposals/reference-types/Overview.md new file mode 100644 index 0000000000..43a36d351b --- /dev/null +++ b/proposals/reference-types/Overview.md @@ -0,0 +1,292 @@ +# Reference Types for WebAssembly + +TODO: more text, motivation, explanation + +## Introduction + +Motivation: + +* Easier and more efficient interop with host environment (see e.g. the [Interface Types proposal](https://github.com/WebAssembly/interface-types/blob/master/proposals/interface-types/Explainer.md)) + - allow host references to be represented directly by type `externref` (see [here](https://github.com/WebAssembly/interface-types/issues/9)) + - without having to go through tables, allocating slots, and maintaining index bijections at the boundaries + +* Basic manipulation of tables inside Wasm + - allow representing data structures containing references +by repurposing tables as a general memory for opaque data types + - allow manipulating function tables from within Wasm. + - add instructions missing from [bulk operations proposal](https://github.com/WebAssembly/bulk-memory-operations/blob/master/proposals/bulk-memory-operations/Overview.md) + +* Set the stage for later additions: + + - Typed function references (see [below](#typed-function-references)) + - Exception references (see the [exception handling proposal](https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md) and [here](https://github.com/WebAssembly/interface-types/issues/10)) + - A smoother transition path to GC (see the [GC proposal](https://github.com/WebAssembly/gc/blob/master/proposals/gc/Overview.md)) + +Get the most important parts soon! + +Summary: +* Add new type `externref` that can be used as both a value types and a table element type. + +* Also allow `funcref` as a value type. + +* Introduce instructions to get and set table slots. + +* Add missing table size, grow, fill instructions. + +* Allow multiple tables. + +Notes: + +* This extension does not imply GC by itself, only if host refs are GCed pointers! + +* Reference types are *opaque*, i.e., their value is abstract and they cannot be stored into linear memory. Tables are used as the equivalent. + + +## Language Extensions + +Typing extensions: + +* Introduce `funcref` and `externref` as a new class of *reference types*. + - `reftype ::= funcref | externref` + +* Value types (of locals, globals, function parameters and results) can now be either numeric types or reference types. + - `numtype ::= i32 | i64 | f32 | f64` + - `valtype ::= | ` + - locals with reference type are initialised with `null` + +* Element types (of tables) are equated with reference types. + - `elemtype ::= ` + + +New/extended instructions: + +* The `select` instruction now optionally takes a value type immediate. Only annotated `select` can be used with reference types. + - `select : [t t i32] -> [t]` + - iff `t` is a `numtype` + - `select t : [t t i32] -> [t]` + +* The new instruction `ref.null` evaluates to the null reference constant. + - `ref.null rt : [] -> [rtref]` + - iff `rt = func` or `rt = extern` + - allowed in constant expressions + +* The new instruction `ref.is_null` checks for null. + - `ref.is_null : [rtref] -> [i32]` + +* The new instruction `ref.func` creates a reference to a given function. + - `ref.func $x : [] -> [funcref]` + - iff `$x : func $t` + - allowed in constant expressions + - Note: the result type of this instruction may be refined by future proposals (e.g., to `[(ref $t)]`) + +* The new instructions `table.get` and `table.set` access tables. + - `table.get $x : [i32] -> [t]` + - iff `$x : table t` + - `table.set $x : [i32 t] -> []` + - iff `$x : table t` + +* The new instructions `table.size`and `table.grow` manipulate the size of a table. + - `table.size $x : [] -> [i32]` + - iff `$x : table t` + - `table.grow $x : [t i32] -> [i32]` + - iff `$x : table t` + - the first operand of `table.grow` is an initialisation value (for compatibility with future extensions to the type system, such as non-nullable references) + +* The new instruction `table.fill` fills a range in a table with a value. + - `table.fill $x : [i32 t i32] -> []` + - iff `$x : table t` + - the first operand is the start index of the range, the third operand its length (analoguous to `memory.fill`) + - traps when range+length > size of the table, but only after filling range up to size (analoguous to `memory.fill`) + +* The `table.init` instruction takes an additional table index as immediate. + - `table.init $x $y : [i32 i32 i32] -> []` + - iff `$x : table t` + - and `$y : elem t'` + - and `t' <: t` + +* The `table.copy` instruction takes two additional table indices as immediate. + - `table.copy $x $y : [i32 i32 i32] -> []` + - iff `$x : table t` + - and `$y : table t'` + - and `t' <: t` + +* The `call_indirect` instruction takes a table index as immediate. + - `call_indirect $x (type $t) : [t1* i32] -> [t2*]` + - iff `$t = [t1*] -> [t2*]` + - and `$x : table t'` + - and `t' <: funcref` + +* In all instructions, table indices can be omitted and default to 0. + +Note: +- In the binary format, space for the additional table indices is already reserved. +- For backwards compatibility, all table indices may be omitted in the text format, in which case they default to 0 (for `table.copy`, both indices must be either present or absent). + + +Table extensions: + +* A module may define, import, and export multiple tables. + - As usual, the imports come first in the index space. + - This is already representable in the binary format. + +* Element segments take a table index as immediate that identifies the table they apply to. + - In the binary format, space for the index is already reserved. + - For backwards compatibility, the index may be omitted in the text format, in which case it defaults to 0. + + +JS API extensions: + +* Any JS value can be passed as `externref` to a Wasm function, stored in a global, or in a table. + +* Any Wasm exported function object or `null` can be passed as `funcref` to a Wasm function, stored in a global, or in a table. + +* The `WebAssembly.Table#grow` method takes an additional initialisation argument. + - optional for backwards compatibility, defaults to default value of respective type + + +## Possible Future Extensions + + +### Subtyping + +Motivation: + +* Enable various extensions (see below). + +Additions: + +* Introduce a simple subtype relation between reference types. + - reflexive transitive closure of the following rules + - `t <: anyref` for all reftypes `t` + + +### Equality on references + +Motivation: + +* Allow references to be compared by identity. +* However, not all reference types should be comparable, since that may make implementation details observable in a non-deterministic fashion (consider e.g. host JavaScript strings). + + +Additions: + +* Add `eqref` as the type of comparable references + - `reftype ::= ... | eqref` +* It is a subtype of `anyref` + - `eqref < anyref` +* Add `ref.eq` instruction. + - `ref.eq : [eqref eqref] -> [i32]` + +API changes: + +* Any JS object (non-primitive value) or symbol or `null` can be passed as `eqref` to a Wasm function, stored in a global, or in a table. + + +Questions: + +* Interaction with type imports/exports: do they need to distinguish equality types from non-equality now? + +* Similarly, the JS API for `WebAssembly.Type` below would need to enable the distinction. + + +### Typed function references + +See the [typed function references proposal](https://github.com/WebAssembly/function-references/blob/master/proposals/function-references/Overview.md) + +Motivation: + +* Allow function pointers to be expressed directly without going through table and dynamic type check. +* Enable functions to be passed to other modules easily. + +Additions: + +* Add `(ref $t)` as a reference type + - `reftype ::= ... | ref ` +* Refine `(ref.func $f)` instruction + - `ref.func $f : [] -> (ref $t)` iff `$f : $t` +* Add `(call_ref)` instruction + - `call_ref : [ts1 (ref $t)] -> [ts2]` iff `$t = [ts1] -> [ts2]` +* Introduce subtyping `ref < funcref` +* Subtying between concrete and universal reference types + - `ref $t < anyref` + - `ref < funcref` + - Note: reference types are not necessarily subtypes of `eqref`, including functions + +* Typed function references cannot be null! + + +### Type Import/Export + +Motivation: + +* Allow the host (or Wasm modules) to distinguish different reference types. + +Additions: + +* Add `(type)` external type, enables types to be imported and exported + - `externtype ::= ... | type` + - `(ref $t)` can now denote an abstract type or a function reference + - imported types have index starting from 0. + - reserve byte in binary format to allow refinements later + +* Add abstract type definitions in type section + - `deftype ::= | new` + - creates unique abstract type + +* Add `WebAssembly.Type` class to JS API + - constructor `new WebAssembly.Type(name)` creates unique abstract type + +* Subtyping `ref ` < `anyref` + + +Questions: + +* Do we need to impose constraints on the order of imports, to stratify section dependencies? Should type import and export be separate sections instead? + +* Do we need a nullable `(optref $t)` type to allow use with locals etc.? Could a `(nullable T)` type constructor work instead? + - Unclear how `nullable` constructor would integrate exactly. Would it only allow (non-nullable) reference types as argument? Does this require a kind system? Should `anyref` be different from `(nullable anyref)`, or the latter disallowed? What about `funcref`? + - Semantically, thinking of `(nullable T)` as `T | nullref` could answer these questions, but we cannot support arbitrary unions in Wasm. + +* Should we add `(new)` definitional type to enable Wasm modules to define new types, too? + +* Do `new` definition types and the `WebAssembly.Type` constructor need to take a "comparable" flag controlling whether references to a type can be compared? + +* Should JS API allow specifying subtyping between new types? + + +### Down Casts + +Motivation: + +* Allow to implement generics by using `anyref` as a top type. + +Addition: + +* Add a `cast` instruction that checks whether its operand can be cast to a lower type and converts its type accordingly if so; otherwise, goes to an else branch. + - `cast * else * end: [] -> ` iff ` < ` and `* : [] -> ` and `* : [] -> ` + - could later be generalised to non-reference types? + +Note: + +* Can decompose `call_indirect` (assuming multi-value proposal): + - `(call_indirect $x (type $t))` reduces to `(table.get $x) (cast $t anyref (ref $t) (then (call_ref (ref $t))) (else (unreachable)))` + + +### GC Types + +See [GC proposal](https://github.com/WebAssembly/gc/blob/master/proposals/gc/Overview.md). + + +### Further possible generalisations + +* Introduce reference types pointing to tables, memories, or globals. + - `deftype ::= ... | global | table | memory ` + - `ref.global $g : [] -> (ref $t)` iff `$g : $t` + - `ref.table $x : [] -> (ref $t)` iff `$x : $t` + - `ref.mem $m : [] -> (ref $t)` iff `$m : $t` + - yields first-class tables, memories, globals + - would requires duplicating all respective instructions + +* Allow all value types as element types. + - `deftype := ... | globaltype | tabletype | memtype` + - would unify element types with value types diff --git a/test/core/binary-leb128.wast b/test/core/binary-leb128.wast index 8503c9ae9e..1d67219583 100644 --- a/test/core/binary-leb128.wast +++ b/test/core/binary-leb128.wast @@ -33,9 +33,10 @@ "\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 + "\09\09\01" ;; Element section with 1 entry + "\02" ;; Element with explicit table index "\80\00" ;; Table index 0, encoded with 2 bytes - "\41\00\0b\00" ;; (i32.const 0) with no elements + "\41\00\0b\00\00" ;; (i32.const 0) with no elements ) (module binary "\00asm" "\01\00\00\00" diff --git a/test/core/binary.wast b/test/core/binary.wast index 8f2e2ba80e..d85c968511 100644 --- a/test/core/binary.wast +++ b/test/core/binary.wast @@ -45,12 +45,120 @@ (assert_malformed (module binary "\00asm\00\00\00\01") "unknown binary version") ;; Invalid section id. -(assert_malformed (module binary "\00asm" "\01\00\00\00" "\0c\00") "malformed 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") +;; 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 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" ;; Memory index 0, encoded with 2 bytes + "\41\00\0b\00" ;; (i32.const 0) with contents "" +) + +;; Element segment 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\09\01" ;; Element section with 1 entry + "\02\80\00" ;; Table index 0, encoded with 2 bytes + "\41\00\0b\00\00" ;; (i32.const 0) with no elements +) ;; Type section with signed LEB128 encoded type (assert_malformed @@ -65,98 +173,582 @@ "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" +) -;; call_indirect reserved byte equal to zero. +;; Signed LEB128 must not be overlong (assert_malformed (module binary "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\04\04\01\70\00\00" ;; Table section - "\0a\09\01" ;; Code section + "\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" +) + + +;; Unsigned LEB128 must not be overlong +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\05\08\01" ;; Memory section with 1 entry + "\00\82\80\80\80\80\00" ;; no max, minimum 2 with one byte too many + ) + "integer representation too long" +) +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\01\04\01\60\00\00" ;; Type section + "\03\02\01\00" ;; Function section + "\05\03\01\00\01" ;; Memory section + "\0a\11\01" ;; Code section ;; function 0 - "\07\00" + "\0f\01\01" ;; local type count + "\7f" ;; i32 "\41\00" ;; i32.const 0 - "\11\00" ;; call_indirect (type 0) - "\01" ;; call_indirect reserved byte is not equal to zero! + "\28" ;; i32.load + "\02" ;; alignment 2 + "\82\80\80\80\80\00" ;; offset 2 with one byte too many + "\1a" ;; drop "\0b" ;; end ) - "zero flag expected" + "integer representation too long" ) - -;; call_indirect reserved byte should not be a "long" LEB128 zero. (assert_malformed (module binary "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\04\04\01\70\00\00" ;; Table section - "\0a\0a\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 - "\07\00" + "\0f\01\01" ;; local type count + "\7f" ;; i32 "\41\00" ;; i32.const 0 - "\11\00" ;; call_indirect (type 0) - "\80\00" ;; call_indirect reserved byte + "\28" ;; i32.load + "\82\80\80\80\80\00" ;; alignment 2 with one byte too many + "\00" ;; offset 0 + "\1a" ;; drop "\0b" ;; end ) - "zero flag expected" + "integer representation too long" ) - -;; Same as above for 3, 4, and 5-byte zero encodings. (assert_malformed (module binary "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\04\04\01\70\00\00" ;; Table section - "\0a\0b\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 - "\08\00" + "\10\01\01" ;; local type count + "\7f" ;; i32 + "\41\00" ;; i32.const 0 + "\41\03" ;; i32.const 3 + "\36" ;; i32.store + "\82\80\80\80\80\00" ;; alignment 2 with one byte too many + "\03" ;; offset 3 + "\0b" ;; end + ) + "integer representation too long" +) +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\01\04\01\60\00\00" ;; Type section + "\03\02\01\00" ;; Function section + "\05\03\01\00\01" ;; Memory section + "\0a\12\01" ;; Code section + ;; function 0 + "\10\01\01" ;; local type count + "\7f" ;; i32 "\41\00" ;; i32.const 0 - "\11\00" ;; call_indirect (type 0) - "\80\80\00" ;; call_indirect reserved byte + "\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 ) - "zero flag expected" + "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" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\04\04\01\70\00\00" ;; Table section - "\0a\0c\01" ;; Code section + "\06\10\01" ;; Global section with 1 entry + "\7e\00" ;; i64, immutable + "\42\80\80\80\80\80\80\80\80\80\80\00" ;; i64.const 0 with one byte too many + "\0b" ;; end + ) + "integer representation too long" +) +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\06\10\01" ;; Global section with 1 entry + "\7e\00" ;; i64, immutable + "\42\ff\ff\ff\ff\ff\ff\ff\ff\ff\ff\7f" ;; i64.const -1 with one byte too many + "\0b" ;; end + ) + "integer representation too long" +) +;; Unsigned LEB128s zero-extend +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\05\07\01" ;; Memory section with 1 entry + "\00\82\80\80\80\70" ;; no max, minimum 2 with unused bits set + ) + "integer too large" +) +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\05\07\01" ;; Memory section with 1 entry + "\00\82\80\80\80\40" ;; no max, minimum 2 with some unused bits set + ) + "integer too large" +) +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\01\04\01\60\00\00" ;; Type section + "\03\02\01\00" ;; Function section + "\05\03\01\00\01" ;; Memory section + "\0a\10\01" ;; Code section ;; function 0 - "\09\00" + "\0e\01\01" ;; local type count + "\7f" ;; i32 "\41\00" ;; i32.const 0 - "\11\00" ;; call_indirect (type 0) - "\80\80\80\00" ;; call_indirect reserved byte + "\28" ;; i32.load + "\02" ;; alignment 2 + "\82\80\80\80\10" ;; offset 2 with unused bits set + "\1a" ;; drop "\0b" ;; end ) - "zero flag expected" + "integer too large" +) +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\01\04\01\60\00\00" ;; Type section + "\03\02\01\00" ;; Function section + "\05\03\01\00\01" ;; Memory section + "\0a\10\01" ;; Code section + ;; function 0 + "\0e\01\01" ;; local type count + "\7f" ;; i32 + "\41\00" ;; i32.const 0 + "\28" ;; i32.load + "\02" ;; alignment 2 + "\82\80\80\80\40" ;; offset 2 with some unused bits set + "\1a" ;; drop + "\0b" ;; end + ) + "integer too large" +) +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\01\04\01\60\00\00" ;; Type section + "\03\02\01\00" ;; Function section + "\05\03\01\00\01" ;; Memory section + "\0a\10\01" ;; Code section + "\0e\01\01" ;; local type count + "\7f" ;; i32 + "\41\00" ;; i32.const 0 + "\28" ;; i32.load + "\82\80\80\80\10" ;; alignment 2 with unused bits set + "\00" ;; offset 0 + "\1a" ;; drop + "\0b" ;; end + ) + "integer too large" +) +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\01\04\01\60\00\00" ;; Type section + "\03\02\01\00" ;; Function section + "\05\03\01\00\01" ;; Memory section + "\0a\10\01" ;; Code section + ;; function 0 + "\0e\01\01" ;; local type count + "\7f" ;; i32 + "\41\00" ;; i32.const 0 + "\28" ;; i32.load + "\82\80\80\80\40" ;; alignment 2 with some unused bits set + "\00" ;; offset 0 + "\1a" ;; drop + "\0b" ;; end + ) + "integer too large" +) +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\01\04\01\60\00\00" ;; Type section + "\03\02\01\00" ;; Function section + "\05\03\01\00\01" ;; Memory section + "\0a\11\01" ;; Code section + ;; function 0 + "\0f\01\01" ;; local type count + "\7f" ;; i32 + "\41\00" ;; i32.const 0 + "\41\03" ;; i32.const 3 + "\36" ;; i32.store + "\82\80\80\80\10" ;; alignment 2 with unused bits set + "\03" ;; offset 3 + "\0b" ;; end + ) + "integer too large" +) +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\01\04\01\60\00\00" ;; Type section + "\03\02\01\00" ;; Function section + "\05\03\01\00\01" ;; Memory section + "\0a\11\01" ;; Code section + ;; function 0 + "\0f\01\01" ;; local type count + "\7f" ;; i32 + "\41\00" ;; i32.const 0 + "\41\03" ;; i32.const 3 + "\36" ;; i32.store + "\82\80\80\80\40" ;; alignment 2 with some unused bits set + "\03" ;; offset 3 + "\0b" ;; end + ) + "integer too large" ) - (assert_malformed (module binary "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\04\04\01\70\00\00" ;; Table section - "\0a\0d\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 + "\03" ;; 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 - "\0a\00" + "\0f\01\01" ;; local type count + "\7f" ;; i32 "\41\00" ;; i32.const 0 - "\11\00" ;; call_indirect (type 0) - "\80\80\80\80\00" ;; call_indirect reserved byte + "\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 ) - "zero flag expected" + "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. @@ -176,7 +768,7 @@ "\1a" ;; drop "\0b" ;; end ) - "zero flag expected" + "zero byte expected" ) ;; memory.grow reserved byte should not be a "long" LEB128 zero. @@ -196,7 +788,7 @@ "\1a" ;; drop "\0b" ;; end ) - "zero flag expected" + "zero byte expected" ) ;; Same as above for 3, 4, and 5-byte zero encodings. @@ -216,7 +808,7 @@ "\1a" ;; drop "\0b" ;; end ) - "zero flag expected" + "zero byte expected" ) (assert_malformed @@ -235,7 +827,7 @@ "\1a" ;; drop "\0b" ;; end ) - "zero flag expected" + "zero byte expected" ) (assert_malformed @@ -254,7 +846,7 @@ "\1a" ;; drop "\0b" ;; end ) - "zero flag expected" + "zero byte expected" ) ;; memory.size reserved byte equal to zero. @@ -273,7 +865,7 @@ "\1a" ;; drop "\0b" ;; end ) - "zero flag expected" + "zero byte expected" ) ;; memory.size reserved byte should not be a "long" LEB128 zero. @@ -292,7 +884,7 @@ "\1a" ;; drop "\0b" ;; end ) - "zero flag expected" + "zero byte expected" ) ;; Same as above for 3, 4, and 5-byte zero encodings. @@ -311,7 +903,7 @@ "\1a" ;; drop "\0b" ;; end ) - "zero flag expected" + "zero byte expected" ) (assert_malformed @@ -329,7 +921,7 @@ "\1a" ;; drop "\0b" ;; end ) - "zero flag expected" + "zero byte expected" ) (assert_malformed @@ -347,7 +939,24 @@ "\1a" ;; drop "\0b" ;; end ) - "zero flag expected" + "zero byte expected" +) + +;; Local number is unsigned 32 bit +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\01\04\01\60\00\00" ;; Type section + "\03\02\01\00" ;; Function section + "\0a\0c\01" ;; Code section + + ;; function 0 + "\0a\02" + "\80\80\80\80\10\7f" ;; 0x100000000 i32 + "\02\7e" ;; 0x00000002 i64 + "\0b" ;; end + ) + "integer too large" ) ;; Local number is unsigned 32 bit @@ -470,6 +1079,168 @@ "\0a\01\00" ;; Code section with 0 functions ) +;; Fewer passive segments than datacount +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\0c\01\03" ;; Datacount section with value "3" + "\0b\05\02" ;; Data section with two entries + "\01\00" ;; Passive data section + "\01\00") ;; Passive data section + "data count and data section have inconsistent lengths") + +;; More passive segments than datacount +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\0c\01\01" ;; Datacount section with value "1" + "\0b\05\02" ;; Data section with two entries + "\01\00" ;; Passive data section + "\01\00") ;; Passive data section + "data count and data section have inconsistent lengths") + +;; memory.init requires a datacount section +(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\00" ;; Memory section + "\0a\0e\01" ;; Code section + + ;; function 0 + "\0c\00" + "\41\00" ;; zero args + "\41\00" + "\41\00" + "\fc\08\00\00" ;; memory.init + "\0b" + + "\0b\03\01\01\00" ;; Data section + ) ;; end + "data count section required") + +;; data.drop requires a datacount section +(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\00" ;; Memory section + "\0a\07\01" ;; Code section + + ;; function 0 + "\05\00" + "\fc\09\00" ;; data.drop + "\0b" + + "\0b\03\01\01\00" ;; Data section + ) ;; end + "data count section required") + +;; passive element segment containing opcode other than ref.func or ref.null +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + + "\01\04\01\60\00\00" ;; Type section + + "\03\02\01\00" ;; Function section + + "\04\04\01" ;; Table section with 1 entry + "\70\00\00" ;; no max, minimum 0, funcref + + "\05\03\01\00\00" ;; Memory section + + "\09\07\01" ;; Element section with one segment + "\05\70" ;; Passive, funcref + "\01" ;; 1 element + "\d3\00\0b" ;; bad opcode, index 0, end + + "\0a\04\01" ;; Code section + + ;; function 0 + "\02\00" + "\0b") ;; end + "illegal opcode") + +;; passive element segment containing type other than funcref +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + + "\01\04\01\60\00\00" ;; Type section + + "\03\02\01\00" ;; Function section + + "\04\04\01" ;; Table section with 1 entry + "\70\00\00" ;; no max, minimum 0, funcref + + "\05\03\01\00\00" ;; Memory section + + "\09\07\01" ;; Element section with one segment + "\05\7f" ;; Passive, i32 + "\01" ;; 1 element + "\d2\00\0b" ;; ref.func, index 0, end + + "\0a\04\01" ;; Code section + + ;; function 0 + "\02\00" + "\0b") ;; end + "malformed reference type") + +;; passive element segment containing opcode ref.func +(module binary + "\00asm" "\01\00\00\00" + + "\01\04\01\60\00\00" ;; Type section + + "\03\02\01\00" ;; Function section + + "\04\04\01" ;; Table section with 1 entry + "\70\00\00" ;; no max, minimum 0, funcref + + "\05\03\01\00\00" ;; Memory section + + "\09\07\01" ;; Element section with one segment + "\05\70" ;; Passive, funcref + "\01" ;; 1 element + "\d2\00\0b" ;; ref.func, index 0, end + + "\0a\04\01" ;; Code section + + ;; function 0 + "\02\00" + "\0b") ;; end + +;; passive element segment containing opcode ref.null +(module binary + "\00asm" "\01\00\00\00" + + "\01\04\01\60\00\00" ;; Type section + + "\03\02\01\00" ;; Function section + + "\04\04\01" ;; Table section with 1 entry + "\70\00\00" ;; no max, minimum 0, funcref + + "\05\03\01\00\00" ;; Memory section + + "\09\07\01" ;; Element section with one segment + "\05\70" ;; Passive, funcref + "\01" ;; 1 element + "\d0\70\0b" ;; ref.null, end + + "\0a\04\01" ;; Code section + + ;; function 0 + "\02\00" + "\0b") ;; end + + ;; Type count can be zero (module binary "\00asm" "\01\00\00\00" diff --git a/test/core/br_table.wast b/test/core/br_table.wast index d03068744e..734593d6c3 100644 --- a/test/core/br_table.wast +++ b/test/core/br_table.wast @@ -1242,6 +1242,26 @@ (i32.const 3) ) ) + + (func (export "meet-externref") (param i32) (param externref) (result externref) + (block $l1 (result externref) + (block $l2 (result externref) + (br_table $l1 $l2 $l1 (local.get 1) (local.get 0)) + ) + ) + ) + + (func (export "meet-bottom") + (block (result f64) + (block (result f32) + (unreachable) + (br_table 0 1 1 (i32.const 1)) + ) + (drop) + (f64.const 0) + ) + (drop) + ) ) (assert_return (invoke "type-i32")) @@ -1425,6 +1445,10 @@ (assert_return (invoke "nested-br_table-loop-block" (i32.const 1)) (i32.const 3)) +(assert_return (invoke "meet-externref" (i32.const 0) (ref.extern 1)) (ref.extern 1)) +(assert_return (invoke "meet-externref" (i32.const 1) (ref.extern 1)) (ref.extern 1)) +(assert_return (invoke "meet-externref" (i32.const 2) (ref.extern 1)) (ref.extern 1)) + (assert_invalid (module (func $type-arg-void-vs-num (result i32) (block (br_table 0 (i32.const 1)) (i32.const 1)) @@ -1588,6 +1612,20 @@ ) +(assert_invalid + (module (func $meet-bottom (param i32) (result externref) + (block $l1 (result externref) + (drop + (block $l2 (result i32) + (br_table $l2 $l1 $l2 (ref.null extern) (local.get 0)) + ) + ) + (ref.null extern) + ) + )) + "type mismatch" +) + (assert_invalid (module (func $unbound-label (block (br_table 2 1 (i32.const 1))) diff --git a/test/core/bulk.wast b/test/core/bulk.wast new file mode 100644 index 0000000000..5dcac724cf --- /dev/null +++ b/test/core/bulk.wast @@ -0,0 +1,351 @@ +;; segment syntax +(module + (memory 1) + (data "foo")) + +(module + (table 3 funcref) + (elem funcref (ref.func 0) (ref.null func) (ref.func 1)) + (func) + (func)) + +;; memory.fill +(module + (memory 1) + + (func (export "fill") (param i32 i32 i32) + (memory.fill + (local.get 0) + (local.get 1) + (local.get 2))) + + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0))) +) + +;; Basic fill test. +(invoke "fill" (i32.const 1) (i32.const 0xff) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0xff)) +(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 0xff)) +(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 0xff)) +(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 0)) + +;; Fill value is stored as a byte. +(invoke "fill" (i32.const 0) (i32.const 0xbbaa) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0xaa)) +(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0xaa)) + +;; Fill all of memory +(invoke "fill" (i32.const 0) (i32.const 0) (i32.const 0x10000)) + +;; Out-of-bounds writes trap, and nothing is written +(assert_trap (invoke "fill" (i32.const 0xff00) (i32.const 1) (i32.const 0x101)) + "out of bounds memory access") +(assert_return (invoke "load8_u" (i32.const 0xff00)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 0xffff)) (i32.const 0)) + +;; Succeed when writing 0 bytes at the end of the region. +(invoke "fill" (i32.const 0x10000) (i32.const 0) (i32.const 0)) + +;; Writing 0 bytes outside the memory traps. +(assert_trap (invoke "fill" (i32.const 0x10001) (i32.const 0) (i32.const 0)) + "out of bounds memory access") + + +;; memory.copy +(module + (memory (data "\aa\bb\cc\dd")) + + (func (export "copy") (param i32 i32 i32) + (memory.copy + (local.get 0) + (local.get 1) + (local.get 2))) + + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0))) +) + +;; Non-overlapping copy. +(invoke "copy" (i32.const 10) (i32.const 0) (i32.const 4)) + +(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0xaa)) +(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0xbb)) +(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 0xcc)) +(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 0xdd)) +(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 0)) + +;; Overlap, source > dest +(invoke "copy" (i32.const 8) (i32.const 10) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 0xaa)) +(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0xbb)) +(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0xcc)) +(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0xdd)) +(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 0xcc)) +(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 0xdd)) + +;; Overlap, source < dest +(invoke "copy" (i32.const 10) (i32.const 7) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0xaa)) +(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 0xbb)) +(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 0xcc)) +(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 0xdd)) +(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 0xcc)) +(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 0)) + +;; Copy ending at memory limit is ok. +(invoke "copy" (i32.const 0xff00) (i32.const 0) (i32.const 0x100)) +(invoke "copy" (i32.const 0xfe00) (i32.const 0xff00) (i32.const 0x100)) + +;; Succeed when copying 0 bytes at the end of the region. +(invoke "copy" (i32.const 0x10000) (i32.const 0) (i32.const 0)) +(invoke "copy" (i32.const 0) (i32.const 0x10000) (i32.const 0)) + +;; Copying 0 bytes outside the memory traps. +(assert_trap (invoke "copy" (i32.const 0x10001) (i32.const 0) (i32.const 0)) + "out of bounds memory access") +(assert_trap (invoke "copy" (i32.const 0) (i32.const 0x10001) (i32.const 0)) + "out of bounds memory access") + + +;; memory.init +(module + (memory 1) + (data "\aa\bb\cc\dd") + + (func (export "init") (param i32 i32 i32) + (memory.init 0 + (local.get 0) + (local.get 1) + (local.get 2))) + + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0))) +) + +(invoke "init" (i32.const 0) (i32.const 1) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0xbb)) +(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0xcc)) +(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 0)) + +;; Init ending at memory limit and segment limit is ok. +(invoke "init" (i32.const 0xfffc) (i32.const 0) (i32.const 4)) + +;; Out-of-bounds writes trap, and nothing is written. +(assert_trap (invoke "init" (i32.const 0xfffe) (i32.const 0) (i32.const 3)) + "out of bounds memory access") +(assert_return (invoke "load8_u" (i32.const 0xfffe)) (i32.const 0xcc)) +(assert_return (invoke "load8_u" (i32.const 0xffff)) (i32.const 0xdd)) + +;; Succeed when writing 0 bytes at the end of either region. +(invoke "init" (i32.const 0x10000) (i32.const 0) (i32.const 0)) +(invoke "init" (i32.const 0) (i32.const 4) (i32.const 0)) + +;; Writing 0 bytes outside the memory traps. +(assert_trap (invoke "init" (i32.const 0x10001) (i32.const 0) (i32.const 0)) + "out of bounds memory access") +(assert_trap (invoke "init" (i32.const 0) (i32.const 5) (i32.const 0)) + "out of bounds memory access") + +;; data.drop +(module + (memory 1) + (data $p "x") + (data $a (memory 0) (i32.const 0) "x") + + (func (export "drop_passive") (data.drop $p)) + (func (export "init_passive") (param $len i32) + (memory.init $p (i32.const 0) (i32.const 0) (local.get $len))) + + (func (export "drop_active") (data.drop $a)) + (func (export "init_active") (param $len i32) + (memory.init $a (i32.const 0) (i32.const 0) (local.get $len))) +) + +(invoke "init_passive" (i32.const 1)) +(invoke "drop_passive") +(invoke "drop_passive") +(assert_return (invoke "init_passive" (i32.const 0))) +(assert_trap (invoke "init_passive" (i32.const 1)) "out of bounds memory access") +(invoke "init_passive" (i32.const 0)) +(invoke "drop_active") +(assert_return (invoke "init_active" (i32.const 0))) +(assert_trap (invoke "init_active" (i32.const 1)) "out of bounds memory access") +(invoke "init_active" (i32.const 0)) + +;; Test that the data segment index is properly encoded as an unsigned (not +;; signed) LEB. +(module + ;; 65 data segments. 64 is the smallest positive number that is encoded + ;; differently as a signed LEB. + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") + (func (data.drop 64))) + +;; No memory is required for the data.drop instruction. +(module (data "goodbye") (func (data.drop 0))) + +;; table.init +(module + (table 3 funcref) + (elem funcref + (ref.func $zero) (ref.func $one) (ref.func $zero) (ref.func $one)) + + (func $zero (result i32) (i32.const 0)) + (func $one (result i32) (i32.const 1)) + + (func (export "init") (param i32 i32 i32) + (table.init 0 + (local.get 0) + (local.get 1) + (local.get 2))) + + (func (export "call") (param i32) (result i32) + (call_indirect (result i32) + (local.get 0))) +) + +;; Out-of-bounds stores trap, and nothing is written. +(assert_trap (invoke "init" (i32.const 2) (i32.const 0) (i32.const 2)) + "out of bounds table access") +(assert_trap (invoke "call" (i32.const 2)) + "uninitialized element 2") + +(invoke "init" (i32.const 0) (i32.const 1) (i32.const 2)) +(assert_return (invoke "call" (i32.const 0)) (i32.const 1)) +(assert_return (invoke "call" (i32.const 1)) (i32.const 0)) +(assert_trap (invoke "call" (i32.const 2)) "uninitialized element") + +;; Init ending at table limit and segment limit is ok. +(invoke "init" (i32.const 1) (i32.const 2) (i32.const 2)) + +;; Succeed when storing 0 elements at the end of either region. +(invoke "init" (i32.const 3) (i32.const 0) (i32.const 0)) +(invoke "init" (i32.const 0) (i32.const 4) (i32.const 0)) + +;; Writing 0 elements outside the table traps. +(assert_trap (invoke "init" (i32.const 4) (i32.const 0) (i32.const 0)) + "out of bounds table access") +(assert_trap (invoke "init" (i32.const 0) (i32.const 5) (i32.const 0)) + "out of bounds table access") + + +;; elem.drop +(module + (table 1 funcref) + (func $f) + (elem $p funcref (ref.func $f)) + (elem $a (table 0) (i32.const 0) func $f) + + (func (export "drop_passive") (elem.drop $p)) + (func (export "init_passive") (param $len i32) + (table.init $p (i32.const 0) (i32.const 0) (local.get $len)) + ) + + (func (export "drop_active") (elem.drop $a)) + (func (export "init_active") (param $len i32) + (table.init $a (i32.const 0) (i32.const 0) (local.get $len)) + ) +) + +(invoke "init_passive" (i32.const 1)) +(invoke "drop_passive") +(invoke "drop_passive") +(assert_return (invoke "init_passive" (i32.const 0))) +(assert_trap (invoke "init_passive" (i32.const 1)) "out of bounds table access") +(invoke "init_passive" (i32.const 0)) +(invoke "drop_active") +(assert_return (invoke "init_active" (i32.const 0))) +(assert_trap (invoke "init_active" (i32.const 1)) "out of bounds table access") +(invoke "init_active" (i32.const 0)) + +;; Test that the elem segment index is properly encoded as an unsigned (not +;; signed) LEB. +(module + ;; 65 elem segments. 64 is the smallest positive number that is encoded + ;; differently as a signed LEB. + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) + (func (elem.drop 64))) + +;; No table is required for the elem.drop instruction. +(module (elem funcref (ref.func 0)) (func (elem.drop 0))) + +;; table.copy +(module + (table 10 funcref) + (elem (i32.const 0) $zero $one $two) + (func $zero (result i32) (i32.const 0)) + (func $one (result i32) (i32.const 1)) + (func $two (result i32) (i32.const 2)) + + (func (export "copy") (param i32 i32 i32) + (table.copy + (local.get 0) + (local.get 1) + (local.get 2))) + + (func (export "call") (param i32) (result i32) + (call_indirect (result i32) + (local.get 0))) +) + +;; Non-overlapping copy. +(invoke "copy" (i32.const 3) (i32.const 0) (i32.const 3)) +;; Now [$zero, $one, $two, $zero, $one, $two, ...] +(assert_return (invoke "call" (i32.const 3)) (i32.const 0)) +(assert_return (invoke "call" (i32.const 4)) (i32.const 1)) +(assert_return (invoke "call" (i32.const 5)) (i32.const 2)) + +;; Overlap, source > dest +(invoke "copy" (i32.const 0) (i32.const 1) (i32.const 3)) +;; Now [$one, $two, $zero, $zero, $one, $two, ...] +(assert_return (invoke "call" (i32.const 0)) (i32.const 1)) +(assert_return (invoke "call" (i32.const 1)) (i32.const 2)) +(assert_return (invoke "call" (i32.const 2)) (i32.const 0)) + +;; Overlap, source < dest +(invoke "copy" (i32.const 2) (i32.const 0) (i32.const 3)) +;; Now [$one, $two, $one, $two, $zero, $two, ...] +(assert_return (invoke "call" (i32.const 2)) (i32.const 1)) +(assert_return (invoke "call" (i32.const 3)) (i32.const 2)) +(assert_return (invoke "call" (i32.const 4)) (i32.const 0)) + +;; Copy ending at table limit is ok. +(invoke "copy" (i32.const 6) (i32.const 8) (i32.const 2)) +(invoke "copy" (i32.const 8) (i32.const 6) (i32.const 2)) + +;; Succeed when copying 0 elements at the end of the region. +(invoke "copy" (i32.const 10) (i32.const 0) (i32.const 0)) +(invoke "copy" (i32.const 0) (i32.const 10) (i32.const 0)) + +;; Fail on out-of-bounds when copying 0 elements outside of table. +(assert_trap (invoke "copy" (i32.const 11) (i32.const 0) (i32.const 0)) + "out of bounds table access") +(assert_trap (invoke "copy" (i32.const 0) (i32.const 11) (i32.const 0)) + "out of bounds table access") diff --git a/test/core/call_indirect.wast b/test/core/call_indirect.wast index 224e3bef09..1ecd9b7baf 100644 --- a/test/core/call_indirect.wast +++ b/test/core/call_indirect.wast @@ -617,6 +617,52 @@ (assert_return (invoke "as-compare-right") (i32.const 1)) (assert_return (invoke "as-convert-operand") (i64.const 1)) + +;; Multiple tables + +(module + (type $ii-i (func (param i32 i32) (result i32))) + + (table $t1 funcref (elem $f $g)) + (table $t2 funcref (elem $h $i $j)) + (table $t3 4 funcref) + (elem (table $t3) (i32.const 0) func $g $h) + (elem (table $t3) (i32.const 3) func $z) + + (func $f (type $ii-i) (i32.add (local.get 0) (local.get 1))) + (func $g (type $ii-i) (i32.sub (local.get 0) (local.get 1))) + (func $h (type $ii-i) (i32.mul (local.get 0) (local.get 1))) + (func $i (type $ii-i) (i32.div_u (local.get 0) (local.get 1))) + (func $j (type $ii-i) (i32.rem_u (local.get 0) (local.get 1))) + (func $z) + + (func (export "call-1") (param i32 i32 i32) (result i32) + (call_indirect $t1 (type $ii-i) (local.get 0) (local.get 1) (local.get 2)) + ) + (func (export "call-2") (param i32 i32 i32) (result i32) + (call_indirect $t2 (type $ii-i) (local.get 0) (local.get 1) (local.get 2)) + ) + (func (export "call-3") (param i32 i32 i32) (result i32) + (call_indirect $t3 (type $ii-i) (local.get 0) (local.get 1) (local.get 2)) + ) +) + +(assert_return (invoke "call-1" (i32.const 2) (i32.const 3) (i32.const 0)) (i32.const 5)) +(assert_return (invoke "call-1" (i32.const 2) (i32.const 3) (i32.const 1)) (i32.const -1)) +(assert_trap (invoke "call-1" (i32.const 2) (i32.const 3) (i32.const 2)) "undefined element") + +(assert_return (invoke "call-2" (i32.const 2) (i32.const 3) (i32.const 0)) (i32.const 6)) +(assert_return (invoke "call-2" (i32.const 2) (i32.const 3) (i32.const 1)) (i32.const 0)) +(assert_return (invoke "call-2" (i32.const 2) (i32.const 3) (i32.const 2)) (i32.const 2)) +(assert_trap (invoke "call-2" (i32.const 2) (i32.const 3) (i32.const 3)) "undefined element") + +(assert_return (invoke "call-3" (i32.const 2) (i32.const 3) (i32.const 0)) (i32.const -1)) +(assert_return (invoke "call-3" (i32.const 2) (i32.const 3) (i32.const 1)) (i32.const 6)) +(assert_trap (invoke "call-3" (i32.const 2) (i32.const 3) (i32.const 2)) "uninitialized element") +(assert_trap (invoke "call-3" (i32.const 2) (i32.const 3) (i32.const 3)) "indirect call type mismatch") +(assert_trap (invoke "call-3" (i32.const 2) (i32.const 3) (i32.const 4)) "undefined element") + + ;; Invalid syntax (assert_malformed diff --git a/test/core/custom.wast b/test/core/custom.wast index 0877a9ad79..b2394f5e3b 100644 --- a/test/core/custom.wast +++ b/test/core/custom.wast @@ -118,3 +118,13 @@ ) "length out of bounds" ) + +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\05\03\01\00\01" ;; memory section + "\0c\01\02" ;; data count section (2 segments) + "\0b\06\01\00\41\00\0b\00" ;; data section (1 segment) + ) + "data count and data section have inconsistent lengths" +) diff --git a/test/core/data.wast b/test/core/data.wast index e840a94674..f7d1f09bca 100644 --- a/test/core/data.wast +++ b/test/core/data.wast @@ -8,14 +8,26 @@ (data (i32.const 1) "a" "" "bcd") (data (offset (i32.const 0))) (data (offset (i32.const 0)) "" "a" "bc" "") - (data 0 (i32.const 0)) - (data 0x0 (i32.const 1) "a" "" "bcd") - (data 0x000 (offset (i32.const 0))) - (data 0 (offset (i32.const 0)) "" "a" "bc" "") - (data $m (i32.const 0)) - (data $m (i32.const 1) "a" "" "bcd") - (data $m (offset (i32.const 0))) - (data $m (offset (i32.const 0)) "" "a" "bc" "") + (data (memory 0) (i32.const 0)) + (data (memory 0x0) (i32.const 1) "a" "" "bcd") + (data (memory 0x000) (offset (i32.const 0))) + (data (memory 0) (offset (i32.const 0)) "" "a" "bc" "") + (data (memory $m) (i32.const 0)) + (data (memory $m) (i32.const 1) "a" "" "bcd") + (data (memory $m) (offset (i32.const 0))) + (data (memory $m) (offset (i32.const 0)) "" "a" "bc" "") + (data $d1 (i32.const 0)) + (data $d2 (i32.const 1) "a" "" "bcd") + (data $d3 (offset (i32.const 0))) + (data $d4 (offset (i32.const 0)) "" "a" "bc" "") + (data $d5 (memory 0) (i32.const 0)) + (data $d6 (memory 0x0) (i32.const 1) "a" "" "bcd") + (data $d7 (memory 0x000) (offset (i32.const 0))) + (data $d8 (memory 0) (offset (i32.const 0)) "" "a" "bc" "") + (data $d9 (memory $m) (i32.const 0)) + (data $d10 (memory $m) (i32.const 1) "a" "" "bcd") + (data $d11 (memory $m) (offset (i32.const 0))) + (data $d12 (memory $m) (offset (i32.const 0)) "" "a" "bc" "") ) ;; Basic use @@ -158,44 +170,42 @@ ;; Invalid bounds for data -(assert_unlinkable +(assert_trap (module (memory 0) (data (i32.const 0) "a") ) - "data segment does not fit" + "out of bounds memory access" ) -(assert_unlinkable +(assert_trap (module (memory 0 0) (data (i32.const 0) "a") ) - "data segment does not fit" + "out of bounds memory access" ) -(assert_unlinkable +(assert_trap (module (memory 0 1) (data (i32.const 0) "a") ) - "data segment does not fit" + "out of bounds memory access" ) - -(assert_unlinkable +(assert_trap (module (memory 0) (data (i32.const 1)) ) - "data segment does not fit" + "out of bounds memory access" ) - -(assert_unlinkable +(assert_trap (module (memory 0 1) (data (i32.const 1)) ) - "data segment does not fit" + "out of bounds memory access" ) ;; This seems to cause a time-out on Travis. @@ -204,77 +214,77 @@ (memory 0x10000) (data (i32.const 0xffffffff) "ab") ) - "" ;; either out of memory or segment does not fit + "" ;; either out of memory or out of bounds ;) -(assert_unlinkable +(assert_trap (module (global (import "spectest" "global_i32") i32) (memory 0) (data (global.get 0) "a") ) - "data segment does not fit" + "out of bounds memory access" ) -(assert_unlinkable +(assert_trap (module (memory 1 2) (data (i32.const 0x1_0000) "a") ) - "data segment does not fit" + "out of bounds memory access" ) -(assert_unlinkable +(assert_trap (module (import "spectest" "memory" (memory 1)) (data (i32.const 0x1_0000) "a") ) - "data segment does not fit" + "out of bounds memory access" ) -(assert_unlinkable +(assert_trap (module (memory 2) (data (i32.const 0x2_0000) "a") ) - "data segment does not fit" + "out of bounds memory access" ) -(assert_unlinkable +(assert_trap (module (memory 2 3) (data (i32.const 0x2_0000) "a") ) - "data segment does not fit" + "out of bounds memory access" ) -(assert_unlinkable +(assert_trap (module (memory 1) (data (i32.const -1) "a") ) - "data segment does not fit" + "out of bounds memory access" ) -(assert_unlinkable +(assert_trap (module (import "spectest" "memory" (memory 1)) (data (i32.const -1) "a") ) - "data segment does not fit" + "out of bounds memory access" ) -(assert_unlinkable +(assert_trap (module (memory 2) (data (i32.const -100) "a") ) - "data segment does not fit" + "out of bounds memory access" ) -(assert_unlinkable +(assert_trap (module (import "spectest" "memory" (memory 1)) (data (i32.const -100) "a") ) - "data segment does not fit" + "out of bounds memory access" ) ;; Data without memory @@ -292,19 +302,30 @@ "\00asm" "\01\00\00\00" "\05\03\01" ;; memory section "\00\00" ;; memory 0 - "\0b\06\01" ;; data section - "\01\41\00\0b" ;; data segment 0 for memory 1 + "\0b\07\01" ;; data section + "\02\01\41\00\0b" ;; active data segment 0 for memory 1 "\00" ;; empty vec(byte) ) "unknown memory 1" ) -;; Data segment with memory index 1 (no memory section) +;; Data segment with memory index 0 (no memory section) (assert_invalid (module binary "\00asm" "\01\00\00\00" "\0b\06\01" ;; data section - "\01\41\00\0b" ;; data segment 0 for memory 1 + "\00\41\00\0b" ;; active data segment 0 for memory 0 + "\00" ;; empty vec(byte) + ) + "unknown memory 0" +) + +;; Data segment with memory index 1 (no memory section) +(assert_invalid + (module binary + "\00asm" "\01\00\00\00" + "\0b\07\01" ;; data section + "\02\01\41\00\0b" ;; active data segment 0 for memory 1 "\00" ;; empty vec(byte) ) "unknown memory 1" @@ -317,7 +338,8 @@ "\00asm" "\01\00\00\00" "\05\03\01" ;; memory section "\00\00" ;; memory 0 - "\0b\44\01" ;; data section + "\0b\45\01" ;; data section + "\02" ;; active segment "\01" ;; memory index "\41\00\0b" ;; offset constant expression "\3e" ;; vec(byte) length @@ -336,7 +358,8 @@ (assert_invalid (module binary "\00asm" "\01\00\00\00" - "\0b\44\01" ;; data section + "\0b\45\01" ;; data section + "\02" ;; active segment "\01" ;; memory index "\41\00\0b" ;; offset constant expression "\3e" ;; vec(byte) length @@ -455,4 +478,4 @@ (data (global.get 0)) ) "constant expression required" -) \ No newline at end of file +) diff --git a/test/core/elem.wast b/test/core/elem.wast index ce8ec1f60f..19b5fe9205 100644 --- a/test/core/elem.wast +++ b/test/core/elem.wast @@ -4,20 +4,86 @@ (module (table $t 10 funcref) (func $f) - (elem (i32.const 0)) - (elem (i32.const 0) $f $f) + (func $g) + + ;; Passive + (elem funcref) + (elem funcref (ref.func $f) (item ref.func $f) (item (ref.null func)) (ref.func $g)) + (elem func) + (elem func $f $f $g $g) + + (elem $p1 funcref) + (elem $p2 funcref (ref.func $f) (ref.func $f) (ref.null func) (ref.func $g)) + (elem $p3 func) + (elem $p4 func $f $f $g $g) + + ;; Active + (elem (table $t) (i32.const 0) funcref) + (elem (table $t) (i32.const 0) funcref (ref.func $f) (ref.null func)) + (elem (table $t) (i32.const 0) func) + (elem (table $t) (i32.const 0) func $f $g) + (elem (table $t) (offset (i32.const 0)) funcref) + (elem (table $t) (offset (i32.const 0)) func $f $g) + (elem (table 0) (i32.const 0) func) + (elem (table 0x0) (i32.const 0) func $f $f) + (elem (table 0x000) (offset (i32.const 0)) func) + (elem (table 0) (offset (i32.const 0)) func $f $f) + (elem (table $t) (i32.const 0) func) + (elem (table $t) (i32.const 0) func $f $f) + (elem (table $t) (offset (i32.const 0)) func) + (elem (table $t) (offset (i32.const 0)) func $f $f) (elem (offset (i32.const 0))) + (elem (offset (i32.const 0)) funcref (ref.func $f) (ref.null func)) + (elem (offset (i32.const 0)) func $f $f) (elem (offset (i32.const 0)) $f $f) - (elem 0 (i32.const 0)) - (elem 0x0 (i32.const 0) $f $f) - (elem 0x000 (offset (i32.const 0))) - (elem 0 (offset (i32.const 0)) $f $f) - (elem $t (i32.const 0)) - (elem $t (i32.const 0) $f $f) - (elem $t (offset (i32.const 0))) - (elem $t (offset (i32.const 0)) $f $f) + (elem (i32.const 0)) + (elem (i32.const 0) funcref (ref.func $f) (ref.null func)) + (elem (i32.const 0) func $f $f) + (elem (i32.const 0) $f $f) + + (elem $a1 (table $t) (i32.const 0) funcref) + (elem $a2 (table $t) (i32.const 0) funcref (ref.func $f) (ref.null func)) + (elem $a3 (table $t) (i32.const 0) func) + (elem $a4 (table $t) (i32.const 0) func $f $g) + (elem $a9 (table $t) (offset (i32.const 0)) funcref) + (elem $a10 (table $t) (offset (i32.const 0)) func $f $g) + (elem $a11 (table 0) (i32.const 0) func) + (elem $a12 (table 0x0) (i32.const 0) func $f $f) + (elem $a13 (table 0x000) (offset (i32.const 0)) func) + (elem $a14 (table 0) (offset (i32.const 0)) func $f $f) + (elem $a15 (table $t) (i32.const 0) func) + (elem $a16 (table $t) (i32.const 0) func $f $f) + (elem $a17 (table $t) (offset (i32.const 0)) func) + (elem $a18 (table $t) (offset (i32.const 0)) func $f $f) + (elem $a19 (offset (i32.const 0))) + (elem $a20 (offset (i32.const 0)) funcref (ref.func $f) (ref.null func)) + (elem $a21 (offset (i32.const 0)) func $f $f) + (elem $a22 (offset (i32.const 0)) $f $f) + (elem $a23 (i32.const 0)) + (elem $a24 (i32.const 0) funcref (ref.func $f) (ref.null func)) + (elem $a25 (i32.const 0) func $f $f) + (elem $a26 (i32.const 0) $f $f) + + ;; Declarative + (elem declare funcref) + (elem declare funcref (ref.func $f) (ref.func $f) (ref.null func) (ref.func $g)) + (elem declare func) + (elem declare func $f $f $g $g) + + (elem $d1 declare funcref) + (elem $d2 declare funcref (ref.func $f) (ref.func $f) (ref.null func) (ref.func $g)) + (elem $d3 declare func) + (elem $d4 declare func $f $f $g $g) ) +(module + (func $f) + (func $g) + + (table $t funcref (elem (ref.func $f) (ref.null func) (ref.func $g))) +) + + ;; Basic use (module @@ -139,108 +205,129 @@ ;; Invalid bounds for elements -(assert_unlinkable +(assert_trap (module (table 0 funcref) (func $f) (elem (i32.const 0) $f) ) - "elements segment does not fit" + "out of bounds table access" ) -(assert_unlinkable +(assert_trap (module (table 0 0 funcref) (func $f) (elem (i32.const 0) $f) ) - "elements segment does not fit" + "out of bounds table access" ) -(assert_unlinkable +(assert_trap (module (table 0 1 funcref) (func $f) (elem (i32.const 0) $f) ) - "elements segment does not fit" + "out of bounds table access" ) -(assert_unlinkable +(assert_trap (module (table 0 funcref) (elem (i32.const 1)) ) - "elements segment does not fit" + "out of bounds table access" ) - -(assert_unlinkable +(assert_trap (module (table 10 funcref) (func $f) (elem (i32.const 10) $f) ) - "elements segment does not fit" + "out of bounds table access" ) -(assert_unlinkable +(assert_trap (module (import "spectest" "table" (table 10 funcref)) (func $f) (elem (i32.const 10) $f) ) - "elements segment does not fit" + "out of bounds table access" ) -(assert_unlinkable +(assert_trap (module (table 10 20 funcref) (func $f) (elem (i32.const 10) $f) ) - "elements segment does not fit" + "out of bounds table access" ) -(assert_unlinkable +(assert_trap (module (import "spectest" "table" (table 10 funcref)) (func $f) (elem (i32.const 10) $f) ) - "elements segment does not fit" + "out of bounds table access" ) -(assert_unlinkable +(assert_trap (module (table 10 funcref) (func $f) (elem (i32.const -1) $f) ) - "elements segment does not fit" + "out of bounds table access" ) -(assert_unlinkable +(assert_trap (module (import "spectest" "table" (table 10 funcref)) (func $f) (elem (i32.const -1) $f) ) - "elements segment does not fit" + "out of bounds table access" ) -(assert_unlinkable +(assert_trap (module (table 10 funcref) (func $f) (elem (i32.const -10) $f) ) - "elements segment does not fit" + "out of bounds table access" ) -(assert_unlinkable +(assert_trap (module (import "spectest" "table" (table 10 funcref)) (func $f) (elem (i32.const -10) $f) ) - "elements segment does not fit" + "out of bounds table access" +) + +;; Implicitly dropped elements + +(module + (table 10 funcref) + (elem $e (i32.const 0) func $f) + (func $f) + (func (export "init") + (table.init $e (i32.const 0) (i32.const 0) (i32.const 1)) + ) +) +(assert_trap (invoke "init") "out of bounds table access") + +(module + (table 10 funcref) + (elem $e declare func $f) + (func $f) + (func (export "init") + (table.init $e (i32.const 0) (i32.const 0) (i32.const 1)) + ) ) +(assert_trap (invoke "init") "out of bounds table access") ;; Element without table diff --git a/test/core/exports.wast b/test/core/exports.wast index ba7f7a7ca8..80d3ae0742 100644 --- a/test/core/exports.wast +++ b/test/core/exports.wast @@ -130,8 +130,7 @@ (module (table 0 funcref) (export "a" (table 0))) (module (table 0 funcref) (export "a" (table 0)) (export "b" (table 0))) -;; No multiple tables yet. -;; (module (table 0 funcref) (table 0 funcref) (export "a" (table 0)) (export "b" (table 1))) +(module (table 0 funcref) (table 0 funcref) (export "a" (table 0)) (export "b" (table 1))) (module (table (export "a") 0 funcref)) (module (table (export "a") 0 1 funcref)) @@ -164,11 +163,10 @@ (module (table 0 funcref) (export "a" (table 0)) (export "a" (table 0))) "duplicate export name" ) -;; No multiple tables yet. -;; (assert_invalid -;; (module (table 0 funcref) (table 0 funcref) (export "a" (table 0)) (export "a" (table 1))) -;; "duplicate export name" -;; ) +(assert_invalid + (module (table 0 funcref) (table 0 funcref) (export "a" (table 0)) (export "a" (table 1))) + "duplicate export name" +) (assert_invalid (module (table 0 funcref) (func) (export "a" (table 0)) (export "a" (func 0))) "duplicate export name" diff --git a/test/core/global.wast b/test/core/global.wast index f3808174e7..9fa5e22311 100644 --- a/test/core/global.wast +++ b/test/core/global.wast @@ -17,14 +17,21 @@ (global $z1 i32 (global.get 0)) (global $z2 i64 (global.get 1)) + (global $r externref (ref.null extern)) + (global $mr (mut externref) (ref.null extern)) + (global funcref (ref.null func)) + (func (export "get-a") (result i32) (global.get $a)) (func (export "get-b") (result i64) (global.get $b)) + (func (export "get-r") (result externref) (global.get $r)) + (func (export "get-mr") (result externref) (global.get $mr)) (func (export "get-x") (result i32) (global.get $x)) (func (export "get-y") (result i64) (global.get $y)) (func (export "get-z1") (result i32) (global.get $z1)) (func (export "get-z2") (result i64) (global.get $z2)) (func (export "set-x") (param i32) (global.set $x (local.get 0))) (func (export "set-y") (param i64) (global.set $y (local.get 0))) + (func (export "set-mr") (param externref) (global.set $mr (local.get 0))) (func (export "get-3") (result f32) (global.get 3)) (func (export "get-4") (result f64) (global.get 4)) @@ -188,6 +195,8 @@ (assert_return (invoke "get-a") (i32.const -2)) (assert_return (invoke "get-b") (i64.const -5)) +(assert_return (invoke "get-r") (ref.null extern)) +(assert_return (invoke "get-mr") (ref.null extern)) (assert_return (invoke "get-x") (i32.const -12)) (assert_return (invoke "get-y") (i64.const -15)) (assert_return (invoke "get-z1") (i32.const 666)) @@ -200,13 +209,24 @@ (assert_return (invoke "set-x" (i32.const 6))) (assert_return (invoke "set-y" (i64.const 7))) + +(assert_return (invoke "set-7" (f32.const 8))) +(assert_return (invoke "set-8" (f64.const 9))) + +(assert_return (invoke "get-x") (i32.const 6)) +(assert_return (invoke "get-y") (i64.const 7)) +(assert_return (invoke "get-7") (f32.const 8)) +(assert_return (invoke "get-8") (f64.const 9)) + (assert_return (invoke "set-7" (f32.const 8))) (assert_return (invoke "set-8" (f64.const 9))) +(assert_return (invoke "set-mr" (ref.extern 10))) (assert_return (invoke "get-x") (i32.const 6)) (assert_return (invoke "get-y") (i64.const 7)) (assert_return (invoke "get-7") (f32.const 8)) (assert_return (invoke "get-8") (f64.const 9)) +(assert_return (invoke "get-mr") (ref.extern 10)) (assert_return (invoke "as-select-first") (i32.const 6)) (assert_return (invoke "as-select-mid") (i32.const 2)) @@ -308,6 +328,11 @@ "type mismatch" ) +(assert_invalid + (module (global (import "" "") externref) (global funcref (global.get 0))) + "type mismatch" +) + (assert_invalid (module (global (import "test" "global-i32") i32) (global i32 (global.get 0) (global.get 0))) "type mismatch" diff --git a/test/core/imports.wast b/test/core/imports.wast index 6cfca2fc62..147f4c3357 100644 --- a/test/core/imports.wast +++ b/test/core/imports.wast @@ -12,8 +12,9 @@ (global (export "global-f32") f32 (f32.const 44)) (global (export "global-mut-i64") (mut i64) (i64.const 66)) (table (export "table-10-inf") 10 funcref) - ;; (table (export "table-10-20") 10 20 funcref) + (table (export "table-10-20") 10 20 funcref) (memory (export "memory-2-inf") 2) + ;; Multiple memories are not yet supported ;; (memory (export "memory-2-4") 2 4) ) @@ -341,11 +342,11 @@ (module (type (func (result i32))) - (import "spectest" "table" (table 10 20 funcref)) - (elem 0 (i32.const 1) $f $g) + (import "spectest" "table" (table $tab 10 20 funcref)) + (elem (table $tab) (i32.const 1) func $f $g) (func (export "call") (param i32) (result i32) - (call_indirect (type 0) (local.get 0)) + (call_indirect $tab (type 0) (local.get 0)) ) (func $f (result i32) (i32.const 11)) (func $g (result i32) (i32.const 22)) @@ -360,11 +361,11 @@ (module (type (func (result i32))) - (table (import "spectest" "table") 10 20 funcref) - (elem 0 (i32.const 1) $f $g) + (table $tab (import "spectest" "table") 10 20 funcref) + (elem (table $tab) (i32.const 1) func $f $g) (func (export "call") (param i32) (result i32) - (call_indirect (type 0) (local.get 0)) + (call_indirect $tab (type 0) (local.get 0)) ) (func $f (result i32) (i32.const 11)) (func $g (result i32) (i32.const 22)) @@ -377,22 +378,25 @@ (assert_trap (invoke "call" (i32.const 100)) "undefined element") -(assert_invalid - (module (import "" "" (table 10 funcref)) (import "" "" (table 10 funcref))) - "multiple tables" -) -(assert_invalid - (module (import "" "" (table 10 funcref)) (table 10 funcref)) - "multiple tables" -) -(assert_invalid - (module (table 10 funcref) (table 10 funcref)) - "multiple tables" +(module + (import "spectest" "table" (table 0 funcref)) + (import "spectest" "table" (table 0 funcref)) + (table 10 funcref) + (table 10 funcref) ) (module (import "test" "table-10-inf" (table 10 funcref))) (module (import "test" "table-10-inf" (table 5 funcref))) (module (import "test" "table-10-inf" (table 0 funcref))) +(module (import "test" "table-10-20" (table 10 funcref))) +(module (import "test" "table-10-20" (table 5 funcref))) +(module (import "test" "table-10-20" (table 0 funcref))) +(module (import "test" "table-10-20" (table 10 20 funcref))) +(module (import "test" "table-10-20" (table 5 20 funcref))) +(module (import "test" "table-10-20" (table 0 20 funcref))) +(module (import "test" "table-10-20" (table 10 25 funcref))) +(module (import "test" "table-10-20" (table 5 25 funcref))) +(module (import "test" "table-10-20" (table 0 25 funcref))) (module (import "spectest" "table" (table 10 funcref))) (module (import "spectest" "table" (table 5 funcref))) (module (import "spectest" "table" (table 0 funcref))) @@ -419,6 +423,14 @@ (module (import "test" "table-10-inf" (table 10 20 funcref))) "incompatible import type" ) +(assert_unlinkable + (module (import "test" "table-10-20" (table 12 20 funcref))) + "incompatible import type" +) +(assert_unlinkable + (module (import "test" "table-10-20" (table 10 18 funcref))) + "incompatible import type" +) (assert_unlinkable (module (import "spectest" "table" (table 12 funcref))) "incompatible import type" @@ -451,7 +463,7 @@ (module (import "spectest" "memory" (memory 1 2)) - (data 0 (i32.const 10) "\10") + (data (memory 0) (i32.const 10) "\10") (func (export "load") (param i32) (result i32) (i32.load (local.get 0))) ) @@ -463,7 +475,7 @@ (module (memory (import "spectest" "memory") 1 2) - (data 0 (i32.const 10) "\10") + (data (memory 0) (i32.const 10) "\10") (func (export "load") (param i32) (result i32) (i32.load (local.get 0))) ) diff --git a/test/core/linking.wast b/test/core/linking.wast index 6868e8b709..994e0f49d0 100644 --- a/test/core/linking.wast +++ b/test/core/linking.wast @@ -92,6 +92,43 @@ "incompatible import type" ) + +(module $Mref_ex + (global (export "g-const-func") funcref (ref.null func)) + (global (export "g-var-func") (mut funcref) (ref.null func)) + (global (export "g-const-extern") externref (ref.null extern)) + (global (export "g-var-extern") (mut externref) (ref.null extern)) +) +(register "Mref_ex" $Mref_ex) + +(module $Mref_im + (global (import "Mref_ex" "g-const-func") funcref) + (global (import "Mref_ex" "g-const-extern") externref) + + (global (import "Mref_ex" "g-var-func") (mut funcref)) + (global (import "Mref_ex" "g-var-extern") (mut externref)) +) + +(assert_unlinkable + (module (global (import "Mref_ex" "g-const-extern") funcref)) + "incompatible import type" +) +(assert_unlinkable + (module (global (import "Mref_ex" "g-const-func") externref)) + "incompatible import type" +) + + +(assert_unlinkable + (module (global (import "Mref_ex" "g-var-func") (mut externref))) + "incompatible import type" +) +(assert_unlinkable + (module (global (import "Mref_ex" "g-var-extern") (mut funcref))) + "incompatible import type" +) + + ;; Tables (module $Mt @@ -133,23 +170,23 @@ (assert_return (invoke $Nt "call" (i32.const 2)) (i32.const 5)) (assert_return (invoke $Nt "call Mt.call" (i32.const 2)) (i32.const 4)) -(assert_trap (invoke $Mt "call" (i32.const 1)) "uninitialized") -(assert_trap (invoke $Nt "Mt.call" (i32.const 1)) "uninitialized") +(assert_trap (invoke $Mt "call" (i32.const 1)) "uninitialized element") +(assert_trap (invoke $Nt "Mt.call" (i32.const 1)) "uninitialized element") (assert_return (invoke $Nt "call" (i32.const 1)) (i32.const 5)) -(assert_trap (invoke $Nt "call Mt.call" (i32.const 1)) "uninitialized") +(assert_trap (invoke $Nt "call Mt.call" (i32.const 1)) "uninitialized element") -(assert_trap (invoke $Mt "call" (i32.const 0)) "uninitialized") -(assert_trap (invoke $Nt "Mt.call" (i32.const 0)) "uninitialized") +(assert_trap (invoke $Mt "call" (i32.const 0)) "uninitialized element") +(assert_trap (invoke $Nt "Mt.call" (i32.const 0)) "uninitialized element") (assert_return (invoke $Nt "call" (i32.const 0)) (i32.const 5)) -(assert_trap (invoke $Nt "call Mt.call" (i32.const 0)) "uninitialized") +(assert_trap (invoke $Nt "call Mt.call" (i32.const 0)) "uninitialized element") -(assert_trap (invoke $Mt "call" (i32.const 20)) "undefined") -(assert_trap (invoke $Nt "Mt.call" (i32.const 20)) "undefined") -(assert_trap (invoke $Nt "call" (i32.const 7)) "undefined") -(assert_trap (invoke $Nt "call Mt.call" (i32.const 20)) "undefined") +(assert_trap (invoke $Mt "call" (i32.const 20)) "undefined element") +(assert_trap (invoke $Nt "Mt.call" (i32.const 20)) "undefined element") +(assert_trap (invoke $Nt "call" (i32.const 7)) "undefined element") +(assert_trap (invoke $Nt "call Mt.call" (i32.const 20)) "undefined element") (assert_return (invoke $Nt "call" (i32.const 3)) (i32.const -4)) -(assert_trap (invoke $Nt "call" (i32.const 4)) "indirect call") +(assert_trap (invoke $Nt "call" (i32.const 4)) "indirect call type mismatch") (module $Ot (type (func (result i32))) @@ -181,13 +218,13 @@ (assert_return (invoke $Nt "call Mt.call" (i32.const 1)) (i32.const 6)) (assert_return (invoke $Ot "call" (i32.const 1)) (i32.const 6)) -(assert_trap (invoke $Mt "call" (i32.const 0)) "uninitialized") -(assert_trap (invoke $Nt "Mt.call" (i32.const 0)) "uninitialized") +(assert_trap (invoke $Mt "call" (i32.const 0)) "uninitialized element") +(assert_trap (invoke $Nt "Mt.call" (i32.const 0)) "uninitialized element") (assert_return (invoke $Nt "call" (i32.const 0)) (i32.const 5)) -(assert_trap (invoke $Nt "call Mt.call" (i32.const 0)) "uninitialized") -(assert_trap (invoke $Ot "call" (i32.const 0)) "uninitialized") +(assert_trap (invoke $Nt "call Mt.call" (i32.const 0)) "uninitialized element") +(assert_trap (invoke $Ot "call" (i32.const 0)) "uninitialized element") -(assert_trap (invoke $Ot "call" (i32.const 20)) "undefined") +(assert_trap (invoke $Ot "call" (i32.const 20)) "undefined element") (module (table (import "Mt" "tab") 0 funcref) @@ -203,13 +240,13 @@ ) (assert_return (get $G2 "g") (i32.const 5)) -(assert_unlinkable +(assert_trap (module (table (import "Mt" "tab") 0 funcref) (elem (i32.const 10) $f) (func $f) ) - "elements segment does not fit" + "out of bounds table access" ) (assert_unlinkable @@ -222,30 +259,54 @@ ) "unknown import" ) -(assert_trap (invoke $Mt "call" (i32.const 7)) "uninitialized") +(assert_trap (invoke $Mt "call" (i32.const 7)) "uninitialized element") -(assert_unlinkable +;; Unlike in the v1 spec, active element segments stored before an +;; out-of-bounds access persist after the instantiation failure. +(assert_trap (module (table (import "Mt" "tab") 10 funcref) (func $f (result i32) (i32.const 0)) (elem (i32.const 7) $f) - (elem (i32.const 12) $f) ;; out of bounds + (elem (i32.const 8) $f $f $f $f $f) ;; (partially) out of bounds ) - "elements segment does not fit" + "out of bounds table access" ) -(assert_trap (invoke $Mt "call" (i32.const 7)) "uninitialized") +(assert_return (invoke $Mt "call" (i32.const 7)) (i32.const 0)) +(assert_trap (invoke $Mt "call" (i32.const 8)) "uninitialized element") -(assert_unlinkable +(assert_trap (module (table (import "Mt" "tab") 10 funcref) (func $f (result i32) (i32.const 0)) (elem (i32.const 7) $f) (memory 1) - (data (i32.const 0x10000) "d") ;; out of bounds + (data (i32.const 0x10000) "d") ;; out of bounds ) - "data segment does not fit" + "out of bounds memory access" +) +(assert_return (invoke $Mt "call" (i32.const 7)) (i32.const 0)) + + +(module $Mtable_ex + (table $t1 (export "t-func") 1 funcref) + (table $t2 (export "t-extern") 1 externref) +) +(register "Mtable_ex" $Mtable_ex) + +(module + (table (import "Mtable_ex" "t-func") 1 funcref) + (table (import "Mtable_ex" "t-extern") 1 externref) +) + +(assert_unlinkable + (module (table (import "Mtable_ex" "t-func") 1 externref)) + "incompatible import type" +) +(assert_unlinkable + (module (table (import "Mtable_ex" "t-extern") 1 funcref)) + "incompatible import type" ) -(assert_trap (invoke $Mt "call" (i32.const 7)) "uninitialized") ;; Memories @@ -295,12 +356,12 @@ (data (i32.const 0xffff) "a") ) -(assert_unlinkable +(assert_trap (module (memory (import "Mm" "mem") 0) (data (i32.const 0x10000) "a") ) - "data segment does not fit" + "out of bounds memory access" ) (module $Pm @@ -331,27 +392,31 @@ ) (assert_return (invoke $Mm "load" (i32.const 0)) (i32.const 0)) -(assert_unlinkable +;; Unlike in v1 spec, active data segments written before an +;; out-of-bounds access persist after the instantiation failure. +(assert_trap (module + ;; Note: the memory is 5 pages large by the time we get here. (memory (import "Mm" "mem") 1) (data (i32.const 0) "abc") - (data (i32.const 0x50000) "d") ;; out of bounds + (data (i32.const 327670) "zzzzzzzzzzzzzzzzzz") ;; (partially) out of bounds ) - "data segment does not fit" + "out of bounds memory access" ) -(assert_return (invoke $Mm "load" (i32.const 0)) (i32.const 0)) +(assert_return (invoke $Mm "load" (i32.const 0)) (i32.const 97)) +(assert_return (invoke $Mm "load" (i32.const 327670)) (i32.const 0)) -(assert_unlinkable +(assert_trap (module (memory (import "Mm" "mem") 1) (data (i32.const 0) "abc") (table 0 funcref) (func) - (elem (i32.const 0) 0) ;; out of bounds + (elem (i32.const 0) 0) ;; out of bounds ) - "elements segment does not fit" + "out of bounds table access" ) -(assert_return (invoke $Mm "load" (i32.const 0)) (i32.const 0)) +(assert_return (invoke $Mm "load" (i32.const 0)) (i32.const 97)) ;; Store is modified if the start function traps. (module $Ms diff --git a/test/core/memory_copy.wast b/test/core/memory_copy.wast new file mode 100644 index 0000000000..472995d79d --- /dev/null +++ b/test/core/memory_copy.wast @@ -0,0 +1,5578 @@ +;; +;; Generated by ../meta/generate_memory_copy.js +;; DO NOT EDIT THIS FILE. CHANGE THE SOURCE AND REGENERATE. +;; + +(module + (memory (export "memory0") 1 1) + (data (i32.const 2) "\03\01\04\01") + (data (i32.const 12) "\07\05\02\03\06") + (func (export "test") + (nop)) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(invoke "test") + +(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29)) (i32.const 0)) + +(module + (memory (export "memory0") 1 1) + (data (i32.const 2) "\03\01\04\01") + (data (i32.const 12) "\07\05\02\03\06") + (func (export "test") + (memory.copy (i32.const 13) (i32.const 2) (i32.const 3))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(invoke "test") + +(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29)) (i32.const 0)) + +(module + (memory (export "memory0") 1 1) + (data (i32.const 2) "\03\01\04\01") + (data (i32.const 12) "\07\05\02\03\06") + (func (export "test") + (memory.copy (i32.const 25) (i32.const 15) (i32.const 2))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(invoke "test") + +(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 26)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 27)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29)) (i32.const 0)) + +(module + (memory (export "memory0") 1 1) + (data (i32.const 2) "\03\01\04\01") + (data (i32.const 12) "\07\05\02\03\06") + (func (export "test") + (memory.copy (i32.const 13) (i32.const 25) (i32.const 3))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(invoke "test") + +(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29)) (i32.const 0)) + +(module + (memory (export "memory0") 1 1) + (data (i32.const 2) "\03\01\04\01") + (data (i32.const 12) "\07\05\02\03\06") + (func (export "test") + (memory.copy (i32.const 20) (i32.const 22) (i32.const 4))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(invoke "test") + +(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29)) (i32.const 0)) + +(module + (memory (export "memory0") 1 1) + (data (i32.const 2) "\03\01\04\01") + (data (i32.const 12) "\07\05\02\03\06") + (func (export "test") + (memory.copy (i32.const 25) (i32.const 1) (i32.const 3))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(invoke "test") + +(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 27)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 28)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29)) (i32.const 0)) + +(module + (memory (export "memory0") 1 1) + (data (i32.const 2) "\03\01\04\01") + (data (i32.const 12) "\07\05\02\03\06") + (func (export "test") + (memory.copy (i32.const 10) (i32.const 12) (i32.const 7))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(invoke "test") + +(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29)) (i32.const 0)) + +(module + (memory (export "memory0") 1 1) + (data (i32.const 2) "\03\01\04\01") + (data (i32.const 12) "\07\05\02\03\06") + (func (export "test") + (memory.copy (i32.const 12) (i32.const 10) (i32.const 7))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(invoke "test") + +(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29)) (i32.const 0)) + +(module + (memory (export "mem") 1 1 ) + (data (i32.const 0) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13") + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(assert_trap (invoke "run" (i32.const 65516) (i32.const 0) (i32.const 40)) + "out of bounds memory access") + +(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 8)) +(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 9)) +(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 10)) +(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 11)) +(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 12)) +(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 13)) +(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 14)) +(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 15)) +(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 16)) +(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 17)) +(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 18)) +(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 19)) +(assert_return (invoke "load8_u" (i32.const 218)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 417)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 616)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 815)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1014)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1213)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1412)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1611)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1810)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2009)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2208)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2407)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2606)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2805)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3004)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3203)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3402)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3601)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3800)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3999)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4198)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4397)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4596)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4795)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4994)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5193)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5392)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5591)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5790)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5989)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6188)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6387)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6586)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6785)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6984)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7183)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7382)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7581)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7780)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7979)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8178)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8377)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8576)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8775)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8974)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9173)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9372)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9571)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9770)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9969)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10168)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10367)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10566)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10765)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10964)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11163)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11362)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11561)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11760)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11959)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12158)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12357)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12556)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12755)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12954)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13153)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13352)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13551)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13750)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13949)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14148)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14347)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14546)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14745)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14944)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15143)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15342)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15541)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15740)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15939)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16138)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16337)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16536)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16735)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16934)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17133)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17332)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17531)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17730)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17929)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18128)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18327)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18526)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18725)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18924)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19123)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19322)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19521)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19720)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19919)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20118)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20317)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20715)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20914)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21113)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21312)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21511)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21710)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21909)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22108)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22307)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22506)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22705)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22904)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23103)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23302)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23501)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23700)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23899)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24098)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24297)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24496)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24695)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24894)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25093)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25292)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25491)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25690)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25889)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26088)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26287)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26486)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26685)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26884)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27083)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27282)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27481)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27680)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27879)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28078)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28277)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28476)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28675)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28874)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29073)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29272)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29471)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29670)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29869)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30068)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30267)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30466)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30665)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30864)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31063)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31262)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31461)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31660)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31859)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32058)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32257)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32456)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32655)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32854)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33053)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33252)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33451)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33650)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33849)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34048)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34247)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34446)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34645)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34844)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35043)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35242)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35441)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35640)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35839)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36038)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36237)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36436)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36635)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36834)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37033)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37232)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37431)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37630)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37829)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38028)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38227)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38426)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38625)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38824)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39023)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39222)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39421)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39620)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39819)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40018)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40217)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40416)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40615)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40814)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41013)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41212)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41411)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41610)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41809)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42008)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42207)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42406)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42605)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42804)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43003)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43202)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43401)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43600)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43799)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43998)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44197)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44396)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44595)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44794)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44993)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45192)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45391)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45590)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45789)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45988)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46187)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46386)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46585)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46784)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46983)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47182)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47381)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47580)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47779)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47978)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48177)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48376)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48575)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48774)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48973)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49172)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49371)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49570)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49769)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49968)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50167)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50366)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50565)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50764)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50963)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51162)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51361)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51560)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51759)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51958)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52157)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52356)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52555)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52754)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52953)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53152)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53351)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53550)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53749)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53948)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54147)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54346)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54545)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54744)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54943)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55142)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55341)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55540)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55739)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55938)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56137)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56336)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56535)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56734)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56933)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57132)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57331)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57530)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57729)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57928)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58127)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58326)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58525)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58724)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58923)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59122)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59321)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59520)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59719)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59918)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60117)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60316)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60515)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60714)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60913)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61112)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61311)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61510)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61709)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61908)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62107)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62306)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62505)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62704)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62903)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63102)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63301)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63500)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63699)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63898)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64097)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64296)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64495)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64694)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64893)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65092)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65291)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65490)) (i32.const 0)) + +(module + (memory (export "mem") 1 1 ) + (data (i32.const 0) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13\14") + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(assert_trap (invoke "run" (i32.const 65515) (i32.const 0) (i32.const 39)) + "out of bounds memory access") + +(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 8)) +(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 9)) +(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 10)) +(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 11)) +(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 12)) +(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 13)) +(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 14)) +(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 15)) +(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 16)) +(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 17)) +(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 18)) +(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 19)) +(assert_return (invoke "load8_u" (i32.const 20)) (i32.const 20)) +(assert_return (invoke "load8_u" (i32.const 219)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 418)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 617)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 816)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1015)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1214)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1413)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1612)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1811)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2010)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2209)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2408)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2607)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2806)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3005)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3204)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3403)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3602)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3801)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4000)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4199)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4398)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4597)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4796)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4995)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5194)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5393)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5592)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5791)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5990)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6189)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6388)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6587)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6786)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6985)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7184)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7383)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7582)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7781)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7980)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8179)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8378)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8577)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8776)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8975)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9174)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9373)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9572)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9771)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9970)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10169)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10368)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10567)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10766)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10965)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11164)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11363)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11562)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11761)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11960)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12159)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12358)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12557)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12756)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12955)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13154)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13353)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13552)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13751)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13950)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14149)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14348)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14547)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14746)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14945)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15144)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15343)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15542)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15741)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15940)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16139)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16338)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16537)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16736)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16935)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17134)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17333)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17532)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17731)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17930)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18129)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18328)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18527)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18726)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18925)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19124)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19323)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19522)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19721)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19920)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20119)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20318)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20517)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20716)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20915)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21114)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21313)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21512)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21711)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21910)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22109)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22308)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22507)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22706)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22905)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23104)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23303)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23502)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23701)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23900)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24099)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24298)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24497)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24696)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24895)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25094)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25293)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25492)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25691)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25890)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26089)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26288)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26487)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26686)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26885)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27084)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27283)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27482)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27681)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27880)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28079)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28278)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28477)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28676)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28875)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29074)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29273)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29472)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29671)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29870)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30069)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30268)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30467)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30666)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30865)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31064)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31263)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31462)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31661)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31860)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32059)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32258)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32457)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32656)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32855)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33054)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33253)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33452)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33651)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33850)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34049)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34248)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34447)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34646)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34845)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35044)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35243)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35442)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35641)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35840)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36039)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36238)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36437)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36636)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36835)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37034)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37233)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37432)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37631)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37830)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38029)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38228)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38427)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38626)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38825)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39024)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39223)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39422)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39621)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39820)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40019)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40218)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40417)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40616)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40815)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41014)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41213)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41412)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41611)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41810)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42009)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42208)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42407)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42606)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42805)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43004)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43203)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43402)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43601)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43800)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43999)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44198)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44397)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44596)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44795)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44994)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45193)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45392)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45591)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45790)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45989)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46188)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46387)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46586)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46785)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46984)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47183)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47382)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47581)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47780)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47979)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48178)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48377)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48576)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48775)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48974)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49173)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49372)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49571)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49770)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49969)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50168)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50367)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50566)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50765)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50964)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51163)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51362)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51561)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51760)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51959)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52158)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52357)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52556)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52755)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52954)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53153)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53352)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53551)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53750)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53949)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54148)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54347)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54546)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54745)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54944)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55143)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55342)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55541)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55740)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55939)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56138)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56337)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56536)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56735)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56934)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57133)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57332)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57531)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57730)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57929)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58128)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58327)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58526)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58725)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58924)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59123)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59322)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59521)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59720)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59919)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60118)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60317)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60715)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60914)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61113)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61312)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61511)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61710)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61909)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62108)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62307)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62506)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62705)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62904)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63103)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63302)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63501)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63700)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63899)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64098)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64297)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64496)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64695)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64894)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65093)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65292)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65491)) (i32.const 0)) + +(module + (memory (export "mem") 1 1 ) + (data (i32.const 65516) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13") + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(assert_trap (invoke "run" (i32.const 0) (i32.const 65516) (i32.const 40)) + "out of bounds memory access") + +(assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 596)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 795)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 994)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1193)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1392)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1591)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1790)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1989)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2188)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2387)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2586)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2785)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2984)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3183)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3382)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3581)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3780)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3979)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4178)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4377)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4576)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4775)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4974)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5173)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5372)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5571)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5770)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5969)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6168)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6367)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6566)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6765)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6964)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7163)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7362)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7561)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7760)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7959)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8158)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8357)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8556)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8755)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8954)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9153)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9352)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9551)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9750)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9949)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10148)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10347)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10546)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10745)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10944)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11143)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11342)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11541)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11740)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11939)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12138)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12337)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12536)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12735)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12934)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13133)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13332)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13531)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13730)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13929)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14128)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14327)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14526)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14725)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14924)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15123)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15322)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15521)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15720)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15919)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16118)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16317)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16715)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16914)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17113)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17312)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17511)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17710)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17909)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18108)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18307)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18506)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18705)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18904)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19103)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19302)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19501)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19700)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19899)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20098)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20297)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20496)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20695)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20894)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21093)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21292)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21491)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21690)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21889)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22088)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22287)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22486)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22685)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22884)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23083)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23282)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23481)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23680)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23879)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24078)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24277)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24476)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24675)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24874)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25073)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25272)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25471)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25670)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25869)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26068)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26267)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26466)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26665)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26864)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27063)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27262)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27461)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27660)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27859)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28058)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28257)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28456)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28655)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28854)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29053)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29252)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29451)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29650)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29849)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30048)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30247)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30446)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30645)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30844)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31043)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31242)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31441)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31640)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31839)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32038)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32237)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32436)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32635)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32834)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33033)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33232)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33431)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33630)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33829)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34028)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34227)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34426)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34625)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34824)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35023)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35222)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35421)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35620)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35819)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36018)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36217)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36416)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36615)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36814)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37013)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37212)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37411)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37610)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37809)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38008)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38207)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38406)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38605)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38804)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39003)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39202)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39401)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39600)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39799)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39998)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40197)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40396)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40595)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40794)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40993)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41192)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41391)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41590)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41789)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41988)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42187)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42386)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42585)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42784)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42983)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43182)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43381)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43580)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43779)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43978)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44177)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44376)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44575)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44774)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44973)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45172)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45371)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45570)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45769)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45968)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46167)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46366)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46565)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46764)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46963)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47162)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47361)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47560)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47759)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47958)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48157)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48356)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48555)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48754)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48953)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49152)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49351)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49550)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49749)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49948)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50147)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50346)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50545)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50744)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50943)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51142)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51341)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51540)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51739)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51938)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52137)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52336)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52535)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52734)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52933)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53132)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53331)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53530)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53729)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53928)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54127)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54326)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54525)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54724)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54923)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55122)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55321)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55520)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55719)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55918)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56117)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56316)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56515)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56714)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56913)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57112)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57311)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57510)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57709)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57908)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58107)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58306)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58505)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58704)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58903)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59102)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59301)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59500)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59699)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59898)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60097)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60296)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60495)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60694)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60893)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61092)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61291)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61490)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61689)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61888)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62087)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62286)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62485)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62684)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62883)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63082)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63281)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63480)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63679)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63878)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64077)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64276)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64475)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64674)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64873)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65072)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65271)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65470)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65517)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 65518)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 65519)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 65520)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 65521)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 65522)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 65523)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 65524)) (i32.const 8)) +(assert_return (invoke "load8_u" (i32.const 65525)) (i32.const 9)) +(assert_return (invoke "load8_u" (i32.const 65526)) (i32.const 10)) +(assert_return (invoke "load8_u" (i32.const 65527)) (i32.const 11)) +(assert_return (invoke "load8_u" (i32.const 65528)) (i32.const 12)) +(assert_return (invoke "load8_u" (i32.const 65529)) (i32.const 13)) +(assert_return (invoke "load8_u" (i32.const 65530)) (i32.const 14)) +(assert_return (invoke "load8_u" (i32.const 65531)) (i32.const 15)) +(assert_return (invoke "load8_u" (i32.const 65532)) (i32.const 16)) +(assert_return (invoke "load8_u" (i32.const 65533)) (i32.const 17)) +(assert_return (invoke "load8_u" (i32.const 65534)) (i32.const 18)) +(assert_return (invoke "load8_u" (i32.const 65535)) (i32.const 19)) + +(module + (memory (export "mem") 1 1 ) + (data (i32.const 65515) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13\14") + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(assert_trap (invoke "run" (i32.const 0) (i32.const 65515) (i32.const 39)) + "out of bounds memory access") + +(assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 596)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 795)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 994)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1193)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1392)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1591)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1790)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1989)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2188)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2387)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2586)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2785)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2984)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3183)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3382)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3581)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3780)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3979)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4178)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4377)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4576)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4775)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4974)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5173)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5372)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5571)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5770)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5969)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6168)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6367)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6566)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6765)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6964)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7163)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7362)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7561)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7760)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7959)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8158)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8357)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8556)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8755)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8954)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9153)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9352)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9551)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9750)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9949)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10148)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10347)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10546)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10745)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10944)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11143)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11342)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11541)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11740)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11939)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12138)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12337)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12536)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12735)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12934)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13133)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13332)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13531)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13730)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13929)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14128)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14327)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14526)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14725)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14924)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15123)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15322)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15521)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15720)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15919)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16118)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16317)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16715)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16914)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17113)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17312)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17511)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17710)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17909)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18108)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18307)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18506)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18705)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18904)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19103)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19302)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19501)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19700)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19899)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20098)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20297)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20496)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20695)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20894)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21093)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21292)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21491)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21690)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21889)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22088)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22287)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22486)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22685)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22884)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23083)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23282)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23481)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23680)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23879)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24078)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24277)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24476)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24675)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24874)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25073)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25272)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25471)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25670)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25869)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26068)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26267)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26466)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26665)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26864)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27063)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27262)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27461)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27660)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27859)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28058)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28257)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28456)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28655)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28854)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29053)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29252)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29451)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29650)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29849)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30048)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30247)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30446)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30645)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30844)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31043)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31242)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31441)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31640)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31839)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32038)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32237)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32436)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32635)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32834)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33033)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33232)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33431)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33630)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33829)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34028)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34227)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34426)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34625)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34824)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35023)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35222)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35421)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35620)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35819)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36018)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36217)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36416)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36615)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36814)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37013)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37212)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37411)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37610)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37809)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38008)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38207)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38406)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38605)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38804)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39003)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39202)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39401)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39600)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39799)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39998)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40197)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40396)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40595)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40794)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40993)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41192)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41391)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41590)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41789)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41988)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42187)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42386)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42585)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42784)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42983)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43182)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43381)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43580)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43779)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43978)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44177)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44376)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44575)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44774)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44973)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45172)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45371)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45570)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45769)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45968)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46167)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46366)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46565)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46764)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46963)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47162)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47361)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47560)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47759)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47958)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48157)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48356)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48555)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48754)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48953)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49152)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49351)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49550)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49749)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49948)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50147)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50346)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50545)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50744)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50943)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51142)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51341)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51540)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51739)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51938)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52137)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52336)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52535)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52734)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52933)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53132)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53331)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53530)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53729)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53928)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54127)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54326)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54525)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54724)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54923)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55122)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55321)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55520)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55719)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55918)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56117)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56316)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56515)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56714)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56913)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57112)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57311)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57510)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57709)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57908)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58107)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58306)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58505)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58704)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58903)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59102)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59301)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59500)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59699)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59898)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60097)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60296)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60495)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60694)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60893)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61092)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61291)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61490)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61689)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61888)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62087)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62286)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62485)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62684)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62883)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63082)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63281)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63480)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63679)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63878)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64077)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64276)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64475)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64674)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64873)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65072)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65271)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65470)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65515)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65516)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 65517)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 65518)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 65519)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 65520)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 65521)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 65522)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 65523)) (i32.const 8)) +(assert_return (invoke "load8_u" (i32.const 65524)) (i32.const 9)) +(assert_return (invoke "load8_u" (i32.const 65525)) (i32.const 10)) +(assert_return (invoke "load8_u" (i32.const 65526)) (i32.const 11)) +(assert_return (invoke "load8_u" (i32.const 65527)) (i32.const 12)) +(assert_return (invoke "load8_u" (i32.const 65528)) (i32.const 13)) +(assert_return (invoke "load8_u" (i32.const 65529)) (i32.const 14)) +(assert_return (invoke "load8_u" (i32.const 65530)) (i32.const 15)) +(assert_return (invoke "load8_u" (i32.const 65531)) (i32.const 16)) +(assert_return (invoke "load8_u" (i32.const 65532)) (i32.const 17)) +(assert_return (invoke "load8_u" (i32.const 65533)) (i32.const 18)) +(assert_return (invoke "load8_u" (i32.const 65534)) (i32.const 19)) +(assert_return (invoke "load8_u" (i32.const 65535)) (i32.const 20)) + +(module + (memory (export "mem") 1 1 ) + (data (i32.const 65486) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13") + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(assert_trap (invoke "run" (i32.const 65516) (i32.const 65486) (i32.const 40)) + "out of bounds memory access") + +(assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 596)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 795)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 994)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1193)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1392)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1591)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1790)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1989)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2188)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2387)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2586)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2785)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2984)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3183)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3382)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3581)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3780)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3979)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4178)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4377)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4576)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4775)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4974)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5173)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5372)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5571)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5770)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5969)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6168)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6367)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6566)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6765)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6964)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7163)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7362)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7561)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7760)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7959)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8158)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8357)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8556)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8755)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8954)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9153)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9352)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9551)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9750)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9949)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10148)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10347)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10546)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10745)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10944)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11143)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11342)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11541)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11740)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11939)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12138)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12337)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12536)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12735)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12934)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13133)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13332)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13531)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13730)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13929)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14128)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14327)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14526)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14725)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14924)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15123)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15322)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15521)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15720)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15919)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16118)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16317)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16715)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16914)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17113)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17312)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17511)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17710)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17909)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18108)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18307)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18506)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18705)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18904)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19103)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19302)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19501)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19700)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19899)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20098)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20297)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20496)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20695)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20894)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21093)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21292)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21491)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21690)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21889)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22088)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22287)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22486)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22685)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22884)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23083)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23282)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23481)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23680)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23879)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24078)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24277)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24476)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24675)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24874)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25073)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25272)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25471)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25670)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25869)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26068)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26267)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26466)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26665)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26864)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27063)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27262)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27461)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27660)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27859)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28058)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28257)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28456)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28655)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28854)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29053)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29252)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29451)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29650)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29849)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30048)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30247)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30446)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30645)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30844)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31043)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31242)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31441)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31640)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31839)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32038)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32237)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32436)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32635)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32834)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33033)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33232)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33431)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33630)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33829)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34028)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34227)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34426)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34625)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34824)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35023)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35222)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35421)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35620)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35819)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36018)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36217)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36416)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36615)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36814)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37013)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37212)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37411)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37610)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37809)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38008)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38207)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38406)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38605)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38804)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39003)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39202)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39401)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39600)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39799)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39998)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40197)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40396)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40595)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40794)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40993)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41192)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41391)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41590)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41789)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41988)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42187)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42386)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42585)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42784)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42983)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43182)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43381)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43580)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43779)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43978)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44177)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44376)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44575)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44774)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44973)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45172)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45371)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45570)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45769)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45968)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46167)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46366)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46565)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46764)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46963)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47162)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47361)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47560)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47759)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47958)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48157)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48356)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48555)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48754)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48953)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49152)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49351)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49550)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49749)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49948)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50147)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50346)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50545)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50744)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50943)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51142)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51341)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51540)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51739)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51938)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52137)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52336)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52535)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52734)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52933)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53132)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53331)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53530)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53729)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53928)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54127)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54326)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54525)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54724)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54923)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55122)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55321)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55520)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55719)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55918)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56117)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56316)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56515)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56714)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56913)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57112)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57311)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57510)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57709)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57908)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58107)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58306)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58505)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58704)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58903)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59102)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59301)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59500)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59699)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59898)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60097)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60296)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60495)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60694)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60893)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61092)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61291)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61490)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61689)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61888)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62087)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62286)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62485)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62684)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62883)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63082)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63281)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63480)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63679)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63878)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64077)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64276)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64475)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64674)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64873)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65072)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65271)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65470)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65486)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65487)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 65488)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 65489)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 65490)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 65491)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 65492)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 65493)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 65494)) (i32.const 8)) +(assert_return (invoke "load8_u" (i32.const 65495)) (i32.const 9)) +(assert_return (invoke "load8_u" (i32.const 65496)) (i32.const 10)) +(assert_return (invoke "load8_u" (i32.const 65497)) (i32.const 11)) +(assert_return (invoke "load8_u" (i32.const 65498)) (i32.const 12)) +(assert_return (invoke "load8_u" (i32.const 65499)) (i32.const 13)) +(assert_return (invoke "load8_u" (i32.const 65500)) (i32.const 14)) +(assert_return (invoke "load8_u" (i32.const 65501)) (i32.const 15)) +(assert_return (invoke "load8_u" (i32.const 65502)) (i32.const 16)) +(assert_return (invoke "load8_u" (i32.const 65503)) (i32.const 17)) +(assert_return (invoke "load8_u" (i32.const 65504)) (i32.const 18)) +(assert_return (invoke "load8_u" (i32.const 65505)) (i32.const 19)) + +(module + (memory (export "mem") 1 1 ) + (data (i32.const 65516) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13") + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(assert_trap (invoke "run" (i32.const 65486) (i32.const 65516) (i32.const 40)) + "out of bounds memory access") + +(assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 596)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 795)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 994)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1193)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1392)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1591)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1790)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1989)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2188)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2387)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2586)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2785)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2984)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3183)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3382)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3581)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3780)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3979)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4178)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4377)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4576)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4775)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4974)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5173)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5372)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5571)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5770)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5969)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6168)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6367)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6566)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6765)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6964)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7163)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7362)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7561)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7760)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7959)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8158)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8357)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8556)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8755)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8954)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9153)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9352)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9551)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9750)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9949)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10148)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10347)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10546)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10745)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10944)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11143)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11342)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11541)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11740)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11939)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12138)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12337)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12536)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12735)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12934)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13133)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13332)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13531)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13730)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13929)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14128)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14327)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14526)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14725)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14924)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15123)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15322)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15521)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15720)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15919)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16118)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16317)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16715)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16914)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17113)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17312)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17511)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17710)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17909)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18108)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18307)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18506)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18705)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18904)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19103)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19302)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19501)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19700)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19899)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20098)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20297)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20496)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20695)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20894)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21093)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21292)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21491)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21690)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21889)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22088)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22287)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22486)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22685)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22884)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23083)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23282)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23481)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23680)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23879)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24078)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24277)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24476)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24675)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24874)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25073)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25272)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25471)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25670)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25869)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26068)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26267)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26466)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26665)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26864)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27063)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27262)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27461)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27660)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27859)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28058)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28257)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28456)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28655)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28854)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29053)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29252)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29451)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29650)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29849)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30048)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30247)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30446)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30645)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30844)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31043)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31242)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31441)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31640)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31839)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32038)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32237)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32436)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32635)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32834)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33033)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33232)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33431)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33630)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33829)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34028)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34227)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34426)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34625)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34824)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35023)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35222)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35421)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35620)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35819)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36018)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36217)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36416)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36615)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36814)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37013)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37212)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37411)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37610)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37809)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38008)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38207)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38406)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38605)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38804)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39003)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39202)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39401)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39600)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39799)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39998)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40197)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40396)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40595)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40794)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40993)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41192)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41391)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41590)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41789)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41988)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42187)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42386)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42585)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42784)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42983)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43182)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43381)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43580)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43779)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43978)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44177)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44376)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44575)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44774)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44973)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45172)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45371)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45570)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45769)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45968)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46167)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46366)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46565)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46764)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46963)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47162)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47361)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47560)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47759)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47958)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48157)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48356)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48555)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48754)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48953)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49152)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49351)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49550)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49749)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49948)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50147)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50346)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50545)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50744)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50943)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51142)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51341)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51540)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51739)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51938)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52137)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52336)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52535)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52734)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52933)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53132)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53331)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53530)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53729)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53928)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54127)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54326)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54525)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54724)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54923)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55122)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55321)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55520)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55719)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55918)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56117)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56316)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56515)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56714)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56913)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57112)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57311)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57510)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57709)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57908)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58107)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58306)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58505)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58704)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58903)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59102)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59301)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59500)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59699)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59898)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60097)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60296)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60495)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60694)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60893)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61092)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61291)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61490)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61689)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61888)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62087)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62286)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62485)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62684)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62883)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63082)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63281)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63480)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63679)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63878)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64077)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64276)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64475)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64674)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64873)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65072)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65271)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65470)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65517)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 65518)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 65519)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 65520)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 65521)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 65522)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 65523)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 65524)) (i32.const 8)) +(assert_return (invoke "load8_u" (i32.const 65525)) (i32.const 9)) +(assert_return (invoke "load8_u" (i32.const 65526)) (i32.const 10)) +(assert_return (invoke "load8_u" (i32.const 65527)) (i32.const 11)) +(assert_return (invoke "load8_u" (i32.const 65528)) (i32.const 12)) +(assert_return (invoke "load8_u" (i32.const 65529)) (i32.const 13)) +(assert_return (invoke "load8_u" (i32.const 65530)) (i32.const 14)) +(assert_return (invoke "load8_u" (i32.const 65531)) (i32.const 15)) +(assert_return (invoke "load8_u" (i32.const 65532)) (i32.const 16)) +(assert_return (invoke "load8_u" (i32.const 65533)) (i32.const 17)) +(assert_return (invoke "load8_u" (i32.const 65534)) (i32.const 18)) +(assert_return (invoke "load8_u" (i32.const 65535)) (i32.const 19)) + +(module + (memory (export "mem") 1 1 ) + (data (i32.const 65506) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13") + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(assert_trap (invoke "run" (i32.const 65516) (i32.const 65506) (i32.const 40)) + "out of bounds memory access") + +(assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 596)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 795)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 994)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1193)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1392)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1591)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1790)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1989)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2188)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2387)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2586)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2785)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2984)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3183)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3382)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3581)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3780)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3979)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4178)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4377)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4576)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4775)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4974)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5173)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5372)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5571)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5770)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5969)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6168)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6367)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6566)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6765)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6964)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7163)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7362)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7561)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7760)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7959)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8158)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8357)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8556)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8755)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8954)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9153)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9352)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9551)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9750)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9949)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10148)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10347)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10546)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10745)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10944)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11143)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11342)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11541)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11740)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11939)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12138)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12337)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12536)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12735)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12934)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13133)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13332)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13531)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13730)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13929)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14128)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14327)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14526)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14725)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14924)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15123)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15322)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15521)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15720)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15919)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16118)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16317)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16715)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16914)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17113)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17312)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17511)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17710)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17909)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18108)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18307)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18506)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18705)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18904)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19103)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19302)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19501)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19700)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19899)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20098)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20297)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20496)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20695)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20894)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21093)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21292)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21491)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21690)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21889)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22088)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22287)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22486)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22685)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22884)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23083)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23282)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23481)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23680)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23879)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24078)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24277)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24476)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24675)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24874)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25073)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25272)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25471)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25670)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25869)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26068)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26267)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26466)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26665)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26864)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27063)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27262)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27461)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27660)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27859)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28058)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28257)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28456)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28655)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28854)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29053)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29252)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29451)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29650)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29849)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30048)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30247)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30446)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30645)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30844)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31043)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31242)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31441)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31640)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31839)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32038)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32237)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32436)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32635)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32834)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33033)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33232)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33431)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33630)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33829)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34028)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34227)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34426)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34625)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34824)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35023)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35222)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35421)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35620)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35819)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36018)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36217)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36416)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36615)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36814)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37013)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37212)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37411)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37610)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37809)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38008)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38207)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38406)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38605)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38804)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39003)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39202)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39401)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39600)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39799)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39998)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40197)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40396)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40595)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40794)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40993)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41192)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41391)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41590)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41789)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41988)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42187)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42386)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42585)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42784)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42983)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43182)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43381)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43580)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43779)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43978)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44177)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44376)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44575)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44774)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44973)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45172)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45371)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45570)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45769)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45968)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46167)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46366)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46565)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46764)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46963)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47162)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47361)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47560)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47759)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47958)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48157)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48356)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48555)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48754)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48953)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49152)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49351)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49550)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49749)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49948)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50147)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50346)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50545)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50744)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50943)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51142)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51341)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51540)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51739)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51938)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52137)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52336)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52535)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52734)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52933)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53132)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53331)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53530)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53729)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53928)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54127)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54326)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54525)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54724)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54923)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55122)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55321)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55520)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55719)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55918)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56117)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56316)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56515)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56714)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56913)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57112)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57311)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57510)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57709)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57908)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58107)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58306)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58505)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58704)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58903)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59102)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59301)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59500)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59699)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59898)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60097)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60296)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60495)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60694)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60893)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61092)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61291)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61490)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61689)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61888)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62087)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62286)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62485)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62684)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62883)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63082)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63281)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63480)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63679)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63878)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64077)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64276)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64475)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64674)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64873)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65072)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65271)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65470)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65506)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65507)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 65508)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 65509)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 65510)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 65511)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 65512)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 65513)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 65514)) (i32.const 8)) +(assert_return (invoke "load8_u" (i32.const 65515)) (i32.const 9)) +(assert_return (invoke "load8_u" (i32.const 65516)) (i32.const 10)) +(assert_return (invoke "load8_u" (i32.const 65517)) (i32.const 11)) +(assert_return (invoke "load8_u" (i32.const 65518)) (i32.const 12)) +(assert_return (invoke "load8_u" (i32.const 65519)) (i32.const 13)) +(assert_return (invoke "load8_u" (i32.const 65520)) (i32.const 14)) +(assert_return (invoke "load8_u" (i32.const 65521)) (i32.const 15)) +(assert_return (invoke "load8_u" (i32.const 65522)) (i32.const 16)) +(assert_return (invoke "load8_u" (i32.const 65523)) (i32.const 17)) +(assert_return (invoke "load8_u" (i32.const 65524)) (i32.const 18)) +(assert_return (invoke "load8_u" (i32.const 65525)) (i32.const 19)) + +(module + (memory (export "mem") 1 1 ) + (data (i32.const 65516) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13") + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(assert_trap (invoke "run" (i32.const 65506) (i32.const 65516) (i32.const 40)) + "out of bounds memory access") + +(assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 596)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 795)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 994)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1193)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1392)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1591)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1790)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1989)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2188)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2387)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2586)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2785)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2984)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3183)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3382)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3581)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3780)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3979)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4178)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4377)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4576)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4775)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4974)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5173)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5372)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5571)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5770)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5969)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6168)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6367)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6566)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6765)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6964)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7163)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7362)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7561)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7760)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7959)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8158)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8357)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8556)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8755)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8954)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9153)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9352)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9551)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9750)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9949)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10148)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10347)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10546)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10745)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10944)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11143)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11342)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11541)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11740)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11939)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12138)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12337)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12536)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12735)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12934)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13133)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13332)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13531)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13730)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13929)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14128)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14327)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14526)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14725)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14924)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15123)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15322)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15521)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15720)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15919)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16118)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16317)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16715)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16914)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17113)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17312)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17511)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17710)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17909)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18108)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18307)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18506)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18705)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18904)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19103)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19302)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19501)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19700)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19899)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20098)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20297)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20496)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20695)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20894)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21093)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21292)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21491)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21690)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21889)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22088)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22287)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22486)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22685)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22884)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23083)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23282)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23481)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23680)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23879)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24078)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24277)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24476)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24675)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24874)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25073)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25272)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25471)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25670)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25869)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26068)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26267)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26466)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26665)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26864)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27063)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27262)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27461)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27660)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27859)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28058)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28257)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28456)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28655)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28854)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29053)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29252)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29451)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29650)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29849)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30048)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30247)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30446)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30645)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30844)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31043)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31242)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31441)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31640)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31839)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32038)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32237)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32436)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32635)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32834)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33033)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33232)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33431)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33630)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33829)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34028)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34227)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34426)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34625)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34824)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35023)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35222)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35421)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35620)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35819)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36018)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36217)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36416)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36615)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36814)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37013)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37212)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37411)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37610)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37809)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38008)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38207)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38406)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38605)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38804)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39003)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39202)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39401)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39600)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39799)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39998)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40197)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40396)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40595)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40794)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40993)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41192)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41391)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41590)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41789)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41988)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42187)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42386)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42585)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42784)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42983)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43182)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43381)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43580)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43779)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43978)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44177)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44376)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44575)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44774)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44973)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45172)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45371)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45570)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45769)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45968)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46167)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46366)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46565)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46764)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46963)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47162)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47361)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47560)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47759)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47958)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48157)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48356)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48555)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48754)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48953)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49152)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49351)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49550)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49749)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49948)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50147)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50346)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50545)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50744)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50943)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51142)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51341)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51540)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51739)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51938)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52137)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52336)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52535)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52734)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52933)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53132)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53331)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53530)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53729)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53928)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54127)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54326)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54525)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54724)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54923)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55122)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55321)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55520)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55719)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55918)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56117)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56316)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56515)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56714)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56913)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57112)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57311)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57510)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57709)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57908)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58107)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58306)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58505)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58704)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58903)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59102)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59301)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59500)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59699)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59898)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60097)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60296)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60495)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60694)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60893)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61092)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61291)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61490)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61689)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61888)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62087)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62286)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62485)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62684)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62883)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63082)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63281)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63480)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63679)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63878)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64077)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64276)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64475)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64674)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64873)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65072)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65271)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65470)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65517)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 65518)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 65519)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 65520)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 65521)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 65522)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 65523)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 65524)) (i32.const 8)) +(assert_return (invoke "load8_u" (i32.const 65525)) (i32.const 9)) +(assert_return (invoke "load8_u" (i32.const 65526)) (i32.const 10)) +(assert_return (invoke "load8_u" (i32.const 65527)) (i32.const 11)) +(assert_return (invoke "load8_u" (i32.const 65528)) (i32.const 12)) +(assert_return (invoke "load8_u" (i32.const 65529)) (i32.const 13)) +(assert_return (invoke "load8_u" (i32.const 65530)) (i32.const 14)) +(assert_return (invoke "load8_u" (i32.const 65531)) (i32.const 15)) +(assert_return (invoke "load8_u" (i32.const 65532)) (i32.const 16)) +(assert_return (invoke "load8_u" (i32.const 65533)) (i32.const 17)) +(assert_return (invoke "load8_u" (i32.const 65534)) (i32.const 18)) +(assert_return (invoke "load8_u" (i32.const 65535)) (i32.const 19)) + +(module + (memory (export "mem") 1 1 ) + (data (i32.const 65516) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13") + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(assert_trap (invoke "run" (i32.const 65516) (i32.const 65516) (i32.const 40)) + "out of bounds memory access") + +(assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 596)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 795)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 994)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1193)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1392)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1591)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1790)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1989)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2188)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2387)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2586)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2785)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2984)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3183)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3382)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3581)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3780)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3979)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4178)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4377)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4576)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4775)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4974)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5173)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5372)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5571)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5770)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5969)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6168)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6367)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6566)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6765)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6964)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7163)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7362)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7561)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7760)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7959)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8158)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8357)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8556)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8755)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8954)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9153)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9352)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9551)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9750)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9949)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10148)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10347)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10546)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10745)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10944)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11143)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11342)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11541)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11740)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11939)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12138)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12337)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12536)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12735)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12934)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13133)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13332)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13531)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13730)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13929)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14128)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14327)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14526)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14725)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14924)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15123)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15322)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15521)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15720)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15919)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16118)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16317)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16715)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16914)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17113)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17312)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17511)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17710)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17909)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18108)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18307)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18506)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18705)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18904)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19103)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19302)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19501)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19700)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19899)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20098)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20297)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20496)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20695)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20894)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21093)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21292)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21491)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21690)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21889)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22088)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22287)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22486)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22685)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22884)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23083)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23282)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23481)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23680)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23879)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24078)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24277)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24476)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24675)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24874)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25073)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25272)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25471)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25670)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25869)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26068)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26267)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26466)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26665)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26864)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27063)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27262)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27461)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27660)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27859)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28058)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28257)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28456)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28655)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28854)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29053)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29252)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29451)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29650)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29849)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30048)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30247)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30446)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30645)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30844)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31043)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31242)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31441)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31640)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31839)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32038)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32237)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32436)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32635)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32834)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33033)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33232)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33431)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33630)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33829)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34028)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34227)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34426)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34625)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34824)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35023)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35222)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35421)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35620)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35819)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36018)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36217)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36416)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36615)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36814)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37013)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37212)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37411)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37610)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37809)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38008)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38207)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38406)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38605)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38804)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39003)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39202)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39401)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39600)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39799)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39998)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40197)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40396)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40595)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40794)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40993)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41192)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41391)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41590)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41789)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41988)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42187)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42386)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42585)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42784)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42983)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43182)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43381)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43580)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43779)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43978)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44177)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44376)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44575)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44774)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44973)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45172)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45371)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45570)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45769)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45968)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46167)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46366)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46565)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46764)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46963)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47162)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47361)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47560)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47759)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47958)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48157)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48356)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48555)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48754)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48953)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49152)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49351)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49550)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49749)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49948)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50147)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50346)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50545)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50744)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50943)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51142)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51341)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51540)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51739)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51938)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52137)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52336)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52535)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52734)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52933)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53132)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53331)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53530)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53729)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53928)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54127)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54326)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54525)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54724)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54923)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55122)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55321)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55520)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55719)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55918)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56117)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56316)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56515)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56714)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56913)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57112)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57311)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57510)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57709)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57908)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58107)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58306)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58505)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58704)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58903)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59102)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59301)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59500)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59699)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59898)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60097)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60296)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60495)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60694)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60893)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61092)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61291)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61490)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61689)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61888)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62087)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62286)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62485)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62684)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62883)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63082)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63281)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63480)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63679)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63878)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64077)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64276)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64475)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64674)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64873)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65072)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65271)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65470)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65517)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 65518)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 65519)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 65520)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 65521)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 65522)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 65523)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 65524)) (i32.const 8)) +(assert_return (invoke "load8_u" (i32.const 65525)) (i32.const 9)) +(assert_return (invoke "load8_u" (i32.const 65526)) (i32.const 10)) +(assert_return (invoke "load8_u" (i32.const 65527)) (i32.const 11)) +(assert_return (invoke "load8_u" (i32.const 65528)) (i32.const 12)) +(assert_return (invoke "load8_u" (i32.const 65529)) (i32.const 13)) +(assert_return (invoke "load8_u" (i32.const 65530)) (i32.const 14)) +(assert_return (invoke "load8_u" (i32.const 65531)) (i32.const 15)) +(assert_return (invoke "load8_u" (i32.const 65532)) (i32.const 16)) +(assert_return (invoke "load8_u" (i32.const 65533)) (i32.const 17)) +(assert_return (invoke "load8_u" (i32.const 65534)) (i32.const 18)) +(assert_return (invoke "load8_u" (i32.const 65535)) (i32.const 19)) + +(module + (memory (export "mem") 1 ) + (data (i32.const 65516) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13") + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(assert_trap (invoke "run" (i32.const 0) (i32.const 65516) (i32.const 4294963200)) + "out of bounds memory access") + +(assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 596)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 795)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 994)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1193)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1392)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1591)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1790)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1989)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2188)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2387)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2586)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2785)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2984)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3183)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3382)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3581)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3780)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3979)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4178)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4377)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4576)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4775)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4974)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5173)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5372)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5571)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5770)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5969)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6168)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6367)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6566)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6765)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6964)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7163)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7362)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7561)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7760)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7959)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8158)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8357)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8556)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8755)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8954)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9153)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9352)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9551)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9750)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9949)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10148)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10347)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10546)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10745)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10944)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11143)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11342)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11541)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11740)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11939)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12138)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12337)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12536)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12735)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12934)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13133)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13332)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13531)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13730)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13929)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14128)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14327)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14526)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14725)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14924)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15123)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15322)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15521)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15720)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15919)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16118)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16317)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16715)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16914)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17113)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17312)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17511)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17710)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17909)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18108)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18307)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18506)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18705)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18904)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19103)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19302)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19501)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19700)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19899)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20098)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20297)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20496)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20695)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20894)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21093)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21292)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21491)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21690)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21889)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22088)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22287)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22486)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22685)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22884)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23083)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23282)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23481)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23680)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23879)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24078)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24277)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24476)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24675)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24874)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25073)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25272)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25471)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25670)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25869)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26068)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26267)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26466)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26665)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26864)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27063)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27262)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27461)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27660)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27859)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28058)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28257)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28456)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28655)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28854)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29053)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29252)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29451)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29650)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29849)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30048)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30247)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30446)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30645)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30844)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31043)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31242)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31441)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31640)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31839)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32038)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32237)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32436)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32635)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32834)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33033)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33232)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33431)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33630)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33829)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34028)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34227)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34426)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34625)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34824)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35023)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35222)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35421)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35620)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35819)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36018)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36217)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36416)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36615)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36814)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37013)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37212)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37411)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37610)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37809)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38008)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38207)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38406)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38605)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38804)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39003)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39202)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39401)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39600)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39799)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39998)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40197)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40396)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40595)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40794)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40993)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41192)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41391)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41590)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41789)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41988)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42187)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42386)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42585)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42784)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42983)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43182)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43381)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43580)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43779)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43978)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44177)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44376)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44575)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44774)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44973)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45172)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45371)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45570)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45769)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45968)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46167)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46366)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46565)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46764)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46963)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47162)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47361)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47560)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47759)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47958)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48157)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48356)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48555)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48754)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48953)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49152)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49351)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49550)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49749)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49948)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50147)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50346)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50545)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50744)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50943)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51142)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51341)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51540)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51739)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51938)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52137)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52336)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52535)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52734)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52933)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53132)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53331)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53530)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53729)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53928)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54127)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54326)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54525)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54724)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54923)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55122)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55321)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55520)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55719)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55918)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56117)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56316)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56515)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56714)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56913)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57112)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57311)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57510)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57709)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57908)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58107)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58306)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58505)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58704)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58903)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59102)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59301)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59500)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59699)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59898)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60097)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60296)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60495)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60694)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60893)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61092)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61291)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61490)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61689)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61888)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62087)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62286)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62485)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62684)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62883)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63082)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63281)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63480)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63679)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63878)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64077)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64276)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64475)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64674)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64873)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65072)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65271)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65470)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65517)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 65518)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 65519)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 65520)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 65521)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 65522)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 65523)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 65524)) (i32.const 8)) +(assert_return (invoke "load8_u" (i32.const 65525)) (i32.const 9)) +(assert_return (invoke "load8_u" (i32.const 65526)) (i32.const 10)) +(assert_return (invoke "load8_u" (i32.const 65527)) (i32.const 11)) +(assert_return (invoke "load8_u" (i32.const 65528)) (i32.const 12)) +(assert_return (invoke "load8_u" (i32.const 65529)) (i32.const 13)) +(assert_return (invoke "load8_u" (i32.const 65530)) (i32.const 14)) +(assert_return (invoke "load8_u" (i32.const 65531)) (i32.const 15)) +(assert_return (invoke "load8_u" (i32.const 65532)) (i32.const 16)) +(assert_return (invoke "load8_u" (i32.const 65533)) (i32.const 17)) +(assert_return (invoke "load8_u" (i32.const 65534)) (i32.const 18)) +(assert_return (invoke "load8_u" (i32.const 65535)) (i32.const 19)) + +(module + (memory (export "mem") 1 1 ) + (data (i32.const 61440) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13") + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(assert_trap (invoke "run" (i32.const 65516) (i32.const 61440) (i32.const 4294967040)) + "out of bounds memory access") + +(assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 596)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 795)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 994)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1193)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1392)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1591)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1790)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1989)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2188)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2387)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2586)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2785)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2984)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3183)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3382)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3581)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3780)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3979)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4178)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4377)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4576)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4775)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4974)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5173)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5372)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5571)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5770)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5969)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6168)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6367)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6566)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6765)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6964)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7163)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7362)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7561)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7760)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7959)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8158)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8357)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8556)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8755)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8954)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9153)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9352)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9551)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9750)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9949)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10148)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10347)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10546)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10745)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10944)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11143)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11342)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11541)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11740)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11939)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12138)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12337)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12536)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12735)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12934)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13133)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13332)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13531)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13730)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13929)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14128)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14327)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14526)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14725)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14924)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15123)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15322)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15521)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15720)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15919)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16118)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16317)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16715)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16914)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17113)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17312)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17511)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17710)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17909)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18108)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18307)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18506)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18705)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18904)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19103)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19302)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19501)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19700)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19899)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20098)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20297)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20496)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20695)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20894)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21093)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21292)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21491)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21690)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21889)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22088)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22287)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22486)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22685)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22884)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23083)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23282)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23481)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23680)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23879)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24078)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24277)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24476)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24675)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24874)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25073)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25272)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25471)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25670)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25869)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26068)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26267)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26466)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26665)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26864)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27063)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27262)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27461)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27660)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27859)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28058)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28257)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28456)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28655)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28854)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29053)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29252)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29451)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29650)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29849)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30048)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30247)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30446)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30645)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30844)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31043)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31242)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31441)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31640)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31839)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32038)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32237)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32436)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32635)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32834)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33033)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33232)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33431)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33630)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33829)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34028)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34227)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34426)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34625)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34824)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35023)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35222)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35421)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35620)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35819)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36018)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36217)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36416)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36615)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36814)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37013)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37212)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37411)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37610)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37809)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38008)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38207)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38406)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38605)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38804)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39003)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39202)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39401)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39600)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39799)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39998)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40197)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40396)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40595)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40794)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40993)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41192)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41391)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41590)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41789)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41988)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42187)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42386)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42585)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42784)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42983)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43182)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43381)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43580)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43779)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43978)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44177)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44376)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44575)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44774)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44973)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45172)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45371)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45570)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45769)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45968)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46167)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46366)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46565)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46764)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46963)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47162)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47361)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47560)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47759)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47958)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48157)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48356)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48555)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48754)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48953)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49152)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49351)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49550)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49749)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49948)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50147)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50346)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50545)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50744)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50943)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51142)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51341)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51540)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51739)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51938)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52137)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52336)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52535)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52734)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52933)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53132)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53331)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53530)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53729)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53928)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54127)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54326)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54525)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54724)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54923)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55122)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55321)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55520)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55719)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55918)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56117)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56316)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56515)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56714)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56913)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57112)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57311)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57510)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57709)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57908)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58107)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58306)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58505)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58704)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58903)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59102)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59301)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59500)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59699)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59898)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60097)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60296)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60495)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60694)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60893)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61092)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61291)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61440)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61441)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 61442)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 61443)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 61444)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 61445)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 61446)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 61447)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 61448)) (i32.const 8)) +(assert_return (invoke "load8_u" (i32.const 61449)) (i32.const 9)) +(assert_return (invoke "load8_u" (i32.const 61450)) (i32.const 10)) +(assert_return (invoke "load8_u" (i32.const 61451)) (i32.const 11)) +(assert_return (invoke "load8_u" (i32.const 61452)) (i32.const 12)) +(assert_return (invoke "load8_u" (i32.const 61453)) (i32.const 13)) +(assert_return (invoke "load8_u" (i32.const 61454)) (i32.const 14)) +(assert_return (invoke "load8_u" (i32.const 61455)) (i32.const 15)) +(assert_return (invoke "load8_u" (i32.const 61456)) (i32.const 16)) +(assert_return (invoke "load8_u" (i32.const 61457)) (i32.const 17)) +(assert_return (invoke "load8_u" (i32.const 61458)) (i32.const 18)) +(assert_return (invoke "load8_u" (i32.const 61459)) (i32.const 19)) +(assert_return (invoke "load8_u" (i32.const 61510)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61709)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61908)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62107)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62306)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62505)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62704)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62903)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63102)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63301)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63500)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63699)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63898)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64097)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64296)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64495)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64694)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64893)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65092)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65291)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65490)) (i32.const 0)) + +(assert_invalid + (module + (func (export "testfn") + (memory.copy (i32.const 10) (i32.const 20) (i32.const 30)))) + "unknown memory 0") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i32.const 10) (i32.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i32.const 10) (i32.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i32.const 10) (i32.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i32.const 10) (f32.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i32.const 10) (f32.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i32.const 10) (f32.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i32.const 10) (f32.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i32.const 10) (i64.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i32.const 10) (i64.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i32.const 10) (i64.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i32.const 10) (i64.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i32.const 10) (f64.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i32.const 10) (f64.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i32.const 10) (f64.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i32.const 10) (f64.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f32.const 10) (i32.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f32.const 10) (i32.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f32.const 10) (i32.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f32.const 10) (i32.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f32.const 10) (f32.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f32.const 10) (f32.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f32.const 10) (f32.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f32.const 10) (f32.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f32.const 10) (i64.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f32.const 10) (i64.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f32.const 10) (i64.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f32.const 10) (i64.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f32.const 10) (f64.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f32.const 10) (f64.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f32.const 10) (f64.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f32.const 10) (f64.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i64.const 10) (i32.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i64.const 10) (i32.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i64.const 10) (i32.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i64.const 10) (i32.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i64.const 10) (f32.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i64.const 10) (f32.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i64.const 10) (f32.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i64.const 10) (f32.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i64.const 10) (i64.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i64.const 10) (i64.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i64.const 10) (i64.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i64.const 10) (i64.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i64.const 10) (f64.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i64.const 10) (f64.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i64.const 10) (f64.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i64.const 10) (f64.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f64.const 10) (i32.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f64.const 10) (i32.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f64.const 10) (i32.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f64.const 10) (i32.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f64.const 10) (f32.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f64.const 10) (f32.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f64.const 10) (f32.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f64.const 10) (f32.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f64.const 10) (i64.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f64.const 10) (i64.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f64.const 10) (i64.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f64.const 10) (i64.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f64.const 10) (f64.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f64.const 10) (f64.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f64.const 10) (f64.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f64.const 10) (f64.const 20) (f64.const 30)))) + "type mismatch") + + +(module + (memory 1 1) + (func (export "test") + (memory.fill (i32.const 10) (i32.const 0x55) (i32.const 10)) + (memory.copy (i32.const 9) (i32.const 10) (i32.const 5))) + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) +) +(invoke "test") + +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 9) (i32.const 0)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 9) (i32.const 20) (i32.const 85)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 20) (i32.const 65536) (i32.const 0)) + (i32.const -1)) + +(module + (memory 1 1) + (func (export "test") + (memory.fill (i32.const 10) (i32.const 0x55) (i32.const 10)) + (memory.copy (i32.const 16) (i32.const 15) (i32.const 5))) + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) +) +(invoke "test") + +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 10) (i32.const 0)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 10) (i32.const 21) (i32.const 85)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 21) (i32.const 65536) (i32.const 0)) + (i32.const -1)) + +(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0xFF00) (i32.const 0x8000) (i32.const 257)))) +(assert_trap (invoke "test") "out of bounds memory access") + +(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0xFFFFFF00) (i32.const 0x4000) (i32.const 257)))) +(assert_trap (invoke "test") "out of bounds memory access") + +(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0x8000) (i32.const 0xFF00) (i32.const 257)))) +(assert_trap (invoke "test") "out of bounds memory access") + +(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0x4000) (i32.const 0xFFFFFF00) (i32.const 257)))) +(assert_trap (invoke "test") "out of bounds memory access") + +(module + (memory 1 1) + (func (export "test") + (memory.fill (i32.const 0x0000) (i32.const 0x55) (i32.const 0x8000)) + (memory.fill (i32.const 0x8000) (i32.const 0xAA) (i32.const 0x8000)) + (memory.copy (i32.const 0x9000) (i32.const 0x7000) (i32.const 0))) + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) +) +(invoke "test") + +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 32768) (i32.const 85)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 32768) (i32.const 65536) (i32.const 170)) + (i32.const -1)) +(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0x10000) (i32.const 0x7000) (i32.const 0)))) +(invoke "test") + +(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0x20000) (i32.const 0x7000) (i32.const 0)))) +(assert_trap (invoke "test") "out of bounds memory access") + +(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0x9000) (i32.const 0x10000) (i32.const 0)))) +(invoke "test") + +(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0x9000) (i32.const 0x20000) (i32.const 0)))) +(assert_trap (invoke "test") "out of bounds memory access") + +(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0x10000) (i32.const 0x10000) (i32.const 0)))) +(invoke "test") + +(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0x20000) (i32.const 0x20000) (i32.const 0)))) +(assert_trap (invoke "test") "out of bounds memory access") + +(module + (memory 1 1) + (func (export "test") + (memory.fill (i32.const 17767) (i32.const 1) (i32.const 1344)) + (memory.fill (i32.const 39017) (i32.const 2) (i32.const 1055)) + (memory.fill (i32.const 56401) (i32.const 3) (i32.const 988)) + (memory.fill (i32.const 37962) (i32.const 4) (i32.const 322)) + (memory.fill (i32.const 7977) (i32.const 5) (i32.const 1994)) + (memory.fill (i32.const 22714) (i32.const 6) (i32.const 3036)) + (memory.fill (i32.const 16882) (i32.const 7) (i32.const 2372)) + (memory.fill (i32.const 43491) (i32.const 8) (i32.const 835)) + (memory.fill (i32.const 124) (i32.const 9) (i32.const 1393)) + (memory.fill (i32.const 2132) (i32.const 10) (i32.const 2758)) + (memory.fill (i32.const 8987) (i32.const 11) (i32.const 3098)) + (memory.fill (i32.const 52711) (i32.const 12) (i32.const 741)) + (memory.fill (i32.const 3958) (i32.const 13) (i32.const 2823)) + (memory.fill (i32.const 49715) (i32.const 14) (i32.const 1280)) + (memory.fill (i32.const 50377) (i32.const 15) (i32.const 1466)) + (memory.fill (i32.const 20493) (i32.const 16) (i32.const 3158)) + (memory.fill (i32.const 47665) (i32.const 17) (i32.const 544)) + (memory.fill (i32.const 12451) (i32.const 18) (i32.const 2669)) + (memory.fill (i32.const 24869) (i32.const 19) (i32.const 2651)) + (memory.fill (i32.const 45317) (i32.const 20) (i32.const 1570)) + (memory.fill (i32.const 43096) (i32.const 21) (i32.const 1691)) + (memory.fill (i32.const 33886) (i32.const 22) (i32.const 646)) + (memory.fill (i32.const 48555) (i32.const 23) (i32.const 1858)) + (memory.fill (i32.const 53453) (i32.const 24) (i32.const 2657)) + (memory.fill (i32.const 30363) (i32.const 25) (i32.const 981)) + (memory.fill (i32.const 9300) (i32.const 26) (i32.const 1807)) + (memory.fill (i32.const 50190) (i32.const 27) (i32.const 487)) + (memory.fill (i32.const 62753) (i32.const 28) (i32.const 530)) + (memory.fill (i32.const 36316) (i32.const 29) (i32.const 943)) + (memory.fill (i32.const 6768) (i32.const 30) (i32.const 381)) + (memory.fill (i32.const 51262) (i32.const 31) (i32.const 3089)) + (memory.fill (i32.const 49729) (i32.const 32) (i32.const 658)) + (memory.fill (i32.const 44540) (i32.const 33) (i32.const 1702)) + (memory.fill (i32.const 33342) (i32.const 34) (i32.const 1092)) + (memory.fill (i32.const 50814) (i32.const 35) (i32.const 1410)) + (memory.fill (i32.const 47594) (i32.const 36) (i32.const 2204)) + (memory.fill (i32.const 54123) (i32.const 37) (i32.const 2394)) + (memory.fill (i32.const 55183) (i32.const 38) (i32.const 250)) + (memory.fill (i32.const 22620) (i32.const 39) (i32.const 2097)) + (memory.fill (i32.const 17132) (i32.const 40) (i32.const 3264)) + (memory.fill (i32.const 54331) (i32.const 41) (i32.const 3299)) + (memory.fill (i32.const 39474) (i32.const 42) (i32.const 2796)) + (memory.fill (i32.const 36156) (i32.const 43) (i32.const 2070)) + (memory.fill (i32.const 35308) (i32.const 44) (i32.const 2763)) + (memory.fill (i32.const 32731) (i32.const 45) (i32.const 312)) + (memory.fill (i32.const 63746) (i32.const 46) (i32.const 192)) + (memory.fill (i32.const 30974) (i32.const 47) (i32.const 596)) + (memory.fill (i32.const 16635) (i32.const 48) (i32.const 501)) + (memory.fill (i32.const 57002) (i32.const 49) (i32.const 686)) + (memory.fill (i32.const 34299) (i32.const 50) (i32.const 385)) + (memory.fill (i32.const 60881) (i32.const 51) (i32.const 903)) + (memory.fill (i32.const 61445) (i32.const 52) (i32.const 2390)) + (memory.fill (i32.const 46972) (i32.const 53) (i32.const 1441)) + (memory.fill (i32.const 25973) (i32.const 54) (i32.const 3162)) + (memory.fill (i32.const 5566) (i32.const 55) (i32.const 2135)) + (memory.fill (i32.const 35977) (i32.const 56) (i32.const 519)) + (memory.fill (i32.const 44892) (i32.const 57) (i32.const 3280)) + (memory.fill (i32.const 46760) (i32.const 58) (i32.const 1678)) + (memory.fill (i32.const 46607) (i32.const 59) (i32.const 3168)) + (memory.fill (i32.const 22449) (i32.const 60) (i32.const 1441)) + (memory.fill (i32.const 58609) (i32.const 61) (i32.const 663)) + (memory.fill (i32.const 32261) (i32.const 62) (i32.const 1671)) + (memory.fill (i32.const 3063) (i32.const 63) (i32.const 721)) + (memory.fill (i32.const 34025) (i32.const 64) (i32.const 84)) + (memory.fill (i32.const 33338) (i32.const 65) (i32.const 2029)) + (memory.fill (i32.const 36810) (i32.const 66) (i32.const 29)) + (memory.fill (i32.const 19147) (i32.const 67) (i32.const 3034)) + (memory.fill (i32.const 12616) (i32.const 68) (i32.const 1043)) + (memory.fill (i32.const 18276) (i32.const 69) (i32.const 3324)) + (memory.fill (i32.const 4639) (i32.const 70) (i32.const 1091)) + (memory.fill (i32.const 16158) (i32.const 71) (i32.const 1997)) + (memory.fill (i32.const 18204) (i32.const 72) (i32.const 2259)) + (memory.fill (i32.const 50532) (i32.const 73) (i32.const 3189)) + (memory.fill (i32.const 11028) (i32.const 74) (i32.const 1968)) + (memory.fill (i32.const 15962) (i32.const 75) (i32.const 1455)) + (memory.fill (i32.const 45406) (i32.const 76) (i32.const 1177)) + (memory.fill (i32.const 54137) (i32.const 77) (i32.const 1568)) + (memory.fill (i32.const 33083) (i32.const 78) (i32.const 1642)) + (memory.fill (i32.const 61028) (i32.const 79) (i32.const 3284)) + (memory.fill (i32.const 51729) (i32.const 80) (i32.const 223)) + (memory.fill (i32.const 4361) (i32.const 81) (i32.const 2171)) + (memory.fill (i32.const 57514) (i32.const 82) (i32.const 1322)) + (memory.fill (i32.const 55724) (i32.const 83) (i32.const 2648)) + (memory.fill (i32.const 24091) (i32.const 84) (i32.const 1045)) + (memory.fill (i32.const 43183) (i32.const 85) (i32.const 3097)) + (memory.fill (i32.const 32307) (i32.const 86) (i32.const 2796)) + (memory.fill (i32.const 3811) (i32.const 87) (i32.const 2010)) + (memory.fill (i32.const 54856) (i32.const 88) (i32.const 0)) + (memory.fill (i32.const 49941) (i32.const 89) (i32.const 2069)) + (memory.fill (i32.const 20411) (i32.const 90) (i32.const 2896)) + (memory.fill (i32.const 33826) (i32.const 91) (i32.const 192)) + (memory.fill (i32.const 9402) (i32.const 92) (i32.const 2195)) + (memory.fill (i32.const 12413) (i32.const 93) (i32.const 24)) + (memory.fill (i32.const 14091) (i32.const 94) (i32.const 577)) + (memory.fill (i32.const 44058) (i32.const 95) (i32.const 2089)) + (memory.fill (i32.const 36735) (i32.const 96) (i32.const 3436)) + (memory.fill (i32.const 23288) (i32.const 97) (i32.const 2765)) + (memory.fill (i32.const 6392) (i32.const 98) (i32.const 830)) + (memory.fill (i32.const 33307) (i32.const 99) (i32.const 1938)) + (memory.fill (i32.const 21941) (i32.const 100) (i32.const 2750)) + (memory.copy (i32.const 59214) (i32.const 54248) (i32.const 2098)) + (memory.copy (i32.const 63026) (i32.const 39224) (i32.const 230)) + (memory.copy (i32.const 51833) (i32.const 23629) (i32.const 2300)) + (memory.copy (i32.const 6708) (i32.const 23996) (i32.const 639)) + (memory.copy (i32.const 6990) (i32.const 33399) (i32.const 1097)) + (memory.copy (i32.const 19403) (i32.const 10348) (i32.const 3197)) + (memory.copy (i32.const 27308) (i32.const 54406) (i32.const 100)) + (memory.copy (i32.const 27221) (i32.const 43682) (i32.const 1717)) + (memory.copy (i32.const 60528) (i32.const 8629) (i32.const 119)) + (memory.copy (i32.const 5947) (i32.const 2308) (i32.const 658)) + (memory.copy (i32.const 4787) (i32.const 51631) (i32.const 2269)) + (memory.copy (i32.const 12617) (i32.const 19197) (i32.const 833)) + (memory.copy (i32.const 11854) (i32.const 46505) (i32.const 3300)) + (memory.copy (i32.const 11376) (i32.const 45012) (i32.const 2281)) + (memory.copy (i32.const 34186) (i32.const 6697) (i32.const 2572)) + (memory.copy (i32.const 4936) (i32.const 1690) (i32.const 1328)) + (memory.copy (i32.const 63164) (i32.const 7637) (i32.const 1670)) + (memory.copy (i32.const 44568) (i32.const 18344) (i32.const 33)) + (memory.copy (i32.const 43918) (i32.const 22348) (i32.const 1427)) + (memory.copy (i32.const 46637) (i32.const 49819) (i32.const 1434)) + (memory.copy (i32.const 63684) (i32.const 8755) (i32.const 834)) + (memory.copy (i32.const 33485) (i32.const 20131) (i32.const 3317)) + (memory.copy (i32.const 40575) (i32.const 54317) (i32.const 3201)) + (memory.copy (i32.const 25812) (i32.const 59254) (i32.const 2452)) + (memory.copy (i32.const 19678) (i32.const 56882) (i32.const 346)) + (memory.copy (i32.const 15852) (i32.const 35914) (i32.const 2430)) + (memory.copy (i32.const 11824) (i32.const 35574) (i32.const 300)) + (memory.copy (i32.const 59427) (i32.const 13957) (i32.const 3153)) + (memory.copy (i32.const 34299) (i32.const 60594) (i32.const 1281)) + (memory.copy (i32.const 8964) (i32.const 12276) (i32.const 943)) + (memory.copy (i32.const 2827) (i32.const 10425) (i32.const 1887)) + (memory.copy (i32.const 43194) (i32.const 43910) (i32.const 738)) + (memory.copy (i32.const 63038) (i32.const 18949) (i32.const 122)) + (memory.copy (i32.const 24044) (i32.const 44761) (i32.const 1755)) + (memory.copy (i32.const 22608) (i32.const 14755) (i32.const 702)) + (memory.copy (i32.const 11284) (i32.const 26579) (i32.const 1830)) + (memory.copy (i32.const 23092) (i32.const 20471) (i32.const 1064)) + (memory.copy (i32.const 57248) (i32.const 54770) (i32.const 2631)) + (memory.copy (i32.const 25492) (i32.const 1025) (i32.const 3113)) + (memory.copy (i32.const 49588) (i32.const 44220) (i32.const 975)) + (memory.copy (i32.const 28280) (i32.const 41722) (i32.const 2336)) + (memory.copy (i32.const 61289) (i32.const 230) (i32.const 2872)) + (memory.copy (i32.const 22480) (i32.const 52506) (i32.const 2197)) + (memory.copy (i32.const 40553) (i32.const 9578) (i32.const 1958)) + (memory.copy (i32.const 29004) (i32.const 20862) (i32.const 2186)) + (memory.copy (i32.const 53029) (i32.const 43955) (i32.const 1037)) + (memory.copy (i32.const 25476) (i32.const 35667) (i32.const 1650)) + (memory.copy (i32.const 58516) (i32.const 45819) (i32.const 1986)) + (memory.copy (i32.const 38297) (i32.const 5776) (i32.const 1955)) + (memory.copy (i32.const 28503) (i32.const 55364) (i32.const 2368)) + (memory.copy (i32.const 62619) (i32.const 18108) (i32.const 1356)) + (memory.copy (i32.const 50149) (i32.const 13861) (i32.const 382)) + (memory.copy (i32.const 16904) (i32.const 36341) (i32.const 1900)) + (memory.copy (i32.const 48098) (i32.const 11358) (i32.const 2807)) + (memory.copy (i32.const 28512) (i32.const 40362) (i32.const 323)) + (memory.copy (i32.const 35506) (i32.const 27856) (i32.const 1670)) + (memory.copy (i32.const 62970) (i32.const 53332) (i32.const 1341)) + (memory.copy (i32.const 14133) (i32.const 46312) (i32.const 644)) + (memory.copy (i32.const 29030) (i32.const 19074) (i32.const 496)) + (memory.copy (i32.const 44952) (i32.const 47577) (i32.const 2784)) + (memory.copy (i32.const 39559) (i32.const 44661) (i32.const 1350)) + (memory.copy (i32.const 10352) (i32.const 29274) (i32.const 1475)) + (memory.copy (i32.const 46911) (i32.const 46178) (i32.const 1467)) + (memory.copy (i32.const 4905) (i32.const 28740) (i32.const 1895)) + (memory.copy (i32.const 38012) (i32.const 57253) (i32.const 1751)) + (memory.copy (i32.const 26446) (i32.const 27223) (i32.const 1127)) + (memory.copy (i32.const 58835) (i32.const 24657) (i32.const 1063)) + (memory.copy (i32.const 61356) (i32.const 38790) (i32.const 766)) + (memory.copy (i32.const 44160) (i32.const 2284) (i32.const 1520)) + (memory.copy (i32.const 32740) (i32.const 47237) (i32.const 3014)) + (memory.copy (i32.const 11148) (i32.const 21260) (i32.const 1011)) + (memory.copy (i32.const 7665) (i32.const 31612) (i32.const 3034)) + (memory.copy (i32.const 18044) (i32.const 12987) (i32.const 3320)) + (memory.copy (i32.const 57306) (i32.const 55905) (i32.const 308)) + (memory.copy (i32.const 24675) (i32.const 16815) (i32.const 1155)) + (memory.copy (i32.const 19900) (i32.const 10115) (i32.const 722)) + (memory.copy (i32.const 2921) (i32.const 5935) (i32.const 2370)) + (memory.copy (i32.const 32255) (i32.const 50095) (i32.const 2926)) + (memory.copy (i32.const 15126) (i32.const 17299) (i32.const 2607)) + (memory.copy (i32.const 45575) (i32.const 28447) (i32.const 2045)) + (memory.copy (i32.const 55149) (i32.const 36113) (i32.const 2596)) + (memory.copy (i32.const 28461) (i32.const 54157) (i32.const 1168)) + (memory.copy (i32.const 47951) (i32.const 53385) (i32.const 3137)) + (memory.copy (i32.const 30646) (i32.const 45155) (i32.const 2649)) + (memory.copy (i32.const 5057) (i32.const 4295) (i32.const 52)) + (memory.copy (i32.const 6692) (i32.const 24195) (i32.const 441)) + (memory.copy (i32.const 32984) (i32.const 27117) (i32.const 3445)) + (memory.copy (i32.const 32530) (i32.const 59372) (i32.const 2785)) + (memory.copy (i32.const 34361) (i32.const 8962) (i32.const 2406)) + (memory.copy (i32.const 17893) (i32.const 54538) (i32.const 3381)) + (memory.copy (i32.const 22685) (i32.const 44151) (i32.const 136)) + (memory.copy (i32.const 59089) (i32.const 7077) (i32.const 1045)) + (memory.copy (i32.const 42945) (i32.const 55028) (i32.const 2389)) + (memory.copy (i32.const 44693) (i32.const 20138) (i32.const 877)) + (memory.copy (i32.const 36810) (i32.const 25196) (i32.const 3447)) + (memory.copy (i32.const 45742) (i32.const 31888) (i32.const 854)) + (memory.copy (i32.const 24236) (i32.const 31866) (i32.const 1377)) + (memory.copy (i32.const 33778) (i32.const 692) (i32.const 1594)) + (memory.copy (i32.const 60618) (i32.const 18585) (i32.const 2987)) + (memory.copy (i32.const 50370) (i32.const 41271) (i32.const 1406)) + ) + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) +) +(invoke "test") + +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 124) (i32.const 0)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 124) (i32.const 1517) (i32.const 9)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 1517) (i32.const 2132) (i32.const 0)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 2132) (i32.const 2827) (i32.const 10)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 2827) (i32.const 2921) (i32.const 92)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 2921) (i32.const 3538) (i32.const 83)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 3538) (i32.const 3786) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 3786) (i32.const 4042) (i32.const 97)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 4042) (i32.const 4651) (i32.const 99)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 4651) (i32.const 5057) (i32.const 0)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 5057) (i32.const 5109) (i32.const 99)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 5109) (i32.const 5291) (i32.const 0)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 5291) (i32.const 5524) (i32.const 72)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 5524) (i32.const 5691) (i32.const 92)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 5691) (i32.const 6552) (i32.const 83)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 6552) (i32.const 7133) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 7133) (i32.const 7665) (i32.const 99)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 7665) (i32.const 8314) (i32.const 0)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 8314) (i32.const 8360) (i32.const 62)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 8360) (i32.const 8793) (i32.const 86)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 8793) (i32.const 8979) (i32.const 83)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 8979) (i32.const 9373) (i32.const 79)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 9373) (i32.const 9518) (i32.const 95)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 9518) (i32.const 9934) (i32.const 59)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 9934) (i32.const 10087) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 10087) (i32.const 10206) (i32.const 5)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 10206) (i32.const 10230) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 10230) (i32.const 10249) (i32.const 41)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 10249) (i32.const 11148) (i32.const 83)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 11148) (i32.const 11356) (i32.const 74)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 11356) (i32.const 11380) (i32.const 93)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 11380) (i32.const 11939) (i32.const 74)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 11939) (i32.const 12159) (i32.const 68)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 12159) (i32.const 12575) (i32.const 83)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 12575) (i32.const 12969) (i32.const 79)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 12969) (i32.const 13114) (i32.const 95)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 13114) (i32.const 14133) (i32.const 59)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 14133) (i32.const 14404) (i32.const 76)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 14404) (i32.const 14428) (i32.const 57)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 14428) (i32.const 14458) (i32.const 59)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 14458) (i32.const 14580) (i32.const 32)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 14580) (i32.const 14777) (i32.const 89)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 14777) (i32.const 15124) (i32.const 59)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 15124) (i32.const 15126) (i32.const 36)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 15126) (i32.const 15192) (i32.const 100)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 15192) (i32.const 15871) (i32.const 96)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 15871) (i32.const 15998) (i32.const 95)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 15998) (i32.const 17017) (i32.const 59)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 17017) (i32.const 17288) (i32.const 76)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 17288) (i32.const 17312) (i32.const 57)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 17312) (i32.const 17342) (i32.const 59)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 17342) (i32.const 17464) (i32.const 32)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 17464) (i32.const 17661) (i32.const 89)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 17661) (i32.const 17727) (i32.const 59)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 17727) (i32.const 17733) (i32.const 5)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 17733) (i32.const 17893) (i32.const 96)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 17893) (i32.const 18553) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 18553) (i32.const 18744) (i32.const 42)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 18744) (i32.const 18801) (i32.const 76)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 18801) (i32.const 18825) (i32.const 57)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 18825) (i32.const 18876) (i32.const 59)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 18876) (i32.const 18885) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 18885) (i32.const 18904) (i32.const 41)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 18904) (i32.const 19567) (i32.const 83)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 19567) (i32.const 20403) (i32.const 96)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 20403) (i32.const 21274) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 21274) (i32.const 21364) (i32.const 100)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 21364) (i32.const 21468) (i32.const 74)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 21468) (i32.const 21492) (i32.const 93)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 21492) (i32.const 22051) (i32.const 74)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 22051) (i32.const 22480) (i32.const 68)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 22480) (i32.const 22685) (i32.const 100)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 22685) (i32.const 22694) (i32.const 68)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 22694) (i32.const 22821) (i32.const 10)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 22821) (i32.const 22869) (i32.const 100)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 22869) (i32.const 24107) (i32.const 97)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 24107) (i32.const 24111) (i32.const 37)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 24111) (i32.const 24236) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 24236) (i32.const 24348) (i32.const 72)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 24348) (i32.const 24515) (i32.const 92)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 24515) (i32.const 24900) (i32.const 83)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 24900) (i32.const 25136) (i32.const 95)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 25136) (i32.const 25182) (i32.const 85)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 25182) (i32.const 25426) (i32.const 68)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 25426) (i32.const 25613) (i32.const 89)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 25613) (i32.const 25830) (i32.const 96)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 25830) (i32.const 26446) (i32.const 100)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 26446) (i32.const 26517) (i32.const 10)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 26517) (i32.const 27468) (i32.const 92)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 27468) (i32.const 27503) (i32.const 95)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 27503) (i32.const 27573) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 27573) (i32.const 28245) (i32.const 92)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 28245) (i32.const 28280) (i32.const 95)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 28280) (i32.const 29502) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 29502) (i32.const 29629) (i32.const 42)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 29629) (i32.const 30387) (i32.const 83)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 30387) (i32.const 30646) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 30646) (i32.const 31066) (i32.const 92)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 31066) (i32.const 31131) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 31131) (i32.const 31322) (i32.const 42)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 31322) (i32.const 31379) (i32.const 76)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 31379) (i32.const 31403) (i32.const 57)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 31403) (i32.const 31454) (i32.const 59)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 31454) (i32.const 31463) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 31463) (i32.const 31482) (i32.const 41)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 31482) (i32.const 31649) (i32.const 83)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 31649) (i32.const 31978) (i32.const 72)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 31978) (i32.const 32145) (i32.const 92)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 32145) (i32.const 32530) (i32.const 83)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 32530) (i32.const 32766) (i32.const 95)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 32766) (i32.const 32812) (i32.const 85)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 32812) (i32.const 33056) (i32.const 68)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 33056) (i32.const 33660) (i32.const 89)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 33660) (i32.const 33752) (i32.const 59)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 33752) (i32.const 33775) (i32.const 36)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 33775) (i32.const 33778) (i32.const 32)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 33778) (i32.const 34603) (i32.const 9)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 34603) (i32.const 35218) (i32.const 0)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 35218) (i32.const 35372) (i32.const 10)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 35372) (i32.const 35486) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 35486) (i32.const 35605) (i32.const 5)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 35605) (i32.const 35629) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 35629) (i32.const 35648) (i32.const 41)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 35648) (i32.const 36547) (i32.const 83)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 36547) (i32.const 36755) (i32.const 74)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 36755) (i32.const 36767) (i32.const 93)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 36767) (i32.const 36810) (i32.const 83)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 36810) (i32.const 36839) (i32.const 100)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 36839) (i32.const 37444) (i32.const 96)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 37444) (i32.const 38060) (i32.const 100)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 38060) (i32.const 38131) (i32.const 10)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 38131) (i32.const 39082) (i32.const 92)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 39082) (i32.const 39117) (i32.const 95)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 39117) (i32.const 39187) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 39187) (i32.const 39859) (i32.const 92)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 39859) (i32.const 39894) (i32.const 95)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 39894) (i32.const 40257) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 40257) (i32.const 40344) (i32.const 89)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 40344) (i32.const 40371) (i32.const 59)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 40371) (i32.const 40804) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 40804) (i32.const 40909) (i32.const 5)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 40909) (i32.const 42259) (i32.const 92)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 42259) (i32.const 42511) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 42511) (i32.const 42945) (i32.const 83)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 42945) (i32.const 43115) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 43115) (i32.const 43306) (i32.const 42)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 43306) (i32.const 43363) (i32.const 76)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 43363) (i32.const 43387) (i32.const 57)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 43387) (i32.const 43438) (i32.const 59)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 43438) (i32.const 43447) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 43447) (i32.const 43466) (i32.const 41)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 43466) (i32.const 44129) (i32.const 83)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 44129) (i32.const 44958) (i32.const 96)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 44958) (i32.const 45570) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 45570) (i32.const 45575) (i32.const 92)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 45575) (i32.const 45640) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 45640) (i32.const 45742) (i32.const 42)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 45742) (i32.const 45832) (i32.const 72)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 45832) (i32.const 45999) (i32.const 92)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 45999) (i32.const 46384) (i32.const 83)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 46384) (i32.const 46596) (i32.const 95)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 46596) (i32.const 46654) (i32.const 92)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 46654) (i32.const 47515) (i32.const 83)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 47515) (i32.const 47620) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 47620) (i32.const 47817) (i32.const 79)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 47817) (i32.const 47951) (i32.const 95)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 47951) (i32.const 48632) (i32.const 100)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 48632) (i32.const 48699) (i32.const 97)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 48699) (i32.const 48703) (i32.const 37)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 48703) (i32.const 49764) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 49764) (i32.const 49955) (i32.const 42)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 49955) (i32.const 50012) (i32.const 76)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 50012) (i32.const 50036) (i32.const 57)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 50036) (i32.const 50087) (i32.const 59)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 50087) (i32.const 50096) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 50096) (i32.const 50115) (i32.const 41)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 50115) (i32.const 50370) (i32.const 83)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 50370) (i32.const 51358) (i32.const 92)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 51358) (i32.const 51610) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 51610) (i32.const 51776) (i32.const 83)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 51776) (i32.const 51833) (i32.const 89)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 51833) (i32.const 52895) (i32.const 100)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 52895) (i32.const 53029) (i32.const 97)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 53029) (i32.const 53244) (i32.const 68)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 53244) (i32.const 54066) (i32.const 100)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 54066) (i32.const 54133) (i32.const 97)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 54133) (i32.const 54137) (i32.const 37)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 54137) (i32.const 55198) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 55198) (i32.const 55389) (i32.const 42)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 55389) (i32.const 55446) (i32.const 76)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 55446) (i32.const 55470) (i32.const 57)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 55470) (i32.const 55521) (i32.const 59)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 55521) (i32.const 55530) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 55530) (i32.const 55549) (i32.const 41)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 55549) (i32.const 56212) (i32.const 83)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 56212) (i32.const 57048) (i32.const 96)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 57048) (i32.const 58183) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 58183) (i32.const 58202) (i32.const 41)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 58202) (i32.const 58516) (i32.const 83)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 58516) (i32.const 58835) (i32.const 95)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 58835) (i32.const 58855) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 58855) (i32.const 59089) (i32.const 95)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 59089) (i32.const 59145) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 59145) (i32.const 59677) (i32.const 99)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 59677) (i32.const 60134) (i32.const 0)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 60134) (i32.const 60502) (i32.const 89)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 60502) (i32.const 60594) (i32.const 59)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 60594) (i32.const 60617) (i32.const 36)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 60617) (i32.const 60618) (i32.const 32)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 60618) (i32.const 60777) (i32.const 42)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 60777) (i32.const 60834) (i32.const 76)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 60834) (i32.const 60858) (i32.const 57)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 60858) (i32.const 60909) (i32.const 59)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 60909) (i32.const 60918) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 60918) (i32.const 60937) (i32.const 41)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 60937) (i32.const 61600) (i32.const 83)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 61600) (i32.const 62436) (i32.const 96)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 62436) (i32.const 63307) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 63307) (i32.const 63397) (i32.const 100)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 63397) (i32.const 63501) (i32.const 74)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 63501) (i32.const 63525) (i32.const 93)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 63525) (i32.const 63605) (i32.const 74)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 63605) (i32.const 63704) (i32.const 100)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 63704) (i32.const 63771) (i32.const 97)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 63771) (i32.const 63775) (i32.const 37)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 63775) (i32.const 64311) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 64311) (i32.const 64331) (i32.const 26)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 64331) (i32.const 64518) (i32.const 92)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 64518) (i32.const 64827) (i32.const 11)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 64827) (i32.const 64834) (i32.const 26)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 64834) (i32.const 65536) (i32.const 0)) + (i32.const -1)) diff --git a/test/core/memory_fill.wast b/test/core/memory_fill.wast new file mode 100644 index 0000000000..98374a1586 --- /dev/null +++ b/test/core/memory_fill.wast @@ -0,0 +1,686 @@ +;; +;; Generated by ../meta/generate_memory_fill.js +;; DO NOT EDIT THIS FILE. CHANGE THE SOURCE AND REGENERATE. +;; + +(module + (memory 1 1) + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) + + (func (export "test") + (memory.fill (i32.const 0xFF00) (i32.const 0x55) (i32.const 256)))) +(invoke "test") + +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 65280) (i32.const 0)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 65280) (i32.const 65536) (i32.const 85)) + (i32.const -1)) +(module + (memory 1 1) + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) + + (func (export "test") + (memory.fill (i32.const 0xFF00) (i32.const 0x55) (i32.const 257)))) +(assert_trap (invoke "test") "out of bounds memory access") + +(module + (memory 1 1) + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) + + (func (export "test") + (memory.fill (i32.const 0xFFFFFF00) (i32.const 0x55) (i32.const 257)))) +(assert_trap (invoke "test") "out of bounds memory access") + +(module + (memory 1 1) + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) + + (func (export "test") + (memory.fill (i32.const 0x12) (i32.const 0x55) (i32.const 0)))) +(invoke "test") + +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 65536) (i32.const 0)) + (i32.const -1)) +(module + (memory 1 1) + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) + + (func (export "test") + (memory.fill (i32.const 0x10000) (i32.const 0x55) (i32.const 0)))) +(invoke "test") + +(module + (memory 1 1) + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) + + (func (export "test") + (memory.fill (i32.const 0x20000) (i32.const 0x55) (i32.const 0)))) +(assert_trap (invoke "test") "out of bounds memory access") + +(module + (memory 1 1) + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) + + (func (export "test") + (memory.fill (i32.const 0x1) (i32.const 0xAA) (i32.const 0xFFFE)))) +(invoke "test") + +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 1) (i32.const 0)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 1) (i32.const 65535) (i32.const 170)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 65535) (i32.const 65536) (i32.const 0)) + (i32.const -1)) + +(module + (memory 1 1) + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) + + (func (export "test") + (memory.fill (i32.const 0x12) (i32.const 0x55) (i32.const 10)) + (memory.fill (i32.const 0x15) (i32.const 0xAA) (i32.const 4)))) +(invoke "test") + +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 18) (i32.const 0)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 18) (i32.const 21) (i32.const 85)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 21) (i32.const 25) (i32.const 170)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 25) (i32.const 28) (i32.const 85)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 28) (i32.const 65536) (i32.const 0)) + (i32.const -1)) +(assert_invalid + (module + (func (export "testfn") + (memory.fill (i32.const 10) (i32.const 20) (i32.const 30)))) + "unknown memory 0") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i32.const 10) (i32.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i32.const 10) (i32.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i32.const 10) (i32.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i32.const 10) (f32.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i32.const 10) (f32.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i32.const 10) (f32.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i32.const 10) (f32.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i32.const 10) (i64.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i32.const 10) (i64.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i32.const 10) (i64.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i32.const 10) (i64.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i32.const 10) (f64.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i32.const 10) (f64.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i32.const 10) (f64.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i32.const 10) (f64.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f32.const 10) (i32.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f32.const 10) (i32.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f32.const 10) (i32.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f32.const 10) (i32.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f32.const 10) (f32.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f32.const 10) (f32.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f32.const 10) (f32.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f32.const 10) (f32.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f32.const 10) (i64.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f32.const 10) (i64.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f32.const 10) (i64.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f32.const 10) (i64.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f32.const 10) (f64.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f32.const 10) (f64.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f32.const 10) (f64.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f32.const 10) (f64.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i64.const 10) (i32.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i64.const 10) (i32.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i64.const 10) (i32.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i64.const 10) (i32.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i64.const 10) (f32.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i64.const 10) (f32.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i64.const 10) (f32.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i64.const 10) (f32.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i64.const 10) (i64.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i64.const 10) (i64.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i64.const 10) (i64.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i64.const 10) (i64.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i64.const 10) (f64.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i64.const 10) (f64.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i64.const 10) (f64.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i64.const 10) (f64.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f64.const 10) (i32.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f64.const 10) (i32.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f64.const 10) (i32.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f64.const 10) (i32.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f64.const 10) (f32.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f64.const 10) (f32.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f64.const 10) (f32.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f64.const 10) (f32.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f64.const 10) (i64.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f64.const 10) (i64.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f64.const 10) (i64.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f64.const 10) (i64.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f64.const 10) (f64.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f64.const 10) (f64.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f64.const 10) (f64.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f64.const 10) (f64.const 20) (f64.const 30)))) + "type mismatch") + +(module + (memory 1 1 ) + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) + + (func (export "run") (param $offs i32) (param $val i32) (param $len i32) + (memory.fill (local.get $offs) (local.get $val) (local.get $len)))) + +(assert_trap (invoke "run" (i32.const 65280) (i32.const 37) (i32.const 512)) + "out of bounds memory access") + +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 1) (i32.const 0)) + (i32.const -1)) +(module + (memory 1 1 ) + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) + + (func (export "run") (param $offs i32) (param $val i32) (param $len i32) + (memory.fill (local.get $offs) (local.get $val) (local.get $len)))) + +(assert_trap (invoke "run" (i32.const 65279) (i32.const 37) (i32.const 514)) + "out of bounds memory access") + +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 1) (i32.const 0)) + (i32.const -1)) +(module + (memory 1 1 ) + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) + + (func (export "run") (param $offs i32) (param $val i32) (param $len i32) + (memory.fill (local.get $offs) (local.get $val) (local.get $len)))) + +(assert_trap (invoke "run" (i32.const 65279) (i32.const 37) (i32.const 4294967295)) + "out of bounds memory access") + +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 1) (i32.const 0)) + (i32.const -1)) diff --git a/test/core/memory_grow.wast b/test/core/memory_grow.wast index 8a87c77c64..aa56297d25 100644 --- a/test/core/memory_grow.wast +++ b/test/core/memory_grow.wast @@ -312,8 +312,8 @@ (assert_invalid (module (memory 0) - (func $type-size-empty - (memory.grow) (drop) + (func $type-size-empty-vs-i32 (result i32) + (memory.grow) ) ) "type mismatch" @@ -321,9 +321,9 @@ (assert_invalid (module (memory 0) - (func $type-size-empty-in-block + (func $type-size-empty-vs-i32-in-block (result i32) (i32.const 0) - (block (memory.grow) (drop)) + (block (result i32) (memory.grow)) ) ) "type mismatch" @@ -331,9 +331,9 @@ (assert_invalid (module (memory 0) - (func $type-size-empty-in-loop + (func $type-size-empty-vs-i32-in-loop (result i32) (i32.const 0) - (loop (memory.grow) (drop)) + (loop (result i32) (memory.grow)) ) ) "type mismatch" @@ -341,15 +341,39 @@ (assert_invalid (module (memory 0) - (func $type-size-empty-in-then + (func $type-size-empty-vs-i32-in-then (result i32) (i32.const 0) (i32.const 0) - (if (then (memory.grow) (drop))) + (if (result i32) (then (memory.grow))) ) ) "type mismatch" ) +(assert_invalid + (module + (memory 1) + (func $type-size-f32-vs-i32 (result i32) + (memory.grow (f32.const 0)) + ) + ) + "type mismatch" +) -;; Type check - -(assert_invalid (module (memory 1) (func (result i32) (memory.grow (f32.const 0)))) "type mismatch") +(assert_invalid + (module + (memory 1) + (func $type-result-i32-vs-empty + (memory.grow (i32.const 0)) + ) + ) + "type mismatch" +) +(assert_invalid + (module + (memory 1) + (func $type-result-i32-vs-f32 (result f32) + (memory.grow (i32.const 0)) + ) + ) + "type mismatch" +) diff --git a/test/core/memory_init.wast b/test/core/memory_init.wast new file mode 100644 index 0000000000..672b1c5013 --- /dev/null +++ b/test/core/memory_init.wast @@ -0,0 +1,967 @@ +;; +;; Generated by ../meta/generate_memory_init.js +;; DO NOT EDIT THIS FILE. CHANGE THE SOURCE AND REGENERATE. +;; + +(module + (memory (export "memory0") 1 1) + (data (i32.const 2) "\03\01\04\01") + (data "\02\07\01\08") + (data (i32.const 12) "\07\05\02\03\06") + (data "\05\09\02\07\06") + (func (export "test") + (nop)) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(invoke "test") + +(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29)) (i32.const 0)) + +(module + (memory (export "memory0") 1 1) + (data (i32.const 2) "\03\01\04\01") + (data "\02\07\01\08") + (data (i32.const 12) "\07\05\02\03\06") + (data "\05\09\02\07\06") + (func (export "test") + (memory.init 1 (i32.const 7) (i32.const 0) (i32.const 4))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(invoke "test") + +(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 8)) +(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29)) (i32.const 0)) + +(module + (memory (export "memory0") 1 1) + (data (i32.const 2) "\03\01\04\01") + (data "\02\07\01\08") + (data (i32.const 12) "\07\05\02\03\06") + (data "\05\09\02\07\06") + (func (export "test") + (memory.init 3 (i32.const 15) (i32.const 1) (i32.const 3))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(invoke "test") + +(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 9)) +(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29)) (i32.const 0)) + +(module + (memory (export "memory0") 1 1) + (data (i32.const 2) "\03\01\04\01") + (data "\02\07\01\08") + (data (i32.const 12) "\07\05\02\03\06") + (data "\05\09\02\07\06") + (func (export "test") + (memory.init 1 (i32.const 7) (i32.const 0) (i32.const 4)) + (data.drop 1) + (memory.init 3 (i32.const 15) (i32.const 1) (i32.const 3)) + (data.drop 3) + (memory.copy (i32.const 20) (i32.const 15) (i32.const 5)) + (memory.copy (i32.const 21) (i32.const 29) (i32.const 1)) + (memory.copy (i32.const 24) (i32.const 10) (i32.const 1)) + (memory.copy (i32.const 13) (i32.const 11) (i32.const 4)) + (memory.copy (i32.const 19) (i32.const 20) (i32.const 5))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(invoke "test") + +(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 8)) +(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 9)) +(assert_return (invoke "load8_u" (i32.const 20)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 22)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23)) (i32.const 8)) +(assert_return (invoke "load8_u" (i32.const 24)) (i32.const 8)) +(assert_return (invoke "load8_u" (i32.const 25)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29)) (i32.const 0)) +(assert_invalid + (module + (func (export "test") + (data.drop 0))) + "unknown data segment") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (data.drop 4))) + "unknown data segment") + +(module + (memory 1) + (data "\37") + (func (export "test") + (data.drop 0) + (data.drop 0))) +(invoke "test") + +(module + (memory 1) + (data "\37") + (func (export "test") + (data.drop 0) + (memory.init 0 (i32.const 1234) (i32.const 1) (i32.const 1)))) +(assert_trap (invoke "test") "out of bounds memory access") + +(module + (memory 1) + (data (i32.const 0) "\37") + (func (export "test") + (memory.init 0 (i32.const 1234) (i32.const 1) (i32.const 1)))) +(assert_trap (invoke "test") "out of bounds memory access") + +(assert_invalid + (module + (func (export "test") + (memory.init 1 (i32.const 1234) (i32.const 1) (i32.const 1)))) + "unknown memory 0") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 1 (i32.const 1234) (i32.const 1) (i32.const 1)))) + "unknown data segment 1") + +(module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 1) (i32.const 0) (i32.const 1)) + (memory.init 0 (i32.const 1) (i32.const 0) (i32.const 1)))) +(invoke "test") + +(module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 1234) (i32.const 0) (i32.const 5)))) +(assert_trap (invoke "test") "out of bounds memory access") + +(module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 1234) (i32.const 2) (i32.const 3)))) +(assert_trap (invoke "test") "out of bounds memory access") + +(module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 0xFFFE) (i32.const 1) (i32.const 3)))) +(assert_trap (invoke "test") "out of bounds memory access") + +(module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 1234) (i32.const 4) (i32.const 0)))) +(assert_trap (invoke "test") "out of bounds memory access") + +(module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 1234) (i32.const 1) (i32.const 0)))) +(invoke "test") + +(module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 0x10001) (i32.const 0) (i32.const 0)))) +(assert_trap (invoke "test") "out of bounds memory access") + +(module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 0x10000) (i32.const 0) (i32.const 0)))) +(invoke "test") + +(module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 0x10000) (i32.const 1) (i32.const 0)))) +(invoke "test") + +(module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 0x10001) (i32.const 4) (i32.const 0)))) +(assert_trap (invoke "test") "out of bounds memory access") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 1) (i32.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 1) (i32.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 1) (i32.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 1) (f32.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 1) (f32.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 1) (f32.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 1) (f32.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 1) (i64.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 1) (i64.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 1) (i64.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 1) (i64.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 1) (f64.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 1) (f64.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 1) (f64.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 1) (f64.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f32.const 1) (i32.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f32.const 1) (i32.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f32.const 1) (i32.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f32.const 1) (i32.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f32.const 1) (f32.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f32.const 1) (f32.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f32.const 1) (f32.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f32.const 1) (f32.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f32.const 1) (i64.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f32.const 1) (i64.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f32.const 1) (i64.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f32.const 1) (i64.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f32.const 1) (f64.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f32.const 1) (f64.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f32.const 1) (f64.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f32.const 1) (f64.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i64.const 1) (i32.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i64.const 1) (i32.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i64.const 1) (i32.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i64.const 1) (i32.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i64.const 1) (f32.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i64.const 1) (f32.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i64.const 1) (f32.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i64.const 1) (f32.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i64.const 1) (i64.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i64.const 1) (i64.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i64.const 1) (i64.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i64.const 1) (i64.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i64.const 1) (f64.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i64.const 1) (f64.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i64.const 1) (f64.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i64.const 1) (f64.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f64.const 1) (i32.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f64.const 1) (i32.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f64.const 1) (i32.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f64.const 1) (i32.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f64.const 1) (f32.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f64.const 1) (f32.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f64.const 1) (f32.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f64.const 1) (f32.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f64.const 1) (i64.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f64.const 1) (i64.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f64.const 1) (i64.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f64.const 1) (i64.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f64.const 1) (f64.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f64.const 1) (f64.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f64.const 1) (f64.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f64.const 1) (f64.const 1) (f64.const 1)))) + "type mismatch") + +(module + (memory 1 1 ) + (data "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42") + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) + + (func (export "run") (param $offs i32) (param $len i32) + (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len)))) + +(assert_trap (invoke "run" (i32.const 65528) (i32.const 16)) + "out of bounds memory access") + +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 1) (i32.const 0)) + (i32.const -1)) +(module + (memory 1 1 ) + (data "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42") + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) + + (func (export "run") (param $offs i32) (param $len i32) + (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len)))) + +(assert_trap (invoke "run" (i32.const 65527) (i32.const 16)) + "out of bounds memory access") + +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 1) (i32.const 0)) + (i32.const -1)) +(module + (memory 1 1 ) + (data "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42") + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) + + (func (export "run") (param $offs i32) (param $len i32) + (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len)))) + +(assert_trap (invoke "run" (i32.const 65472) (i32.const 30)) + "out of bounds memory access") + +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 1) (i32.const 0)) + (i32.const -1)) +(module + (memory 1 1 ) + (data "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42") + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) + + (func (export "run") (param $offs i32) (param $len i32) + (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len)))) + +(assert_trap (invoke "run" (i32.const 65473) (i32.const 31)) + "out of bounds memory access") + +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 1) (i32.const 0)) + (i32.const -1)) +(module + (memory 1 ) + (data "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42") + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) + + (func (export "run") (param $offs i32) (param $len i32) + (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len)))) + +(assert_trap (invoke "run" (i32.const 65528) (i32.const 4294967040)) + "out of bounds memory access") + +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 1) (i32.const 0)) + (i32.const -1)) +(module + (memory 1 ) + (data "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42") + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) + + (func (export "run") (param $offs i32) (param $len i32) + (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len)))) + +(assert_trap (invoke "run" (i32.const 0) (i32.const 4294967292)) + "out of bounds memory access") + +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 1) (i32.const 0)) + (i32.const -1)) + +(module + (memory 1) + ;; 65 data segments. 64 is the smallest positive number that is encoded + ;; differently as a signed LEB. + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") + (func (memory.init 64 (i32.const 0) (i32.const 0) (i32.const 0)))) diff --git a/test/core/ref_func.wast b/test/core/ref_func.wast new file mode 100644 index 0000000000..adb5cb788d --- /dev/null +++ b/test/core/ref_func.wast @@ -0,0 +1,115 @@ +(module + (func (export "f") (param $x i32) (result i32) (local.get $x)) +) +(register "M") + +(module + (func $f (import "M" "f") (param i32) (result i32)) + (func $g (param $x i32) (result i32) + (i32.add (local.get $x) (i32.const 1)) + ) + + (global funcref (ref.func $f)) + (global funcref (ref.func $g)) + (global $v (mut funcref) (ref.func $f)) + + (global funcref (ref.func $gf1)) + (global funcref (ref.func $gf2)) + (func (drop (ref.func $ff1)) (drop (ref.func $ff2))) + (elem declare func $gf1 $ff1) + (elem declare funcref (ref.func $gf2) (ref.func $ff2)) + (func $gf1) + (func $gf2) + (func $ff1) + (func $ff2) + + (func (export "is_null-f") (result i32) + (ref.is_null (ref.func $f)) + ) + (func (export "is_null-g") (result i32) + (ref.is_null (ref.func $g)) + ) + (func (export "is_null-v") (result i32) + (ref.is_null (global.get $v)) + ) + + (func (export "set-f") (global.set $v (ref.func $f))) + (func (export "set-g") (global.set $v (ref.func $g))) + + (table $t 1 funcref) + (elem declare func $f $g) + + (func (export "call-f") (param $x i32) (result i32) + (table.set $t (i32.const 0) (ref.func $f)) + (call_indirect $t (param i32) (result i32) (local.get $x) (i32.const 0)) + ) + (func (export "call-g") (param $x i32) (result i32) + (table.set $t (i32.const 0) (ref.func $g)) + (call_indirect $t (param i32) (result i32) (local.get $x) (i32.const 0)) + ) + (func (export "call-v") (param $x i32) (result i32) + (table.set $t (i32.const 0) (global.get $v)) + (call_indirect $t (param i32) (result i32) (local.get $x) (i32.const 0)) + ) +) + +(assert_return (invoke "is_null-f") (i32.const 0)) +(assert_return (invoke "is_null-g") (i32.const 0)) +(assert_return (invoke "is_null-v") (i32.const 0)) + +(assert_return (invoke "call-f" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "call-g" (i32.const 4)) (i32.const 5)) +(assert_return (invoke "call-v" (i32.const 4)) (i32.const 4)) +(invoke "set-g") +(assert_return (invoke "call-v" (i32.const 4)) (i32.const 5)) +(invoke "set-f") +(assert_return (invoke "call-v" (i32.const 4)) (i32.const 4)) + +(assert_invalid + (module + (func $f (import "M" "f") (param i32) (result i32)) + (func $g (import "M" "g") (param i32) (result i32)) + (global funcref (ref.func 7)) + ) + "unknown function 7" +) + + +;; Reference declaration + +(module + (func $f1) + (func $f2) + (func $f3) + (func $f4) + (func $f5) + (func $f6) + + (table $t 1 funcref) + + (global funcref (ref.func $f1)) + (export "f" (func $f2)) + (elem (table $t) (i32.const 0) func $f3) + (elem (table $t) (i32.const 0) funcref (ref.func $f4)) + (elem func $f5) + (elem funcref (ref.func $f6)) + + (func + (ref.func $f1) + (ref.func $f2) + (ref.func $f3) + (ref.func $f4) + (ref.func $f5) + (ref.func $f6) + (return) + ) +) + +(assert_invalid + (module (func $f (drop (ref.func $f)))) + "undeclared function reference" +) +(assert_invalid + (module (start $f) (func $f (drop (ref.func $f)))) + "undeclared function reference" +) diff --git a/test/core/ref_is_null.wast b/test/core/ref_is_null.wast new file mode 100644 index 0000000000..8396da4a7e --- /dev/null +++ b/test/core/ref_is_null.wast @@ -0,0 +1,58 @@ +(module + (func $f1 (export "funcref") (param $x funcref) (result i32) + (ref.is_null (local.get $x)) + ) + (func $f2 (export "externref") (param $x externref) (result i32) + (ref.is_null (local.get $x)) + ) + + (table $t1 2 funcref) + (table $t2 2 externref) + (elem (table $t1) (i32.const 1) func $dummy) + (func $dummy) + + (func (export "init") (param $r externref) + (table.set $t2 (i32.const 1) (local.get $r)) + ) + (func (export "deinit") + (table.set $t1 (i32.const 1) (ref.null func)) + (table.set $t2 (i32.const 1) (ref.null extern)) + ) + + (func (export "funcref-elem") (param $x i32) (result i32) + (call $f1 (table.get $t1 (local.get $x))) + ) + (func (export "externref-elem") (param $x i32) (result i32) + (call $f2 (table.get $t2 (local.get $x))) + ) +) + +(assert_return (invoke "funcref" (ref.null func)) (i32.const 1)) +(assert_return (invoke "externref" (ref.null extern)) (i32.const 1)) + +(assert_return (invoke "externref" (ref.extern 1)) (i32.const 0)) + +(invoke "init" (ref.extern 0)) + +(assert_return (invoke "funcref-elem" (i32.const 0)) (i32.const 1)) +(assert_return (invoke "externref-elem" (i32.const 0)) (i32.const 1)) + +(assert_return (invoke "funcref-elem" (i32.const 1)) (i32.const 0)) +(assert_return (invoke "externref-elem" (i32.const 1)) (i32.const 0)) + +(invoke "deinit") + +(assert_return (invoke "funcref-elem" (i32.const 0)) (i32.const 1)) +(assert_return (invoke "externref-elem" (i32.const 0)) (i32.const 1)) + +(assert_return (invoke "funcref-elem" (i32.const 1)) (i32.const 1)) +(assert_return (invoke "externref-elem" (i32.const 1)) (i32.const 1)) + +(assert_invalid + (module (func $ref-vs-num (param i32) (ref.is_null (local.get 0)))) + "type mismatch" +) +(assert_invalid + (module (func $ref-vs-empty (ref.is_null))) + "type mismatch" +) diff --git a/test/core/ref_null.wast b/test/core/ref_null.wast new file mode 100644 index 0000000000..b88b0888fd --- /dev/null +++ b/test/core/ref_null.wast @@ -0,0 +1,10 @@ +(module + (func (export "externref") (result externref) (ref.null extern)) + (func (export "funcref") (result funcref) (ref.null func)) + + (global externref (ref.null extern)) + (global funcref (ref.null func)) +) + +(assert_return (invoke "externref") (ref.null extern)) +(assert_return (invoke "funcref") (ref.null func)) diff --git a/test/core/select.wast b/test/core/select.wast index e40347e355..b343bf93cb 100644 --- a/test/core/select.wast +++ b/test/core/select.wast @@ -1,30 +1,50 @@ (module - - (memory 1) - + ;; Auxiliary (func $dummy) + (table $tab funcref (elem $dummy)) + (memory 1) - (func (export "select_i32") (param $lhs i32) (param $rhs i32) (param $cond i32) (result i32) - (select (local.get $lhs) (local.get $rhs) (local.get $cond))) - - (func (export "select_i64") (param $lhs i64) (param $rhs i64) (param $cond i32) (result i64) - (select (local.get $lhs) (local.get $rhs) (local.get $cond))) - - (func (export "select_f32") (param $lhs f32) (param $rhs f32) (param $cond i32) (result f32) - (select (local.get $lhs) (local.get $rhs) (local.get $cond))) + (func (export "select-i32") (param i32 i32 i32) (result i32) + (select (local.get 0) (local.get 1) (local.get 2)) + ) + (func (export "select-i64") (param i64 i64 i32) (result i64) + (select (local.get 0) (local.get 1) (local.get 2)) + ) + (func (export "select-f32") (param f32 f32 i32) (result f32) + (select (local.get 0) (local.get 1) (local.get 2)) + ) + (func (export "select-f64") (param f64 f64 i32) (result f64) + (select (local.get 0) (local.get 1) (local.get 2)) + ) - (func (export "select_f64") (param $lhs f64) (param $rhs f64) (param $cond i32) (result f64) - (select (local.get $lhs) (local.get $rhs) (local.get $cond))) + (func (export "select-i32-t") (param i32 i32 i32) (result i32) + (select (result i32) (local.get 0) (local.get 1) (local.get 2)) + ) + (func (export "select-i64-t") (param i64 i64 i32) (result i64) + (select (result i64) (local.get 0) (local.get 1) (local.get 2)) + ) + (func (export "select-f32-t") (param f32 f32 i32) (result f32) + (select (result f32) (local.get 0) (local.get 1) (local.get 2)) + ) + (func (export "select-f64-t") (param f64 f64 i32) (result f64) + (select (result f64) (local.get 0) (local.get 1) (local.get 2)) + ) + (func (export "select-funcref") (param funcref funcref i32) (result funcref) + (select (result funcref) (local.get 0) (local.get 1) (local.get 2)) + ) + (func (export "select-externref") (param externref externref i32) (result externref) + (select (result externref) (local.get 0) (local.get 1) (local.get 2)) + ) ;; Check that both sides of the select are evaluated - (func (export "select_trap_l") (param $cond i32) (result i32) + (func (export "select-trap-left") (param $cond i32) (result i32) (select (unreachable) (i32.const 0) (local.get $cond)) ) - (func (export "select_trap_r") (param $cond i32) (result i32) + (func (export "select-trap-right") (param $cond i32) (result i32) (select (i32.const 0) (unreachable) (local.get $cond)) ) - (func (export "select_unreached") + (func (export "select-unreached") (unreachable) (select) (unreachable) (i32.const 0) (select) (unreachable) (i32.const 0) (i32.const 0) (select) @@ -89,24 +109,24 @@ (func $func (param i32 i32) (result i32) (local.get 0)) (type $check (func (param i32 i32) (result i32))) - (table funcref (elem $func)) + (table $t funcref (elem $func)) (func (export "as-call_indirect-first") (param i32) (result i32) (block (result i32) - (call_indirect (type $check) + (call_indirect $t (type $check) (select (i32.const 2) (i32.const 3) (local.get 0)) (i32.const 1) (i32.const 0) ) ) ) (func (export "as-call_indirect-mid") (param i32) (result i32) (block (result i32) - (call_indirect (type $check) + (call_indirect $t (type $check) (i32.const 1) (select (i32.const 2) (i32.const 3) (local.get 0)) (i32.const 0) ) ) ) (func (export "as-call_indirect-last") (param i32) (result i32) (block (result i32) - (call_indirect (type $check) + (call_indirect $t (type $check) (i32.const 1) (i32.const 4) (select (i32.const 2) (i32.const 3) (local.get 0)) ) ) @@ -184,40 +204,84 @@ ) ) + (func (export "unreachable-num") + (unreachable) + (select) + (i32.eqz) + (drop) + ) + (func (export "unreachable-ref") + (unreachable) + (select) + (ref.is_null) + (drop) + ) ) -(assert_return (invoke "select_i32" (i32.const 1) (i32.const 2) (i32.const 1)) (i32.const 1)) -(assert_return (invoke "select_i64" (i64.const 2) (i64.const 1) (i32.const 1)) (i64.const 2)) -(assert_return (invoke "select_f32" (f32.const 1) (f32.const 2) (i32.const 1)) (f32.const 1)) -(assert_return (invoke "select_f64" (f64.const 1) (f64.const 2) (i32.const 1)) (f64.const 1)) - -(assert_return (invoke "select_i32" (i32.const 1) (i32.const 2) (i32.const 0)) (i32.const 2)) -(assert_return (invoke "select_i32" (i32.const 2) (i32.const 1) (i32.const 0)) (i32.const 1)) -(assert_return (invoke "select_i64" (i64.const 2) (i64.const 1) (i32.const -1)) (i64.const 2)) -(assert_return (invoke "select_i64" (i64.const 2) (i64.const 1) (i32.const 0xf0f0f0f0)) (i64.const 2)) - -(assert_return (invoke "select_f32" (f32.const nan) (f32.const 1) (i32.const 1)) (f32.const nan)) -(assert_return (invoke "select_f32" (f32.const nan:0x20304) (f32.const 1) (i32.const 1)) (f32.const nan:0x20304)) -(assert_return (invoke "select_f32" (f32.const nan) (f32.const 1) (i32.const 0)) (f32.const 1)) -(assert_return (invoke "select_f32" (f32.const nan:0x20304) (f32.const 1) (i32.const 0)) (f32.const 1)) -(assert_return (invoke "select_f32" (f32.const 2) (f32.const nan) (i32.const 1)) (f32.const 2)) -(assert_return (invoke "select_f32" (f32.const 2) (f32.const nan:0x20304) (i32.const 1)) (f32.const 2)) -(assert_return (invoke "select_f32" (f32.const 2) (f32.const nan) (i32.const 0)) (f32.const nan)) -(assert_return (invoke "select_f32" (f32.const 2) (f32.const nan:0x20304) (i32.const 0)) (f32.const nan:0x20304)) - -(assert_return (invoke "select_f64" (f64.const nan) (f64.const 1) (i32.const 1)) (f64.const nan)) -(assert_return (invoke "select_f64" (f64.const nan:0x20304) (f64.const 1) (i32.const 1)) (f64.const nan:0x20304)) -(assert_return (invoke "select_f64" (f64.const nan) (f64.const 1) (i32.const 0)) (f64.const 1)) -(assert_return (invoke "select_f64" (f64.const nan:0x20304) (f64.const 1) (i32.const 0)) (f64.const 1)) -(assert_return (invoke "select_f64" (f64.const 2) (f64.const nan) (i32.const 1)) (f64.const 2)) -(assert_return (invoke "select_f64" (f64.const 2) (f64.const nan:0x20304) (i32.const 1)) (f64.const 2)) -(assert_return (invoke "select_f64" (f64.const 2) (f64.const nan) (i32.const 0)) (f64.const nan)) -(assert_return (invoke "select_f64" (f64.const 2) (f64.const nan:0x20304) (i32.const 0)) (f64.const nan:0x20304)) - -(assert_trap (invoke "select_trap_l" (i32.const 1)) "unreachable") -(assert_trap (invoke "select_trap_l" (i32.const 0)) "unreachable") -(assert_trap (invoke "select_trap_r" (i32.const 1)) "unreachable") -(assert_trap (invoke "select_trap_r" (i32.const 0)) "unreachable") +(assert_return (invoke "select-i32" (i32.const 1) (i32.const 2) (i32.const 1)) (i32.const 1)) +(assert_return (invoke "select-i64" (i64.const 2) (i64.const 1) (i32.const 1)) (i64.const 2)) +(assert_return (invoke "select-f32" (f32.const 1) (f32.const 2) (i32.const 1)) (f32.const 1)) +(assert_return (invoke "select-f64" (f64.const 1) (f64.const 2) (i32.const 1)) (f64.const 1)) + +(assert_return (invoke "select-i32" (i32.const 1) (i32.const 2) (i32.const 0)) (i32.const 2)) +(assert_return (invoke "select-i32" (i32.const 2) (i32.const 1) (i32.const 0)) (i32.const 1)) +(assert_return (invoke "select-i64" (i64.const 2) (i64.const 1) (i32.const -1)) (i64.const 2)) +(assert_return (invoke "select-i64" (i64.const 2) (i64.const 1) (i32.const 0xf0f0f0f0)) (i64.const 2)) + +(assert_return (invoke "select-f32" (f32.const nan) (f32.const 1) (i32.const 1)) (f32.const nan)) +(assert_return (invoke "select-f32" (f32.const nan:0x20304) (f32.const 1) (i32.const 1)) (f32.const nan:0x20304)) +(assert_return (invoke "select-f32" (f32.const nan) (f32.const 1) (i32.const 0)) (f32.const 1)) +(assert_return (invoke "select-f32" (f32.const nan:0x20304) (f32.const 1) (i32.const 0)) (f32.const 1)) +(assert_return (invoke "select-f32" (f32.const 2) (f32.const nan) (i32.const 1)) (f32.const 2)) +(assert_return (invoke "select-f32" (f32.const 2) (f32.const nan:0x20304) (i32.const 1)) (f32.const 2)) +(assert_return (invoke "select-f32" (f32.const 2) (f32.const nan) (i32.const 0)) (f32.const nan)) +(assert_return (invoke "select-f32" (f32.const 2) (f32.const nan:0x20304) (i32.const 0)) (f32.const nan:0x20304)) + +(assert_return (invoke "select-f64" (f64.const nan) (f64.const 1) (i32.const 1)) (f64.const nan)) +(assert_return (invoke "select-f64" (f64.const nan:0x20304) (f64.const 1) (i32.const 1)) (f64.const nan:0x20304)) +(assert_return (invoke "select-f64" (f64.const nan) (f64.const 1) (i32.const 0)) (f64.const 1)) +(assert_return (invoke "select-f64" (f64.const nan:0x20304) (f64.const 1) (i32.const 0)) (f64.const 1)) +(assert_return (invoke "select-f64" (f64.const 2) (f64.const nan) (i32.const 1)) (f64.const 2)) +(assert_return (invoke "select-f64" (f64.const 2) (f64.const nan:0x20304) (i32.const 1)) (f64.const 2)) +(assert_return (invoke "select-f64" (f64.const 2) (f64.const nan) (i32.const 0)) (f64.const nan)) +(assert_return (invoke "select-f64" (f64.const 2) (f64.const nan:0x20304) (i32.const 0)) (f64.const nan:0x20304)) + +(assert_return (invoke "select-i32-t" (i32.const 1) (i32.const 2) (i32.const 1)) (i32.const 1)) +(assert_return (invoke "select-i64-t" (i64.const 2) (i64.const 1) (i32.const 1)) (i64.const 2)) +(assert_return (invoke "select-f32-t" (f32.const 1) (f32.const 2) (i32.const 1)) (f32.const 1)) +(assert_return (invoke "select-f64-t" (f64.const 1) (f64.const 2) (i32.const 1)) (f64.const 1)) +(assert_return (invoke "select-funcref" (ref.null func) (ref.null func) (i32.const 1)) (ref.null func)) +(assert_return (invoke "select-externref" (ref.extern 1) (ref.extern 2) (i32.const 1)) (ref.extern 1)) + +(assert_return (invoke "select-i32-t" (i32.const 1) (i32.const 2) (i32.const 0)) (i32.const 2)) +(assert_return (invoke "select-i32-t" (i32.const 2) (i32.const 1) (i32.const 0)) (i32.const 1)) +(assert_return (invoke "select-i64-t" (i64.const 2) (i64.const 1) (i32.const -1)) (i64.const 2)) +(assert_return (invoke "select-i64-t" (i64.const 2) (i64.const 1) (i32.const 0xf0f0f0f0)) (i64.const 2)) +(assert_return (invoke "select-externref" (ref.extern 1) (ref.extern 2) (i32.const 0)) (ref.extern 2)) +(assert_return (invoke "select-externref" (ref.extern 2) (ref.extern 1) (i32.const 0)) (ref.extern 1)) + +(assert_return (invoke "select-f32-t" (f32.const nan) (f32.const 1) (i32.const 1)) (f32.const nan)) +(assert_return (invoke "select-f32-t" (f32.const nan:0x20304) (f32.const 1) (i32.const 1)) (f32.const nan:0x20304)) +(assert_return (invoke "select-f32-t" (f32.const nan) (f32.const 1) (i32.const 0)) (f32.const 1)) +(assert_return (invoke "select-f32-t" (f32.const nan:0x20304) (f32.const 1) (i32.const 0)) (f32.const 1)) +(assert_return (invoke "select-f32-t" (f32.const 2) (f32.const nan) (i32.const 1)) (f32.const 2)) +(assert_return (invoke "select-f32-t" (f32.const 2) (f32.const nan:0x20304) (i32.const 1)) (f32.const 2)) +(assert_return (invoke "select-f32-t" (f32.const 2) (f32.const nan) (i32.const 0)) (f32.const nan)) +(assert_return (invoke "select-f32-t" (f32.const 2) (f32.const nan:0x20304) (i32.const 0)) (f32.const nan:0x20304)) + +(assert_return (invoke "select-f64-t" (f64.const nan) (f64.const 1) (i32.const 1)) (f64.const nan)) +(assert_return (invoke "select-f64-t" (f64.const nan:0x20304) (f64.const 1) (i32.const 1)) (f64.const nan:0x20304)) +(assert_return (invoke "select-f64-t" (f64.const nan) (f64.const 1) (i32.const 0)) (f64.const 1)) +(assert_return (invoke "select-f64-t" (f64.const nan:0x20304) (f64.const 1) (i32.const 0)) (f64.const 1)) +(assert_return (invoke "select-f64-t" (f64.const 2) (f64.const nan) (i32.const 1)) (f64.const 2)) +(assert_return (invoke "select-f64-t" (f64.const 2) (f64.const nan:0x20304) (i32.const 1)) (f64.const 2)) +(assert_return (invoke "select-f64-t" (f64.const 2) (f64.const nan) (i32.const 0)) (f64.const nan)) +(assert_return (invoke "select-f64-t" (f64.const 2) (f64.const nan:0x20304) (i32.const 0)) (f64.const nan:0x20304)) + +(assert_trap (invoke "select-trap-left" (i32.const 1)) "unreachable") +(assert_trap (invoke "select-trap-left" (i32.const 0)) "unreachable") +(assert_trap (invoke "select-trap-right" (i32.const 1)) "unreachable") +(assert_trap (invoke "select-trap-right" (i32.const 0)) "unreachable") (assert_return (invoke "as-select-first" (i32.const 0)) (i32.const 1)) (assert_return (invoke "as-select-first" (i32.const 1)) (i32.const 0)) @@ -251,7 +315,7 @@ (assert_return (invoke "as-br_table-last" (i32.const 1)) (i32.const 2)) (assert_return (invoke "as-call_indirect-first" (i32.const 0)) (i32.const 3)) -(assert_return (invoke "as-call_indirect-first" (i32.const 1)) (i32.const 2)) +;;(assert_return (invoke "as-call_indirect-first" (i32.const 1)) (i32.const 2)) (assert_return (invoke "as-call_indirect-mid" (i32.const 0)) (i32.const 1)) (assert_return (invoke "as-call_indirect-mid" (i32.const 1)) (i32.const 1)) (assert_trap (invoke "as-call_indirect-last" (i32.const 0)) "undefined element") @@ -296,12 +360,59 @@ (assert_return (invoke "as-convert-operand" (i32.const 1)) (i32.const 1)) (assert_invalid - (module (func $arity-0 (select (nop) (nop) (i32.const 1)) (drop))) + (module (func $arity-0-implicit (select (nop) (nop) (i32.const 1)))) + "type mismatch" +) +(assert_invalid + (module (func $arity-0 (select (result) (nop) (nop) (i32.const 1)))) + "invalid result arity" +) +(assert_invalid + (module (func $arity-2 (result i32 i32) + (select (result i32 i32) + (i32.const 0) (i32.const 0) + (i32.const 0) (i32.const 0) + (i32.const 1) + ) + )) + "invalid result arity" +) + + +(assert_invalid + (module (func $type-externref-implicit (param $r externref) + (drop (select (local.get $r) (local.get $r) (i32.const 1))) + )) "type mismatch" ) -;; The first two operands should have the same type as each other +(assert_invalid + (module (func $type-num-vs-num + (drop (select (i32.const 1) (i64.const 1) (i32.const 1))) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-num-vs-num + (drop (select (i32.const 1) (f32.const 1.0) (i32.const 1))) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-num-vs-num + (drop (select (i32.const 1) (f64.const 1.0) (i32.const 1))) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-num-vs-num (select (i32.const 1) (i64.const 1) (i32.const 1)) (drop))) + "type mismatch" +) +(assert_invalid + (module (func $type-num-vs-num (select (i32.const 1) (f32.const 1.0) (i32.const 1)) (drop))) + "type mismatch" +) (assert_invalid (module (func $type-num-vs-num (select (i32.const 1) (i64.const 1) (i32.const 1)) (drop))) "type mismatch" diff --git a/test/core/table-sub.wast b/test/core/table-sub.wast new file mode 100644 index 0000000000..08787bddd2 --- /dev/null +++ b/test/core/table-sub.wast @@ -0,0 +1,21 @@ +(assert_invalid + (module + (table $t1 10 funcref) + (table $t2 10 externref) + (func $f + (table.copy $t1 $t2 (i32.const 0) (i32.const 1) (i32.const 2)) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (table $t 10 funcref) + (elem $el externref) + (func $f + (table.init $t $el (i32.const 0) (i32.const 1) (i32.const 2)) + ) + ) + "type mismatch" +) diff --git a/test/core/table.wast b/test/core/table.wast index 0bc43ca60c..0bd04f5cc4 100644 --- a/test/core/table.wast +++ b/test/core/table.wast @@ -8,8 +8,8 @@ (module (table 0 65536 funcref)) (module (table 0 0xffff_ffff funcref)) -(assert_invalid (module (table 0 funcref) (table 0 funcref)) "multiple tables") -(assert_invalid (module (table (import "spectest" "table") 0 funcref) (table 0 funcref)) "multiple tables") +(module (table 0 funcref) (table 0 funcref)) +(module (table (import "spectest" "table") 0 funcref) (table 0 funcref)) (assert_invalid (module (elem (i32.const 0))) "unknown table") (assert_invalid (module (elem (i32.const 0) $f) (func $f)) "unknown table") diff --git a/test/core/table_copy.wast b/test/core/table_copy.wast new file mode 100644 index 0000000000..380e84ee59 --- /dev/null +++ b/test/core/table_copy.wast @@ -0,0 +1,3082 @@ +;; +;; Generated by ../meta/generate_table_copy.js +;; DO NOT EDIT THIS FILE. CHANGE THE SOURCE AND REGENERATE. +;; + +(module + (func (export "ef0") (result i32) (i32.const 0)) + (func (export "ef1") (result i32) (i32.const 1)) + (func (export "ef2") (result i32) (i32.const 2)) + (func (export "ef3") (result i32) (i32.const 3)) + (func (export "ef4") (result i32) (i32.const 4)) +) +(register "a") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (table $t1) (i32.const 3) func 1 3 1 4) + (elem (table $t1) (i32.const 11) func 6 3 2 5 7) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (nop)) + (func (export "check_t0") (param i32) (result i32) + (call_indirect $t0 (type 0) (local.get 0))) + (func (export "check_t1") (param i32) (result i32) + (call_indirect $t1 (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check_t0" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t0" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check_t0" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check_t0" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "check_t0" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "check_t0" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "check_t0" (i32.const 15)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 16)) (i32.const 6)) +(assert_trap (invoke "check_t0" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 2)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 4)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 6)) (i32.const 4)) +(assert_trap (invoke "check_t1" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 10)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 11)) (i32.const 6)) +(assert_return (invoke "check_t1" (i32.const 12)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 13)) (i32.const 2)) +(assert_return (invoke "check_t1" (i32.const 14)) (i32.const 5)) +(assert_return (invoke "check_t1" (i32.const 15)) (i32.const 7)) +(assert_trap (invoke "check_t1" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (table $t1) (i32.const 3) func 1 3 1 4) + (elem (table $t1) (i32.const 11) func 6 3 2 5 7) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.copy $t0 $t0 (i32.const 13) (i32.const 2) (i32.const 3))) + (func (export "check_t0") (param i32) (result i32) + (call_indirect $t0 (type 0) (local.get 0))) + (func (export "check_t1") (param i32) (result i32) + (call_indirect $t1 (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check_t0" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t0" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check_t0" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check_t0" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "check_t0" (i32.const 13)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 14)) (i32.const 1)) +(assert_return (invoke "check_t0" (i32.const 15)) (i32.const 4)) +(assert_return (invoke "check_t0" (i32.const 16)) (i32.const 6)) +(assert_trap (invoke "check_t0" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 2)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 4)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 6)) (i32.const 4)) +(assert_trap (invoke "check_t1" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 10)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 11)) (i32.const 6)) +(assert_return (invoke "check_t1" (i32.const 12)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 13)) (i32.const 2)) +(assert_return (invoke "check_t1" (i32.const 14)) (i32.const 5)) +(assert_return (invoke "check_t1" (i32.const 15)) (i32.const 7)) +(assert_trap (invoke "check_t1" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (table $t1) (i32.const 3) func 1 3 1 4) + (elem (table $t1) (i32.const 11) func 6 3 2 5 7) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.copy $t0 $t0 (i32.const 25) (i32.const 15) (i32.const 2))) + (func (export "check_t0") (param i32) (result i32) + (call_indirect $t0 (type 0) (local.get 0))) + (func (export "check_t1") (param i32) (result i32) + (call_indirect $t1 (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check_t0" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t0" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check_t0" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check_t0" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "check_t0" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "check_t0" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "check_t0" (i32.const 15)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 16)) (i32.const 6)) +(assert_trap (invoke "check_t0" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 24)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 25)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 26)) (i32.const 6)) +(assert_trap (invoke "check_t0" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 2)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 4)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 6)) (i32.const 4)) +(assert_trap (invoke "check_t1" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 10)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 11)) (i32.const 6)) +(assert_return (invoke "check_t1" (i32.const 12)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 13)) (i32.const 2)) +(assert_return (invoke "check_t1" (i32.const 14)) (i32.const 5)) +(assert_return (invoke "check_t1" (i32.const 15)) (i32.const 7)) +(assert_trap (invoke "check_t1" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (table $t1) (i32.const 3) func 1 3 1 4) + (elem (table $t1) (i32.const 11) func 6 3 2 5 7) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.copy $t0 $t0 (i32.const 13) (i32.const 25) (i32.const 3))) + (func (export "check_t0") (param i32) (result i32) + (call_indirect $t0 (type 0) (local.get 0))) + (func (export "check_t1") (param i32) (result i32) + (call_indirect $t1 (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check_t0" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t0" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check_t0" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check_t0" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 12)) (i32.const 7)) +(assert_trap (invoke "check_t0" (i32.const 13)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 14)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 15)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 16)) (i32.const 6)) +(assert_trap (invoke "check_t0" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 2)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 4)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 6)) (i32.const 4)) +(assert_trap (invoke "check_t1" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 10)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 11)) (i32.const 6)) +(assert_return (invoke "check_t1" (i32.const 12)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 13)) (i32.const 2)) +(assert_return (invoke "check_t1" (i32.const 14)) (i32.const 5)) +(assert_return (invoke "check_t1" (i32.const 15)) (i32.const 7)) +(assert_trap (invoke "check_t1" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (table $t1) (i32.const 3) func 1 3 1 4) + (elem (table $t1) (i32.const 11) func 6 3 2 5 7) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.copy $t0 $t0 (i32.const 20) (i32.const 22) (i32.const 4))) + (func (export "check_t0") (param i32) (result i32) + (call_indirect $t0 (type 0) (local.get 0))) + (func (export "check_t1") (param i32) (result i32) + (call_indirect $t1 (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check_t0" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t0" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check_t0" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check_t0" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "check_t0" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "check_t0" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "check_t0" (i32.const 15)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 16)) (i32.const 6)) +(assert_trap (invoke "check_t0" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 2)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 4)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 6)) (i32.const 4)) +(assert_trap (invoke "check_t1" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 10)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 11)) (i32.const 6)) +(assert_return (invoke "check_t1" (i32.const 12)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 13)) (i32.const 2)) +(assert_return (invoke "check_t1" (i32.const 14)) (i32.const 5)) +(assert_return (invoke "check_t1" (i32.const 15)) (i32.const 7)) +(assert_trap (invoke "check_t1" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (table $t1) (i32.const 3) func 1 3 1 4) + (elem (table $t1) (i32.const 11) func 6 3 2 5 7) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.copy $t0 $t0 (i32.const 25) (i32.const 1) (i32.const 3))) + (func (export "check_t0") (param i32) (result i32) + (call_indirect $t0 (type 0) (local.get 0))) + (func (export "check_t1") (param i32) (result i32) + (call_indirect $t1 (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check_t0" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t0" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check_t0" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check_t0" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "check_t0" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "check_t0" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "check_t0" (i32.const 15)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 16)) (i32.const 6)) +(assert_trap (invoke "check_t0" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 25)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 26)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 27)) (i32.const 1)) +(assert_trap (invoke "check_t0" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 2)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 4)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 6)) (i32.const 4)) +(assert_trap (invoke "check_t1" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 10)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 11)) (i32.const 6)) +(assert_return (invoke "check_t1" (i32.const 12)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 13)) (i32.const 2)) +(assert_return (invoke "check_t1" (i32.const 14)) (i32.const 5)) +(assert_return (invoke "check_t1" (i32.const 15)) (i32.const 7)) +(assert_trap (invoke "check_t1" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (table $t1) (i32.const 3) func 1 3 1 4) + (elem (table $t1) (i32.const 11) func 6 3 2 5 7) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.copy $t0 $t0 (i32.const 10) (i32.const 12) (i32.const 7))) + (func (export "check_t0") (param i32) (result i32) + (call_indirect $t0 (type 0) (local.get 0))) + (func (export "check_t1") (param i32) (result i32) + (call_indirect $t1 (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check_t0" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t0" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check_t0" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check_t0" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 9)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 10)) (i32.const 7)) +(assert_return (invoke "check_t0" (i32.const 11)) (i32.const 5)) +(assert_return (invoke "check_t0" (i32.const 12)) (i32.const 2)) +(assert_return (invoke "check_t0" (i32.const 13)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 14)) (i32.const 6)) +(assert_trap (invoke "check_t0" (i32.const 15)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 2)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 4)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 6)) (i32.const 4)) +(assert_trap (invoke "check_t1" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 10)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 11)) (i32.const 6)) +(assert_return (invoke "check_t1" (i32.const 12)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 13)) (i32.const 2)) +(assert_return (invoke "check_t1" (i32.const 14)) (i32.const 5)) +(assert_return (invoke "check_t1" (i32.const 15)) (i32.const 7)) +(assert_trap (invoke "check_t1" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (table $t1) (i32.const 3) func 1 3 1 4) + (elem (table $t1) (i32.const 11) func 6 3 2 5 7) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.copy $t0 $t0 (i32.const 12) (i32.const 10) (i32.const 7))) + (func (export "check_t0") (param i32) (result i32) + (call_indirect $t0 (type 0) (local.get 0))) + (func (export "check_t1") (param i32) (result i32) + (call_indirect $t1 (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check_t0" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t0" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check_t0" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check_t0" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 11)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 12)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 13)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 14)) (i32.const 7)) +(assert_return (invoke "check_t0" (i32.const 15)) (i32.const 5)) +(assert_return (invoke "check_t0" (i32.const 16)) (i32.const 2)) +(assert_return (invoke "check_t0" (i32.const 17)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 18)) (i32.const 6)) +(assert_trap (invoke "check_t0" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 2)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 4)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 6)) (i32.const 4)) +(assert_trap (invoke "check_t1" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 10)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 11)) (i32.const 6)) +(assert_return (invoke "check_t1" (i32.const 12)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 13)) (i32.const 2)) +(assert_return (invoke "check_t1" (i32.const 14)) (i32.const 5)) +(assert_return (invoke "check_t1" (i32.const 15)) (i32.const 7)) +(assert_trap (invoke "check_t1" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (table $t1) (i32.const 3) func 1 3 1 4) + (elem (table $t1) (i32.const 11) func 6 3 2 5 7) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.copy $t1 $t0 (i32.const 10) (i32.const 0) (i32.const 20))) + (func (export "check_t0") (param i32) (result i32) + (call_indirect $t0 (type 0) (local.get 0))) + (func (export "check_t1") (param i32) (result i32) + (call_indirect $t1 (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check_t0" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t0" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check_t0" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check_t0" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "check_t0" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "check_t0" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "check_t0" (i32.const 15)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 16)) (i32.const 6)) +(assert_trap (invoke "check_t0" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 2)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 4)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 6)) (i32.const 4)) +(assert_trap (invoke "check_t1" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 12)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 13)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 14)) (i32.const 4)) +(assert_return (invoke "check_t1" (i32.const 15)) (i32.const 1)) +(assert_trap (invoke "check_t1" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 21)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 22)) (i32.const 7)) +(assert_return (invoke "check_t1" (i32.const 23)) (i32.const 5)) +(assert_return (invoke "check_t1" (i32.const 24)) (i32.const 2)) +(assert_return (invoke "check_t1" (i32.const 25)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 26)) (i32.const 6)) +(assert_trap (invoke "check_t1" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (table $t0) (i32.const 3) func 1 3 1 4) + (elem (table $t0) (i32.const 11) func 6 3 2 5 7) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (nop)) + (func (export "check_t0") (param i32) (result i32) + (call_indirect $t1 (type 0) (local.get 0))) + (func (export "check_t1") (param i32) (result i32) + (call_indirect $t0 (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check_t0" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t0" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check_t0" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check_t0" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "check_t0" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "check_t0" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "check_t0" (i32.const 15)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 16)) (i32.const 6)) +(assert_trap (invoke "check_t0" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 2)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 4)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 6)) (i32.const 4)) +(assert_trap (invoke "check_t1" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 10)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 11)) (i32.const 6)) +(assert_return (invoke "check_t1" (i32.const 12)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 13)) (i32.const 2)) +(assert_return (invoke "check_t1" (i32.const 14)) (i32.const 5)) +(assert_return (invoke "check_t1" (i32.const 15)) (i32.const 7)) +(assert_trap (invoke "check_t1" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (table $t0) (i32.const 3) func 1 3 1 4) + (elem (table $t0) (i32.const 11) func 6 3 2 5 7) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.copy $t1 $t1 (i32.const 13) (i32.const 2) (i32.const 3))) + (func (export "check_t0") (param i32) (result i32) + (call_indirect $t1 (type 0) (local.get 0))) + (func (export "check_t1") (param i32) (result i32) + (call_indirect $t0 (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check_t0" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t0" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check_t0" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check_t0" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "check_t0" (i32.const 13)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 14)) (i32.const 1)) +(assert_return (invoke "check_t0" (i32.const 15)) (i32.const 4)) +(assert_return (invoke "check_t0" (i32.const 16)) (i32.const 6)) +(assert_trap (invoke "check_t0" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 2)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 4)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 6)) (i32.const 4)) +(assert_trap (invoke "check_t1" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 10)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 11)) (i32.const 6)) +(assert_return (invoke "check_t1" (i32.const 12)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 13)) (i32.const 2)) +(assert_return (invoke "check_t1" (i32.const 14)) (i32.const 5)) +(assert_return (invoke "check_t1" (i32.const 15)) (i32.const 7)) +(assert_trap (invoke "check_t1" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (table $t0) (i32.const 3) func 1 3 1 4) + (elem (table $t0) (i32.const 11) func 6 3 2 5 7) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.copy $t1 $t1 (i32.const 25) (i32.const 15) (i32.const 2))) + (func (export "check_t0") (param i32) (result i32) + (call_indirect $t1 (type 0) (local.get 0))) + (func (export "check_t1") (param i32) (result i32) + (call_indirect $t0 (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check_t0" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t0" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check_t0" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check_t0" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "check_t0" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "check_t0" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "check_t0" (i32.const 15)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 16)) (i32.const 6)) +(assert_trap (invoke "check_t0" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 24)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 25)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 26)) (i32.const 6)) +(assert_trap (invoke "check_t0" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 2)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 4)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 6)) (i32.const 4)) +(assert_trap (invoke "check_t1" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 10)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 11)) (i32.const 6)) +(assert_return (invoke "check_t1" (i32.const 12)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 13)) (i32.const 2)) +(assert_return (invoke "check_t1" (i32.const 14)) (i32.const 5)) +(assert_return (invoke "check_t1" (i32.const 15)) (i32.const 7)) +(assert_trap (invoke "check_t1" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (table $t0) (i32.const 3) func 1 3 1 4) + (elem (table $t0) (i32.const 11) func 6 3 2 5 7) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.copy $t1 $t1 (i32.const 13) (i32.const 25) (i32.const 3))) + (func (export "check_t0") (param i32) (result i32) + (call_indirect $t1 (type 0) (local.get 0))) + (func (export "check_t1") (param i32) (result i32) + (call_indirect $t0 (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check_t0" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t0" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check_t0" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check_t0" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 12)) (i32.const 7)) +(assert_trap (invoke "check_t0" (i32.const 13)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 14)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 15)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 16)) (i32.const 6)) +(assert_trap (invoke "check_t0" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 2)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 4)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 6)) (i32.const 4)) +(assert_trap (invoke "check_t1" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 10)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 11)) (i32.const 6)) +(assert_return (invoke "check_t1" (i32.const 12)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 13)) (i32.const 2)) +(assert_return (invoke "check_t1" (i32.const 14)) (i32.const 5)) +(assert_return (invoke "check_t1" (i32.const 15)) (i32.const 7)) +(assert_trap (invoke "check_t1" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (table $t0) (i32.const 3) func 1 3 1 4) + (elem (table $t0) (i32.const 11) func 6 3 2 5 7) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.copy $t1 $t1 (i32.const 20) (i32.const 22) (i32.const 4))) + (func (export "check_t0") (param i32) (result i32) + (call_indirect $t1 (type 0) (local.get 0))) + (func (export "check_t1") (param i32) (result i32) + (call_indirect $t0 (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check_t0" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t0" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check_t0" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check_t0" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "check_t0" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "check_t0" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "check_t0" (i32.const 15)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 16)) (i32.const 6)) +(assert_trap (invoke "check_t0" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 2)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 4)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 6)) (i32.const 4)) +(assert_trap (invoke "check_t1" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 10)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 11)) (i32.const 6)) +(assert_return (invoke "check_t1" (i32.const 12)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 13)) (i32.const 2)) +(assert_return (invoke "check_t1" (i32.const 14)) (i32.const 5)) +(assert_return (invoke "check_t1" (i32.const 15)) (i32.const 7)) +(assert_trap (invoke "check_t1" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (table $t0) (i32.const 3) func 1 3 1 4) + (elem (table $t0) (i32.const 11) func 6 3 2 5 7) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.copy $t1 $t1 (i32.const 25) (i32.const 1) (i32.const 3))) + (func (export "check_t0") (param i32) (result i32) + (call_indirect $t1 (type 0) (local.get 0))) + (func (export "check_t1") (param i32) (result i32) + (call_indirect $t0 (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check_t0" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t0" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check_t0" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check_t0" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "check_t0" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "check_t0" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "check_t0" (i32.const 15)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 16)) (i32.const 6)) +(assert_trap (invoke "check_t0" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 25)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 26)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 27)) (i32.const 1)) +(assert_trap (invoke "check_t0" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 2)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 4)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 6)) (i32.const 4)) +(assert_trap (invoke "check_t1" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 10)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 11)) (i32.const 6)) +(assert_return (invoke "check_t1" (i32.const 12)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 13)) (i32.const 2)) +(assert_return (invoke "check_t1" (i32.const 14)) (i32.const 5)) +(assert_return (invoke "check_t1" (i32.const 15)) (i32.const 7)) +(assert_trap (invoke "check_t1" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (table $t0) (i32.const 3) func 1 3 1 4) + (elem (table $t0) (i32.const 11) func 6 3 2 5 7) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.copy $t1 $t1 (i32.const 10) (i32.const 12) (i32.const 7))) + (func (export "check_t0") (param i32) (result i32) + (call_indirect $t1 (type 0) (local.get 0))) + (func (export "check_t1") (param i32) (result i32) + (call_indirect $t0 (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check_t0" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t0" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check_t0" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check_t0" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 9)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 10)) (i32.const 7)) +(assert_return (invoke "check_t0" (i32.const 11)) (i32.const 5)) +(assert_return (invoke "check_t0" (i32.const 12)) (i32.const 2)) +(assert_return (invoke "check_t0" (i32.const 13)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 14)) (i32.const 6)) +(assert_trap (invoke "check_t0" (i32.const 15)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 2)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 4)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 6)) (i32.const 4)) +(assert_trap (invoke "check_t1" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 10)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 11)) (i32.const 6)) +(assert_return (invoke "check_t1" (i32.const 12)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 13)) (i32.const 2)) +(assert_return (invoke "check_t1" (i32.const 14)) (i32.const 5)) +(assert_return (invoke "check_t1" (i32.const 15)) (i32.const 7)) +(assert_trap (invoke "check_t1" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (table $t0) (i32.const 3) func 1 3 1 4) + (elem (table $t0) (i32.const 11) func 6 3 2 5 7) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.copy $t1 $t1 (i32.const 12) (i32.const 10) (i32.const 7))) + (func (export "check_t0") (param i32) (result i32) + (call_indirect $t1 (type 0) (local.get 0))) + (func (export "check_t1") (param i32) (result i32) + (call_indirect $t0 (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check_t0" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t0" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check_t0" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check_t0" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 11)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 12)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 13)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 14)) (i32.const 7)) +(assert_return (invoke "check_t0" (i32.const 15)) (i32.const 5)) +(assert_return (invoke "check_t0" (i32.const 16)) (i32.const 2)) +(assert_return (invoke "check_t0" (i32.const 17)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 18)) (i32.const 6)) +(assert_trap (invoke "check_t0" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 2)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 4)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 6)) (i32.const 4)) +(assert_trap (invoke "check_t1" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 10)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 11)) (i32.const 6)) +(assert_return (invoke "check_t1" (i32.const 12)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 13)) (i32.const 2)) +(assert_return (invoke "check_t1" (i32.const 14)) (i32.const 5)) +(assert_return (invoke "check_t1" (i32.const 15)) (i32.const 7)) +(assert_trap (invoke "check_t1" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (table $t0) (i32.const 3) func 1 3 1 4) + (elem (table $t0) (i32.const 11) func 6 3 2 5 7) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.copy $t0 $t1 (i32.const 10) (i32.const 0) (i32.const 20))) + (func (export "check_t0") (param i32) (result i32) + (call_indirect $t1 (type 0) (local.get 0))) + (func (export "check_t1") (param i32) (result i32) + (call_indirect $t0 (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check_t0" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t0" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check_t0" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check_t0" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "check_t0" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "check_t0" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "check_t0" (i32.const 15)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 16)) (i32.const 6)) +(assert_trap (invoke "check_t0" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 2)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 4)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 6)) (i32.const 4)) +(assert_trap (invoke "check_t1" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 12)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 13)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 14)) (i32.const 4)) +(assert_return (invoke "check_t1" (i32.const 15)) (i32.const 1)) +(assert_trap (invoke "check_t1" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 21)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 22)) (i32.const 7)) +(assert_return (invoke "check_t1" (i32.const 23)) (i32.const 5)) +(assert_return (invoke "check_t1" (i32.const 24)) (i32.const 2)) +(assert_return (invoke "check_t1" (i32.const 25)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 26)) (i32.const 6)) +(assert_trap (invoke "check_t1" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 29)) "uninitialized element") + +(module + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy $t0 $t0 (i32.const 28) (i32.const 1) (i32.const 3)) + )) + +(assert_trap (invoke "test") "out of bounds table access") + +(module + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy $t0 $t0 (i32.const 0xFFFFFFFE) (i32.const 1) (i32.const 2)) + )) + +(assert_trap (invoke "test") "out of bounds table access") + +(module + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy $t0 $t0 (i32.const 15) (i32.const 25) (i32.const 6)) + )) + +(assert_trap (invoke "test") "out of bounds table access") + +(module + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy $t0 $t0 (i32.const 15) (i32.const 0xFFFFFFFE) (i32.const 2)) + )) + +(assert_trap (invoke "test") "out of bounds table access") + +(module + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy $t0 $t0 (i32.const 15) (i32.const 25) (i32.const 0)) + )) + +(invoke "test") + +(module + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy $t0 $t0 (i32.const 30) (i32.const 15) (i32.const 0)) + )) + +(invoke "test") + +(module + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy $t0 $t0 (i32.const 31) (i32.const 15) (i32.const 0)) + )) + +(assert_trap (invoke "test") "out of bounds table access") + +(module + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy $t0 $t0 (i32.const 15) (i32.const 30) (i32.const 0)) + )) + +(invoke "test") + +(module + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy $t0 $t0 (i32.const 15) (i32.const 31) (i32.const 0)) + )) + +(assert_trap (invoke "test") "out of bounds table access") + +(module + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy $t0 $t0 (i32.const 30) (i32.const 30) (i32.const 0)) + )) + +(invoke "test") + +(module + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy $t0 $t0 (i32.const 31) (i32.const 31) (i32.const 0)) + )) + +(assert_trap (invoke "test") "out of bounds table access") + +(module + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy $t1 $t0 (i32.const 28) (i32.const 1) (i32.const 3)) + )) + +(assert_trap (invoke "test") "out of bounds table access") + +(module + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy $t1 $t0 (i32.const 0xFFFFFFFE) (i32.const 1) (i32.const 2)) + )) + +(assert_trap (invoke "test") "out of bounds table access") + +(module + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy $t1 $t0 (i32.const 15) (i32.const 25) (i32.const 6)) + )) + +(assert_trap (invoke "test") "out of bounds table access") + +(module + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy $t1 $t0 (i32.const 15) (i32.const 0xFFFFFFFE) (i32.const 2)) + )) + +(assert_trap (invoke "test") "out of bounds table access") + +(module + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy $t1 $t0 (i32.const 15) (i32.const 25) (i32.const 0)) + )) + +(invoke "test") + +(module + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy $t1 $t0 (i32.const 30) (i32.const 15) (i32.const 0)) + )) + +(invoke "test") + +(module + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy $t1 $t0 (i32.const 31) (i32.const 15) (i32.const 0)) + )) + +(assert_trap (invoke "test") "out of bounds table access") + +(module + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy $t1 $t0 (i32.const 15) (i32.const 30) (i32.const 0)) + )) + +(invoke "test") + +(module + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy $t1 $t0 (i32.const 15) (i32.const 31) (i32.const 0)) + )) + +(assert_trap (invoke "test") "out of bounds table access") + +(module + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy $t1 $t0 (i32.const 30) (i32.const 30) (i32.const 0)) + )) + +(invoke "test") + +(module + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy $t1 $t0 (i32.const 31) (i32.const 31) (i32.const 0)) + )) + +(assert_trap (invoke "test") "out of bounds table access") + +(module + (type (func (result i32))) + (table 32 64 funcref) + (elem (i32.const 0) + $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7) + (func $f0 (export "f0") (result i32) (i32.const 0)) + (func $f1 (export "f1") (result i32) (i32.const 1)) + (func $f2 (export "f2") (result i32) (i32.const 2)) + (func $f3 (export "f3") (result i32) (i32.const 3)) + (func $f4 (export "f4") (result i32) (i32.const 4)) + (func $f5 (export "f5") (result i32) (i32.const 5)) + (func $f6 (export "f6") (result i32) (i32.const 6)) + (func $f7 (export "f7") (result i32) (i32.const 7)) + (func $f8 (export "f8") (result i32) (i32.const 8)) + (func $f9 (export "f9") (result i32) (i32.const 9)) + (func $f10 (export "f10") (result i32) (i32.const 10)) + (func $f11 (export "f11") (result i32) (i32.const 11)) + (func $f12 (export "f12") (result i32) (i32.const 12)) + (func $f13 (export "f13") (result i32) (i32.const 13)) + (func $f14 (export "f14") (result i32) (i32.const 14)) + (func $f15 (export "f15") (result i32) (i32.const 15)) + (func (export "test") (param $n i32) (result i32) + (call_indirect (type 0) (local.get $n))) + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))) + +(assert_trap (invoke "run" (i32.const 24) (i32.const 0) (i32.const 16)) + "out of bounds table access") +(assert_return (invoke "test" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "test" (i32.const 1)) (i32.const 1)) +(assert_return (invoke "test" (i32.const 2)) (i32.const 2)) +(assert_return (invoke "test" (i32.const 3)) (i32.const 3)) +(assert_return (invoke "test" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "test" (i32.const 5)) (i32.const 5)) +(assert_return (invoke "test" (i32.const 6)) (i32.const 6)) +(assert_return (invoke "test" (i32.const 7)) (i32.const 7)) +(assert_trap (invoke "test" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 11)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 12)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 13)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 14)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 15)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 30)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 31)) "uninitialized element") + +(module + (type (func (result i32))) + (table 32 64 funcref) + (elem (i32.const 0) + $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8) + (func $f0 (export "f0") (result i32) (i32.const 0)) + (func $f1 (export "f1") (result i32) (i32.const 1)) + (func $f2 (export "f2") (result i32) (i32.const 2)) + (func $f3 (export "f3") (result i32) (i32.const 3)) + (func $f4 (export "f4") (result i32) (i32.const 4)) + (func $f5 (export "f5") (result i32) (i32.const 5)) + (func $f6 (export "f6") (result i32) (i32.const 6)) + (func $f7 (export "f7") (result i32) (i32.const 7)) + (func $f8 (export "f8") (result i32) (i32.const 8)) + (func $f9 (export "f9") (result i32) (i32.const 9)) + (func $f10 (export "f10") (result i32) (i32.const 10)) + (func $f11 (export "f11") (result i32) (i32.const 11)) + (func $f12 (export "f12") (result i32) (i32.const 12)) + (func $f13 (export "f13") (result i32) (i32.const 13)) + (func $f14 (export "f14") (result i32) (i32.const 14)) + (func $f15 (export "f15") (result i32) (i32.const 15)) + (func (export "test") (param $n i32) (result i32) + (call_indirect (type 0) (local.get $n))) + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))) + +(assert_trap (invoke "run" (i32.const 23) (i32.const 0) (i32.const 15)) + "out of bounds table access") +(assert_return (invoke "test" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "test" (i32.const 1)) (i32.const 1)) +(assert_return (invoke "test" (i32.const 2)) (i32.const 2)) +(assert_return (invoke "test" (i32.const 3)) (i32.const 3)) +(assert_return (invoke "test" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "test" (i32.const 5)) (i32.const 5)) +(assert_return (invoke "test" (i32.const 6)) (i32.const 6)) +(assert_return (invoke "test" (i32.const 7)) (i32.const 7)) +(assert_return (invoke "test" (i32.const 8)) (i32.const 8)) +(assert_trap (invoke "test" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 11)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 12)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 13)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 14)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 15)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 30)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 31)) "uninitialized element") + +(module + (type (func (result i32))) + (table 32 64 funcref) + (elem (i32.const 24) + $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7) + (func $f0 (export "f0") (result i32) (i32.const 0)) + (func $f1 (export "f1") (result i32) (i32.const 1)) + (func $f2 (export "f2") (result i32) (i32.const 2)) + (func $f3 (export "f3") (result i32) (i32.const 3)) + (func $f4 (export "f4") (result i32) (i32.const 4)) + (func $f5 (export "f5") (result i32) (i32.const 5)) + (func $f6 (export "f6") (result i32) (i32.const 6)) + (func $f7 (export "f7") (result i32) (i32.const 7)) + (func $f8 (export "f8") (result i32) (i32.const 8)) + (func $f9 (export "f9") (result i32) (i32.const 9)) + (func $f10 (export "f10") (result i32) (i32.const 10)) + (func $f11 (export "f11") (result i32) (i32.const 11)) + (func $f12 (export "f12") (result i32) (i32.const 12)) + (func $f13 (export "f13") (result i32) (i32.const 13)) + (func $f14 (export "f14") (result i32) (i32.const 14)) + (func $f15 (export "f15") (result i32) (i32.const 15)) + (func (export "test") (param $n i32) (result i32) + (call_indirect (type 0) (local.get $n))) + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))) + +(assert_trap (invoke "run" (i32.const 0) (i32.const 24) (i32.const 16)) + "out of bounds table access") +(assert_trap (invoke "test" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 2)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 3)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 4)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 5)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 11)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 12)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 13)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 14)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 15)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 23)) "uninitialized element") +(assert_return (invoke "test" (i32.const 24)) (i32.const 0)) +(assert_return (invoke "test" (i32.const 25)) (i32.const 1)) +(assert_return (invoke "test" (i32.const 26)) (i32.const 2)) +(assert_return (invoke "test" (i32.const 27)) (i32.const 3)) +(assert_return (invoke "test" (i32.const 28)) (i32.const 4)) +(assert_return (invoke "test" (i32.const 29)) (i32.const 5)) +(assert_return (invoke "test" (i32.const 30)) (i32.const 6)) +(assert_return (invoke "test" (i32.const 31)) (i32.const 7)) + +(module + (type (func (result i32))) + (table 32 64 funcref) + (elem (i32.const 23) + $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8) + (func $f0 (export "f0") (result i32) (i32.const 0)) + (func $f1 (export "f1") (result i32) (i32.const 1)) + (func $f2 (export "f2") (result i32) (i32.const 2)) + (func $f3 (export "f3") (result i32) (i32.const 3)) + (func $f4 (export "f4") (result i32) (i32.const 4)) + (func $f5 (export "f5") (result i32) (i32.const 5)) + (func $f6 (export "f6") (result i32) (i32.const 6)) + (func $f7 (export "f7") (result i32) (i32.const 7)) + (func $f8 (export "f8") (result i32) (i32.const 8)) + (func $f9 (export "f9") (result i32) (i32.const 9)) + (func $f10 (export "f10") (result i32) (i32.const 10)) + (func $f11 (export "f11") (result i32) (i32.const 11)) + (func $f12 (export "f12") (result i32) (i32.const 12)) + (func $f13 (export "f13") (result i32) (i32.const 13)) + (func $f14 (export "f14") (result i32) (i32.const 14)) + (func $f15 (export "f15") (result i32) (i32.const 15)) + (func (export "test") (param $n i32) (result i32) + (call_indirect (type 0) (local.get $n))) + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))) + +(assert_trap (invoke "run" (i32.const 0) (i32.const 23) (i32.const 15)) + "out of bounds table access") +(assert_trap (invoke "test" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 2)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 3)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 4)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 5)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 11)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 12)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 13)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 14)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 15)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 22)) "uninitialized element") +(assert_return (invoke "test" (i32.const 23)) (i32.const 0)) +(assert_return (invoke "test" (i32.const 24)) (i32.const 1)) +(assert_return (invoke "test" (i32.const 25)) (i32.const 2)) +(assert_return (invoke "test" (i32.const 26)) (i32.const 3)) +(assert_return (invoke "test" (i32.const 27)) (i32.const 4)) +(assert_return (invoke "test" (i32.const 28)) (i32.const 5)) +(assert_return (invoke "test" (i32.const 29)) (i32.const 6)) +(assert_return (invoke "test" (i32.const 30)) (i32.const 7)) +(assert_return (invoke "test" (i32.const 31)) (i32.const 8)) + +(module + (type (func (result i32))) + (table 32 64 funcref) + (elem (i32.const 11) + $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7) + (func $f0 (export "f0") (result i32) (i32.const 0)) + (func $f1 (export "f1") (result i32) (i32.const 1)) + (func $f2 (export "f2") (result i32) (i32.const 2)) + (func $f3 (export "f3") (result i32) (i32.const 3)) + (func $f4 (export "f4") (result i32) (i32.const 4)) + (func $f5 (export "f5") (result i32) (i32.const 5)) + (func $f6 (export "f6") (result i32) (i32.const 6)) + (func $f7 (export "f7") (result i32) (i32.const 7)) + (func $f8 (export "f8") (result i32) (i32.const 8)) + (func $f9 (export "f9") (result i32) (i32.const 9)) + (func $f10 (export "f10") (result i32) (i32.const 10)) + (func $f11 (export "f11") (result i32) (i32.const 11)) + (func $f12 (export "f12") (result i32) (i32.const 12)) + (func $f13 (export "f13") (result i32) (i32.const 13)) + (func $f14 (export "f14") (result i32) (i32.const 14)) + (func $f15 (export "f15") (result i32) (i32.const 15)) + (func (export "test") (param $n i32) (result i32) + (call_indirect (type 0) (local.get $n))) + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))) + +(assert_trap (invoke "run" (i32.const 24) (i32.const 11) (i32.const 16)) + "out of bounds table access") +(assert_trap (invoke "test" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 2)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 3)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 4)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 5)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 10)) "uninitialized element") +(assert_return (invoke "test" (i32.const 11)) (i32.const 0)) +(assert_return (invoke "test" (i32.const 12)) (i32.const 1)) +(assert_return (invoke "test" (i32.const 13)) (i32.const 2)) +(assert_return (invoke "test" (i32.const 14)) (i32.const 3)) +(assert_return (invoke "test" (i32.const 15)) (i32.const 4)) +(assert_return (invoke "test" (i32.const 16)) (i32.const 5)) +(assert_return (invoke "test" (i32.const 17)) (i32.const 6)) +(assert_return (invoke "test" (i32.const 18)) (i32.const 7)) +(assert_trap (invoke "test" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 30)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 31)) "uninitialized element") + +(module + (type (func (result i32))) + (table 32 64 funcref) + (elem (i32.const 24) + $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7) + (func $f0 (export "f0") (result i32) (i32.const 0)) + (func $f1 (export "f1") (result i32) (i32.const 1)) + (func $f2 (export "f2") (result i32) (i32.const 2)) + (func $f3 (export "f3") (result i32) (i32.const 3)) + (func $f4 (export "f4") (result i32) (i32.const 4)) + (func $f5 (export "f5") (result i32) (i32.const 5)) + (func $f6 (export "f6") (result i32) (i32.const 6)) + (func $f7 (export "f7") (result i32) (i32.const 7)) + (func $f8 (export "f8") (result i32) (i32.const 8)) + (func $f9 (export "f9") (result i32) (i32.const 9)) + (func $f10 (export "f10") (result i32) (i32.const 10)) + (func $f11 (export "f11") (result i32) (i32.const 11)) + (func $f12 (export "f12") (result i32) (i32.const 12)) + (func $f13 (export "f13") (result i32) (i32.const 13)) + (func $f14 (export "f14") (result i32) (i32.const 14)) + (func $f15 (export "f15") (result i32) (i32.const 15)) + (func (export "test") (param $n i32) (result i32) + (call_indirect (type 0) (local.get $n))) + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))) + +(assert_trap (invoke "run" (i32.const 11) (i32.const 24) (i32.const 16)) + "out of bounds table access") +(assert_trap (invoke "test" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 2)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 3)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 4)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 5)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 11)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 12)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 13)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 14)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 15)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 23)) "uninitialized element") +(assert_return (invoke "test" (i32.const 24)) (i32.const 0)) +(assert_return (invoke "test" (i32.const 25)) (i32.const 1)) +(assert_return (invoke "test" (i32.const 26)) (i32.const 2)) +(assert_return (invoke "test" (i32.const 27)) (i32.const 3)) +(assert_return (invoke "test" (i32.const 28)) (i32.const 4)) +(assert_return (invoke "test" (i32.const 29)) (i32.const 5)) +(assert_return (invoke "test" (i32.const 30)) (i32.const 6)) +(assert_return (invoke "test" (i32.const 31)) (i32.const 7)) + +(module + (type (func (result i32))) + (table 32 64 funcref) + (elem (i32.const 21) + $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7) + (func $f0 (export "f0") (result i32) (i32.const 0)) + (func $f1 (export "f1") (result i32) (i32.const 1)) + (func $f2 (export "f2") (result i32) (i32.const 2)) + (func $f3 (export "f3") (result i32) (i32.const 3)) + (func $f4 (export "f4") (result i32) (i32.const 4)) + (func $f5 (export "f5") (result i32) (i32.const 5)) + (func $f6 (export "f6") (result i32) (i32.const 6)) + (func $f7 (export "f7") (result i32) (i32.const 7)) + (func $f8 (export "f8") (result i32) (i32.const 8)) + (func $f9 (export "f9") (result i32) (i32.const 9)) + (func $f10 (export "f10") (result i32) (i32.const 10)) + (func $f11 (export "f11") (result i32) (i32.const 11)) + (func $f12 (export "f12") (result i32) (i32.const 12)) + (func $f13 (export "f13") (result i32) (i32.const 13)) + (func $f14 (export "f14") (result i32) (i32.const 14)) + (func $f15 (export "f15") (result i32) (i32.const 15)) + (func (export "test") (param $n i32) (result i32) + (call_indirect (type 0) (local.get $n))) + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))) + +(assert_trap (invoke "run" (i32.const 24) (i32.const 21) (i32.const 16)) + "out of bounds table access") +(assert_trap (invoke "test" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 2)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 3)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 4)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 5)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 11)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 12)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 13)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 14)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 15)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 20)) "uninitialized element") +(assert_return (invoke "test" (i32.const 21)) (i32.const 0)) +(assert_return (invoke "test" (i32.const 22)) (i32.const 1)) +(assert_return (invoke "test" (i32.const 23)) (i32.const 2)) +(assert_return (invoke "test" (i32.const 24)) (i32.const 3)) +(assert_return (invoke "test" (i32.const 25)) (i32.const 4)) +(assert_return (invoke "test" (i32.const 26)) (i32.const 5)) +(assert_return (invoke "test" (i32.const 27)) (i32.const 6)) +(assert_return (invoke "test" (i32.const 28)) (i32.const 7)) +(assert_trap (invoke "test" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 30)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 31)) "uninitialized element") + +(module + (type (func (result i32))) + (table 32 64 funcref) + (elem (i32.const 24) + $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7) + (func $f0 (export "f0") (result i32) (i32.const 0)) + (func $f1 (export "f1") (result i32) (i32.const 1)) + (func $f2 (export "f2") (result i32) (i32.const 2)) + (func $f3 (export "f3") (result i32) (i32.const 3)) + (func $f4 (export "f4") (result i32) (i32.const 4)) + (func $f5 (export "f5") (result i32) (i32.const 5)) + (func $f6 (export "f6") (result i32) (i32.const 6)) + (func $f7 (export "f7") (result i32) (i32.const 7)) + (func $f8 (export "f8") (result i32) (i32.const 8)) + (func $f9 (export "f9") (result i32) (i32.const 9)) + (func $f10 (export "f10") (result i32) (i32.const 10)) + (func $f11 (export "f11") (result i32) (i32.const 11)) + (func $f12 (export "f12") (result i32) (i32.const 12)) + (func $f13 (export "f13") (result i32) (i32.const 13)) + (func $f14 (export "f14") (result i32) (i32.const 14)) + (func $f15 (export "f15") (result i32) (i32.const 15)) + (func (export "test") (param $n i32) (result i32) + (call_indirect (type 0) (local.get $n))) + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))) + +(assert_trap (invoke "run" (i32.const 21) (i32.const 24) (i32.const 16)) + "out of bounds table access") +(assert_trap (invoke "test" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 2)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 3)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 4)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 5)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 11)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 12)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 13)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 14)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 15)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 23)) "uninitialized element") +(assert_return (invoke "test" (i32.const 24)) (i32.const 0)) +(assert_return (invoke "test" (i32.const 25)) (i32.const 1)) +(assert_return (invoke "test" (i32.const 26)) (i32.const 2)) +(assert_return (invoke "test" (i32.const 27)) (i32.const 3)) +(assert_return (invoke "test" (i32.const 28)) (i32.const 4)) +(assert_return (invoke "test" (i32.const 29)) (i32.const 5)) +(assert_return (invoke "test" (i32.const 30)) (i32.const 6)) +(assert_return (invoke "test" (i32.const 31)) (i32.const 7)) + +(module + (type (func (result i32))) + (table 32 64 funcref) + (elem (i32.const 21) + $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10) + (func $f0 (export "f0") (result i32) (i32.const 0)) + (func $f1 (export "f1") (result i32) (i32.const 1)) + (func $f2 (export "f2") (result i32) (i32.const 2)) + (func $f3 (export "f3") (result i32) (i32.const 3)) + (func $f4 (export "f4") (result i32) (i32.const 4)) + (func $f5 (export "f5") (result i32) (i32.const 5)) + (func $f6 (export "f6") (result i32) (i32.const 6)) + (func $f7 (export "f7") (result i32) (i32.const 7)) + (func $f8 (export "f8") (result i32) (i32.const 8)) + (func $f9 (export "f9") (result i32) (i32.const 9)) + (func $f10 (export "f10") (result i32) (i32.const 10)) + (func $f11 (export "f11") (result i32) (i32.const 11)) + (func $f12 (export "f12") (result i32) (i32.const 12)) + (func $f13 (export "f13") (result i32) (i32.const 13)) + (func $f14 (export "f14") (result i32) (i32.const 14)) + (func $f15 (export "f15") (result i32) (i32.const 15)) + (func (export "test") (param $n i32) (result i32) + (call_indirect (type 0) (local.get $n))) + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))) + +(assert_trap (invoke "run" (i32.const 21) (i32.const 21) (i32.const 16)) + "out of bounds table access") +(assert_trap (invoke "test" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 2)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 3)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 4)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 5)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 11)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 12)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 13)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 14)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 15)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 20)) "uninitialized element") +(assert_return (invoke "test" (i32.const 21)) (i32.const 0)) +(assert_return (invoke "test" (i32.const 22)) (i32.const 1)) +(assert_return (invoke "test" (i32.const 23)) (i32.const 2)) +(assert_return (invoke "test" (i32.const 24)) (i32.const 3)) +(assert_return (invoke "test" (i32.const 25)) (i32.const 4)) +(assert_return (invoke "test" (i32.const 26)) (i32.const 5)) +(assert_return (invoke "test" (i32.const 27)) (i32.const 6)) +(assert_return (invoke "test" (i32.const 28)) (i32.const 7)) +(assert_return (invoke "test" (i32.const 29)) (i32.const 8)) +(assert_return (invoke "test" (i32.const 30)) (i32.const 9)) +(assert_return (invoke "test" (i32.const 31)) (i32.const 10)) + +(module + (type (func (result i32))) + (table 128 128 funcref) + (elem (i32.const 112) + $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15) + (func $f0 (export "f0") (result i32) (i32.const 0)) + (func $f1 (export "f1") (result i32) (i32.const 1)) + (func $f2 (export "f2") (result i32) (i32.const 2)) + (func $f3 (export "f3") (result i32) (i32.const 3)) + (func $f4 (export "f4") (result i32) (i32.const 4)) + (func $f5 (export "f5") (result i32) (i32.const 5)) + (func $f6 (export "f6") (result i32) (i32.const 6)) + (func $f7 (export "f7") (result i32) (i32.const 7)) + (func $f8 (export "f8") (result i32) (i32.const 8)) + (func $f9 (export "f9") (result i32) (i32.const 9)) + (func $f10 (export "f10") (result i32) (i32.const 10)) + (func $f11 (export "f11") (result i32) (i32.const 11)) + (func $f12 (export "f12") (result i32) (i32.const 12)) + (func $f13 (export "f13") (result i32) (i32.const 13)) + (func $f14 (export "f14") (result i32) (i32.const 14)) + (func $f15 (export "f15") (result i32) (i32.const 15)) + (func (export "test") (param $n i32) (result i32) + (call_indirect (type 0) (local.get $n))) + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))) + +(assert_trap (invoke "run" (i32.const 0) (i32.const 112) (i32.const 4294967264)) + "out of bounds table access") +(assert_trap (invoke "test" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 2)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 3)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 4)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 5)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 11)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 12)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 13)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 14)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 15)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 30)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 31)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 32)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 33)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 34)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 35)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 36)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 37)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 38)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 39)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 40)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 41)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 42)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 43)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 44)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 45)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 46)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 47)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 48)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 49)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 50)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 51)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 52)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 53)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 54)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 55)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 56)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 57)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 58)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 59)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 60)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 61)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 62)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 63)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 64)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 65)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 66)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 67)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 68)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 69)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 70)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 71)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 72)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 73)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 74)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 75)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 76)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 77)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 78)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 79)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 80)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 81)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 82)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 83)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 84)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 85)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 86)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 87)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 88)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 89)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 90)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 91)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 92)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 93)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 94)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 95)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 96)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 97)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 98)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 99)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 100)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 101)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 102)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 103)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 104)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 105)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 106)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 107)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 108)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 109)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 110)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 111)) "uninitialized element") +(assert_return (invoke "test" (i32.const 112)) (i32.const 0)) +(assert_return (invoke "test" (i32.const 113)) (i32.const 1)) +(assert_return (invoke "test" (i32.const 114)) (i32.const 2)) +(assert_return (invoke "test" (i32.const 115)) (i32.const 3)) +(assert_return (invoke "test" (i32.const 116)) (i32.const 4)) +(assert_return (invoke "test" (i32.const 117)) (i32.const 5)) +(assert_return (invoke "test" (i32.const 118)) (i32.const 6)) +(assert_return (invoke "test" (i32.const 119)) (i32.const 7)) +(assert_return (invoke "test" (i32.const 120)) (i32.const 8)) +(assert_return (invoke "test" (i32.const 121)) (i32.const 9)) +(assert_return (invoke "test" (i32.const 122)) (i32.const 10)) +(assert_return (invoke "test" (i32.const 123)) (i32.const 11)) +(assert_return (invoke "test" (i32.const 124)) (i32.const 12)) +(assert_return (invoke "test" (i32.const 125)) (i32.const 13)) +(assert_return (invoke "test" (i32.const 126)) (i32.const 14)) +(assert_return (invoke "test" (i32.const 127)) (i32.const 15)) + +(module + (type (func (result i32))) + (table 128 128 funcref) + (elem (i32.const 0) + $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15) + (func $f0 (export "f0") (result i32) (i32.const 0)) + (func $f1 (export "f1") (result i32) (i32.const 1)) + (func $f2 (export "f2") (result i32) (i32.const 2)) + (func $f3 (export "f3") (result i32) (i32.const 3)) + (func $f4 (export "f4") (result i32) (i32.const 4)) + (func $f5 (export "f5") (result i32) (i32.const 5)) + (func $f6 (export "f6") (result i32) (i32.const 6)) + (func $f7 (export "f7") (result i32) (i32.const 7)) + (func $f8 (export "f8") (result i32) (i32.const 8)) + (func $f9 (export "f9") (result i32) (i32.const 9)) + (func $f10 (export "f10") (result i32) (i32.const 10)) + (func $f11 (export "f11") (result i32) (i32.const 11)) + (func $f12 (export "f12") (result i32) (i32.const 12)) + (func $f13 (export "f13") (result i32) (i32.const 13)) + (func $f14 (export "f14") (result i32) (i32.const 14)) + (func $f15 (export "f15") (result i32) (i32.const 15)) + (func (export "test") (param $n i32) (result i32) + (call_indirect (type 0) (local.get $n))) + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))) + +(assert_trap (invoke "run" (i32.const 112) (i32.const 0) (i32.const 4294967264)) + "out of bounds table access") +(assert_return (invoke "test" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "test" (i32.const 1)) (i32.const 1)) +(assert_return (invoke "test" (i32.const 2)) (i32.const 2)) +(assert_return (invoke "test" (i32.const 3)) (i32.const 3)) +(assert_return (invoke "test" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "test" (i32.const 5)) (i32.const 5)) +(assert_return (invoke "test" (i32.const 6)) (i32.const 6)) +(assert_return (invoke "test" (i32.const 7)) (i32.const 7)) +(assert_return (invoke "test" (i32.const 8)) (i32.const 8)) +(assert_return (invoke "test" (i32.const 9)) (i32.const 9)) +(assert_return (invoke "test" (i32.const 10)) (i32.const 10)) +(assert_return (invoke "test" (i32.const 11)) (i32.const 11)) +(assert_return (invoke "test" (i32.const 12)) (i32.const 12)) +(assert_return (invoke "test" (i32.const 13)) (i32.const 13)) +(assert_return (invoke "test" (i32.const 14)) (i32.const 14)) +(assert_return (invoke "test" (i32.const 15)) (i32.const 15)) +(assert_trap (invoke "test" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 30)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 31)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 32)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 33)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 34)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 35)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 36)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 37)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 38)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 39)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 40)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 41)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 42)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 43)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 44)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 45)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 46)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 47)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 48)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 49)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 50)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 51)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 52)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 53)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 54)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 55)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 56)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 57)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 58)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 59)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 60)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 61)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 62)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 63)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 64)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 65)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 66)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 67)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 68)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 69)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 70)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 71)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 72)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 73)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 74)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 75)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 76)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 77)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 78)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 79)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 80)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 81)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 82)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 83)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 84)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 85)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 86)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 87)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 88)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 89)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 90)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 91)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 92)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 93)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 94)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 95)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 96)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 97)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 98)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 99)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 100)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 101)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 102)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 103)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 104)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 105)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 106)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 107)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 108)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 109)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 110)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 111)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 112)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 113)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 114)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 115)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 116)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 117)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 118)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 119)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 120)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 121)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 122)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 123)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 124)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 125)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 126)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 127)) "uninitialized element") diff --git a/test/core/table_fill.wast b/test/core/table_fill.wast new file mode 100644 index 0000000000..3df64da1ab --- /dev/null +++ b/test/core/table_fill.wast @@ -0,0 +1,153 @@ +(module + (table $t 10 externref) + + (func (export "fill") (param $i i32) (param $r externref) (param $n i32) + (table.fill $t (local.get $i) (local.get $r) (local.get $n)) + ) + + (func (export "get") (param $i i32) (result externref) + (table.get $t (local.get $i)) + ) +) + +(assert_return (invoke "get" (i32.const 1)) (ref.null extern)) +(assert_return (invoke "get" (i32.const 2)) (ref.null extern)) +(assert_return (invoke "get" (i32.const 3)) (ref.null extern)) +(assert_return (invoke "get" (i32.const 4)) (ref.null extern)) +(assert_return (invoke "get" (i32.const 5)) (ref.null extern)) + +(assert_return (invoke "fill" (i32.const 2) (ref.extern 1) (i32.const 3))) +(assert_return (invoke "get" (i32.const 1)) (ref.null extern)) +(assert_return (invoke "get" (i32.const 2)) (ref.extern 1)) +(assert_return (invoke "get" (i32.const 3)) (ref.extern 1)) +(assert_return (invoke "get" (i32.const 4)) (ref.extern 1)) +(assert_return (invoke "get" (i32.const 5)) (ref.null extern)) + +(assert_return (invoke "fill" (i32.const 4) (ref.extern 2) (i32.const 2))) +(assert_return (invoke "get" (i32.const 3)) (ref.extern 1)) +(assert_return (invoke "get" (i32.const 4)) (ref.extern 2)) +(assert_return (invoke "get" (i32.const 5)) (ref.extern 2)) +(assert_return (invoke "get" (i32.const 6)) (ref.null extern)) + +(assert_return (invoke "fill" (i32.const 4) (ref.extern 3) (i32.const 0))) +(assert_return (invoke "get" (i32.const 3)) (ref.extern 1)) +(assert_return (invoke "get" (i32.const 4)) (ref.extern 2)) +(assert_return (invoke "get" (i32.const 5)) (ref.extern 2)) + +(assert_return (invoke "fill" (i32.const 8) (ref.extern 4) (i32.const 2))) +(assert_return (invoke "get" (i32.const 7)) (ref.null extern)) +(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 "get" (i32.const 8)) (ref.extern 4)) +(assert_return (invoke "get" (i32.const 9)) (ref.null extern)) + +(assert_return (invoke "fill" (i32.const 10) (ref.extern 5) (i32.const 0))) +(assert_return (invoke "get" (i32.const 9)) (ref.null extern)) + +(assert_trap + (invoke "fill" (i32.const 8) (ref.extern 6) (i32.const 3)) + "out of bounds table access" +) +(assert_return (invoke "get" (i32.const 7)) (ref.null extern)) +(assert_return (invoke "get" (i32.const 8)) (ref.extern 4)) +(assert_return (invoke "get" (i32.const 9)) (ref.null extern)) + +(assert_trap + (invoke "fill" (i32.const 11) (ref.null extern) (i32.const 0)) + "out of bounds table access" +) + +(assert_trap + (invoke "fill" (i32.const 11) (ref.null extern) (i32.const 10)) + "out of bounds table access" +) + + +;; Type errors + +(assert_invalid + (module + (table $t 10 externref) + (func $type-index-value-length-empty-vs-i32-i32 + (table.fill $t) + ) + ) + "type mismatch" +) +(assert_invalid + (module + (table $t 10 externref) + (func $type-index-empty-vs-i32 + (table.fill $t (ref.null extern) (i32.const 1)) + ) + ) + "type mismatch" +) +(assert_invalid + (module + (table $t 10 externref) + (func $type-value-empty-vs + (table.fill $t (i32.const 1) (i32.const 1)) + ) + ) + "type mismatch" +) +(assert_invalid + (module + (table $t 10 externref) + (func $type-length-empty-vs-i32 + (table.fill $t (i32.const 1) (ref.null extern)) + ) + ) + "type mismatch" +) +(assert_invalid + (module + (table $t 0 externref) + (func $type-index-f32-vs-i32 + (table.fill $t (f32.const 1) (ref.null extern) (i32.const 1)) + ) + ) + "type mismatch" +) +(assert_invalid + (module + (table $t 0 funcref) + (func $type-value-vs-funcref (param $r externref) + (table.fill $t (i32.const 1) (local.get $r) (i32.const 1)) + ) + ) + "type mismatch" +) +(assert_invalid + (module + (table $t 0 externref) + (func $type-length-f32-vs-i32 + (table.fill $t (i32.const 1) (ref.null extern) (f32.const 1)) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (table $t1 1 externref) + (table $t2 1 funcref) + (func $type-value-externref-vs-funcref-multi (param $r externref) + (table.fill $t2 (i32.const 0) (local.get $r) (i32.const 1)) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (table $t 1 externref) + (func $type-result-empty-vs-num (result i32) + (table.fill $t (i32.const 0) (ref.null extern) (i32.const 1)) + ) + ) + "type mismatch" +) diff --git a/test/core/table_get.wast b/test/core/table_get.wast new file mode 100644 index 0000000000..5d57c31983 --- /dev/null +++ b/test/core/table_get.wast @@ -0,0 +1,88 @@ +(module + (table $t2 2 externref) + (table $t3 3 funcref) + (elem (table $t3) (i32.const 1) func $dummy) + (func $dummy) + + (func (export "init") (param $r externref) + (table.set $t2 (i32.const 1) (local.get $r)) + (table.set $t3 (i32.const 2) (table.get $t3 (i32.const 1))) + ) + + (func (export "get-externref") (param $i i32) (result externref) + (table.get $t2 (local.get $i)) + ) + (func $f3 (export "get-funcref") (param $i i32) (result funcref) + (table.get $t3 (local.get $i)) + ) + + (func (export "is_null-funcref") (param $i i32) (result i32) + (ref.is_null (call $f3 (local.get $i))) + ) +) + +(invoke "init" (ref.extern 1)) + +(assert_return (invoke "get-externref" (i32.const 0)) (ref.null extern)) +(assert_return (invoke "get-externref" (i32.const 1)) (ref.extern 1)) + +(assert_return (invoke "get-funcref" (i32.const 0)) (ref.null func)) +(assert_return (invoke "is_null-funcref" (i32.const 1)) (i32.const 0)) +(assert_return (invoke "is_null-funcref" (i32.const 2)) (i32.const 0)) + +(assert_trap (invoke "get-externref" (i32.const 2)) "out of bounds table access") +(assert_trap (invoke "get-funcref" (i32.const 3)) "out of bounds table access") +(assert_trap (invoke "get-externref" (i32.const -1)) "out of bounds table access") +(assert_trap (invoke "get-funcref" (i32.const -1)) "out of bounds table access") + + +;; Type errors + +(assert_invalid + (module + (table $t 10 externref) + (func $type-index-empty-vs-i32 (result externref) + (table.get $t) + ) + ) + "type mismatch" +) +(assert_invalid + (module + (table $t 10 externref) + (func $type-index-f32-vs-i32 (result externref) + (table.get $t (f32.const 1)) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (table $t 10 externref) + (func $type-result-externref-vs-empty + (table.get $t (i32.const 0)) + ) + ) + "type mismatch" +) +(assert_invalid + (module + (table $t 10 externref) + (func $type-result-externref-vs-funcref (result funcref) + (table.get $t (i32.const 1)) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (table $t1 1 funcref) + (table $t2 1 externref) + (func $type-result-externref-vs-funcref-multi (result funcref) + (table.get $t2 (i32.const 0)) + ) + ) + "type mismatch" +) diff --git a/test/core/table_grow.wast b/test/core/table_grow.wast new file mode 100644 index 0000000000..7d5b5630fc --- /dev/null +++ b/test/core/table_grow.wast @@ -0,0 +1,173 @@ +(module + (table $t 0 externref) + + (func (export "get") (param $i i32) (result externref) (table.get $t (local.get $i))) + (func (export "set") (param $i i32) (param $r externref) (table.set $t (local.get $i) (local.get $r))) + + (func (export "grow") (param $sz i32) (param $init externref) (result i32) + (table.grow $t (local.get $init) (local.get $sz)) + ) + (func (export "size") (result i32) (table.size $t)) +) + +(assert_return (invoke "size") (i32.const 0)) +(assert_trap (invoke "set" (i32.const 0) (ref.extern 2)) "out of bounds table access") +(assert_trap (invoke "get" (i32.const 0)) "out of bounds table access") + +(assert_return (invoke "grow" (i32.const 1) (ref.null extern)) (i32.const 0)) +(assert_return (invoke "size") (i32.const 1)) +(assert_return (invoke "get" (i32.const 0)) (ref.null extern)) +(assert_return (invoke "set" (i32.const 0) (ref.extern 2))) +(assert_return (invoke "get" (i32.const 0)) (ref.extern 2)) +(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 "size") (i32.const 5)) +(assert_return (invoke "get" (i32.const 0)) (ref.extern 2)) +(assert_return (invoke "set" (i32.const 0) (ref.extern 2))) +(assert_return (invoke "get" (i32.const 0)) (ref.extern 2)) +(assert_return (invoke "get" (i32.const 1)) (ref.extern 3)) +(assert_return (invoke "get" (i32.const 4)) (ref.extern 3)) +(assert_return (invoke "set" (i32.const 4) (ref.extern 4))) +(assert_return (invoke "get" (i32.const 4)) (ref.extern 4)) +(assert_trap (invoke "set" (i32.const 5) (ref.extern 2)) "out of bounds table access") +(assert_trap (invoke "get" (i32.const 5)) "out of bounds table access") + + +;; Reject growing to size outside i32 value range +(module + (table $t 0x10 funcref) + (elem declare func $f) + (func $f (export "grow") (result i32) + (table.grow $t (ref.func $f) (i32.const 0xffff_fff0)) + ) +) + +(assert_return (invoke "grow") (i32.const -1)) + + +(module + (table $t 0 externref) + (func (export "grow") (param i32) (result i32) + (table.grow $t (ref.null extern) (local.get 0)) + ) +) + +(assert_return (invoke "grow" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "grow" (i32.const 1)) (i32.const 0)) +(assert_return (invoke "grow" (i32.const 0)) (i32.const 1)) +(assert_return (invoke "grow" (i32.const 2)) (i32.const 1)) +(assert_return (invoke "grow" (i32.const 800)) (i32.const 3)) + + +(module + (table $t 0 10 externref) + (func (export "grow") (param i32) (result i32) + (table.grow $t (ref.null extern) (local.get 0)) + ) +) + +(assert_return (invoke "grow" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "grow" (i32.const 1)) (i32.const 0)) +(assert_return (invoke "grow" (i32.const 1)) (i32.const 1)) +(assert_return (invoke "grow" (i32.const 2)) (i32.const 2)) +(assert_return (invoke "grow" (i32.const 6)) (i32.const 4)) +(assert_return (invoke "grow" (i32.const 0)) (i32.const 10)) +(assert_return (invoke "grow" (i32.const 1)) (i32.const -1)) +(assert_return (invoke "grow" (i32.const 0x10000)) (i32.const -1)) + + +(module + (table $t 10 funcref) + (func (export "grow") (param i32) (result i32) + (table.grow $t (ref.null func) (local.get 0)) + ) + (elem declare func 1) + (func (export "check-table-null") (param i32 i32) (result funcref) + (local funcref) + (local.set 2 (ref.func 1)) + (block + (loop + (local.set 2 (table.get $t (local.get 0))) + (br_if 1 (i32.eqz (ref.is_null (local.get 2)))) + (br_if 1 (i32.ge_u (local.get 0) (local.get 1))) + (local.set 0 (i32.add (local.get 0) (i32.const 1))) + (br_if 0 (i32.le_u (local.get 0) (local.get 1))) + ) + ) + (local.get 2) + ) +) + +(assert_return (invoke "check-table-null" (i32.const 0) (i32.const 9)) (ref.null func)) +(assert_return (invoke "grow" (i32.const 10)) (i32.const 10)) +(assert_return (invoke "check-table-null" (i32.const 0) (i32.const 19)) (ref.null func)) + + +;; Type errors + +(assert_invalid + (module + (table $t 0 externref) + (func $type-init-size-empty-vs-i32-externref (result i32) + (table.grow $t) + ) + ) + "type mismatch" +) +(assert_invalid + (module + (table $t 0 externref) + (func $type-size-empty-vs-i32 (result i32) + (table.grow $t (ref.null extern)) + ) + ) + "type mismatch" +) +(assert_invalid + (module + (table $t 0 externref) + (func $type-init-empty-vs-externref (result i32) + (table.grow $t (i32.const 1)) + ) + ) + "type mismatch" +) +(assert_invalid + (module + (table $t 0 externref) + (func $type-size-f32-vs-i32 (result i32) + (table.grow $t (ref.null extern) (f32.const 1)) + ) + ) + "type mismatch" +) +(assert_invalid + (module + (table $t 0 funcref) + (func $type-init-externref-vs-funcref (param $r externref) (result i32) + (table.grow $t (local.get $r) (i32.const 1)) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (table $t 1 externref) + (func $type-result-i32-vs-empty + (table.grow $t (ref.null extern) (i32.const 0)) + ) + ) + "type mismatch" +) +(assert_invalid + (module + (table $t 1 externref) + (func $type-result-i32-vs-f32 (result f32) + (table.grow $t (ref.null extern) (i32.const 0)) + ) + ) + "type mismatch" +) diff --git a/test/core/table_init.wast b/test/core/table_init.wast new file mode 100644 index 0000000000..0b2d26f772 --- /dev/null +++ b/test/core/table_init.wast @@ -0,0 +1,2143 @@ +;; +;; Generated by ../meta/generate_table_init.js +;; DO NOT EDIT THIS FILE. CHANGE THE SOURCE AND REGENERATE. +;; + +(module + (func (export "ef0") (result i32) (i32.const 0)) + (func (export "ef1") (result i32) (i32.const 1)) + (func (export "ef2") (result i32) (i32.const 2)) + (func (export "ef3") (result i32) (i32.const 3)) + (func (export "ef4") (result i32) (i32.const 4)) +) +(register "a") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.init $t0 1 (i32.const 7) (i32.const 0) (i32.const 4))) + (func (export "check") (param i32) (result i32) + (call_indirect $t0 (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check" (i32.const 6)) "uninitialized element") +(assert_return (invoke "check" (i32.const 7)) (i32.const 2)) +(assert_return (invoke "check" (i32.const 8)) (i32.const 7)) +(assert_return (invoke "check" (i32.const 9)) (i32.const 1)) +(assert_return (invoke "check" (i32.const 10)) (i32.const 8)) +(assert_trap (invoke "check" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "check" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "check" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "check" (i32.const 15)) (i32.const 3)) +(assert_return (invoke "check" (i32.const 16)) (i32.const 6)) +(assert_trap (invoke "check" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.init $t0 3 (i32.const 15) (i32.const 1) (i32.const 3))) + (func (export "check") (param i32) (result i32) + (call_indirect $t0 (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "check" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "check" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "check" (i32.const 15)) (i32.const 9)) +(assert_return (invoke "check" (i32.const 16)) (i32.const 2)) +(assert_return (invoke "check" (i32.const 17)) (i32.const 7)) +(assert_trap (invoke "check" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.init $t0 1 (i32.const 7) (i32.const 0) (i32.const 4)) + (elem.drop 1) + (table.init $t0 3 (i32.const 15) (i32.const 1) (i32.const 3)) + (elem.drop 3) + (table.copy $t0 0 (i32.const 20) (i32.const 15) (i32.const 5)) + (table.copy $t0 0 (i32.const 21) (i32.const 29) (i32.const 1)) + (table.copy $t0 0 (i32.const 24) (i32.const 10) (i32.const 1)) + (table.copy $t0 0 (i32.const 13) (i32.const 11) (i32.const 4)) + (table.copy $t0 0 (i32.const 19) (i32.const 20) (i32.const 5))) + (func (export "check") (param i32) (result i32) + (call_indirect $t0 (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check" (i32.const 6)) "uninitialized element") +(assert_return (invoke "check" (i32.const 7)) (i32.const 2)) +(assert_return (invoke "check" (i32.const 8)) (i32.const 7)) +(assert_return (invoke "check" (i32.const 9)) (i32.const 1)) +(assert_return (invoke "check" (i32.const 10)) (i32.const 8)) +(assert_trap (invoke "check" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check" (i32.const 12)) (i32.const 7)) +(assert_trap (invoke "check" (i32.const 13)) "uninitialized element") +(assert_return (invoke "check" (i32.const 14)) (i32.const 7)) +(assert_return (invoke "check" (i32.const 15)) (i32.const 5)) +(assert_return (invoke "check" (i32.const 16)) (i32.const 2)) +(assert_return (invoke "check" (i32.const 17)) (i32.const 7)) +(assert_trap (invoke "check" (i32.const 18)) "uninitialized element") +(assert_return (invoke "check" (i32.const 19)) (i32.const 9)) +(assert_trap (invoke "check" (i32.const 20)) "uninitialized element") +(assert_return (invoke "check" (i32.const 21)) (i32.const 7)) +(assert_trap (invoke "check" (i32.const 22)) "uninitialized element") +(assert_return (invoke "check" (i32.const 23)) (i32.const 8)) +(assert_return (invoke "check" (i32.const 24)) (i32.const 8)) +(assert_trap (invoke "check" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.init $t1 1 (i32.const 7) (i32.const 0) (i32.const 4))) + (func (export "check") (param i32) (result i32) + (call_indirect $t1 (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check" (i32.const 6)) "uninitialized element") +(assert_return (invoke "check" (i32.const 7)) (i32.const 2)) +(assert_return (invoke "check" (i32.const 8)) (i32.const 7)) +(assert_return (invoke "check" (i32.const 9)) (i32.const 1)) +(assert_return (invoke "check" (i32.const 10)) (i32.const 8)) +(assert_trap (invoke "check" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "check" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "check" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "check" (i32.const 15)) (i32.const 3)) +(assert_return (invoke "check" (i32.const 16)) (i32.const 6)) +(assert_trap (invoke "check" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.init $t1 3 (i32.const 15) (i32.const 1) (i32.const 3))) + (func (export "check") (param i32) (result i32) + (call_indirect $t1 (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "check" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "check" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "check" (i32.const 15)) (i32.const 9)) +(assert_return (invoke "check" (i32.const 16)) (i32.const 2)) +(assert_return (invoke "check" (i32.const 17)) (i32.const 7)) +(assert_trap (invoke "check" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.init $t1 1 (i32.const 7) (i32.const 0) (i32.const 4)) + (elem.drop 1) + (table.init $t1 3 (i32.const 15) (i32.const 1) (i32.const 3)) + (elem.drop 3) + (table.copy $t1 1 (i32.const 20) (i32.const 15) (i32.const 5)) + (table.copy $t1 1 (i32.const 21) (i32.const 29) (i32.const 1)) + (table.copy $t1 1 (i32.const 24) (i32.const 10) (i32.const 1)) + (table.copy $t1 1 (i32.const 13) (i32.const 11) (i32.const 4)) + (table.copy $t1 1 (i32.const 19) (i32.const 20) (i32.const 5))) + (func (export "check") (param i32) (result i32) + (call_indirect $t1 (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check" (i32.const 6)) "uninitialized element") +(assert_return (invoke "check" (i32.const 7)) (i32.const 2)) +(assert_return (invoke "check" (i32.const 8)) (i32.const 7)) +(assert_return (invoke "check" (i32.const 9)) (i32.const 1)) +(assert_return (invoke "check" (i32.const 10)) (i32.const 8)) +(assert_trap (invoke "check" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check" (i32.const 12)) (i32.const 7)) +(assert_trap (invoke "check" (i32.const 13)) "uninitialized element") +(assert_return (invoke "check" (i32.const 14)) (i32.const 7)) +(assert_return (invoke "check" (i32.const 15)) (i32.const 5)) +(assert_return (invoke "check" (i32.const 16)) (i32.const 2)) +(assert_return (invoke "check" (i32.const 17)) (i32.const 7)) +(assert_trap (invoke "check" (i32.const 18)) "uninitialized element") +(assert_return (invoke "check" (i32.const 19)) (i32.const 9)) +(assert_trap (invoke "check" (i32.const 20)) "uninitialized element") +(assert_return (invoke "check" (i32.const 21)) (i32.const 7)) +(assert_trap (invoke "check" (i32.const 22)) "uninitialized element") +(assert_return (invoke "check" (i32.const 23)) (i32.const 8)) +(assert_return (invoke "check" (i32.const 24)) (i32.const 8)) +(assert_trap (invoke "check" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 29)) "uninitialized element") +(assert_invalid + (module + (func (export "test") + (elem.drop 0))) + "unknown elem segment 0") + +(assert_invalid + (module + (func (export "test") + (table.init 0 (i32.const 12) (i32.const 1) (i32.const 1)))) + "unknown table 0") + +(assert_invalid + (module + (elem funcref (ref.func 0)) + (func (result i32) (i32.const 0)) + (func (export "test") + (elem.drop 4))) + "unknown elem segment 4") + +(assert_invalid + (module + (elem funcref (ref.func 0)) + (func (result i32) (i32.const 0)) + (func (export "test") + (table.init 4 (i32.const 12) (i32.const 1) (i32.const 1)))) + "unknown table 0") + + +(module + (table $t0 30 30 funcref) + (table $t1 28 28 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (elem.drop 2) + )) +(invoke "test") + +(module + (table $t0 30 30 funcref) + (table $t1 28 28 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.init 2 (i32.const 12) (i32.const 1) (i32.const 1)) + )) +(assert_trap (invoke "test") "out of bounds table access") + +(module + (table $t0 30 30 funcref) + (table $t1 28 28 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.init 1 (i32.const 12) (i32.const 1) (i32.const 1)) + (table.init 1 (i32.const 21) (i32.const 1) (i32.const 1)))) +(invoke "test") + +(module + (table $t0 30 30 funcref) + (table $t1 28 28 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (elem.drop 1) + (elem.drop 1))) +(invoke "test") + +(module + (table $t0 30 30 funcref) + (table $t1 28 28 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (elem.drop 1) + (table.init 1 (i32.const 12) (i32.const 1) (i32.const 1)))) +(assert_trap (invoke "test") "out of bounds table access") + +(module + (table $t0 30 30 funcref) + (table $t1 28 28 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.init 1 (i32.const 12) (i32.const 0) (i32.const 5)) + )) +(assert_trap (invoke "test") "out of bounds table access") + +(module + (table $t0 30 30 funcref) + (table $t1 28 28 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.init 1 (i32.const 12) (i32.const 2) (i32.const 3)) + )) +(assert_trap (invoke "test") "out of bounds table access") + +(module + (table $t0 30 30 funcref) + (table $t1 28 28 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.init $t0 1 (i32.const 28) (i32.const 1) (i32.const 3)) + )) +(assert_trap (invoke "test") "out of bounds table access") + +(module + (table $t0 30 30 funcref) + (table $t1 28 28 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.init $t0 1 (i32.const 12) (i32.const 4) (i32.const 0)) + )) +(invoke "test") + +(module + (table $t0 30 30 funcref) + (table $t1 28 28 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.init $t0 1 (i32.const 12) (i32.const 5) (i32.const 0)) + )) +(assert_trap (invoke "test") "out of bounds table access") + +(module + (table $t0 30 30 funcref) + (table $t1 28 28 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.init $t0 1 (i32.const 30) (i32.const 2) (i32.const 0)) + )) +(invoke "test") + +(module + (table $t0 30 30 funcref) + (table $t1 28 28 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.init $t0 1 (i32.const 31) (i32.const 2) (i32.const 0)) + )) +(assert_trap (invoke "test") "out of bounds table access") + +(module + (table $t0 30 30 funcref) + (table $t1 28 28 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.init $t0 1 (i32.const 30) (i32.const 4) (i32.const 0)) + )) +(invoke "test") + +(module + (table $t0 30 30 funcref) + (table $t1 28 28 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.init $t0 1 (i32.const 31) (i32.const 5) (i32.const 0)) + )) +(assert_trap (invoke "test") "out of bounds table access") + +(module + (table $t0 30 30 funcref) + (table $t1 28 28 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.init $t1 1 (i32.const 26) (i32.const 1) (i32.const 3)) + )) +(assert_trap (invoke "test") "out of bounds table access") + +(module + (table $t0 30 30 funcref) + (table $t1 28 28 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.init $t1 1 (i32.const 12) (i32.const 4) (i32.const 0)) + )) +(invoke "test") + +(module + (table $t0 30 30 funcref) + (table $t1 28 28 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.init $t1 1 (i32.const 12) (i32.const 5) (i32.const 0)) + )) +(assert_trap (invoke "test") "out of bounds table access") + +(module + (table $t0 30 30 funcref) + (table $t1 28 28 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.init $t1 1 (i32.const 28) (i32.const 2) (i32.const 0)) + )) +(invoke "test") + +(module + (table $t0 30 30 funcref) + (table $t1 28 28 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.init $t1 1 (i32.const 29) (i32.const 2) (i32.const 0)) + )) +(assert_trap (invoke "test") "out of bounds table access") + +(module + (table $t0 30 30 funcref) + (table $t1 28 28 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.init $t1 1 (i32.const 28) (i32.const 4) (i32.const 0)) + )) +(invoke "test") + +(module + (table $t0 30 30 funcref) + (table $t1 28 28 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.init $t1 1 (i32.const 29) (i32.const 5) (i32.const 0)) + )) +(assert_trap (invoke "test") "out of bounds table access") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i32.const 1) (i32.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i32.const 1) (i32.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i32.const 1) (i32.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i32.const 1) (f32.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i32.const 1) (f32.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i32.const 1) (f32.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i32.const 1) (f32.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i32.const 1) (i64.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i32.const 1) (i64.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i32.const 1) (i64.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i32.const 1) (i64.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i32.const 1) (f64.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i32.const 1) (f64.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i32.const 1) (f64.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i32.const 1) (f64.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f32.const 1) (i32.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f32.const 1) (i32.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f32.const 1) (i32.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f32.const 1) (i32.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f32.const 1) (f32.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f32.const 1) (f32.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f32.const 1) (f32.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f32.const 1) (f32.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f32.const 1) (i64.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f32.const 1) (i64.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f32.const 1) (i64.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f32.const 1) (i64.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f32.const 1) (f64.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f32.const 1) (f64.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f32.const 1) (f64.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f32.const 1) (f64.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i64.const 1) (i32.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i64.const 1) (i32.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i64.const 1) (i32.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i64.const 1) (i32.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i64.const 1) (f32.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i64.const 1) (f32.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i64.const 1) (f32.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i64.const 1) (f32.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i64.const 1) (i64.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i64.const 1) (i64.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i64.const 1) (i64.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i64.const 1) (i64.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i64.const 1) (f64.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i64.const 1) (f64.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i64.const 1) (f64.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i64.const 1) (f64.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f64.const 1) (i32.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f64.const 1) (i32.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f64.const 1) (i32.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f64.const 1) (i32.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f64.const 1) (f32.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f64.const 1) (f32.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f64.const 1) (f32.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f64.const 1) (f32.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f64.const 1) (i64.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f64.const 1) (i64.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f64.const 1) (i64.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f64.const 1) (i64.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f64.const 1) (f64.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f64.const 1) (f64.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f64.const 1) (f64.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f64.const 1) (f64.const 1) (f64.const 1)))) + "type mismatch") + +(module + (type (func (result i32))) + (table 32 64 funcref) + (elem funcref + (ref.func $f0) (ref.func $f1) (ref.func $f2) (ref.func $f3) + (ref.func $f4) (ref.func $f5) (ref.func $f6) (ref.func $f7) + (ref.func $f8) (ref.func $f9) (ref.func $f10) (ref.func $f11) + (ref.func $f12) (ref.func $f13) (ref.func $f14) (ref.func $f15)) + (func $f0 (export "f0") (result i32) (i32.const 0)) + (func $f1 (export "f1") (result i32) (i32.const 1)) + (func $f2 (export "f2") (result i32) (i32.const 2)) + (func $f3 (export "f3") (result i32) (i32.const 3)) + (func $f4 (export "f4") (result i32) (i32.const 4)) + (func $f5 (export "f5") (result i32) (i32.const 5)) + (func $f6 (export "f6") (result i32) (i32.const 6)) + (func $f7 (export "f7") (result i32) (i32.const 7)) + (func $f8 (export "f8") (result i32) (i32.const 8)) + (func $f9 (export "f9") (result i32) (i32.const 9)) + (func $f10 (export "f10") (result i32) (i32.const 10)) + (func $f11 (export "f11") (result i32) (i32.const 11)) + (func $f12 (export "f12") (result i32) (i32.const 12)) + (func $f13 (export "f13") (result i32) (i32.const 13)) + (func $f14 (export "f14") (result i32) (i32.const 14)) + (func $f15 (export "f15") (result i32) (i32.const 15)) + (func (export "test") (param $n i32) (result i32) + (call_indirect (type 0) (local.get $n))) + (func (export "run") (param $offs i32) (param $len i32) + (table.init 0 (local.get $offs) (i32.const 0) (local.get $len)))) +(assert_trap (invoke "run" (i32.const 24) (i32.const 16)) "out of bounds table access") +(assert_trap (invoke "test" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 2)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 3)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 4)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 5)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 11)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 12)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 13)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 14)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 15)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 30)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 31)) "uninitialized element") + +(module + (type (func (result i32))) + (table 32 64 funcref) + (elem funcref + (ref.func $f0) (ref.func $f1) (ref.func $f2) (ref.func $f3) + (ref.func $f4) (ref.func $f5) (ref.func $f6) (ref.func $f7) + (ref.func $f8) (ref.func $f9) (ref.func $f10) (ref.func $f11) + (ref.func $f12) (ref.func $f13) (ref.func $f14) (ref.func $f15)) + (func $f0 (export "f0") (result i32) (i32.const 0)) + (func $f1 (export "f1") (result i32) (i32.const 1)) + (func $f2 (export "f2") (result i32) (i32.const 2)) + (func $f3 (export "f3") (result i32) (i32.const 3)) + (func $f4 (export "f4") (result i32) (i32.const 4)) + (func $f5 (export "f5") (result i32) (i32.const 5)) + (func $f6 (export "f6") (result i32) (i32.const 6)) + (func $f7 (export "f7") (result i32) (i32.const 7)) + (func $f8 (export "f8") (result i32) (i32.const 8)) + (func $f9 (export "f9") (result i32) (i32.const 9)) + (func $f10 (export "f10") (result i32) (i32.const 10)) + (func $f11 (export "f11") (result i32) (i32.const 11)) + (func $f12 (export "f12") (result i32) (i32.const 12)) + (func $f13 (export "f13") (result i32) (i32.const 13)) + (func $f14 (export "f14") (result i32) (i32.const 14)) + (func $f15 (export "f15") (result i32) (i32.const 15)) + (func (export "test") (param $n i32) (result i32) + (call_indirect (type 0) (local.get $n))) + (func (export "run") (param $offs i32) (param $len i32) + (table.init 0 (local.get $offs) (i32.const 0) (local.get $len)))) +(assert_trap (invoke "run" (i32.const 25) (i32.const 16)) "out of bounds table access") +(assert_trap (invoke "test" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 2)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 3)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 4)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 5)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 11)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 12)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 13)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 14)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 15)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 30)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 31)) "uninitialized element") + +(module + (type (func (result i32))) + (table 160 320 funcref) + (elem funcref + (ref.func $f0) (ref.func $f1) (ref.func $f2) (ref.func $f3) + (ref.func $f4) (ref.func $f5) (ref.func $f6) (ref.func $f7) + (ref.func $f8) (ref.func $f9) (ref.func $f10) (ref.func $f11) + (ref.func $f12) (ref.func $f13) (ref.func $f14) (ref.func $f15)) + (func $f0 (export "f0") (result i32) (i32.const 0)) + (func $f1 (export "f1") (result i32) (i32.const 1)) + (func $f2 (export "f2") (result i32) (i32.const 2)) + (func $f3 (export "f3") (result i32) (i32.const 3)) + (func $f4 (export "f4") (result i32) (i32.const 4)) + (func $f5 (export "f5") (result i32) (i32.const 5)) + (func $f6 (export "f6") (result i32) (i32.const 6)) + (func $f7 (export "f7") (result i32) (i32.const 7)) + (func $f8 (export "f8") (result i32) (i32.const 8)) + (func $f9 (export "f9") (result i32) (i32.const 9)) + (func $f10 (export "f10") (result i32) (i32.const 10)) + (func $f11 (export "f11") (result i32) (i32.const 11)) + (func $f12 (export "f12") (result i32) (i32.const 12)) + (func $f13 (export "f13") (result i32) (i32.const 13)) + (func $f14 (export "f14") (result i32) (i32.const 14)) + (func $f15 (export "f15") (result i32) (i32.const 15)) + (func (export "test") (param $n i32) (result i32) + (call_indirect (type 0) (local.get $n))) + (func (export "run") (param $offs i32) (param $len i32) + (table.init 0 (local.get $offs) (i32.const 0) (local.get $len)))) +(assert_trap (invoke "run" (i32.const 96) (i32.const 32)) "out of bounds table access") +(assert_trap (invoke "test" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 2)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 3)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 4)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 5)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 11)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 12)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 13)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 14)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 15)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 30)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 31)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 32)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 33)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 34)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 35)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 36)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 37)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 38)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 39)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 40)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 41)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 42)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 43)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 44)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 45)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 46)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 47)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 48)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 49)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 50)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 51)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 52)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 53)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 54)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 55)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 56)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 57)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 58)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 59)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 60)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 61)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 62)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 63)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 64)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 65)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 66)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 67)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 68)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 69)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 70)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 71)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 72)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 73)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 74)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 75)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 76)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 77)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 78)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 79)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 80)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 81)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 82)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 83)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 84)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 85)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 86)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 87)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 88)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 89)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 90)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 91)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 92)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 93)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 94)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 95)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 96)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 97)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 98)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 99)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 100)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 101)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 102)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 103)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 104)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 105)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 106)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 107)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 108)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 109)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 110)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 111)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 112)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 113)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 114)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 115)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 116)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 117)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 118)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 119)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 120)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 121)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 122)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 123)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 124)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 125)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 126)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 127)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 128)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 129)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 130)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 131)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 132)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 133)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 134)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 135)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 136)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 137)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 138)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 139)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 140)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 141)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 142)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 143)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 144)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 145)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 146)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 147)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 148)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 149)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 150)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 151)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 152)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 153)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 154)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 155)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 156)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 157)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 158)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 159)) "uninitialized element") + +(module + (type (func (result i32))) + (table 160 320 funcref) + (elem funcref + (ref.func $f0) (ref.func $f1) (ref.func $f2) (ref.func $f3) + (ref.func $f4) (ref.func $f5) (ref.func $f6) (ref.func $f7) + (ref.func $f8) (ref.func $f9) (ref.func $f10) (ref.func $f11) + (ref.func $f12) (ref.func $f13) (ref.func $f14) (ref.func $f15)) + (func $f0 (export "f0") (result i32) (i32.const 0)) + (func $f1 (export "f1") (result i32) (i32.const 1)) + (func $f2 (export "f2") (result i32) (i32.const 2)) + (func $f3 (export "f3") (result i32) (i32.const 3)) + (func $f4 (export "f4") (result i32) (i32.const 4)) + (func $f5 (export "f5") (result i32) (i32.const 5)) + (func $f6 (export "f6") (result i32) (i32.const 6)) + (func $f7 (export "f7") (result i32) (i32.const 7)) + (func $f8 (export "f8") (result i32) (i32.const 8)) + (func $f9 (export "f9") (result i32) (i32.const 9)) + (func $f10 (export "f10") (result i32) (i32.const 10)) + (func $f11 (export "f11") (result i32) (i32.const 11)) + (func $f12 (export "f12") (result i32) (i32.const 12)) + (func $f13 (export "f13") (result i32) (i32.const 13)) + (func $f14 (export "f14") (result i32) (i32.const 14)) + (func $f15 (export "f15") (result i32) (i32.const 15)) + (func (export "test") (param $n i32) (result i32) + (call_indirect (type 0) (local.get $n))) + (func (export "run") (param $offs i32) (param $len i32) + (table.init 0 (local.get $offs) (i32.const 0) (local.get $len)))) +(assert_trap (invoke "run" (i32.const 97) (i32.const 31)) "out of bounds table access") +(assert_trap (invoke "test" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 2)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 3)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 4)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 5)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 11)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 12)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 13)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 14)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 15)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 30)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 31)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 32)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 33)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 34)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 35)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 36)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 37)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 38)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 39)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 40)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 41)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 42)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 43)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 44)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 45)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 46)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 47)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 48)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 49)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 50)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 51)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 52)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 53)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 54)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 55)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 56)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 57)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 58)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 59)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 60)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 61)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 62)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 63)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 64)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 65)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 66)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 67)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 68)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 69)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 70)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 71)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 72)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 73)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 74)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 75)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 76)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 77)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 78)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 79)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 80)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 81)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 82)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 83)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 84)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 85)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 86)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 87)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 88)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 89)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 90)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 91)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 92)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 93)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 94)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 95)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 96)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 97)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 98)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 99)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 100)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 101)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 102)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 103)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 104)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 105)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 106)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 107)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 108)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 109)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 110)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 111)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 112)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 113)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 114)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 115)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 116)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 117)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 118)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 119)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 120)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 121)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 122)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 123)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 124)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 125)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 126)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 127)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 128)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 129)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 130)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 131)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 132)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 133)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 134)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 135)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 136)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 137)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 138)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 139)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 140)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 141)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 142)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 143)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 144)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 145)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 146)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 147)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 148)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 149)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 150)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 151)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 152)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 153)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 154)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 155)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 156)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 157)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 158)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 159)) "uninitialized element") + +(module + (type (func (result i32))) + (table 64 64 funcref) + (elem funcref + (ref.func $f0) (ref.func $f1) (ref.func $f2) (ref.func $f3) + (ref.func $f4) (ref.func $f5) (ref.func $f6) (ref.func $f7) + (ref.func $f8) (ref.func $f9) (ref.func $f10) (ref.func $f11) + (ref.func $f12) (ref.func $f13) (ref.func $f14) (ref.func $f15)) + (func $f0 (export "f0") (result i32) (i32.const 0)) + (func $f1 (export "f1") (result i32) (i32.const 1)) + (func $f2 (export "f2") (result i32) (i32.const 2)) + (func $f3 (export "f3") (result i32) (i32.const 3)) + (func $f4 (export "f4") (result i32) (i32.const 4)) + (func $f5 (export "f5") (result i32) (i32.const 5)) + (func $f6 (export "f6") (result i32) (i32.const 6)) + (func $f7 (export "f7") (result i32) (i32.const 7)) + (func $f8 (export "f8") (result i32) (i32.const 8)) + (func $f9 (export "f9") (result i32) (i32.const 9)) + (func $f10 (export "f10") (result i32) (i32.const 10)) + (func $f11 (export "f11") (result i32) (i32.const 11)) + (func $f12 (export "f12") (result i32) (i32.const 12)) + (func $f13 (export "f13") (result i32) (i32.const 13)) + (func $f14 (export "f14") (result i32) (i32.const 14)) + (func $f15 (export "f15") (result i32) (i32.const 15)) + (func (export "test") (param $n i32) (result i32) + (call_indirect (type 0) (local.get $n))) + (func (export "run") (param $offs i32) (param $len i32) + (table.init 0 (local.get $offs) (i32.const 0) (local.get $len)))) +(assert_trap (invoke "run" (i32.const 48) (i32.const 4294967280)) "out of bounds table access") +(assert_trap (invoke "test" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 2)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 3)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 4)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 5)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 11)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 12)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 13)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 14)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 15)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 30)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 31)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 32)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 33)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 34)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 35)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 36)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 37)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 38)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 39)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 40)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 41)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 42)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 43)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 44)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 45)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 46)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 47)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 48)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 49)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 50)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 51)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 52)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 53)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 54)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 55)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 56)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 57)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 58)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 59)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 60)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 61)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 62)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 63)) "uninitialized element") + +(module + (type (func (result i32))) + (table 16 16 funcref) + (elem funcref + (ref.func $f0) (ref.func $f1) (ref.func $f2) (ref.func $f3) + (ref.func $f4) (ref.func $f5) (ref.func $f6) (ref.func $f7) + (ref.func $f8) (ref.func $f9) (ref.func $f10) (ref.func $f11) + (ref.func $f12) (ref.func $f13) (ref.func $f14) (ref.func $f15)) + (func $f0 (export "f0") (result i32) (i32.const 0)) + (func $f1 (export "f1") (result i32) (i32.const 1)) + (func $f2 (export "f2") (result i32) (i32.const 2)) + (func $f3 (export "f3") (result i32) (i32.const 3)) + (func $f4 (export "f4") (result i32) (i32.const 4)) + (func $f5 (export "f5") (result i32) (i32.const 5)) + (func $f6 (export "f6") (result i32) (i32.const 6)) + (func $f7 (export "f7") (result i32) (i32.const 7)) + (func $f8 (export "f8") (result i32) (i32.const 8)) + (func $f9 (export "f9") (result i32) (i32.const 9)) + (func $f10 (export "f10") (result i32) (i32.const 10)) + (func $f11 (export "f11") (result i32) (i32.const 11)) + (func $f12 (export "f12") (result i32) (i32.const 12)) + (func $f13 (export "f13") (result i32) (i32.const 13)) + (func $f14 (export "f14") (result i32) (i32.const 14)) + (func $f15 (export "f15") (result i32) (i32.const 15)) + (func (export "test") (param $n i32) (result i32) + (call_indirect (type 0) (local.get $n))) + (func (export "run") (param $offs i32) (param $len i32) + (table.init 0 (local.get $offs) (i32.const 8) (local.get $len)))) +(assert_trap (invoke "run" (i32.const 0) (i32.const 4294967292)) "out of bounds table access") +(assert_trap (invoke "test" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 2)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 3)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 4)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 5)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 11)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 12)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 13)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 14)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 15)) "uninitialized element") + +(module + (table 1 funcref) + ;; 65 elem segments. 64 is the smallest positive number that is encoded + ;; differently as a signed LEB. + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) + (func (table.init 64 (i32.const 0) (i32.const 0) (i32.const 0)))) diff --git a/test/core/table_set.wast b/test/core/table_set.wast new file mode 100644 index 0000000000..5a9cfa3715 --- /dev/null +++ b/test/core/table_set.wast @@ -0,0 +1,119 @@ +(module + (table $t2 1 externref) + (table $t3 2 funcref) + (elem (table $t3) (i32.const 1) func $dummy) + (func $dummy) + + (func (export "get-externref") (param $i i32) (result externref) + (table.get $t2 (local.get $i)) + ) + (func $f3 (export "get-funcref") (param $i i32) (result funcref) + (table.get $t3 (local.get $i)) + ) + + (func (export "set-externref") (param $i i32) (param $r externref) + (table.set $t2 (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)) + ) + (func (export "set-funcref-from") (param $i i32) (param $j i32) + (table.set $t3 (local.get $i) (table.get $t3 (local.get $j))) + ) + + (func (export "is_null-funcref") (param $i i32) (result i32) + (ref.is_null (call $f3 (local.get $i))) + ) +) + +(assert_return (invoke "get-externref" (i32.const 0)) (ref.null extern)) +(assert_return (invoke "set-externref" (i32.const 0) (ref.extern 1))) +(assert_return (invoke "get-externref" (i32.const 0)) (ref.extern 1)) +(assert_return (invoke "set-externref" (i32.const 0) (ref.null extern))) +(assert_return (invoke "get-externref" (i32.const 0)) (ref.null extern)) + +(assert_return (invoke "get-funcref" (i32.const 0)) (ref.null func)) +(assert_return (invoke "set-funcref-from" (i32.const 0) (i32.const 1))) +(assert_return (invoke "is_null-funcref" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "set-funcref" (i32.const 0) (ref.null func))) +(assert_return (invoke "get-funcref" (i32.const 0)) (ref.null func)) + +(assert_trap (invoke "set-externref" (i32.const 2) (ref.null extern)) "out of bounds table access") +(assert_trap (invoke "set-funcref" (i32.const 3) (ref.null func)) "out of bounds table access") +(assert_trap (invoke "set-externref" (i32.const -1) (ref.null extern)) "out of bounds table access") +(assert_trap (invoke "set-funcref" (i32.const -1) (ref.null func)) "out of bounds table access") + +(assert_trap (invoke "set-externref" (i32.const 2) (ref.extern 0)) "out of bounds table access") +(assert_trap (invoke "set-funcref-from" (i32.const 3) (i32.const 1)) "out of bounds table access") +(assert_trap (invoke "set-externref" (i32.const -1) (ref.extern 0)) "out of bounds table access") +(assert_trap (invoke "set-funcref-from" (i32.const -1) (i32.const 1)) "out of bounds table access") + + +;; Type errors + +(assert_invalid + (module + (table $t 10 externref) + (func $type-index-value-empty-vs-i32-externref + (table.set $t) + ) + ) + "type mismatch" +) +(assert_invalid + (module + (table $t 10 externref) + (func $type-index-empty-vs-i32 + (table.set $t (ref.null extern)) + ) + ) + "type mismatch" +) +(assert_invalid + (module + (table $t 10 externref) + (func $type-value-empty-vs-externref + (table.set $t (i32.const 1)) + ) + ) + "type mismatch" +) +(assert_invalid + (module + (table $t 10 externref) + (func $type-size-f32-vs-i32 + (table.set $t (f32.const 1) (ref.null extern)) + ) + ) + "type mismatch" +) +(assert_invalid + (module + (table $t 10 funcref) + (func $type-value-externref-vs-funcref (param $r externref) + (table.set $t (i32.const 1) (local.get $r)) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (table $t1 1 externref) + (table $t2 1 funcref) + (func $type-value-externref-vs-funcref-multi (param $r externref) + (table.set $t2 (i32.const 0) (local.get $r)) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (table $t 10 externref) + (func $type-result-empty-vs-num (result i32) + (table.set $t (i32.const 0) (ref.null extern)) + ) + ) + "type mismatch" +) diff --git a/test/core/table_size.wast b/test/core/table_size.wast new file mode 100644 index 0000000000..ad293b5ee4 --- /dev/null +++ b/test/core/table_size.wast @@ -0,0 +1,86 @@ +(module + (table $t0 0 externref) + (table $t1 1 externref) + (table $t2 0 2 externref) + (table $t3 3 8 externref) + + (func (export "size-t0") (result i32) (table.size $t0)) + (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)) + + (func (export "grow-t0") (param $sz i32) + (drop (table.grow $t0 (ref.null extern) (local.get $sz))) + ) + (func (export "grow-t1") (param $sz i32) + (drop (table.grow $t1 (ref.null extern) (local.get $sz))) + ) + (func (export "grow-t2") (param $sz i32) + (drop (table.grow $t2 (ref.null extern) (local.get $sz))) + ) + (func (export "grow-t3") (param $sz i32) + (drop (table.grow $t3 (ref.null extern) (local.get $sz))) + ) +) + +(assert_return (invoke "size-t0") (i32.const 0)) +(assert_return (invoke "grow-t0" (i32.const 1))) +(assert_return (invoke "size-t0") (i32.const 1)) +(assert_return (invoke "grow-t0" (i32.const 4))) +(assert_return (invoke "size-t0") (i32.const 5)) +(assert_return (invoke "grow-t0" (i32.const 0))) +(assert_return (invoke "size-t0") (i32.const 5)) + +(assert_return (invoke "size-t1") (i32.const 1)) +(assert_return (invoke "grow-t1" (i32.const 1))) +(assert_return (invoke "size-t1") (i32.const 2)) +(assert_return (invoke "grow-t1" (i32.const 4))) +(assert_return (invoke "size-t1") (i32.const 6)) +(assert_return (invoke "grow-t1" (i32.const 0))) +(assert_return (invoke "size-t1") (i32.const 6)) + +(assert_return (invoke "size-t2") (i32.const 0)) +(assert_return (invoke "grow-t2" (i32.const 3))) +(assert_return (invoke "size-t2") (i32.const 0)) +(assert_return (invoke "grow-t2" (i32.const 1))) +(assert_return (invoke "size-t2") (i32.const 1)) +(assert_return (invoke "grow-t2" (i32.const 0))) +(assert_return (invoke "size-t2") (i32.const 1)) +(assert_return (invoke "grow-t2" (i32.const 4))) +(assert_return (invoke "size-t2") (i32.const 1)) +(assert_return (invoke "grow-t2" (i32.const 1))) +(assert_return (invoke "size-t2") (i32.const 2)) + +(assert_return (invoke "size-t3") (i32.const 3)) +(assert_return (invoke "grow-t3" (i32.const 1))) +(assert_return (invoke "size-t3") (i32.const 4)) +(assert_return (invoke "grow-t3" (i32.const 3))) +(assert_return (invoke "size-t3") (i32.const 7)) +(assert_return (invoke "grow-t3" (i32.const 0))) +(assert_return (invoke "size-t3") (i32.const 7)) +(assert_return (invoke "grow-t3" (i32.const 2))) +(assert_return (invoke "size-t3") (i32.const 7)) +(assert_return (invoke "grow-t3" (i32.const 1))) +(assert_return (invoke "size-t3") (i32.const 8)) + + +;; Type errors + +(assert_invalid + (module + (table $t 1 externref) + (func $type-result-i32-vs-empty + (table.size $t) + ) + ) + "type mismatch" +) +(assert_invalid + (module + (table $t 1 externref) + (func $type-result-i32-vs-f32 (result f32) + (table.size $t) + ) + ) + "type mismatch" +) diff --git a/test/core/unreached-invalid.wast b/test/core/unreached-invalid.wast index 6ef4ac5520..3ddd77385f 100644 --- a/test/core/unreached-invalid.wast +++ b/test/core/unreached-invalid.wast @@ -535,20 +535,6 @@ )) "type mismatch" ) -(assert_invalid - (module (func $type-br_table-label-num-vs-label-num-after-unreachable - (block (result f64) - (block (result f32) - (unreachable) - (br_table 0 1 1 (i32.const 1)) - ) - (drop) - (f64.const 0) - ) - (drop) - )) - "type mismatch" -) (assert_invalid (module (func $type-block-value-nested-unreachable-num-vs-void diff --git a/test/harness/async_index.js b/test/harness/async_index.js index 038d6859cd..c200019ac6 100644 --- a/test/harness/async_index.js +++ b/test/harness/async_index.js @@ -52,6 +52,25 @@ const EXPECT_INVALID = false; /* DATA **********************************************************************/ +let externrefs = {}; +let externsym = Symbol("externref"); +function externref(s) { + if (! (s in externrefs)) externrefs[s] = {[externsym]: s}; + return externrefs[s]; +} +function is_externref(x) { + return (x !== null && externsym in x) ? 1 : 0; +} +function is_funcref(x) { + return typeof x === "function" ? 1 : 0; +} +function eq_externref(x, y) { + return x === y ? 1 : 0; +} +function eq_funcref(x, y) { + return x === y ? 1 : 0; +} + // Default imports. var registry = {}; @@ -67,6 +86,11 @@ function reinitializeRegistry() { chain = chain.then(_ => { let spectest = { + externref: externref, + is_externref: is_externref, + is_funcref: is_funcref, + eq_externref: eq_externref, + eq_funcref: eq_funcref, print: console.log.bind(console), print_i32: console.log.bind(console), print_i32_f32: console.log.bind(console), @@ -180,9 +204,9 @@ function instance(bytes, imports, valid = true) { return chain; } -function exports(name, instance) { +function exports(instance) { return instance.then(inst => { - return { [name]: inst.exports }; + return { module: inst.exports, spectest: registry.spectest }; }); } @@ -243,18 +267,32 @@ function assert_return(action, ...expected) { .then( values => { uniqueTest(_ => { - let actual = values[0]; if (actual === undefined) { - actual = []; + actual = []; } else if (!Array.isArray(actual)) { - actual = [actual]; + actual = [actual]; } if (actual.length !== expected.length) { - throw new Error(expected.length + " value(s) expected, got " + actual.length); + throw new Error(expected.length + " value(s) expected, got " + actual.length); } - for (let i = 0; i < actual.length; ++i) { - assert_equals(actual[i], expected[i], loc); + switch (expected[i]) { + case "nan:canonical": + case "nan:arithmetic": + case "nan:any": + // Note that JS can't reliably distinguish different NaN values, + // so there's no good way to test that it's a canonical NaN. + assert_true(Number.isNaN(actual[i]), `expected NaN, observed ${actual[i]}.`); + return; + case "ref.func": + assert_true(typeof actual[i] === "function", `expected Wasm function, got ${actual[i]}`); + return; + case "ref.extern": + assert_true(actual[i] !== null, `expected Wasm reference, got ${actual[i]}`); + return; + default: + assert_equals(actual[i], expected[i], loc); + } } }, test); }, diff --git a/test/harness/sync_index.js b/test/harness/sync_index.js index fd4e72326a..7ed9f29159 100644 --- a/test/harness/sync_index.js +++ b/test/harness/sync_index.js @@ -66,6 +66,25 @@ const EXPECT_INVALID = false; /* DATA **********************************************************************/ +let externrefs = {}; +let externsym = Symbol("externref"); +function externref(s) { + if (! (s in externrefs)) externrefs[s] = {[externsym]: s}; + return externrefs[s]; +} +function is_externref(x) { + return (x !== null && externsym in x) ? 1 : 0; +} +function is_funcref(x) { + return typeof x === "function" ? 1 : 0; +} +function eq_externref(x, y) { + return x === y ? 1 : 0; +} +function eq_funcref(x, y) { + return x === y ? 1 : 0; +} + let $$; // Default imports. @@ -77,6 +96,11 @@ function reinitializeRegistry() { return; let spectest = { + externref: externref, + is_externref: is_externref, + is_funcref: is_funcref, + eq_externref: eq_externref, + eq_funcref: eq_funcref, print: console.log.bind(console), print_i32: console.log.bind(console), print_i32_f32: console.log.bind(console), @@ -228,13 +252,13 @@ function get(instance, name) { return ValueResult((v instanceof WebAssembly.Global) ? v.value : v); } -function exports(name, instance) { +function exports(instance) { _assert(instance instanceof Result); if (instance.isError()) return instance; - return ValueResult({ [name]: instance.value.exports }); + return ValueResult({ module: instance.value.exports, spectest: registry.spectest }); } function run(action) { @@ -313,7 +337,6 @@ function assert_return(action, ...expected) { uniqueTest(() => { assert_true(!result.isError(), `expected success result, got: ${result.value}.`); - let actual = result.value; if (actual === undefined) { actual = []; @@ -323,17 +346,32 @@ function assert_return(action, ...expected) { if (actual.length !== expected.length) { throw new Error(expected.length + " value(s) expected, got " + actual.length); } - for (let i = 0; i < actual.length; ++i) { if (expected[i] instanceof Result) { if (expected[i].isError()) return; expected[i] = expected[i].value; } - assert_equals(actual[i], expected[i]); + switch (expected[i]) { + case "nan:canonical": + case "nan:arithmetic": + case "nan:any": + // Note that JS can't reliably distinguish different NaN values, + // so there's no good way to test that it's a canonical NaN. + assert_true(Number.isNaN(actual[i]), `expected NaN, observed ${actual[i]}.`); + return; + case "ref.func": + assert_true(typeof actual[i] === "function", `expected Wasm function, got ${actual[i]}`); + return; + case "ref.extern": + assert_true(actual[i] !== null, `expected Wasm reference, got ${actual[i]}`); + return; + default: + assert_equals(actual[i], expected[i]); + } } }, "A wast module that must return a particular value."); -}; +} function assert_return_nan(action) { let result = action(); diff --git a/test/js-api/limits.any.js b/test/js-api/limits.any.js index 6bbdaebc80..7e690cad91 100644 --- a/test/js-api/limits.any.js +++ b/test/js-api/limits.any.js @@ -16,7 +16,7 @@ const kJSEmbeddingMaxFunctionLocals = 50000; const kJSEmbeddingMaxFunctionParams = 1000; const kJSEmbeddingMaxFunctionReturns = 1000; const kJSEmbeddingMaxElementSegments = 10000000; -const kJSEmbeddingMaxTables = 1; +const kJSEmbeddingMaxTables = 100000; const kJSEmbeddingMaxMemories = 1; // Dynamic limits diff --git a/test/meta/Makefile b/test/meta/Makefile new file mode 100644 index 0000000000..20e9adb2f5 --- /dev/null +++ b/test/meta/Makefile @@ -0,0 +1,32 @@ +SHARED_MEM=false + +# SpiderMonkey shell +JSSHELL=~/mozilla-central/js/src/build-debug/dist/bin/js -e 'const WITH_SHARED_MEMORY=$(SHARED_MEM);' -f common.js + +# Node.js +#JSSHELL=./noderun.sh $(SHARED_MEM) + +TARGETDIR=../core + +.PHONY: all + +all: $(TARGETDIR)/memory_copy.wast \ + $(TARGETDIR)/memory_init.wast \ + $(TARGETDIR)/memory_fill.wast \ + $(TARGETDIR)/table_copy.wast \ + $(TARGETDIR)/table_init.wast + +$(TARGETDIR)/memory_copy.wast: generate_memory_copy.js common.js Makefile + $(JSSHELL) $< > $@ + +$(TARGETDIR)/memory_init.wast: generate_memory_init.js common.js Makefile + $(JSSHELL) $< > $@ + +$(TARGETDIR)/memory_fill.wast: generate_memory_fill.js common.js Makefile + $(JSSHELL) $< > $@ + +$(TARGETDIR)/table_copy.wast: generate_table_copy.js common.js Makefile + $(JSSHELL) $< > $@ + +$(TARGETDIR)/table_init.wast: generate_table_init.js common.js Makefile + $(JSSHELL) $< > $@ diff --git a/test/meta/README.md b/test/meta/README.md new file mode 100644 index 0000000000..aeaf790251 --- /dev/null +++ b/test/meta/README.md @@ -0,0 +1 @@ +These programs generate test cases. See Makefile for details. diff --git a/test/meta/common.js b/test/meta/common.js new file mode 100644 index 0000000000..9a277e44f2 --- /dev/null +++ b/test/meta/common.js @@ -0,0 +1,29 @@ +const PAGESIZE = 65536; + +function print_origin(origin) { + print(";;"); + print(";; Generated by ../meta/" + origin); + print(";; DO NOT EDIT THIS FILE. CHANGE THE SOURCE AND REGENERATE."); + print(";;"); +} + +function checkRangeCode() { + return ` + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) +`; +} + +function checkRange(from, to, expected) { + print( +`(assert_return (invoke "checkRange" (i32.const ${from}) (i32.const ${to}) (i32.const ${expected})) + (i32.const -1))`); +} diff --git a/test/meta/generate_memory_copy.js b/test/meta/generate_memory_copy.js new file mode 100644 index 0000000000..e5b7c0c997 --- /dev/null +++ b/test/meta/generate_memory_copy.js @@ -0,0 +1,768 @@ +// This program generates .wast code that contains all the spec tests for +// memory.copy. See `Makefile`. + +print_origin("generate_memory_copy.js"); + +// In-bounds tests. + +function mem_test(instruction, expected_result_vector) { + print( +` +(module + (memory (export "memory0") 1 1) + (data (i32.const 2) "\\03\\01\\04\\01") + (data (i32.const 12) "\\07\\05\\02\\03\\06") + (func (export "test") + ${instruction}) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(invoke "test") +`); + for (let i = 0; i < expected_result_vector.length; i++) { + print(`(assert_return (invoke "load8_u" (i32.const ${i})) (i32.const ${expected_result_vector[i]}))`); + } +} + +const e = 0; + +// This just gives the initial state of the memory, with its active +// initialisers applied. +mem_test("(nop)", + [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e]); + +// Copy non-zero over non-zero +mem_test("(memory.copy (i32.const 13) (i32.const 2) (i32.const 3))", + [e,e,3,1,4, 1,e,e,e,e, e,e,7,3,1, 4,6,e,e,e, e,e,e,e,e, e,e,e,e,e]); + +// Copy non-zero over zero +mem_test("(memory.copy (i32.const 25) (i32.const 15) (i32.const 2))", + [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, 3,6,e,e,e]); + +// Copy zero over non-zero +mem_test("(memory.copy (i32.const 13) (i32.const 25) (i32.const 3))", + [e,e,3,1,4, 1,e,e,e,e, e,e,7,e,e, e,6,e,e,e, e,e,e,e,e, e,e,e,e,e]); + +// Copy zero over zero +mem_test("(memory.copy (i32.const 20) (i32.const 22) (i32.const 4))", + [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e]); + +// Copy zero and non-zero entries, non overlapping +mem_test("(memory.copy (i32.const 25) (i32.const 1) (i32.const 3))", + [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,3,1,e,e]); + +// Copy zero and non-zero entries, overlapping, backwards +mem_test("(memory.copy (i32.const 10) (i32.const 12) (i32.const 7))", + [e,e,3,1,4, 1,e,e,e,e, 7,5,2,3,6, e,e,e,e,e, e,e,e,e,e, e,e,e,e,e]); + +// Copy zero and non-zero entries, overlapping, forwards +mem_test("(memory.copy (i32.const 12) (i32.const 10) (i32.const 7))", + [e,e,3,1,4, 1,e,e,e,e, e,e,e,e,7, 5,2,3,6,e, e,e,e,e,e, e,e,e,e,e]); + +// Out-of-bounds tests. +// +// The operation is out of bounds of the memory for the source or target, but +// must perform the operation up to the appropriate bound. Major cases: +// +// - non-overlapping regions +// - overlapping regions with src >= dest +// - overlapping regions with src == dest +// - overlapping regions with src < dest +// - arithmetic overflow on src addresses +// - arithmetic overflow on target addresses +// +// for each of those, +// +// - src address oob +// - target address oob +// - both oob + +function initializers(count, startingAt) { + let s = ""; + for ( let i=0, j=startingAt; i < count; i++, j++ ) + s += "\\" + (i + 256).toString(16).substring(1); + return s; +} + +function mem_copy(min, max, shared, srcOffs, targetOffs, len) { + let copyDown = srcOffs < targetOffs; + let memLength = min * PAGESIZE; + let targetAvail = memLength - targetOffs; + let srcAvail = memLength - srcOffs; + let targetLim = targetOffs + Math.min(len, targetAvail, srcAvail); + let srcLim = srcOffs + Math.min(len, targetAvail, srcAvail); + + print( +` +(module + (memory (export "mem") ${min} ${max} ${shared}) + (data (i32.const ${srcOffs}) "${initializers(srcLim - srcOffs, 0)}") + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(assert_trap (invoke "run" (i32.const ${targetOffs}) (i32.const ${srcOffs}) (i32.const ${len})) + "out of bounds") +`); + + let immediateOOB = copyDown && (srcOffs + len > memLength || targetOffs + len > memLength); + + var s = 0; + var i = 0; + let k = 0; + for (i=0; i < memLength; i++ ) { + if (i >= srcOffs && i < srcLim) { + print(`(assert_return (invoke "load8_u" (i32.const ${i})) (i32.const ${(s++) & 0xFF}))`); + continue; + } + // Only spot-check for zero, or we'll be here all night. + if (++k == 199) { + print(`(assert_return (invoke "load8_u" (i32.const ${i})) (i32.const 0))`); + k = 0; + } + } +} + +// OOB target address, nonoverlapping +mem_copy(1, 1, "", 0, PAGESIZE-20, 40); +mem_copy(1, 1, "", 0, PAGESIZE-21, 39); +if (WITH_SHARED_MEMORY) { + mem_copy(2, 4, "shared", 0, 2*PAGESIZE-20, 40); + mem_copy(2, 4, "shared", 0, 2*PAGESIZE-21, 39); +} + +// OOB source address, nonoverlapping +mem_copy(1, 1, "", PAGESIZE-20, 0, 40); +mem_copy(1, 1, "", PAGESIZE-21, 0, 39); +if (WITH_SHARED_MEMORY) { + mem_copy(2, 4, "shared", 2*PAGESIZE-20, 0, 40); + mem_copy(2, 4, "shared", 2*PAGESIZE-21, 0, 39); +} + +// OOB target address, overlapping, src < target +mem_copy(1, 1, "", PAGESIZE-50, PAGESIZE-20, 40); + +// OOB source address, overlapping, target < src +mem_copy(1, 1, "", PAGESIZE-20, PAGESIZE-50, 40); + +// OOB both, overlapping, including target == src +mem_copy(1, 1, "", PAGESIZE-30, PAGESIZE-20, 40); +mem_copy(1, 1, "", PAGESIZE-20, PAGESIZE-30, 40); +mem_copy(1, 1, "", PAGESIZE-20, PAGESIZE-20, 40); + +// Arithmetic overflow on source address. +mem_copy(1, "", "", PAGESIZE-20, 0, 0xFFFFF000); + +// Arithmetic overflow on target adddress is an overlapping case. +mem_copy(1, 1, "", PAGESIZE-0x1000, PAGESIZE-20, 0xFFFFFF00); + +// Sundry compilation failures. + +// Module doesn't have a memory. +print( +` +(assert_invalid + (module + (func (export "testfn") + (memory.copy (i32.const 10) (i32.const 20) (i32.const 30)))) + "unknown memory 0") +`); + +// Invalid argument types. TODO: We can add anyref, funcref, etc here. +{ + const tys = ['i32', 'f32', 'i64', 'f64']; + for (let ty1 of tys) { + for (let ty2 of tys) { + for (let ty3 of tys) { + if (ty1 == 'i32' && ty2 == 'i32' && ty3 == 'i32') + continue; // this is the only valid case + print( +`(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (${ty1}.const 10) (${ty2}.const 20) (${ty3}.const 30)))) + "type mismatch") +`); + }}} +} + +// Both ranges valid. Copy 5 bytes backwards by 1 (overlapping). +// result = 0x00--(09) 0x55--(11) 0x00--(pagesize-20) +print( +` +(module + (memory 1 1) + (func (export "test") + (memory.fill (i32.const 10) (i32.const 0x55) (i32.const 10)) + (memory.copy (i32.const 9) (i32.const 10) (i32.const 5))) + ${checkRangeCode()}) +(invoke "test") +`); +checkRange(0, 0+9, 0x00); +checkRange(9, 9+11, 0x55); +checkRange(9+11, 0x10000, 0x00); + +// Both ranges valid. Copy 5 bytes forwards by 1 (overlapping). +// result = 0x00--(10) 0x55--(11) 0x00--(pagesize-19) +print( +` +(module + (memory 1 1) + (func (export "test") + (memory.fill (i32.const 10) (i32.const 0x55) (i32.const 10)) + (memory.copy (i32.const 16) (i32.const 15) (i32.const 5))) + ${checkRangeCode()}) +(invoke "test") +`); +checkRange(0, 0+10, 0x00); +checkRange(10, 10+11, 0x55); +checkRange(10+11, 0x10000, 0x00); + +// Destination range invalid +print( +` +(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0xFF00) (i32.const 0x8000) (i32.const 257)))) +(assert_trap (invoke "test") "out of bounds") +`); + +// Destination wraparound the end of 32-bit offset space +print( +`(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0xFFFFFF00) (i32.const 0x4000) (i32.const 257)))) +(assert_trap (invoke "test") "out of bounds") +`); + +// Source range invalid +print( +`(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0x8000) (i32.const 0xFF00) (i32.const 257)))) +(assert_trap (invoke "test") "out of bounds") +`); + +// Source wraparound the end of 32-bit offset space +print( +`(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0x4000) (i32.const 0xFFFFFF00) (i32.const 257)))) +(assert_trap (invoke "test") "out of bounds") +`); + +// Zero len with both offsets in-bounds is a no-op +print( +`(module + (memory 1 1) + (func (export "test") + (memory.fill (i32.const 0x0000) (i32.const 0x55) (i32.const 0x8000)) + (memory.fill (i32.const 0x8000) (i32.const 0xAA) (i32.const 0x8000)) + (memory.copy (i32.const 0x9000) (i32.const 0x7000) (i32.const 0))) + ${checkRangeCode()}) +(invoke "test") +`); +checkRange(0x00000, 0x08000, 0x55); +checkRange(0x08000, 0x10000, 0xAA); + +// Zero len with dest offset out-of-bounds at the end of memory is allowed +print( +`(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0x10000) (i32.const 0x7000) (i32.const 0)))) +(invoke "test") +`); + +// Zero len with dest offset out-of-bounds past the end of memory is not allowed +print( +`(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0x20000) (i32.const 0x7000) (i32.const 0)))) +(assert_trap (invoke "test") "out of bounds") +`); + +// Zero len with src offset out-of-bounds at the end of memory is allowed +print( +`(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0x9000) (i32.const 0x10000) (i32.const 0)))) +(invoke "test") +`); + +// Zero len with src offset out-of-bounds past the end of memory is not allowed +print( +`(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0x9000) (i32.const 0x20000) (i32.const 0)))) +(assert_trap (invoke "test") "out of bounds") +`); + +// Zero len with both dest and src offsets out-of-bounds at the end of memory is allowed +print( +`(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0x10000) (i32.const 0x10000) (i32.const 0)))) +(invoke "test") +`); + +// Zero len with both dest and src offsets out-of-bounds past the end of memory is not allowed +print( +`(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0x20000) (i32.const 0x20000) (i32.const 0)))) +(assert_trap (invoke "test") "out of bounds") +`); + +// 100 random fills followed by 100 random copies, in a single-page buffer, +// followed by verification of the (now heavily mashed-around) buffer. +print( +`(module + (memory 1 1) + (func (export "test") + (memory.fill (i32.const 17767) (i32.const 1) (i32.const 1344)) + (memory.fill (i32.const 39017) (i32.const 2) (i32.const 1055)) + (memory.fill (i32.const 56401) (i32.const 3) (i32.const 988)) + (memory.fill (i32.const 37962) (i32.const 4) (i32.const 322)) + (memory.fill (i32.const 7977) (i32.const 5) (i32.const 1994)) + (memory.fill (i32.const 22714) (i32.const 6) (i32.const 3036)) + (memory.fill (i32.const 16882) (i32.const 7) (i32.const 2372)) + (memory.fill (i32.const 43491) (i32.const 8) (i32.const 835)) + (memory.fill (i32.const 124) (i32.const 9) (i32.const 1393)) + (memory.fill (i32.const 2132) (i32.const 10) (i32.const 2758)) + (memory.fill (i32.const 8987) (i32.const 11) (i32.const 3098)) + (memory.fill (i32.const 52711) (i32.const 12) (i32.const 741)) + (memory.fill (i32.const 3958) (i32.const 13) (i32.const 2823)) + (memory.fill (i32.const 49715) (i32.const 14) (i32.const 1280)) + (memory.fill (i32.const 50377) (i32.const 15) (i32.const 1466)) + (memory.fill (i32.const 20493) (i32.const 16) (i32.const 3158)) + (memory.fill (i32.const 47665) (i32.const 17) (i32.const 544)) + (memory.fill (i32.const 12451) (i32.const 18) (i32.const 2669)) + (memory.fill (i32.const 24869) (i32.const 19) (i32.const 2651)) + (memory.fill (i32.const 45317) (i32.const 20) (i32.const 1570)) + (memory.fill (i32.const 43096) (i32.const 21) (i32.const 1691)) + (memory.fill (i32.const 33886) (i32.const 22) (i32.const 646)) + (memory.fill (i32.const 48555) (i32.const 23) (i32.const 1858)) + (memory.fill (i32.const 53453) (i32.const 24) (i32.const 2657)) + (memory.fill (i32.const 30363) (i32.const 25) (i32.const 981)) + (memory.fill (i32.const 9300) (i32.const 26) (i32.const 1807)) + (memory.fill (i32.const 50190) (i32.const 27) (i32.const 487)) + (memory.fill (i32.const 62753) (i32.const 28) (i32.const 530)) + (memory.fill (i32.const 36316) (i32.const 29) (i32.const 943)) + (memory.fill (i32.const 6768) (i32.const 30) (i32.const 381)) + (memory.fill (i32.const 51262) (i32.const 31) (i32.const 3089)) + (memory.fill (i32.const 49729) (i32.const 32) (i32.const 658)) + (memory.fill (i32.const 44540) (i32.const 33) (i32.const 1702)) + (memory.fill (i32.const 33342) (i32.const 34) (i32.const 1092)) + (memory.fill (i32.const 50814) (i32.const 35) (i32.const 1410)) + (memory.fill (i32.const 47594) (i32.const 36) (i32.const 2204)) + (memory.fill (i32.const 54123) (i32.const 37) (i32.const 2394)) + (memory.fill (i32.const 55183) (i32.const 38) (i32.const 250)) + (memory.fill (i32.const 22620) (i32.const 39) (i32.const 2097)) + (memory.fill (i32.const 17132) (i32.const 40) (i32.const 3264)) + (memory.fill (i32.const 54331) (i32.const 41) (i32.const 3299)) + (memory.fill (i32.const 39474) (i32.const 42) (i32.const 2796)) + (memory.fill (i32.const 36156) (i32.const 43) (i32.const 2070)) + (memory.fill (i32.const 35308) (i32.const 44) (i32.const 2763)) + (memory.fill (i32.const 32731) (i32.const 45) (i32.const 312)) + (memory.fill (i32.const 63746) (i32.const 46) (i32.const 192)) + (memory.fill (i32.const 30974) (i32.const 47) (i32.const 596)) + (memory.fill (i32.const 16635) (i32.const 48) (i32.const 501)) + (memory.fill (i32.const 57002) (i32.const 49) (i32.const 686)) + (memory.fill (i32.const 34299) (i32.const 50) (i32.const 385)) + (memory.fill (i32.const 60881) (i32.const 51) (i32.const 903)) + (memory.fill (i32.const 61445) (i32.const 52) (i32.const 2390)) + (memory.fill (i32.const 46972) (i32.const 53) (i32.const 1441)) + (memory.fill (i32.const 25973) (i32.const 54) (i32.const 3162)) + (memory.fill (i32.const 5566) (i32.const 55) (i32.const 2135)) + (memory.fill (i32.const 35977) (i32.const 56) (i32.const 519)) + (memory.fill (i32.const 44892) (i32.const 57) (i32.const 3280)) + (memory.fill (i32.const 46760) (i32.const 58) (i32.const 1678)) + (memory.fill (i32.const 46607) (i32.const 59) (i32.const 3168)) + (memory.fill (i32.const 22449) (i32.const 60) (i32.const 1441)) + (memory.fill (i32.const 58609) (i32.const 61) (i32.const 663)) + (memory.fill (i32.const 32261) (i32.const 62) (i32.const 1671)) + (memory.fill (i32.const 3063) (i32.const 63) (i32.const 721)) + (memory.fill (i32.const 34025) (i32.const 64) (i32.const 84)) + (memory.fill (i32.const 33338) (i32.const 65) (i32.const 2029)) + (memory.fill (i32.const 36810) (i32.const 66) (i32.const 29)) + (memory.fill (i32.const 19147) (i32.const 67) (i32.const 3034)) + (memory.fill (i32.const 12616) (i32.const 68) (i32.const 1043)) + (memory.fill (i32.const 18276) (i32.const 69) (i32.const 3324)) + (memory.fill (i32.const 4639) (i32.const 70) (i32.const 1091)) + (memory.fill (i32.const 16158) (i32.const 71) (i32.const 1997)) + (memory.fill (i32.const 18204) (i32.const 72) (i32.const 2259)) + (memory.fill (i32.const 50532) (i32.const 73) (i32.const 3189)) + (memory.fill (i32.const 11028) (i32.const 74) (i32.const 1968)) + (memory.fill (i32.const 15962) (i32.const 75) (i32.const 1455)) + (memory.fill (i32.const 45406) (i32.const 76) (i32.const 1177)) + (memory.fill (i32.const 54137) (i32.const 77) (i32.const 1568)) + (memory.fill (i32.const 33083) (i32.const 78) (i32.const 1642)) + (memory.fill (i32.const 61028) (i32.const 79) (i32.const 3284)) + (memory.fill (i32.const 51729) (i32.const 80) (i32.const 223)) + (memory.fill (i32.const 4361) (i32.const 81) (i32.const 2171)) + (memory.fill (i32.const 57514) (i32.const 82) (i32.const 1322)) + (memory.fill (i32.const 55724) (i32.const 83) (i32.const 2648)) + (memory.fill (i32.const 24091) (i32.const 84) (i32.const 1045)) + (memory.fill (i32.const 43183) (i32.const 85) (i32.const 3097)) + (memory.fill (i32.const 32307) (i32.const 86) (i32.const 2796)) + (memory.fill (i32.const 3811) (i32.const 87) (i32.const 2010)) + (memory.fill (i32.const 54856) (i32.const 88) (i32.const 0)) + (memory.fill (i32.const 49941) (i32.const 89) (i32.const 2069)) + (memory.fill (i32.const 20411) (i32.const 90) (i32.const 2896)) + (memory.fill (i32.const 33826) (i32.const 91) (i32.const 192)) + (memory.fill (i32.const 9402) (i32.const 92) (i32.const 2195)) + (memory.fill (i32.const 12413) (i32.const 93) (i32.const 24)) + (memory.fill (i32.const 14091) (i32.const 94) (i32.const 577)) + (memory.fill (i32.const 44058) (i32.const 95) (i32.const 2089)) + (memory.fill (i32.const 36735) (i32.const 96) (i32.const 3436)) + (memory.fill (i32.const 23288) (i32.const 97) (i32.const 2765)) + (memory.fill (i32.const 6392) (i32.const 98) (i32.const 830)) + (memory.fill (i32.const 33307) (i32.const 99) (i32.const 1938)) + (memory.fill (i32.const 21941) (i32.const 100) (i32.const 2750)) + (memory.copy (i32.const 59214) (i32.const 54248) (i32.const 2098)) + (memory.copy (i32.const 63026) (i32.const 39224) (i32.const 230)) + (memory.copy (i32.const 51833) (i32.const 23629) (i32.const 2300)) + (memory.copy (i32.const 6708) (i32.const 23996) (i32.const 639)) + (memory.copy (i32.const 6990) (i32.const 33399) (i32.const 1097)) + (memory.copy (i32.const 19403) (i32.const 10348) (i32.const 3197)) + (memory.copy (i32.const 27308) (i32.const 54406) (i32.const 100)) + (memory.copy (i32.const 27221) (i32.const 43682) (i32.const 1717)) + (memory.copy (i32.const 60528) (i32.const 8629) (i32.const 119)) + (memory.copy (i32.const 5947) (i32.const 2308) (i32.const 658)) + (memory.copy (i32.const 4787) (i32.const 51631) (i32.const 2269)) + (memory.copy (i32.const 12617) (i32.const 19197) (i32.const 833)) + (memory.copy (i32.const 11854) (i32.const 46505) (i32.const 3300)) + (memory.copy (i32.const 11376) (i32.const 45012) (i32.const 2281)) + (memory.copy (i32.const 34186) (i32.const 6697) (i32.const 2572)) + (memory.copy (i32.const 4936) (i32.const 1690) (i32.const 1328)) + (memory.copy (i32.const 63164) (i32.const 7637) (i32.const 1670)) + (memory.copy (i32.const 44568) (i32.const 18344) (i32.const 33)) + (memory.copy (i32.const 43918) (i32.const 22348) (i32.const 1427)) + (memory.copy (i32.const 46637) (i32.const 49819) (i32.const 1434)) + (memory.copy (i32.const 63684) (i32.const 8755) (i32.const 834)) + (memory.copy (i32.const 33485) (i32.const 20131) (i32.const 3317)) + (memory.copy (i32.const 40575) (i32.const 54317) (i32.const 3201)) + (memory.copy (i32.const 25812) (i32.const 59254) (i32.const 2452)) + (memory.copy (i32.const 19678) (i32.const 56882) (i32.const 346)) + (memory.copy (i32.const 15852) (i32.const 35914) (i32.const 2430)) + (memory.copy (i32.const 11824) (i32.const 35574) (i32.const 300)) + (memory.copy (i32.const 59427) (i32.const 13957) (i32.const 3153)) + (memory.copy (i32.const 34299) (i32.const 60594) (i32.const 1281)) + (memory.copy (i32.const 8964) (i32.const 12276) (i32.const 943)) + (memory.copy (i32.const 2827) (i32.const 10425) (i32.const 1887)) + (memory.copy (i32.const 43194) (i32.const 43910) (i32.const 738)) + (memory.copy (i32.const 63038) (i32.const 18949) (i32.const 122)) + (memory.copy (i32.const 24044) (i32.const 44761) (i32.const 1755)) + (memory.copy (i32.const 22608) (i32.const 14755) (i32.const 702)) + (memory.copy (i32.const 11284) (i32.const 26579) (i32.const 1830)) + (memory.copy (i32.const 23092) (i32.const 20471) (i32.const 1064)) + (memory.copy (i32.const 57248) (i32.const 54770) (i32.const 2631)) + (memory.copy (i32.const 25492) (i32.const 1025) (i32.const 3113)) + (memory.copy (i32.const 49588) (i32.const 44220) (i32.const 975)) + (memory.copy (i32.const 28280) (i32.const 41722) (i32.const 2336)) + (memory.copy (i32.const 61289) (i32.const 230) (i32.const 2872)) + (memory.copy (i32.const 22480) (i32.const 52506) (i32.const 2197)) + (memory.copy (i32.const 40553) (i32.const 9578) (i32.const 1958)) + (memory.copy (i32.const 29004) (i32.const 20862) (i32.const 2186)) + (memory.copy (i32.const 53029) (i32.const 43955) (i32.const 1037)) + (memory.copy (i32.const 25476) (i32.const 35667) (i32.const 1650)) + (memory.copy (i32.const 58516) (i32.const 45819) (i32.const 1986)) + (memory.copy (i32.const 38297) (i32.const 5776) (i32.const 1955)) + (memory.copy (i32.const 28503) (i32.const 55364) (i32.const 2368)) + (memory.copy (i32.const 62619) (i32.const 18108) (i32.const 1356)) + (memory.copy (i32.const 50149) (i32.const 13861) (i32.const 382)) + (memory.copy (i32.const 16904) (i32.const 36341) (i32.const 1900)) + (memory.copy (i32.const 48098) (i32.const 11358) (i32.const 2807)) + (memory.copy (i32.const 28512) (i32.const 40362) (i32.const 323)) + (memory.copy (i32.const 35506) (i32.const 27856) (i32.const 1670)) + (memory.copy (i32.const 62970) (i32.const 53332) (i32.const 1341)) + (memory.copy (i32.const 14133) (i32.const 46312) (i32.const 644)) + (memory.copy (i32.const 29030) (i32.const 19074) (i32.const 496)) + (memory.copy (i32.const 44952) (i32.const 47577) (i32.const 2784)) + (memory.copy (i32.const 39559) (i32.const 44661) (i32.const 1350)) + (memory.copy (i32.const 10352) (i32.const 29274) (i32.const 1475)) + (memory.copy (i32.const 46911) (i32.const 46178) (i32.const 1467)) + (memory.copy (i32.const 4905) (i32.const 28740) (i32.const 1895)) + (memory.copy (i32.const 38012) (i32.const 57253) (i32.const 1751)) + (memory.copy (i32.const 26446) (i32.const 27223) (i32.const 1127)) + (memory.copy (i32.const 58835) (i32.const 24657) (i32.const 1063)) + (memory.copy (i32.const 61356) (i32.const 38790) (i32.const 766)) + (memory.copy (i32.const 44160) (i32.const 2284) (i32.const 1520)) + (memory.copy (i32.const 32740) (i32.const 47237) (i32.const 3014)) + (memory.copy (i32.const 11148) (i32.const 21260) (i32.const 1011)) + (memory.copy (i32.const 7665) (i32.const 31612) (i32.const 3034)) + (memory.copy (i32.const 18044) (i32.const 12987) (i32.const 3320)) + (memory.copy (i32.const 57306) (i32.const 55905) (i32.const 308)) + (memory.copy (i32.const 24675) (i32.const 16815) (i32.const 1155)) + (memory.copy (i32.const 19900) (i32.const 10115) (i32.const 722)) + (memory.copy (i32.const 2921) (i32.const 5935) (i32.const 2370)) + (memory.copy (i32.const 32255) (i32.const 50095) (i32.const 2926)) + (memory.copy (i32.const 15126) (i32.const 17299) (i32.const 2607)) + (memory.copy (i32.const 45575) (i32.const 28447) (i32.const 2045)) + (memory.copy (i32.const 55149) (i32.const 36113) (i32.const 2596)) + (memory.copy (i32.const 28461) (i32.const 54157) (i32.const 1168)) + (memory.copy (i32.const 47951) (i32.const 53385) (i32.const 3137)) + (memory.copy (i32.const 30646) (i32.const 45155) (i32.const 2649)) + (memory.copy (i32.const 5057) (i32.const 4295) (i32.const 52)) + (memory.copy (i32.const 6692) (i32.const 24195) (i32.const 441)) + (memory.copy (i32.const 32984) (i32.const 27117) (i32.const 3445)) + (memory.copy (i32.const 32530) (i32.const 59372) (i32.const 2785)) + (memory.copy (i32.const 34361) (i32.const 8962) (i32.const 2406)) + (memory.copy (i32.const 17893) (i32.const 54538) (i32.const 3381)) + (memory.copy (i32.const 22685) (i32.const 44151) (i32.const 136)) + (memory.copy (i32.const 59089) (i32.const 7077) (i32.const 1045)) + (memory.copy (i32.const 42945) (i32.const 55028) (i32.const 2389)) + (memory.copy (i32.const 44693) (i32.const 20138) (i32.const 877)) + (memory.copy (i32.const 36810) (i32.const 25196) (i32.const 3447)) + (memory.copy (i32.const 45742) (i32.const 31888) (i32.const 854)) + (memory.copy (i32.const 24236) (i32.const 31866) (i32.const 1377)) + (memory.copy (i32.const 33778) (i32.const 692) (i32.const 1594)) + (memory.copy (i32.const 60618) (i32.const 18585) (i32.const 2987)) + (memory.copy (i32.const 50370) (i32.const 41271) (i32.const 1406)) + ) + ${checkRangeCode()}) +(invoke "test") +`); +checkRange(0, 124, 0); +checkRange(124, 1517, 9); +checkRange(1517, 2132, 0); +checkRange(2132, 2827, 10); +checkRange(2827, 2921, 92); +checkRange(2921, 3538, 83); +checkRange(3538, 3786, 77); +checkRange(3786, 4042, 97); +checkRange(4042, 4651, 99); +checkRange(4651, 5057, 0); +checkRange(5057, 5109, 99); +checkRange(5109, 5291, 0); +checkRange(5291, 5524, 72); +checkRange(5524, 5691, 92); +checkRange(5691, 6552, 83); +checkRange(6552, 7133, 77); +checkRange(7133, 7665, 99); +checkRange(7665, 8314, 0); +checkRange(8314, 8360, 62); +checkRange(8360, 8793, 86); +checkRange(8793, 8979, 83); +checkRange(8979, 9373, 79); +checkRange(9373, 9518, 95); +checkRange(9518, 9934, 59); +checkRange(9934, 10087, 77); +checkRange(10087, 10206, 5); +checkRange(10206, 10230, 77); +checkRange(10230, 10249, 41); +checkRange(10249, 11148, 83); +checkRange(11148, 11356, 74); +checkRange(11356, 11380, 93); +checkRange(11380, 11939, 74); +checkRange(11939, 12159, 68); +checkRange(12159, 12575, 83); +checkRange(12575, 12969, 79); +checkRange(12969, 13114, 95); +checkRange(13114, 14133, 59); +checkRange(14133, 14404, 76); +checkRange(14404, 14428, 57); +checkRange(14428, 14458, 59); +checkRange(14458, 14580, 32); +checkRange(14580, 14777, 89); +checkRange(14777, 15124, 59); +checkRange(15124, 15126, 36); +checkRange(15126, 15192, 100); +checkRange(15192, 15871, 96); +checkRange(15871, 15998, 95); +checkRange(15998, 17017, 59); +checkRange(17017, 17288, 76); +checkRange(17288, 17312, 57); +checkRange(17312, 17342, 59); +checkRange(17342, 17464, 32); +checkRange(17464, 17661, 89); +checkRange(17661, 17727, 59); +checkRange(17727, 17733, 5); +checkRange(17733, 17893, 96); +checkRange(17893, 18553, 77); +checkRange(18553, 18744, 42); +checkRange(18744, 18801, 76); +checkRange(18801, 18825, 57); +checkRange(18825, 18876, 59); +checkRange(18876, 18885, 77); +checkRange(18885, 18904, 41); +checkRange(18904, 19567, 83); +checkRange(19567, 20403, 96); +checkRange(20403, 21274, 77); +checkRange(21274, 21364, 100); +checkRange(21364, 21468, 74); +checkRange(21468, 21492, 93); +checkRange(21492, 22051, 74); +checkRange(22051, 22480, 68); +checkRange(22480, 22685, 100); +checkRange(22685, 22694, 68); +checkRange(22694, 22821, 10); +checkRange(22821, 22869, 100); +checkRange(22869, 24107, 97); +checkRange(24107, 24111, 37); +checkRange(24111, 24236, 77); +checkRange(24236, 24348, 72); +checkRange(24348, 24515, 92); +checkRange(24515, 24900, 83); +checkRange(24900, 25136, 95); +checkRange(25136, 25182, 85); +checkRange(25182, 25426, 68); +checkRange(25426, 25613, 89); +checkRange(25613, 25830, 96); +checkRange(25830, 26446, 100); +checkRange(26446, 26517, 10); +checkRange(26517, 27468, 92); +checkRange(27468, 27503, 95); +checkRange(27503, 27573, 77); +checkRange(27573, 28245, 92); +checkRange(28245, 28280, 95); +checkRange(28280, 29502, 77); +checkRange(29502, 29629, 42); +checkRange(29629, 30387, 83); +checkRange(30387, 30646, 77); +checkRange(30646, 31066, 92); +checkRange(31066, 31131, 77); +checkRange(31131, 31322, 42); +checkRange(31322, 31379, 76); +checkRange(31379, 31403, 57); +checkRange(31403, 31454, 59); +checkRange(31454, 31463, 77); +checkRange(31463, 31482, 41); +checkRange(31482, 31649, 83); +checkRange(31649, 31978, 72); +checkRange(31978, 32145, 92); +checkRange(32145, 32530, 83); +checkRange(32530, 32766, 95); +checkRange(32766, 32812, 85); +checkRange(32812, 33056, 68); +checkRange(33056, 33660, 89); +checkRange(33660, 33752, 59); +checkRange(33752, 33775, 36); +checkRange(33775, 33778, 32); +checkRange(33778, 34603, 9); +checkRange(34603, 35218, 0); +checkRange(35218, 35372, 10); +checkRange(35372, 35486, 77); +checkRange(35486, 35605, 5); +checkRange(35605, 35629, 77); +checkRange(35629, 35648, 41); +checkRange(35648, 36547, 83); +checkRange(36547, 36755, 74); +checkRange(36755, 36767, 93); +checkRange(36767, 36810, 83); +checkRange(36810, 36839, 100); +checkRange(36839, 37444, 96); +checkRange(37444, 38060, 100); +checkRange(38060, 38131, 10); +checkRange(38131, 39082, 92); +checkRange(39082, 39117, 95); +checkRange(39117, 39187, 77); +checkRange(39187, 39859, 92); +checkRange(39859, 39894, 95); +checkRange(39894, 40257, 77); +checkRange(40257, 40344, 89); +checkRange(40344, 40371, 59); +checkRange(40371, 40804, 77); +checkRange(40804, 40909, 5); +checkRange(40909, 42259, 92); +checkRange(42259, 42511, 77); +checkRange(42511, 42945, 83); +checkRange(42945, 43115, 77); +checkRange(43115, 43306, 42); +checkRange(43306, 43363, 76); +checkRange(43363, 43387, 57); +checkRange(43387, 43438, 59); +checkRange(43438, 43447, 77); +checkRange(43447, 43466, 41); +checkRange(43466, 44129, 83); +checkRange(44129, 44958, 96); +checkRange(44958, 45570, 77); +checkRange(45570, 45575, 92); +checkRange(45575, 45640, 77); +checkRange(45640, 45742, 42); +checkRange(45742, 45832, 72); +checkRange(45832, 45999, 92); +checkRange(45999, 46384, 83); +checkRange(46384, 46596, 95); +checkRange(46596, 46654, 92); +checkRange(46654, 47515, 83); +checkRange(47515, 47620, 77); +checkRange(47620, 47817, 79); +checkRange(47817, 47951, 95); +checkRange(47951, 48632, 100); +checkRange(48632, 48699, 97); +checkRange(48699, 48703, 37); +checkRange(48703, 49764, 77); +checkRange(49764, 49955, 42); +checkRange(49955, 50012, 76); +checkRange(50012, 50036, 57); +checkRange(50036, 50087, 59); +checkRange(50087, 50096, 77); +checkRange(50096, 50115, 41); +checkRange(50115, 50370, 83); +checkRange(50370, 51358, 92); +checkRange(51358, 51610, 77); +checkRange(51610, 51776, 83); +checkRange(51776, 51833, 89); +checkRange(51833, 52895, 100); +checkRange(52895, 53029, 97); +checkRange(53029, 53244, 68); +checkRange(53244, 54066, 100); +checkRange(54066, 54133, 97); +checkRange(54133, 54137, 37); +checkRange(54137, 55198, 77); +checkRange(55198, 55389, 42); +checkRange(55389, 55446, 76); +checkRange(55446, 55470, 57); +checkRange(55470, 55521, 59); +checkRange(55521, 55530, 77); +checkRange(55530, 55549, 41); +checkRange(55549, 56212, 83); +checkRange(56212, 57048, 96); +checkRange(57048, 58183, 77); +checkRange(58183, 58202, 41); +checkRange(58202, 58516, 83); +checkRange(58516, 58835, 95); +checkRange(58835, 58855, 77); +checkRange(58855, 59089, 95); +checkRange(59089, 59145, 77); +checkRange(59145, 59677, 99); +checkRange(59677, 60134, 0); +checkRange(60134, 60502, 89); +checkRange(60502, 60594, 59); +checkRange(60594, 60617, 36); +checkRange(60617, 60618, 32); +checkRange(60618, 60777, 42); +checkRange(60777, 60834, 76); +checkRange(60834, 60858, 57); +checkRange(60858, 60909, 59); +checkRange(60909, 60918, 77); +checkRange(60918, 60937, 41); +checkRange(60937, 61600, 83); +checkRange(61600, 62436, 96); +checkRange(62436, 63307, 77); +checkRange(63307, 63397, 100); +checkRange(63397, 63501, 74); +checkRange(63501, 63525, 93); +checkRange(63525, 63605, 74); +checkRange(63605, 63704, 100); +checkRange(63704, 63771, 97); +checkRange(63771, 63775, 37); +checkRange(63775, 64311, 77); +checkRange(64311, 64331, 26); +checkRange(64331, 64518, 92); +checkRange(64518, 64827, 11); +checkRange(64827, 64834, 26); +checkRange(64834, 65536, 0); diff --git a/test/meta/generate_memory_fill.js b/test/meta/generate_memory_fill.js new file mode 100644 index 0000000000..0dba569e9b --- /dev/null +++ b/test/meta/generate_memory_fill.js @@ -0,0 +1,157 @@ +// This program generates .wast code that contains all the spec tests for +// memory.fill. See `Makefile`. + +print_origin("generate_memory_fill.js"); + +let PREAMBLE = + `(memory 1 1) + ${checkRangeCode()}`; + +// Range valid +print( +` +(module + ${PREAMBLE} + (func (export "test") + (memory.fill (i32.const 0xFF00) (i32.const 0x55) (i32.const 256)))) +(invoke "test") +`); +checkRange(0x00000, 0x0FF00, 0x00) +checkRange(0x0FF00, 0x10000, 0x55) + +// Range invalid +print( +`(module + ${PREAMBLE} + (func (export "test") + (memory.fill (i32.const 0xFF00) (i32.const 0x55) (i32.const 257)))) +(assert_trap (invoke "test") "out of bounds memory access") +`); + +// Wraparound the end of 32-bit offset space +print( +`(module + ${PREAMBLE} + (func (export "test") + (memory.fill (i32.const 0xFFFFFF00) (i32.const 0x55) (i32.const 257)))) +(assert_trap (invoke "test") "out of bounds memory access") +`); + +// Zero len with offset in-bounds is a no-op +print( +`(module + ${PREAMBLE} + (func (export "test") + (memory.fill (i32.const 0x12) (i32.const 0x55) (i32.const 0)))) +(invoke "test") +`); +checkRange(0x00000, 0x10000, 0x00); + +// Zero len with offset out-of-bounds at the end of memory is allowed +print( +`(module + ${PREAMBLE} + (func (export "test") + (memory.fill (i32.const 0x10000) (i32.const 0x55) (i32.const 0)))) +(invoke "test") +`); + +// Zero len with offset out-of-bounds past the end of memory is not allowed +print( +`(module + ${PREAMBLE} + (func (export "test") + (memory.fill (i32.const 0x20000) (i32.const 0x55) (i32.const 0)))) +(assert_trap (invoke "test") "out of bounds") +`); + +// Very large range +print( +`(module + ${PREAMBLE} + (func (export "test") + (memory.fill (i32.const 0x1) (i32.const 0xAA) (i32.const 0xFFFE)))) +(invoke "test") +`); +checkRange(0x00000, 0x00001, 0x00); +checkRange(0x00001, 0x0FFFF, 0xAA); +checkRange(0x0FFFF, 0x10000, 0x00); + +// Sequencing +print( +` +(module + ${PREAMBLE} + (func (export "test") + (memory.fill (i32.const 0x12) (i32.const 0x55) (i32.const 10)) + (memory.fill (i32.const 0x15) (i32.const 0xAA) (i32.const 4)))) +(invoke "test") +`); +checkRange(0x0, 0x12+0, 0x00); +checkRange(0x12+0, 0x12+3, 0x55); +checkRange(0x12+3, 0x12+7, 0xAA); +checkRange(0x12+7, 0x12+10, 0x55); +checkRange(0x12+10, 0x10000, 0x00); + +// Sundry compilation failures. + +// Module doesn't have a memory. +print( +`(assert_invalid + (module + (func (export "testfn") + (memory.fill (i32.const 10) (i32.const 20) (i32.const 30)))) + "unknown memory 0") +`); + +// Invalid argument types. TODO: We can add anyref, funcref, etc here. +{ + const tys = ['i32', 'f32', 'i64', 'f64']; + for (let ty1 of tys) { + for (let ty2 of tys) { + for (let ty3 of tys) { + if (ty1 == 'i32' && ty2 == 'i32' && ty3 == 'i32') + continue; // this is the only valid case + print( +`(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (${ty1}.const 10) (${ty2}.const 20) (${ty3}.const 30)))) + "type mismatch") +`); + }}} +} + +// memory.fill: out of bounds, and should not perform a partial fill. +// +// Arithmetic overflow of memory offset + len should not affect the behavior, we +// should still fill up to the limit. + +function mem_fill(min, max, shared, backup, write=backup*2) { + print( +`(module + (memory ${min} ${max} ${shared}) + ${checkRangeCode()} + (func (export "run") (param $offs i32) (param $val i32) (param $len i32) + (memory.fill (local.get $offs) (local.get $val) (local.get $len)))) +`); + // A fill past the end should throw *and* not have performed a partial fill + let offs = min*PAGESIZE - backup; + let val = 37; + print( +`(assert_trap (invoke "run" (i32.const ${offs}) (i32.const ${val}) (i32.const ${write})) + "out of bounds") +`); + checkRange(0, min, 0); +} + +mem_fill(1, 1, "", 256); +mem_fill(1, 1, "", 257); +mem_fill(1, 1, "", 257, 0xFFFFFFFF); // offs + len overflows 32-bit + +if (WITH_SHARED_MEMORY) { + mem_fill(2, 4, "shared", 256); + mem_fill(2, 4, "shared", 257); + mem_fill(2, 4, "shared", 257, 0xFFFFFFFF); // offs + len overflows 32-bit +} diff --git a/test/meta/generate_memory_init.js b/test/meta/generate_memory_init.js new file mode 100644 index 0000000000..64fb07f95d --- /dev/null +++ b/test/meta/generate_memory_init.js @@ -0,0 +1,313 @@ +// This program generates .wast code that contains all the spec tests for +// memory.init and data.drop. See `Makefile`. + +print_origin("generate_memory_init.js"); + +// In-bounds tests. + +function mem_test(instruction, expected_result_vector) { + print( +` +(module + (memory (export "memory0") 1 1) + (data (i32.const 2) "\\03\\01\\04\\01") + (data "\\02\\07\\01\\08") + (data (i32.const 12) "\\07\\05\\02\\03\\06") + (data "\\05\\09\\02\\07\\06") + (func (export "test") + ${instruction}) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(invoke "test") +`); + for (let i = 0; i < expected_result_vector.length; i++) { + print(`(assert_return (invoke "load8_u" (i32.const ${i})) (i32.const ${expected_result_vector[i]}))`); + } +} + +const e = 0; + +// This just gives the initial state of the memory, with its active +// initialisers applied. +mem_test("(nop)", + [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e]); + +// Passive init that overwrites all-zero entries +mem_test("(memory.init 1 (i32.const 7) (i32.const 0) (i32.const 4))", + [e,e,3,1,4, 1,e,2,7,1, 8,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e]); + +// Passive init that overwrites existing active-init-created entries +mem_test("(memory.init 3 (i32.const 15) (i32.const 1) (i32.const 3))", + [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 9,2,7,e,e, e,e,e,e,e, e,e,e,e,e]); + +// Perform active and passive initialisation and then multiple copies +mem_test(`(memory.init 1 (i32.const 7) (i32.const 0) (i32.const 4)) + (data.drop 1) + (memory.init 3 (i32.const 15) (i32.const 1) (i32.const 3)) + (data.drop 3) + (memory.copy (i32.const 20) (i32.const 15) (i32.const 5)) + (memory.copy (i32.const 21) (i32.const 29) (i32.const 1)) + (memory.copy (i32.const 24) (i32.const 10) (i32.const 1)) + (memory.copy (i32.const 13) (i32.const 11) (i32.const 4)) + (memory.copy (i32.const 19) (i32.const 20) (i32.const 5))`, + [e,e,3,1,4, 1,e,2,7,1, 8,e,7,e,7, 5,2,7,e,9, e,7,e,8,8, e,e,e,e,e]); + +// Miscellaneous + +let PREAMBLE = + `(memory 1) + (data "\\37")`; + +// drop with no memory +print( +`(assert_invalid + (module + (func (export "test") + (data.drop 0))) + "unknown memory 0") +`); + +// drop with data seg ix out of range +print( +`(assert_invalid + (module + ${PREAMBLE} + (func (export "test") + (data.drop 4))) + "unknown data segment") +`); + +// drop, then drop +print( +`(module + ${PREAMBLE} + (func (export "test") + (data.drop 0) + (data.drop 0))) +(invoke "test") +`); + +// drop, then init +print( +`(module + ${PREAMBLE} + (func (export "test") + (data.drop 0) + (memory.init 0 (i32.const 1234) (i32.const 1) (i32.const 1)))) +(assert_trap (invoke "test") "out of bounds") +`); + +// init with data seg ix indicating an active segment +print( +`(module + (memory 1) + (data (i32.const 0) "\\37") + (func (export "test") + (memory.init 0 (i32.const 1234) (i32.const 1) (i32.const 1)))) +(assert_trap (invoke "test") "out of bounds") +`); + +// init with no memory +print( +`(assert_invalid + (module + (func (export "test") + (memory.init 1 (i32.const 1234) (i32.const 1) (i32.const 1)))) + "unknown memory 0") +`); + +// init with data seg ix out of range +print( +`(assert_invalid + (module + ${PREAMBLE} + (func (export "test") + (memory.init 1 (i32.const 1234) (i32.const 1) (i32.const 1)))) + "unknown data segment 1") +`); + +// init, using a data seg ix more than once is OK +print( +`(module + ${PREAMBLE} + (func (export "test") + (memory.init 0 (i32.const 1) (i32.const 0) (i32.const 1)) + (memory.init 0 (i32.const 1) (i32.const 0) (i32.const 1)))) +(invoke "test") +`); + +// init: seg ix is valid passive, but length to copy > len of seg +print( +`(module + ${PREAMBLE} + (func (export "test") + (memory.init 0 (i32.const 1234) (i32.const 0) (i32.const 5)))) +(assert_trap (invoke "test") "out of bounds") +`); + +// init: seg ix is valid passive, but implies copying beyond end of seg +print( +`(module + ${PREAMBLE} + (func (export "test") + (memory.init 0 (i32.const 1234) (i32.const 2) (i32.const 3)))) +(assert_trap (invoke "test") "out of bounds") +`); + +// init: seg ix is valid passive, but implies copying beyond end of dst +print( +`(module + ${PREAMBLE} + (func (export "test") + (memory.init 0 (i32.const 0xFFFE) (i32.const 1) (i32.const 3)))) +(assert_trap (invoke "test") "out of bounds") +`); + +// init: seg ix is valid passive, src offset past the end, zero len is invalid +print( +`(module + ${PREAMBLE} + (func (export "test") + (memory.init 0 (i32.const 1234) (i32.const 4) (i32.const 0)))) +(assert_trap (invoke "test") "out of bounds") +`); + +// init: seg ix is valid passive, zero len, src offset at the end +print( +`(module + ${PREAMBLE} + (func (export "test") + (memory.init 0 (i32.const 1234) (i32.const 1) (i32.const 0)))) +(invoke "test") +`); + +// init: seg ix is valid passive, dst offset past the end, zero len is invalid +print( +`(module + ${PREAMBLE} + (func (export "test") + (memory.init 0 (i32.const 0x10001) (i32.const 0) (i32.const 0)))) +(assert_trap (invoke "test") "out of bounds") +`); + +// init: seg ix is valid passive, zero len, but dst offset at the end +print( +`(module + ${PREAMBLE} + (func (export "test") + (memory.init 0 (i32.const 0x10000) (i32.const 0) (i32.const 0)))) +(invoke "test") +`); + +// init: seg ix is valid passive, zero len, dst and src offsets at the end +print( +`(module + ${PREAMBLE} + (func (export "test") + (memory.init 0 (i32.const 0x10000) (i32.const 1) (i32.const 0)))) +(invoke "test") +`); + +// init: seg ix is valid passive, src and dst offset past the end, zero len is +// invalid +print( +`(module + ${PREAMBLE} + (func (export "test") + (memory.init 0 (i32.const 0x10001) (i32.const 4) (i32.const 0)))) +(assert_trap (invoke "test") "out of bounds") +`); + +// invalid argument types. TODO: can add anyfunc etc here. +{ + const tys = ['i32', 'f32', 'i64', 'f64']; + + for (let ty1 of tys) { + for (let ty2 of tys) { + for (let ty3 of tys) { + if (ty1 == 'i32' && ty2 == 'i32' && ty3 == 'i32') + continue; // this is the only valid case + print( +`(assert_invalid + (module + ${PREAMBLE} + (func (export "test") + (memory.init 0 (${ty1}.const 1) (${ty2}.const 1) (${ty3}.const 1)))) + "type mismatch") +`); + }}} +} + +// memory.init: out of bounds of the memory or the segment, but should perform +// the operation up to the appropriate bound. +// +// Arithmetic overflow of memoffset + len or of bufferoffset + len should not +// affect the behavior. + +// Note, the length of the data segment is 16. +const mem_init_len = 16; + +function mem_init(min, max, shared, backup, write) { + print( +`(module + (memory ${min} ${max} ${shared}) + (data "\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42") + ${checkRangeCode()} + (func (export "run") (param $offs i32) (param $len i32) + (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len)))) +`); + // A fill writing past the end of the memory should throw *and* have filled + // all the way up to the end. + // + // A fill reading past the end of the segment should throw *and* have filled + // memory with as much data as was available. + let offs = min*PAGESIZE - backup; + print( +`(assert_trap (invoke "run" (i32.const ${offs}) (i32.const ${write})) + "out of bounds") +`); + checkRange(0, min, 0); +} + +// We exceed the bounds of the memory but not of the data segment +mem_init(1, 1, "", Math.floor(mem_init_len/2), mem_init_len); +mem_init(1, 1, "", Math.floor(mem_init_len/2)+1, mem_init_len); +if (WITH_SHARED_MEMORY) { + mem_init(2, 4, "shared", Math.floor(mem_init_len/2), mem_init_len); + mem_init(2, 4, "shared", Math.floor(mem_init_len/2)+1, mem_init_len); +} + +// We exceed the bounds of the data segment but not the memory +mem_init(1, 1, "", mem_init_len*4, mem_init_len*2-2); +mem_init(1, 1, "", mem_init_len*4-1, mem_init_len*2-1); +if (WITH_SHARED_MEMORY) { + mem_init(2, 4, "shared", mem_init_len*4, mem_init_len*2-2); + mem_init(2, 4, "shared", mem_init_len*4-1, mem_init_len*2-1); +} + +// We arithmetically overflow the memory limit but not the segment limit +mem_init(1, "", "", Math.floor(mem_init_len/2), 0xFFFFFF00); + +// We arithmetically overflow the segment limit but not the memory limit +mem_init(1, "", "", PAGESIZE, 0xFFFFFFFC); + +// Test that the data segment index is properly encoded as an unsigned (not +// signed) LEB. +print( +` +(module + (memory 1) + ;; 65 data segments. 64 is the smallest positive number that is encoded + ;; differently as a signed LEB. + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") + (func (memory.init 64 (i32.const 0) (i32.const 0) (i32.const 0)))) +`) diff --git a/test/meta/generate_table_copy.js b/test/meta/generate_table_copy.js new file mode 100644 index 0000000000..63aa53b06b --- /dev/null +++ b/test/meta/generate_table_copy.js @@ -0,0 +1,359 @@ +// This program generates .wast code that contains all the spec tests for +// table.copy. See `Makefile`. + +print_origin("generate_table_copy.js"); + +// This module "a" exports 5 functions ... + +function emit_a() { + print( +` +(module + (func (export "ef0") (result i32) (i32.const 0)) + (func (export "ef1") (result i32) (i32.const 1)) + (func (export "ef2") (result i32) (i32.const 2)) + (func (export "ef3") (result i32) (i32.const 3)) + (func (export "ef4") (result i32) (i32.const 4)) +) +(register "a")`); +} + +// ... and this one imports those 5 functions. It adds 5 of its own, creates a +// 30 element table using both active and passive initialisers, with a mixture +// of the imported and local functions. |test| is exported. It uses the +// supplied |insn| to modify the table somehow. |check| will then indirect-call +// the table entry number specified as a parameter. That will either return a +// value 0 to 9 indicating the function called, or will throw an exception if +// the table entry is empty. + +function emit_b(insn, t0, t1) { + print( +` +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t${t0}) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t${t0}) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (table $t${t1}) (i32.const 3) func 1 3 1 4) + (elem (table $t${t1}) (i32.const 11) func 6 3 2 5 7) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + ${insn}) + (func (export "check_t0") (param i32) (result i32) + (call_indirect $t${t0} (type 0) (local.get 0))) + (func (export "check_t1") (param i32) (result i32) + (call_indirect $t${t1} (type 0) (local.get 0))) +) +`); +} + +// This is the test driver. It constructs the abovementioned module, using the +// given |instruction| to modify the table, and then probes the table by making +// indirect calls, one for each element of |expected_result_vector|. The +// results are compared to those in the vector. +// +// "dest_table" may be t0 or t1. + +function tab_test(args, t0, t1, dest_table, expected_t0, expected_t1) { + if (typeof args != "string") + emit_b("(nop)", t0, t1); + else + emit_b(`(table.copy $t${dest_table} $t${t0} ${args})`, t0, t1); + print(`(invoke "test")`); + for (let i = 0; i < expected_t0.length; i++) { + let expected = expected_t0[i]; + if (expected === undefined) { + print(`(assert_trap (invoke "check_t0" (i32.const ${i})) "uninitialized element")`); + } else { + print(`(assert_return (invoke "check_t0" (i32.const ${i})) (i32.const ${expected}))`); + } + } + for (let i = 0; i < expected_t1.length; i++) { + let expected = expected_t1[i]; + if (expected === undefined) { + print(`(assert_trap (invoke "check_t1" (i32.const ${i})) "uninitialized element")`); + } else { + print(`(assert_return (invoke "check_t1" (i32.const ${i})) (i32.const ${expected}))`); + } + } +} + +emit_a(); + +// Using 'e' for empty (undefined) spaces in the table, to make it easier +// to count through the vector entries when debugging. +let e = undefined; + +for ( let table of [0,1] ) { + let other_table = (table + 1) % 2; + + // Tests for copying in a single table. + + // This just gives the initial state of the table, with its active + // initialisers applied + tab_test(false, table, other_table, table, + [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e], + [e,e,e,1,3, 1,4,e,e,e, e,6,3,2,5, 7,e,e,e,e, e,e,e,e,e, e,e,e,e,e]); + + // Copy non-null over non-null + tab_test("(i32.const 13) (i32.const 2) (i32.const 3)", table, other_table, table, + [e,e,3,1,4, 1,e,e,e,e, e,e,7,3,1, 4,6,e,e,e, e,e,e,e,e, e,e,e,e,e], + [e,e,e,1,3, 1,4,e,e,e, e,6,3,2,5, 7,e,e,e,e, e,e,e,e,e, e,e,e,e,e]); + + // Copy non-null over null + tab_test("(i32.const 25) (i32.const 15) (i32.const 2)", table, other_table, table, + [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, 3,6,e,e,e], + [e,e,e,1,3, 1,4,e,e,e, e,6,3,2,5, 7,e,e,e,e, e,e,e,e,e, e,e,e,e,e]); + + // Copy null over non-null + tab_test("(i32.const 13) (i32.const 25) (i32.const 3)", table, other_table, table, + [e,e,3,1,4, 1,e,e,e,e, e,e,7,e,e, e,6,e,e,e, e,e,e,e,e, e,e,e,e,e], + [e,e,e,1,3, 1,4,e,e,e, e,6,3,2,5, 7,e,e,e,e, e,e,e,e,e, e,e,e,e,e]); + + // Copy null over null + tab_test("(i32.const 20) (i32.const 22) (i32.const 4)", table, other_table, table, + [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e], + [e,e,e,1,3, 1,4,e,e,e, e,6,3,2,5, 7,e,e,e,e, e,e,e,e,e, e,e,e,e,e]); + + // Copy null and non-null entries, non overlapping + tab_test("(i32.const 25) (i32.const 1) (i32.const 3)", table, other_table, table, + [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,3,1,e,e], + [e,e,e,1,3, 1,4,e,e,e, e,6,3,2,5, 7,e,e,e,e, e,e,e,e,e, e,e,e,e,e]); + + // Copy null and non-null entries, overlapping, backwards + tab_test("(i32.const 10) (i32.const 12) (i32.const 7)", table, other_table, table, + [e,e,3,1,4, 1,e,e,e,e, 7,5,2,3,6, e,e,e,e,e, e,e,e,e,e, e,e,e,e,e], + [e,e,e,1,3, 1,4,e,e,e, e,6,3,2,5, 7,e,e,e,e, e,e,e,e,e, e,e,e,e,e]); + + // Copy null and non-null entries, overlapping, forwards + tab_test("(i32.const 12) (i32.const 10) (i32.const 7)", table, other_table, table, + [e,e,3,1,4, 1,e,e,e,e, e,e,e,e,7, 5,2,3,6,e, e,e,e,e,e, e,e,e,e,e], + [e,e,e,1,3, 1,4,e,e,e, e,6,3,2,5, 7,e,e,e,e, e,e,e,e,e, e,e,e,e,e]); + + // Tests for copying from one table to the other. Here, overlap and copy + // direction don't matter. + + tab_test("(i32.const 10) (i32.const 0) (i32.const 20)", table, other_table, other_table, + [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e], + [e,e,e,1,3, 1,4,e,e,e, e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e]); +} + +// Out-of-bounds checks. + +function do_test(insn1, insn2, errText) +{ + print(` +(module + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + ${insn1} + ${insn2})) +`); + + if (errText !== undefined) { + print(`(assert_trap (invoke "test") "${errText}")`); + } else { + print(`(invoke "test")`); + } +} + +function tab_test2(insn1, insn2, errKind, errText) { + do_test(insn1, insn2, errKind, errText); +} + +function tab_test_nofail(insn1, insn2) { + do_test(insn1, insn2, undefined, undefined); +} + +for ( let dest of ["$t0","$t1"] ) { + // Here we test the boundary-failure cases. The table's valid indices are 0..29 + // inclusive. + + // copy: dst range invalid + tab_test2(`(table.copy ${dest} $t0 (i32.const 28) (i32.const 1) (i32.const 3))`, + "", + "out of bounds"); + + // copy: dst wraparound end of 32 bit offset space + tab_test2(`(table.copy ${dest} $t0 (i32.const 0xFFFFFFFE) (i32.const 1) (i32.const 2))`, + "", + "out of bounds"); + + // copy: src range invalid + tab_test2(`(table.copy ${dest} $t0 (i32.const 15) (i32.const 25) (i32.const 6))`, + "", + "out of bounds"); + + // copy: src wraparound end of 32 bit offset space + tab_test2(`(table.copy ${dest} $t0 (i32.const 15) (i32.const 0xFFFFFFFE) (i32.const 2))`, + "", + "out of bounds"); + + // copy: zero length with both offsets in-bounds is OK + tab_test_nofail( + `(table.copy ${dest} $t0 (i32.const 15) (i32.const 25) (i32.const 0))`, + ""); + + // copy: zero length with dst offset out of bounds at the end of the table is allowed + tab_test2(`(table.copy ${dest} $t0 (i32.const 30) (i32.const 15) (i32.const 0))`, + "", + undefined); + + // copy: zero length with dst offset out of bounds past the end of the table is not allowed + tab_test2(`(table.copy ${dest} $t0 (i32.const 31) (i32.const 15) (i32.const 0))`, + "", + "out of bounds"); + + // copy: zero length with src offset out of bounds at the end of the table is allowed + tab_test2(`(table.copy ${dest} $t0 (i32.const 15) (i32.const 30) (i32.const 0))`, + "", + undefined); + + // copy: zero length with src offset out of bounds past the end of the table is not allowed + tab_test2(`(table.copy ${dest} $t0 (i32.const 15) (i32.const 31) (i32.const 0))`, + "", + "out of bounds"); + + // copy: zero length with both dst and src offset out of bounds at the end of the table is allowed + tab_test2(`(table.copy ${dest} $t0 (i32.const 30) (i32.const 30) (i32.const 0))`, + "", + undefined); + + // copy: zero length with both dst and src offset out of bounds past the end of the table is not allowed + tab_test2(`(table.copy ${dest} $t0 (i32.const 31) (i32.const 31) (i32.const 0))`, + "", + "out of bounds"); +} + +// table.copy: out of bounds of the table for the source or target, but should +// perform the operation up to the appropriate bound. Major cases: +// +// - non-overlapping regions +// - overlapping regions with src > dest +// - overlapping regions with src == dest +// - overlapping regions with src < dest +// - arithmetic overflow on src addresses +// - arithmetic overflow on target addresses +// +// for each of those, +// +// - src address oob +// - target address oob +// - both oob + +const tbl_copy_len = 16; + +function tbl_copy(min, max, srcOffs, targetOffs, len) { + let copyDown = srcOffs < targetOffs; + let tblLength = min; + + let targetAvail = tblLength - targetOffs; + let srcAvail = tblLength - srcOffs; + let targetLim = targetOffs + Math.min(len, targetAvail, srcAvail); + let srcLim = srcOffs + Math.min(len, targetAvail, srcAvail); + + print( + ` +(module + (type (func (result i32))) + (table ${min} ${max} funcref) + (elem (i32.const ${srcOffs}) + ${(function () { + var s = ""; + for (let i=srcOffs, j=0; i < srcLim; i++, j++) + s += " $f" + j; + return s; + })()}) + (func $f0 (export "f0") (result i32) (i32.const 0)) + (func $f1 (export "f1") (result i32) (i32.const 1)) + (func $f2 (export "f2") (result i32) (i32.const 2)) + (func $f3 (export "f3") (result i32) (i32.const 3)) + (func $f4 (export "f4") (result i32) (i32.const 4)) + (func $f5 (export "f5") (result i32) (i32.const 5)) + (func $f6 (export "f6") (result i32) (i32.const 6)) + (func $f7 (export "f7") (result i32) (i32.const 7)) + (func $f8 (export "f8") (result i32) (i32.const 8)) + (func $f9 (export "f9") (result i32) (i32.const 9)) + (func $f10 (export "f10") (result i32) (i32.const 10)) + (func $f11 (export "f11") (result i32) (i32.const 11)) + (func $f12 (export "f12") (result i32) (i32.const 12)) + (func $f13 (export "f13") (result i32) (i32.const 13)) + (func $f14 (export "f14") (result i32) (i32.const 14)) + (func $f15 (export "f15") (result i32) (i32.const 15)) + (func (export "test") (param $n i32) (result i32) + (call_indirect (type 0) (local.get $n))) + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))) +`); + + let immediateOOB = copyDown && (srcOffs + len > tblLength || targetOffs + len > tblLength); + + print(`(assert_trap (invoke "run" (i32.const ${targetOffs}) (i32.const ${srcOffs}) (i32.const ${len})) + "out of bounds")`); + + var s = 0; + var i = 0; + for (i=0; i < tblLength; i++ ) { + if (i >= srcOffs && i < srcLim) { + print(`(assert_return (invoke "test" (i32.const ${i})) (i32.const ${s++}))`); + continue; + } + print(`(assert_trap (invoke "test" (i32.const ${i})) "uninitialized element")`); + } +} + +// OOB target address, nonoverlapping +tbl_copy(tbl_copy_len*2, tbl_copy_len*4, 0, Math.floor(1.5*tbl_copy_len), tbl_copy_len); +tbl_copy(tbl_copy_len*2, tbl_copy_len*4, 0, Math.floor(1.5*tbl_copy_len)-1, tbl_copy_len-1); + +// OOB source address, nonoverlapping +tbl_copy(tbl_copy_len*2, tbl_copy_len*4, Math.floor(1.5*tbl_copy_len), 0, tbl_copy_len); +tbl_copy(tbl_copy_len*2, tbl_copy_len*4, Math.floor(1.5*tbl_copy_len)-1, 0, tbl_copy_len-1); + +// OOB target address, overlapping, src < target +tbl_copy(tbl_copy_len*2, tbl_copy_len*4, tbl_copy_len-5, Math.floor(1.5*tbl_copy_len), tbl_copy_len); + +// OOB source address, overlapping, target < src +tbl_copy(tbl_copy_len*2, tbl_copy_len*4, Math.floor(1.5*tbl_copy_len), tbl_copy_len-5, tbl_copy_len); + +// OOB both, overlapping, including src == target +tbl_copy(tbl_copy_len*2, tbl_copy_len*4, tbl_copy_len+5, Math.floor(1.5*tbl_copy_len), tbl_copy_len); +tbl_copy(tbl_copy_len*2, tbl_copy_len*4, Math.floor(1.5*tbl_copy_len), tbl_copy_len+5, tbl_copy_len); +tbl_copy(tbl_copy_len*2, tbl_copy_len*4, tbl_copy_len+5, tbl_copy_len+5, tbl_copy_len); + +// Arithmetic overflow on source address. +tbl_copy(tbl_copy_len*8, tbl_copy_len*8, tbl_copy_len*7, 0, 0xFFFFFFE0); + +// Arithmetic overflow on target adddress is an overlapping case. +tbl_copy(tbl_copy_len*8, tbl_copy_len*8, 0, tbl_copy_len*7, 0xFFFFFFE0); diff --git a/test/meta/generate_table_init.js b/test/meta/generate_table_init.js new file mode 100644 index 0000000000..2f5ec4c775 --- /dev/null +++ b/test/meta/generate_table_init.js @@ -0,0 +1,387 @@ +// This program generates .wast code that contains all the spec tests for +// table.init and elem.drop. See `Makefile`. + +print_origin("generate_table_init.js"); + +// This module "a" exports 5 functions ... + +function emit_a() { + print( +` +(module + (func (export "ef0") (result i32) (i32.const 0)) + (func (export "ef1") (result i32) (i32.const 1)) + (func (export "ef2") (result i32) (i32.const 2)) + (func (export "ef3") (result i32) (i32.const 3)) + (func (export "ef4") (result i32) (i32.const 4)) +) +(register "a")`); +} + +// ... and this one imports those 5 functions. It adds 5 of its own, creates a +// 30 element table using both active and passive initialisers, with a mixture +// of the imported and local functions. |test| is exported. It uses the +// supplied |insn| to modify the table somehow. |check| will then indirect-call +// the table entry number specified as a parameter. That will either return a +// value 0 to 9 indicating the function called, or will throw an exception if +// the table entry is empty. + +function emit_b(insn, table) { + print( +` +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t${table}) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t${table}) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + ${insn}) + (func (export "check") (param i32) (result i32) + (call_indirect $t${table} (type 0) (local.get 0))) +) +`); +} + +// This is the test driver. It constructs the abovementioned module, using the +// given |instruction| to modify the table, and then probes the table by making +// indirect calls, one for each element of |expected_result_vector|. The +// results are compared to those in the vector. + +function tab_test(instruction, table, expected_result_vector) { + emit_b(instruction, table); + print(`(invoke "test")`); + for (let i = 0; i < expected_result_vector.length; i++) { + let expected = expected_result_vector[i]; + if (expected === undefined) { + print(`(assert_trap (invoke "check" (i32.const ${i})) "uninitialized element")`); + } else { + print(`(assert_return (invoke "check" (i32.const ${i})) (i32.const ${expected}))`); + } + } +} + +emit_a(); + +// Using 'e' for empty (undefined) spaces in the table, to make it easier +// to count through the vector entries when debugging. +let e = undefined; + +for ( let table of [0, 1] ) { + // Passive init that overwrites all-null entries + tab_test(`(table.init $t${table} 1 (i32.const 7) (i32.const 0) (i32.const 4))`, + table, + [e,e,3,1,4, 1,e,2,7,1, 8,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e]); + + // Passive init that overwrites existing active-init-created entries + tab_test(`(table.init $t${table} 3 (i32.const 15) (i32.const 1) (i32.const 3))`, + table, + [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 9,2,7,e,e, e,e,e,e,e, e,e,e,e,e]); + + // Perform active and passive initialisation and then multiple copies + tab_test( + `(table.init $t${table} 1 (i32.const 7) (i32.const 0) (i32.const 4)) + (elem.drop 1) + (table.init $t${table} 3 (i32.const 15) (i32.const 1) (i32.const 3)) + (elem.drop 3) + (table.copy $t${table} ${table} (i32.const 20) (i32.const 15) (i32.const 5)) + (table.copy $t${table} ${table} (i32.const 21) (i32.const 29) (i32.const 1)) + (table.copy $t${table} ${table} (i32.const 24) (i32.const 10) (i32.const 1)) + (table.copy $t${table} ${table} (i32.const 13) (i32.const 11) (i32.const 4)) + (table.copy $t${table} ${table} (i32.const 19) (i32.const 20) (i32.const 5))`, + table, + [e,e,3,1,4, 1,e,2,7,1, 8,e,7,e,7, 5,2,7,e,9, e,7,e,8,8, e,e,e,e,e]); +} + +// elem.drop requires a table, minimally +print( +`(assert_invalid + (module + (func (export "test") + (elem.drop 0))) + "unknown table 0") +`); + +// table.init requires a table, minimally +print( +`(assert_invalid + (module + (func (export "test") + (table.init 0 (i32.const 12) (i32.const 1) (i32.const 1)))) + "unknown table 0") +`); + +// elem.drop with elem seg ix out of range +print( +`(assert_invalid + (module + (elem funcref (ref.func 0)) + (func (result i32) (i32.const 0)) + (func (export "test") + (elem.drop 4))) + "unknown table 0") +`); + +// init with elem seg ix out of range +print( +`(assert_invalid + (module + (elem funcref (ref.func 0)) + (func (result i32) (i32.const 0)) + (func (export "test") + (table.init 4 (i32.const 12) (i32.const 1) (i32.const 1)))) + "unknown table 0") +`); + +let tab0_len = 30; +let tab1_len = 28; + +function do_test(insn1, insn2, table, errText) +{ + print(` +(module + (table $t0 ${tab0_len} ${tab0_len} funcref) + (table $t1 ${tab1_len} ${tab1_len} funcref) + (elem (table $t${table}) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t${table}) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + ${insn1} + ${insn2}))`); + + if (errText !== undefined) { + print(`(assert_trap (invoke "test") "${errText}")`); + } else { + print(`(invoke "test")`); + } +} + +function tab_test1(insn1, table, errText) { + do_test(insn1, "", table, errText); +} + +function tab_test2(insn1, insn2, errText) { + do_test(insn1, insn2, 0, errText); +} + +// drop with elem seg ix indicating an active segment +tab_test1("(elem.drop 2)", 0, + undefined); + +// init with elem seg ix indicating an active segment +tab_test1("(table.init 2 (i32.const 12) (i32.const 1) (i32.const 1))", 0, + "out of bounds"); + +// init, using an elem seg ix more than once is OK +tab_test2( + "(table.init 1 (i32.const 12) (i32.const 1) (i32.const 1))", + "(table.init 1 (i32.const 21) (i32.const 1) (i32.const 1))", + undefined); + +// drop, then drop +tab_test2("(elem.drop 1)", + "(elem.drop 1)", + undefined); + +// drop, then init +tab_test2("(elem.drop 1)", + "(table.init 1 (i32.const 12) (i32.const 1) (i32.const 1))", + "out of bounds"); + +// init: seg ix is valid passive, but length to copy > len of seg +tab_test1("(table.init 1 (i32.const 12) (i32.const 0) (i32.const 5))", 0, + "out of bounds"); + +// init: seg ix is valid passive, but implies copying beyond end of seg +tab_test1("(table.init 1 (i32.const 12) (i32.const 2) (i32.const 3))", 0, + "out of bounds"); + +// Tables are of different length with t1 shorter than t0, to test that we're not +// using t0's limit for t1's bound + +for ( let [table, oobval] of [[0,30],[1,28]] ) { + // init: seg ix is valid passive, but implies copying beyond end of dst + tab_test1(`(table.init $t${table} 1 (i32.const ${oobval-2}) (i32.const 1) (i32.const 3))`, + table, + "out of bounds"); + + // init: seg ix is valid passive, zero len, and src offset out of bounds at the + // end of the table - this is allowed + tab_test1(`(table.init $t${table} 1 (i32.const 12) (i32.const 4) (i32.const 0))`, + table, + undefined); + + // init: seg ix is valid passive, zero len, and src offset out of bounds past the + // end of the table - this is not allowed + tab_test1(`(table.init $t${table} 1 (i32.const 12) (i32.const 5) (i32.const 0))`, + table, + "out of bounds"); + + // init: seg ix is valid passive, zero len, and dst offset out of bounds at the + // end of the table - this is allowed + tab_test1(`(table.init $t${table} 1 (i32.const ${oobval}) (i32.const 2) (i32.const 0))`, + table, + undefined); + + // init: seg ix is valid passive, zero len, and dst offset out of bounds past the + // end of the table - this is not allowed + tab_test1(`(table.init $t${table} 1 (i32.const ${oobval+1}) (i32.const 2) (i32.const 0))`, + table, + "out of bounds"); + + // init: seg ix is valid passive, zero len, and dst and src offsets out of bounds + // at the end of the table - this is allowed + tab_test1(`(table.init $t${table} 1 (i32.const ${oobval}) (i32.const 4) (i32.const 0))`, + table, + undefined); + + // init: seg ix is valid passive, zero len, and src/dst offset out of bounds past the + // end of the table - this is not allowed + tab_test1(`(table.init $t${table} 1 (i32.const ${oobval+1}) (i32.const 5) (i32.const 0))`, + table, + "out of bounds"); +} + +// invalid argument types +{ + const tys = ['i32', 'f32', 'i64', 'f64']; + + for (let ty1 of tys) { + for (let ty2 of tys) { + for (let ty3 of tys) { + if (ty1 == 'i32' && ty2 == 'i32' && ty3 == 'i32') + continue; // this is the only valid case + print( +` +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (${ty1}.const 1) (${ty2}.const 1) (${ty3}.const 1)))) + "type mismatch")`); + }}} +} + +// table.init: out of bounds of the table or the element segment, but should +// perform the operation up to the appropriate bound. +// +// Arithmetic overflow of tableoffset + len or of segmentoffset + len should not +// affect the behavior. + +// Note, the length of the element segment is 16. +const tbl_init_len = 16; + +function tbl_init(min, max, backup, write, segoffs=0) { + print( + ` +(module + (type (func (result i32))) + (table ${min} ${max} funcref) + (elem funcref + (ref.func $f0) (ref.func $f1) (ref.func $f2) (ref.func $f3) + (ref.func $f4) (ref.func $f5) (ref.func $f6) (ref.func $f7) + (ref.func $f8) (ref.func $f9) (ref.func $f10) (ref.func $f11) + (ref.func $f12) (ref.func $f13) (ref.func $f14) (ref.func $f15)) + (func $f0 (export "f0") (result i32) (i32.const 0)) + (func $f1 (export "f1") (result i32) (i32.const 1)) + (func $f2 (export "f2") (result i32) (i32.const 2)) + (func $f3 (export "f3") (result i32) (i32.const 3)) + (func $f4 (export "f4") (result i32) (i32.const 4)) + (func $f5 (export "f5") (result i32) (i32.const 5)) + (func $f6 (export "f6") (result i32) (i32.const 6)) + (func $f7 (export "f7") (result i32) (i32.const 7)) + (func $f8 (export "f8") (result i32) (i32.const 8)) + (func $f9 (export "f9") (result i32) (i32.const 9)) + (func $f10 (export "f10") (result i32) (i32.const 10)) + (func $f11 (export "f11") (result i32) (i32.const 11)) + (func $f12 (export "f12") (result i32) (i32.const 12)) + (func $f13 (export "f13") (result i32) (i32.const 13)) + (func $f14 (export "f14") (result i32) (i32.const 14)) + (func $f15 (export "f15") (result i32) (i32.const 15)) + (func (export "test") (param $n i32) (result i32) + (call_indirect (type 0) (local.get $n))) + (func (export "run") (param $offs i32) (param $len i32) + (table.init 0 (local.get $offs) (i32.const ${segoffs}) (local.get $len))))`); + + // A fill writing past the end of the table should throw *and* have filled + // all the way up to the end. + // + // A fill reading past the end of the segment should throw *and* have filled + // table with as much data as was available. + let offs = min - backup; + print(`(assert_trap (invoke "run" (i32.const ${offs}) (i32.const ${write})) "out of bounds")`); + for (let i=0; i < min; i++) { + print(`(assert_trap (invoke "test" (i32.const ${i})) "uninitialized element")`); + } +} + +// We exceed the bounds of the table but not of the element segment +tbl_init(tbl_init_len*2, tbl_init_len*4, Math.floor(tbl_init_len/2), tbl_init_len); +tbl_init(tbl_init_len*2, tbl_init_len*4, Math.floor(tbl_init_len/2)-1, tbl_init_len); + +// We exceed the bounds of the element segment but not the table +tbl_init(tbl_init_len*10, tbl_init_len*20, tbl_init_len*4, tbl_init_len*2); +tbl_init(tbl_init_len*10, tbl_init_len*20, tbl_init_len*4-1, tbl_init_len*2-1); + +// We arithmetically overflow the table limit but not the segment limit +tbl_init(tbl_init_len*4, tbl_init_len*4, tbl_init_len, 0xFFFFFFF0); + +// We arithmetically overflow the segment limit but not the table limit +tbl_init(tbl_init_len, tbl_init_len, tbl_init_len, 0xFFFFFFFC, Math.floor(tbl_init_len/2)); + +// Test that the elem segment index is properly encoded as an unsigned (not +// signed) LEB. +print( +` +(module + (table 1 funcref) + ;; 65 elem segments. 64 is the smallest positive number that is encoded + ;; differently as a signed LEB. + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) + (func (table.init 64 (i32.const 0) (i32.const 0) (i32.const 0)))) +`) diff --git a/test/meta/noderun.sh b/test/meta/noderun.sh new file mode 100755 index 0000000000..7b07a28cf9 --- /dev/null +++ b/test/meta/noderun.sh @@ -0,0 +1,16 @@ +if [ $# -ne 2 ]; then + echo "Bad args" + exit 1 +fi + +rm -f nodeprog.js +cat <> nodeprog.js +const WITH_SHARED_MEMORY=$1; +function print(x) { + console.log(x); +} +EOF +cat common.js >> nodeprog.js +cat $2 >> nodeprog.js +node nodeprog.js +rm nodeprog.js