blob: afcb5a6e6d9f227bec312e32e0273a6cda2af8c5 [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-module-parse>` of the :ref:`text format <text>`.
Types
.....
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.
For numeric parameters, notation like :math:`n:\u32` is used to specify a symbolic name in addition to the respective value range.
.. _embed-error:
Errors
......
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.
Pre- and Post-Conditions
........................
Some operations state *pre-conditions* about their arguments or *post-conditions* about their results.
It is the embedder's responsibility to meet the pre-conditions.
If it does, the post conditions are guaranteed by the semantics.
In addition to pre- and post-conditions explicitly stated with each operation, the specification adopts the following conventions for :ref:`runtime objects <syntax-runtime>` (:math:`store`, :math:`\moduleinst`, :math:`\externval`, :ref:`addresses <syntax-addr>`):
* Every runtime object passed as a parameter must be :ref:`valid <valid-store>` per an implicit pre-condition.
* Every runtime object returned as a result is :ref:`valid <valid-store>` per an implicit post-condition.
.. note::
As long as an embedder treats runtime objects as abstract and only creates and manipulates them through the interface defined here, all implicit pre-conditions are automatically met.
.. index:: allocation, store
.. _embed-store:
Store
~~~~~
.. _embed-store-init:
:math:`\F{store\_init}() : \store`
..................................
1. Return the empty :ref:`store <syntax-store>`.
.. math::
\begin{array}{lclll}
\F{store\_init}() &=& \{ \SFUNCS~\epsilon,~ \SMEMS~\epsilon,~ \STABLES~\epsilon,~ \SGLOBALS~\epsilon \} \\
\end{array}
.. index:: module
.. _embed-module:
Modules
~~~~~~~
.. index:: binary format
.. _embed-module-decode:
:math:`\F{module\_decode}(\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{module\_decode}(b^\ast) &=& m && (\iff \Bmodule \stackrel\ast\Longrightarrow m{:}b^\ast) \\
\F{module\_decode}(b^\ast) &=& \ERROR && (\otherwise) \\
\end{array}
.. index:: text format
.. _embed-module-parse:
:math:`\F{module\_parse}(\char^\ast) : \module ~|~ \error`
..........................................................
1. If there exists a derivation for the :ref:`source <text-source>` :math:`\char^\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{module\_parse}(c^\ast) &=& m && (\iff \Tmodule \stackrel\ast\Longrightarrow m{:}c^\ast) \\
\F{module\_parse}(c^\ast) &=& \ERROR && (\otherwise) \\
\end{array}
.. index:: validation
.. _embed-module-validate:
:math:`\F{module\_validate}(\module) : \error^?`
................................................
1. If :math:`\module` is :ref:`valid <valid-module>`, then return nothing.
2. Else, return :math:`\ERROR`.
.. math::
\begin{array}{lclll}
\F{module\_validate}(m) &=& \epsilon && (\iff {} \vdashmodule m : \externtype^\ast \to {\externtype'}^\ast) \\
\F{module\_validate}(m) &=& \ERROR && (\otherwise) \\
\end{array}
.. index:: instantiation, module instance
.. _embed-module-instantiate:
:math:`\F{module\_instantiate}(\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{module\_instantiate}(S, m, \X{ev}^\ast) &=& (S', F.\AMODULE) && (\iff \instantiate(S, m, \X{ev}^\ast) \stepto^\ast S'; F; \epsilon) \\
\F{module\_instantiate}(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-module-imports:
:math:`\F{module\_imports}(\module) : (\name, \name, \externtype)^\ast`
.......................................................................
1. Pre-condition: :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.
6. Post-condition: each :math:`\externtype_i` is :ref:`valid <valid-externtype>`.
.. 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-module-exports:
:math:`\F{module\_exports}(\module) : (\name, \externtype)^\ast`
................................................................
1. Pre-condition: :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.
6. Post-condition: each :math:`\externtype'_i` is :ref:`valid <valid-externtype>`.
.. 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, module instance
.. _embed-instance:
Module Instances
~~~~~~~~~~~~~~~~
.. index:: export, export instance
.. _embed-instance-export:
:math:`\F{instance\_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{instance\_export}(m, \name) &=& m.\MIEXPORTS[i].\EIVALUE && (\iff m.\MEXPORTS[i].\EINAME = \name) \\
\F{instance\_export}(m, \name) &=& \ERROR && (\otherwise) \\
\end{array}
.. index:: function, host function, function address, function instance, function type, store
.. _embed-func:
Functions
~~~~~~~~~
.. _embed-func-alloc:
:math:`\F{func\_alloc}(\store, \functype, \hostfunc) : (\store, \funcaddr)`
...........................................................................
1. Pre-condition: :math:`\functype` is :math:`valid <valid-functype>`.
2. 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`.
3. Return the new store paired with :math:`\funcaddr`.
.. math::
\begin{array}{lclll}
\F{func\_alloc}(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-module-instantiate>`.
.. _embed-func-type:
:math:`\F{func\_type}(\store, \funcaddr) : \functype`
.....................................................
1. Assert: the :ref:`external value <syntax-externval>` :math:`\EVFUNC~\funcaddr` is :ref:`valid <valid-externval>` with :ref:`external type <syntax-externtype>` :math:`\ETFUNC~\functype`.
2. Return :math:`\functype`.
3. Post-condition: :math:`\functype` is :ref:`valid <valid-functype>`.
.. math::
\begin{array}{lclll}
\F{func\_type}(S, a) &=& \X{ft} && (\iff S \vdashexternval \EVFUNC~a : \ETFUNC~\X{ft}) \\
\end{array}
.. index:: invocation, value, result
.. _embed-func-invoke:
:math:`\F{func\_invoke}(\store, \funcaddr, \val^\ast) : (\store, \val^\ast ~|~ \error)`
........................................................................................
1. 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`.
2. Return the new store paired with :math:`\X{result}`.
.. math::
~ \\
\begin{array}{lclll}
\F{func\_invoke}(S, a, v^\ast) &=& (S', {v'}^\ast) && (\iff \invoke(S, a, v^\ast) \stepto^\ast S'; F; {v'}^\ast) \\
\F{func\_invoke}(S, a, v^\ast) &=& (S', \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-table-alloc:
:math:`\F{table\_alloc}(\store, \tabletype) : (\store, \tableaddr)`
...................................................................
1. Pre-condition: :math:`\tabletype` is :math:`valid <valid-tabletype>`.
2. Let :math:`\tableaddr` be the result of :ref:`allocating a table <alloc-table>` in :math:`\store` with :ref:`table type <syntax-tabletype>` :math:`\tabletype`.
3. Return the new store paired with :math:`\tableaddr`.
.. math::
\begin{array}{lclll}
\F{table\_alloc}(S, \X{tt}) &=& (S', \X{a}) && (\iff \alloctable(S, \X{tt}) = S', \X{a}) \\
\end{array}
.. _embed-table-type:
:math:`\F{table\_type}(\store, \tableaddr) : \tabletype`
........................................................
1. Assert: the :ref:`external value <syntax-externval>` :math:`\EVTABLE~\tableaddr` is :ref:`valid <valid-externval>` with :ref:`external type <syntax-externtype>` :math:`\ETTABLE~\tabletype`.
2. Return :math:`\tabletype`.
3. Post-condition: :math:`\tabletype` is :math:`valid <valid-tabletype>`.
.. math::
\begin{array}{lclll}
\F{table\_type}(S, a) &=& \X{tt} && (\iff S \vdashexternval \EVTABLE~a : \ETTABLE~\X{tt}) \\
\end{array}
.. _embed-table-read:
:math:`\F{table\_read}(\store, \tableaddr, i:\u32) : \funcaddr^? ~|~ \error`
............................................................................
1. Let :math:`\X{ti}` be the :ref:`table instance <syntax-tableinst>` :math:`\store.\STABLES[\tableaddr]`.
2. If :math:`i` is larger than or equal to the length of :math:`\X{ti}.\TIELEM`, then return :math:`\ERROR`.
3. Else, return :math:`\X{ti}.\TIELEM[i]`.
.. math::
\begin{array}{lclll}
\F{table\_read}(S, a, i) &=& \X{fa}^? && (\iff S.\STABLES[a].\TIELEM[i] = \X{fa}^?) \\
\F{table\_read}(S, a, i) &=& \ERROR && (\otherwise) \\
\end{array}
.. _embed-table-write:
:math:`\F{table\_write}(\store, \tableaddr, i:\u32, \funcaddr^?) : \store ~|~ \error`
.......................................................................................
1. Let :math:`\X{ti}` be the :ref:`table instance <syntax-tableinst>` :math:`\store.\STABLES[\tableaddr]`.
2. If :math:`i` is larger than or equal to the length of :math:`\X{ti}.\TIELEM`, then return :math:`\ERROR`.
3. Replace :math:`\X{ti}.\TIELEM[i]` with the optional :ref:`function address <syntax-funcaddr>` :math:`\X{fa}^?`.
4. Return the updated store.
.. math::
\begin{array}{lclll}
\F{table\_write}(S, a, i, \X{fa}^?) &=& S' && (\iff S' = S \with \STABLES[a].\TIELEM[i] = \X{fa}^?) \\
\F{table\_write}(S, a, i, \X{fa}^?) &=& \ERROR && (\otherwise) \\
\end{array}
.. _embed-table-size:
:math:`\F{table\_size}(\store, \tableaddr) : \u32`
..................................................
1. Return the length of :math:`\store.\STABLES[\tableaddr].\TIELEM`.
.. math::
~ \\
\begin{array}{lclll}
\F{table\_size}(S, a) &=& n &&
(\iff |S.\STABLES[a].\TIELEM| = n) \\
\end{array}
.. _embed-table-grow:
:math:`\F{table\_grow}(\store, \tableaddr, n:\u32) : \store ~|~ \error`
.......................................................................
1. 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{table\_grow}(S, a, n) &=& S' &&
(\iff S' = S \with \STABLES[a] = \growtable(S.\STABLES[a], n)) \\
\F{table\_grow}(S, a, n) &=& \ERROR && (\otherwise) \\
\end{array}
.. index:: memory, memory address, store, memory instance, memory type, byte
.. _embed-mem:
Memories
~~~~~~~~
.. _embed-mem-alloc:
:math:`\F{mem\_alloc}(\store, \memtype) : (\store, \memaddr)`
................................................................
1. Pre-condition: :math:`\memtype` is :math:`valid <valid-memtype>`.
2. Let :math:`\memaddr` be the result of :ref:`allocating a memory <alloc-mem>` in :math:`\store` with :ref:`memory type <syntax-memtype>` :math:`\memtype`.
3. Return the new store paired with :math:`\memaddr`.
.. math::
\begin{array}{lclll}
\F{mem\_alloc}(S, \X{mt}) &=& (S', \X{a}) && (\iff \allocmem(S, \X{mt}) = S', \X{a}) \\
\end{array}
.. _embed-mem-type:
:math:`\F{mem\_type}(\store, \memaddr) : \memtype`
..................................................
1. Assert: the :ref:`external value <syntax-externval>` :math:`\EVMEM~\memaddr` is :ref:`valid <valid-externval>` with :ref:`external type <syntax-externtype>` :math:`\ETMEM~\memtype`.
2. Return :math:`\memtype`.
3. Post-condition: :math:`\memtype` is :math:`valid <valid-memtype>`.
.. math::
\begin{array}{lclll}
\F{mem\_type}(S, a) &=& \X{mt} && (\iff S \vdashexternval \EVMEM~a : \ETMEM~\X{mt}) \\
\end{array}
.. _embed-mem-read:
:math:`\F{mem\_read}(\store, \memaddr, i:\u32) : \byte ~|~ \error`
..................................................................
1. Let :math:`\X{mi}` be the :ref:`memory instance <syntax-meminst>` :math:`\store.\SMEMS[\memaddr]`.
2. If :math:`i` is larger than or equal to the length of :math:`\X{mi}.\MIDATA`, then return :math:`\ERROR`.
3. Else, return the :ref:`byte <syntax-byte>` :math:`\X{mi}.\MIDATA[i]`.
.. math::
\begin{array}{lclll}
\F{mem\_read}(S, a, i) &=& b && (\iff S.\SMEMS[a].\MIDATA[i] = b) \\
\F{mem\_read}(S, a, i) &=& \ERROR && (\otherwise) \\
\end{array}
.. _embed-mem-write:
:math:`\F{mem\_write}(\store, \memaddr, i:\u32, \byte) : \store ~|~ \error`
...........................................................................
1. Let :math:`\X{mi}` be the :ref:`memory instance <syntax-meminst>` :math:`\store.\SMEMS[\memaddr]`.
2. If :math:`\u32` is larger than or equal to the length of :math:`\X{mi}.\MIDATA`, then return :math:`\ERROR`.
3. Replace :math:`\X{mi}.\MIDATA[i]` with :math:`\byte`.
4. Return the updated store.
.. math::
\begin{array}{lclll}
\F{mem\_write}(S, a, i, b) &=& S' && (\iff S' = S \with \SMEMS[a].\MIDATA[i] = b) \\
\F{mem\_write}(S, a, i, b) &=& \ERROR && (\otherwise) \\
\end{array}
.. _embed-mem-size:
:math:`\F{mem\_size}(\store, \memaddr) : \u32`
..............................................
1. Return the length of :math:`\store.\SMEMS[\memaddr].\MIDATA` divided by the :ref:`page size <page-size>`.
.. math::
~ \\
\begin{array}{lclll}
\F{mem\_size}(S, a) &=& n &&
(\iff |S.\SMEMS[a].\MIDATA| = n \cdot 64\,\F{Ki}) \\
\end{array}
.. _embed-mem-grow:
:math:`\F{mem\_grow}(\store, \memaddr, n:\u32) : \store ~|~ \error`
...................................................................
1. 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{mem\_grow}(S, a, n) &=& S' &&
(\iff S' = S \with \SMEMS[a] = \growmem(S.\SMEMS[a], n)) \\
\F{mem\_grow}(S, a, n) &=& \ERROR && (\otherwise) \\
\end{array}
.. index:: global, global address, store, global instance, global type, value
.. _embed-global:
Globals
~~~~~~~
.. _embed-global-alloc:
:math:`\F{global\_alloc}(\store, \globaltype, \val) : (\store, \globaladdr)`
............................................................................
1. Pre-condition: :math:`\globaltype` is :math:`valid <valid-globaltype>`.
2. 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`.
3. Return the new store paired with :math:`\globaladdr`.
.. math::
\begin{array}{lclll}
\F{global\_alloc}(S, \X{gt}, v) &=& (S', \X{a}) && (\iff \allocglobal(S, \X{gt}, v) = S', \X{a}) \\
\end{array}
.. _embed-global-type:
:math:`\F{global\_type}(\store, \globaladdr) : \globaltype`
...........................................................
1. Assert: the :ref:`external value <syntax-externval>` :math:`\EVGLOBAL~\globaladdr` is :ref:`valid <valid-externval>` with :ref:`external type <syntax-externtype>` :math:`\ETGLOBAL~\globaltype`.
2. Return :math:`\globaltype`.
3. Post-condition: :math:`\globaltype` is :math:`valid <valid-globaltype>`.
.. math::
\begin{array}{lclll}
\F{global\_type}(S, a) &=& \X{gt} && (\iff S \vdashexternval \EVGLOBAL~a : \ETGLOBAL~\X{gt}) \\
\end{array}
.. _embed-global-read:
:math:`\F{global\_read}(\store, \globaladdr) : \val`
....................................................
1. Let :math:`\X{gi}` be the :ref:`global instance <syntax-globalinst>` :math:`\store.\SGLOBALS[\globaladdr]`.
2. Return the :ref:`value <syntax-val>` :math:`\X{gi}.\GIVALUE`.
.. math::
\begin{array}{lclll}
\F{global\_read}(S, a) &=& v && (\iff S.\SGLOBALS[a].\GIVALUE = v) \\
\end{array}
.. _embed-global-write:
:math:`\F{global\_write}(\store, \globaladdr, \val) : \store ~|~ \error`
........................................................................
1. Let :math:`\X{gi}` be the :ref:`global instance <syntax-globalinst>` :math:`\store.\SGLOBALS[\globaladdr]`.
2. If :math:`\X{gi}.\GIMUT` is not :math:`\MVAR`, then return :math:`\ERROR`.
3. Replace :math:`\X{gi}.\GIVALUE` with the :ref:`value <syntax-val>` :math:`\val`.
4. Return the updated store.
.. math::
~ \\
\begin{array}{lclll}
\F{global\_write}(S, a, v) &=& S' && (\iff S.\SGLOBALS[a].\GIMUT = \MVAR \wedge S' = S \with \SGLOBALS[a].\GIVALUE = v) \\
\F{global\_write}(S, a, v) &=& \ERROR && (\otherwise) \\
\end{array}