@@ -6986,6 +6986,7 @@ void Compiler::pickGDV(GenTreeCall* call,
6986
6986
const int maxLikelyMethods = MAX_GDV_TYPE_CHECKS;
6987
6987
LikelyClassMethodRecord likelyMethods[maxLikelyMethods];
6988
6988
unsigned numberOfMethods = 0 ;
6989
+ bool isInferredGDV = false ;
6989
6990
6990
6991
// TODO-GDV: R2R support requires additional work to reacquire the
6991
6992
// entrypoint, similar to what happens at the end of impDevirtualizeCall.
@@ -7000,6 +7001,39 @@ void Compiler::pickGDV(GenTreeCall* call,
7000
7001
pgoInfo.PgoData , ilOffset);
7001
7002
}
7002
7003
7004
+ if ((numberOfClasses < 1 ) && (numberOfMethods < 1 ) && hasEnumeratorLikelyTypeMap ())
7005
+ {
7006
+ // See if we can infer a GDV here for enumerator var uses
7007
+ //
7008
+ CallArg* const thisArg = call->gtArgs .FindWellKnownArg (WellKnownArg::ThisPointer);
7009
+
7010
+ if (thisArg != nullptr )
7011
+ {
7012
+ GenTree* const thisNode = thisArg->GetEarlyNode ();
7013
+ if (thisNode->OperIs (GT_LCL_VAR))
7014
+ {
7015
+ GenTreeLclVarCommon* thisLclNode = thisNode->AsLclVarCommon ();
7016
+ LclVarDsc* const thisVarDsc = lvaGetDesc (thisLclNode);
7017
+ unsigned const thisLclNum = thisLclNode->GetLclNum ();
7018
+
7019
+ if (thisVarDsc->lvIsEnumerator )
7020
+ {
7021
+ VarToLikelyClassMap* const map = getImpEnumeratorLikelyTypeMap ();
7022
+ InferredGdvEntry e;
7023
+ if (map->Lookup (thisLclNum, &e))
7024
+ {
7025
+ JITDUMP (" Recalling that V%02u has %u%% likely class %s\n " , thisLclNum, e.m_likelihood ,
7026
+ eeGetClassName (e.m_classHandle ));
7027
+ numberOfClasses = 1 ;
7028
+ likelyClasses[0 ].handle = (INT_PTR)e.m_classHandle ;
7029
+ likelyClasses[0 ].likelihood = e.m_likelihood ;
7030
+ isInferredGDV = true ;
7031
+ }
7032
+ }
7033
+ }
7034
+ }
7035
+ }
7036
+
7003
7037
if ((numberOfClasses < 1 ) && (numberOfMethods < 1 ))
7004
7038
{
7005
7039
if (verboseLogging)
@@ -7186,6 +7220,58 @@ void Compiler::pickGDV(GenTreeCall* call,
7186
7220
JITDUMP (" Accepting type %s with likelihood %u as a candidate\n " ,
7187
7221
eeGetClassName (classGuesses[guessIdx]), likelihoods[guessIdx])
7188
7222
}
7223
+
7224
+ // If the 'this' arg to the call is an enumerator var, record any
7225
+ // dominant likely class so we can possibly infer a GDV at places where we
7226
+ // never observed the var's value. (eg an unreached Dispose call if
7227
+ // control is hijacked out of Tier0+i by OSR).
7228
+ //
7229
+ // Note enumerator vars are special as they are generally not redefined
7230
+ // and we want to ensure all methods called on them get inlined to enable
7231
+ // escape analysis to kick in, if possible.
7232
+ //
7233
+ const unsigned dominantLikelihood = 50 ;
7234
+
7235
+ if (!isInferredGDV && (likelihoods[guessIdx] >= dominantLikelihood))
7236
+ {
7237
+ CallArg* const thisArg = call->gtArgs .FindWellKnownArg (WellKnownArg::ThisPointer);
7238
+
7239
+ if (thisArg != nullptr )
7240
+ {
7241
+ GenTree* const thisNode = thisArg->GetEarlyNode ();
7242
+ if (thisNode->OperIs (GT_LCL_VAR))
7243
+ {
7244
+ GenTreeLclVarCommon* thisLclNode = thisNode->AsLclVarCommon ();
7245
+ LclVarDsc* const thisVarDsc = lvaGetDesc (thisLclNode);
7246
+ unsigned const thisLclNum = thisLclNode->GetLclNum ();
7247
+
7248
+ if (thisVarDsc->lvIsEnumerator )
7249
+ {
7250
+ VarToLikelyClassMap* const map = getImpEnumeratorLikelyTypeMap ();
7251
+
7252
+ // If we have multiple type observations, we just use the first.
7253
+ //
7254
+ // Note importation order is somewhat reverse-post-orderish;
7255
+ // a block is only imported if one of its imported preds is imported.
7256
+ //
7257
+ // Enumerator vars tend to have a dominating MoveNext call that will
7258
+ // be the one subsequent uses will see, if they lack their own
7259
+ // type observations.
7260
+ //
7261
+ if (!map->Lookup (thisLclNum))
7262
+ {
7263
+ InferredGdvEntry e;
7264
+ e.m_classHandle = classGuesses[guessIdx];
7265
+ e.m_likelihood = likelihoods[guessIdx];
7266
+
7267
+ JITDUMP (" Remembering that V%02u has %u%% likely class %s\n " , thisLclNum,
7268
+ e.m_likelihood , eeGetClassName (e.m_classHandle ));
7269
+ map->Set (thisLclNum, e);
7270
+ }
7271
+ }
7272
+ }
7273
+ }
7274
+ }
7189
7275
}
7190
7276
else
7191
7277
{
0 commit comments