Skip to content

[spec/interpreter/test] Land bulk instructions & reference types proposals #1287

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 233 commits into from
Mar 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
233 commits
Select commit Hold shift + click to select a range
6185199
Add initial proposal overview
binji Sep 6, 2017
107c4cc
Include link to gist for benchmark
binji Oct 26, 2017
1efc603
Merge remote-tracking branch 'spec/master' into HEAD
binji Jan 17, 2018
096ac5b
Include ConditionalSegmentInitialization proposal (#4)
binji Jan 18, 2018
83b7620
Rename `{set,move}_memory` to `mem.{set,copy}`
binji Jan 18, 2018
dd356d5
Combine bulk-memory-ops + cond-seg-init proposals (#5)
binji Jan 18, 2018
5d60dab
Rename `mem.set` to `mem.fill` (#6)
binji Feb 1, 2018
c71b281
Initial
rossberg Feb 27, 2018
277308d
Add first sketch of overview
rossberg Mar 5, 2018
c985a1b
Add note
rossberg Mar 6, 2018
835dc7d
Fix typo in subtype relation (#5)
chicoxyzzy Mar 8, 2018
9f0c7aa
Add links
rossberg Mar 13, 2018
7a8d371
Fix issue links
rossberg Mar 13, 2018
1d7785d
[interpreter] Implement basic reference types and multiple tables (#2)
rossberg Mar 24, 2018
1f29a8e
[spec] First go at specification (#3)
rossberg Apr 4, 2018
fec2142
Update overview
rossberg Apr 5, 2018
10c465a
Merge branch 'master' of https://github.com/WebAssembly/reference-types
rossberg Apr 7, 2018
a219a03
[spec] JS API changes (#8)
rossberg Apr 12, 2018
4fee761
Rename to eqref; allow any JS value for anyref (#10)
rossberg Apr 15, 2018
4302793
Merge remote-tracking branch 'upstream/master'
binji May 1, 2018
cf1826f
Add instruction encoding to overview
binji May 1, 2018
ab760d0
Remove ref.eq (#12)
rossberg May 4, 2018
ba2a5f8
Rename `mem.*` -> `memory.*`
binji May 7, 2018
c86bece
[spec] Initial documentation of syntax (#12)
binji May 10, 2018
9319fa7
Fix memory.{init,drop} mistakes in overview (#14)
binji May 10, 2018
91d8fa2
Merge remote-tracking branch 'spec/master' into HEAD
binji May 10, 2018
863d963
[spec] Document validation (#16)
binji May 11, 2018
eeec740
Link spec in README
rossberg May 12, 2018
506907b
[spec] Documentation of binary format (#17)
binji May 15, 2018
008e552
[spec] Documentation of text format (#18)
binji May 31, 2018
d50d7e5
Fix links to broken/obsolete proposals (#15)
flaki Jun 9, 2018
f4bdb3a
Remove eqref remainders
rossberg Jul 15, 2018
bf6e067
Update overview
rossberg Jul 15, 2018
b022826
Update link to GC proposal overview (#16)
chicoxyzzy Aug 29, 2018
872fcfa
Tweak segment encoding to keep memory/table index encoding (#28)
AndrewScheidecker Sep 11, 2018
4123d1e
Don't statically validate whether the segment index immediates of `me…
AndrewScheidecker Sep 20, 2018
7ea73f7
Add memory index for {memory,table}.init (#33)
binji Oct 5, 2018
b73c079
Clarify some encoding/semantics (#32)
alexcrichton Oct 5, 2018
30092f1
Update binary encoding to use varuint32 for flags (#35)
alexcrichton Oct 15, 2018
61018e8
Fix typo in overview: memory->table
binji Oct 31, 2018
1276e58
Update Overview.md for element segments (#41)
binji Nov 26, 2018
d6d2c1f
Add new `DataCount` section (#42)
binji Nov 29, 2018
b19cbf3
Add a second placeholder zero to the encoding of `memory.copy` and `t…
AndrewScheidecker Nov 29, 2018
aa7efea
Change DataCount section ID to 12 (#44)
aheejin Dec 12, 2018
0b8da7e
Merge remote-tracking branch 'upstream/master'
rossberg Dec 12, 2018
c34d22f
Forgot to rename in Overview
rossberg Dec 12, 2018
59e2ee5
Add store typing
rossberg Dec 12, 2018
fa335d7
Check that ref.null is a const instruction
rossberg Dec 12, 2018
2a00b2e
Add ref.func instruction (#24)
rossberg Dec 12, 2018
b70d03c
Rename ref.isnull to ref.is_null (#23)
rossberg Dec 13, 2018
178a7f6
Two zero immediates for memory.copy and table.copy (#43)
binji Jan 9, 2019
446b9c2
Reverse order of {table,memory}.init immediates (#45)
binji Jan 9, 2019
3115daa
Fix small typo in validation->set_table (#27)
gahaas Jan 16, 2019
af60ffe
Rename memory.drop and table.drop as per agreement (#46)
lars-t-hansen Jan 22, 2019
241c48d
[spec] Fix typo (#28)
gahaas Jan 23, 2019
e27277d
Clarify *.{init,copy,fill} w/ zero count (#48)
binji Jan 24, 2019
b752e8b
Clarify trapping semantics (#50)
lars-t-hansen Jan 28, 2019
79bf48c
Remove the intermediate buffer for memory.copy (#51)
lars-t-hansen Jan 30, 2019
f497d55
[Overview] Update segment initialization text (#57)
binji Feb 4, 2019
a252581
[interpreter] Implement bulk memory operations (#54)
binji Feb 5, 2019
1e03671
[interpreter] Flatten segment AST (#58)
rossberg Feb 7, 2019
564fc40
[proposal] Link to function reference proposal
rossberg Feb 12, 2019
5e3df28
[Interpreter] Decode/encode the data count section (#59)
binji Feb 21, 2019
d91b74e
[Interpreter] Implement memory.copy, memory.fill (#60)
binji Feb 21, 2019
7c357ab
Merge remote-tracking branch 'spec/master' into HEAD
binji Feb 21, 2019
63986ff
Move MemoryCopy and MemoryFill definitions
binji Feb 21, 2019
1671a38
[Interpreter] Handle 0-byte copies properly. (#61)
binji Feb 22, 2019
f817560
[Interpreter] Initialized segments persist after instantiation failure
binji Feb 22, 2019
f574364
[Interpreter] Implement rest of the instructions (#64)
binji Mar 1, 2019
d97e8fb
[Interpreter] New syntax for passive elem segments (#65)
binji Mar 1, 2019
35d08d2
[Interpreter] Fix bugs found by Lars' tests (#66)
binji Mar 5, 2019
72ada2b
Bulk memory operations test cases (#67)
lars-t-hansen Mar 5, 2019
a1c04b5
[test] Add required `funcref` to passive elems (#68)
binji Mar 5, 2019
6c802fa
[test] Minor cleanup to generated output (#69)
binji Mar 5, 2019
63cceba
Remove irrelevant comment + support node.js (#70)
lars-t-hansen Mar 7, 2019
0cf128e
[interpreter] Refactor element type in passive segments (#71)
rossberg Mar 8, 2019
c2cd260
Replace decoding flag with condition on free vars (#72)
rossberg Mar 9, 2019
d9ebd33
[interpreter] Fix JS generator (#34)
rossberg Mar 30, 2019
ef6678a
Merge remote-tracking branch 'upstream/master'
rossberg Mar 30, 2019
726d7ec
[spec/interpreter] Rename elem/data.drop; update README; reorder (#75)
rossberg Mar 30, 2019
c3d5cbc
[spec/interpreter/test] Add table bulk instructions missing from bulk…
rossberg Apr 3, 2019
40785ff
Increase the table count limit to 100,000
Apr 4, 2019
fcef8d6
[spec] Use `data.drop` instead of `memory.drop`
binji Apr 5, 2019
d346a8f
[spec] Update instruction index (#81)
binji Apr 5, 2019
e27b4ea
[spec] DataCount section, syntax, and validation (#80)
binji Apr 5, 2019
8bc0aa1
Merge remote-tracking branch 'spec/master' into HEAD
binji Apr 9, 2019
864f382
[spec] Simplify datacount side condition (#83)
rossberg Apr 16, 2019
1b1d70c
Merge remote-tracking branch 'upstream/master'
rossberg Apr 18, 2019
5ad8059
[spec] Adjust soundness appendix
rossberg Apr 18, 2019
a2d5f93
[spec] Adjust invoke
rossberg Apr 18, 2019
8b3fb37
[spec] Fix latex issue
rossberg Apr 18, 2019
dcbc1c5
Merge remote-tracking branch 'upstream/master'
rossberg Apr 19, 2019
02117e4
[spec] Remove Sphinx/Latex workaround
rossberg Apr 19, 2019
4c97261
[spec] Proper binary format for element segments (#82)
binji Apr 19, 2019
05672b0
[test] Disallow table size overflow
rossberg Apr 20, 2019
09dccac
[spec] Correctly account for subtyping in global/table instances (#39)
rossberg Apr 23, 2019
1fec5c1
Update host bindings proposal links
rossberg Apr 25, 2019
b8f6478
Fix links 2
rossberg Apr 25, 2019
d6cd997
[interpreter] Forgot commit
rossberg Apr 30, 2019
16b65a2
[interpreter] Eps
rossberg Apr 30, 2019
29540ac
[spec/interpreter/test] Avoid lubs and glbs (#43)
rossberg May 11, 2019
6eb26a3
Slight simplifications to text format (#84)
rossberg May 13, 2019
08be05a
Init/copy/fill with offsets at the end of the memory or table (#86)
sunfishcode May 13, 2019
e2e3383
Fix merge conflicts introduced w/ PRs #84 and #86 (#87)
binji May 13, 2019
e5cf99f
[spec] Fix oversight in elem typing rule
rossberg May 15, 2019
82c9db1
[spec] Formatting nit
rossberg May 15, 2019
eca021a
[spec] Add memory.fill to exec section (#88)
binji May 16, 2019
4e1a093
[travis] Use a different deploy_key
binji May 21, 2019
822039b
Copy bikeshed fix from spec repo
binji May 21, 2019
0f7f930
[test] JS-compatible module name (#45)
gahaas May 23, 2019
c3289d2
[spec] Add element type to passive element segment (#90)
binji May 23, 2019
88cb638
[spec] Fix title underline in valid/modules.rst
binji May 23, 2019
86c7e35
[spec] Adjust binary format of element segments (#46)
gahaas May 27, 2019
b2d34e0
[test] Use more JS-compatible names (#47)
gahaas May 28, 2019
a976b82
[spec] Runtime format of element and data segments (#91)
binji May 31, 2019
0ee9e67
[spec] Add memory.init and data.drop for exec (#92)
binji Jun 5, 2019
80aea4a
[spec] Use optional data instance, not data address (#93)
binji Jun 8, 2019
983df68
[spec] Add `table.init`, `elem.drop` exec text (#95)
binji Jun 28, 2019
d976981
Update overview for the zero-byte OOB case (#100)
binji Jun 28, 2019
8c6ea22
[spec] Update text for zero-byte OOB case (#101)
binji Jun 28, 2019
d18ec64
[interp] Don't trap on zero-bytes out-of-bounds (#102)
binji Jun 28, 2019
07c57f1
[interp] Remove overlap check from *.copy instr (#103)
binji Jul 6, 2019
aa596e5
Merge pull request #38 from lars-t-hansen/max_tables
binji Jul 7, 2019
600c524
[spec] Add `table.copy` exec text (#105)
gahaas Jul 11, 2019
fd48080
Polish table.init exec spec (#104)
gahaas Jul 11, 2019
820bd12
[spec] Add `memory.copy` exec text (#106)
binji Jul 23, 2019
aadc467
Change element segment encoding (#108)
gahaas Aug 1, 2019
1f0d158
Update some links (#52)
chicoxyzzy Aug 21, 2019
c69a117
New element section encoding in the interpreter (#109)
gahaas Aug 23, 2019
3d87cfa
Adjust element segment encoding to match the bulk-memory proposal (#53)
gahaas Sep 11, 2019
bc81602
[test] Fix the binary.wast test for multi-bytes table indices (#110)
gahaas Sep 12, 2019
d5101bc
[test] Add negative test for ref.func globals (#54)
gahaas Sep 17, 2019
c1a0415
Fix typo in validation of br_table (#56)
eqrion Sep 21, 2019
b1830ae
Adjust immediate memidx order (#118)
rossberg Oct 4, 2019
f47a675
Segment refactoring (#113)
rossberg Oct 7, 2019
df2a55f
[spec] Specify instantiate (#114)
rossberg Oct 7, 2019
8db23a9
[interpreter] Use small-step semantics (#115)
rossberg Oct 7, 2019
b95f821
Polish text format (#119)
rossberg Oct 7, 2019
4f9ae30
Merge remote-tracking branch 'upstream/master'
rossberg Oct 7, 2019
9aef0c5
[interpreter/test] Update table.init semantics as well (#120)
rossberg Oct 7, 2019
074a6fa
Merge remote-tracking branch 'upstream/master'
rossberg Oct 16, 2019
1e05d9b
Fix test expectation (#58)
gahaas Oct 29, 2019
e66f532
Fix call_indirect immediates
rossberg Nov 14, 2019
be7ce1b
[spec] Bounds check bulk-memory before execution (#123)
eqrion Nov 14, 2019
34a7ebe
Fix layout
rossberg Nov 14, 2019
24b0882
Merge remote-tracking branch 'upstream/master'
rossberg Nov 19, 2019
303c942
Merge remote-tracking branch 'upstream/master'
rossberg Nov 20, 2019
b2a5c4f
[interpreter] Simplify zero-len and drop semantics (#126)
rossberg Nov 22, 2019
1e29660
[spec] Adapt OOB behaviour in spec; store typing (#129)
rossberg Nov 23, 2019
d4bc208
[spec/interpreter/test] Allow nullref type externally (#66)
rossberg Dec 13, 2019
82be3c0
New segment encoding (#130)
lars-t-hansen Dec 16, 2019
a00705b
Delete mentions of copying order in Overview.md (#134)
aheejin Dec 16, 2019
e383b99
Rebase on bulk proposal (#65)
rossberg Jan 10, 2020
fd804cf
Merge remote-tracking branch 'upstream/master' into rebase-master
rossberg Jan 13, 2020
97dec20
Travis setup; fix references to spec
binji Jan 15, 2020
3e32403
Fix various TODOs (#72)
rossberg Jan 16, 2020
64f9837
[spec/interpreter/test] Declarative element segments (#73)
rossberg Jan 16, 2020
2719ec3
[spec] Fix merge artefact
rossberg Jan 16, 2020
11388e7
Add test ensuring data segment index is unsigned (#136)
binji Jan 28, 2020
22ce5e3
[interpreter] Fix ref asserts (#78)
rossberg Feb 3, 2020
fc990e3
[spec] Fix validation context for globals (#77)
rossberg Feb 3, 2020
404b7e7
[interpreter/test] Fix validation for `elem.drop` (#137)
fitzgen Feb 6, 2020
d258902
[spec/interpreter] Fix missing multi table bulk cases (#80)
rossberg Feb 13, 2020
774dd1d
[spec] Typo
rossberg Feb 19, 2020
a1bfe97
[spec] Fix binary immediate order for table/memory.init (#82)
rossberg Feb 24, 2020
7cfa199
[test] call_indirect with multiple tables (#83)
rossberg Feb 27, 2020
ffdbb6e
Test that drop instructions work w/on memory/table (#140)
binji Feb 28, 2020
060678f
Change validation error -> malformed in Overview (#143)
binji Mar 23, 2020
d7f0241
Fix {memory,table}.init immediate order (#147)
binji Mar 23, 2020
2028231
[js-api] Extend with reference types support. (#79)
Ms2ger Mar 24, 2020
1568b35
Generalize test generators for table.copy and table.init to multi-tab…
lars-t-hansen Mar 24, 2020
b4637e9
Merge remote-tracking branch 'upstream/master'
sbc100 Mar 26, 2020
30002e7
Merge remote-tracking branch 'upstream/master'
rossberg Apr 2, 2020
9f6a39f
Merge fixups
rossberg Apr 2, 2020
c0f30ca
[test] Update JS harnesses to match interpreter harness (#86)
eqrion Apr 3, 2020
551e876
Remove subtyping (#87)
rossberg May 7, 2020
5567def
Merge upstream (#89)
rossberg May 12, 2020
e56ef21
Adjust readme
rossberg May 12, 2020
c8d58c7
Update test/harness/*_index.js for removing subtyping (#88)
eqrion May 12, 2020
b728bbc
[spec/interpreter/test] Relax ref check to whole module (#90)
rossberg May 13, 2020
37e44c9
Update `ref.null` encoding after subtyping change (#149)
binji May 13, 2020
996ef3f
Merge remote-tracking branch 'upstream/master' into HEAD
binji May 13, 2020
dcfc963
Merge remote-tracking branch 'upstream/master' into HEAD
binji May 13, 2020
66d90a7
Test that partially out of bounds segments don't write to a memory/ta…
fitzgen May 13, 2020
c90e289
Merge remote-tracking branch 'bulk/master' into merge2
rossberg May 14, 2020
0b6f675
Re-add test that fails with a bottom type (#93)
eqrion May 18, 2020
a83b16e
[tests] Delete leftover harness function (#92)
gahaas May 18, 2020
f23154e
[interpreter] Improve error message
rossberg May 19, 2020
8dd9a90
[test] Fix JS harness and binary test (#95)
gahaas May 20, 2020
5bc46bb
[js-api] More subtyping removal. (#96)
Ms2ger May 25, 2020
b4f254b
Add select to Overview
rossberg Jun 5, 2020
f18a4eb
Fix off-by-one in spec
rossberg Jun 9, 2020
6c0beae
Remove type annotation on ref.is_null (#100)
rossberg Jun 10, 2020
b583fad
[interpreter] Hot fix
rossberg Jun 10, 2020
7ab5846
[interpreter] Simplify hot fix
rossberg Jun 10, 2020
da20676
[interpreter] ARgh
rossberg Jun 10, 2020
9df8a3e
Update Overview wrt table.grow
rossberg Jun 17, 2020
401c8eb
Fix links to `table.fill`'s validation and execution in appendix (#103)
fitzgen Jun 22, 2020
1e652dd
Add a test for mutating `externref` globals (#104)
fitzgen Jul 16, 2020
c360086
table.fill: Bounds check before mutating the table (#106)
fitzgen Jul 21, 2020
50e699f
Remove type annotation on ref.is_null in overview
aheejin Aug 26, 2020
4722e6b
Merge remote-tracking branch 'upstream/master' into HEAD
binji Aug 28, 2020
ec4bcea
Update document to use u32 for opcode after prefix (#155)
binji Aug 28, 2020
7708eb4
Merge pull request #108 from aheejin/remove_ref_is_null_type
binji Sep 8, 2020
7ae4890
fix decription of ref.func
turbolent Sep 12, 2020
8f5038e
Merge pull request #109 from turbolent/patch-1
binji Sep 14, 2020
4495265
[test] Uniform failure strings (#117)
q82419 Sep 23, 2020
2ccd487
[spec/interpreter/test] Reintroduce bottom type (#116)
rossberg Sep 30, 2020
736bda2
[test] Fix table index encoding (#154)
gahaas Oct 12, 2020
2799329
[spec] Fix xref
rossberg Oct 14, 2020
28c3a5b
[spec] Fix xref
rossberg Oct 14, 2020
9ad83c3
Fix formatting in 'Table Instructions'. (#119)
Ms2ger Oct 19, 2020
596e5f6
Merge remote-tracking branch 'upstream/master' into merge-upstream
rossberg Oct 29, 2020
244c841
Merge remote-tracking branch 'bulk/master' into merge-upstream2
rossberg Oct 29, 2020
ad009e0
Merge pull request #122 from WebAssembly/merge-upstream2
rossberg Nov 3, 2020
173ea33
Rename "refedtype" to "heaptype" (#124)
wingo Nov 3, 2020
d6046b8
[spec] Fix instantiation to handle ref.func in initializers (#115)
rossberg Nov 4, 2020
c19b709
Fix indentation (#126)
chicoxyzzy Jan 14, 2021
7c7bd2a
Fix some js-api bugs. (#128)
Ms2ger Jan 14, 2021
dd92422
[js-api] Explicitly disallow creating Tables with non-reftypes. (#129)
Ms2ger Jan 14, 2021
fc4b17f
Merge remote-tracking branch 'upstream/master' into merge-upstream3
rossberg Jan 20, 2021
cbb4030
Merge upstream (#130)
rossberg Jan 20, 2021
44b626b
[spec] Add missing immediates
rossberg Feb 10, 2021
8546739
Merge upstream (#157)
rossberg Feb 11, 2021
33da5b9
Merge remote-tracking branch 'bulk/master' into merge-bulk
rossberg Feb 11, 2021
1f4297e
Merge upstream bulk instructions proposal (#132)
rossberg Feb 11, 2021
1698322
Merge remote-tracking branch 'upstream/master' into merge-main
rossberg Feb 11, 2021
063d34e
Merge upstream (#133)
rossberg Feb 11, 2021
54dde91
Undo repo-local modifications
rossberg Feb 11, 2021
1dca287
Makefile and other minor tweaks
rossberg Mar 10, 2021
c8ff382
Merge branch 'master' into merge-ref-bulk
rossberg Mar 10, 2021
38b0c57
Update algorithm.rst
rossberg Mar 10, 2021
fa006af
Fix test failures from merge
rossberg Mar 10, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 73 additions & 48 deletions document/core/appendix/algorithm.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,25 @@ The algorithm is expressed in typed pseudo code whose semantics is intended to b
Data Structures
~~~~~~~~~~~~~~~

The algorithm uses two separate stacks: the *operand stack* and the *control stack*.
Types are representable as an enumeration.

.. code-block:: pseudo

type val_type = I32 | I64 | F32 | F64 | Funcref | Externref

func is_num(t : val_type | Unknown) : bool =
return t = I32 || t = I64 || t = F32 || t = F64 || t = Unknown

func is_ref(t : val_type | Unknown) : bool =
return t = Funcref || t = Externref || t = Unknown

The algorithm uses two separate stacks: the *value stack* and the *control stack*.
The former tracks the :ref:`types <syntax-valtype>` of operand values on the :ref:`stack <stack>`,
the latter surrounding :ref:`structured control instructions <syntax-instr-control>` and their associated :ref:`blocks <syntax-instr-control>`.

.. code-block:: pseudo

type val_type = I32 | I64 | F32 | F64

type opd_stack = stack(val_type | Unknown)
type val_stack = stack(val_type | Unknown)

type ctrl_stack = stack(ctrl_frame)
type ctrl_frame = {
Expand All @@ -40,79 +50,82 @@ the latter surrounding :ref:`structured control instructions <syntax-instr-contr
unreachable : bool
}

For each value, the operand stack records its :ref:`value type <syntax-valtype>`, or :code:`Unknown` when the type is not known.
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 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:

.. code-block:: pseudo

var opds : opd_stack
var vals : val_stack
var ctrls : ctrl_stack

However, these variables are not manipulated directly by the main checking function, but through a set of auxiliary functions:

.. code-block:: pseudo

func push_opd(type : val_type | Unknown) =
opds.push(type)
func push_val(type : val_type | Unknown) =
vals.push(type)

func pop_opd() : val_type | Unknown =
if (opds.size() = ctrls[0].height && ctrls[0].unreachable) return Unknown
error_if(opds.size() = ctrls[0].height)
return opds.pop()
func pop_val() : val_type | Unknown =
if (vals.size() = ctrls[0].height && ctrls[0].unreachable) return Unknown
error_if(vals.size() = ctrls[0].height)
return vals.pop()

func pop_opd(expect : val_type | Unknown) : val_type | Unknown =
let actual = pop_opd()
func pop_val(expect : val_type | Unknown) : val_type | Unknown =
let actual = pop_val()
if (actual = Unknown) return expect
if (expect = Unknown) return actual
error_if(actual =/= expect)
return actual

func push_opds(types : list(val_type)) = foreach (t in types) push_opd(t)
func pop_opds(types : list(val_type)) = foreach (t in reverse(types)) pop_opd(t)
func push_vals(types : list(val_type)) = foreach (t in types) push_val(t)
func pop_vals(types : list(val_type)) : list(val_type) =
var popped := []
foreach (t in reverse(types)) popped.append(pop_val(t))
return popped

Pushing an operand simply pushes the respective type to the operand stack.
Pushing an operand value simply pushes the respective type to the value stack.

Popping an operand checks that the operand stack does not underflow the current block and then removes one type.
But first, a special case is handled where the block contains no known operands, but has been marked as unreachable.
Popping an operand value checks that the value stack does not underflow the current block and then removes one type.
But first, a special case is handled where the block contains no known values, but has been marked as unreachable.
That can occur after an unconditional branch, when the stack is typed :ref:`polymorphically <polymorphism>`.
In that case, an unknown type is returned.

A second function for popping an operand takes an expected type, which the actual operand type is checked against.
A second function for popping an operand value takes an expected type, which the actual operand type is checked against.
The types may differ in case one of them is Unknown.
The more specific type is returned.
The function returns the actual type popped from the stack.

Finally, there are accumulative functions for pushing or popping multiple operand types.

.. note::
The notation :code:`stack[i]` is meant to index the stack from the top,
so that :code:`ctrls[0]` accesses the element pushed last.
so that, e.g., :code:`ctrls[0]` accesses the element pushed last.


The control stack is likewise manipulated through auxiliary functions:

.. code-block:: pseudo

func push_ctrl(opcode : opcode, in : list(val_type), out : list(val_type)) =
 let frame = ctrl_frame(opcode, in, out, opds.size(), false)
 let frame = ctrl_frame(opcode, in, out, vals.size(), false)
  ctrls.push(frame)
push_opds(in)
push_vals(in)

func pop_ctrl() : ctrl_frame =
 error_if(ctrls.is_empty())
 let frame = ctrls[0]
  pop_opds(frame.end_types)
  error_if(opds.size() =/= frame.height)
  pop_vals(frame.end_types)
  error_if(vals.size() =/= frame.height)
ctrls.pop()
  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() =
  opds.resize(ctrls[0].height)
  vals.resize(ctrls[0].height)
  ctrls[0].unreachable := true

Pushing a control frame takes the types of the label and result values.
Expand All @@ -125,7 +138,7 @@ 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 operand stack, in order to allow for the :ref:`stack-polymorphism <polymorphism>` logic in :code:`pop_opd` to take effect.
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.

.. note::
Even with the unreachable flag set, consecutive operands are still pushed to and popped from the operand stack.
Expand All @@ -150,38 +163,46 @@ Other instructions are checked in a similar manner.
func validate(opcode) =
switch (opcode)
case (i32.add)
pop_opd(I32)
pop_opd(I32)
push_opd(I32)
pop_val(I32)
pop_val(I32)
push_val(I32)

case (drop)
pop_opd()
pop_val()

case (select)
pop_opd(I32)
let t1 = pop_opd()
let t2 = pop_opd(t1)
push_opd(t2)
pop_val(I32)
let t1 = pop_val()
let t2 = pop_val()
error_if(not (is_num(t1) && is_num(t2)))
error_if(t1 =/= t2 && t1 =/= Unknown && t2 =/= Unknown)
push_val(if (t1 = Unknown) t2 else t1)

case (select t)
pop_val(I32)
pop_val(t)
pop_val(t)
push_val(t)

   case (unreachable)
      unreachable()

case (block t1*->t2*)
pop_opds([t1*])
pop_vals([t1*])
push_ctrl(block, [t1*], [t2*])

case (loop t1*->t2*)
pop_opds([t1*])
pop_vals([t1*])
push_ctrl(loop, [t1*], [t2*])

case (if t1*->t2*)
pop_opd(I32)
pop_opds([t1*])
pop_val(I32)
pop_vals([t1*])
push_ctrl(if, [t1*], [t2*])

case (end)
let frame = pop_ctrl()
push_opds(frame.end_types)
push_vals(frame.end_types)

case (else)
let frame = pop_ctrl()
Expand All @@ -190,23 +211,27 @@ Other instructions are checked in a similar manner.

case (br n)
     error_if(ctrls.size() < n)
      pop_opds(label_types(ctrls[n]))
      pop_vals(label_types(ctrls[n]))
      unreachable()

case (br_if n)
     error_if(ctrls.size() < n)
pop_opd(I32)
      pop_opds(label_types(ctrls[n]))
      push_opds(label_types(ctrls[n]))
pop_val(I32)
      pop_vals(label_types(ctrls[n]))
      push_vals(label_types(ctrls[n]))

   case (br_table n* m)
pop_val(I32)
      error_if(ctrls.size() < m)
let arity = label_types(ctrls[m]).size()
      foreach (n in n*)
        error_if(ctrls.size() < n || label_types(ctrls[n]) =/= label_types(ctrls[m]))
pop_opd(I32)
      pop_opds(label_types(ctrls[m]))
        error_if(ctrls.size() < n)
        error_if(label_types(ctrls[n]).size() =/= arity)
push_vals(pop_vals(label_types(ctrls[n])))
pop_vals(label_types(ctrls[m]))
      unreachable()


.. note::
It is an invariant under the current WebAssembly instruction set that an operand of :code:`Unknown` type is never duplicated on the stack.
This would change if the language were extended with stack instructions like :code:`dup`.
Expand Down
Loading