RyuJIT: Optimize `obj.GetType() != typeof(X)` for sealed classes (#32790)
authorEgor Bogatov <egorbo@gmail.com>
Thu, 27 Feb 2020 15:47:16 +0000 (18:47 +0300)
committerGitHub <noreply@github.com>
Thu, 27 Feb 2020 15:47:16 +0000 (07:47 -0800)
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
src/coreclr/src/jit/importer.cpp

index 053482e..5ea3bea 100644 (file)
@@ -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
index 6d1079e..df51349 100644 (file)
@@ -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;
 }
 
 //------------------------------------------------------------------------