From b5c5b87238ffc51b0f05f6cd49ce07b8a4407703 Mon Sep 17 00:00:00 2001 From: Andy Ayers Date: Wed, 29 Jan 2020 00:47:56 -0800 Subject: [PATCH] Enable inline type checks for all type equality cases (#2276) Now that method tables are not shared by distinct types, we can always emit inlined type equality tests. Closes #1258. --- src/coreclr/src/vm/jitinterface.cpp | 64 ++---------- .../tests/src/JIT/Intrinsics/TypeEquality.cs | 107 +++++++++++++++++++++ .../tests/src/JIT/Intrinsics/TypeEquality_r.csproj | 10 ++ .../src/JIT/Intrinsics/TypeEquality_ro.csproj | 10 ++ .../tests/src/JIT/Intrinsics/TypeIntrinsics.cs | 7 +- 5 files changed, 139 insertions(+), 59 deletions(-) create mode 100644 src/coreclr/tests/src/JIT/Intrinsics/TypeEquality.cs create mode 100644 src/coreclr/tests/src/JIT/Intrinsics/TypeEquality_r.csproj create mode 100644 src/coreclr/tests/src/JIT/Intrinsics/TypeEquality_ro.csproj diff --git a/src/coreclr/src/vm/jitinterface.cpp b/src/coreclr/src/vm/jitinterface.cpp index 0a32499..725ac62 100644 --- a/src/coreclr/src/vm/jitinterface.cpp +++ b/src/coreclr/src/vm/jitinterface.cpp @@ -3759,37 +3759,14 @@ BOOL CEEInfo::isValueClass(CORINFO_CLASS_HANDLE clsHnd) /*********************************************************************/ // Decides how the JIT should do the optimization to inline the check for -// GetTypeFromHandle(handle) == obj.GetType() (for CORINFO_INLINE_TYPECHECK_SOURCE_VTABLE) -// GetTypeFromHandle(X) == GetTypeFromHandle(Y) (for CORINFO_INLINE_TYPECHECK_SOURCE_TOKEN) +// GetTypeFromHandle(handle) == obj.GetType() +// GetTypeFromHandle(X) == GetTypeFromHandle(Y) // // This will enable to use directly the typehandle instead of going through getClassByHandle CorInfoInlineTypeCheck CEEInfo::canInlineTypeCheck(CORINFO_CLASS_HANDLE clsHnd, CorInfoInlineTypeCheckSource source) { - CONTRACTL { - NOTHROW; - GC_NOTRIGGER; - MODE_PREEMPTIVE; - } CONTRACTL_END; - - CorInfoInlineTypeCheck ret; - - JIT_TO_EE_TRANSITION_LEAF(); - - if (source == CORINFO_INLINE_TYPECHECK_SOURCE_TOKEN) - { - // It's always okay to compare type handles coming from IL tokens - ret = CORINFO_INLINE_TYPECHECK_PASS; - } - else - { - _ASSERTE(source == CORINFO_INLINE_TYPECHECK_SOURCE_VTABLE); - ret = canInlineTypeCheckWithObjectVTable(clsHnd) ? - CORINFO_INLINE_TYPECHECK_PASS : CORINFO_INLINE_TYPECHECK_NONE; - } - - EE_TO_JIT_TRANSITION_LEAF(); - - return(ret); + LIMITED_METHOD_CONTRACT; + return CORINFO_INLINE_TYPECHECK_PASS; } /*********************************************************************/ @@ -3799,37 +3776,8 @@ CorInfoInlineTypeCheck CEEInfo::canInlineTypeCheck(CORINFO_CLASS_HANDLE clsHnd, // This will enable to use directly the typehandle instead of going through getClassByHandle BOOL CEEInfo::canInlineTypeCheckWithObjectVTable (CORINFO_CLASS_HANDLE clsHnd) { - CONTRACTL { - NOTHROW; - GC_NOTRIGGER; - MODE_PREEMPTIVE; - } CONTRACTL_END; - - BOOL ret = FALSE; - - JIT_TO_EE_TRANSITION_LEAF(); - - _ASSERTE(clsHnd); - - TypeHandle VMClsHnd(clsHnd); - if (VMClsHnd == TypeHandle(g_pCanonMethodTableClass)) - { - // We can't do this optimization in shared generics code because of we do not know what the actual type is going to be. - // (It can be array, marshalbyref, etc.) - ret = FALSE; - } - else - { - // It is safe to perform this optimization - // NOTE: clsHnd could be a TypeDesc with shared MethodTable (ex: typeof(int*) == o.GetType()), but that is still optimizable. - // That is because optimized version compares literally a handle to a methodtable and that will be not equal, - // which is valid since none of MethodDesc types can have heap instances. - ret = TRUE; - } - - EE_TO_JIT_TRANSITION_LEAF(); - - return(ret); + LIMITED_METHOD_CONTRACT; + return TRUE; } /*********************************************************************/ diff --git a/src/coreclr/tests/src/JIT/Intrinsics/TypeEquality.cs b/src/coreclr/tests/src/JIT/Intrinsics/TypeEquality.cs new file mode 100644 index 0000000..aa4fad2 --- /dev/null +++ b/src/coreclr/tests/src/JIT/Intrinsics/TypeEquality.cs @@ -0,0 +1,107 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// + +using System; +using System.Runtime.CompilerServices; + +// Optimization of type equality tests to various +// vtable and handle comparisons. + +class X +{ + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Is(object o) + { + return typeof(Q) == o.GetType(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool IsR(object o) + { + return o.GetType() == typeof(Q); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Is

() + { + return typeof(Q) == typeof(P); + } +} + +class X +{ + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Is(object o) + { + return typeof(Q) == o.GetType(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool IsR(object o) + { + return o.GetType() == typeof(Q); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Is() + { + return typeof(Q) == typeof(P); + } +} + +class P +{ + public static int Main() + { + bool passed = true; + + string s = "string"; + object o = new object(); + string[] sarray = new string[0]; + object[] oarray = new object[0]; + + // positive cases + passed &= X.Is(s); + passed &= X.Is(o); + passed &= X.Is(sarray); + passed &= X.Is(oarray); + + passed &= X.IsR(s); + + passed &= X.Is(); + + passed &= X.Is(s); + passed &= X.Is(o); + passed &= X.Is(sarray); + passed &= X.Is(oarray); + + passed &= X.IsR(s); + + passed &= X.Is(); + + // negative cases + bool failed = false; + + failed |= X.Is(o); + failed |= X.Is(s); + failed |= X.Is(oarray); + failed |= X.Is(sarray); + + failed |= X.IsR(o); + + failed |= X.Is(); + + failed |= X.Is(o); + failed |= X.Is(s); + failed |= X.Is(oarray); + failed |= X.Is(sarray); + + failed |= X.IsR(o); + + failed |= X.Is(); + + return passed && !failed ? 100 : -1; + } +} diff --git a/src/coreclr/tests/src/JIT/Intrinsics/TypeEquality_r.csproj b/src/coreclr/tests/src/JIT/Intrinsics/TypeEquality_r.csproj new file mode 100644 index 0000000..2e353c5 --- /dev/null +++ b/src/coreclr/tests/src/JIT/Intrinsics/TypeEquality_r.csproj @@ -0,0 +1,10 @@ + + + Exe + None + + + + + + diff --git a/src/coreclr/tests/src/JIT/Intrinsics/TypeEquality_ro.csproj b/src/coreclr/tests/src/JIT/Intrinsics/TypeEquality_ro.csproj new file mode 100644 index 0000000..71027d7 --- /dev/null +++ b/src/coreclr/tests/src/JIT/Intrinsics/TypeEquality_ro.csproj @@ -0,0 +1,10 @@ + + + Exe + None + True + + + + + diff --git a/src/coreclr/tests/src/JIT/Intrinsics/TypeIntrinsics.cs b/src/coreclr/tests/src/JIT/Intrinsics/TypeIntrinsics.cs index 6dee554..179e96f 100644 --- a/src/coreclr/tests/src/JIT/Intrinsics/TypeIntrinsics.cs +++ b/src/coreclr/tests/src/JIT/Intrinsics/TypeIntrinsics.cs @@ -1,3 +1,8 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// + using System; using System.Collections; using System.Collections.Generic; @@ -174,4 +179,4 @@ public struct GenericStruct public enum SimpleEnum { A,B,C -} \ No newline at end of file +} -- 2.7.4