Skip to content

Commit

Permalink
Reflect spec changes in delegate immediate operand (#178)
Browse files Browse the repository at this point in the history
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)
  • Loading branch information
aheejin authored Sep 15, 2021
1 parent ea7f2c0 commit c830a2f
Showing 1 changed file with 101 additions and 20 deletions.
121 changes: 101 additions & 20 deletions proposals/exception-handling/Exceptions.md
Original file line number Diff line number Diff line change
Expand Up @@ -274,10 +274,10 @@ try label and delegates exception handling to a `catch`/`catch_all`/`delegate`
specified by the `try` label. For example, consider this code:

```
try $l1
try $l0
try
call $foo
delegate $l1 ;; (= delegate 0)
delegate $l0 ;; (= delegate 0)
catch
...
catch_all
Expand All @@ -288,28 +288,109 @@ end
If `call $foo` throws, searching for a catching block first finds `delegate`,
and because it delegates exception handling to catching instructions associated
with `$l1`, it will be next checked by the outer `catch` and then `catch_all`
instructions. When the specified label within a `delegate` instruction does not
correspond to a `try` instruction, it is a validation failure.
instructions.

`delegate` can also target `catch`-less `try`s or non-`try` block constructs
like `block`s or `loop`s, in which case the delegated exception is assumed to
propagate to the outer scope and will be caught by the next matching
try-catches, or rethrown to the caller if there is no outer try block. In the
examples, catches are annotated with `($label_name)` to clarify which `try` it
belongs to for clarification; it is not the official syntax.
```
try $l0
block $l1
try
call $foo
delegate $l1 ;; delegates to 'catch ($l0)'
end
catch ($l0)
end
```

Like branches, `delegate` can only target outer blocks, and effectively
rethrows the exception in that block. Consequently, delegating to a specific
`catch` or `catch_all` handler requires targeting the respective label from
within the associated `try` block. Delegating to a label from within a `catch`
block does delegate the exception to the next enclosing handler -- analogous to
performing a `throw` within a `catch` block, that handler is no longer active
at that point. Here is another example:

Note that the example below is a validation failure:
```
try $l1
catch
try $l0
try $l1
catch ($l1)
try
call $foo
delegate $l1 ;; delegates to 'catch ($l0)'
catch_all
...
end
catch ($l0)
```

Here the `delegate` is targeting `catch ($l1)`, which exists before the
`delegate`. So in case an exception occurs, it propagates out and ends up
targetting `catch ($l0)`, if the catch has a matching tag. If not, it will
propagate further out. Even if the `catch_all` is below the `delegate`,
`delegate` targets catches of a `try` as a whole and does not target an
individual `catch`/`catch_all`, so it doesn't apply.

If `delegate` targets the implicit function body block, then in effect it
delegates the exception to the caller of the current function. For example:
```
(func $test
try
call $foo
delegate $l1 ;; (= delegate 0)
catch_all
...
end
try
call $foo
delegate 1 ;; delegates to the caller
catch
...
catch_all
...
end
)
```
In case `foo` throws, `delegate 1` here delegates the exception handling to the
caller, i.e., the exception escapes the current function. If the immediate is
greater than or equal to the number of block nesting including the implicit
function-level block, it is a validation failure. In this example, any number
equal to or greater than 2 is not allowed.

The below is an example that includes all the cases explained. The numbers
within `()` after `delegate`s are the label operands in immediate values.
```
(func $test
try $lA
block $lB
try $lC
try
delegate $lC (0) ;; delegates to 'catch ($lC)'
try
delegate $lB (1) ;; $lB is a block, so delegates to 'catch ($lA)'
try
delegate $lA (2) ;; delegates to 'catch ($lA)'
try
delegate 3 ;; propagates to the caller
try
delegate 4 ;; validation failure
catch ($lC)
try
delegate $lC (0) ;; 'catch ($lC)' is above this instruction,
;; so delegates to 'catch ($lA)'
try
delegate $lB (1) ;; $lB is a block, so delegates to 'catch ($lA)'
try
delegate $lA (2) ;; delegates to 'catch ($lA)'
try
delegate 3 ;; propagates to the caller
try
delegate 4 ;; validation failure
end ;; try $lC
end ;; block $lB
catch ($lA)
end ;; try $lA
)
```
Here `delegate` is trying to delegate to `catch`, which exists before the
`delegate`. The `delegate` instruction can only target `try` label whose
catching instructions (`catch`/`catch_all`/`delegate`) come after the
`delegate` instruction.

`delegate` can also target `catch`-less `try`, in which case the effect is the
same as if the `try` has catches but none of the catches are able to handle the
exception.

### JS API

Expand Down

0 comments on commit c830a2f

Please sign in to comment.