Skip to content

Commit b0c39fe

Browse files
EgorBotmds
authored andcommitted
Late cast expansion: castclass (dotnet#97237)
1 parent 6cadfb2 commit b0c39fe

2 files changed

Lines changed: 30 additions & 78 deletions

File tree

src/coreclr/jit/helperexpansion.cpp

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1888,9 +1888,8 @@ static CORINFO_CLASS_HANDLE PickLikelyClass(Compiler* comp, IL_OFFSET offset, un
18881888
//
18891889
bool Compiler::fgLateCastExpansionForCall(BasicBlock** pBlock, Statement* stmt, GenTreeCall* call)
18901890
{
1891-
if (!call->IsHelperCall() || !impIsCastHelperMayHaveProfileData(call->GetHelperNum()))
1891+
if (!call->IsHelperCall())
18921892
{
1893-
// Not a cast helper we're interested in
18941893
return false;
18951894
}
18961895

@@ -1901,6 +1900,26 @@ bool Compiler::fgLateCastExpansionForCall(BasicBlock** pBlock, Statement* stmt,
19011900
return false;
19021901
}
19031902

1903+
bool isInstanceOf = false;
1904+
switch (call->GetHelperNum())
1905+
{
1906+
case CORINFO_HELP_ISINSTANCEOFINTERFACE:
1907+
case CORINFO_HELP_ISINSTANCEOFARRAY:
1908+
case CORINFO_HELP_ISINSTANCEOFCLASS:
1909+
case CORINFO_HELP_ISINSTANCEOFANY:
1910+
isInstanceOf = true;
1911+
break;
1912+
1913+
case CORINFO_HELP_CHKCASTINTERFACE:
1914+
case CORINFO_HELP_CHKCASTARRAY:
1915+
case CORINFO_HELP_CHKCASTCLASS:
1916+
case CORINFO_HELP_CHKCASTANY:
1917+
break;
1918+
1919+
default:
1920+
return false;
1921+
}
1922+
19041923
// Helper calls are never tail calls
19051924
assert(!call->IsTailCall());
19061925

@@ -1946,6 +1965,13 @@ bool Compiler::fgLateCastExpansionForCall(BasicBlock** pBlock, Statement* stmt,
19461965
return false;
19471966
}
19481967

1968+
if ((castResult == TypeCompareState::MustNot) && !isInstanceOf)
1969+
{
1970+
// Don't expand castclass if likelyclass always fails the type check
1971+
// it's going to throw an exception anyway.
1972+
return false;
1973+
}
1974+
19491975
if ((info.compCompHnd->getClassAttribs(likelyCls) & (CORINFO_FLG_INTERFACE | CORINFO_FLG_ABSTRACT)) != 0)
19501976
{
19511977
// Possible scenario: someone changed Foo to be an interface,

src/coreclr/jit/importer.cpp

Lines changed: 2 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -5518,79 +5518,6 @@ GenTree* Compiler::impCastClassOrIsInstToTree(
55185518
// If the class is exact, the jit can expand the IsInst check inline.
55195519
canExpandInline = isClassExact;
55205520
}
5521-
5522-
// Check if this cast helper have some profile data
5523-
// "isinst" with profile data is moved to a late phase.
5524-
// The long-term plan is to move all non-trivial expansions there.
5525-
if (impIsCastHelperMayHaveProfileData(helper) && isCastClass)
5526-
{
5527-
const int maxLikelyClasses = 32;
5528-
LikelyClassMethodRecord likelyClasses[maxLikelyClasses];
5529-
unsigned likelyClassCount =
5530-
getLikelyClasses(likelyClasses, maxLikelyClasses, fgPgoSchema, fgPgoSchemaCount, fgPgoData, ilOffset);
5531-
5532-
if (likelyClassCount > 0)
5533-
{
5534-
#ifdef DEBUG
5535-
for (UINT32 i = 0; i < likelyClassCount; i++)
5536-
{
5537-
const char* className = eeGetClassName((CORINFO_CLASS_HANDLE)likelyClasses[i].handle);
5538-
JITDUMP(" %u) %p (%s) [likelihood:%u%%]\n", i + 1, likelyClasses[i].handle, className,
5539-
likelyClasses[i].likelihood);
5540-
}
5541-
5542-
// Optional stress mode to pick a random known class, rather than
5543-
// the most likely known class.
5544-
if (JitConfig.JitRandomGuardedDevirtualization() != 0)
5545-
{
5546-
// Reuse the random inliner's random state.
5547-
CLRRandom* const random =
5548-
impInlineRoot()->m_inlineStrategy->GetRandom(JitConfig.JitRandomGuardedDevirtualization());
5549-
5550-
unsigned index = static_cast<unsigned>(random->Next(static_cast<int>(likelyClassCount)));
5551-
likelyClasses[0].handle = likelyClasses[index].handle;
5552-
likelyClasses[0].likelihood = 100;
5553-
likelyClassCount = 1;
5554-
}
5555-
#endif
5556-
5557-
LikelyClassMethodRecord likelyClass = likelyClasses[0];
5558-
CORINFO_CLASS_HANDLE likelyCls = (CORINFO_CLASS_HANDLE)likelyClass.handle;
5559-
5560-
// if there is a dominating candidate with >= 40% likelihood, use it
5561-
const unsigned likelihoodMinThreshold = 40;
5562-
if ((likelyCls != NO_CLASS_HANDLE) && (likelyClass.likelihood > likelihoodMinThreshold))
5563-
{
5564-
TypeCompareState castResult =
5565-
info.compCompHnd->compareTypesForCast(likelyCls, pResolvedToken->hClass);
5566-
5567-
// If case of MustNot we still can optimize isinst (only), e.g.:
5568-
//
5569-
// bool objIsDisposable = obj is IDisposable;
5570-
//
5571-
// when the profile tells us that obj is mostly Int32, hence, never implements that interface.
5572-
// for castclass it makes little sense as it will always throw a cast exception anyway.
5573-
if ((castResult == TypeCompareState::Must) ||
5574-
(castResult == TypeCompareState::MustNot && !isCastClass))
5575-
{
5576-
bool isAbstract = (info.compCompHnd->getClassAttribs(likelyCls) &
5577-
(CORINFO_FLG_INTERFACE | CORINFO_FLG_ABSTRACT)) != 0;
5578-
// If it's abstract it means we most likely deal with a stale PGO data so bail out.
5579-
if (!isAbstract)
5580-
{
5581-
JITDUMP("Adding \"is %s (%X)\" check as a fast path for %s using PGO data.\n",
5582-
eeGetClassName(likelyCls), likelyCls, isCastClass ? "castclass" : "isinst");
5583-
5584-
reversedMTCheck = castResult == TypeCompareState::MustNot;
5585-
canExpandInline = true;
5586-
partialExpand = true;
5587-
exactCls = likelyCls;
5588-
fastPathLikelihood = likelyClass.likelihood;
5589-
}
5590-
}
5591-
}
5592-
}
5593-
}
55945521
}
55955522

55965523
const bool expandInline = canExpandInline && shouldExpandInline;
@@ -5621,10 +5548,9 @@ GenTree* Compiler::impCastClassOrIsInstToTree(
56215548
compCurBB->SetFlags(BBF_HAS_HISTOGRAM_PROFILE);
56225549
}
56235550
}
5624-
else if (!isCastClass && impIsCastHelperMayHaveProfileData(helper))
5551+
else if (impIsCastHelperMayHaveProfileData(helper))
56255552
{
5626-
// Maybe the late-cast-expand phase will have a better luck expanding this cast.
5627-
// TODO: enable for cast-class as well.
5553+
// Leave a note for fgLateCastExpand to expand this helper call
56285554
call->gtCallMoreFlags |= GTF_CALL_M_CAST_CAN_BE_EXPANDED;
56295555
call->gtCastHelperILOffset = ilOffset;
56305556
}

0 commit comments

Comments
 (0)