-
Notifications
You must be signed in to change notification settings - Fork 36
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
Formal overview address latest review #205
Formal overview address latest review #205
Conversation
@aheejin about your question in the last comment of that discussion:
I think the reason for putting the label outside of adm.delegate was so that it's similar to what happens in |
Well, I don't know, I would very much prefer to avoid non-standard premises talking about the size or depending on the ordering of the context, which is a bit of an abstraction leak. Note that the condition @aheejin is right that it would be natural and solve the problem to nest label and admin delegate the other way around. You are also right that the current reduction keeps it symmetric with catch. But that was itself a hack, so it may be better to keep that confined to catch. WDYT? |
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.
Sorry for the late reply.
It would be probably better to split out the other non-delegate
-related parts into another PR and commit it, so this PR only concerns delegate
..?
So I think the correct rule for try-delegate should be the following (previously the 3rd premise was
C.labels[l] = [t'*]
, which was equivalent to|C.labels| > l
).
Does this account for the added label
in delegate
's execution semantics, which @rossberg was concerned about?
Note that the condition
|C.labels| >= l
is technically equivalent to sayingC.labels[l] = t*
for somet*
, so it should be fine to keep the latter – we could easily prove a lemma saying that ifC.labels[l+1] = t*
then C.labels[l] = t'*`, which would make your previous formulation work.
Can this handle the the case @ioannad described, in which delegate N
delegates to the caller? For example,
(func $test
(try
(do
...
)
(delegate 0)
)
)
given that there's no label this delegate
targets within this function? Or, do we implicitly push a label when a function is entered in the formal spec?
How do we handle br
without a block
? Is that a validation failure?
(func $test
(br 0)
)
Is this a validation failure or it just exits the function?
@@ -152,34 +154,34 @@ An absent tag address in a `catch` administrative instruction (i.e., `a? = ε`) | |||
``` | |||
F; throw x ↪ F; throw a (if F.module.tagaddrs[x]=a) | |||
|
|||
caught{a val^n} B^l[rethrow l] end | |||
↪ caught{a val^n} B^l[val^n (throw a)] end | |||
caught{a val*} B^l[rethrow l] end |
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.
In the formal spec, when do we use ^n
and when do we use *
? Can they be used interchangeably? I see both notations in the current (standardized) formal spec and I'm not very familiar with the formal notation, so..
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 we use ^n
when the n
has a constraint in the rule it is mentioned, but I think in the formal spec document this is not always the case.
This change is to implement exactly this idea, so to only use the n
if it has a particular constraint, as it does for example in lines 163-164.
I think that this change makes the formal overview a bit more concise, as I see the formal overview as a "cheatsheet" for Wasm exceptions.
Also I wasn't able to follow every argument from https://github.com/WebAssembly/exception-handling/pull/143/files#r759907998, partly due to I wasn't able to understand this rule.
Why is |
Yes, a function creates an implicit outermost label. |
For (func $test
try
delegate 0 ;; throw to the caller
try
delegate N ;; For any N >= 1. Do we allow this?
) In this case (func $test
br 0 ;; allowed
br N ;; N >= 1 is not allowed
) |
Ah right, I was confused. Thanks, then I think we should assume we don't allow unbound labels. (Maybe I was the only one who was assuming we were allowing this anyway) |
@ioannad Gentle ping :) Are you planning to update this soon? |
Apologies for the long silence @aheejin ! |
I don't understand why is "
I haven't checked all the details yet, but now I think this should work fine. |
@ioannad, oops, you are right, I missed the =. Rather, |
a236e95
to
ba7edb6
Compare
Just rebased but I see something went wrong there, fixing... Still todo: haven't finished switching to @aheejin's suggestion yet - checking the examples work as expected. |
This is not the suggestion given in that last review of WebAssembly#143: https://github.com/WebAssembly/exception-handling/pull/143/files#r759907998 but a potential fix of the issue raised there.
ba7edb6
to
46d3f94
Compare
…to formal-overview-address-latest-review
The original review comment: https://github.com/WebAssembly/exception-handling/pull/143/files#r759907998 The explanation line clarifies what happens if the label targets the frame, and what labels are allowed.
@aheejin, @rossberg, I tried to implement this in the interpreter and ran into some issues that I'm not sure how to resolve, although they are probably solvable. In order to keep things confined and more easily searchable (so to not have a too long discussion in the PR or inline), I will make a new PR dedicated to that change, in which I will also include the changes I tried in the interpreter, and more details. To wrap up this PR, I reverted the changes involving the length of |
@rossberg, reading again this comment of the original discussion in #143, I am thinking that your objection may be in using Am I reading that comment correctly, so is it the case that you think that the typing rule for
Or am I misunderstanding that comment? |
I'm also wondering about this. Only changing
And what @rossberg said in https://github.com/WebAssembly/exception-handling/pull/143/files#r811680384 was:
So we should change the LHS to |
@ioannad, you are right, the first premise needs changing as well – the added label is wrong there, since that's added by the surrounding |
@ioannad Can we make the change and merge it? |
…ests) [Currently](https://github.com/WebAssembly/exception-handling/blob/main/proposals/exception-handling/Exceptions-formal-overview.md) `(try ... delegate l)` reduces to `(label_n{} ( delegate{l} ... end ) end)`, so by putting a label outside (i.e., before) the administrative `delegate{l}`. An idea proposed in past [unresolved](WebAssembly#205 (comment)) [discussions](https://github.com/WebAssembly/exception-handling/pull/143/files#r812476148) of WebAssembly#205 and WebAssembly#143, is to simplify and improve the formalism by instead putting the delegate label inside (i.e., after) the `delegate{l}`. So instead to reduce to `(delegate{l} ( label_n{} ... end ) end)`. TL;DR ----- I can't seem to make it work. This PR explored an approach to implement this idea, in the [formal overview file ](https://github.com/WebAssembly/exception-handling/blob/main/proposals/exception-handling/Exceptions-formal-overview.md), as well as in the interpreter, but had failing tests which I wasn't able to fix. Perhaps I'm overseeing some other solution or approach, or there is some mistake in the interpreter implementation and/or argumentation below. Details ------- I think the problem is as follows. With the current [definition of block contexts](https://webassembly.github.io/exception-handling/core/exec/runtime.html#block-contexts), the instruction sequence `B^l[ delegate{l} T[val^n (throw a)] end ]` not only is ambiguous, but doesn't work with a try-catch label located outside of the try-catch. Take for example the following possible reduction. ``` (try (try (throw x) delegate 0) catch x end) ↪ (label_0{} (catch{a_x ε} (delegate{0} (label_0{} (throw a_x) end) end) end) end) ``` The intention for this delegate is to throw inside the handler `catch{a_x ε}` and be caught there. However, a possible `B^0` for the reduction of `delegate{0}` is `B^0 = [_] catch{a_x ε}`, in which case the reduction rule gives the following. ``` ↪ (label_0{} (throw a_x) end) ↪ (throw a_x) ``` The issue here seems to be that there is no label between the `delegate{l}` and the `catch{...}`. Perhaps there is a different change we can easily make it work, for example changing control contexts or block contexts? Failing tests ............. We can observe the above wrong behaviour also in the interpreter tests, although this could be fixable somehow. In particular, the first commit of this PR has the formal overview changes also implemented in the execution steps of the interpreter (in `interpreter/exec/eval.ml`): - The reduction of `try ... delegate l` puts the `label{}` after the `delegate{l}`. - The reduction of `delegate{l}` does not pattern match for an initial label. I tried to minimise a failing test from `test/core/try_delegate.wast` in the file `test/core/try_delegate_minimal_fail.wast`. To reproduce the failure build the interpreter and run the above test file as follows, for example from a Linux terminal in the base directory of the repository: ``` cd interpreter make ./wasm ../test/core/try_delegate_minimal_fail.wast ``` See also comments in the test file.
This PR attempts to address @rossberg 's last review on merged PR#143, and makes some extra changes for readability, and documentation.
@rossberg @aheejin
Continuing here the last discussion from the merged PR #143, because that PR is closed and difficult to follow.
The change to remove the +1 from the typing rule of the administrative delegate (will call it adm.delegate) was related to the decision to allow a plain
(try bt instr* delegate 0)
in the function body. It seems I forgot to update the typing rule for try-delegate itself to be in accord with that decision.So I think the correct rule for try-delegate should be the following (previously the 3rd premise was
C.labels[l] = [t'*]
, which was equivalent to|C.labels| > l
).This way, a context with an empty labels vector can validate this even for
l=0
.If we now rewrite the typing rule of adm.delegate in the same style it becomes:
So perhaps there was no +1 missing from this rule, but a label too many in the typing rule of try.delegate?
Question
try-delegate
addresses your concerns with regard to type preservation?