Description
A non-exceptional call to an EH finally
clause is represented in RyuJIT by two basic blocks:
- a
BBJ_CALLFINALLY
, whose block target is the finally clause being called - an immediately following
BBJ_ALWAYS
which represents the block to which the finally clause should return (also called the "continuation" or "finally continuation"). This block must be empty (of code). It is marked with theBBF_KEEP_BBJ_ALWAYS
flag. If the JIT can prove that the finally doesn't return (e.g., it always executes athrow
), this block won't exist, and theBBJ_CALLFINALLY
will have theBBF_RETLESS_CALL
flag.
The flow graph is constructed as follows. The single successor of BBJ_CALLFINALLY
is its finally clause target. The predecessors of a finally clause entry are all the BBJ_CALLFINALLY
which call it. The finally clause ends with a BBJ_EHFINALLYRET
block. Its successors are all the BBJ_ALWAYS blocks paired with BBJ_CALLFINALLY
blocks which call that finally. The BBJ_ALWAYS
block predecessor is the single BBJ_EHFINALLYRET of the finally clause called by the paired BBJ_CALLFINALLY
.
Having these two blocks, paired, leads to a lot of special case code in the JIT, including checking for isBBCallAlwaysPair
, isBBCallAlwaysPairTail
, etc.
Proposal
Consider removing the paired BBJ_ALWAYS
block and adding the continuation target as an additional field of the BBJ_CALLFINALLY
block. Call this bbFinallyContinuation
.
In the flow graph, the successor of the BBJ_EHFINALLYRET
would no longer by the BBJ_ALWAYS; it would be all the finally continuation blocks. The finally continuation block predecessors would include both BBJ_EHFINALLYRET
and non-finally predecessors.
"Retless" BBJ_CALLFINALLY
might no longer need the BBF_RETLESS_CALL
flag: a null bbFinallyContinuation
would be sufficient.
This adds an additional BasicBlock*
to the BasicBlock
type that will not be used by most blocks. It's possible that the elimination of bbNext as "fall through" flow will lead to introducing an additional BasicBlock*
for BBJ_COND
"false" (branch not taken) flow, in which case the BBJ_CALLFINALLY
can reuse this additional field.
@dotnet/jit-contrib