From 366a4d6233091ad220b76afe3614a28cdcb3f588 Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Thu, 27 Feb 2020 18:47:16 +0300 Subject: [PATCH] RyuJIT: Optimize `obj.GetType() != typeof(X)` for sealed classes (#32790) An array type with value type or final ref type elements is exact. Use this to optimize more cases of type equality checking. --- src/coreclr/src/jit/gentree.cpp | 33 +++++++++++++++++++++++++++++++++ src/coreclr/src/jit/importer.cpp | 19 ++++++++++++++++--- 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/src/coreclr/src/jit/gentree.cpp b/src/coreclr/src/jit/gentree.cpp index 053482e..5ea3bea 100644 --- a/src/coreclr/src/jit/gentree.cpp +++ b/src/coreclr/src/jit/gentree.cpp @@ -12503,6 +12503,39 @@ GenTree* Compiler::gtFoldTypeCompare(GenTree* tree) 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 diff --git a/src/coreclr/src/jit/importer.cpp b/src/coreclr/src/jit/importer.cpp index 6d1079e..df51349 100644 --- a/src/coreclr/src/jit/importer.cpp +++ b/src/coreclr/src/jit/importer.cpp @@ -20654,15 +20654,28 @@ void Compiler::addExpRuntimeLookupCandidate(GenTreeCall* call) // 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; } //------------------------------------------------------------------------ -- 2.7.4