@@ -19168,10 +19168,17 @@ CORINFO_CLASS_HANDLE Compiler::gtGetClassHandle(GenTree* tree, bool* pIsExact, b
1916819168 // No benefit to calling gtGetFieldClassHandle here, as
1916919169 // the exact field being accessed can vary.
1917019170 CORINFO_FIELD_HANDLE fieldHnd = fieldSeq->GetFieldHandle();
19171+ CORINFO_CLASS_HANDLE fieldOwner = NO_CLASS_HANDLE;
1917119172 CORINFO_CLASS_HANDLE fieldClass = NO_CLASS_HANDLE;
19172- var_types fieldType = eeGetFieldType(fieldHnd, &fieldClass);
1917319173
19174- if (fieldType == TYP_REF)
19174+ // fieldOwner helps us to get a more exact field class for instance fields
19175+ if (!fieldSeq->IsStaticField())
19176+ {
19177+ bool objIsExact, objIsNonNull;
19178+ fieldOwner = gtGetClassHandle(op1, &objIsExact, &objIsNonNull);
19179+ }
19180+
19181+ if (eeGetFieldType(fieldHnd, &fieldClass, fieldOwner) == TYP_REF)
1917519182 {
1917619183 objClass = fieldClass;
1917719184 }
@@ -31840,3 +31847,116 @@ GenTree* Compiler::gtFoldExprHWIntrinsic(GenTreeHWIntrinsic* tree)
3184031847 return resultNode;
3184131848}
3184231849#endif // FEATURE_HW_INTRINSICS
31850+
31851+ //------------------------------------------------------------------------
31852+ // gtCanSkipCovariantStoreCheck: see if storing a ref type value to an array
31853+ // can skip the array store covariance check.
31854+ //
31855+ // Arguments:
31856+ // value -- tree producing the value to store
31857+ // array -- tree representing the array to store to
31858+ //
31859+ // Returns:
31860+ // true if the store does not require a covariance check.
31861+ //
31862+ bool Compiler::gtCanSkipCovariantStoreCheck(GenTree* value, GenTree* array)
31863+ {
31864+ // We should only call this when optimizing.
31865+ assert(opts.OptimizationEnabled());
31866+
31867+ // Check for store to same array, ie. arrLcl[i] = arrLcl[j]
31868+ if (value->OperIs(GT_IND) && value->AsIndir()->Addr()->OperIs(GT_INDEX_ADDR) && array->OperIs(GT_LCL_VAR))
31869+ {
31870+ GenTree* valueArray = value->AsIndir()->Addr()->AsIndexAddr()->Arr();
31871+ if (valueArray->OperIs(GT_LCL_VAR))
31872+ {
31873+ unsigned valueArrayLcl = valueArray->AsLclVar()->GetLclNum();
31874+ unsigned arrayLcl = array->AsLclVar()->GetLclNum();
31875+ if ((valueArrayLcl == arrayLcl) && !lvaGetDesc(arrayLcl)->IsAddressExposed())
31876+ {
31877+ JITDUMP("\nstelem of ref from same array: skipping covariant store check\n");
31878+ return true;
31879+ }
31880+ }
31881+ }
31882+
31883+ // Check for store of NULL.
31884+ if (value->OperIs(GT_CNS_INT))
31885+ {
31886+ assert(value->gtType == TYP_REF);
31887+ if (value->AsIntCon()->gtIconVal == 0)
31888+ {
31889+ JITDUMP("\nstelem of null: skipping covariant store check\n");
31890+ return true;
31891+ }
31892+ // Non-0 const refs can only occur with frozen objects
31893+ assert(value->IsIconHandle(GTF_ICON_OBJ_HDL));
31894+ assert(doesMethodHaveFrozenObjects() ||
31895+ (compIsForInlining() && impInlineInfo->InlinerCompiler->doesMethodHaveFrozenObjects()));
31896+ }
31897+
31898+ // Try and get a class handle for the array
31899+ if (!value->TypeIs(TYP_REF))
31900+ {
31901+ return false;
31902+ }
31903+
31904+ bool arrayIsExact = false;
31905+ bool arrayIsNonNull = false;
31906+ CORINFO_CLASS_HANDLE arrayHandle = gtGetClassHandle(array, &arrayIsExact, &arrayIsNonNull);
31907+
31908+ if (arrayHandle == NO_CLASS_HANDLE)
31909+ {
31910+ return false;
31911+ }
31912+
31913+ // There are some methods in corelib where we're storing to an array but the IL
31914+ // doesn't reflect this (see SZArrayHelper). Avoid.
31915+ DWORD attribs = info.compCompHnd->getClassAttribs(arrayHandle);
31916+ if ((attribs & CORINFO_FLG_ARRAY) == 0)
31917+ {
31918+ return false;
31919+ }
31920+
31921+ CORINFO_CLASS_HANDLE arrayElementHandle = nullptr;
31922+ CorInfoType arrayElemType = info.compCompHnd->getChildType(arrayHandle, &arrayElementHandle);
31923+
31924+ // Verify array type handle is really an array of ref type
31925+ assert(arrayElemType == CORINFO_TYPE_CLASS);
31926+
31927+ // Check for exactly object[]
31928+ if (arrayIsExact && (arrayElementHandle == impGetObjectClass()))
31929+ {
31930+ JITDUMP("\nstelem to (exact) object[]: skipping covariant store check\n");
31931+ return true;
31932+ }
31933+
31934+ const bool arrayTypeIsSealed = info.compCompHnd->isExactType(arrayElementHandle);
31935+
31936+ if ((!arrayIsExact && !arrayTypeIsSealed) || (arrayElementHandle == NO_CLASS_HANDLE))
31937+ {
31938+ // Bail out if we don't know array's exact type
31939+ return false;
31940+ }
31941+
31942+ bool valueIsExact = false;
31943+ bool valueIsNonNull = false;
31944+ CORINFO_CLASS_HANDLE valueHandle = gtGetClassHandle(value, &valueIsExact, &valueIsNonNull);
31945+
31946+ // Array's type is sealed and equals to value's type
31947+ if (arrayTypeIsSealed && (valueHandle == arrayElementHandle))
31948+ {
31949+ JITDUMP("\nstelem to T[] with T exact: skipping covariant store check\n");
31950+ return true;
31951+ }
31952+
31953+ // Array's type is not sealed but we know its exact type
31954+ if (arrayIsExact && (valueHandle != NO_CLASS_HANDLE) &&
31955+ (info.compCompHnd->compareTypesForCast(valueHandle, arrayElementHandle) == TypeCompareState::Must))
31956+ {
31957+ JITDUMP("\nstelem to T[] with T exact: skipping covariant store check\n");
31958+ return true;
31959+ }
31960+
31961+ return false;
31962+ }
0 commit comments