Skip to content

Commit

Permalink
Merge upstream (#89)
Browse files Browse the repository at this point in the history
* Upgrade to latest Sphinx release (2.4.4) (#1171)

Fixes #1157

* Support 4GB of memory both in initial and max.

* [interpreter] Strictify and specify .bin.wast format (#1173)

* Merge nontrapping-float-to-int proposal into spec (#1143)

See the non-trapping-float-to-int-conversions proposal here:

https://github.com/WebAssembly/nontrapping-float-to-int-conversions

* Merge sign-extension-ops proposal into spec (#1144)

See the sign-extension-ops proposal here:

https://github.com/WebAssembly/sign-extension-ops

This PR is built on top of #1143 (merge nontrapping-float-to-int).

* Merge multi-value proposal into spec (#1145)

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)

* [interpreter] Remove junk in README

* [interpreter] Remove junk in README

* [spec] Fix grammar for fractions (#1178)

* [spec] Add missing i64.extend32_s syntax (#1179)

* [js-api][web-api] Fix some markup errors.

* Add a README to the proposals directory.

* Add more address overflow tests (#1188)

There are already tests for effective address overflow, but those have a
large value baked into the offset. These tests all use `1` as the
immediate offset, and use `-1` for the address on the stack, which may
be compiled differently.

* Add a test for non-treelike behavior of stack (#961)

We've recently found a bug in a WebAssembly library we've been working
with where we're mapping WebAssembly to a tree-like IR internally. The
way we parse into this representation, however, has a bug when the
function isn't itself tree-like but rather exibits properties that
exploit a stack machine. For example this isn't so straightforward to
represent in a tree-like fashion:

    (import "" "a" (func $foo))
    (import "" "b" (func $foo (result i32)))
    (func (result i32)
      call $b
      call $b
      call $a
      i32.xor)

The extra `call $a` in the middle is valid `WebAssembly` but needs
special treatment when converting to a more tree-like IR format. I
figured it'd be good to ensure there's a spec test covering this case as
we currently pass the suite of spec tests but still contain this bug!

* [js-api] Various editorial improvements.

* [js-api] Replace pseudo-ASCII characters by normal ones.

This also required disambiguating the references to "module", as there are now
two definitions by that name.

* [js-api] Improve prose in 'run a host function'.

* [js-api] Improve some of the multi-value prose.

* Synchronize js-api tests.

* Add script to synchronize js-api tests.

Co-authored-by: Ng Zhi An <ngzhian@gmail.com>
Co-authored-by: Alon Zakai <azakai@google.com>
Co-authored-by: Ben Smith <binji@chromium.org>
Co-authored-by: Ms2ger <Ms2ger@igalia.com>
Co-authored-by: Alex Crichton <alex@alexcrichton.com>
  • Loading branch information
6 people authored May 12, 2020
1 parent 551e876 commit 5567def
Show file tree
Hide file tree
Showing 113 changed files with 4,995 additions and 1,260 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ addons:
- yarn

install:
- pip install Sphinx==2.3.0
- pip install Sphinx==2.4.4
- git clone https://github.com/tabatkins/bikeshed.git
- pip install --editable $PWD/bikeshed
- bikeshed update
Expand Down
57 changes: 32 additions & 25 deletions document/core/appendix/algorithm.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ the latter surrounding :ref:`structured control instructions <syntax-instr-contr
type ctrl_stack = stack(ctrl_frame)
type ctrl_frame = {
label_types : list(val_type)
opcode : opcode
start_types : list(val_type)
end_types : list(val_type)
height : nat
unreachable : bool
Expand All @@ -52,11 +53,7 @@ the latter surrounding :ref:`structured control instructions <syntax-instr-contr
For each value, the value stack records its :ref:`value type <syntax-valtype>`, or :code:`Unknown` when the type is not known.


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).

.. note::
In the presentation of this algorithm, multiple values are supported for the :ref:`result types <syntax-resulttype>` classifying blocks and labels.
With the current version of WebAssembly, the :code:`list` could be simplified to an optional value.
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).

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

Expand Down Expand Up @@ -112,17 +109,21 @@ The control stack is likewise manipulated through auxiliary functions:

.. code-block:: pseudo
func push_ctrl(label : list(val_type), out : list(val_type)) =
 let frame = ctrl_frame(label, out, vals.size(), false)
func push_ctrl(opcode : opcode, in : list(val_type), out : list(val_type)) =
 let frame = ctrl_frame(opcode, in, out, vals.size(), false)
  ctrls.push(frame)
push_vals(in)
func pop_ctrl() : list(val_type) =
func pop_ctrl() : ctrl_frame =
 error_if(ctrls.is_empty())
 let frame = ctrls[0]
  pop_vals(frame.end_types)
  error_if(vals.size() =/= frame.height)
ctrls.pop()
  return frame.end_types
  return frame
func label_types(frame : ctrl_frame) : list(val_types) =
return (if frame.opcode == loop then frame.start_types else frame.end_types)
func unreachable() =
  vals.resize(ctrls[0].height)
Expand All @@ -135,6 +136,8 @@ Popping a frame first checks that the control stack is not empty.
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.
Afterwards, it checks that the stack has shrunk back to its initial height.

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.

Finally, the current frame can be marked as unreachable.
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.

Expand Down Expand Up @@ -185,41 +188,45 @@ Other instructions are checked in a similar manner.
   case (unreachable)
      unreachable()
case (block t*)
push_ctrl([t*], [t*])
case (block t1*->t2*)
pop_vals([t1*])
push_ctrl(block, [t1*], [t2*])
case (loop t*)
push_ctrl([], [t*])
case (loop t1*->t2*)
pop_vals([t1*])
push_ctrl(loop, [t1*], [t2*])
case (if t*)
case (if t1*->t2*)
pop_val(I32)
push_ctrl([t*], [t*])
pop_vals([t1*])
push_ctrl(if, [t1*], [t2*])
case (end)
let results = pop_ctrl()
push_vals(results)
let frame = pop_ctrl()
push_vals(frame.end_types)
case (else)
let results = pop_ctrl()
push_ctrl(results, results)
let frame = pop_ctrl()
error_if(frame.opcode =/= if)
push_ctrl(else, frame.start_types, frame.end_types)
case (br n)
     error_if(ctrls.size() < n)
      pop_vals(ctrls[n].label_types)
      pop_vals(label_types(ctrls[n]))
      unreachable()
case (br_if n)
     error_if(ctrls.size() < n)
pop_val(I32)
      pop_vals(ctrls[n].label_types)
      push_vals(ctrls[n].label_types)
      pop_vals(label_types(ctrls[n]))
      push_vals(label_types(ctrls[n]))
   case (br_table n* m)
      error_if(ctrls.size() < m)
      foreach (n in n*)
        error_if(ctrls.size() < n || ctrls[n].label_types =/= ctrls[m].label_types)
        error_if(ctrls.size() < n || label_types(ctrls[n]) =/= label_types(ctrls[m]))
pop_val(I32)
      pop_vals(ctrls[m].label_types)
      pop_vals(label_types(ctrls[m]))
      unreachable()
.. note::
Expand Down
2 changes: 2 additions & 0 deletions document/core/appendix/implementation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ An implementation may impose restrictions on the following dimensions of a modul
* the number of :ref:`exports <syntax-export>` from a :ref:`module <syntax-module>`
* the number of parameters in a :ref:`function type <syntax-functype>`
* the number of results in a :ref:`function type <syntax-functype>`
* the number of parameters in a :ref:`block type <syntax-blocktype>`
* the number of results in a :ref:`block type <syntax-blocktype>`
* the number of :ref:`locals <syntax-local>` in a :ref:`function <syntax-func>`
* the size of a :ref:`function <syntax-func>` body
* the size of a :ref:`structured control instruction <syntax-instr-control>`
Expand Down
Loading

0 comments on commit 5567def

Please sign in to comment.