Tail calls via the tail call helper must live in GC-safe blocks. A block
is GC-safe if either it or all of its dominators are also GC-safe. If we
are not optimizing, we will not compute dominators, and will therfore
not mark blocks whose dominators are all GC-safe. When deciding whether
or not we need to make a block GC-safe during tail call morphing,
however, we allow a tail call in an unmarked block iff the entry block
is GC-safe, as the entry block trivially dominates every reachable
block. This change fixes an assert that was not allowing for a tail call
in a block that is not marked GC-safe where the entry block is marked
GC-safe.
Commit migrated from https://github.com/dotnet/coreclr/commit/
c777aec201d57ef1f896bd5a3089fb322cd53707
// The TailCall helper call never returns to the caller and is not GC interruptible.
// Therefore the block containing the tail call should be a GC safe point to avoid
- // GC starvation.
- assert(comp->compCurBB->bbFlags & BBF_GC_SAFE_POINT);
+ // GC starvation. It is legal for the block to be unmarked iff the entry block is a
+ // GC safe point, as the entry block trivially dominates every reachable block.
+ assert((comp->compCurBB->bbFlags & BBF_GC_SAFE_POINT) || (comp->fgFirstBB->bbFlags & BBF_GC_SAFE_POINT));
+
// If PInvokes are in-lined, we have to remember to execute PInvoke method epilog anywhere that
// a method returns. This is a case of caller method has both PInvokes and tail calls.