Skip to content

Commit c8f9a24

Browse files
Add an assert concerning branch to BBJ_CALLFINALLY blocks (#55858)
In the FEATURE_EH_CALLFINALLY_THUNKS case, BBJ_CALLFINALLY blocks live in the EH region enclosing the `try` block that needs to call the finally. However, we need all flow to the BBJ_CALLFINALLY to come from that try block; we don't want flow optimizations to otherwise branch directly to this BBJ_CALLFINALLY block. Add an assert to verify this is the case. The assert also covers the non-FEATURE_EH_CALLFINALLY_THUNKS case.
1 parent e0024e2 commit c8f9a24

File tree

1 file changed

+46
-0
lines changed

1 file changed

+46
-0
lines changed

src/coreclr/jit/fgdiagnostic.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2740,6 +2740,52 @@ void Compiler::fgDebugCheckBBlist(bool checkBBNum /* = false */, bool checkBBRef
27402740
assert(block->getTryIndex() < compHndBBtabCount);
27412741
}
27422742

2743+
// A branch or fall-through to a BBJ_CALLFINALLY block must come from the `try` region associated
2744+
// with the finally block the BBJ_CALLFINALLY is targeting. There is one special case: if the
2745+
// BBJ_CALLFINALLY is the first block of a `try`, then its predecessor can be outside the `try`:
2746+
// either a branch or fall-through to the first block.
2747+
//
2748+
// Note that this IR condition is a choice. It naturally occurs when importing EH constructs.
2749+
// This condition prevents flow optimizations from skipping blocks in a `try` and branching
2750+
// directly to the BBJ_CALLFINALLY. Relaxing this constraint would require careful thinking about
2751+
// the implications, such as data flow optimizations.
2752+
//
2753+
// Don't depend on predecessors list for the check.
2754+
for (BasicBlock* const succBlock : block->Succs())
2755+
{
2756+
if (succBlock->bbJumpKind == BBJ_CALLFINALLY)
2757+
{
2758+
BasicBlock* finallyBlock = succBlock->bbJumpDest;
2759+
assert(finallyBlock->hasHndIndex());
2760+
unsigned finallyIndex = finallyBlock->getHndIndex();
2761+
2762+
// Now make sure the block branching to the BBJ_CALLFINALLY is in the correct region. The branch
2763+
// to the BBJ_CALLFINALLY can come from the try region of the finally block, or from a more nested
2764+
// try region, e.g.:
2765+
// try {
2766+
// try {
2767+
// LEAVE L_OUTER; // this becomes a branch to a BBJ_CALLFINALLY in an outer try region
2768+
// // (in the FEATURE_EH_CALLFINALLY_THUNKS case)
2769+
// } catch {
2770+
// }
2771+
// } finally {
2772+
// }
2773+
// L_OUTER:
2774+
//
2775+
EHblkDsc* ehDsc = ehGetDsc(finallyIndex);
2776+
if (ehDsc->ebdTryBeg == succBlock)
2777+
{
2778+
// The BBJ_CALLFINALLY is the first block of it's `try` region. Don't check the predecessor.
2779+
// Note that this case won't occur in the FEATURE_EH_CALLFINALLY_THUNKS case, since the
2780+
// BBJ_CALLFINALLY in that case won't exist in the `try` region of the `finallyIndex`.
2781+
}
2782+
else
2783+
{
2784+
assert(bbInTryRegions(finallyIndex, block));
2785+
}
2786+
}
2787+
}
2788+
27432789
/* Check if BBF_RUN_RARELY is set that we have bbWeight of zero */
27442790
if (block->isRunRarely())
27452791
{

0 commit comments

Comments
 (0)