void fgUpdateFinallyTargetFlags();
+ void fgClearAllFinallyTargetBits();
+
+ void fgAddFinallyTargetFlags();
+
+#if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
+ // Sometimes we need to defer updating the BBF_FINALLY_TARGET bit. fgNeedToAddFinallyTargetBits signals
+ // when this is necessary.
+ bool fgNeedToAddFinallyTargetBits;
+#endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
+
bool fgRetargetBranchesToCanonicalCallFinally(BasicBlock* block,
BasicBlock* handler,
BlockToBlockMap& continuationMap);
*/
inline void Compiler::fgConvertBBToThrowBB(BasicBlock* block)
{
+ // If we're converting a BBJ_CALLFINALLY block to a BBJ_THROW block,
+ // then mark the subsequent BBJ_ALWAYS block as unreferenced.
+ if (block->isBBCallAlwaysPair())
+ {
+ BasicBlock* leaveBlk = block->bbNext;
+ noway_assert(leaveBlk->bbJumpKind == BBJ_ALWAYS);
+
+ leaveBlk->bbFlags &= ~BBF_DONT_REMOVE;
+ leaveBlk->bbRefs = 0;
+ leaveBlk->bbPreds = nullptr;
+
+#if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
+ // This function (fgConvertBBToThrowBB) can be called before the predecessor lists are created (e.g., in
+ // fgMorph). The fgClearFinallyTargetBit() function to update the BBF_FINALLY_TARGET bit depends on these
+ // predecessor lists. If there are no predecessor lists, we immediately clear all BBF_FINALLY_TARGET bits
+ // (to allow subsequent dead code elimination to delete such blocks without asserts), and set a flag to
+ // recompute them later, before they are required.
+ if (fgComputePredsDone)
+ {
+ fgClearFinallyTargetBit(leaveBlk->bbJumpDest);
+ }
+ else
+ {
+ fgClearAllFinallyTargetBits();
+ fgNeedToAddFinallyTargetBits = true;
+ }
+#endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
+ }
+
block->bbJumpKind = BBJ_THROW;
block->bbSetRunRarely(); // any block with a throw is rare
}
JITDUMP("In fgUpdateFinallyTargetFlags, updating finally target flag bits\n");
+ fgClearAllFinallyTargetBits();
+ fgAddFinallyTargetFlags();
+
+#endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
+}
+
+//------------------------------------------------------------------------
+// fgClearAllFinallyTargetBits: Clear all BBF_FINALLY_TARGET bits; these will need to be
+// recomputed later.
+//
+void Compiler::fgClearAllFinallyTargetBits()
+{
+#if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
+
+ JITDUMP("*************** In fgClearAllFinallyTargetBits()\n");
+
+ // Note that we clear the flags even if there are no EH clauses (compHndBBtabCount == 0)
+ // in case bits are left over from EH clauses being deleted.
+
// Walk all blocks, and reset the target bits.
for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
{
block->bbFlags &= ~BBF_FINALLY_TARGET;
}
- // Walk all blocks again, and set the target bits.
+#endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
+}
+
+//------------------------------------------------------------------------
+// fgAddFinallyTargetFlags: Add BBF_FINALLY_TARGET bits to all finally targets.
+//
+void Compiler::fgAddFinallyTargetFlags()
+{
+#if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
+
+ JITDUMP("*************** In fgAddFinallyTargetFlags()\n");
+
+ if (compHndBBtabCount == 0)
+ {
+ JITDUMP("No EH in this method, no flags to set.\n");
+ return;
+ }
+
for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
{
if (block->isBBCallAlwaysPair())
DBEXEC(VERBOSE, fgDispBasicBlocks(true));
#endif
+#if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
+ if (fgNeedToAddFinallyTargetBits)
+ {
+ // We previously wiped out the BBF_FINALLY_TARGET bits due to some morphing; add them back.
+ fgAddFinallyTargetFlags();
+ fgNeedToAddFinallyTargetBits = false;
+ }
+#endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
+
/* Decide the kind of code we want to generate */
fgSetOptions();