-
Notifications
You must be signed in to change notification settings - Fork 5.3k
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_ALWAYSwhich 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_ALWAYSflag. If the JIT can prove that the finally doesn't return (e.g., it always executes athrow), this block won't exist, and theBBJ_CALLFINALLYwill have theBBF_RETLESS_CALLflag.
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