Skip to content

Commit d3a8b88

Browse files
committed
Merge multi-value proposal into spec
See the multi-value proposal here: https://github.com/WebAssembly/multi-value This PR is built on top of the following PRs: * #1143 (merge nontrapping-float-to-int) * #1144 (merge sign-extension-ops)
1 parent e308ca2 commit d3a8b88

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+2711
-655
lines changed

document/core/appendix/algorithm.rst

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -33,19 +33,16 @@ the latter surrounding :ref:`structured control instructions <syntax-instr-contr
3333
3434
type ctrl_stack = stack(ctrl_frame)
3535
type ctrl_frame = {
36-
label_types : list(val_type)
36+
opcode : opcode
37+
start_types : list(val_type)
3738
end_types : list(val_type)
3839
height : nat
3940
unreachable : bool
4041
}
4142
4243
For each value, the operand stack records its :ref:`value type <syntax-valtype>`, or :code:`Unknown` when the type is not known.
4344

44-
For each entered block, the control stack records a *control frame* with the type of the associated :ref:`label <syntax-label>` (used to type-check branches), the result type of the block (used to check its result), 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).
45-
46-
.. note::
47-
In the presentation of this algorithm, multiple values are supported for the :ref:`result types <syntax-resulttype>` classifying blocks and labels.
48-
With the current version of WebAssembly, the :code:`list` could be simplified to an optional value.
45+
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).
4946

5047
For the purpose of presenting the algorithm, the operand and control stacks are simply maintained as global variables:
5148

@@ -98,17 +95,21 @@ The control stack is likewise manipulated through auxiliary functions:
9895

9996
.. code-block:: pseudo
10097
101-
func push_ctrl(label : list(val_type), out : list(val_type)) =
102-
 let frame = ctrl_frame(label, out, opds.size(), false)
98+
func push_ctrl(opcode : opcode, in : list(val_type), out : list(val_type)) =
99+
 let frame = ctrl_frame(opcode, in, out, opds.size(), false)
103100
  ctrls.push(frame)
101+
push_opds(in)
104102
105-
func pop_ctrl() : list(val_type) =
103+
func pop_ctrl() : ctrl_frame =
106104
 error_if(ctrls.is_empty())
107105
 let frame = ctrls[0]
108106
  pop_opds(frame.end_types)
109107
  error_if(opds.size() =/= frame.height)
110108
ctrls.pop()
111-
  return frame.end_types
109+
  return frame
110+
111+
func label_types(frame : ctrl_frame) : list(val_types) =
112+
return (if frame.opcode == loop then frame.start_types else frame.end_types)
112113
113114
func unreachable() =
114115
  opds.resize(ctrls[0].height)
@@ -121,6 +122,8 @@ Popping a frame first checks that the control stack is not empty.
121122
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.
122123
Afterwards, it checks that the stack has shrunk back to its initial height.
123124

125+
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.
126+
124127
Finally, the current frame can be marked as unreachable.
125128
In that case, all existing operand types are purged from the operand stack, in order to allow for the :ref:`stack-polymorphism <polymorphism>` logic in :code:`pop_opd` to take effect.
126129

@@ -163,41 +166,45 @@ Other instructions are checked in a similar manner.
163166
   case (unreachable)
164167
      unreachable()
165168
166-
case (block t*)
167-
push_ctrl([t*], [t*])
169+
case (block t1*->t2*)
170+
pop_opds([t1*])
171+
push_ctrl(block, [t1*], [t2*])
168172
169-
case (loop t*)
170-
push_ctrl([], [t*])
173+
case (loop t1*->t2*)
174+
pop_opds([t1*])
175+
push_ctrl(loop, [t1*], [t2*])
171176
172-
case (if t*)
177+
case (if t1*->t2*)
173178
pop_opd(I32)
174-
push_ctrl([t*], [t*])
179+
pop_opds([t1*])
180+
push_ctrl(if, [t1*], [t2*])
175181
176182
case (end)
177-
let results = pop_ctrl()
178-
push_opds(results)
183+
let frame = pop_ctrl()
184+
push_opds(frame.end_types)
179185
180186
case (else)
181-
let results = pop_ctrl()
182-
push_ctrl(results, results)
187+
let frame = pop_ctrl()
188+
error_if(frame.opcode =/= if)
189+
push_ctrl(else, frame.start_types, frame.end_types)
183190
184191
case (br n)
185192
     error_if(ctrls.size() < n)
186-
      pop_opds(ctrls[n].label_types)
193+
      pop_opds(label_types(ctrls[n]))
187194
      unreachable()
188195
189196
case (br_if n)
190197
     error_if(ctrls.size() < n)
191198
pop_opd(I32)
192-
      pop_opds(ctrls[n].label_types)
193-
      push_opds(ctrls[n].label_types)
199+
      pop_opds(label_types(ctrls[n]))
200+
      push_opds(label_types(ctrls[n]))
194201
195202
   case (br_table n* m)
196203
      error_if(ctrls.size() < m)
197204
      foreach (n in n*)
198-
        error_if(ctrls.size() < n || ctrls[n].label_types =/= ctrls[m].label_types)
205+
        error_if(ctrls.size() < n || label_types(ctrls[n]) =/= label_types(ctrls[m]))
199206
pop_opd(I32)
200-
      pop_opds(ctrls[m].label_types)
207+
      pop_opds(label_types(ctrls[m]))
201208
      unreachable()
202209
203210
.. note::

document/core/appendix/implementation.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ An implementation may impose restrictions on the following dimensions of a modul
4343
* the number of :ref:`exports <syntax-export>` from a :ref:`module <syntax-module>`
4444
* the number of parameters in a :ref:`function type <syntax-functype>`
4545
* the number of results in a :ref:`function type <syntax-functype>`
46+
* the number of parameters in a :ref:`block type <syntax-blocktype>`
47+
* the number of results in a :ref:`block type <syntax-blocktype>`
4648
* the number of :ref:`locals <syntax-local>` in a :ref:`function <syntax-func>`
4749
* the size of a :ref:`function <syntax-func>` body
4850
* the size of a :ref:`structured control instruction <syntax-instr-control>`

0 commit comments

Comments
 (0)