-
Notifications
You must be signed in to change notification settings - Fork 40
[spec] First go at specification #3
Conversation
document/core/exec/instructions.rst
Outdated
|
||
7. Pop the value :math:`\I32.\CONST~i` from the stack. | ||
|
||
8. If :math:`i` is larger than the length of :math:`\X{tab}.\TIELEM`, then: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be "is not smaller than", right? This matches the behavior in call_indirect.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, done.
document/core/exec/instructions.rst
Outdated
|
||
9. Pop the value :math:`\I32.\CONST~i` from the stack. | ||
|
||
10. If :math:`i` is larger than the length of :math:`\X{tab}.\TIELEM`, then: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here w/ "not smaller"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
|
||
7. Let :math:`\X{ft}_{\F{expect}}` be the :ref:`function type <syntax-functype>` :math:`F.\AMODULE.\MITYPES[x]`. | ||
7. Let :math:`\X{ft}_{\F{expect}}` be the :ref:`function type <syntax-functype>` :math:`F.\AMODULE.\MITYPES[y]`. | ||
|
||
8. Assert: due to :ref:`validation <valid-call_indirect>`, a value with :ref:`value type <syntax-valtype>` |I32| is on the top of the stack. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't mark the proper line, but shouldn't "if tab.elem[i] is uninitialized" be changed to "is REFNULL"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed. Also needed to change the consecutive line, since the table no longer contains a function address directly. The semantics of elem segments required a similar tweak.
document/core/exec/runtime.rst
Outdated
.. _syntax-val: | ||
|
||
Values | ||
~~~~~~ | ||
|
||
WebAssembly computations manipulate *values* of the four basic :ref:`value types <syntax-valtype>`: :ref:`integers <syntax-int>` and :ref:`floating-point data <syntax-float>` of 32 or 64 bit width each, respectively. | ||
WebAssembly computations manipulate *values* of the four basic :ref:`value types <syntax-valtype>`: :ref:`integers <syntax-int>` and :ref:`floating-point data <syntax-float>` of 32 or 64 bit width each, or of references, respectively. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"respectively" sounds strange to me here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed the wording.
document/core/exec/runtime.rst
Outdated
|
||
References other than null are represented with additional :ref:`administrative instructions <syntax-instr-admin>`. | ||
They either are *function references*, pointing to a specific :ref:`function address <syntax-funcaddr>`, | ||
or *host references* pointing to an unintrpreted form of :ref:`host address <syntax-hostaddr>` that can be defined by the :ref:`embedder <embedder>`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sp: uninterpreted
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
document/core/valid/instructions.rst
Outdated
|
||
* Let :math:`\limits~t` be the :ref:`table type <syntax-tabletype>` :math:`C.\CTABLES[x]`. | ||
|
||
* Then the instruction is valid with type :math:`[t] \to []`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[\I32~t] \to []
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
document/core/valid/instructions.rst
Outdated
|
||
* Let :math:`\limits~t` be the :ref:`table type <syntax-tabletype>` :math:`C.\CTABLES[x]`. | ||
|
||
* Then the instruction is valid with type :math:`[] \to [t]`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[\I32] \to [t]
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
document/core/syntax/types.rst
Outdated
Reference Types | ||
~~~~~~~~~~~~~~~ | ||
|
||
*Reference types* classify |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove newlines
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, this actually was a half-finished edit.
document/core/syntax/types.rst
Outdated
The type |ANYFUNC| denotes the infinite union of all references to :ref:`functions <syntax-func>`, regardless of their :ref:`function types <syntax-functype>`. | ||
|
||
The type |EQREF| denotes the infinite union of all references that can be compared for equality; | ||
in order to avoid exposing implementation details, some reference types, such as |ANYFUNC|, do not admit equality, and therefor are not :ref:`subtypes <match-reftype>` of |EQREF|. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sp: therefore
@@ -147,7 +147,7 @@ The |MTABLES| component of a module defines a vector of *tables* described by th | |||
\{ \TTYPE~\tabletype \} \\ | |||
\end{array} | |||
|
|||
A table is a vector of opaque values of a particular table :ref:`element type <syntax-elemtype>`. | |||
A table is a vector of opaque values of a particular :ref:`reference type <syntax-reftype>`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just so I understand, of the instructions that operate on a table:
- All table types allow use of
get_table
,set_table
. - A table of
ANYFUNC
allowscall_indirect
. - A table of
EQREF
allowsref.eq
. - A table of
ANYREF
allows no other instructions.
Is that correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that's right, except that ref.eq does not operate on tables but on references directly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the review!
document/core/exec/instructions.rst
Outdated
|
||
7. Pop the value :math:`\I32.\CONST~i` from the stack. | ||
|
||
8. If :math:`i` is larger than the length of :math:`\X{tab}.\TIELEM`, then: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, done.
document/core/exec/instructions.rst
Outdated
|
||
9. Pop the value :math:`\I32.\CONST~i` from the stack. | ||
|
||
10. If :math:`i` is larger than the length of :math:`\X{tab}.\TIELEM`, then: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
|
||
7. Let :math:`\X{ft}_{\F{expect}}` be the :ref:`function type <syntax-functype>` :math:`F.\AMODULE.\MITYPES[x]`. | ||
7. Let :math:`\X{ft}_{\F{expect}}` be the :ref:`function type <syntax-functype>` :math:`F.\AMODULE.\MITYPES[y]`. | ||
|
||
8. Assert: due to :ref:`validation <valid-call_indirect>`, a value with :ref:`value type <syntax-valtype>` |I32| is on the top of the stack. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed. Also needed to change the consecutive line, since the table no longer contains a function address directly. The semantics of elem segments required a similar tweak.
document/core/exec/runtime.rst
Outdated
.. _syntax-val: | ||
|
||
Values | ||
~~~~~~ | ||
|
||
WebAssembly computations manipulate *values* of the four basic :ref:`value types <syntax-valtype>`: :ref:`integers <syntax-int>` and :ref:`floating-point data <syntax-float>` of 32 or 64 bit width each, respectively. | ||
WebAssembly computations manipulate *values* of the four basic :ref:`value types <syntax-valtype>`: :ref:`integers <syntax-int>` and :ref:`floating-point data <syntax-float>` of 32 or 64 bit width each, or of references, respectively. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed the wording.
document/core/exec/runtime.rst
Outdated
|
||
References other than null are represented with additional :ref:`administrative instructions <syntax-instr-admin>`. | ||
They either are *function references*, pointing to a specific :ref:`function address <syntax-funcaddr>`, | ||
or *host references* pointing to an unintrpreted form of :ref:`host address <syntax-hostaddr>` that can be defined by the :ref:`embedder <embedder>`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
@@ -147,7 +147,7 @@ The |MTABLES| component of a module defines a vector of *tables* described by th | |||
\{ \TTYPE~\tabletype \} \\ | |||
\end{array} | |||
|
|||
A table is a vector of opaque values of a particular table :ref:`element type <syntax-elemtype>`. | |||
A table is a vector of opaque values of a particular :ref:`reference type <syntax-reftype>`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that's right, except that ref.eq does not operate on tables but on references directly.
document/core/syntax/types.rst
Outdated
Reference Types | ||
~~~~~~~~~~~~~~~ | ||
|
||
*Reference types* classify |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, this actually was a half-finished edit.
document/core/valid/instructions.rst
Outdated
|
||
* Let :math:`\limits~t` be the :ref:`table type <syntax-tabletype>` :math:`C.\CTABLES[x]`. | ||
|
||
* Then the instruction is valid with type :math:`[] \to [t]`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
document/core/valid/instructions.rst
Outdated
|
||
* Let :math:`\limits~t` be the :ref:`table type <syntax-tabletype>` :math:`C.\CTABLES[x]`. | ||
|
||
* Then the instruction is valid with type :math:`[t] \to []`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
document/core/valid/instructions.rst
Outdated
C \vdashinstrseq \instr^\ast : [t_1^\ast] \to [t_0^\ast~t^\ast] | ||
C \vdashinstrseq \instr^\ast : [t_1^\ast] \to [t_0^\ast~{t'}^\ast] | ||
\qquad | ||
(\vdashvaltypematch t' \leq t)^\ast |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replaced it with a hyperlinked version.
document/core/appendix/algorithm.rst
Outdated
|
||
type val_type = I32 | I64 | F32 | F64 | Anyref | Anyfunc | Eqref | Nullref | ||
|
||
func is_ref(t : valtype) : bool = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: val_type
(function parameter)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
|
||
.. math:: | ||
\begin{array}{llclll} | ||
\production{element segment} & \Telem_I &::=& | ||
\text{(}~\text{elem}~~(x{:}\Ttableidx_I)^?~~\text{(}~\text{offset}~~e{:}\Texpr_I~\text{)}~~y^\ast{:}\Tvec(\Tfuncidx_I)~\text{)} \\ &&& \qquad | ||
\Rightarrow\quad \{ \ETABLE~x', \EOFFSET~e, \EINIT~y^\ast \} \\ | ||
&&& \qquad\qquad\qquad (\iff x' = x^? \neq \epsilon \vee x' = 0) \\ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might want to uplift this change to the v.1 spec as an editorial fix. The new way is much cleaner and I'm not even sure if the original expression parses...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, will do.
document/core/appendix/algorithm.rst
Outdated
@@ -70,7 +81,7 @@ However, these variables are not manipulated directly by the main checking funct | |||
let actual = pop_opd() | |||
if (actual = Unknown) return expect | |||
if (expect = Unknown) return actual | |||
error_if(actual =/= expect) | |||
error_if(not matches(actual, expect)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIUC, according to the validation rules, (select (ref.null) (get_table ...) (...))
is supposed to validate, since subtyping is applied to ref.null
when validating select
with t
= anyref
. To implement this, I think select
now needs special treatment below; I expect taking a meet of the two pop_opd()
s.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, good catch! This is not just for nullref, subtyping generally changes the way select needs to be handled. To simplify things, I refactored the pseudo code somewhat to make Unknown act more like a bottom type (which has been your view all along, I think :) ).
While fixing this I realised that subtyping also affects how br_table needs to be handled, so I incorporated respective changes as well.
document/core/syntax/types.rst
Outdated
|
||
The type |ANYFUNC| denotes the infinite union of all references to :ref:`functions <syntax-func>`, regardless of their :ref:`function types <syntax-functype>`. | ||
|
||
The type |EQREF| denotes the infinite union of all references that can be compared for equality; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bikeshed: for symmetry with the other any
*, could this perhaps be anyeqref
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
document/core/syntax/types.rst
Outdated
|
||
The type |NULLREF| only contains a single value: the :ref:`null <syntax-ref_null>` reference. | ||
It is a :ref:`subtype <match-reftype>` of all other reference types. | ||
The |NULLREF| type cannot be used in a program, it only occurs during :ref:`validation <valid>`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm trying to see how this is the case: as is, it appears that nullref
is a valtype
which means it can appear in function signatures and as the type of locals. So you can have silly expressions like:
(local $x nulltype)
(call $foo (tee_local $x (get_local $x)))
Instead of trying to introduce a validation-only type, can't we just have an operator reftype.null
where reftype
is later constrained by validation to only allow nullable types?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is prevented simply by not making nullref part of the "concrete" syntax, i.e., it cannot be expressed in either the binary or the text format. That could be made more explicit by separating it out from value types into a separate class used only for validation, but is it worth it? Alternatively, would a respective note suffice?
A syntax like <reftype>.null
cannot nicely be generalised to less primitive reference types. And it seems a bit wasteful to have separate null instructions for each type constructor, especially when they all necessarily produce the same value per subtyping.
We could type-annotate the instruction instead, but that also just seems unnecessary given that we're already buying into subtyping anyway. What the proposed semantics does mirrors the treatment of null expressions in most languages, e.g. Java or C++.
This seems like a point worth discussing at the April meeting.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah hah, I hadn't noticed nullref
wasn't part of concrete syntax! Yes, that does solve the problem rather elegantly in the spec. In the implementation, though, what will still be annoying is that we'll probably need separate valtype enums for what can appear in locals/signatures (the latter of which takes part in serialization and indirect call ABI matching so we need to be crystal clear about what the cases are) and for what can appear as part of validation. And we'll have to go back and forth between them and ask "which valtype enum do I use here?" and it's not a huge deal, but it'd be nice to avoid if there's not a downside.
And it seems a bit wasteful to have separate null instructions for each type constructor
For this I was assuming a single bytecode "null" followed by the reftype as an immediate (which handles both the primitive and compound types in the encoding)...
We could type-annotate the instruction instead, but that also just seems unnecessary given that we're already buying into subtyping anyway.
... which is what I think you mean here. Agreed we are necessarily buying into subtyping, the only difference here is that the other types will be present in the concrete syntax and so there's not really another option (other than, I suppose, removing subtyping in lieu of a static upcast
operator). With null, it seems like we have an option and the non-subtype route seems mildly simpler.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems like a point worth discussing at the April meeting.
Yeah, happy to discuss in the group. In the short-term, we were wanting to get going on a prototype impl of this proposal and, because of aforementioned valtype warts, we'd prefer to implement the type-parameterized null
. Could you perhaps flip the proposal to that so we can directly implement the proposal (knowing we might have to change if the proposal flips back)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, it's a few hours work on tests and interpreter, too, that I probably want to postpone until it's clear that I won't have to undo it shortly after. But I'm happy to hold back landing these PRs until the meeting. I don’t think that needs to block you from prototyping either version.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the review!
document/core/appendix/algorithm.rst
Outdated
@@ -70,7 +81,7 @@ However, these variables are not manipulated directly by the main checking funct | |||
let actual = pop_opd() | |||
if (actual = Unknown) return expect | |||
if (expect = Unknown) return actual | |||
error_if(actual =/= expect) | |||
error_if(not matches(actual, expect)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, good catch! This is not just for nullref, subtyping generally changes the way select needs to be handled. To simplify things, I refactored the pseudo code somewhat to make Unknown act more like a bottom type (which has been your view all along, I think :) ).
While fixing this I realised that subtyping also affects how br_table needs to be handled, so I incorporated respective changes as well.
document/core/syntax/types.rst
Outdated
|
||
The type |ANYFUNC| denotes the infinite union of all references to :ref:`functions <syntax-func>`, regardless of their :ref:`function types <syntax-functype>`. | ||
|
||
The type |EQREF| denotes the infinite union of all references that can be compared for equality; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
|
||
.. math:: | ||
\begin{array}{llclll} | ||
\production{element segment} & \Telem_I &::=& | ||
\text{(}~\text{elem}~~(x{:}\Ttableidx_I)^?~~\text{(}~\text{offset}~~e{:}\Texpr_I~\text{)}~~y^\ast{:}\Tvec(\Tfuncidx_I)~\text{)} \\ &&& \qquad | ||
\Rightarrow\quad \{ \ETABLE~x', \EOFFSET~e, \EINIT~y^\ast \} \\ | ||
&&& \qquad\qquad\qquad (\iff x' = x^? \neq \epsilon \vee x' = 0) \\ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, will do.
document/core/syntax/types.rst
Outdated
|
||
The type |NULLREF| only contains a single value: the :ref:`null <syntax-ref_null>` reference. | ||
It is a :ref:`subtype <match-reftype>` of all other reference types. | ||
The |NULLREF| type cannot be used in a program, it only occurs during :ref:`validation <valid>`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is prevented simply by not making nullref part of the "concrete" syntax, i.e., it cannot be expressed in either the binary or the text format. That could be made more explicit by separating it out from value types into a separate class used only for validation, but is it worth it? Alternatively, would a respective note suffice?
A syntax like <reftype>.null
cannot nicely be generalised to less primitive reference types. And it seems a bit wasteful to have separate null instructions for each type constructor, especially when they all necessarily produce the same value per subtyping.
We could type-annotate the instruction instead, but that also just seems unnecessary given that we're already buying into subtyping anyway. What the proposed semantics does mirrors the treatment of null expressions in most languages, e.g. Java or C++.
This seems like a point worth discussing at the April meeting.
First go at specifying the baseline proposal, analogous to #2:
anyref
andeqref
(and internalnullref
) and respective subtyping (splitting valtype into numtype and reftype)ref.null
,ref.isnull
,ref.eq
,get_table
,set_table
This change should already be complete, but opcodes are preliminary; names of table instruction might also be subject to change, depending on pending main spec PR.
Edit: Rendered version