}
//------------------------------------------------------------------------
+// isBBCallAlwaysPair: Determine if this is hte first block of a BBJ_CALLFINALLY/BBJ_ALWAYS pari
+
+// Return Value:
+// True iff "this" is the first block of a BBJ_CALLFINALLY/BBJ_ALWAYS pair
+// -- a block corresponding to an exit from the try of a try/finally.
+//
+// Notes:
+// In the flow graph, this becomes a block that calls the finally, and a second, immediately
+// following empty block (in the bbNext chain) to which the finally will return, and which
+// branches unconditionally to the next block to be executed outside the try/finally.
+// Note that code is often generated differently than this description. For example, on ARM,
+// the target of the BBJ_ALWAYS is loaded in LR (the return register), and a direct jump is
+// made to the 'finally'. The effect is that the 'finally' returns directly to the target of
+// the BBJ_ALWAYS. A "retless" BBJ_CALLFINALLY is one that has no corresponding BBJ_ALWAYS.
+// This can happen if the finally is known to not return (e.g., it contains a 'throw'). In
+// that case, the BBJ_CALLFINALLY flags has BBF_RETLESS_CALL set. Note that ARM never has
+// "retless" BBJ_CALLFINALLY blocks due to a requirement to use the BBJ_ALWAYS for
+// generating code.
+//
+bool BasicBlock::isBBCallAlwaysPair()
+{
+#if defined(FEATURE_EH_FUNCLETS) && defined(_TARGET_ARM_)
+ if (this->bbJumpKind == BBJ_CALLFINALLY)
+#else
+ if ((this->bbJumpKind == BBJ_CALLFINALLY) && !(this->bbFlags & BBF_RETLESS_CALL))
+#endif
+ {
+#if defined(FEATURE_EH_FUNCLETS) && defined(_TARGET_ARM_)
+ // On ARM, there are no retless BBJ_CALLFINALLY.
+ assert(!(this->bbFlags & BBF_RETLESS_CALL));
+#endif
+ // Some asserts that the next block is a BBJ_ALWAYS of the proper form.
+ assert(this->bbNext != nullptr);
+ assert(this->bbNext->bbJumpKind == BBJ_ALWAYS);
+ assert(this->bbNext->bbFlags & BBF_KEEP_BBJ_ALWAYS);
+ assert(this->bbNext->isEmpty());
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+//------------------------------------------------------------------------
+// isBBCallAlwaysPairTail: Determine if this is the last block of a BBJ_CALLFINALLY/BBJ_ALWAYS pari
+//
+// Return Value:
+// True iff "this" is the last block of a BBJ_CALLFINALLY/BBJ_ALWAYS pair
+// -- a block corresponding to an exit from the try of a try/finally.
+//
+// Notes:
+// See notes on isBBCallAlwaysPair(), above.
+//
+bool BasicBlock::isBBCallAlwaysPairTail()
+{
+ return (bbPrev != nullptr) && bbPrev->isBBCallAlwaysPair();
+}
+
+//------------------------------------------------------------------------
// hasEHBoundaryIn: Determine if this block begins at an EH boundary.
//
// Return Value:
bool BasicBlock::hasEHBoundaryOut()
{
bool returnVal = false;
- // If a block is marked BBF_KEEP_BBJ_ALWAYS, it is always paired with its predecessor which is an
- // EH boundary block. It must remain empty, and we must not have any live incoming vars in registers,
- // in particular because we can't perform resolution if there are mismatches across edges.
- if ((bbFlags & BBF_KEEP_BBJ_ALWAYS) != 0)
- {
- returnVal = true;
- }
-
if (bbJumpKind == BBJ_EHFILTERRET)
{
returnVal = true;
bool isValid();
// Returns "true" iff "this" is the first block of a BBJ_CALLFINALLY/BBJ_ALWAYS pair --
- // a block corresponding to an exit from the try of a try/finally. In the flow graph,
- // this becomes a block that calls the finally, and a second, immediately
- // following empty block (in the bbNext chain) to which the finally will return, and which
- // branches unconditionally to the next block to be executed outside the try/finally.
- // Note that code is often generated differently than this description. For example, on ARM,
- // the target of the BBJ_ALWAYS is loaded in LR (the return register), and a direct jump is
- // made to the 'finally'. The effect is that the 'finally' returns directly to the target of
- // the BBJ_ALWAYS. A "retless" BBJ_CALLFINALLY is one that has no corresponding BBJ_ALWAYS.
- // This can happen if the finally is known to not return (e.g., it contains a 'throw'). In
- // that case, the BBJ_CALLFINALLY flags has BBF_RETLESS_CALL set. Note that ARM never has
- // "retless" BBJ_CALLFINALLY blocks due to a requirement to use the BBJ_ALWAYS for
- // generating code.
- bool isBBCallAlwaysPair()
- {
-#if defined(FEATURE_EH_FUNCLETS) && defined(_TARGET_ARM_)
- if (this->bbJumpKind == BBJ_CALLFINALLY)
-#else
- if ((this->bbJumpKind == BBJ_CALLFINALLY) && !(this->bbFlags & BBF_RETLESS_CALL))
-#endif
- {
-#if defined(FEATURE_EH_FUNCLETS) && defined(_TARGET_ARM_)
- // On ARM, there are no retless BBJ_CALLFINALLY.
- assert(!(this->bbFlags & BBF_RETLESS_CALL));
-#endif
- // Some asserts that the next block is a BBJ_ALWAYS of the proper form.
- assert(this->bbNext != nullptr);
- assert(this->bbNext->bbJumpKind == BBJ_ALWAYS);
- assert(this->bbNext->bbFlags & BBF_KEEP_BBJ_ALWAYS);
- assert(this->bbNext->isEmpty());
-
- return true;
- }
- else
- {
- return false;
- }
- }
+ // a block corresponding to an exit from the try of a try/finally.
+ bool isBBCallAlwaysPair();
+ // Returns "true" iff "this" is the last block of a BBJ_CALLFINALLY/BBJ_ALWAYS pair --
+ // a block corresponding to an exit from the try of a try/finally.
+ bool isBBCallAlwaysPairTail();
BBjumpKinds bbJumpKind; // jump (if any) at the end of this block