diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 00b70e8f..b64d31bb 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -19,7 +19,11 @@ jobs: with: ocaml-compiler: 4.12.x - run: opam install --yes ocamlbuild.0.14.0 - - run: cd interpreter && opam exec make all + - name: Setup Node.js + uses: actions/setup-node@v1 + with: + node-version: 18.x + - run: cd interpreter && opam exec make JS=node all ref-interpreter-js-library: runs-on: ubuntu-latest @@ -60,6 +64,9 @@ jobs: - uses: actions/checkout@v2 with: submodules: "recursive" + - uses: actions/setup-node@v3 + with: + node-version: 16 - run: pip install bikeshed && bikeshed update - run: pip install six - run: sudo apt-get update -y && sudo apt-get install -y latexmk texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended diff --git a/document/core/appendix/gen-index-instructions.py b/document/core/appendix/gen-index-instructions.py index 65a97171..fffa2b32 100755 --- a/document/core/appendix/gen-index-instructions.py +++ b/document/core/appendix/gen-index-instructions.py @@ -427,10 +427,10 @@ def Instruction(name, opcode, type=None, validation=None, execution=None, operat Instruction(r'\V128.\LOAD\K{16\_lane}~\memarg~\laneidx', r'\hex{FD}~~\hex{55}', r'[\I32~\V128] \to [\V128]', r'valid-load-lane', r'exec-load-lane'), Instruction(r'\V128.\LOAD\K{32\_lane}~\memarg~\laneidx', r'\hex{FD}~~\hex{56}', r'[\I32~\V128] \to [\V128]', r'valid-load-lane', r'exec-load-lane'), Instruction(r'\V128.\LOAD\K{64\_lane}~\memarg~\laneidx', r'\hex{FD}~~\hex{57}', r'[\I32~\V128] \to [\V128]', r'valid-load-lane', r'exec-load-lane'), - Instruction(r'\V128.\STORE\K{8\_lane}~\memarg~\laneidx', r'\hex{FD}~~\hex{58}', r'[\I32~\V128] \to [\V128]', r'valid-store-lane', r'exec-store-lane'), - Instruction(r'\V128.\STORE\K{16\_lane}~\memarg~\laneidx', r'\hex{FD}~~\hex{59}', r'[\I32~\V128] \to [\V128]', r'valid-store-lane', r'exec-store-lane'), - Instruction(r'\V128.\STORE\K{32\_lane}~\memarg~\laneidx', r'\hex{FD}~~\hex{5A}', r'[\I32~\V128] \to [\V128]', r'valid-store-lane', r'exec-store-lane'), - Instruction(r'\V128.\STORE\K{64\_lane}~\memarg~\laneidx', r'\hex{FD}~~\hex{5B}', r'[\I32~\V128] \to [\V128]', r'valid-store-lane', r'exec-store-lane'), + Instruction(r'\V128.\STORE\K{8\_lane}~\memarg~\laneidx', r'\hex{FD}~~\hex{58}', r'[\I32~\V128] \to []', r'valid-store-lane', r'exec-store-lane'), + Instruction(r'\V128.\STORE\K{16\_lane}~\memarg~\laneidx', r'\hex{FD}~~\hex{59}', r'[\I32~\V128] \to []', r'valid-store-lane', r'exec-store-lane'), + Instruction(r'\V128.\STORE\K{32\_lane}~\memarg~\laneidx', r'\hex{FD}~~\hex{5A}', r'[\I32~\V128] \to []', r'valid-store-lane', r'exec-store-lane'), + Instruction(r'\V128.\STORE\K{64\_lane}~\memarg~\laneidx', r'\hex{FD}~~\hex{5B}', r'[\I32~\V128] \to []', r'valid-store-lane', r'exec-store-lane'), Instruction(r'\V128.\LOAD\K{32\_zero}~\memarg~\laneidx', r'\hex{FD}~~\hex{5C}', r'[\I32] \to [\V128]', r'valid-load-zero', r'exec-load-zero'), Instruction(r'\V128.\LOAD\K{64\_zero}~\memarg~\laneidx', r'\hex{FD}~~\hex{5D}', r'[\I32] \to [\V128]', r'valid-load-zero', r'exec-load-zero'), Instruction(r'\F32X4.\VDEMOTE\K{\_f64x2\_zero}', r'\hex{FD}~~\hex{5E}', r'[\V128] \to [\V128]', r'valid-vcvtop', r'exec-vcvtop', r'op-demote'), diff --git a/document/core/appendix/index-instructions.rst b/document/core/appendix/index-instructions.rst index 84055a9f..977c21fb 100644 --- a/document/core/appendix/index-instructions.rst +++ b/document/core/appendix/index-instructions.rst @@ -367,10 +367,10 @@ Instruction Binary Opcode :math:`\V128.\LOAD\K{16\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{55}` :math:`[\I32~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` :math:`\V128.\LOAD\K{32\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{56}` :math:`[\I32~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` :math:`\V128.\LOAD\K{64\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{57}` :math:`[\I32~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\STORE\K{8\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{58}` :math:`[\I32~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\STORE\K{16\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{59}` :math:`[\I32~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\STORE\K{32\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{5A}` :math:`[\I32~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` -:math:`\V128.\STORE\K{64\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{5B}` :math:`[\I32~\V128] \to [\V128]` :ref:`validation ` :ref:`execution ` +:math:`\V128.\STORE\K{8\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{58}` :math:`[\I32~\V128] \to []` :ref:`validation ` :ref:`execution ` +:math:`\V128.\STORE\K{16\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{59}` :math:`[\I32~\V128] \to []` :ref:`validation ` :ref:`execution ` +:math:`\V128.\STORE\K{32\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{5A}` :math:`[\I32~\V128] \to []` :ref:`validation ` :ref:`execution ` +:math:`\V128.\STORE\K{64\_lane}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{5B}` :math:`[\I32~\V128] \to []` :ref:`validation ` :ref:`execution ` :math:`\V128.\LOAD\K{32\_zero}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{5C}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` :math:`\V128.\LOAD\K{64\_zero}~\memarg~\laneidx` :math:`\hex{FD}~~\hex{5D}` :math:`[\I32] \to [\V128]` :ref:`validation ` :ref:`execution ` :math:`\F32X4.\VDEMOTE\K{\_f64x2\_zero}` :math:`\hex{FD}~~\hex{5E}` :math:`[\V128] \to [\V128]` :ref:`validation ` :ref:`execution `, :ref:`operator ` diff --git a/document/core/conf.py b/document/core/conf.py index 22a578a2..3952701b 100644 --- a/document/core/conf.py +++ b/document/core/conf.py @@ -297,7 +297,8 @@ 'pointsize': '10pt', # Additional stuff for the LaTeX preamble. - 'preamble': '', + # Don't type-set cross references with emphasis. + 'preamble': '\\renewcommand\\sphinxcrossref[1]{#1}\n', # Latex figure (float) alignment 'figure_align': 'htbp', diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index b61bbc2c..42318361 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -394,7 +394,7 @@ Most vector instructions are defined in terms of generic numeric operators appli .. math:: \begin{array}{l} \begin{array}{lcl@{\qquad}l} - (\V128\K{.}\VCONST~c_1)~(\V128\K{.}\VCONST~c_2)~\V128\K{.}\SWIZZLE &\stepto& (\V128\K{.}\VCONST~c') + (\V128\K{.}\VCONST~c_1)~(\V128\K{.}\VCONST~c_2)~\I8X16\K{.}\SWIZZLE &\stepto& (\V128\K{.}\VCONST~c') \end{array} \\ \qquad \begin{array}[t]{@{}r@{~}l@{}} @@ -431,7 +431,7 @@ Most vector instructions are defined in terms of generic numeric operators appli .. math:: \begin{array}{l} \begin{array}{lcl@{\qquad}l} - (\V128\K{.}\VCONST~c_1)~(\V128\K{.}\VCONST~c_2)~\V128\K{.}\SHUFFLE~x^\ast &\stepto& (\V128\K{.}\VCONST~c) + (\V128\K{.}\VCONST~c_1)~(\V128\K{.}\VCONST~c_2)~\I8X16\K{.}\SHUFFLE~x^\ast &\stepto& (\V128\K{.}\VCONST~c) \end{array} \\ \qquad \begin{array}[t]{@{}r@{~}l@{}} @@ -1312,7 +1312,7 @@ Table Instructions \end{array} \\[1ex] \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~n)~(\TABLEGROW~x) &\stepto& S; F; (\I32.\CONST~\signed_{32}^{-1}(-1)) + S; F; \val~(\I32.\CONST~n)~(\TABLEGROW~x) &\stepto& S; F; (\I32.\CONST~\signed_{32}^{-1}(-1)) \end{array} \end{array} @@ -2244,7 +2244,7 @@ Memory Instructions S; F; (\I32.\CONST~d)~\val~(\I32.\CONST~n)~\MEMORYFILL \quad\stepto\quad S; F; \TRAP \\ \qquad - (\iff d + n > |S.\SMEMS[F.\AMODULE.\MIMEMS[x]].\MIDATA|) + (\iff d + n > |S.\SMEMS[F.\AMODULE.\MIMEMS[0]].\MIDATA|) \\[1ex] S; F; (\I32.\CONST~d)~\val~(\I32.\CONST~0)~\MEMORYFILL \quad\stepto\quad S; F; \epsilon @@ -2451,7 +2451,7 @@ Memory Instructions \\ \qquad \begin{array}[t]{@{}r@{~}l@{}} (\iff & s + n > |S.\SDATAS[F.\AMODULE.\MIDATAS[x]].\DIDATA| \\ - \vee & d + n > |S.\SMEMS[F.\AMODULE.\MIMEMS[x]].\MIDATA|) \\[1ex] + \vee & d + n > |S.\SMEMS[F.\AMODULE.\MIMEMS[0]].\MIDATA|) \\[1ex] \end{array} \\[1ex] S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~0)~(\MEMORYINIT~x) @@ -3143,15 +3143,13 @@ Invocation of :ref:`function address ` :math:`a` 7. Pop the values :math:`\val^n` from the stack. -8. Let :math:`\val_0^\ast` be the list of zero values of types :math:`t^\ast`. - -9. Let :math:`F` be the :ref:`frame ` :math:`\{ \AMODULE~f.\FIMODULE, \ALOCALS~\val^n~(\default_t)^\ast \}`. +8. 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. +9. Push the activation of :math:`F` with arity :math:`m` to the stack. -11. Let :math:`L` be the :ref:`label ` whose arity is :math:`m` and whose continuation is the end of the function. +10. Let :math:`L` be the :ref:`label ` whose arity is :math:`m` and whose continuation is the end of the function. -12. :ref:`Enter ` the instruction sequence :math:`\instr^\ast` with label :math:`L`. +11. :ref:`Enter ` the instruction sequence :math:`\instr^\ast` with label :math:`L`. .. math:: ~\\[-1ex] diff --git a/document/core/exec/modules.rst b/document/core/exec/modules.rst index 0858f56a..b8eab49e 100644 --- a/document/core/exec/modules.rst +++ b/document/core/exec/modules.rst @@ -495,8 +495,7 @@ and list of :ref:`reference ` vectors for the module's :ref:`element a. Let :math:`\limits_i~t_i` be the :ref:`table type ` :math:`\table_i.\TTYPE`. - b. Let :math:`\tableaddr_i` be the :ref:`table address ` resulting from :ref:`allocating ` :math:`\table_i.\TTYPE` - with initialization value :math:`\REFNULL~t_i`. + b. Let :math:`\tableaddr_i` be the :ref:`table address ` resulting from :ref:`allocating ` :math:`\table_i.\TTYPE` with initialization value :math:`\REFNULL~t_i`. 4. For each :ref:`memory ` :math:`\mem_i` in :math:`\module.\MMEMS`, do: diff --git a/document/core/exec/runtime.rst b/document/core/exec/runtime.rst index a48cadab..81766713 100644 --- a/document/core/exec/runtime.rst +++ b/document/core/exec/runtime.rst @@ -510,8 +510,8 @@ Intuitively, :math:`\instr^\ast` is the *continuation* to execute when the branc When branching, the empty continuation ends the targeted block, such that execution can proceed with consecutive instructions. -Activations and Frames -...................... +Activation Frames +................. Activation frames carry the return arity :math:`n` of the respective function, hold the values of its :ref:`locals ` (including arguments) in the order corresponding to their static :ref:`local indices `, @@ -519,8 +519,6 @@ and a reference to the function's own :ref:`module instance ` .. math:: \begin{array}{llll} - \production{activation} & \X{activation} &::=& - \FRAME_n\{\frame\} \\ \production{frame} & \frame &::=& \{ \ALOCALS~\val^\ast, \AMODULE~\moduleinst \} \\ \end{array} diff --git a/document/core/static/custom.css b/document/core/static/custom.css index 45838c1e..33bb863d 100644 --- a/document/core/static/custom.css +++ b/document/core/static/custom.css @@ -44,6 +44,8 @@ div.admonition p.admonition-title { div.math { background-color: #F0F0F0; padding: 3px 0 3px 0; + overflow-x: auto; + overflow-y: hidden; } div.relations { diff --git a/document/core/syntax/conventions.rst b/document/core/syntax/conventions.rst index 9e5dca18..5eeff48c 100644 --- a/document/core/syntax/conventions.rst +++ b/document/core/syntax/conventions.rst @@ -20,7 +20,7 @@ Grammar Notation The following conventions are adopted in defining grammar rules for abstract syntax. -* Terminal symbols (atoms) are written in sans-serif font: :math:`\K{i32}, \K{end}`. +* Terminal symbols (atoms) are written in sans-serif font or in symbolic form: :math:`\K{i32}, \K{end}, {\to}, [, ]`. * Nonterminal symbols are written in italic font: :math:`\X{valtype}, \X{instr}`. diff --git a/document/core/syntax/instructions.rst b/document/core/syntax/instructions.rst index a79190a7..de01fdf5 100644 --- a/document/core/syntax/instructions.rst +++ b/document/core/syntax/instructions.rst @@ -45,7 +45,7 @@ These operations closely match respective operations available in hardware. \production{signedness} & \sx &::=& \K{u} ~|~ \K{s} \\ \production{instruction} & \instr &::=& - \K{i}\X{nn}\K{.}\CONST~\xref{syntax/values}{syntax-int}{\iX{\X{nn}}} ~|~ + \K{i}\X{nn}\K{.}\CONST~\xref{syntax/values}{syntax-int}{\uX{\X{nn}}} ~|~ \K{f}\X{nn}\K{.}\CONST~\xref{syntax/values}{syntax-float}{\fX{\X{nn}}} \\&&|& \K{i}\X{nn}\K{.}\iunop ~|~ \K{f}\X{nn}\K{.}\funop \\&&|& diff --git a/document/core/text/instructions.rst b/document/core/text/instructions.rst index bc5202ca..07882dc2 100644 --- a/document/core/text/instructions.rst +++ b/document/core/text/instructions.rst @@ -34,6 +34,8 @@ The following grammar handles the corresponding update to the :ref:`identifier c \production{label} & \Tlabel_I &::=& v{:}\Tid &\Rightarrow& \{\ILABELS~v\} \compose I & (\iff v \notin I.\ILABELS) \\ &&|& + v{:}\Tid &\Rightarrow& \{\ILABELS~v\} \compose (I \with \ILABELS[i] = \epsilon) + & (\iff I.\ILABELS[i] = v) \\ &&|& \epsilon &\Rightarrow& \{\ILABELS~(\epsilon)\} \compose I \\ \end{array} @@ -42,6 +44,9 @@ The following grammar handles the corresponding update to the :ref:`identifier c This effectively shifts all existing labels up by one, mirroring the fact that control instructions are indexed relatively not absolutely. + If a label with the same name already exists, + then it is shadowed and the earlier label becomes inaccessible. + .. index:: control instructions, structured control, label, block, branch, result type, label index, function index, type index, vector, polymorphism, tag index, exception instructions pair: text format; instruction @@ -175,7 +180,7 @@ Reference Instructions \production{instruction} & \Tplaininstr_I &::=& \dots \\ &&|& \text{ref.null}~~t{:}\Theaptype &\Rightarrow& \REFNULL~t \\ &&|& \text{ref.is\_null} &\Rightarrow& \REFISNULL \\ &&|& - \text{ref.func}~~x{:}\Tfuncidx &\Rightarrow& \REFFUNC~x \\ &&|& + \text{ref.func}~~x{:}\Tfuncidx &\Rightarrow& \REFFUNC~x \\ \end{array} @@ -901,7 +906,7 @@ Vector constant instructions have a mandatory :ref:`shape ` de \text{f64x2.convert\_low\_i32x4\_s} &\Rightarrow& \F64X2.\VCONVERT\K{\_low\_i32x4\_s}\\ &&|& \text{f64x2.convert\_low\_i32x4\_u} &\Rightarrow& \F64X2.\VCONVERT\K{\_low\_i32x4\_u}\\ &&|& \text{f32x4.demote\_f64x2\_zero} &\Rightarrow& \F32X4.\VDEMOTE\K{\_f64x2\_zero}\\ &&|& - \text{f64x2.promote\_low\_f32x4} &\Rightarrow& \F64X2.\VPROMOTE\K{\_low\_f32x4}\\ &&|& + \text{f64x2.promote\_low\_f32x4} &\Rightarrow& \F64X2.\VPROMOTE\K{\_low\_f32x4}\\ \end{array} diff --git a/document/core/text/lexical.rst b/document/core/text/lexical.rst index f4664666..1dd34c86 100644 --- a/document/core/text/lexical.rst +++ b/document/core/text/lexical.rst @@ -48,7 +48,7 @@ The character stream in the source text is divided, from left to right, into a s \text{(} ~|~ \text{)} ~|~ \Treserved \\ \production{keyword} & \Tkeyword &::=& (\text{a} ~|~ \dots ~|~ \text{z})~\Tidchar^\ast - \qquad (\mbox{if occurring as a literal terminal in the grammar}) \\ + \qquad (\iff~\mbox{occurring as a literal terminal in the grammar}) \\ \production{reserved} & \Treserved &::=& (\Tidchar ~|~ \Tstring)^+ \\ \end{array} diff --git a/document/core/text/modules.rst b/document/core/text/modules.rst index 0ec6611d..c0891669 100644 --- a/document/core/text/modules.rst +++ b/document/core/text/modules.rst @@ -112,7 +112,7 @@ If inline declarations are given, then their types must match the referenced :re \end{array} \\ \end{array} -The synthesized attribute of a |Ttypeuse| is a pair consisting of both the used :ref:`type index ` and the updated :ref:`identifier context ` including possible parameter identifiers. +The synthesized attribute of a |Ttypeuse| is a pair consisting of both the used :ref:`type index ` and the local :ref:`identifier context ` containing possible parameter identifiers. The following auxiliary function extracts optional identifiers from parameters: .. math:: @@ -206,7 +206,7 @@ Function definitions can bind a symbolic :ref:`function identifier `, a \text{(}~\text{func}~~\Tid^?~~x,I'{:}\Ttypeuse_I~~ (t{:}\Tlocal)^\ast~~(\X{in}{:}\Tinstr_{I''})^\ast~\text{)} \\ &&& \qquad \Rightarrow\quad \{ \FTYPE~x, \FLOCALS~t^\ast, \FBODY~\X{in}^\ast~\END \} \\ &&& \qquad\qquad\qquad - (\iff I'' = I' \compose \{\ILOCALS~\F{id}(\Tlocal)^\ast\} \idcwellformed) \\[1ex] + (\iff I'' = I \compose I' \compose \{\ILOCALS~\F{id}(\Tlocal)^\ast\} \idcwellformed) \\[1ex] \production{local} & \Tlocal &::=& \text{(}~\text{local}~~\Tid^?~~t{:}\Tvaltype~\text{)} \quad\Rightarrow\quad t \\ diff --git a/document/js-api/index.bs b/document/js-api/index.bs index 5878b556..4d090fc8 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -93,6 +93,8 @@ urlPrefix: https://tc39.github.io/ecma262/; spec: ECMASCRIPT text: IterableToList; url: sec-iterabletolist text: ToBigInt64; url: #sec-tobigint64 text: BigInt; url: #sec-ecmascript-language-types-bigint-type + text: ๐”ฝ; url: #๐”ฝ + text: โ„ค; url: #โ„ค type: abstract-op text: CreateMethodProperty; url: sec-createmethodproperty urlPrefix: https://webassembly.github.io/exception-handling/core/; spec: WebAssembly; type: dfn @@ -164,6 +166,12 @@ urlPrefix: https://webassembly.github.io/exception-handling/core/; spec: WebAsse text: reftype text: funcref text: externref + url: syntax/values.html#syntax-float + text: +โˆž + text: โˆ’โˆž + text: nan + text: canon + text: signif text: function element; url: exec/runtime.html#syntax-funcelem text: import component; url: syntax/modules.html#imports url: exec/runtime.html#syntax-externval @@ -292,7 +300,7 @@ dictionary WebAssemblyInstantiatedSource { required Instance instance; }; -[Exposed=(Window,Worker,Worklet)] +[Exposed=*] namespace WebAssembly { boolean validate(BufferSource bytes); Promise<Module> compile(BufferSource bytes); @@ -488,18 +496,20 @@ The verification of WebAssembly type requirements is deferred to the 1. Let |module| be |moduleObject|.\[[Module]]. 1. [=Read the imports=] of |module| with imports |importObject|, and let |imports| be the result. If this operation throws an exception, catch it, [=reject=] |promise| with the exception, and return |promise|. - 1. [=Queue a task=] to perform the following steps: - 1. [=Instantiate the core of a WebAssembly module=] |module| with |imports|, and let |instance| be the result. - If this throws an exception, catch it, [=reject=] |promise| with the exception, and terminate these substeps. - 1. Let |instanceObject| be a [=/new=] {{Instance}}. - 1. [=initialize an instance object|Initialize=] |instanceObject| from |module| and |instance|. - If this throws an exception, catch it, [=reject=] |promise| with the exception, and terminate these substeps. - 1. [=Resolve=] |promise| with |instanceObject|. + 1. Run the following steps [=in parallel=]: + 1. [=Queue a task=] to perform the following steps: + Note: Implementation-specific work may be performed here. + 1. [=Instantiate the core of a WebAssembly module=] |module| with |imports|, and let |instance| be the result. + If this throws an exception, catch it, [=reject=] |promise| with the exception, and terminate these substeps. + 1. Let |instanceObject| be a [=/new=] {{Instance}}. + 1. [=initialize an instance object|Initialize=] |instanceObject| from |module| and |instance|. + If this throws an exception, catch it, [=reject=] |promise| with the exception, and terminate these substeps. + 1. [=Resolve=] |promise| with |instanceObject|. 1. Return |promise|.
- To instantiate a WebAssembly module from a {{Module}} |moduleObject| and imports |importObject|, perform the following steps: + To synchronously instantiate a WebAssembly module from a {{Module}} |moduleObject| and imports |importObject|, perform the following steps: 1. Let |module| be |moduleObject|.\[[Module]]. 1. [=Read the imports=] of |module| with imports |importObject|, and let |imports| be the result. 1. [=Instantiate the core of a WebAssembly module=] |module| with |imports|, and let |instance| be the result. @@ -513,14 +523,15 @@ The verification of WebAssembly type requirements is deferred to the 1. Let |promise| be [=a new promise=]. 1. [=Upon fulfillment=] of |promiseOfModule| with value |module|: - 1. [=instantiate a WebAssembly module|Instantiate the WebAssembly module=] |module| importing |importObject|, and let |instance| be the result. If this throws an exception, catch it, [=reject=] |promise| with the exception, and abort these substeps. - 1. Let |result| be the {{WebAssemblyInstantiatedSource}} value ยซ[ "{{WebAssemblyInstantiatedSource/module}}" โ†’ |module|, "{{WebAssemblyInstantiatedSource/instance}}" โ†’ |instance| ]ยป. - 1. [=Resolve=] |promise| with |result|. + 1. [=asynchronously instantiate a WebAssembly module|Instantiate the WebAssembly module=] |module| importing |importObject|, and let |innerPromise| be the result. + 1. [=Upon fulfillment=] of |innerPromise| with value |instance|. + 1. Let |result| be the {{WebAssemblyInstantiatedSource}} value ยซ[ "{{WebAssemblyInstantiatedSource/module}}" โ†’ |module|, "{{WebAssemblyInstantiatedSource/instance}}" โ†’ |instance| ]ยป. + 1. [=Resolve=] |promise| with |result|. + 1. [=Upon rejection=] of |innerPromise| with reason |reason|: + 1. [=Reject=] |promise| with |reason|. 1. [=Upon rejection=] of |promiseOfModule| with reason |reason|: 1. [=Reject=] |promise| with |reason|. 1. Return |promise|. - - Note: It would be valid to perform certain parts of the instantiation [=in parallel=], but several parts need to happen in the event loop, including JavaScript operations to access the |importObject| and execution of the start function.
@@ -560,7 +571,7 @@ dictionary ModuleImportDescriptor { required ImportExportKind kind; }; -[LegacyNamespace=WebAssembly, Exposed=(Window,Worker,Worklet)] +[LegacyNamespace=WebAssembly, Exposed=*] interface Module { constructor(BufferSource bytes); static sequence<ModuleExportDescriptor> exports(Module moduleObject); @@ -620,12 +631,14 @@ interface Module { 1. If |module| is [=error=], throw a {{CompileError}} exception. 1. Set **this**.\[[Module]] to |module|. 1. Set **this**.\[[Bytes]] to |stableBytes|. + +Note: Some implementations enforce a size limitation on |bytes|. Use of this API is discouraged, in favor of asynchronous APIs.

Instances

-[LegacyNamespace=WebAssembly, Exposed=(Window,Worker,Worklet)]
+[LegacyNamespace=WebAssembly, Exposed=*]
 interface Instance {
   constructor(Module module, optional object importObject);
   readonly attribute object exports;
@@ -638,6 +651,8 @@ interface Instance {
     1. [=Read the imports=] of |module| with imports |importObject|, and let |imports| be the result.
     1. [=Instantiate the core of a WebAssembly module=] |module| with |imports|, and let |instance| be the result.
     1. [=initialize an instance object|Initialize=] **this** from |module| and |instance|.
+
+Note: The use of this synchronous API is discouraged, as some implementations sometimes do long-running compilation work when instantiating.
 
 
 
@@ -652,7 +667,7 @@ dictionary MemoryDescriptor { [EnforceRange] unsigned long maximum; }; -[LegacyNamespace=WebAssembly, Exposed=(Window,Worker,Worklet)] +[LegacyNamespace=WebAssembly, Exposed=*] interface Memory { constructor(MemoryDescriptor descriptor); unsigned long grow([EnforceRange] unsigned long delta); @@ -762,7 +777,7 @@ dictionary TableDescriptor { [EnforceRange] unsigned long maximum; }; -[LegacyNamespace=WebAssembly, Exposed=(Window,Worker,Worklet)] +[LegacyNamespace=WebAssembly, Exposed=*] interface Table { constructor(TableDescriptor descriptor, optional any value); unsigned long grow([EnforceRange] unsigned long delta, optional any value); @@ -884,7 +899,7 @@ dictionary GlobalDescriptor { boolean mutable = false; }; -[LegacyNamespace=WebAssembly, Exposed=(Window,Worker,Worklet)] +[LegacyNamespace=WebAssembly, Exposed=*] interface Global { constructor(GlobalDescriptor descriptor, optional any v); any valueOf(); @@ -1127,10 +1142,16 @@ The algorithm ToJSValue(|w|) coerces a [=WebAssembly value=] to a Jav 1. Assert: |w| is not of the form [=v128.const=] v128. 1. If |w| is of the form [=i64.const=] |i64|, 1. Let |v| be [=signed_64=](|i64|). - 1. Return a [=BigInt=] representing the mathematical value |v|. -1. If |w| is of the form [=i32.const=] |i32|, return [=the Number value=] for [=signed_32=](|i32|). -1. If |w| is of the form [=f32.const=] |f32|, return [=the Number value=] for |f32|. -1. If |w| is of the form [=f64.const=] |f64|, return [=the Number value=] for |f64|. + 1. Return [=โ„ค=](|v| interpreted as a mathematical value). +1. If |w| is of the form [=i32.const=] |i32|, return [=๐”ฝ=]([=signed_32=](|i32| interpreted as a mathematical value)). +1. If |w| is of the form [=f32.const=] |f32|, + 1. If |f32| is [=+โˆž=] or [=โˆ’โˆž=], return **+โˆž**๐”ฝ or **-โˆž**๐”ฝ, respectively. + 1. If |f32| is [=nan=], return **NaN**. + 1. Return [=๐”ฝ=](|f32| interpreted as a mathematical value). +1. If |w| is of the form [=f64.const=] |f64|, + 1. If |f64| is [=+โˆž=] or [=โˆ’โˆž=], return **+โˆž**๐”ฝ or **-โˆž**๐”ฝ, respectively. + 1. If |f64| is [=nan=], return **NaN**. + 1. Return [=๐”ฝ=](|f64| interpreted as a mathematical value). 1. If |w| is of the form [=ref.null=] t, return null. 1. If |w| is of the form [=ref.func=] |funcaddr|, return the result of creating [=a new Exported Function=] from |funcaddr|. 1. If |w| is of the form [=ref.extern=] |externaddr|, return the result of [=retrieving an extern value=] from |externaddr|. @@ -1159,10 +1180,20 @@ The algorithm ToWebAssemblyValue(|v|, |type|) coerces a JavaScript va 1. Let |i32| be [=?=] [=ToInt32=](|v|). 1. Return [=i32.const=] |i32|. 1. If |type| is [=f32=], - 1. Let |f32| be [=?=] [=ToNumber=](|v|) rounded to the nearest representable value using IEEE 754-2008 round to nearest, ties to even mode. + 1. Let |number| be [=?=] [=ToNumber=](|v|). + 1. If |number| is **NaN**, + 1. Let |n| be an implementation-defined integer such that [=canon=]32 โ‰ค |n| < 2[=signif=](32). + 1. Let |f32| be [=nan=](n). + 1. Otherwise, + 1. Let |f32| be |number| rounded to the nearest representable value using IEEE 754-2008 round to nearest, ties to even mode. [[IEEE-754]] 1. Return [=f32.const=] |f32|. 1. If |type| is [=f64=], - 1. Let |f64| be [=?=] [=ToNumber=](|v|). + 1. Let |number| be [=?=] [=ToNumber=](|v|). + 1. If |number| is **NaN**, + 1. Let |n| be an implementation-defined integer such that [=canon=]64 โ‰ค |n| < 2[=signif=](64). + 1. Let |f64| be [=nan=](n). + 1. Otherwise, + 1. Let |f64| be |number|. 1. Return [=f64.const=] |f64|. 1. If |type| is [=funcref=], 1. If |v| is null, diff --git a/document/web-api/index.bs b/document/web-api/index.bs index efeb3bb9..5edd4e8a 100644 --- a/document/web-api/index.bs +++ b/document/web-api/index.bs @@ -76,6 +76,7 @@ url:https://w3c.github.io/webappsec-secure-contexts/#environment-settings-object @@ -118,8 +119,10 @@ Note: This algorithm accepts a {{Response}} object, or a 1. Let |returnValue| be [=a new promise=] 1. [=Upon fulfillment=] of |source| with value |unwrappedSource|: 1. Let |response| be |unwrappedSource|'s [=Response/response=]. - 1. Let |mimeType| be the result of [=extracting a MIME type=] from |response|'s [=response/header list=]. - 1. If |mimeType| is not `` `application/wasm` ``, reject |returnValue| with a {{TypeError}} and abort these substeps. + 1. Let |mimeType| be the result of [=header list/getting=] `` `Content-Type` `` from |response|'s [=response/header list=]. + 1. If |mimeType| is null, reject |returnValue| with a {{TypeError}} and abort these substeps. + 1. Remove all [=HTTP tab or space byte=] from the start and end of |mimeType|. + 1. If |mimeType| is not a [=byte-case-insensitive=] match for `` `application/wasm` ``, reject |returnValue| with a {{TypeError}} and abort these substeps. Note: extra parameters are not allowed, including the empty `` `application/wasm;` ``. diff --git a/interpreter/Makefile b/interpreter/Makefile index 7820e642..97e6e17c 100644 --- a/interpreter/Makefile +++ b/interpreter/Makefile @@ -18,12 +18,12 @@ JSLIB = wast WINMAKE = winmake.bat DIRS = util syntax binary text valid runtime exec script host main tests -LIBS = bigarray +LIBS = FLAGS = -lexflags -ml -cflags '-w +a-4-27-42-44-45-70 -warn-error +a-3' OCBA = ocamlbuild $(FLAGS) $(DIRS:%=-I %) OCB = $(OCBA) $(LIBS:%=-libs %) JSO = js_of_ocaml -q --opt 3 -JS = # set to JS shell command to run JS tests +JS = # set to JS shell command to run JS tests, empty to skip # Main targets diff --git a/interpreter/README.md b/interpreter/README.md index 418b8450..18aa36c0 100644 --- a/interpreter/README.md +++ b/interpreter/README.md @@ -1,6 +1,6 @@ # WebAssembly Reference Interpreter -This repository implements a interpreter for WebAssembly. It is written for clarity and simplicity, _not_ speed. It is intended as a playground for trying out ideas and a device for nailing down the exact semantics, and as a proxy for the (yet to be produced) formal specification of WebAssembly. For that purpose, the code is written in a fairly declarative, "speccy" way. +This repository implements an interpreter for WebAssembly. It is written for clarity and simplicity, _not_ speed. It is intended as a playground for trying out ideas and a device for nailing down their exact semantics. For that purpose, the code is written in a fairly declarative, "speccy" way. The interpreter can diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly index 13617b06..af25869c 100644 --- a/interpreter/text/parser.mly +++ b/interpreter/text/parser.mly @@ -373,12 +373,16 @@ align_opt : /* Instructions & Expressions */ -instr : +instr_list : + | /* empty */ { fun c -> [] } + | instr1 instr_list { fun c -> $1 c @ $2 c } + | select_instr_instr_list { $1 } + | call_instr_instr_list { $1 } + +instr1 : | plain_instr { let at = at () in fun c -> [$1 c @@ at] } - | select_instr_instr { fun c -> let e, es = $1 c in e :: es } - | call_instr_instr { fun c -> let e, es = $1 c in e :: es } | block_instr { let at = at () in fun c -> [$1 c @@ at] } - | expr { $1 } /* Sugar */ + | expr { $1 } /* Sugar */ plain_instr : | UNREACHABLE { fun c -> unreachable } @@ -451,89 +455,51 @@ plain_instr : | VEC_REPLACE NAT { let at = at () in fun c -> $1 (vec_lane_index $2 at) } -select_instr : - | SELECT select_instr_results - { let at = at () in fun c -> let b, ts = $2 in - select (if b then (Some ts) else None) @@ at } - -select_instr_results : - | LPAR RESULT value_type_list RPAR select_instr_results - { let _, ts = $5 in true, $3 @ ts } - | /* empty */ - { false, [] } - -select_instr_instr : - | SELECT select_instr_results_instr +select_instr_instr_list : + | SELECT select_instr_results_instr_list { let at1 = ati 1 in fun c -> let b, ts, es = $2 c in - select (if b then (Some ts) else None) @@ at1, es } + (select (if b then (Some ts) else None) @@ at1) :: es } -select_instr_results_instr : - | LPAR RESULT value_type_list RPAR select_instr_results_instr +select_instr_results_instr_list : + | LPAR RESULT value_type_list RPAR select_instr_results_instr_list { fun c -> let _, ts, es = $5 c in true, $3 @ ts, es } - | instr + | instr_list { fun c -> false, [], $1 c } -call_instr : - | CALL_INDIRECT var call_instr_type - { let at = at () in fun c -> call_indirect ($2 c table) ($3 c) @@ at } - | CALL_INDIRECT call_instr_type /* Sugar */ - { let at = at () in fun c -> call_indirect (0l @@ at) ($2 c) @@ at } - -call_instr_type : - | type_use call_instr_params - { let at1 = ati 1 in - fun c -> - match $2 c with - | FuncType ([], []) -> $1 c type_ - | ft -> inline_type_explicit c ($1 c type_) ft at1 } - | call_instr_params - { let at = at () in fun c -> inline_type c ($1 c) at } - -call_instr_params : - | LPAR PARAM value_type_list RPAR call_instr_params - { fun c -> let FuncType (ts1, ts2) = $5 c in FuncType ($3 @ ts1, ts2) } - | call_instr_results - { fun c -> FuncType ([], $1 c) } - -call_instr_results : - | LPAR RESULT value_type_list RPAR call_instr_results - { fun c -> $3 @ $5 c } - | /* empty */ - { fun c -> [] } - - -call_instr_instr : - | CALL_INDIRECT var call_instr_type_instr +call_instr_instr_list : + | CALL_INDIRECT var call_instr_type_instr_list { let at1 = ati 1 in - fun c -> let x, es = $3 c in call_indirect ($2 c table) x @@ at1, es } - | CALL_INDIRECT call_instr_type_instr /* Sugar */ + fun c -> let x, es = $3 c in + (call_indirect ($2 c table) x @@ at1) :: es } + | CALL_INDIRECT call_instr_type_instr_list /* Sugar */ { let at1 = ati 1 in - fun c -> let x, es = $2 c in call_indirect (0l @@ at1) x @@ at1, es } + fun c -> let x, es = $2 c in + (call_indirect (0l @@ at1) x @@ at1) :: es } -call_instr_type_instr : - | type_use call_instr_params_instr +call_instr_type_instr_list : + | type_use call_instr_params_instr_list { let at1 = ati 1 in fun c -> match $2 c with | FuncType ([], []), es -> $1 c type_, es | ft, es -> inline_type_explicit c ($1 c type_) ft at1, es } - | call_instr_params_instr + | call_instr_params_instr_list { let at = at () in fun c -> let ft, es = $1 c in inline_type c ft at, es } -call_instr_params_instr : - | LPAR PARAM value_type_list RPAR call_instr_params_instr +call_instr_params_instr_list : + | LPAR PARAM value_type_list RPAR call_instr_params_instr_list { fun c -> let FuncType (ts1, ts2), es = $5 c in FuncType ($3 @ ts1, ts2), es } - | call_instr_results_instr + | call_instr_results_instr_list { fun c -> let ts, es = $1 c in FuncType ([], ts), es } -call_instr_results_instr : - | LPAR RESULT value_type_list RPAR call_instr_results_instr +call_instr_results_instr_list : + | LPAR RESULT value_type_list RPAR call_instr_results_instr_list { fun c -> let ts, es = $5 c in $3 @ ts, es } - | instr + | instr_list { fun c -> [], $1 c } @@ -744,12 +710,6 @@ try_ : | LPAR DO instr_list RPAR handler { fun bt c c' -> $5 bt ($3 c') c c' } -instr_list : - | /* empty */ { fun c -> [] } - | select_instr { fun c -> [$1 c] } - | call_instr { fun c -> [$1 c] } - | instr instr_list { fun c -> $1 c @ $2 c } - expr_list : | /* empty */ { fun c -> [] } | expr expr_list { fun c -> $1 c @ $2 c } diff --git a/test/core/call_indirect.wast b/test/core/call_indirect.wast index 1ecd9b7b..79b8dc39 100644 --- a/test/core/call_indirect.wast +++ b/test/core/call_indirect.wast @@ -1015,3 +1015,23 @@ (module (table funcref (elem 0 0))) "unknown function" ) + + + + +;; Flat syntax + +(module + (table 1 funcref) + (func unreachable call_indirect) + (func unreachable call_indirect nop) + (func unreachable call_indirect call_indirect) + (func unreachable call_indirect (call_indirect)) + (func unreachable call_indirect call_indirect call_indirect) + (func unreachable call_indirect (result)) + (func unreachable call_indirect (result) (result)) + (func unreachable call_indirect (result) (result) call_indirect) + (func unreachable call_indirect (result) (result) call_indirect (result)) + (func (result i32) unreachable call_indirect select) + (func (result i32) unreachable call_indirect select call_indirect) +) diff --git a/test/core/elem.wast b/test/core/elem.wast index 8dc04e6e..5857ae8b 100644 --- a/test/core/elem.wast +++ b/test/core/elem.wast @@ -148,6 +148,25 @@ (assert_return (invoke "call-7") (i32.const 65)) (assert_return (invoke "call-9") (i32.const 66)) +;; Same as the above, but use ref.null to ensure the elements use exprs. +;; Note: some tools like wast2json avoid using exprs when possible. +(module + (type $out-i32 (func (result i32))) + (table 11 funcref) + (elem (i32.const 6) funcref (ref.null func) (ref.func $const-i32-a)) + (elem (i32.const 9) funcref (ref.func $const-i32-b) (ref.null func)) + (func $const-i32-a (type $out-i32) (i32.const 65)) + (func $const-i32-b (type $out-i32) (i32.const 66)) + (func (export "call-7") (type $out-i32) + (call_indirect (type $out-i32) (i32.const 7)) + ) + (func (export "call-9") (type $out-i32) + (call_indirect (type $out-i32) (i32.const 9)) + ) +) +(assert_return (invoke "call-7") (i32.const 65)) +(assert_return (invoke "call-9") (i32.const 66)) + (assert_invalid (module (table 1 funcref) (global i32 (i32.const 0)) (elem (global.get 0) $f) (func $f)) "unknown global" diff --git a/test/core/select.wast b/test/core/select.wast index 046e6fe2..673dcf47 100644 --- a/test/core/select.wast +++ b/test/core/select.wast @@ -512,3 +512,20 @@ "type mismatch" ) + +;; Flat syntax + +(module + (table 1 funcref) + (func (result i32) unreachable select) + (func (result i32) unreachable select nop) + (func (result i32) unreachable select (select)) + (func (result i32) unreachable select select) + (func (result i32) unreachable select select select) + (func (result i32) unreachable select (result i32)) + (func (result i32) unreachable select (result i32) (result)) + (func (result i32) unreachable select (result i32) (result) select) + (func (result i32) unreachable select (result) (result i32) select (result i32)) + (func (result i32) unreachable select call_indirect) + (func (result i32) unreachable select call_indirect select) +) diff --git a/test/core/simd/simd_linking.wast b/test/core/simd/simd_linking.wast new file mode 100644 index 00000000..1a1d1635 --- /dev/null +++ b/test/core/simd/simd_linking.wast @@ -0,0 +1,12 @@ +(module + (global (export "g-v128") v128 (v128.const i64x2 0 0)) + (global (export "mg-v128") (mut v128) (v128.const i64x2 0 0)) +) +(register "Mv128") + +(module + ;; TODO: Reactivate once the fix for https://bugs.chromium.org/p/v8/issues/detail?id=13732 + ;; has made it to the downstream node.js that we use on CI. + ;; (import "Mv128" "g-v128" (global v128)) + (import "Mv128" "mg-v128" (global (mut v128))) +) diff --git a/test/core/table_fill.wast b/test/core/table_fill.wast index 3df64da1..a8e22255 100644 --- a/test/core/table_fill.wast +++ b/test/core/table_fill.wast @@ -5,6 +5,10 @@ (table.fill $t (local.get $i) (local.get $r) (local.get $n)) ) + (func (export "fill-abbrev") (param $i i32) (param $r externref) (param $n i32) + (table.fill (local.get $i) (local.get $r) (local.get $n)) + ) + (func (export "get") (param $i i32) (result externref) (table.get $t (local.get $i)) ) @@ -39,7 +43,7 @@ (assert_return (invoke "get" (i32.const 8)) (ref.extern 4)) (assert_return (invoke "get" (i32.const 9)) (ref.extern 4)) -(assert_return (invoke "fill" (i32.const 9) (ref.null extern) (i32.const 1))) +(assert_return (invoke "fill-abbrev" (i32.const 9) (ref.null extern) (i32.const 1))) (assert_return (invoke "get" (i32.const 8)) (ref.extern 4)) (assert_return (invoke "get" (i32.const 9)) (ref.null extern)) diff --git a/test/core/table_get.wast b/test/core/table_get.wast index 5d57c319..0dedb19f 100644 --- a/test/core/table_get.wast +++ b/test/core/table_get.wast @@ -10,7 +10,7 @@ ) (func (export "get-externref") (param $i i32) (result externref) - (table.get $t2 (local.get $i)) + (table.get (local.get $i)) ) (func $f3 (export "get-funcref") (param $i i32) (result funcref) (table.get $t3 (local.get $i)) diff --git a/test/core/table_grow.wast b/test/core/table_grow.wast index 7d5b5630..9a931a7f 100644 --- a/test/core/table_grow.wast +++ b/test/core/table_grow.wast @@ -7,6 +7,9 @@ (func (export "grow") (param $sz i32) (param $init externref) (result i32) (table.grow $t (local.get $init) (local.get $sz)) ) + (func (export "grow-abbrev") (param $sz i32) (param $init externref) (result i32) + (table.grow (local.get $init) (local.get $sz)) + ) (func (export "size") (result i32) (table.size $t)) ) @@ -22,7 +25,7 @@ (assert_trap (invoke "set" (i32.const 1) (ref.extern 2)) "out of bounds table access") (assert_trap (invoke "get" (i32.const 1)) "out of bounds table access") -(assert_return (invoke "grow" (i32.const 4) (ref.extern 3)) (i32.const 1)) +(assert_return (invoke "grow-abbrev" (i32.const 4) (ref.extern 3)) (i32.const 1)) (assert_return (invoke "size") (i32.const 5)) (assert_return (invoke "get" (i32.const 0)) (ref.extern 2)) (assert_return (invoke "set" (i32.const 0) (ref.extern 2))) diff --git a/test/core/table_set.wast b/test/core/table_set.wast index 5a9cfa37..3362f956 100644 --- a/test/core/table_set.wast +++ b/test/core/table_set.wast @@ -12,7 +12,7 @@ ) (func (export "set-externref") (param $i i32) (param $r externref) - (table.set $t2 (local.get $i) (local.get $r)) + (table.set (local.get $i) (local.get $r)) ) (func (export "set-funcref") (param $i i32) (param $r funcref) (table.set $t3 (local.get $i) (local.get $r)) diff --git a/test/core/table_size.wast b/test/core/table_size.wast index ad293b5e..83fef02b 100644 --- a/test/core/table_size.wast +++ b/test/core/table_size.wast @@ -4,7 +4,7 @@ (table $t2 0 2 externref) (table $t3 3 8 externref) - (func (export "size-t0") (result i32) (table.size $t0)) + (func (export "size-t0") (result i32) table.size) (func (export "size-t1") (result i32) (table.size $t1)) (func (export "size-t2") (result i32) (table.size $t2)) (func (export "size-t3") (result i32) (table.size $t3)) diff --git a/test/js-api/wasm-module-builder.js b/test/js-api/wasm-module-builder.js index 86d836a5..d0f9e78b 100644 --- a/test/js-api/wasm-module-builder.js +++ b/test/js-api/wasm-module-builder.js @@ -754,9 +754,9 @@ class WasmModuleBuilder { addTag(type) { let type_index = (typeof type) == "number" ? type : this.addType(type); - let except_index = this.tags.length + this.num_imported_tags; + let tag_index = this.tags.length + this.num_imported_tags; this.tags.push(type_index); - return except_index; + return tag_index; } addFunction(name, type) {