/*********************************************************************/
// 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;
}
/*********************************************************************/
// 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;
}
/*********************************************************************/
--- /dev/null
+// 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<Q>
+{
+ [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<P>()
+ {
+ return typeof(Q) == typeof(P);
+ }
+}
+
+class X
+{
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static bool Is<Q>(object o)
+ {
+ return typeof(Q) == o.GetType();
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static bool IsR<Q>(object o)
+ {
+ return o.GetType() == typeof(Q);
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static bool Is<P,Q>()
+ {
+ 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<string>.Is(s);
+ passed &= X<object>.Is(o);
+ passed &= X<string[]>.Is(sarray);
+ passed &= X<object[]>.Is(oarray);
+
+ passed &= X<string>.IsR(s);
+
+ passed &= X.Is<string, string>();
+
+ passed &= X.Is<string>(s);
+ passed &= X.Is<object>(o);
+ passed &= X.Is<string[]>(sarray);
+ passed &= X.Is<object[]>(oarray);
+
+ passed &= X.IsR<string>(s);
+
+ passed &= X<string>.Is<string>();
+
+ // negative cases
+ bool failed = false;
+
+ failed |= X<string>.Is(o);
+ failed |= X<object>.Is(s);
+ failed |= X<string[]>.Is(oarray);
+ failed |= X<object[]>.Is(sarray);
+
+ failed |= X<string>.IsR(o);
+
+ failed |= X.Is<string, object>();
+
+ failed |= X.Is<string>(o);
+ failed |= X.Is<object>(s);
+ failed |= X.Is<string[]>(oarray);
+ failed |= X.Is<object[]>(sarray);
+
+ failed |= X.IsR<string>(o);
+
+ failed |= X<object>.Is<string>();
+
+ return passed && !failed ? 100 : -1;
+ }
+}