@@ -1828,31 +1828,12 @@ bool Compiler::fgVNBasedIntrinsicExpansionForCall_ReadUtf8(BasicBlock** pBlock,
1828
1828
//
1829
1829
PhaseStatus Compiler::fgLateCastExpansion ()
1830
1830
{
1831
- if (!doesMethodHaveExpandableCasts ())
1831
+ if (!doesMethodHaveExpandableCasts () || opts. OptimizationDisabled () )
1832
1832
{
1833
1833
// Nothing to expand in the current method
1834
1834
return PhaseStatus::MODIFIED_NOTHING;
1835
1835
}
1836
1836
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
-
1856
1837
// TODO-InlineCast: should we still inline some trivial cases even in cold blocks?
1857
1838
const bool skipForRarelyRunBlocks = true ;
1858
1839
return fgExpandHelper<&Compiler::fgLateCastExpansionForCall>(skipForRarelyRunBlocks);
@@ -1862,6 +1843,7 @@ enum class TypeCheckFailedAction
1862
1843
{
1863
1844
ReturnNull,
1864
1845
CallHelper,
1846
+ CallHelper_Specialized,
1865
1847
CallHelper_AlwaysThrows
1866
1848
};
1867
1849
@@ -1978,14 +1960,25 @@ static CORINFO_CLASS_HANDLE PickCandidateForTypeCheck(Compiler* com
1978
1960
const bool isCastToExact = comp->info .compCompHnd ->isExactType (castToCls);
1979
1961
if (isCastToExact && ((helper == CORINFO_HELP_CHKCASTCLASS) || (helper == CORINFO_HELP_CHKCASTARRAY)))
1980
1962
{
1981
- // (string)obj
1982
- // (string[])obj
1963
+ result = castToCls;
1964
+
1965
+ // obj is string
1966
+ // obj is string[]
1983
1967
//
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 ;
1986
1978
1987
- // Assume that exceptions are rare
1988
- *likelihood = 100 ;
1979
+ // Update the common denominator class to be more exact
1980
+ *commonCls = result;
1981
+ }
1989
1982
1990
1983
// We're done, there is no need in consulting with PGO data
1991
1984
}
@@ -1996,39 +1989,55 @@ static CORINFO_CLASS_HANDLE PickCandidateForTypeCheck(Compiler* com
1996
1989
// obj is string[]
1997
1990
//
1998
1991
// 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.
1999
1994
*typeCheckFailed = TypeCheckFailedAction::ReturnNull;
1995
+
1996
+ // We're done, there is no need in consulting with PGO data
1997
+ result = castToCls;
2000
1998
}
2001
1999
else
2002
2000
{
2001
+ CORINFO_CLASS_HANDLE exactClass = NO_CLASS_HANDLE;
2003
2002
// 2) If VM can tell us the exact class for this "cast to" class - use it.
2004
2003
// 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 ))
2007
2006
{
2008
- if (isCastClass)
2007
+ result = exactClass;
2008
+
2009
+ if ((helper == CORINFO_HELP_CHKCASTINTERFACE) || (helper == CORINFO_HELP_CHKCASTCLASS))
2009
2010
{
2010
2011
// Fallback call is only needed for castclass and only to throw InvalidCastException
2011
2012
*typeCheckFailed = TypeCheckFailedAction::CallHelper_AlwaysThrows;
2012
2013
2013
2014
// Assume that exceptions are rare
2014
2015
*likelihood = 100 ;
2016
+
2017
+ // Update the common denominator class to be more exact
2018
+ *commonCls = result;
2015
2019
}
2016
- else
2020
+ else if ((helper == CORINFO_HELP_ISINSTANCEOFINTERFACE) || (helper == CORINFO_HELP_ISINSTANCEOFCLASS))
2017
2021
{
2018
2022
// Fallback for isinst simply returns null here
2019
2023
*typeCheckFailed = TypeCheckFailedAction::ReturnNull;
2020
- }
2021
2024
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
+ }
2024
2028
}
2025
2029
else
2026
2030
{
2027
2031
// 3) Consult with PGO data
2028
2032
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
+ }
2032
2041
2033
2042
if (likelyClassCount != 0 )
2034
2043
{
@@ -2183,10 +2192,12 @@ static CORINFO_CLASS_HANDLE PickCandidateForTypeCheck(Compiler* com
2183
2192
unreached ();
2184
2193
}
2185
2194
2186
- if (isCastClass && (result == castToCls) && (*typeCheckFailed == TypeCheckFailedAction::CallHelper))
2195
+ if ((helper == CORINFO_HELP_CHKCASTCLASS) && (result == castToCls) &&
2196
+ (*typeCheckFailed == TypeCheckFailedAction::CallHelper))
2187
2197
{
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;
2190
2201
}
2191
2202
2192
2203
assert (result != NO_CLASS_HANDLE);
@@ -2299,6 +2310,12 @@ bool Compiler::fgLateCastExpansionForCall(BasicBlock** pBlock, Statement* stmt,
2299
2310
}
2300
2311
else
2301
2312
{
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
+ }
2302
2319
GenTree* fallbackTree = gtNewTempStore (tmpNum, call);
2303
2320
fallbackBb = fgNewBBFromTreeAfter (BBJ_ALWAYS, typeCheckBb, fallbackTree, debugInfo, lastBb, true );
2304
2321
}
@@ -2346,10 +2363,7 @@ bool Compiler::fgLateCastExpansionForCall(BasicBlock** pBlock, Statement* stmt,
2346
2363
//
2347
2364
nullcheckBb->inheritWeight (firstBb);
2348
2365
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);
2353
2367
typeCheckSucceedBb->inheritWeightPercentage (typeCheckBb, likelihood);
2354
2368
lastBb->inheritWeight (firstBb);
2355
2369
0 commit comments