diff --git a/.github/workflows/ci-spec.yml b/.github/workflows/ci-spec.yml index cda39a8dbf..254ffd7579 100644 --- a/.github/workflows/ci-spec.yml +++ b/.github/workflows/ci-spec.yml @@ -35,7 +35,7 @@ jobs: - name: Setup TexLive run: sudo apt-get update -y && sudo apt-get install -y latexmk texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended - name: Setup Sphinx - run: pip install six && pip install sphinx==8.0.0 + run: pip install six && pip install sphinx==8.1.3 - name: Build SpecTec run: cd spectec && opam exec make - name: Build main spec @@ -83,13 +83,13 @@ jobs: needs: [build-core-spec] steps: - name: Checkout repo - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: submodules: "recursive" - name: Setup TexLive run: sudo apt-get update -y && sudo apt-get install -y latexmk texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended - name: Setup Sphinx - run: pip install six && pip install sphinx==8.0.0 + run: pip install six && pip install sphinx==8.1.3 - name: Build main spec run: cd document/metadata/code && make main - name: Upload artifact @@ -102,13 +102,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repo - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: submodules: "recursive" - name: Setup TexLive run: sudo apt-get update -y && sudo apt-get install -y latexmk texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended - name: Setup Sphinx - run: pip install six && pip install sphinx==8.0.0 + run: pip install six && pip install sphinx==8.1.3 - name: Build main spec run: cd document/legacy/exceptions/core && make main - name: Upload artifact @@ -121,7 +121,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repo - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Setup Bikeshed run: pip install bikeshed && bikeshed update - name: Run Bikeshed diff --git a/.github/workflows/ci-spectec.yml b/.github/workflows/ci-spectec.yml index 542c4ee957..cb56e2fff8 100644 --- a/.github/workflows/ci-spectec.yml +++ b/.github/workflows/ci-spectec.yml @@ -27,6 +27,6 @@ jobs: - name: Setup Latex run: sudo apt-get update -y && sudo apt-get install -y latexmk texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended - name: Setup Sphinx - run: pip install six && pip install sphinx==8.0.0 + run: pip install six && pip install sphinx==8.1.3 - name: Build and test run: cd spectec && opam exec make ci diff --git a/document/core/appendix/changes.rst b/document/core/appendix/changes.rst index 888cb48c80..7c23b20f99 100644 --- a/document/core/appendix/changes.rst +++ b/document/core/appendix/changes.rst @@ -308,7 +308,7 @@ Allowed basic numeric computations in constant expressions. [#proposal-extconst] - |GLOBALGET| for any previously declared immutable :ref:`global ` .. note:: - The :ref:`garbage collection ` added further constant instructions. + The :ref:`garbage collection ` extension added further constant instructions. .. index:: instruction, function, call @@ -462,6 +462,8 @@ Added more precise types for references. [#proposal-typedref]_ * Refined typing of :ref:`local instructions ` and :ref:`instruction sequences ` to track the :ref:`initialization status ` of :ref:`locals ` with non-defaultable type +* Refined decoding of :ref:`active ` :ref:`element segments ` with implicit element type and plain function indices (opcode :math:`0`) to produce :ref:`non-nullable ` :ref:`reference type `. + * Extended :ref:`table definitions ` with optional initializer expression @@ -622,7 +624,7 @@ mirroring the role of custom sections in the binary format. [#proposal-annot]_ .. [#proposal-extconst] - https://github.com/WebAssembly/spec/blob/main/proposals/extended-const/ + https://github.com/WebAssembly/spec/tree/main/proposals/extended-const/ .. [#proposal-tailcall] https://github.com/WebAssembly/spec/tree/main/proposals/tail-call/ @@ -631,10 +633,10 @@ mirroring the role of custom sections in the binary format. [#proposal-annot]_ https://github.com/WebAssembly/spec/tree/main/proposals/exception-handling/ .. [#proposal-multimem] - https://github.com/WebAssembly/spec/blob/main/proposals/multi-memory/ + https://github.com/WebAssembly/spec/tree/main/proposals/multi-memory/ .. [#proposal-addr64] - https://github.com/WebAssembly/spec/blob/main/proposals/memory64/ + https://github.com/WebAssembly/spec/tree/main/proposals/memory64/ .. [#proposal-typedref] https://github.com/WebAssembly/spec/tree/main/proposals/function-references/ @@ -646,4 +648,4 @@ mirroring the role of custom sections in the binary format. [#proposal-annot]_ https://github.com/WebAssembly/spec/tree/main/proposals/relaxed-simd/ .. [#proposal-annot] - https://github.com/WebAssembly/annotations/tree/main/proposals/annotations/ + https://github.com/WebAssembly/spec/tree/main/proposals/annotations/ diff --git a/document/core/appendix/index-instructions.py b/document/core/appendix/index-instructions.py index a597968798..09211d30e8 100755 --- a/document/core/appendix/index-instructions.py +++ b/document/core/appendix/index-instructions.py @@ -334,7 +334,7 @@ def Instruction(version, name, opcode, type=None, validation=None, execution=Non Instruction(3.0, r'\STRUCTGETS~x~y', r'\hex{FB}~\hex{03}', r'[(\REF~\NULL~x)] \to [\I32]', r'valid-struct.get', r'exec-struct.get'), Instruction(3.0, r'\STRUCTGETU~x~y', r'\hex{FB}~\hex{04}', r'[(\REF~\NULL~x)] \to [\I32]', r'valid-struct.get', r'exec-struct.get'), Instruction(3.0, r'\STRUCTSET~x~y', r'\hex{FB}~\hex{05}', r'[(\REF~\NULL~x)~t] \to []', r'valid-struct.set', r'exec-struct.set'), - Instruction(3.0, r'\ARRAYNEW~x', r'\hex{FB}~\hex{06}', r'[t] \to [(\REF~x)]', r'valid-array.new', r'exec-array.new'), + Instruction(3.0, r'\ARRAYNEW~x', r'\hex{FB}~\hex{06}', r'[t~\I32] \to [(\REF~x)]', r'valid-array.new', r'exec-array.new'), Instruction(3.0, r'\ARRAYNEWDEFAULT~x', r'\hex{FB}~\hex{07}', r'[\I32] \to [(\REF~x)]', r'valid-array.new', r'exec-array.new'), Instruction(3.0, r'\ARRAYNEWFIXED~x~n', r'\hex{FB}~\hex{08}', r'[t^n] \to [(\REF~x)]', r'valid-array.new_fixed', r'exec-array.new_fixed'), Instruction(3.0, r'\ARRAYNEWDATA~x~y', r'\hex{FB}~\hex{09}', r'[\I32~\I32] \to [(\REF~x)]', r'valid-array.new_data', r'exec-array.new_data'), diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index a770d941ce..d7608035df 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -196,9 +196,8 @@ $${rule: {Step_pure/ref.eq-*}} $${rule-prose: Step_read/ref.test} -.. todo:: - Below is the actual prose. - (9) Need to handle RulePr s \|- ref : rt properly in prose instead of $ref_type_of +.. todo:: (9) Need to handle RulePr s \|- ref : rt properly in prose instead of $ref_type_of + Below is the actual prose. 1. Let :math:`F` be the :ref:`current ` :ref:`frame `. @@ -229,9 +228,8 @@ $${rule: {Step_read/ref.test-*}} $${rule-prose: Step_read/ref.cast} -.. todo:: +.. todo:: (9) Need to handle RulePr s \|- ref : rt properly in prose instead of $ref_type_of Below is the actual prose. - (9) Need to handle RulePr s \|- ref : rt properly in prose instead of $ref_type_of 1. Let :math:`F` be the :ref:`current ` :ref:`frame `. @@ -269,10 +267,8 @@ $${rule: {Step_pure/ref.i31}} $${rule-prose: Step_pure/i31.get} -.. todo:: +.. todo:: (3) Introduce if-let instruction instead of "is of the case". (4) Guarantees from validation can help simplify the prose. Below is the actual prose. - (3) Introduce if-let instruction instead of "is of the case". - (4) Guarantees from validation can help simplify the prose. 1. Assert: due to :ref:`validation `, a :ref:`value ` of :ref:`type ` :math:`(\REF~\NULL~\I31)` is on the top of the stack. @@ -297,10 +293,8 @@ $${rule: {Step_pure/i31.get-*}} $${rule-prose: Step/struct.new} -.. todo:: +.. todo:: (3') Introduce let binding instead of "is of the case". (5) Use "the expansion of" instead of $expand function application. Below is the actual prose. - (3') Introduce let binding instead of "is of the case". - (5) Use "the expansion of" instead of $expand function application. 1. Let :math:`F` be the :ref:`current ` :ref:`frame `. @@ -339,10 +333,8 @@ $${rule: {Step/struct.new}} $${rule-prose: Step_read/struct.new_default} -.. todo:: +.. todo:: (3') Introduce let binding instead of "is of the case". (5) Use "the expansion of" instead of $expand function application. Below is the actual prose. - (3') Introduce let binding instead of "is of the case". - (5) Use "the expansion of" instead of $expand function application. 1. Let :math:`F` be the :ref:`current ` :ref:`frame `. @@ -374,10 +366,8 @@ $${rule: {Step_read/struct.new_default}} $${rule-prose: Step_read/struct.get} -.. todo:: +.. todo:: (3) Introduce if-let instruction instead of "is of the case". (5) Use "the expansion of" instead of $expand function application. Below is the actual prose. - (3) Introduce if-let instruction instead of "is of the case". - (5) Use "the expansion of" instead of $expand function application. 1. Let :math:`F` be the :ref:`current ` :ref:`frame `. @@ -418,10 +408,8 @@ $${rule: {Step_read/struct.get-*}} $${rule-prose: Step/struct.set} -.. todo:: +.. todo:: (3) Introduce if-let instruction instead of "is of the case". (5) Use "the expansion of" instead of $expand function application. Below is the actual prose. - (3) Introduce if-let instruction instead of "is of the case". - (5) Use "the expansion of" instead of $expand function application. 1. Let :math:`F` be the :ref:`current ` :ref:`frame `. @@ -471,10 +459,8 @@ $${rule: {Step_pure/array.new}} $${rule-prose: Step_read/array.new_default} -.. todo:: +.. todo:: (3') Introduce let binding instead of "is of the case". (5) Use "the expansion of" instead of $expand function application. Below is the actual prose. - (3') Introduce let binding instead of "is of the case". - (5) Use "the expansion of" instead of $expand function application. 1. Let :math:`F` be the :ref:`current ` :ref:`frame `. @@ -505,10 +491,8 @@ $${rule: {Step_read/array.new_default}} $${rule-prose: Step/array.new_fixed} -.. todo:: +.. todo:: (3') Introduce let binding instead of "is of the case". (5) Use "the expansion of" instead of $expand function application. Below is the actual prose. - (3') Introduce let binding instead of "is of the case". - (5) Use "the expansion of" instead of $expand function application. 1. Let :math:`F` be the :ref:`current ` :ref:`frame `. @@ -545,9 +529,8 @@ $${rule: {Step/array.new_fixed}} $${rule-prose: Step_read/array.new_data} -.. todo:: +.. todo:: (7) Render $inverse_ with display hint. Below is the actual prose. - (7) Render $inverse_ with display hint. 1. Let :math:`F` be the :ref:`current ` :ref:`frame `. @@ -610,10 +593,8 @@ $${rule: {Step_read/array.new_elem-*}} $${rule-prose: Step_read/array.get} -.. todo:: +.. todo:: (3) Introduce if-let instruction instead of "is of the case". (5) Use "the expansion of" instead of $expand function application. Below is the actual prose. - (3) Introduce if-let instruction instead of "is of the case". - (5) Use "the expansion of" instead of $expand function application. 1. Let :math:`F` be the :ref:`current ` :ref:`frame `. @@ -660,10 +641,8 @@ $${rule: {Step_read/array.get-*}} $${rule-prose: Step/array.set} -.. todo:: +.. todo:: (3) Introduce if-let instruction instead of "is of the case". (5) Use "the expansion of" instead of $expand function application. Below is the actual prose. - (3) Introduce if-let instruction instead of "is of the case". - (5) Use "the expansion of" instead of $expand function application. 1. Let :math:`F` be the :ref:`current ` :ref:`frame `. @@ -728,11 +707,8 @@ $${rule: {Step_read/array.fill-*}} .. _exec-array.copy: -.. todo:: +.. todo:: (3) Introduce if-let instruction instead of "is of the case". (5) Use "the expansion of" instead of $expand function application. + Too deeply nested Below is the actual prose. - (3) Introduce if-let instruction instead of "is of the case". - (5) Use "the expansion of" instead of $expand function application. - + Too deeply nested 1. Let :math:`F` be the :ref:`current ` :ref:`frame `. @@ -864,9 +840,8 @@ $${definition: sx} $${rule-prose: Step_read/array.init_data} -.. todo:: +.. todo:: (7) Render $inverse_ with display hint. Below is the actual prose. - (7) Render $inverse_ with display hint. 1. Let :math:`F` be the :ref:`current ` :ref:`frame `. @@ -1322,9 +1297,8 @@ Memory Instructions $${rule-prose: Step_read/load} -.. todo:: +.. todo:: (7) Render $inverse_of_nbytes with display hint. Below is the actual prose. - (7) Render $inverse_of_nbytes with display hint. 1. Let :math:`F` be the :ref:`current ` :ref:`frame `. @@ -1816,9 +1790,8 @@ $${rule: {Step_pure/br_on_non_null-*}} $${rule-prose: Step_read/br_on_cast} -.. todo:: +.. todo:: (9) Need to handle RulePr s \|- ref : rt properly in prose instead of $ref_type_of Below is the acutal prose. - (9) Need to handle RulePr s \|- ref : rt properly in prose instead of $ref_type_of 1. Let :math:`F` be the :ref:`current ` :ref:`frame `. @@ -1847,9 +1820,8 @@ $${rule: {Step_read/br_on_cast-*}} $${rule-prose: Step_read/br_on_cast_fail} -.. todo:: +.. todo:: (9) Need to handle RulePr s \|- ref : rt properly in prose instead of $ref_type_of Below is the actual prose. - (9) Need to handle RulePr s \|- ref : rt properly in prose instead of $ref_type_of 1. Let :math:`F` be the :ref:`current ` :ref:`frame `. @@ -1934,8 +1906,7 @@ $${rule: {Step_read/return_call}} :math:`\RETURNCALLREF~x` ........................ -.. todo:: - (*) Prose not spliced, Sphinx cannot build the document with deeply nested ordered list. (mainly caused by spurious conditions that should be assertions) +.. todo:: (*) Prose not spliced, Sphinx cannot build the document with deeply nested ordered list. (mainly caused by spurious conditions that should be assertions) 1. Assert: due to :ref:`validation `, a :ref:`function reference ` is on the top of the stack. diff --git a/document/core/exec/modules.rst b/document/core/exec/modules.rst index b52e42d7b6..9c32a2d757 100644 --- a/document/core/exec/modules.rst +++ b/document/core/exec/modules.rst @@ -200,7 +200,7 @@ and list of :ref:`reference ` lists for the module's :ref:`element s 8. For each :ref:`element segment ` :math:`\elem_i` in :math:`\module.\MELEMS`, do: - a. Let :math:`\reftype_i` be the element :ref:`reference type ` obtained by `instantiating ` :math:`\elem_i.\ETYPE` in :math:`\moduleinst` defined below. + a. Let :math:`\reftype_i` be the element :ref:`reference type ` obtained by :ref:`instantiating ` :math:`\elem_i.\ETYPE` in :math:`\moduleinst` defined below. b. Let :math:`\elemaddr_i` be the :ref:`element address ` resulting from :ref:`allocating ` a :ref:`element instance ` of :ref:`reference type ` :math:`\reftype_i` with contents :math:`(\reff_{\F{e}}^\ast)^\ast[i]`. diff --git a/document/core/syntax/types.rst b/document/core/syntax/types.rst index 4e3c6adee7..0b2b8c0a83 100644 --- a/document/core/syntax/types.rst +++ b/document/core/syntax/types.rst @@ -404,6 +404,26 @@ Global Types $${syntax: globaltype} +.. index:: ! tag type, function type, defined type, exception + pair: abstract syntax; tag type + pair: tag; type +.. _syntax-tagtype: + +Tag Types +~~~~~~~~~ + +*Tag types* classify the signature of :ref:`tags ` with a defined type |deftype|, which expands to a function type |functype|. + +$${syntax: tagtype} + +Tags are used for categorizing exceptions. +The parameters of |functype| define the list of values associated with the exception thrown with this tag. +Furthermore, it is an invariant of the semantics that every |functype| in a :ref:`valid ` tag type for an exception has an empty result type. + +.. note:: + Future versions of WebAssembly may have additional uses for tags, and may allow non-empty result types in the function types of tags. + + .. index:: ! element type, reference type, table, element pair: abstract syntax; element type pair: element; type diff --git a/document/core/valid/matching.rst b/document/core/valid/matching.rst index 018164b204..0471c5257a 100644 --- a/document/core/valid/matching.rst +++ b/document/core/valid/matching.rst @@ -38,8 +38,7 @@ Heap Types $${rule-prose: Heaptype_sub} -.. todo:: - below is the official specification +.. todo:: below is the official specification A :ref:`heap type ` ${:heaptype_1} matches a :ref:`heap type ` ${:heaptype_2} if and only if: @@ -90,8 +89,8 @@ Reference Types ~~~~~~~~~~~~~~~ $${rule-prose: Reftype_sub} -.. todo:: - below is the official specification + +.. todo:: below is the official specification A :ref:`reference type ` ${reftype: REF nul1 heaptype_1} matches a :ref:`reference type ` ${reftype: REF nul2 heaptype_2} if and only if: @@ -264,6 +263,12 @@ $${rule-prose: Tagtype_sub} $${rule: {Tagtype_sub}} +.. note:: + Although the conclusion of this rule looks identical to its premise, + they in fact describe different relations: + the premise invokes subtyping on defined types, + while the conclusion defines it on tag types that happen to be expressed as defined types. + .. index:: external type, function type, table type, memory type, global type .. _match-externtype: diff --git a/document/core/valid/modules.rst b/document/core/valid/modules.rst index 2c98647b5b..543c20d185 100644 --- a/document/core/valid/modules.rst +++ b/document/core/valid/modules.rst @@ -36,10 +36,9 @@ Functions Functions ${:func} are classified by :ref:`defined types ` that :ref:`expand ` to :ref:`function types ` of the form ${comptype: FUNC (t_1* -> t_2*)}. - $${rule-prose: Func_ok} -.. todo:: - below is the official specification + +.. todo:: below is the official specification * The :ref:`defined type ` :math:`C.\CTYPES[x]` must be a :ref:`function type `. @@ -306,8 +305,8 @@ Consequently, no initial :ref:`context ` is required. Instead, the :ref:`context ` ${:C} for validation of the module's content is constructed from the definitions in the module. $${rule-prose: Module_ok} -.. todo:: - below is the official specification + +.. todo:: below is the official specification * Let :math:`\module` be the module to validate. @@ -412,8 +411,6 @@ $${rule-prose: Module_ok} * Let :math:`\X{et}^\ast` be the concatenation of :ref:`external types ` :math:`\X{et}_i` of the exports, in index order. -* The length of :math:`C.\CMEMS` must not be larger than :math:`1`. - * All export names :math:`\export_i.\XNAME` must be different. * Then the module is valid with :ref:`external types ` :math:`\X{it}^\ast \to \X{et}^\ast`. diff --git a/document/core/valid/types.rst b/document/core/valid/types.rst index 64992095c9..0c14fb66bf 100644 --- a/document/core/valid/types.rst +++ b/document/core/valid/types.rst @@ -218,9 +218,10 @@ Recursive Types :math:`\TREC~\subtype^\ast` ........................... + $${rule-prose: Rectype_ok} -.. todo:: - below is the official specification + +.. todo:: below is the official specification * Either the sequence :math:`\subtype^\ast` is empty. @@ -237,9 +238,10 @@ $${rule: {Rectype_ok/empty Rectype_ok/cons}} :math:`\TSUB~\TFINAL^?~y^\ast~\comptype` ........................................ + $${rule-prose: Subtype_ok} -.. todo:: - below is the official specification + +.. todo:: below is the official specification * The :ref:`composite type ` :math:`\comptype` must be :ref:`valid `. diff --git a/document/js-api/index.bs b/document/js-api/index.bs index 6295ec1465..5806abbf2c 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -1803,7 +1803,8 @@ In practice, an implementation may run out of resources for valid modules below
  • The maximum size of a table is 10,000,000.
  • -
  • The maximum number of pages of a memory is 65,536.
  • +
  • The maximum size of a 32-bit memory is 65,536 pages (4 GiB).
  • +
  • The maximum size of a 64-bit memory is 262,144 pages (16 GiB).

Security and Privacy Considerations

diff --git a/proposals/exception-handling/legacy/Exceptions.md b/proposals/exception-handling/legacy/Exceptions.md index 74270f88c0..a214ee21fe 100644 --- a/proposals/exception-handling/legacy/Exceptions.md +++ b/proposals/exception-handling/legacy/Exceptions.md @@ -703,9 +703,9 @@ throws, and rethrows as follows: | `try` | `0x06` | sig : `blocktype` | begins a block which can handle thrown exceptions | | `catch` | `0x07` | index : `varint32` | begins the catch block of the try block | | `catch_all` | `0x19` | | begins the catch_all block of the try block | -| `delegate` | `0x18` | relative_depth : `varuint32` | begins the delegate block of the try block | -| `throw` | `0x08` | index : `varint32` | Creates an exception defined by the tag and then throws it | -| `rethrow` | `0x09` | relative_depth : `varuint32` | Pops the `exnref` on top of the stack and throws it | +| `delegate` | `0x18` | relative_depth : `varuint32` | ends the current try block and delegates any exceptions to the block at `relative_depth` | +| `throw` | `0x08` | index : `varint32` | creates an exception defined by the tag and then throws it | +| `rethrow` | `0x09` | relative_depth : `varuint32` | throws the exception caught by the catch block at `relative_depth` | The *sig* fields of `block`, `if`, and `try` operators are block signatures which describe their use of the operand stack. diff --git a/proposals/memory64/Overview.md b/proposals/memory64/Overview.md index 3e947b5829..7e0e9e0121 100644 --- a/proposals/memory64/Overview.md +++ b/proposals/memory64/Overview.md @@ -88,16 +88,16 @@ have to support 32-bit memory addresses in their ABI. * [Memory page limits][valid limits] and [Table entry limits][valid limits] are classified by their respective address types - ``` - ⊦ it : k n <= k (m <= k)? (n < m)? + ⊦ at : k n <= k (m <= k)? (n < m)? ------------------------------------------- - ⊦ { min n, max m? } : it + ⊦ { min n, max m? } : at ``` * Memory and Table types are validated accordingly: - ``` - ⊦ limits : it + ⊦ limits : at -------------- - ⊦ it limits ok + ⊦ at limits ok ``` * All [memory instructions][valid meminst] are changed to use the address type, @@ -195,11 +195,11 @@ have to support 32-bit memory addresses in their ABI. ---------------------------------- C ⊦ tables.fill x : [at t at] → [] ``` - - table.copy x y + - table.copy d s - ``` - C.tables[d] = aN limits t C.tables[s] = aM limits t K = min {aN, AM} + C.tables[d] = aD limits t C.tables[s] = aS limits t aN = min {aD, aS} ----------------------------------------------------------------------------- - C ⊦ table.copy d s : [aN aM aK] → [] + C ⊦ table.copy d s : [aD aS aN] → [] ``` - table.init x y - ``` diff --git a/spectec/src/backend-interpreter/interpreter.ml b/spectec/src/backend-interpreter/interpreter.ml index 1877e36275..4fbe8eae68 100644 --- a/spectec/src/backend-interpreter/interpreter.ml +++ b/spectec/src/backend-interpreter/interpreter.ml @@ -163,11 +163,11 @@ and check_type ty v expr = boolV (ty = "val") (* numtype *) | CaseV (nt, []) when List.mem nt inn_types -> - boolV (ty = "Inn" || ty = "Jnn" || ty = "numtype" || ty = "valtype") + boolV (ty = "Inn" || ty = "Jnn" || ty = "numtype" || ty = "valtype" || ty = "consttype") | CaseV (nt, []) when List.mem nt fnn_types -> - boolV (ty = "Fnn" || ty = "numtype" || ty = "valtype") + boolV (ty = "Fnn" || ty = "numtype" || ty = "valtype" || ty = "consttype") | CaseV (vt, []) when List.mem vt vnn_types -> - boolV (ty = "Vnn" || ty = "vectype" || ty = "valtype") + boolV (ty = "Vnn" || ty = "vectype" || ty = "valtype" || ty = "consttype") (* valtype *) | CaseV ("REF", _) -> boolV (ty = "reftype" || ty = "valtype" || ty = "val") @@ -190,7 +190,7 @@ and check_type ty v expr = | CaseV (pt, []) when List.mem pt pnn_types -> boolV (ty = "Pnn" || ty = "Jnn" || ty = "packtype" || ty = "storagetype") | v -> fail_expr expr - (sprintf "%s doesn't have type %s" (structured_string_of_value v) ty) + (sprintf "cannot decide if %s has type %s" (structured_string_of_value v) ty) and eval_expr env expr = let rec to_bool source = function diff --git a/spectec/test-interpreter/TEST.md b/spectec/test-interpreter/TEST.md index 3c42d4421c..8f51d66aec 100644 --- a/spectec/test-interpreter/TEST.md +++ b/spectec/test-interpreter/TEST.md @@ -897,7 +897,7 @@ watsup 0.4 generator - 39/39 (100.00%) ===== ../../test-interpreter/spec-test-3/gc/array.wast ===== -- 53/53 (100.00%) +- 61/61 (100.00%) ===== ../../test-interpreter/spec-test-3/gc/array_copy.wast ===== - 36/36 (100.00%) @@ -911,6 +911,12 @@ watsup 0.4 generator ===== ../../test-interpreter/spec-test-3/gc/array_init_elem.wast ===== - 24/24 (100.00%) +===== ../../test-interpreter/spec-test-3/gc/array_new_data.wast ===== +- 19/19 (100.00%) + +===== ../../test-interpreter/spec-test-3/gc/array_new_elem.wast ===== +- 26/26 (100.00%) + ===== ../../test-interpreter/spec-test-3/gc/binary-gc.wast ===== - 0/0 (100.00%) @@ -939,7 +945,7 @@ watsup 0.4 generator - 35/35 (100.00%) ===== ../../test-interpreter/spec-test-3/gc/type-subtyping.wast ===== -- 135/135 (100.00%) +- 143/143 (100.00%) ===== ../../test-interpreter/spec-test-3/global.wast ===== - 125/125 (100.00%) @@ -1018,10 +1024,10 @@ watsup 0.4 generator - 8/8 (100.00%) ===== ../../test-interpreter/spec-test-3/memory.wast ===== -- 97/97 (100.00%) +- 98/98 (100.00%) ===== ../../test-interpreter/spec-test-3/memory64.wast ===== -- 75/75 (100.00%) +- 78/78 (100.00%) ===== ../../test-interpreter/spec-test-3/memory_copy.wast ===== - 0/0 (100.00%) @@ -1422,7 +1428,7 @@ watsup 0.4 generator - 4/4 (100.00%) ===== ../../test-interpreter/spec-test-3/table.wast ===== -- 78/78 (100.00%) +- 84/84 (100.00%) ===== ../../test-interpreter/spec-test-3/table_copy.wast ===== - 1845/1845 (100.00%) @@ -1502,7 +1508,7 @@ watsup 0.4 generator ===== ../../test-interpreter/spec-test-3/utf8-invalid-encoding.wast ===== - 0/0 (100.00%) -Total [52904/52904] (100.00%) +Total [52975/52975] (100.00%) == Complete. ``` diff --git a/test/core/gc/array.wast b/test/core/gc/array.wast index 6ad95c0873..cebf20069e 100644 --- a/test/core/gc/array.wast +++ b/test/core/gc/array.wast @@ -158,6 +158,10 @@ (array.new_data $vec $d (i32.const 1) (i32.const 3)) ) + (func $new-overflow (export "new-overflow") (result (ref $vec)) + (array.new_data $vec $d (i32.const 0x8000_0000) (i32.const 0x8000_0000)) + ) + (func $get_u (param $i i32) (param $v (ref $vec)) (result i32) (array.get_u $vec (local.get $v) (local.get $i)) ) @@ -189,6 +193,10 @@ (func (export "len") (result i32) (call $len (call $new)) ) + + (func (export "drop_segs") + (data.drop $d) + ) ) (assert_return (invoke "new") (ref.array)) @@ -198,10 +206,16 @@ (assert_return (invoke "set_get" (i32.const 1) (i32.const 7)) (i32.const 7)) (assert_return (invoke "len") (i32.const 3)) +(assert_trap (invoke "new-overflow") "out of bounds memory access") (assert_trap (invoke "get_u" (i32.const 10)) "out of bounds array access") (assert_trap (invoke "get_s" (i32.const 10)) "out of bounds array access") (assert_trap (invoke "set_get" (i32.const 10) (i32.const 7)) "out of bounds array access") +(assert_return (invoke "drop_segs")) + +(assert_trap (invoke "new") "out of bounds memory access") +(assert_trap (invoke "new-overflow") "out of bounds memory access") + (module (type $bvec (array i8)) (type $vec (array (ref $bvec))) @@ -218,6 +232,10 @@ (array.new_elem $vec $e (i32.const 0) (i32.const 2)) ) + (func $new-overflow (export "new-overflow") (result (ref $vec)) + (array.new_elem $vec $e (i32.const 0x8000_0000) (i32.const 0x8000_0000)) + ) + (func $sub1 (result (ref $nvec)) (array.new_elem $nvec $e (i32.const 0) (i32.const 2)) ) @@ -249,6 +267,10 @@ (func (export "len") (result i32) (call $len (call $new)) ) + + (func (export "drop_segs") + (elem.drop $e) + ) ) (assert_return (invoke "new") (ref.array)) @@ -258,9 +280,15 @@ (assert_return (invoke "set_get" (i32.const 0) (i32.const 1) (i32.const 1)) (i32.const 2)) (assert_return (invoke "len") (i32.const 2)) +(assert_trap (invoke "new-overflow") "out of bounds table access") (assert_trap (invoke "get" (i32.const 10) (i32.const 0)) "out of bounds array access") (assert_trap (invoke "set_get" (i32.const 10) (i32.const 0) (i32.const 0)) "out of bounds array access") +(assert_return (invoke "drop_segs")) + +(assert_trap (invoke "new") "out of bounds table access") +(assert_trap (invoke "new-overflow") "out of bounds table access") + (assert_invalid (module (type $a (array i64)) diff --git a/test/core/gc/array_new_data.wast b/test/core/gc/array_new_data.wast new file mode 100644 index 0000000000..2af894c169 --- /dev/null +++ b/test/core/gc/array_new_data.wast @@ -0,0 +1,68 @@ +(module + (type $arr (array (mut i8))) + + (data $d "abcd") + + (func (export "array-new-data") (param i32 i32) (result (ref $arr)) + (array.new_data $arr $d (local.get 0) (local.get 1)) + ) +) + +;; In-bounds data segment accesses. +(assert_return (invoke "array-new-data" (i32.const 0) (i32.const 0)) (ref.array)) +(assert_return (invoke "array-new-data" (i32.const 0) (i32.const 4)) (ref.array)) +(assert_return (invoke "array-new-data" (i32.const 1) (i32.const 2)) (ref.array)) +(assert_return (invoke "array-new-data" (i32.const 4) (i32.const 0)) (ref.array)) + +;; Out-of-bounds data segment accesses. +(assert_trap (invoke "array-new-data" (i32.const 0) (i32.const 5)) "out of bounds memory access") +(assert_trap (invoke "array-new-data" (i32.const 5) (i32.const 0)) "out of bounds memory access") +(assert_trap (invoke "array-new-data" (i32.const 1) (i32.const 4)) "out of bounds memory access") +(assert_trap (invoke "array-new-data" (i32.const 4) (i32.const 1)) "out of bounds memory access") + + +(module + (type $arr (array (mut i8))) + + (data $d "\aa\bb\cc\dd") + + (func (export "array-new-data-contents") (result i32 i32) + (local (ref $arr)) + (local.set 0 (array.new_data $arr $d (i32.const 1) (i32.const 2))) + (array.get_u $arr (local.get 0) (i32.const 0)) + (array.get_u $arr (local.get 0) (i32.const 1)) + ) +) + +;; Array is initialized with the correct contents. +(assert_return (invoke "array-new-data-contents") (i32.const 0xbb) (i32.const 0xcc)) + +(module + (type $arr (array (mut i32))) + + (data $d "\aa\bb\cc\dd") + + (func (export "array-new-data-little-endian") (result i32) + (array.get $arr + (array.new_data $arr $d (i32.const 0) (i32.const 1)) + (i32.const 0)) + ) +) + +;; Data segments are interpreted as little-endian. +(assert_return (invoke "array-new-data-little-endian") (i32.const 0xddccbbaa)) + +(module + (type $arr (array (mut i16))) + + (data $d "\00\11\22") + + (func (export "array-new-data-unaligned") (result i32) + (array.get_u $arr + (array.new_data $arr $d (i32.const 1) (i32.const 1)) + (i32.const 0)) + ) +) + +;; Data inside the segment doesn't need to be aligned to the element size. +(assert_return (invoke "array-new-data-unaligned") (i32.const 0x2211)) diff --git a/test/core/gc/array_new_elem.wast b/test/core/gc/array_new_elem.wast new file mode 100644 index 0000000000..d71d981d63 --- /dev/null +++ b/test/core/gc/array_new_elem.wast @@ -0,0 +1,103 @@ +;;;; Expression-style element segments. + +(module + (type $arr (array i31ref)) + + (elem $e i31ref + (ref.i31 (i32.const 0xaa)) + (ref.i31 (i32.const 0xbb)) + (ref.i31 (i32.const 0xcc)) + (ref.i31 (i32.const 0xdd))) + + (func (export "array-new-elem") (param i32 i32) (result (ref $arr)) + (array.new_elem $arr $e (local.get 0) (local.get 1)) + ) +) + +;; In-bounds element segment accesses. +(assert_return (invoke "array-new-elem" (i32.const 0) (i32.const 0)) (ref.array)) +(assert_return (invoke "array-new-elem" (i32.const 0) (i32.const 4)) (ref.array)) +(assert_return (invoke "array-new-elem" (i32.const 1) (i32.const 2)) (ref.array)) +(assert_return (invoke "array-new-elem" (i32.const 4) (i32.const 0)) (ref.array)) + +;; Out-of-bounds element segment accesses. +(assert_trap (invoke "array-new-elem" (i32.const 0) (i32.const 5)) "out of bounds table access") +(assert_trap (invoke "array-new-elem" (i32.const 5) (i32.const 0)) "out of bounds table access") +(assert_trap (invoke "array-new-elem" (i32.const 1) (i32.const 4)) "out of bounds table access") +(assert_trap (invoke "array-new-elem" (i32.const 4) (i32.const 1)) "out of bounds table access") + +(module + (type $arr (array i31ref)) + + (elem $e i31ref + (ref.i31 (i32.const 0xaa)) + (ref.i31 (i32.const 0xbb)) + (ref.i31 (i32.const 0xcc)) + (ref.i31 (i32.const 0xdd))) + + (func (export "array-new-elem-contents") (result i32 i32) + (local (ref $arr)) + (local.set 0 (array.new_elem $arr $e (i32.const 1) (i32.const 2))) + (i31.get_u (array.get $arr (local.get 0) (i32.const 0))) + (i31.get_u (array.get $arr (local.get 0) (i32.const 1))) + ) +) + +;; Array is initialized with the correct contents. +(assert_return (invoke "array-new-elem-contents") (i32.const 0xbb) (i32.const 0xcc)) + +;;;; MVP-style function-index segments. + +(module + (type $arr (array funcref)) + + (elem $e func $aa $bb $cc $dd) + (func $aa (result i32) (i32.const 0xaa)) + (func $bb (result i32) (i32.const 0xbb)) + (func $cc (result i32) (i32.const 0xcc)) + (func $dd (result i32) (i32.const 0xdd)) + + (func (export "array-new-elem") (param i32 i32) (result (ref $arr)) + (array.new_elem $arr $e (local.get 0) (local.get 1)) + ) +) + +;; In-bounds element segment accesses. +(assert_return (invoke "array-new-elem" (i32.const 0) (i32.const 0)) (ref.array)) +(assert_return (invoke "array-new-elem" (i32.const 0) (i32.const 4)) (ref.array)) +(assert_return (invoke "array-new-elem" (i32.const 1) (i32.const 2)) (ref.array)) +(assert_return (invoke "array-new-elem" (i32.const 4) (i32.const 0)) (ref.array)) + +;; Out-of-bounds element segment accesses. +(assert_trap (invoke "array-new-elem" (i32.const 0) (i32.const 5)) "out of bounds table access") +(assert_trap (invoke "array-new-elem" (i32.const 5) (i32.const 0)) "out of bounds table access") +(assert_trap (invoke "array-new-elem" (i32.const 1) (i32.const 4)) "out of bounds table access") +(assert_trap (invoke "array-new-elem" (i32.const 4) (i32.const 1)) "out of bounds table access") + +(module + (type $f (func (result i32))) + (type $arr (array funcref)) + + (elem $e func $aa $bb $cc $dd) + (func $aa (result i32) (i32.const 0xaa)) + (func $bb (result i32) (i32.const 0xbb)) + (func $cc (result i32) (i32.const 0xcc)) + (func $dd (result i32) (i32.const 0xdd)) + + (table $t 2 2 funcref) + + (func (export "array-new-elem-contents") (result i32 i32) + (local (ref $arr)) + (local.set 0 (array.new_elem $arr $e (i32.const 1) (i32.const 2))) + + (table.set $t (i32.const 0) (array.get $arr (local.get 0) (i32.const 0))) + (table.set $t (i32.const 1) (array.get $arr (local.get 0) (i32.const 1))) + + (call_indirect (type $f) (i32.const 0)) + (call_indirect (type $f) (i32.const 1)) + + ) +) + +;; Array is initialized with the correct contents. +(assert_return (invoke "array-new-elem-contents") (i32.const 0xbb) (i32.const 0xcc)) diff --git a/test/core/gc/i31.wast b/test/core/gc/i31.wast index 7485650454..6309e72b65 100644 --- a/test/core/gc/i31.wast +++ b/test/core/gc/i31.wast @@ -14,7 +14,7 @@ (i31.get_u (ref.null i31)) ) (func (export "get_s-null") (result i32) - (i31.get_u (ref.null i31)) + (i31.get_s (ref.null i31)) ) (global $i (ref i31) (ref.i31 (i32.const 2))) diff --git a/test/core/gc/type-subtyping.wast b/test/core/gc/type-subtyping.wast index f2b33d7c49..891aa31ad0 100644 --- a/test/core/gc/type-subtyping.wast +++ b/test/core/gc/type-subtyping.wast @@ -824,6 +824,70 @@ "sub type" ) +(assert_invalid + (module + (type $a (sub (array (ref none)))) + (type $b (sub $a (array (ref any)))) + ) + "sub type 1 does not match super type" +) + +(assert_invalid + (module + (type $a (sub (array (mut (ref any))))) + (type $b (sub $a (array (mut (ref none))))) + ) + "sub type 1 does not match super type" +) + +(assert_invalid + (module + (type $a (sub (array (mut (ref any))))) + (type $b (sub $a (array (ref any)))) + ) + "sub type 1 does not match super type" +) + +(assert_invalid + (module + (type $a (sub (array (ref any)))) + (type $b (sub $a (array (mut (ref any))))) + ) + "sub type 1 does not match super type" +) + +(assert_invalid + (module + (type $a (sub (struct (field (ref none))))) + (type $b (sub $a (struct (field (ref any))))) + ) + "sub type 1 does not match super type" +) + +(assert_invalid + (module + (type $a (sub (struct (field (mut (ref any)))))) + (type $b (sub $a (struct (field (mut (ref none)))))) + ) + "sub type 1 does not match super type" +) + +(assert_invalid + (module + (type $a (sub (struct (field (mut (ref any)))))) + (type $b (sub $a (struct (field (ref any))))) + ) + "sub type 1 does not match super type" +) + +(assert_invalid + (module + (type $a (sub (struct (field (ref any))))) + (type $b (sub $a (struct (field (mut (ref any)))))) + ) + "sub type 1 does not match super type" +) + (assert_invalid (module (type $f0 (sub (func))) diff --git a/test/core/memory.wast b/test/core/memory.wast index e01170a8f4..8ae51eca4b 100644 --- a/test/core/memory.wast +++ b/test/core/memory.wast @@ -5,6 +5,7 @@ (module (memory 0 0)) (module (memory 0 1)) (module (memory 1 256)) +(module definition (memory 65536)) (module (memory 0 65536)) (module (memory (data)) (func (export "memsize") (result i32) (memory.size))) diff --git a/test/core/memory64.wast b/test/core/memory64.wast index ba3b242335..b9d9ed9082 100644 --- a/test/core/memory64.wast +++ b/test/core/memory64.wast @@ -5,6 +5,8 @@ (module (memory i64 0 1)) (module (memory i64 1 256)) (module (memory i64 0 65536)) +(module definition (memory i64 0x1_0000_0000_0000)) +(module (memory i64 0 0x1_0000_0000_0000)) (module (memory i64 (data)) (func (export "memsize") (result i64) (memory.size))) (assert_return (invoke "memsize") (i64.const 0)) diff --git a/test/core/table.wast b/test/core/table.wast index a0feefff9c..56baa1984d 100644 --- a/test/core/table.wast +++ b/test/core/table.wast @@ -6,6 +6,7 @@ (module (table 0 1 funcref)) (module (table 1 256 funcref)) (module (table 0 65536 funcref)) +(module definition (table 0xffff_ffff funcref)) (module (table 0 0xffff_ffff funcref)) (module (table 1 (ref null func))) @@ -53,6 +54,9 @@ (module (table i64 1 256 funcref)) (module (table i64 0 65536 funcref)) (module (table i64 0 0xffff_ffff funcref)) +(module (table i64 0 0x1_0000_0000 funcref)) +(module definition (table i64 0xffff_ffff_ffff_ffff funcref)) +(module (table i64 0 0xffff_ffff_ffff_ffff funcref)) (module (table i64 0 funcref) (table i64 0 funcref)) (module (table (import "spectest" "table64") i64 0 funcref) (table i64 0 funcref))