@@ -1828,31 +1828,12 @@ bool Compiler::fgVNBasedIntrinsicExpansionForCall_ReadUtf8(BasicBlock** pBlock,
18281828//
18291829PhaseStatus Compiler::fgLateCastExpansion ()
18301830{
1831- if (!doesMethodHaveExpandableCasts ())
1831+ if (!doesMethodHaveExpandableCasts () || opts. OptimizationDisabled () )
18321832 {
18331833 // Nothing to expand in the current method
18341834 return PhaseStatus::MODIFIED_NOTHING;
18351835 }
18361836
1837- if (!opts.IsOptimizedWithProfile ())
1838- {
1839- // Currently, we're only interested in expanding cast helpers using profile data
1840- return PhaseStatus::MODIFIED_NOTHING;
1841- }
1842-
1843- if (JitConfig.JitConsumeProfileForCasts () == 0 )
1844- {
1845- return PhaseStatus::MODIFIED_NOTHING;
1846- }
1847-
1848- const bool preferSize = opts.jitFlags ->IsSet (JitFlags::JIT_FLAG_SIZE_OPT);
1849- if (preferSize)
1850- {
1851- // The optimization comes with a codegen size increase
1852- JITDUMP (" Optimized for size - bail out.\n " );
1853- return PhaseStatus::MODIFIED_NOTHING;
1854- }
1855-
18561837 // TODO-InlineCast: should we still inline some trivial cases even in cold blocks?
18571838 const bool skipForRarelyRunBlocks = true ;
18581839 return fgExpandHelper<&Compiler::fgLateCastExpansionForCall>(skipForRarelyRunBlocks);
@@ -1862,6 +1843,7 @@ enum class TypeCheckFailedAction
18621843{
18631844 ReturnNull,
18641845 CallHelper,
1846+ CallHelper_Specialized,
18651847 CallHelper_AlwaysThrows
18661848};
18671849
@@ -1978,14 +1960,25 @@ static CORINFO_CLASS_HANDLE PickCandidateForTypeCheck(Compiler* com
19781960 const bool isCastToExact = comp->info .compCompHnd ->isExactType (castToCls);
19791961 if (isCastToExact && ((helper == CORINFO_HELP_CHKCASTCLASS) || (helper == CORINFO_HELP_CHKCASTARRAY)))
19801962 {
1981- // (string)obj
1982- // (string[])obj
1963+ result = castToCls;
1964+
1965+ // obj is string
1966+ // obj is string[]
19831967 //
1984- // Fallbacks for these expansions always throw InvalidCastException
1985- *typeCheckFailed = TypeCheckFailedAction::CallHelper_AlwaysThrows;
1968+ if ((helper == CORINFO_HELP_CHKCASTCLASS))
1969+ {
1970+ // (string)obj
1971+ //
1972+ // Fallback for this expansion always throws InvalidCastException
1973+ // TODO: can we do the same for string[]? (importer did not)
1974+ *typeCheckFailed = TypeCheckFailedAction::CallHelper_AlwaysThrows;
1975+
1976+ // Assume that exceptions are rare
1977+ *likelihood = 100 ;
19861978
1987- // Assume that exceptions are rare
1988- *likelihood = 100 ;
1979+ // Update the common denominator class to be more exact
1980+ *commonCls = result;
1981+ }
19891982
19901983 // We're done, there is no need in consulting with PGO data
19911984 }
@@ -1996,39 +1989,55 @@ static CORINFO_CLASS_HANDLE PickCandidateForTypeCheck(Compiler* com
19961989 // obj is string[]
19971990 //
19981991 // Fallbacks for these expansions simply return null
1992+ // TODO: should we keep the helper call for ISINSTANCEOFARRAY like we do for CHKCASTARRAY above?
1993+ // The logic is copied from the importer.
19991994 *typeCheckFailed = TypeCheckFailedAction::ReturnNull;
1995+
1996+ // We're done, there is no need in consulting with PGO data
1997+ result = castToCls;
20001998 }
20011999 else
20022000 {
2001+ CORINFO_CLASS_HANDLE exactClass = NO_CLASS_HANDLE;
20032002 // 2) If VM can tell us the exact class for this "cast to" class - use it.
20042003 // Just make sure the class is truly exact.
2005- if ((comp->info .compCompHnd ->getExactClasses (castToCls, 1 , &result ) == 1 ) &&
2006- comp->info .compCompHnd ->isExactType (result ))
2004+ if ((comp->info .compCompHnd ->getExactClasses (castToCls, 1 , &exactClass ) == 1 ) &&
2005+ comp->info .compCompHnd ->isExactType (exactClass ))
20072006 {
2008- if (isCastClass)
2007+ result = exactClass;
2008+
2009+ if ((helper == CORINFO_HELP_CHKCASTINTERFACE) || (helper == CORINFO_HELP_CHKCASTCLASS))
20092010 {
20102011 // Fallback call is only needed for castclass and only to throw InvalidCastException
20112012 *typeCheckFailed = TypeCheckFailedAction::CallHelper_AlwaysThrows;
20122013
20132014 // Assume that exceptions are rare
20142015 *likelihood = 100 ;
2016+
2017+ // Update the common denominator class to be more exact
2018+ *commonCls = result;
20152019 }
2016- else
2020+ else if ((helper == CORINFO_HELP_ISINSTANCEOFINTERFACE) || (helper == CORINFO_HELP_ISINSTANCEOFCLASS))
20172021 {
20182022 // Fallback for isinst simply returns null here
20192023 *typeCheckFailed = TypeCheckFailedAction::ReturnNull;
2020- }
20212024
2022- // Update the common denominator class to be more exact
2023- *commonCls = result;
2025+ // Update the common denominator class to be more exact
2026+ *commonCls = result;
2027+ }
20242028 }
20252029 else
20262030 {
20272031 // 3) Consult with PGO data
20282032 LikelyClassMethodRecord likelyClasses[MAX_GDV_TYPE_CHECKS];
2029- unsigned likelyClassCount =
2030- getLikelyClasses (likelyClasses, MAX_GDV_TYPE_CHECKS, comp->fgPgoSchema , comp->fgPgoSchemaCount ,
2031- comp->fgPgoData , (int )castHelper->gtCastHelperILOffset );
2033+ unsigned likelyClassCount = 0 ;
2034+
2035+ if (comp->opts .IsOptimizedWithProfile () && (JitConfig.JitConsumeProfileForCasts () != 0 ))
2036+ {
2037+ const int ilOffset = (int )castHelper->gtCastHelperILOffset ;
2038+ likelyClassCount = getLikelyClasses (likelyClasses, MAX_GDV_TYPE_CHECKS, comp->fgPgoSchema ,
2039+ comp->fgPgoSchemaCount , comp->fgPgoData , ilOffset);
2040+ }
20322041
20332042 if (likelyClassCount != 0 )
20342043 {
@@ -2183,10 +2192,12 @@ static CORINFO_CLASS_HANDLE PickCandidateForTypeCheck(Compiler* com
21832192 unreached ();
21842193 }
21852194
2186- if (isCastClass && (result == castToCls) && (*typeCheckFailed == TypeCheckFailedAction::CallHelper))
2195+ if ((helper == CORINFO_HELP_CHKCASTCLASS) && (result == castToCls) &&
2196+ (*typeCheckFailed == TypeCheckFailedAction::CallHelper))
21872197 {
2188- // TODO-InlineCast: Change helper to faster CORINFO_HELP_CHKCASTCLASS_SPECIAL
2189- // it won't check for null and castToCls assuming we've already done it inline.
2198+ // A small optimization - use a slightly faster fallback which assumes that we've already checked
2199+ // for null and for castToCls itself so it won't do it again.
2200+ *typeCheckFailed = TypeCheckFailedAction::CallHelper_Specialized;
21902201 }
21912202
21922203 assert (result != NO_CLASS_HANDLE);
@@ -2299,6 +2310,12 @@ bool Compiler::fgLateCastExpansionForCall(BasicBlock** pBlock, Statement* stmt,
22992310 }
23002311 else
23012312 {
2313+ if (typeCheckFailedAction == TypeCheckFailedAction::CallHelper_Specialized)
2314+ {
2315+ // A slightly faster fallback which assumes that we've already checked
2316+ // for null and for castToCls itself.
2317+ call->gtCallMethHnd = eeFindHelper (CORINFO_HELP_CHKCASTCLASS_SPECIAL);
2318+ }
23022319 GenTree* fallbackTree = gtNewTempStore (tmpNum, call);
23032320 fallbackBb = fgNewBBFromTreeAfter (BBJ_ALWAYS, typeCheckBb, fallbackTree, debugInfo, lastBb, true );
23042321 }
@@ -2346,10 +2363,7 @@ bool Compiler::fgLateCastExpansionForCall(BasicBlock** pBlock, Statement* stmt,
23462363 //
23472364 nullcheckBb->inheritWeight (firstBb);
23482365 typeCheckBb->inheritWeightPercentage (nullcheckBb, 50 );
2349- fallbackBb->inheritWeightPercentage (typeCheckBb,
2350- (typeCheckFailedAction == TypeCheckFailedAction::CallHelper_AlwaysThrows)
2351- ? 0
2352- : 100 - likelihood);
2366+ fallbackBb->inheritWeightPercentage (typeCheckBb, fallbackBb->KindIs (BBJ_THROW) ? 0 : 100 - likelihood);
23532367 typeCheckSucceedBb->inheritWeightPercentage (typeCheckBb, likelihood);
23542368 lastBb->inheritWeight (firstBb);
23552369
0 commit comments