blob: 48b601b2a0ca50de2d7c721214f05e950d62a17e [file] [log] [blame]
.. index:: ! embedding, embedder, implementation, host
.. _embed:
Embedding
---------
A WebAssembly implementation will typically be *embedded* into a *host* environment.
An *embedder* implements the connection between such a host environment and the WebAssembly semantics as defined in the main body of this specification.
An embedder is expected to interact with the semantics in well-defined ways.
This section defines a suitable interface to the WebAssembly semantics in the form of entry points through which an embedder can access it.
The interface is intended to be complete, in the sense that an embedder does not need to reference other functional parts of the WebAssembly specification directly.
.. note::
On the other hand, an embedder does not need to provide the host environment with access to all functionality defined in this interface.
For example, an implementation may not support :ref:`parsing <embed-parse-module>` of the :ref:`text format <text>`.
In the description of the embedder interface, syntactic classes from the :ref:`abstract syntax <syntax>` and the :ref:`runtime's abstract machine <syntax-runtime>` are used as names for variables that range over the possible objects from that class.
Hence, these syntactic classes can also be interpreted as types.
.. _embed-error:
Failure of an interface operation is indicated by an auxiliary syntactic class:
.. math::
\begin{array}{llll}
\production{(error)} & \error &::=& \ERROR \\
\end{array}
In addition to the error conditions specified explicitly in this section, implementations may also return errors when specific :ref:`implementation limitations <impl>` are reached.
.. note::
Errors are abstract and unspecific with this definition.
Implementations can refine it to carry suitable classifications and diagnostic messages.
.. index:: allocation, store
.. _embed-store:
Store
~~~~~
.. _embed-init-store:
:math:`\F{init\_store}() : \store`
..................................
1. Return the empty :ref:`store <syntax-store>`.
.. math::
\begin{array}{lclll}
\F{init\_store}() &=& \{ \SFUNCS~\epsilon,~ \SMEMS~\epsilon,~ \STABLES~\epsilon,~ \SGLOBALS~\epsilon \} \\
\end{array}
.. index:: module
.. _embed-module:
Modules
~~~~~~~
.. index:: binary format
.. _embed-decode-module:
:math:`\F{decode\_module}(\byte^\ast) : \module ~|~ \error`
...........................................................
1. If there exists a derivation for the :ref:`byte <syntax-byte>` sequence :math:`\byte^\ast` as a :math:`\Bmodule` according to the :ref:`binary grammar for modules <binary-module>`, yielding a :ref:`module <syntax-module>` :math:`m`, then return :math:`m`.
2. Else, return :math:`\ERROR`.
.. math::
\begin{array}{lclll}
\F{decode\_module}(b^\ast) &=& m && (\iff \Bmodule \stackrel\ast\Longrightarrow m{:}b^\ast) \\
\F{decode\_module}(b^\ast) &=& \ERROR && (\otherwise) \\
\end{array}
.. index:: text format
.. _embed-parse-module:
:math:`\F{parse\_module}(\codepoint^\ast) : \module ~|~ \error`
...............................................................
1. If there exists a derivation for the :ref:`source <text-source>` :math:`\codepoint^\ast` as a :math:`\Tmodule` according to the :ref:`text grammar for modules <text-module>`, yielding a :ref:`module <syntax-module>` :math:`m`, then return :math:`m`.
2. Else, return :math:`\ERROR`.
.. math::
\begin{array}{lclll}
\F{parse\_module}(c^\ast) &=& m && (\iff \Tmodule \stackrel\ast\Longrightarrow m{:}c^\ast) \\
\F{parse\_module}(c^\ast) &=& \ERROR && (\otherwise) \\
\end{array}
.. index:: validation
.. _embed-validate-module:
:math:`\F{validate\_module}(\module) : \error^?`
................................................
1. If :math:`\module` is :ref:`valid <valid-module>`, then return nothing.
2. Else, return :math:`\ERROR`.
.. math::
\begin{array}{lclll}
\F{validate\_module}(m) &=& \epsilon && (\iff {} \vdashmodule m : \externtype^\ast \to {\externtype'}^\ast) \\
\F{validate\_module}(m) &=& \ERROR && (\otherwise) \\
\end{array}
.. index:: instantiation, module instance
.. _embed-instantiate-module:
:math:`\F{instantiate\_module}(\store, \module, \externval^\ast) : (\store, \moduleinst ~|~ \error)`
....................................................................................................
1. Try :ref:`instantiating <exec-instantiation>` :math:`\module` in :math:`\store` with :ref:`external values <syntax-externval>` :math:`\externval^\ast` as imports:
a. If it succeeds with a :ref:`module instance <syntax-moduleinst>` :math:`\moduleinst`, then let :math:`\X{result}` be :math:`\moduleinst`.
b. Else, let :math:`\X{result}` be :math:`\ERROR`.
2. Return the new store paired with :math:`\X{result}`.
.. math::
\begin{array}{lclll}
\F{instantiate\_module}(S, m, \X{ev}^\ast) &=& (S', F.\AMODULE) && (\iff \instantiate(S, m, \X{ev}^\ast) \stepto^\ast S'; F; \epsilon) \\
\F{instantiate\_module}(S, m, \X{ev}^\ast) &=& (S', \ERROR) && (\iff \instantiate(S, m, \X{ev}^\ast) \stepto^\ast S'; F; \TRAP) \\
\end{array}
.. note::
The store may be modified even in case of an error.
.. index:: import
.. _embed-imports:
:math:`\F{module\_imports}(\module) : (\name, \name, \externtype)^\ast`
.......................................................................
1. Assert: :math:`\module` is :ref:`valid <valid-module>` with external import types :math:`\externtype^\ast` and external export types :math:`{\externtype'}^\ast`.
2. Let :math:`\import^\ast` be the :ref:`imports <syntax-import>` :math:`\module.\MIMPORTS`.
3. Assert: the length of :math:`\import^\ast` equals the length of :math:`\externtype^\ast`.
4. For each :math:`\import_i` in :math:`\import^\ast` and corresponding :math:`\externtype_i` in :math:`\externtype^\ast`, do:
a. Let :math:`\X{result}_i` be the triple :math:`(\import_i.\IMODULE, \import_i.\INAME, \externtype_i)`.
5. Return the concatenation of all :math:`\X{result}_i`, in index order.
.. math::
~ \\
\begin{array}{lclll}
\F{module\_imports}(m) &=& (\X{im}.\IMODULE, \X{im}.\INAME, \externtype)^\ast \\
&& \qquad (\iff \X{im}^\ast = m.\MIMPORTS \wedge {} \vdashmodule m : \externtype^\ast \to {\externtype'}^\ast) \\
\end{array}
.. index:: export
.. _embed-exports:
:math:`\F{module\_exports}(\module) : (\name, \externtype)^\ast`
................................................................
1. Assert: :math:`\module` is :ref:`valid <valid-module>` with external import types :math:`\externtype^\ast` and external export types :math:`{\externtype'}^\ast`.
2. Let :math:`\export^\ast` be the :ref:`exports <syntax-export>` :math:`\module.\MEXPORTS`.
3. Assert: the length of :math:`\export^\ast` equals the length of :math:`{\externtype'}^\ast`.
4. For each :math:`\export_i` in :math:`\export^\ast` and corresponding :math:`\externtype'_i` in :math:`{\externtype'}^\ast`, do:
a. Let :math:`\X{result}_i` be the pair :math:`(\export_i.\ENAME, \externtype'_i)`.
5. Return the concatenation of all :math:`\X{result}_i`, in index order.
.. math::
~ \\
\begin{array}{lclll}
\F{module\_exports}(m) &=& (\X{ex}.\ENAME, \externtype')^\ast \\
&& \qquad (\iff \X{ex}^\ast = m.\MEXPORTS \wedge {} \vdashmodule m : \externtype^\ast \to {\externtype'}^\ast) \\
\end{array}
.. index:: module, store, module instance, export instance
.. _embed-export:
Exports
~~~~~~~
.. _embed-get-export:
:math:`\F{get\_export}(\moduleinst, \name) : \externval ~|~ \error`
...................................................................
1. Assert: due to :ref:`validity <valid-moduleinst>` of the :ref:`module instance <syntax-moduleinst>` :math:`\moduleinst`, all its :ref:`export names <syntax-exportinst>` are different.
2. If there exists an :math:`\exportinst_i` in :math:`\moduleinst.\MIEXPORTS` such that :ref:`name <syntax-name>` :math:`\exportinst_i.\EINAME` equals :math:`\name`, then:
a. Return the :ref:`external value <syntax-externval>` :math:`\exportinst_i.\EIVALUE`.
3. Else, return :math:`\ERROR`.
.. math::
~ \\
\begin{array}{lclll}
\F{get\_export}(m, \name) &=& m.\MIEXPORTS[i].\EIVALUE && (\iff m.\MEXPORTS[i].\EINAME = \name) \\
\F{get\_export}(m, \name) &=& \ERROR && (\otherwise) \\
\end{array}
.. index:: function, host function, function address, function instance, function type, store
.. _embed-func:
Functions
~~~~~~~~~
.. _embed-alloc-func:
:math:`\F{alloc\_func}(\store, \functype, \hostfunc) : (\store, \funcaddr)`
...........................................................................
1. Let :math:`\funcaddr` be the result of :ref:`allocating a host function <alloc-func>` in :math:`\store` with :ref:`function type <syntax-functype>` :math:`\functype` and host function code :math:`\hostfunc`.
2. Return the new store paired with :math:`\funcaddr`.
.. math::
\begin{array}{lclll}
\F{alloc\_func}(S, \X{ft}, \X{code}) &=& (S', \X{a}) && (\iff \allochostfunc(S, \X{ft}, \X{code}) = S', \X{a}) \\
\end{array}
.. note::
This operation assumes that :math:`\hostfunc` satisfies the :ref:`pre- and post-conditions <exec-invoke-host>` required for a function instance with type :math:`\functype`.
Regular (non-host) function instances can only be created indirectly through :ref:`module instantiation <embed-instantiate-module>`.
.. _embed-type-func:
:math:`\F{type\_func}(\store, \funcaddr) : \functype`
.....................................................
1. Assert: :math:`\store.\SFUNCS[\funcaddr]` exists.
2. Assert: the :ref:`external value <syntax-externval>` :math:`\EVFUNC~\funcaddr` is :ref:`valid <valid-externval>` with :ref:`external type <syntax-externtype>` :math:`\ETFUNC~\functype`.
3. Return :math:`\functype`.
.. math::
\begin{array}{lclll}
\F{type\_func}(S, a) &=& \X{ft} && (\iff S \vdashexternval \EVFUNC~a : \ETFUNC~\X{ft}) \\
\end{array}
.. index:: invocation, value, result
.. _embed-invoke-func:
:math:`\F{invoke\_func}(\store, \funcaddr, \val^\ast) : (\store, \val^\ast ~|~ \error)`
........................................................................................
1. Assert: :math:`\store.\SFUNCS[\funcaddr]` exists.
2. Try :ref:`invoking <exec-invocation>` the function :math:`\funcaddr` in :math:`\store` with :ref:`values <syntax-val>` :math:`\val^\ast` as arguments:
a. If it succeeds with :ref:`values <syntax-val>` :math:`{\val'}^\ast` as results, then let :math:`\X{result}` be :math:`{\val'}^\ast`.
b. Else it has trapped, hence let :math:`\X{result}` be :math:`\ERROR`.
3. Return the new store paired with :math:`\X{result}`.
.. math::
~ \\
\begin{array}{lclll}
\F{invoke\_func}(S, a, v^\ast) &=& (S', {v'}^\ast) && (\iff \invoke(S, a, v^\ast) \stepto^\ast S'; F; {v'}^\ast) \\
\F{invoke\_func}(S, a, v^\ast) &=& (S', \ERROR) && (\iff \invoke(S, a, v^\ast) \stepto^\ast S'; F; \TRAP) \\
\end{array}
.. note::
The store may be modified even in case of an error.
.. index:: table, table address, store, table instance, table type, element, function address
.. _embed-table:
Tables
~~~~~~
.. _embed-alloc-table:
:math:`\F{alloc\_table}(\store, \tabletype) : (\store, \tableaddr)`
...................................................................
1. Let :math:`\tableaddr` be the result of :ref:`allocating a table <alloc-table>` in :math:`\store` with :ref:`table type <syntax-tabletype>` :math:`\tabletype`.
2. Return the new store paired with :math:`\tableaddr`.
.. math::
\begin{array}{lclll}
\F{alloc\_table}(S, \X{tt}) &=& (S', \X{a}) && (\iff \alloctable(S, \X{tt}) = S', \X{a}) \\
\end{array}
.. _embed-type-table:
:math:`\F{type\_table}(\store, \tableaddr) : \tabletype`
........................................................
1. Assert: :math:`\store.\STABLES[\tableaddr]` exists.
2. Assert: the :ref:`external value <syntax-externval>` :math:`\EVTABLE~\tableaddr` is :ref:`valid <valid-externval>` with :ref:`external type <syntax-externtype>` :math:`\ETTABLE~\tabletype`.
3. Return :math:`\tabletype`.
.. math::
\begin{array}{lclll}
\F{type\_table}(S, a) &=& \X{tt} && (\iff S \vdashexternval \EVTABLE~a : \ETTABLE~\X{tt}) \\
\end{array}
.. _embed-read-table:
:math:`\F{read\_table}(\store, \tableaddr, i) : \funcaddr^? ~|~ \error`
.......................................................................
1. Assert: :math:`\store.\STABLES[\tableaddr]` exists.
2. Assert: :math:`i` is a non-negative integer.
3. Let :math:`\X{ti}` be the :ref:`table instance <syntax-tableinst>` :math:`\store.\STABLES[\tableaddr]`.
4. If :math:`i` is larger than or equal to the length of :math:`\X{ti}.\TIELEM`, then return :math:`\ERROR`.
5. Else, return :math:`\X{ti}.\TIELEM[i]`.
.. math::
\begin{array}{lclll}
\F{read\_table}(S, a, i) &=& \X{fa}^? && (\iff S.\STABLES[a].\TIELEM[i] = \X{fa}^?) \\
\F{read\_table}(S, a, i) &=& \ERROR && (\otherwise) \\
\end{array}
.. _embed-write-table:
:math:`\F{write\_table}(\store, \tableaddr, i, \funcaddr^?) : \store ~|~ \error`
................................................................................
1. Assert: :math:`\store.\STABLES[\tableaddr]` exists.
2. Assert: :math:`i` is a non-negative integer.
3. Let :math:`\X{ti}` be the :ref:`table instance <syntax-tableinst>` :math:`\store.\STABLES[\tableaddr]`.
4. If :math:`i` is larger than or equal to the length of :math:`\X{ti}.\TIELEM`, then return :math:`\ERROR`.
5. Replace :math:`\X{ti}.\TIELEM[i]` with the optional :ref:`function address <syntax-funcaddr>` :math:`\X{fa}^?`.
6. Return the updated store.
.. math::
\begin{array}{lclll}
\F{write\_table}(S, a, i, \X{fa}^?) &=& S' && (\iff S' = S \with \STABLES[a].\TIELEM[i] = \X{fa}^?) \\
\F{write\_table}(S, a, i, \X{fa}^?) &=& \ERROR && (\otherwise) \\
\end{array}
.. _embed-size-table:
:math:`\F{size\_table}(\store, \tableaddr) : \X{i32}`
.....................................................
1. Assert: :math:`\store.\STABLES[\tableaddr]` exists.
2. Return the length of :math:`\store.\STABLES[\tableaddr].\TIELEM`.
.. math::
~ \\
\begin{array}{lclll}
\F{size\_table}(S, a) &=& n &&
(\iff |S.\STABLES[a].\TIELEM| = n) \\
\end{array}
.. _embed-grow-table:
:math:`\F{grow\_table}(\store, \tableaddr, n) : \store ~|~ \error`
..................................................................
1. Assert: :math:`\store.\STABLES[\tableaddr]` exists.
2. Assert: :math:`n` is a non-negative integer.
3. Try :ref:`growing <grow-table>` the :ref:`table instance <syntax-tableinst>` :math:`\store.\STABLES[\tableaddr]` by :math:`n` elements:
a. If it succeeds, return the updated store.
b. Else, return :math:`\ERROR`.
.. math::
~ \\
\begin{array}{lclll}
\F{grow\_table}(S, a, n) &=& S' &&
(\iff S' = S \with \STABLES[a] = \growtable(S.\STABLES[a], n)) \\
\F{grow\_table}(S, a, n) &=& \ERROR && (\otherwise) \\
\end{array}
.. index:: memory, memory address, store, memory instance, memory type, byte
.. _embed-mem:
Memories
~~~~~~~~
.. _embed-alloc-mem:
:math:`\F{alloc\_mem}(\store, \memtype) : (\store, \memaddr)`
................................................................
1. Let :math:`\memaddr` be the result of :ref:`allocating a memory <alloc-mem>` in :math:`\store` with :ref:`memory type <syntax-memtype>` :math:`\memtype`.
2. Return the new store paired with :math:`\memaddr`.
.. math::
\begin{array}{lclll}
\F{alloc\_mem}(S, \X{mt}) &=& (S', \X{a}) && (\iff \allocmem(S, \X{mt}) = S', \X{a}) \\
\end{array}
.. _embed-type-mem:
:math:`\F{type\_mem}(\store, \memaddr) : \memtype`
..................................................
1. Assert: :math:`\store.\SMEMS[\memaddr]` exists.
2. Assert: the :ref:`external value <syntax-externval>` :math:`\EVMEM~\memaddr` is :ref:`valid <valid-externval>` with :ref:`external type <syntax-externtype>` :math:`\ETMEM~\memtype`.
3. Return :math:`\memtype`.
.. math::
\begin{array}{lclll}
\F{type\_mem}(S, a) &=& \X{mt} && (\iff S \vdashexternval \EVMEM~a : \ETMEM~\X{mt}) \\
\end{array}
.. _embed-read-mem:
:math:`\F{read\_mem}(\store, \memaddr, i) : \byte ~|~ \error`
.............................................................
1. Assert: :math:`\store.\SMEMS[\memaddr]` exists.
2. Assert: :math:`i` is a non-negative integer.
3. Let :math:`\X{mi}` be the :ref:`memory instance <syntax-meminst>` :math:`\store.\SMEMS[\memaddr]`.
4. If :math:`i` is larger than or equal to the length of :math:`\X{mi}.\MIDATA`, then return :math:`\ERROR`.
5. Else, return the :ref:`byte <syntax-byte>` :math:`\X{mi}.\MIDATA[i]`.
.. math::
\begin{array}{lclll}
\F{read\_mem}(S, a, i) &=& b && (\iff S.\SMEMS[a].\MIDATA[i] = b) \\
\F{read\_mem}(S, a, i) &=& \ERROR && (\otherwise) \\
\end{array}
.. _embed-write-mem:
:math:`\F{write\_mem}(\store, \memaddr, i, \byte) : \store ~|~ \error`
......................................................................
1. Assert: :math:`\store.\SMEMS[\memaddr]` exists.
2. Assert: :math:`i` is a non-negative integer.
3. Let :math:`\X{mi}` be the :ref:`memory instance <syntax-meminst>` :math:`\store.\SMEMS[\memaddr]`.
4. If :math:`i` is larger than or equal to the length of :math:`\X{mi}.\MIDATA`, then return :math:`\ERROR`.
5. Replace :math:`\X{mi}.\MIDATA[i]` with :math:`\byte`.
6. Return the updated store.
.. math::
\begin{array}{lclll}
\F{write\_mem}(S, a, i, b) &=& S' && (\iff S' = S \with \SMEMS[a].\MIDATA[i] = b) \\
\F{write\_mem}(S, a, i, b) &=& \ERROR && (\otherwise) \\
\end{array}
.. _embed-size-mem:
:math:`\F{size\_mem}(\store, \memaddr) : \X{i32}`
.................................................
1. Assert: :math:`\store.\SMEMS[\memaddr]` exists.
2. Return the length of :math:`\store.\SMEMS[\memaddr].\MIDATA` divided by the :ref:`page size <page-size>`.
.. math::
~ \\
\begin{array}{lclll}
\F{size\_mem}(S, a) &=& n &&
(\iff |S.\SMEMS[a].\MIDATA| = n \cdot 64\,\F{Ki}) \\
\end{array}
.. _embed-grow-mem:
:math:`\F{grow\_mem}(\store, \memaddr, n) : \store ~|~ \error`
..............................................................
1. Assert: :math:`\store.\SMEMS[\memaddr]` exists.
2. Assert: :math:`n` is a non-negative integer.
3. Try :ref:`growing <grow-mem>` the :ref:`memory instance <syntax-meminst>` :math:`\store.\SMEMS[\memaddr]` by :math:`n` :ref:`pages <page-size>`:
a. If it succeeds, return the updated store.
b. Else, return :math:`\ERROR`.
.. math::
~ \\
\begin{array}{lclll}
\F{grow\_mem}(S, a, n) &=& S' &&
(\iff S' = S \with \SMEMS[a] = \growmem(S.\SMEMS[a], n)) \\
\F{grow\_mem}(S, a, n) &=& \ERROR && (\otherwise) \\
\end{array}
.. index:: global, global address, store, global instance, global type, value
.. _embed-global:
Globals
~~~~~~~
.. _embed-alloc-global:
:math:`\F{alloc\_global}(\store, \globaltype, \val) : (\store, \globaladdr)`
............................................................................
1. Let :math:`\globaladdr` be the result of :ref:`allocating a global <alloc-global>` in :math:`\store` with :ref:`global type <syntax-globaltype>` :math:`\globaltype` and initialization value :math:`\val`.
2. Return the new store paired with :math:`\globaladdr`.
.. math::
\begin{array}{lclll}
\F{alloc\_global}(S, \X{gt}, v) &=& (S', \X{a}) && (\iff \allocglobal(S, \X{gt}, v) = S', \X{a}) \\
\end{array}
.. _embed-type-global:
:math:`\F{type\_global}(\store, \globaladdr) : \globaltype`
...........................................................
1. Assert: :math:`\store.\SGLOBALS[\globaladdr]` exists.
2. Assert: the :ref:`external value <syntax-externval>` :math:`\EVGLOBAL~\globaladdr` is :ref:`valid <valid-externval>` with :ref:`external type <syntax-externtype>` :math:`\ETGLOBAL~\globaltype`.
3. Return :math:`\globaltype`.
.. math::
\begin{array}{lclll}
\F{type\_global}(S, a) &=& \X{gt} && (\iff S \vdashexternval \EVGLOBAL~a : \ETGLOBAL~\X{gt}) \\
\end{array}
.. _embed-read-global:
:math:`\F{read\_global}(\store, \globaladdr) : \val`
....................................................
1. Assert: :math:`\store.\SGLOBALS[\globaladdr]` exists.
2. Let :math:`\X{gi}` be the :ref:`global instance <syntax-globalinst>` :math:`\store.\SGLOBALS[\globaladdr]`.
3. Return the :ref:`value <syntax-val>` :math:`\X{gi}.\GIVALUE`.
.. math::
\begin{array}{lclll}
\F{read\_global}(S, a) &=& v && (\iff S.\SGLOBALS[a].\GIVALUE = v) \\
\end{array}
.. _embed-write-global:
:math:`\F{write\_global}(\store, \globaladdr, \val) : \store ~|~ \error`
........................................................................
1. Assert: :math:`\store.\SGLOBALS[a]` exists.
2. Let :math:`\X{gi}` be the :ref:`global instance <syntax-globalinst>` :math:`\store.\SGLOBALS[\globaladdr]`.
3. If :math:`\X{gi}.\GIMUT` is not :math:`\MVAR`, then return :math:`\ERROR`.
4. Replace :math:`\X{gi}.\GIVALUE` with the :ref:`value <syntax-val>` :math:`\val`.
5. Return the updated store.
.. math::
~ \\
\begin{array}{lclll}
\F{write\_global}(S, a, v) &=& S' && (\iff S.\SGLOBALS[a].\GIMUT = \MVAR \wedge S' = S \with \SGLOBALS[a].\GIVALUE = v) \\
\F{write\_global}(S, a, v) &=& \ERROR && (\otherwise) \\
\end{array}