objOp = opOther->AsCall()->gtCallThisArg->GetNode();
}
+ bool pIsExact = false;
+ bool pIsNonNull = false;
+ CORINFO_CLASS_HANDLE objCls = gtGetClassHandle(objOp, &pIsExact, &pIsNonNull);
+
+ // if both classes are "final" (e.g. System.String[]) we can replace the comparison
+ // with `true/false` + null check.
+ if ((objCls != NO_CLASS_HANDLE) && (pIsExact || impIsClassExact(objCls)))
+ {
+ TypeCompareState tcs = info.compCompHnd->compareTypesForEquality(objCls, clsHnd);
+ if (tcs != TypeCompareState::May)
+ {
+ const bool operatorIsEQ = oper == GT_EQ;
+ const bool typesAreEqual = tcs == TypeCompareState::Must;
+ GenTree* compareResult = gtNewIconNode((operatorIsEQ ^ typesAreEqual) ? 0 : 1);
+
+ if (!pIsNonNull)
+ {
+ // we still have to emit a null-check
+ // obj.GetType == typeof() -> (nullcheck) true/false
+ GenTree* nullcheck = gtNewNullCheck(objOp, compCurBB);
+ return gtNewOperNode(GT_COMMA, tree->TypeGet(), nullcheck, compareResult);
+ }
+ else if (objOp->gtFlags & GTF_ALL_EFFECT)
+ {
+ return gtNewOperNode(GT_COMMA, tree->TypeGet(), objOp, compareResult);
+ }
+ else
+ {
+ return compareResult;
+ }
+ }
+ }
+
GenTree* const objMT = gtNewOperNode(GT_IND, TYP_I_IMPL, objOp);
// Update various flags
// variance or similar.
//
// Note:
-// We are conservative on arrays here. It might be worth checking
-// for types like int[].
+// We are conservative on arrays of primitive types here.
bool Compiler::impIsClassExact(CORINFO_CLASS_HANDLE classHnd)
{
DWORD flags = info.compCompHnd->getClassAttribs(classHnd);
DWORD flagsMask = CORINFO_FLG_FINAL | CORINFO_FLG_VARIANCE | CORINFO_FLG_ARRAY;
- return ((flags & flagsMask) == CORINFO_FLG_FINAL);
+ if ((flags & flagsMask) == CORINFO_FLG_FINAL)
+ {
+ return true;
+ }
+ if ((flags & flagsMask) == (CORINFO_FLG_FINAL | CORINFO_FLG_ARRAY))
+ {
+ CORINFO_CLASS_HANDLE arrayElementHandle = nullptr;
+ CorInfoType type = info.compCompHnd->getChildType(classHnd, &arrayElementHandle);
+
+ if ((type == CORINFO_TYPE_CLASS) || (type == CORINFO_TYPE_VALUECLASS))
+ {
+ return impIsClassExact(arrayElementHandle);
+ }
+ }
+ return false;
}
//------------------------------------------------------------------------