| .. index:: instruction, function type, context, value, operand stack, ! polymorphism | |
| .. _valid-instr: | |
| Instructions | |
| ------------ | |
| :ref:`Instructions <syntax-instr>` are classified by :ref:`function types <syntax-functype>` :math:`[t_1^\ast] \to [t_2^\ast]` | |
| that describe how they manipulate the :ref:`operand stack <stack>`. | |
| The types describe the required input stack with argument values of types :math:`t_1^\ast` that an instruction pops off | |
| and the provided output stack with result values of types :math:`t_2^\ast` that it pushes back. | |
| .. note:: | |
| For example, the instruction :math:`\I32.\ADD` has type :math:`[\I32~\I32] \to [\I32]`, | |
| consuming two |I32| values and producing one. | |
| Typing extends to :ref:`instruction sequences <valid-instr-seq>` :math:`\instr^\ast`. | |
| Such a sequence has a :ref:`function type <syntax-functype>` :math:`[t_1^\ast] \to [t_2^\ast]` if the accumulative effect of executing the instructions is consuming values of types :math:`t_1^\ast` off the operand stack and pushing new values of types :math:`t_2^\ast`. | |
| .. _polymorphism: | |
| For some instructions, the typing rules do not fully constrain the type, | |
| and therefore allow for multiple types. | |
| Such instructions are called *polymorphic*. | |
| Two degrees of polymorphism can be distinguished: | |
| * *value-polymorphic*: | |
| the :ref:`value type <syntax-valtype>` :math:`t` of one or several individual operands is unconstrained. | |
| That is the case for all :ref:`parametric instructions <valid-instr-parametric>` like |DROP| and |SELECT|. | |
| * *stack-polymorphic*: | |
| the entire (or most of the) :ref:`function type <syntax-functype>` :math:`[t_1^\ast] \to [t_2^\ast]` of the instruction is unconstrained. | |
| That is the case for all :ref:`control instructions <valid-instr-control>` that perform an *unconditional control transfer*, such as |UNREACHABLE|, |BR|, |BRTABLE|, and |RETURN|. | |
| In both cases, the unconstrained types or type sequences can be chosen arbitrarily, as long as they meet the constraints imposed for the surrounding parts of the program. | |
| .. note:: | |
| For example, the |SELECT| instruction is valid with type :math:`[t~t~\I32] \to [t]`, for any possible :ref:`value type <syntax-valtype>` :math:`t`. Consequently, both instruction sequences | |
| .. math:: | |
| (\I32.\CONST~1)~~(\I32.\CONST~2)~~(\I32.\CONST~3)~~\SELECT{} | |
| and | |
| .. math:: | |
| (\F64.\CONST~1.0)~~(\F64.\CONST~2.0)~~(\I32.\CONST~3)~~\SELECT{} | |
| are valid, with :math:`t` in the typing of |SELECT| being instantiated to |I32| or |F64|, respectively. | |
| The |UNREACHABLE| instruction is valid with type :math:`[t_1^\ast] \to [t_2^\ast]` for any possible sequences of value types :math:`t_1^\ast` and :math:`t_2^\ast`. | |
| Consequently, | |
| .. math:: | |
| \UNREACHABLE~~\I32.\ADD | |
| is valid by assuming type :math:`[] \to [\I32~\I32]` for the |UNREACHABLE| instruction. | |
| In contrast, | |
| .. math:: | |
| \UNREACHABLE~~(\I64.\CONST~0)~~\I32.\ADD | |
| is invalid, because there is no possible type to pick for the |UNREACHABLE| instruction that would make the sequence well-typed. | |
| .. index:: numeric instruction | |
| pair: validation; instruction | |
| single: abstract syntax; instruction | |
| .. _valid-instr-numeric: | |
| Numeric Instructions | |
| ~~~~~~~~~~~~~~~~~~~~ | |
| .. _valid-const: | |
| :math:`t\K{.}\CONST~c` | |
| ...................... | |
| * The instruction is valid with type :math:`[] \to [t]`. | |
| .. math:: | |
| \frac{ | |
| }{ | |
| C \vdashinstr t\K{.}\CONST~c : [] \to [t] | |
| } | |
| .. _valid-unop: | |
| :math:`t\K{.}\unop` | |
| ................... | |
| * The instruction is valid with type :math:`[t] \to [t]`. | |
| .. math:: | |
| \frac{ | |
| }{ | |
| C \vdashinstr t\K{.}\unop : [t] \to [t] | |
| } | |
| .. _valid-binop: | |
| :math:`t\K{.}\binop` | |
| .................... | |
| * The instruction is valid with type :math:`[t~t] \to [t]`. | |
| .. math:: | |
| \frac{ | |
| }{ | |
| C \vdashinstr t\K{.}\binop : [t~t] \to [t] | |
| } | |
| .. _valid-testop: | |
| :math:`t\K{.}\testop` | |
| ..................... | |
| * The instruction is valid with type :math:`[t] \to [\I32]`. | |
| .. math:: | |
| \frac{ | |
| }{ | |
| C \vdashinstr t\K{.}\testop : [t] \to [\I32] | |
| } | |
| .. _valid-relop: | |
| :math:`t\K{.}\relop` | |
| .................... | |
| * The instruction is valid with type :math:`[t~t] \to [\I32]`. | |
| .. math:: | |
| \frac{ | |
| }{ | |
| C \vdashinstr t\K{.}\relop : [t~t] \to [\I32] | |
| } | |
| .. _valid-cvtop: | |
| :math:`t_2\K{.}\cvtop\K{\_}t_1\K{\_}\sx^?` | |
| .......................................... | |
| * The instruction is valid with type :math:`[t_1] \to [t_2]`. | |
| .. math:: | |
| \frac{ | |
| }{ | |
| C \vdashinstr t_2\K{.}\cvtop\K{\_}t_1\K{\_}\sx^? : [t_1] \to [t_2] | |
| } | |
| .. index:: parametric instructions, value type, polymorphism | |
| pair: validation; instruction | |
| single: abstract syntax; instruction | |
| .. _valid-instr-parametric: | |
| Parametric Instructions | |
| ~~~~~~~~~~~~~~~~~~~~~~~ | |
| .. _valid-drop: | |
| :math:`\DROP` | |
| ............. | |
| * The instruction is valid with type :math:`[t] \to []`, for any :ref:`value type <syntax-valtype>` :math:`t`. | |
| .. math:: | |
| \frac{ | |
| }{ | |
| C \vdashinstr \DROP : [t] \to [] | |
| } | |
| .. _valid-select: | |
| :math:`\SELECT` | |
| ............... | |
| * The instruction is valid with type :math:`[t~t~\I32] \to [t]`, for any :ref:`value type <syntax-valtype>` :math:`t`. | |
| .. math:: | |
| \frac{ | |
| }{ | |
| C \vdashinstr \SELECT : [t~t~\I32] \to [t] | |
| } | |
| .. note:: | |
| Both |DROP| and |SELECT| are :ref:`value-polymorphic <polymorphism>` instructions. | |
| .. index:: variable instructions, local index, global index, context | |
| pair: validation; instruction | |
| single: abstract syntax; instruction | |
| .. _valid-instr-variable: | |
| Variable Instructions | |
| ~~~~~~~~~~~~~~~~~~~~~ | |
| .. _valid-local.get: | |
| :math:`\LOCALGET~x` | |
| ................... | |
| * The local :math:`C.\CLOCALS[x]` must be defined in the context. | |
| * Let :math:`t` be the :ref:`value type <syntax-valtype>` :math:`C.\CLOCALS[x]`. | |
| * Then the instruction is valid with type :math:`[] \to [t]`. | |
| .. math:: | |
| \frac{ | |
| C.\CLOCALS[x] = t | |
| }{ | |
| C \vdashinstr \LOCALGET~x : [] \to [t] | |
| } | |
| .. _valid-local.set: | |
| :math:`\LOCALSET~x` | |
| ................... | |
| * The local :math:`C.\CLOCALS[x]` must be defined in the context. | |
| * Let :math:`t` be the :ref:`value type <syntax-valtype>` :math:`C.\CLOCALS[x]`. | |
| * Then the instruction is valid with type :math:`[t] \to []`. | |
| .. math:: | |
| \frac{ | |
| C.\CLOCALS[x] = t | |
| }{ | |
| C \vdashinstr \LOCALSET~x : [t] \to [] | |
| } | |
| .. _valid-local.tee: | |
| :math:`\LOCALTEE~x` | |
| ................... | |
| * The local :math:`C.\CLOCALS[x]` must be defined in the context. | |
| * Let :math:`t` be the :ref:`value type <syntax-valtype>` :math:`C.\CLOCALS[x]`. | |
| * Then the instruction is valid with type :math:`[t] \to [t]`. | |
| .. math:: | |
| \frac{ | |
| C.\CLOCALS[x] = t | |
| }{ | |
| C \vdashinstr \LOCALTEE~x : [t] \to [t] | |
| } | |
| .. _valid-global.get: | |
| :math:`\GLOBALGET~x` | |
| .................... | |
| * The global :math:`C.\CGLOBALS[x]` must be defined in the context. | |
| * Let :math:`\mut~t` be the :ref:`global type <syntax-globaltype>` :math:`C.\CGLOBALS[x]`. | |
| * Then the instruction is valid with type :math:`[] \to [t]`. | |
| .. math:: | |
| \frac{ | |
| C.\CGLOBALS[x] = \mut~t | |
| }{ | |
| C \vdashinstr \GLOBALGET~x : [] \to [t] | |
| } | |
| .. _valid-global.set: | |
| :math:`\GLOBALSET~x` | |
| .................... | |
| * The global :math:`C.\CGLOBALS[x]` must be defined in the context. | |
| * Let :math:`\mut~t` be the :ref:`global type <syntax-globaltype>` :math:`C.\CGLOBALS[x]`. | |
| * The mutability :math:`\mut` must be |MVAR|. | |
| * Then the instruction is valid with type :math:`[t] \to []`. | |
| .. math:: | |
| \frac{ | |
| C.\CGLOBALS[x] = \MVAR~t | |
| }{ | |
| C \vdashinstr \GLOBALSET~x : [t] \to [] | |
| } | |
| .. index:: memory instruction, memory index, context | |
| pair: validation; instruction | |
| single: abstract syntax; instruction | |
| .. _valid-memarg: | |
| .. _valid-instr-memory: | |
| Memory Instructions | |
| ~~~~~~~~~~~~~~~~~~~ | |
| .. _valid-load: | |
| :math:`t\K{.}\LOAD~\memarg` | |
| ........................... | |
| * The memory :math:`C.\CMEMS[0]` must be defined in the context. | |
| * The alignment :math:`2^{\memarg.\ALIGN}` must not be larger than the :ref:`bit width <syntax-valtype>` of :math:`t` divided by :math:`8`. | |
| * Then the instruction is valid with type :math:`[\I32] \to [t]`. | |
| .. math:: | |
| \frac{ | |
| C.\CMEMS[0] = \memtype | |
| \qquad | |
| 2^{\memarg.\ALIGN} \leq |t|/8 | |
| }{ | |
| C \vdashinstr t\K{.load}~\memarg : [\I32] \to [t] | |
| } | |
| .. _valid-loadn: | |
| :math:`t\K{.}\LOAD{N}\K{\_}\sx~\memarg` | |
| ....................................... | |
| * The memory :math:`C.\CMEMS[0]` must be defined in the context. | |
| * The alignment :math:`2^{\memarg.\ALIGN}` must not be larger than :math:`N/8`. | |
| * Then the instruction is valid with type :math:`[\I32] \to [t]`. | |
| .. math:: | |
| \frac{ | |
| C.\CMEMS[0] = \memtype | |
| \qquad | |
| 2^{\memarg.\ALIGN} \leq N/8 | |
| }{ | |
| C \vdashinstr t\K{.load}N\K{\_}\sx~\memarg : [\I32] \to [t] | |
| } | |
| :math:`t\K{.}\STORE~\memarg` | |
| ............................ | |
| * The memory :math:`C.\CMEMS[0]` must be defined in the context. | |
| * The alignment :math:`2^{\memarg.\ALIGN}` must not be larger than the :ref:`bit width <syntax-valtype>` of :math:`t` divided by :math:`8`. | |
| * Then the instruction is valid with type :math:`[\I32~t] \to []`. | |
| .. math:: | |
| \frac{ | |
| C.\CMEMS[0] = \memtype | |
| \qquad | |
| 2^{\memarg.\ALIGN} \leq |t|/8 | |
| }{ | |
| C \vdashinstr t\K{.store}~\memarg : [\I32~t] \to [] | |
| } | |
| .. _valid-storen: | |
| :math:`t\K{.}\STORE{N}~\memarg` | |
| ............................... | |
| * The memory :math:`C.\CMEMS[0]` must be defined in the context. | |
| * The alignment :math:`2^{\memarg.\ALIGN}` must not be larger than :math:`N/8`. | |
| * Then the instruction is valid with type :math:`[\I32~t] \to []`. | |
| .. math:: | |
| \frac{ | |
| C.\CMEMS[0] = \memtype | |
| \qquad | |
| 2^{\memarg.\ALIGN} \leq N/8 | |
| }{ | |
| C \vdashinstr t\K{.store}N~\memarg : [\I32~t] \to [] | |
| } | |
| .. _valid-memory.size: | |
| :math:`\MEMORYSIZE` | |
| ................... | |
| * The memory :math:`C.\CMEMS[0]` must be defined in the context. | |
| * Then the instruction is valid with type :math:`[] \to [\I32]`. | |
| .. math:: | |
| \frac{ | |
| C.\CMEMS[0] = \memtype | |
| }{ | |
| C \vdashinstr \MEMORYSIZE : [] \to [\I32] | |
| } | |
| .. _valid-memory.grow: | |
| :math:`\MEMORYGROW` | |
| ................... | |
| * The memory :math:`C.\CMEMS[0]` must be defined in the context. | |
| * Then the instruction is valid with type :math:`[\I32] \to [\I32]`. | |
| .. math:: | |
| \frac{ | |
| C.\CMEMS[0] = \memtype | |
| }{ | |
| C \vdashinstr \MEMORYGROW : [\I32] \to [\I32] | |
| } | |
| .. index:: control instructions, structured control, label, block, branch, result type, label index, function index, type index, vector, polymorphism, context | |
| pair: validation; instruction | |
| single: abstract syntax; instruction | |
| .. _valid-label: | |
| .. _valid-instr-control: | |
| Control Instructions | |
| ~~~~~~~~~~~~~~~~~~~~ | |
| .. _valid-nop: | |
| :math:`\NOP` | |
| ............ | |
| * The instruction is valid with type :math:`[] \to []`. | |
| .. math:: | |
| \frac{ | |
| }{ | |
| C \vdashinstr \NOP : [] \to [] | |
| } | |
| .. _valid-unreachable: | |
| :math:`\UNREACHABLE` | |
| .................... | |
| * The instruction is valid with type :math:`[t_1^\ast] \to [t_2^\ast]`, for any sequences of :ref:`value types <syntax-valtype>` :math:`t_1^\ast` and :math:`t_2^\ast`. | |
| .. math:: | |
| \frac{ | |
| }{ | |
| C \vdashinstr \UNREACHABLE : [t_1^\ast] \to [t_2^\ast] | |
| } | |
| .. note:: | |
| The |UNREACHABLE| instruction is :ref:`stack-polymorphic <polymorphism>`. | |
| .. _valid-block: | |
| :math:`\BLOCK~[t^?]~\instr^\ast~\END` | |
| ..................................... | |
| * Let :math:`C'` be the same :ref:`context <context>` as :math:`C`, but with the :ref:`result type <syntax-resulttype>` :math:`[t^?]` prepended to the |CLABELS| vector. | |
| * Under context :math:`C'`, | |
| the instruction sequence :math:`\instr^\ast` must be :ref:`valid <valid-instr-seq>` with type :math:`[] \to [t^?]`. | |
| * Then the compound instruction is valid with type :math:`[] \to [t^?]`. | |
| .. math:: | |
| \frac{ | |
| C,\CLABELS\,[t^?] \vdashinstrseq \instr^\ast : [] \to [t^?] | |
| }{ | |
| C \vdashinstr \BLOCK~[t^?]~\instr^\ast~\END : [] \to [t^?] | |
| } | |
| .. note:: | |
| The :ref:`notation <notation-extend>` :math:`C,\CLABELS\,[t^?]` inserts the new label type at index :math:`0`, shifting all others. | |
| The fact that the nested instruction sequence :math:`\instr^\ast` must have type :math:`[] \to [t^?]` implies that it cannot access operands that have been pushed on the stack before the block was entered. | |
| This may be generalized in future versions of WebAssembly. | |
| .. _valid-loop: | |
| :math:`\LOOP~[t^?]~\instr^\ast~\END` | |
| .................................... | |
| * Let :math:`C'` be the same :ref:`context <context>` as :math:`C`, but with the empty :ref:`result type <syntax-resulttype>` :math:`[]` prepended to the |CLABELS| vector. | |
| * Under context :math:`C'`, | |
| the instruction sequence :math:`\instr^\ast` must be :ref:`valid <valid-instr-seq>` with type :math:`[] \to [t^?]`. | |
| * Then the compound instruction is valid with type :math:`[] \to [t^?]`. | |
| .. math:: | |
| \frac{ | |
| C,\CLABELS\,[] \vdashinstrseq \instr^\ast : [] \to [t^?] | |
| }{ | |
| C \vdashinstr \LOOP~[t^?]~\instr^\ast~\END : [] \to [t^?] | |
| } | |
| .. note:: | |
| The :ref:`notation <notation-extend>` :math:`C,\CLABELS\,[]` inserts the new label type at index :math:`0`, shifting all others. | |
| The fact that the nested instruction sequence :math:`\instr^\ast` must have type :math:`[] \to [t^?]` implies that it cannot access operands that have been pushed on the stack before the loop was entered. | |
| This may be generalized in future versions of WebAssembly. | |
| .. _valid-if: | |
| :math:`\IF~[t^?]~\instr_1^\ast~\ELSE~\instr_2^\ast~\END` | |
| ........................................................ | |
| * Let :math:`C'` be the same :ref:`context <context>` as :math:`C`, but with the :ref:`result type <syntax-resulttype>` :math:`[t^?]` prepended to the |CLABELS| vector. | |
| * Under context :math:`C'`, | |
| the instruction sequence :math:`\instr_1^\ast` must be :ref:`valid <valid-instr-seq>` with type :math:`[] \to [t^?]`. | |
| * Under context :math:`C'`, | |
| the instruction sequence :math:`\instr_2^\ast` must be :ref:`valid <valid-instr-seq>` with type :math:`[] \to [t^?]`. | |
| * Then the compound instruction is valid with type :math:`[\I32] \to [t^?]`. | |
| .. math:: | |
| \frac{ | |
| C,\CLABELS\,[t^?] \vdashinstrseq \instr_1^\ast : [] \to [t^?] | |
| \qquad | |
| C,\CLABELS\,[t^?] \vdashinstrseq \instr_2^\ast : [] \to [t^?] | |
| }{ | |
| C \vdashinstr \IF~[t^?]~\instr_1^\ast~\ELSE~\instr_2^\ast~\END : [\I32] \to [t^?] | |
| } | |
| .. note:: | |
| The :ref:`notation <notation-extend>` :math:`C,\CLABELS\,[t^?]` inserts the new label type at index :math:`0`, shifting all others. | |
| The fact that the nested instruction sequence :math:`\instr^\ast` must have type :math:`[] \to [t^?]` implies that it cannot access operands that have been pushed on the stack before the conditional was entered. | |
| This may be generalized in future versions of WebAssembly. | |
| .. _valid-br: | |
| :math:`\BR~l` | |
| ............. | |
| * The label :math:`C.\CLABELS[l]` must be defined in the context. | |
| * Let :math:`[t^?]` be the :ref:`result type <syntax-resulttype>` :math:`C.\CLABELS[l]`. | |
| * Then the instruction is valid with type :math:`[t_1^\ast~t^?] \to [t_2^\ast]`, for any sequences of :ref:`value types <syntax-valtype>` :math:`t_1^\ast` and :math:`t_2^\ast`. | |
| .. math:: | |
| \frac{ | |
| C.\CLABELS[l] = [t^?] | |
| }{ | |
| C \vdashinstr \BR~l : [t_1^\ast~t^?] \to [t_2^\ast] | |
| } | |
| .. note:: | |
| The :ref:`label index <syntax-labelidx>` space in the :ref:`context <context>` :math:`C` contains the most recent label first, so that :math:`C.\CLABELS[l]` performs a relative lookup as expected. | |
| The |BR| instruction is :ref:`stack-polymorphic <polymorphism>`. | |
| .. _valid-br_if: | |
| :math:`\BRIF~l` | |
| ............... | |
| * The label :math:`C.\CLABELS[l]` must be defined in the context. | |
| * Let :math:`[t^?]` be the :ref:`result type <syntax-resulttype>` :math:`C.\CLABELS[l]`. | |
| * Then the instruction is valid with type :math:`[t^?~\I32] \to [t^?]`. | |
| .. math:: | |
| \frac{ | |
| C.\CLABELS[l] = [t^?] | |
| }{ | |
| C \vdashinstr \BRIF~l : [t^?~\I32] \to [t^?] | |
| } | |
| .. note:: | |
| The :ref:`label index <syntax-labelidx>` space in the :ref:`context <context>` :math:`C` contains the most recent label first, so that :math:`C.\CLABELS[l]` performs a relative lookup as expected. | |
| .. _valid-br_table: | |
| :math:`\BRTABLE~l^\ast~l_N` | |
| ........................... | |
| * The label :math:`C.\CLABELS[l_N]` must be defined in the context. | |
| * Let :math:`[t^?]` be the :ref:`result type <syntax-resulttype>` :math:`C.\CLABELS[l_N]`. | |
| * For all :math:`l_i` in :math:`l^\ast`, | |
| the label :math:`C.\CLABELS[l_i]` must be defined in the context. | |
| * For all :math:`l_i` in :math:`l^\ast`, | |
| :math:`C.\CLABELS[l_i]` must be :math:`[t^?]`. | |
| * Then the instruction is valid with type :math:`[t_1^\ast~t^?~\I32] \to [t_2^\ast]`, for any sequences of :ref:`value types <syntax-valtype>` :math:`t_1^\ast` and :math:`t_2^\ast`. | |
| .. math:: | |
| \frac{ | |
| (C.\CLABELS[l] = [t^?])^\ast | |
| \qquad | |
| C.\CLABELS[l_N] = [t^?] | |
| }{ | |
| C \vdashinstr \BRTABLE~l^\ast~l_N : [t_1^\ast~t^?~\I32] \to [t_2^\ast] | |
| } | |
| .. note:: | |
| The :ref:`label index <syntax-labelidx>` space in the :ref:`context <context>` :math:`C` contains the most recent label first, so that :math:`C.\CLABELS[l_i]` performs a relative lookup as expected. | |
| The |BRTABLE| instruction is :ref:`stack-polymorphic <polymorphism>`. | |
| .. _valid-return: | |
| :math:`\RETURN` | |
| ............... | |
| * The return type :math:`C.\CRETURN` must not be absent in the context. | |
| * Let :math:`[t^?]` be the :ref:`result type <syntax-resulttype>` of :math:`C.\CRETURN`. | |
| * Then the instruction is valid with type :math:`[t_1^\ast~t^?] \to [t_2^\ast]`, for any sequences of :ref:`value types <syntax-valtype>` :math:`t_1^\ast` and :math:`t_2^\ast`. | |
| .. math:: | |
| \frac{ | |
| C.\CRETURN = [t^?] | |
| }{ | |
| C \vdashinstr \RETURN : [t_1^\ast~t^?] \to [t_2^\ast] | |
| } | |
| .. note:: | |
| The |RETURN| instruction is :ref:`stack-polymorphic <polymorphism>`. | |
| :math:`C.\CRETURN` is absent (set to :math:`\epsilon`) when validating an :ref:`expression <valid-expr>` that is not a function body. | |
| This differs from it being set to the empty result type (:math:`[\epsilon]`), | |
| which is the case for functions not returning anything. | |
| .. _valid-call: | |
| :math:`\CALL~x` | |
| ............... | |
| * The function :math:`C.\CFUNCS[x]` must be defined in the context. | |
| * Then the instruction is valid with type :math:`C.\CFUNCS[x]`. | |
| .. math:: | |
| \frac{ | |
| C.\CFUNCS[x] = [t_1^\ast] \to [t_2^\ast] | |
| }{ | |
| C \vdashinstr \CALL~x : [t_1^\ast] \to [t_2^\ast] | |
| } | |
| .. _valid-call_indirect: | |
| :math:`\CALLINDIRECT~x` | |
| ....................... | |
| * The table :math:`C.\CTABLES[0]` must be defined in the context. | |
| * Let :math:`\limits~\elemtype` be the :ref:`table type <syntax-tabletype>` :math:`C.\CTABLES[0]`. | |
| * The :ref:`element type <syntax-elemtype>` :math:`\elemtype` must be |FUNCREF|. | |
| * The type :math:`C.\CTYPES[x]` must be defined in the context. | |
| * Let :math:`[t_1^\ast] \to [t_2^\ast]` be the :ref:`function type <syntax-functype>` :math:`C.\CTYPES[x]`. | |
| * Then the instruction is valid with type :math:`[t_1^\ast~\I32] \to [t_2^\ast]`. | |
| .. math:: | |
| \frac{ | |
| C.\CTABLES[0] = \limits~\FUNCREF | |
| \qquad | |
| C.\CTYPES[x] = [t_1^\ast] \to [t_2^\ast] | |
| }{ | |
| C \vdashinstr \CALLINDIRECT~x : [t_1^\ast~\I32] \to [t_2^\ast] | |
| } | |
| .. index:: instruction, instruction sequence | |
| .. _valid-instr-seq: | |
| Instruction Sequences | |
| ~~~~~~~~~~~~~~~~~~~~~ | |
| Typing of instruction sequences is defined recursively. | |
| Empty Instruction Sequence: :math:`\epsilon` | |
| ............................................ | |
| * The empty instruction sequence is valid with type :math:`[t^\ast] \to [t^\ast]`, | |
| for any sequence of :ref:`value types <syntax-valtype>` :math:`t^\ast`. | |
| .. math:: | |
| \frac{ | |
| }{ | |
| C \vdashinstrseq \epsilon : [t^\ast] \to [t^\ast] | |
| } | |
| Non-empty Instruction Sequence: :math:`\instr^\ast~\instr_N` | |
| ............................................................ | |
| * The instruction sequence :math:`\instr^\ast` must be valid with type :math:`[t_1^\ast] \to [t_2^\ast]`, | |
| for some sequences of :ref:`value types <syntax-valtype>` :math:`t_1^\ast` and :math:`t_2^\ast`. | |
| * The instruction :math:`\instr_N` must be valid with type :math:`[t^\ast] \to [t_3^\ast]`, | |
| for some sequences of :ref:`value types <syntax-valtype>` :math:`t^\ast` and :math:`t_3^\ast`. | |
| * There must be a sequence of :ref:`value types <syntax-valtype>` :math:`t_0^\ast`, | |
| such that :math:`t_2^\ast = t_0^\ast~t^\ast`. | |
| * Then the combined instruction sequence is valid with type :math:`[t_1^\ast] \to [t_0^\ast~t_3^\ast]`. | |
| .. math:: | |
| \frac{ | |
| C \vdashinstrseq \instr^\ast : [t_1^\ast] \to [t_0^\ast~t^\ast] | |
| \qquad | |
| C \vdashinstr \instr_N : [t^\ast] \to [t_3^\ast] | |
| }{ | |
| C \vdashinstrseq \instr^\ast~\instr_N : [t_1^\ast] \to [t_0^\ast~t_3^\ast] | |
| } | |
| .. index:: expression | |
| pair: validation; expression | |
| single: abstract syntax; expression | |
| single: expression; constant | |
| .. _valid-expr: | |
| Expressions | |
| ~~~~~~~~~~~ | |
| Expressions :math:`\expr` are classified by :ref:`result types <syntax-resulttype>` of the form :math:`[t^?]`. | |
| :math:`\instr^\ast~\END` | |
| ........................ | |
| * The instruction sequence :math:`\instr^\ast` must be :ref:`valid <valid-instr-seq>` with type :math:`[] \to [t^?]`, | |
| for some optional :ref:`value type <syntax-valtype>` :math:`t^?`. | |
| * Then the expression is valid with :ref:`result type <syntax-resulttype>` :math:`[t^?]`. | |
| .. math:: | |
| \frac{ | |
| C \vdashinstrseq \instr^\ast : [] \to [t^?] | |
| }{ | |
| C \vdashexpr \instr^\ast~\END : [t^?] | |
| } | |
| .. index:: ! constant | |
| .. _valid-constant: | |
| Constant Expressions | |
| .................... | |
| * In a *constant* expression :math:`\instr^\ast~\END` all instructions in :math:`\instr^\ast` must be constant. | |
| * A constant instruction :math:`\instr` must be: | |
| * either of the form :math:`t.\CONST~c`, | |
| * or of the form :math:`\GLOBALGET~x`, in which case :math:`C.\CGLOBALS[x]` must be a :ref:`global type <syntax-globaltype>` of the form :math:`\CONST~t`. | |
| .. math:: | |
| \frac{ | |
| (C \vdashinstrconst \instr \const)^\ast | |
| }{ | |
| C \vdashexprconst \instr^\ast~\END \const | |
| } | |
| .. math:: | |
| \frac{ | |
| }{ | |
| C \vdashinstrconst t.\CONST~c \const | |
| } | |
| \qquad | |
| \frac{ | |
| C.\CGLOBALS[x] = \CONST~t | |
| }{ | |
| C \vdashinstrconst \GLOBALGET~x \const | |
| } | |
| .. note:: | |
| Currently, constant expressions occurring as initializers of :ref:`globals <syntax-global>` are further constrained in that contained |GLOBALGET| instructions are only allowed to refer to *imported* globals. | |
| This is enforced in the :ref:`validation rule for modules <valid-module>` by constraining the context :math:`C` accordingly. | |
| The definition of constant expression may be extended in future versions of WebAssembly. |