Skip to content

Commit 452a0fe

Browse files
committed
Reflect spec changes in delegate immediate operand
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.
1 parent 7fcfe17 commit 452a0fe

File tree

1 file changed

+93
-20
lines changed

1 file changed

+93
-20
lines changed

proposals/exception-handling/Exceptions.md

+93-20
Original file line numberDiff line numberDiff line change
@@ -274,10 +274,10 @@ try label and delegates exception handling to a `catch`/`catch_all`/`delegate`
274274
specified by the `try` label. For example, consider this code:
275275

276276
```
277-
try $l1
277+
try $l0
278278
try
279279
call $foo
280-
delegate $l1 ;; (= delegate 0)
280+
delegate $l0 (= delegate 0)
281281
catch
282282
...
283283
catch_all
@@ -288,28 +288,101 @@ end
288288
If `call $foo` throws, searching for a catching block first finds `delegate`,
289289
and because it delegates exception handling to catching instructions associated
290290
with `$l1`, it will be next checked by the outer `catch` and then `catch_all`
291-
instructions. When the specified label within a `delegate` instruction does not
292-
correspond to a `try` instruction, it is a validation failure.
291+
instructions.
293292

294-
Note that the example below is a validation failure:
293+
`delegate` can also target catchless trys or non-try block constructs like
294+
`block`s or `loop`s, in which case the delegated exception is assumed to
295+
propagate to outer scope and will be caught by the next matching try-catches. In
296+
the examples, catches are annotated with '($label_name)' to clarify which `try`
297+
it belongs to.
295298
```
296-
try $l1
297-
catch
298-
try
299-
call $foo
300-
delegate $l1 ;; (= delegate 0)
301-
catch_all
302-
...
299+
try $l0
300+
block $l1
301+
try
302+
call $foo
303+
delegate $l1 ;; delegates to 'catch ($l0)'
304+
end
305+
catch ($l0)
303306
end
304307
```
305-
Here `delegate` is trying to delegate to `catch`, which exists before the
306-
`delegate`. The `delegate` instruction can only target `try` label whose
307-
catching instructions (`catch`/`catch_all`/`delegate`) come after the
308-
`delegate` instruction.
309-
310-
`delegate` can also target `catch`-less `try`, in which case the effect is the
311-
same as if the `try` has catches but none of the catches are able to handle the
312-
exception.
308+
309+
`delegate` can only target `catch`/`catch_all`s that is below the current
310+
instruction, i.e., it can only delegate downwards. It also targets all
311+
`catch`/`catch_all`s of a `try` as a whole and does not target individual
312+
`catch`/`catch_all` within a `try`. Here is another example:
313+
```
314+
try $l0
315+
try $l1
316+
catch ($l1)
317+
try
318+
call $foo
319+
delegate $l1 ;; delegates to 'catch ($l0)'
320+
catch_all
321+
...
322+
end
323+
catch ($l0)
324+
```
325+
326+
Here `delegate` is targeting `catch ($l1)`, which exists before the `delegate`.
327+
So in case an exception occurs, it propagates out and ends up targetting `catch
328+
($l0)`, if the catch has a matching tag. If not, it will propagate further out.
329+
Even if the `catch_all` is below the `delegate`, `delegate` targets catches of
330+
a `try` as a whole and does not target an individual `catch`/`catch_all`, so it
331+
doesn't apply.
332+
333+
If `delegate`'s immediate argument is the depth of the outermost block + 1, it
334+
is considered to target the function-level block, so it in effect delegates the
335+
exception to the caller of the current function. For example:
336+
```
337+
(func $test
338+
try $l
339+
try
340+
call $foo
341+
delegate 1 ;; delegates to the caller
342+
catch
343+
...
344+
catch_all
345+
...
346+
end
347+
)
348+
```
349+
In case `foo` throws, `delegate 1` here delegates the exception handling to the
350+
caller, i.e., the exception escapes the current function. If the immediate is
351+
greater than the depth of the outermost block + 1, it is a validation failure.
352+
353+
The below is an example that includes all the cases explained:
354+
```
355+
(func $test
356+
try $lA
357+
block $lB
358+
try $lC
359+
try
360+
delegate $lC (0) ;; delegates to 'catch ($lC)'
361+
try
362+
delegate $lB (1) ;; $lB is a block, so delegates to 'catch ($lA)'
363+
try
364+
delegate $lA (2) ;; delegates to 'catch ($lA)'
365+
try
366+
delegate 3 ;; propagates to the caller
367+
try
368+
delegate 4 ;; validation failure
369+
catch ($lC)
370+
try
371+
delegate $lC (0) ;; 'catch ($lC)' is above this instruction, so delegates to 'catch ($lA)'
372+
try
373+
delegate $lB (1) ;; $lB is a block, so delegates to 'catch ($lA)'
374+
try
375+
delegate $lA (2) ;; delegates to 'catch ($lA)'
376+
try
377+
delegate 3 ;; propagates to the caller
378+
try
379+
delegate 4 ;; validation failure
380+
end ;; try $lC
381+
end ;; block $lB
382+
catch ($lA)
383+
end ;; try $lA
384+
)
385+
```
313386

314387
### JS API
315388

0 commit comments

Comments
 (0)