-
Notifications
You must be signed in to change notification settings - Fork 35
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
Match delegate's immediate and label argument to those of branches #146
Comments
Sounds good to me! I think this is in line with my own previous assumptions as well. |
Thanks! Sounds like we are still on the same page. |
Thanks for the write-up. Looks good to me! |
Sounds good, that already was my assumption as well. |
Thanks for the clarification! It sounds good to me and I think it matches my mental model of the semantics. I just wanted to get clarification on one thing, sorry if I missed this somewhere in the write-up. If a |
@takikawa Yes, |
Full agreement from me too, @aheejin. |
This adds support for reading/writing of the new 'delegate' instruction in the folded wast format, the stack IR format, and the binary format in Binaryen. We don't have a format spec written down yet, but please refer to WebAssembly/exception-handling#137 and WebAssembly/exception-handling#146 for the informal semantics. In the current version of spec `delegate` is basically a rethrow, but with branch-like immediate argument so that it can bypass other catches/delegates in between. 'delegate' is not represented a new `Expression`, but it is rather an option within a `Try` class, like `catch`/`catch_all`. `delegate` semantically targets an outer `catch` or `delegate`, but we write `delegate` target as a `try` label because we only give labels to block-like scoping expressions. So far we has not given `Try` a label and used inner blocks or a wrapping block in case a branch targets the `try`. But in case of `delegate`, it can syntactically only target `try` and if it targets blocks or loops it is a validation failure. So after discussions in WebAssembly#3497, we give `Try` a label but this label can only be targeted by `delegate`s. Unfortunately this makes parsing and writing of `Try` expression somewhat complicated. Also there is one special case; if the immediate argument of `try` is the same as the depth of control flow stack, this means the 'delegate' delegates to the caller. To handle this case this adds a fake label `DELEGATE_CALLER_TARGET`, and when writing it back to the wast format writes it as an immediate value, unlike other cases in which we write labels. This uses `DELEGATE_FIELD_SCOPE_NAME_DEF/USE` to represent `try`'s label and `delegate`'s target. There are many cases that `try` and `delegate`'s labels need to be treated in the same way as block and branch labels, such as for hashing or comparing. But there are routines in which we automatically assume all label uses are branches. I thought about adding a new kind of defines such as `DELEGATE_FIELD_TRY_NAME_DEF/USE`, but I think it will also involve some duplication of existing routines or classes. So at the moment this PR chooses to use the existing `DELEGATE_FIELD_SCOPE_NAME_DEF/USE` for `try` and `delegate` labels and makes only necessary amount of changes in branch-utils. We can revisit this decision later if necessary. This only supports reading and writing and has not been tested against any optimization passes yet.
This adds support for reading/writing of the new 'delegate' instruction in the folded wast format, the stack IR format, and the binary format in Binaryen. We don't have a format spec written down yet, but please refer to WebAssembly/exception-handling#137 and WebAssembly/exception-handling#146 for the informal semantics. In the current version of spec `delegate` is basically a rethrow, but with branch-like immediate argument so that it can bypass other catches/delegates in between. 'delegate' is not represented a new `Expression`, but it is rather an option within a `Try` class, like `catch`/`catch_all`. One special thing about `delegate` is, even though it is written _within_ a `try` in the folded wat format, like ```wasm (try (do ... ) (delegate $l) ) ``` In the unfolded wat format or in the binary format, `delegate` serves as a scope end instruction so there is no separate `end`: ```wasm try ... delegate $l ``` `delegate` semantically targets an outer `catch` or `delegate`, but we write `delegate` target as a `try` label because we only give labels to block-like scoping expressions. So far we has not given `Try` a label and used inner blocks or a wrapping block in case a branch targets the `try`. But in case of `delegate`, it can syntactically only target `try` and if it targets blocks or loops it is a validation failure. So after discussions in WebAssembly#3497, we give `Try` a label but this label can only be targeted by `delegate`s. Unfortunately this makes parsing and writing of `Try` expression somewhat complicated. Also there is one special case; if the immediate argument of `try` is the same as the depth of control flow stack, this means the 'delegate' delegates to the caller. To handle this case this adds a fake label `DELEGATE_CALLER_TARGET`, and when writing it back to the wast format writes it as an immediate value, unlike other cases in which we write labels. This uses `DELEGATE_FIELD_SCOPE_NAME_DEF/USE` to represent `try`'s label and `delegate`'s target. There are many cases that `try` and `delegate`'s labels need to be treated in the same way as block and branch labels, such as for hashing or comparing. But there are routines in which we automatically assume all label uses are branches. I thought about adding a new kind of defines such as `DELEGATE_FIELD_TRY_NAME_DEF/USE`, but I think it will also involve some duplication of existing routines or classes. So at the moment this PR chooses to use the existing `DELEGATE_FIELD_SCOPE_NAME_DEF/USE` for `try` and `delegate` labels and makes only necessary amount of changes in branch-utils. We can revisit this decision later if necessary. Many of changes to the existing test cases are because now all `try`s are automatically assigned a label. They will be removed in `RemoveUnusedNames` pass in the same way as block labels if not targeted by any delegates. This only supports reading and writing and has not been tested against any optimization passes yet.
This adds support for reading/writing of the new 'delegate' instruction in the folded wast format, the stack IR format, and the binary format in Binaryen. We don't have a format spec written down yet, but please refer to WebAssembly/exception-handling#137 and WebAssembly/exception-handling#146 for the informal semantics. In the current version of spec `delegate` is basically a rethrow, but with branch-like immediate argument so that it can bypass other catches/delegates in between. 'delegate' is not represented a new `Expression`, but it is rather an option within a `Try` class, like `catch`/`catch_all`. One special thing about `delegate` is, even though it is written _within_ a `try` in the folded wat format, like ```wasm (try (do ... ) (delegate $l) ) ``` In the unfolded wat format or in the binary format, `delegate` serves as a scope end instruction so there is no separate `end`: ```wasm try ... delegate $l ``` `delegate` semantically targets an outer `catch` or `delegate`, but we write `delegate` target as a `try` label because we only give labels to block-like scoping expressions. So far we has not given `Try` a label and used inner blocks or a wrapping block in case a branch targets the `try`. But in case of `delegate`, it can syntactically only target `try` and if it targets blocks or loops it is a validation failure. So after discussions in WebAssembly#3497, we give `Try` a label but this label can only be targeted by `delegate`s. Unfortunately this makes parsing and writing of `Try` expression somewhat complicated. Also there is one special case; if the immediate argument of `try` is the same as the depth of control flow stack, this means the 'delegate' delegates to the caller. To handle this case this adds a fake label `DELEGATE_CALLER_TARGET`, and when writing it back to the wast format writes it as an immediate value, unlike other cases in which we write labels. This uses `DELEGATE_FIELD_SCOPE_NAME_DEF/USE` to represent `try`'s label and `delegate`'s target. There are many cases that `try` and `delegate`'s labels need to be treated in the same way as block and branch labels, such as for hashing or comparing. But there are routines in which we automatically assume all label uses are branches. I thought about adding a new kind of defines such as `DELEGATE_FIELD_TRY_NAME_DEF/USE`, but I think it will also involve some duplication of existing routines or classes. So at the moment this PR chooses to use the existing `DELEGATE_FIELD_SCOPE_NAME_DEF/USE` for `try` and `delegate` labels and makes only necessary amount of changes in branch-utils. We can revisit this decision later if necessary. Many of changes to the existing test cases are because now all `try`s are automatically assigned a label. They will be removed in `RemoveUnusedNames` pass in the same way as block labels if not targeted by any delegates. This only supports reading and writing and has not been tested against any optimization passes yet.
This adds support for reading/writing of the new 'delegate' instruction in the folded wast format, the stack IR format, and the binary format in Binaryen. We don't have a format spec written down yet, but please refer to WebAssembly/exception-handling#137 and WebAssembly/exception-handling#146 for the informal semantics. In the current version of spec `delegate` is basically a rethrow, but with branch-like immediate argument so that it can bypass other catches/delegates in between. 'delegate' is not represented a new `Expression`, but it is rather an option within a `Try` class, like `catch`/`catch_all`. One special thing about `delegate` is, even though it is written _within_ a `try` in the folded wat format, like ```wasm (try (do ... ) (delegate $l) ) ``` In the unfolded wat format or in the binary format, `delegate` serves as a scope end instruction so there is no separate `end`: ```wasm try ... delegate $l ``` `delegate` semantically targets an outer `catch` or `delegate`, but we write `delegate` target as a `try` label because we only give labels to block-like scoping expressions. So far we has not given `Try` a label and used inner blocks or a wrapping block in case a branch targets the `try`. But in case of `delegate`, it can syntactically only target `try` and if it targets blocks or loops it is a validation failure. So after discussions in WebAssembly#3497, we give `Try` a label but this label can only be targeted by `delegate`s. Unfortunately this makes parsing and writing of `Try` expression somewhat complicated. Also there is one special case; if the immediate argument of `try` is the same as the depth of control flow stack, this means the 'delegate' delegates to the caller. To handle this case this adds a fake label `DELEGATE_CALLER_TARGET`, and when writing it back to the wast format writes it as an immediate value, unlike other cases in which we write labels. This uses `DELEGATE_FIELD_SCOPE_NAME_DEF/USE` to represent `try`'s label and `delegate`'s target. There are many cases that `try` and `delegate`'s labels need to be treated in the same way as block and branch labels, such as for hashing or comparing. But there are routines in which we automatically assume all label uses are branches. I thought about adding a new kind of defines such as `DELEGATE_FIELD_TRY_NAME_DEF/USE`, but I think it will also involve some duplication of existing routines or classes. So at the moment this PR chooses to use the existing `DELEGATE_FIELD_SCOPE_NAME_DEF/USE` for `try` and `delegate` labels and makes only necessary amount of changes in branch-utils. We can revisit this decision later if necessary. Many of changes to the existing test cases are because now all `try`s are automatically assigned a label. They will be removed in `RemoveUnusedNames` pass in the same way as block labels if not targeted by any delegates. This only supports reading and writing and has not been tested against any optimization passes yet.
This adds support for reading/writing of the new 'delegate' instruction in the folded wast format, the stack IR format, the poppy IR format, and the binary format in Binaryen. We don't have a format spec written down yet, but please refer to WebAssembly/exception-handling#137 and WebAssembly/exception-handling#146 for the informal semantics. In the current version of spec `delegate` is basically a rethrow, but with branch-like immediate argument so that it can bypass other catches/delegates in between. 'delegate' is not represented a new `Expression`, but it is rather an option within a `Try` class, like `catch`/`catch_all`. One special thing about `delegate` is, even though it is written _within_ a `try` in the folded wat format, like ```wasm (try (do ... ) (delegate $l) ) ``` In the unfolded wat format or in the binary format, `delegate` serves as a scope end instruction so there is no separate `end`: ```wasm try ... delegate $l ``` `delegate` semantically targets an outer `catch` or `delegate`, but we write `delegate` target as a `try` label because we only give labels to block-like scoping expressions. So far we has not given `Try` a label and used inner blocks or a wrapping block in case a branch targets the `try`. But in case of `delegate`, it can syntactically only target `try` and if it targets blocks or loops it is a validation failure. So after discussions in WebAssembly#3497, we give `Try` a label but this label can only be targeted by `delegate`s. Unfortunately this makes parsing and writing of `Try` expression somewhat complicated. Also there is one special case; if the immediate argument of `try` is the same as the depth of control flow stack, this means the 'delegate' delegates to the caller. To handle this case this adds a fake label `DELEGATE_CALLER_TARGET`, and when writing it back to the wast format writes it as an immediate value, unlike other cases in which we write labels. This uses `DELEGATE_FIELD_SCOPE_NAME_DEF/USE` to represent `try`'s label and `delegate`'s target. There are many cases that `try` and `delegate`'s labels need to be treated in the same way as block and branch labels, such as for hashing or comparing. But there are routines in which we automatically assume all label uses are branches. I thought about adding a new kind of defines such as `DELEGATE_FIELD_TRY_NAME_DEF/USE`, but I think it will also involve some duplication of existing routines or classes. So at the moment this PR chooses to use the existing `DELEGATE_FIELD_SCOPE_NAME_DEF/USE` for `try` and `delegate` labels and makes only necessary amount of changes in branch-utils. We can revisit this decision later if necessary. Many of changes to the existing test cases are because now all `try`s are automatically assigned a label. They will be removed in `RemoveUnusedNames` pass in the same way as block labels if not targeted by any delegates. This only supports reading and writing and has not been tested against any optimization passes yet.
As clarified in: WebAssembly/exception-handling#146 the delegate target cannot be a `block` or `loop`. This commit also adds a failure test that covers several cases discussed in that issue.
Can we assume Associated with the For example consider the following: try
...
catch 1
...
block
...
try
...
catch 2
...
try
...
catch 3
...
rethrow N
end
end
end
...
end In this example, Note that I didn't invent this rule for the explainer myself; I simply restored the old rule from the very first version of the spec, which is similar to the current spec except the current spec has try $label1
...
catch ($label1)
...
block $label2
...
try $label3
...
catch ($label3)
...
try $label4
...
catch ($label4)
...
;; These two rethrow the exception caught by catch ($label4)
rethrow $label4
rethrow 0
;; These two rethrow the exception caught by catch ($label3)
rethrow $label3
rethrow 1
;; These correspond to the block $label2, so validation failure
rethrow $label2
rethrow 2
;; These two rethrow the exception caught by catch ($label1)
rethrow $label1
rethrow 3
end
end
end
...
end Do we also agree on this? |
Oh, also, to make try $label1
...
catch ($label1)
...
block $label2
...
try $label3
...
catch ($label3)
...
try $label4
...
;; These two refers to 'catch (label$4)', but it is not within 'catch (label$4)', so validation failure
rethrow $label4
rethrow 0
;; These two rethrow the exception caught by catch ($label3)
rethrow $label3
rethrow 1
;; These correspond to the block $label2, so validation failure
rethrow $label2
rethrow 2
;; These two rethrow the exception caught by catch ($label1)
rethrow $label1
rethrow 3
catch ($label4)
...
;; These two rethrow the exception caught by catch ($label4)
rethrow $label4
rethrow 0
;; These two rethrow the exception caught by catch ($label3)
rethrow $label3
rethrow 1
;; These correspond to the block $label2, so validation failure
rethrow $label2
rethrow 2
;; These two rethrow the exception caught by catch ($label1)
rethrow $label1
rethrow 3
end
end
end
...
end |
Thanks for the examples, they still match my expectation and V8's implementation so far. |
@aheejin Thanks for clarifying this. Based on previous examples from this PR (example 2 there) my understanding had been that the current interpretation was that But I'm also happy to implement this interpretation of the |
This adds support for reading/writing of the new `delegate` instruction in the folded wast format, the stack IR format, the poppy IR format, and the binary format in Binaryen. We don't have a formal spec written down yet, but please refer to WebAssembly/exception-handling#137 and WebAssembly/exception-handling#146 for the informal semantics. In the current version of spec `delegate` is basically a rethrow, but with branch-like immediate argument so that it can bypass other catches/delegates in between. `delegate` is not represented as a new `Expression`, but it is rather an option within a `Try` class, like `catch`/`catch_all`. One special thing about `delegate` is, even though it is written _within_ a `try` in the folded wat format, like ```wasm (try (do ... ) (delegate $l) ) ``` In the unfolded wat format or in the binary format, `delegate` serves as a scope end instruction so there is no separate `end`: ```wasm try ... delegate $l ``` `delegate` semantically targets an outer `catch` or `delegate`, but we write `delegate` target as a `try` label because we only give labels to block-like scoping expressions. So far we have not given `Try` a label and used inner blocks or a wrapping block in case a branch targets the `try`. But in case of `delegate`, it can syntactically only target `try` and if it targets blocks or loops it is a validation failure. So after discussions in #3497, we give `Try` a label but this label can only be targeted by `delegate`s. Unfortunately this makes parsing and writing of `Try` expression somewhat complicated. Also there is one special case; if the immediate argument of `try` is the same as the depth of control flow stack, this means the 'delegate' delegates to the caller. To handle this case this adds a fake label `DELEGATE_CALLER_TARGET`, and when writing it back to the wast format writes it as an immediate value, unlike other cases in which we write labels. This uses `DELEGATE_FIELD_SCOPE_NAME_DEF/USE` to represent `try`'s label and `delegate`'s target. There are many cases that `try` and `delegate`'s labels need to be treated in the same way as block and branch labels, such as for hashing or comparing. But there are routines in which we automatically assume all label uses are branches. I thought about adding a new kind of defines such as `DELEGATE_FIELD_TRY_NAME_DEF/USE`, but I think it will also involve some duplication of existing routines or classes. So at the moment this PR chooses to use the existing `DELEGATE_FIELD_SCOPE_NAME_DEF/USE` for `try` and `delegate` labels and makes only necessary amount of changes in branch-utils. We can revisit this decision later if necessary. Many of changes to the existing test cases are because now all `try`s are automatically assigned a label. They will be removed in `RemoveUnusedNames` pass in the same way as block labels if not targeted by any delegates. This only supports reading and writing and has not been tested against any optimization passes yet. --- Original unfolded wat file to generate test/try-delegate.wasm: ```wasm (module (event $e) (func try try delegate 0 catch $e end) (func try try catch $e i32.const 0 drop try delegate 1 end catch $e end ) ) ```
I previously assumed `delegate`'s immediate argument computation followed a different rule than that of branches, but we agreed to make it the same (WebAssembly/exception-handling#146). This removes the need for a separate `DelegateStack` in both CFGStackify and InstPrinter. When computing the immediate argument, we use a different function for `delegate` computation because in MIR `DELEGATE`'s instruction's destination is the destination catch BB or delegate BB, and when it is a catch BB, we need an additional step of getting its corresponding `end` marker. Reviewed By: tlively, dschuff Differential Revision: https://reviews.llvm.org/D96525
@takikawa Sorry, yeah, I was mistaken about the rule too, but while discussing the impl with @thibaudmichaud I realized the Explainer says it uses the same rule with branches (and delegates). |
Previously we assumed `rethrow`'s argument was always 0, but it turned out `rethrow` follows the same rule with `br` or `delegate`: WebAssembly/exception-handling#137 WebAssembly/exception-handling#146 (comment) Currently `rethrow`s generated by our backend always rethrow the exception caught by the innermost enclosing catch, so this adds a function to compute that and replaces `rethrow`'s argument with its computed result. This also renames `EHPadStack` in `InstPrinter` to `TryStack`, because in CFGStackify we use `EHPadStack` to mean the range between `catch`~`end`, while in `InstPrinter` we used it to mean the range between `try`~`catch`, so choosing different names would look clearer. Doesn't contain any functional changes in `InstPrinter`. Reviewed By: dschuff Differential Revision: https://reviews.llvm.org/D96595
I was previously mistaken about `rethrow`'s argument rule and thoought it only counted `catch`'s depth. But it turns out it follows the same rule `delegate`'s label: the immediate argument follows the same rule as when computing branch labels, but it only can target `try` labels (semantically it targets that `try`'s corresponding `catch`); otherwise it will be a validation failure. Unlike `delegate`, `rethrow`'s label denotes not where to rethrow, but which exception to rethrow. For example, ```wasm try $l0 catch ($l0) try $l1 catch ($l1) rethrow $l0 ;; rethrow the exception caught by 'catch ($l0)' end end ``` Refer to this comment for the more detailed informal semantics: WebAssembly/exception-handling#146 (comment)
I was previously mistaken about `rethrow`'s argument rule and thought it only counted `catch`'s depth. But it turns out it follows the same rule with `delegate`'s label: the immediate argument is comptuted in the same way as branch labels, but it only can target `try` labels (semantically it targets that `try`'s corresponding `catch`); otherwise it will be a validation failure. Unlike `delegate`, `rethrow`'s label denotes not where to rethrow, but which exception to rethrow. For example, ```wasm try $l0 catch ($l0) try $l1 catch ($l1) rethrow $l0 ;; rethrow the exception caught by 'catch ($l0)' end end ``` Refer to this comment for the more detailed informal semantics: WebAssembly/exception-handling#146 (comment)
I was previously mistaken about `rethrow`'s argument rule and thought it only counted `catch`'s depth. But it turns out it follows the same rule with `delegate`'s label: the immediate argument is comptuted in the same way as branch labels, but it only can target `try` labels (semantically it targets that `try`'s corresponding `catch`); otherwise it will be a validation failure. Unlike `delegate`, `rethrow`'s label denotes not where to rethrow, but which exception to rethrow. For example, ```wasm try $l0 catch ($l0) try $l1 catch ($l1) rethrow $l0 ;; rethrow the exception caught by 'catch ($l0)' end end ``` Refer to this comment for the more detailed informal semantics: WebAssembly/exception-handling#146 (comment)
I was previously mistaken about `rethrow`'s argument rule and thought it only counted `catch`'s depth. But it turns out it follows the same rule with `delegate`'s label: the immediate argument is comptuted in the same way as branch labels, but it only can target `try` labels (semantically it targets that `try`'s corresponding `catch`); otherwise it will be a validation failure. Unlike `delegate`, `rethrow`'s label denotes not where to rethrow, but which exception to rethrow. For example, ```wasm try $l0 catch ($l0) try $l1 catch ($l1) rethrow $l0 ;; rethrow the exception caught by 'catch ($l0)' end end ``` Refer to this comment for the more detailed informal semantics: WebAssembly/exception-handling#146 (comment) This also reverses some of `delegateTarget` -> `exceptionTarget` changes done in WebAssembly#3562 in the validator. Label validation rules apply differently for `delegate` and `rethrow` for try-catch. For example, this is valid: ```wasm try $l0 try delegate $l0 catch ($l0) end ``` But this is NOT valid: ```wasm try $l0 catch ($l0) try delegate $l0 end ``` So `try`'s label should be used within try-catch range (not catch-end range) for `delegate`s. But for the `rethrow` the rule is different. For example, this is valid: ```wasm try $l0 catch ($l0) rethrow $l0 end ``` But this is NOT valid: ```wasm try $l0 rethrow $l0 catch ($l0) end ``` So the `try`'s label should be used within catch-end range instead.
I was previously mistaken about `rethrow`'s argument rule and thought it only counted `catch`'s depth. But it turns out it follows the same rule `delegate`'s label: the immediate argument follows the same rule as when computing branch labels, but it only can target `try` labels (semantically it targets that `try`'s corresponding `catch`); otherwise it will be a validation failure. Unlike `delegate`, `rethrow`'s label denotes not where to rethrow, but which exception to rethrow. For example, ```wasm try $l0 catch ($l0) try $l1 catch ($l1) rethrow $l0 ;; rethrow the exception caught by 'catch ($l0)' end end ``` Refer to this comment for the more detailed informal semantics: WebAssembly/exception-handling#146 (comment) --- This also reverts some of `delegateTarget` -> `exceptionTarget` changes done in #3562 in the validator. Label validation rules apply differently for `delegate` and `rethrow` for try-catch. For example, this is valid: ```wasm try $l0 try delegate $l0 catch ($l0) end ``` But this is NOT valid: ```wasm try $l0 catch ($l0) try delegate $l0 end ``` So `try`'s label should be used within try-catch range (not catch-end range) for `delegate`s. But for the `rethrow` the rule is different. For example, this is valid: ```wasm try $l0 catch ($l0) rethrow $l0 end ``` But this is NOT valid: ```wasm try $l0 rethrow $l0 catch ($l0) end ``` So the `try`'s label should be used within catch-end range instead.
@aheejin SGTM too! I am updating the formal-spec-overview now, and it seems the semantics as agreed in this issue do make things simpler. Although we're back to a new attribute (this time I call it |
As clarified in: WebAssembly/exception-handling#146 the delegate target cannot be a `block` or `loop`. This commit also adds a failure test that covers several cases discussed in that issue.
This adds the changes decided in WebAssembly#176 and adds a modified version from WebAssembly#146 (comment) for clarification. (The example is not the same by the way; the `catch` from the outermost `try` has been moved) Closes WebAssembly#176.
This adds the changes decided in WebAssembly#176 and adds a modified version from WebAssembly#146 (comment) for clarification. (The example is not the same by the way; the `catch` from the outermost `try` has been moved) Closes WebAssembly#176.
This adds the changes decided in #176 and adds a modified version from #146 (comment) for clarification. (The example is not the same by the way; the `catch` from the outermost `try` has been moved)
I previously assumed `delegate`'s immediate argument computation followed a different rule than that of branches, but we agreed to make it the same (WebAssembly/exception-handling#146). This removes the need for a separate `DelegateStack` in both CFGStackify and InstPrinter. When computing the immediate argument, we use a different function for `delegate` computation because in MIR `DELEGATE`'s instruction's destination is the destination catch BB or delegate BB, and when it is a catch BB, we need an additional step of getting its corresponding `end` marker. Reviewed By: tlively, dschuff Differential Revision: https://reviews.llvm.org/D96525
Previously we assumed `rethrow`'s argument was always 0, but it turned out `rethrow` follows the same rule with `br` or `delegate`: WebAssembly/exception-handling#137 WebAssembly/exception-handling#146 (comment) Currently `rethrow`s generated by our backend always rethrow the exception caught by the innermost enclosing catch, so this adds a function to compute that and replaces `rethrow`'s argument with its computed result. This also renames `EHPadStack` in `InstPrinter` to `TryStack`, because in CFGStackify we use `EHPadStack` to mean the range between `catch`~`end`, while in `InstPrinter` we used it to mean the range between `try`~`catch`, so choosing different names would look clearer. Doesn't contain any functional changes in `InstPrinter`. Reviewed By: dschuff Differential Revision: https://reviews.llvm.org/D96595
The current explainer has a detailed example on `delegate`, which was adapted from WebAssembly#146 (comment), but not the one for `rethrow` from the same issue (WebAssembly#146 (comment)). This adds the detailed `rethrow` example to the explainer, with the some cosmetic changes to the label names and comments.
The current explainer has a detailed example on `delegate`, which was adapted from #146 (comment), but not the one for `rethrow` from the same issue (#146 (comment)). This adds the detailed `rethrow` example to the explainer, with the some cosmetic changes to the label names and comments.
I'd like to suggest a slight change to the current seemingly discussed spec in #143 so that we can treat the target of
br
s anddelegate
s in a similar way in the wast format. I think this will help reading and writing the wast format and spec tests.I'm not actually very sure if this will be a suggestion to change, because after discussions w/ @thibaudmichaud I realized my understanding was different from his and what I'd like to suggest here was actually already more in line with his V8
implementation. (Now I think we two are on the same page.)
So what I'd like to achieve is we can write the argument of
delegate
as labels in the wast format, as we do forbr
/br_if
s, and makedelegate
can syntactically target atry
, which semantically in turn goes to thattry
's correspondingcatch
.delegate
's immediate argument is translated to the labels in the same way we do forbr
s. Let me illustrate that with an example. I annotatedcatch
es with their correspondingtry
's labels just to make it more readable. The example looks a bit long, but please bear with me:(catches can be either
catch
orcatch_all
, it doesn't really matter here.unwind
will be treated the same.)So what I propose is basically this: Treat
delegate
's immediate/label in the same way asbr
's immediate/label.delegate
also can target any ofblock
/loop
/try
, but if the target is ablock
orloop
it is a validation failure. (I think this was discussed somewhat already in #143).If the target is a
try
, if thetry
's correspondingcatch
is below thedelegate
as in the firstdelegate 0
in my example, it delegates to thatcatch
. If the correspondingcatch
is above thedelegate
as in the seconddelegate 0
in my example, we can't delegate to somewhere upwards, so it is a validation failure. Please notice the difference between twodelegate 0
's interpretation in my example. But the advantage of this format is we can maintain a single control flow stack, and use labels and immediates interchangeably in the wast format as we already do forbr
/br_if
. In my examplebr
s are just written to show that whenbr
's immediate anddelegate
's immediate are the same, their label arguments will also be the same.Also, when there are multiple
catch
/catch_all
s pertry
, they are treated as a chunk. Sodelegate 0
here targets $labelA's all catches as a chunk. Becausecatch tag_a
is above thisdelegate 0
, this is rather a validation failure, and it does not delegate tocatch tag_b
orcatch_all
below.I'm not necessarily trying to discuss the formal spec yet; if we are all on the same page on the operational semantics in informal English, I think we can proceed to the format version.
WDYT? cc @thibaudmichaud @backes @ioannad @takikawa @tlively
The text was updated successfully, but these errors were encountered: