Skip to content

Commit 8e2a1d5

Browse files
authored
JIT: relax constraint in conditional escape analysis (#117222)
Enable conditional escape analysis if the allocation was at one time guarded by a GDV, even if that GDV gets resolved by the new GDV cleanup pass that runs before escape analysis. Fixes #117204.
1 parent 9ba30d8 commit 8e2a1d5

File tree

2 files changed

+64
-80
lines changed

2 files changed

+64
-80
lines changed

src/coreclr/jit/objectalloc.cpp

Lines changed: 64 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -3317,102 +3317,89 @@ void ObjectAllocator::CheckForGuardedAllocationOrCopy(BasicBlock* block,
33173317
//
33183318
if (data->OperIs(GT_ALLOCOBJ))
33193319
{
3320-
// See if this store is made under a successful GDV test.
3320+
// This may be an allocation of a concrete class under GDV.
33213321
//
3322-
GuardInfo controllingGDV;
3323-
if (IsGuarded(block, tree, &controllingGDV, /* testOutcome */ true))
3322+
// Find the local that will ultimately represent its uses (we have kept track of
3323+
// this during importation and GDV expansion). Note it is usually *not* lclNum.
3324+
//
3325+
// We will keep special track of all accesses to this local.
3326+
//
3327+
Compiler::NodeToUnsignedMap* const map = comp->getImpEnumeratorGdvLocalMap();
3328+
unsigned enumeratorLocal = BAD_VAR_NUM;
3329+
if (map->Lookup(data, &enumeratorLocal))
33243330
{
3325-
// This is the allocation of concrete class under GDV.
3326-
//
3327-
// Find the local that will ultimately represent its uses (we have kept track of
3328-
// this during importation and GDV expansion). Note it is usually *not* lclNum.
3329-
//
3330-
// We will keep special track of all accesses to this local.
3331+
// If it turns out we can't stack allocate this new object even if it does not escape,
3332+
// then don't bother setting up tracking. Note length here is just set to a nominal
3333+
// value that won't cause failure. We will do the real length check later if we decide to allocate.
33313334
//
3332-
Compiler::NodeToUnsignedMap* const map = comp->getImpEnumeratorGdvLocalMap();
3333-
unsigned enumeratorLocal = BAD_VAR_NUM;
3334-
if (map->Lookup(data, &enumeratorLocal))
3335+
CORINFO_CLASS_HANDLE clsHnd = data->AsAllocObj()->gtAllocObjClsHnd;
3336+
const char* reason = nullptr;
3337+
unsigned size = 0;
3338+
unsigned length = TARGET_POINTER_SIZE;
3339+
ObjectAllocationType oat = AllocationKind(data);
3340+
if (CanAllocateLclVarOnStack(enumeratorLocal, clsHnd, oat, length, &size, &reason,
3341+
/* preliminaryCheck */ true))
33353342
{
3336-
// If it turns out we can't stack allocate this new object even if it does not escape,
3337-
// then don't bother setting up tracking. Note length here is just set to a nominal
3338-
// value that won't cause failure. We will do the real length check later if we decide to allocate.
3343+
// We are going to conditionally track accesses to the enumerator local via a pseudo.
33393344
//
3340-
CORINFO_CLASS_HANDLE clsHnd = data->AsAllocObj()->gtAllocObjClsHnd;
3341-
const char* reason = nullptr;
3342-
unsigned size = 0;
3343-
unsigned length = TARGET_POINTER_SIZE;
3344-
ObjectAllocationType oat = AllocationKind(data);
3345-
if (CanAllocateLclVarOnStack(enumeratorLocal, clsHnd, oat, length, &size, &reason,
3346-
/* preliminaryCheck */ true))
3345+
const unsigned pseudoIndex = NewPseudoIndex();
3346+
assert(pseudoIndex != BAD_VAR_NUM);
3347+
bool added = m_EnumeratorLocalToPseudoIndexMap.AddOrUpdate(enumeratorLocal, pseudoIndex);
3348+
3349+
if (!added)
33473350
{
3348-
// We are going to conditionally track accesses to the enumerator local via a pseudo.
3351+
// Seems like we have multiple GDVs that can define this local.
3352+
// Carry on for now, but later we may see these collide
3353+
// and end up not cloning any of them.
33493354
//
3350-
const unsigned pseudoIndex = NewPseudoIndex();
3351-
assert(pseudoIndex != BAD_VAR_NUM);
3352-
bool added = m_EnumeratorLocalToPseudoIndexMap.AddOrUpdate(enumeratorLocal, pseudoIndex);
3353-
3354-
if (!added)
3355-
{
3356-
// Seems like we have multiple GDVs that can define this local.
3357-
// Carry on for now, but later we may see these collide
3358-
// and end up not cloning any of them.
3359-
//
3360-
// Since we are walking in RPO we may also be able to see that
3361-
// they are properly disjoint and things will work out just fine.
3362-
//
3363-
JITDUMP("Looks like enumerator var re-use (multiple defining GDVs)\n");
3364-
}
3365-
3366-
// We will query this info if we see CALL(enumeratorLocal)
3367-
// during subsequent analysis, to verify that access is
3368-
// under the same guard conditions.
3355+
// Since we are walking in RPO we may also be able to see that
3356+
// they are properly disjoint and things will work out just fine.
33693357
//
3370-
CompAllocator alloc(comp->getAllocator(CMK_ObjectAllocator));
3371-
CloneInfo* info = new (alloc) CloneInfo();
3372-
info->m_local = enumeratorLocal;
3373-
info->m_type = clsHnd;
3374-
info->m_pseudoIndex = pseudoIndex;
3375-
info->m_appearanceMap = new (alloc) EnumeratorVarMap(alloc);
3376-
info->m_allocBlock = block;
3377-
info->m_allocStmt = stmt;
3378-
info->m_allocTree = data;
3379-
info->m_domBlock = controllingGDV.m_block;
3380-
m_CloneMap.Set(pseudoIndex, info);
3381-
3382-
JITDUMP("Enumerator allocation [%06u]: will track accesses to V%02u guarded by type %s via",
3383-
comp->dspTreeID(data), enumeratorLocal, comp->eeGetClassName(clsHnd));
3384-
JITDUMPEXEC(DumpIndex(pseudoIndex));
3385-
JITDUMP("\n");
3386-
3387-
// If this is not a direct assignment to the enumerator var we also need to
3388-
// track the temps that will appear in between. Later we will rewrite these
3389-
// to a fresh set of temps.
3390-
//
3391-
if (lclNum != enumeratorLocal)
3392-
{
3393-
CheckForEnumeratorUse(enumeratorLocal, lclNum);
3394-
RecordAppearance(lclNum, block, stmt, use);
3395-
}
3358+
JITDUMP("Looks like enumerator var re-use (multiple defining GDVs)\n");
33963359
}
3397-
else
3360+
3361+
// We will query this info if we see CALL(enumeratorLocal)
3362+
// during subsequent analysis, to verify that access is
3363+
// under the same guard conditions.
3364+
//
3365+
CompAllocator alloc(comp->getAllocator(CMK_ObjectAllocator));
3366+
CloneInfo* info = new (alloc) CloneInfo();
3367+
info->m_local = enumeratorLocal;
3368+
info->m_type = clsHnd;
3369+
info->m_pseudoIndex = pseudoIndex;
3370+
info->m_appearanceMap = new (alloc) EnumeratorVarMap(alloc);
3371+
info->m_allocBlock = block;
3372+
info->m_allocStmt = stmt;
3373+
info->m_allocTree = data;
3374+
m_CloneMap.Set(pseudoIndex, info);
3375+
3376+
JITDUMP("Enumerator allocation [%06u]: will track accesses to V%02u guarded by type %s via",
3377+
comp->dspTreeID(data), enumeratorLocal, comp->eeGetClassName(clsHnd));
3378+
JITDUMPEXEC(DumpIndex(pseudoIndex));
3379+
JITDUMP("\n");
3380+
3381+
// If this is not a direct assignment to the enumerator var we also need to
3382+
// track the temps that will appear in between. Later we will rewrite these
3383+
// to a fresh set of temps.
3384+
//
3385+
if (lclNum != enumeratorLocal)
33983386
{
3399-
JITDUMP(
3400-
"Enumerator allocation [%06u]: enumerator type %s cannot be stack allocated, so not tracking enumerator local V%02u\n",
3401-
comp->dspTreeID(data), comp->eeGetClassName(clsHnd), enumeratorLocal);
3387+
CheckForEnumeratorUse(enumeratorLocal, lclNum);
3388+
RecordAppearance(lclNum, block, stmt, use);
34023389
}
34033390
}
34043391
else
34053392
{
3406-
// This allocation is not currently of interest
3407-
//
3408-
JITDUMP("Allocation [%06u] was not flagged for conditional escape tracking\n", comp->dspTreeID(data));
3393+
JITDUMP(
3394+
"Enumerator allocation [%06u]: enumerator type %s cannot be stack allocated, so not tracking enumerator local V%02u\n",
3395+
comp->dspTreeID(data), comp->eeGetClassName(clsHnd), enumeratorLocal);
34093396
}
34103397
}
34113398
else
34123399
{
3413-
// This allocation was not done under a GDV guard
3400+
// This allocation is not currently of interest
34143401
//
3415-
JITDUMP("Allocation [%06u] is not under a GDV guard\n", comp->dspTreeID(data));
3402+
JITDUMP("Allocation [%06u] was not flagged for conditional escape tracking\n", comp->dspTreeID(data));
34163403
}
34173404
}
34183405
else if (data->OperIs(GT_LCL_VAR, GT_BOX))

src/coreclr/jit/objectalloc.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,6 @@ struct CloneInfo : public GuardInfo
9494
Statement* m_allocStmt = nullptr;
9595
BasicBlock* m_allocBlock = nullptr;
9696

97-
// Block holding the GDV test that decides if the enumerator will be allocated
98-
BasicBlock* m_domBlock = nullptr;
99-
10097
// Blocks to clone (in order), and a set representation
10198
// of the same
10299
jitstd::vector<BasicBlock*>* m_blocksToClone = nullptr;

0 commit comments

Comments
 (0)