You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Validation requires a :ref:`context <context>` for checking uses of :ref:`indices <syntax-index>`.
83
+
For the purpose of presenting the algorithm, it is maintained in a set of global variables:
84
+
85
+
.. code-block:: pseudo
86
+
87
+
var locals : array(val_type)
88
+
var locals_init : array(bool)
89
+
var globals : array(global_type)
90
+
var funcs : array(func_type)
91
+
var tables : array(table_type)
92
+
var mems : array(mem_type)
93
+
94
+
This assumes suitable representations for the various :ref:`types <syntax-type>` besides :code:`val_type`, which are omitted here.
95
+
96
+
For locals, there is an additional array recording the initialization status of each local.
97
+
98
+
Stacks
99
+
......
72
100
73
-
The algorithm uses two separate stacks: the *value stack* and the *control stack*.
74
-
The former tracks the :ref:`types <syntax-valtype>` of operand values on the :ref:`stack <stack>`,
75
-
the latter surrounding :ref:`structured control instructions <syntax-instr-control>` and their associated :ref:`blocks <syntax-instr-control>`.
101
+
The algorithm uses three separate stacks: the *value stack*, the *control stack*, and the *initialization stack*.
102
+
The value stack tracks the :ref:`types <syntax-valtype>` of operand values on the :ref:`stack <stack>`.
103
+
The control stack tracks surrounding :ref:`structured control instructions <syntax-instr-control>` and their associated :ref:`blocks <syntax-instr-control>`.
104
+
The initialization stack records all :ref:`locals <syntax-local>` that have been initialized since the beginning of the function.
76
105
77
106
.. code-block:: pseudo
78
107
79
108
type val_stack = stack(val_type)
109
+
type init_stack = stack(u32)
80
110
81
111
type ctrl_stack = stack(ctrl_frame)
82
112
type ctrl_frame = {
83
113
opcode : opcode
84
114
start_types : list(val_type)
85
115
end_types : list(val_type)
86
-
height : nat
116
+
val_height : nat
117
+
init_height : nat
87
118
unreachable : bool
88
119
}
89
120
90
-
For each value, the value stack records its :ref:`value type <syntax-valtype>`.
91
-
For each entered block, the control stack records a *control frame* with the originating opcode, the types on the top of the operand stack at the start and end of the block (used to check its result as well as branches), the height of the operand stack at the start of the block (used to check that operands do not underflow the current block), and a flag recording whether the remainder of the block is unreachable (used to handle :ref:`stack-polymorphic <polymorphism>` typing after branches).
121
+
For each entered block, the control stack records a *control frame* with the originating opcode, the types on the top of the operand stack at the start and end of the block (used to check its result as well as branches), the height of the operand stack at the start of the block (used to check that operands do not underflow the current block), the height of the initialization stack at the start of the block (used to reset initialization status at the end of the block), and a flag recording whether the remainder of the block is unreachable (used to handle :ref:`stack-polymorphic <polymorphism>` typing after branches).
92
122
93
-
For the purpose of presenting the algorithm, the operand and control stacks are simply maintained as global variables:
123
+
For the purpose of presenting the algorithm, these stacks are simply maintained as global variables:
94
124
95
125
.. code-block:: pseudo
96
126
97
127
var vals : val_stack
128
+
var inits : init_stack
98
129
var ctrls : ctrl_stack
99
130
100
131
However, these variables are not manipulated directly by the main checking function, but through a set of auxiliary functions:
@@ -122,7 +153,7 @@ However, these variables are not manipulated directly by the main checking funct
122
153
func pop_ref() : ref_type =
123
154
let actual = pop_val()
124
155
error_if(not is_ref(actual))
125
-
if actual = Bot then return Ref(Bot, false)
156
+
if (actual = Bot) return Ref(Bot, false)
126
157
return actual
127
158
128
159
func push_vals(types : list(val_type)) = foreach (t in types) push_val(t)
@@ -149,25 +180,49 @@ Finally, there are accumulative functions for pushing or popping multiple operan
149
180
so that, e.g., :code:`ctrls[0]` accesses the element pushed last.
150
181
151
182
183
+
The initialization stack and the initialization status of locals is manipulated through the following functions:
184
+
185
+
.. code-block:: pseudo
186
+
187
+
func get_local(idx : u32) =
188
+
error_if(not locals_init[idx])
189
+
190
+
func set_local(idx : u32) =
191
+
if (not locals_init[idx])
192
+
inits.push(idx)
193
+
locals_init[idx] := true
194
+
195
+
func reset_locals(height : nat) =
196
+
while (inits.size() > height)
197
+
locals_init[inits.pop()] := false
198
+
199
+
Getting a local verifies that it is known to be initialized.
200
+
When a local is set that was not set already,
201
+
then its initialization status is updated and the change is recorded in the initialization stack.
202
+
Thus, the initialization status of all locals can be reset to a previous state by denoting a specific height in the initialization stack.
203
+
204
+
The size of the initialization stack is bounded by the number of (non-defaultable) locals in a function, so can be preallocated by an algorithm.
205
+
152
206
The control stack is likewise manipulated through auxiliary functions:
153
207
154
208
.. code-block:: pseudo
155
209
156
210
func push_ctrl(opcode : opcode, in : list(val_type), out : list(val_type)) =
157
-
let frame = ctrl_frame(opcode, in, out, vals.size(), false)
211
+
let frame = ctrl_frame(opcode, in, out, vals.size(), inits.size(), false)
@@ -179,18 +234,22 @@ It allocates a new frame record recording them along with the current height of
179
234
Popping a frame first checks that the control stack is not empty.
180
235
It then verifies that the operand stack contains the right types of values expected at the end of the exited block and pops them off the operand stack.
181
236
Afterwards, it checks that the stack has shrunk back to its initial height.
237
+
Finally, it undoes all changes to the initialization status of locals that happend inside the block.
182
238
183
239
The type of the :ref:`label <syntax-label>` associated with a control frame is either that of the stack at the start or the end of the frame, determined by the opcode that it originates from.
184
240
185
241
Finally, the current frame can be marked as unreachable.
186
242
In that case, all existing operand types are purged from the value stack, in order to allow for the :ref:`stack-polymorphism <polymorphism>` logic in :code:`pop_val` to take effect.
243
+
Because every function has an implicit outermost label that corresponds to an implicit block frame,
244
+
it is an invariant of the validation algorithm that there always is at least one frame on the control stack when validating an instruction, and hence, `ctrls[0]` is always defined.
187
245
188
246
.. note::
189
247
Even with the unreachable flag set, consecutive operands are still pushed to and popped from the operand stack.
190
248
That is necessary to detect invalid :ref:`examples <polymorphism>` like :math:`(\UNREACHABLE~(\I32.\CONST)~\I64.\ADD)`.
191
249
However, a polymorphic stack cannot underflow, but instead generates :code:`Bot` types as needed.
192
250
193
251
252
+
194
253
.. index:: opcode
195
254
196
255
Validation of Opcode Sequences
@@ -199,10 +258,6 @@ Validation of Opcode Sequences
199
258
The following function shows the validation of a number of representative instructions that manipulate the stack.
200
259
Other instructions are checked in a similar manner.
201
260
202
-
.. note::
203
-
Various instructions not shown here will additionally require the presence of a validation :ref:`context <context>` for checking uses of :ref:`indices <syntax-index>`.
204
-
That is an easy addition and therefore omitted from this presentation.
205
-
206
261
.. code-block:: pseudo
207
262
208
263
func validate(opcode) =
@@ -221,7 +276,7 @@ Other instructions are checked in a similar manner.
Copy file name to clipboardExpand all lines: document/core/appendix/changes.rst
+31-1Lines changed: 31 additions & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -53,7 +53,7 @@ Added |FUNCREF| and |EXTERNREF| as new value types and respective instructions [
53
53
54
54
* New :ref:`reference instructions <syntax-instr-ref>`: |REFNULL|, |REFFUNC|, |REFISNULL|
55
55
56
-
* Enrich:ref:`parametric instruction <syntax-instr-parametric>`: |SELECT| with optional type immediate
56
+
* Extended:ref:`parametric instruction <syntax-instr-parametric>`: |SELECT| with optional type immediate
57
57
58
58
* New :ref:`declarative <syntax-elemmode>` form of :ref:`element segment <syntax-elem>`
59
59
@@ -138,6 +138,33 @@ Added vector type and instructions that manipulate multiple numeric values in pa
138
138
* New injection/projection :ref:`vector instructions <syntax-instr-vec>`: :math:`\K{i}\!N\!\K{x}\!M\!\K{.splat}`, :math:`\K{f}\!N\!\K{x}\!M\!\K{.splat}`, :math:`\K{i}\!N\!\K{x}\!M\!\K{.bitmask}`
139
139
140
140
141
+
Release 2.?
142
+
~~~~~~~~~~~
143
+
144
+
.. index:: reference, reference type, heap type, value type, local, local type, instruction, instruction type, table, function, function type, matching, subtyping
145
+
146
+
Typeful References
147
+
..................
148
+
149
+
Added more precise types for references [#proposal-typedref]_.
150
+
151
+
* New generalised form of :ref:`reference types <syntax-reftype>`: :math:`(\REF~\NULL^?~\heaptype)`
152
+
153
+
* New class of :ref:`heap types <syntax-heaptype>`: |FUNC|, |EXTERN|, :math:`\typeidx`
154
+
155
+
* Basic :ref:`subtyping <match>` on :ref:`reference <match-reftype>` and :ref:`value <match-valtype>` types
156
+
157
+
* New :ref:`reference instructions <syntax-instr-ref>`: |REFASNONNULL|, |BRONNULL|, |BRONNONNULL|
158
+
159
+
* New :ref:`control instruction <syntax-instr-control>`: |CALLREF|
160
+
161
+
* Refined typing of :ref:`reference instruction <syntax-instr-ref>` |REFFUNC| with more precise result type
162
+
163
+
* Refined typing of :ref:`local instructions <valid-instr-variable>` and :ref:`instruction sequences <valid-instr-seq>` to track the :ref:`initialization status <syntax-init>` of :ref:`locals <syntax-local>` with non-:ref:`defaultable <valid-defaultable>` type
164
+
165
+
* Extended :ref:`table definitions <syntax-table>` with optional initializer expression
0 commit comments