Simplify exception dispatch to branches #58
Description
The current if_except
for handling exceptions is a structured instruction and as such quite complex. For example, embodying blocks, it has to deal with block signatures, labels, etc.
In the context of working on the GC proposal, where a similar construct is needed for downcasts, I realised that we probably don't want to introduce a zoo of block constructs. And it turns out that with the multi-value proposal we can simplify all these by replacing them with simple branches.
For the exception proposal, this would mean that instead of the structured if_except
construct, we simply have a new branch of the form
br_on_exn <labelidx> <exnidx>
which checks whether the exception package on the top of the stack matches the exception denoted by <exnidx>
, and if so, branches to <labelidx>
. The trick, however, is that the block signature of the branch target has to be compatible with the exception's tag type -- because it receives the exception arguments as branch operands. If the exception does not match, it remains on the stack.
For example:
(exception $e i32 i64)
...
block $l (result i32 i64)
...
try
(i32.const 1)
(i64.const 2)
(throw $e)
catch
(br_on_exn $l $e) ;; branch to $l with $e's arguments
(rethrow) ;; ignore other exceptions
end
...
end
;; (i32.const 1) (i64.const 2) are now on the stack
This can now be used to construct handler switches in the same way br_table
is used to construct regular switch:
block $end
block $l1
...
block $lN
(br_on_exn $l1 $e1)
...
(br_on_exn $lN $eN)
(rethrow)
end $lN
;; handler for $eN here
(br $end)
...
end $l1
;; handler for $e1
end $end
I think this is a simpler primitive and makes better reuse of existing instructions. (The try
construct remains unchanged.) WDYT?