summaryrefslogtreecommitdiff
path: root/src/ToolBox
diff options
context:
space:
mode:
authorAndy Ayers <andya@microsoft.com>2017-09-27 07:15:04 -0700
committerGitHub <noreply@github.com>2017-09-27 07:15:04 -0700
commitccc5e17738a4b2f652059f31e8146513163dbee7 (patch)
treeeb7fe9d6b30b01d02a6b8bbe454333607899d507 /src/ToolBox
parent9509fc86a50ad107ee4d601e917cf072f135aa5e (diff)
downloadcoreclr-ccc5e17738a4b2f652059f31e8146513163dbee7.tar.gz
coreclr-ccc5e17738a4b2f652059f31e8146513163dbee7.tar.bz2
coreclr-ccc5e17738a4b2f652059f31e8146513163dbee7.zip
JIT: devirtualization support for EqualityComparer<T>.Default (#14125)
Mark `EqualityComparer<T>.Default`'s getter as `[Intrinsic]` so the jit knows there is something special about it. Extend the jit's named intrinsic recognizer to recognize this method. Add a new jit interface method to determine the exact type returned by `EqualityComparer<T>.Default`, given `T`. Compute the return type by mirroring the logic used in the actual implementation. Bail out when `T` is not final as those cases won't simplify down much and lead to code bloat. Invoke this interface method when trying to devirtualize calls where the 'this' object in the call comes from `EqualityComparer<T>.Default`. The devirtualized methods can then be inlined. Since the specific comparer `Equal` and `GetHashCode` methods look more complicated in IL than they really are, mark them with AggressiveInlining attributes. If devirtualization and inlining happen, it is quite likely that the value of the comparer object itself is not used in the body of the comparer. This value comes from a static field cache on the comparer helper. When the comparer value is ignored, the jit removes the field access since it is non-faulting. It also removes the the class init helper that is there to ensure that the (no-longer accessed) field is properly initialized. This helper has relatively high overhead even in the fast case where the class has been initialized aready. Add a perf test. Closes #6688.
Diffstat (limited to 'src/ToolBox')
-rw-r--r--src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h12
-rw-r--r--src/ToolBox/superpmi/superpmi-shared/lwmlist.h1
-rw-r--r--src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp17
-rw-r--r--src/ToolBox/superpmi/superpmi-shared/methodcontext.h8
-rw-r--r--src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp10
-rw-r--r--src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp8
-rw-r--r--src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp7
-rw-r--r--src/ToolBox/superpmi/superpmi/icorjitinfo.cpp9
8 files changed, 69 insertions, 3 deletions
diff --git a/src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h b/src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h
index 4ce775d177..29baaa8a39 100644
--- a/src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h
+++ b/src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h
@@ -119,6 +119,15 @@ CORINFO_METHOD_HANDLE resolveVirtualMethod(CORINFO_METHOD_HANDLE virtualMethod,
CORINFO_CLASS_HANDLE implementingClass,
CORINFO_CONTEXT_HANDLE ownerType);
+// Given T, return the type of the default EqualityComparer<T>.
+// Returns null if the type can't be determined exactly.
+CORINFO_CLASS_HANDLE getDefaultEqualityComparerClass(CORINFO_CLASS_HANDLE elemType);
+
+// Given resolved token that corresponds to an intrinsic classified as
+// a CORINFO_INTRINSIC_GetRawHandle intrinsic, fetch the handle associated
+// with the token. If this is not possible at compile-time (because the current method's
+// code is shared and the token contains generic parameters) then indicate
+// how the handle should be looked up at runtime.
void expandRawHandleIntrinsic(
CORINFO_RESOLVED_TOKEN * pResolvedToken,
CORINFO_GENERICHANDLE_RESULT * pResult);
@@ -126,8 +135,7 @@ void expandRawHandleIntrinsic(
// If a method's attributes have (getMethodAttribs) CORINFO_FLG_INTRINSIC set,
// getIntrinsicID() returns the intrinsic ID.
// *pMustExpand tells whether or not JIT must expand the intrinsic.
-CorInfoIntrinsics getIntrinsicID(CORINFO_METHOD_HANDLE method, bool* pMustExpand = NULL /* OUT */
- );
+CorInfoIntrinsics getIntrinsicID(CORINFO_METHOD_HANDLE method, bool* pMustExpand = NULL /* OUT */);
// Is the given module the System.Numerics.Vectors module?
// This defaults to false.
diff --git a/src/ToolBox/superpmi/superpmi-shared/lwmlist.h b/src/ToolBox/superpmi/superpmi-shared/lwmlist.h
index 898641c790..21f7906510 100644
--- a/src/ToolBox/superpmi/superpmi-shared/lwmlist.h
+++ b/src/ToolBox/superpmi/superpmi-shared/lwmlist.h
@@ -69,6 +69,7 @@ LWM(GetClassName, DWORDLONG, DWORD)
LWM(GetClassNumInstanceFields, DWORDLONG, DWORD)
LWM(GetClassSize, DWORDLONG, DWORD)
LWM(GetCookieForPInvokeCalliSig, GetCookieForPInvokeCalliSigValue, DLDL)
+LWM(GetDefaultEqualityComparerClass, DWORDLONG, DWORDLONG)
LWM(GetDelegateCtor, Agnostic_GetDelegateCtorIn, Agnostic_GetDelegateCtorOut)
LWM(GetEEInfo, DWORD, Agnostic_CORINFO_EE_INFO)
LWM(GetEHinfo, DLD, Agnostic_CORINFO_EH_CLAUSE)
diff --git a/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp b/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp
index 02a940d2b5..0bf288d196 100644
--- a/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp
+++ b/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp
@@ -3012,6 +3012,23 @@ CORINFO_METHOD_HANDLE MethodContext::repResolveVirtualMethod(CORINFO_METHOD_HAND
return (CORINFO_METHOD_HANDLE)result;
}
+void MethodContext::recGetDefaultEqualityComparerClass(CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE result)
+{
+ if (GetDefaultEqualityComparerClass == nullptr)
+ GetDefaultEqualityComparerClass = new LightWeightMap<DWORDLONG, DWORDLONG>();
+
+ GetDefaultEqualityComparerClass->Add((DWORDLONG)cls, (DWORDLONG)result);
+}
+void MethodContext::dmpGetDefaultEqualityComparerClass(DWORDLONG key, DWORDLONG value)
+{
+ printf("GetDefaultEqualityComparerClass key cls-%016llX, value cls-%016llX", key, value);
+}
+CORINFO_CLASS_HANDLE MethodContext::repGetDefaultEqualityComparerClass(CORINFO_CLASS_HANDLE cls)
+{
+ CORINFO_CLASS_HANDLE result = (CORINFO_CLASS_HANDLE)GetDefaultEqualityComparerClass->Get((DWORDLONG)cls);
+ return result;
+}
+
void MethodContext::recGetTokenTypeAsHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_CLASS_HANDLE result)
{
if (GetTokenTypeAsHandle == nullptr)
diff --git a/src/ToolBox/superpmi/superpmi-shared/methodcontext.h b/src/ToolBox/superpmi/superpmi-shared/methodcontext.h
index 7f79b2b9f6..52515733d3 100644
--- a/src/ToolBox/superpmi/superpmi-shared/methodcontext.h
+++ b/src/ToolBox/superpmi/superpmi-shared/methodcontext.h
@@ -872,6 +872,11 @@ public:
CORINFO_CLASS_HANDLE implClass,
CORINFO_CONTEXT_HANDLE ownerType);
+ void recGetDefaultEqualityComparerClass(CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE result);
+ void dmpGetDefaultEqualityComparerClass(DWORDLONG key, DWORDLONG value);
+ CORINFO_CLASS_HANDLE repGetDefaultEqualityComparerClass(CORINFO_CLASS_HANDLE cls);
+
+
void recGetTokenTypeAsHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_CLASS_HANDLE result);
void dmpGetTokenTypeAsHandle(const GetTokenTypeAsHandleValue& key, DWORDLONG value);
CORINFO_CLASS_HANDLE repGetTokenTypeAsHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken);
@@ -1252,7 +1257,7 @@ private:
};
// ********************* Please keep this up-to-date to ease adding more ***************
-// Highest packet number: 161
+// Highest packet number: 162
// *************************************************************************************
enum mcPackets
{
@@ -1319,6 +1324,7 @@ enum mcPackets
Packet_GetIntConfigValue = 151, // Added 2/12/2015
Packet_GetStringConfigValue = 152, // Added 2/12/2015
Packet_GetCookieForPInvokeCalliSig = 48,
+ Packet_GetDefaultEqualityComparerClass = 162, // Added 9/24/2017
Packet_GetDelegateCtor = 49,
Packet_GetEEInfo = 50,
Packet_GetEHinfo = 51,
diff --git a/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp
index 2a477a07e3..6051de8840 100644
--- a/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp
+++ b/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp
@@ -236,6 +236,16 @@ CORINFO_METHOD_HANDLE interceptor_ICJI::resolveVirtualMethod(CORINFO_METHOD_HAND
return result;
}
+// Given T, return the type of the default EqualityComparer<T>.
+// Returns null if the type can't be determined exactly.
+CORINFO_CLASS_HANDLE interceptor_ICJI::getDefaultEqualityComparerClass(CORINFO_CLASS_HANDLE cls)
+{
+ mc->cr->AddCall("getDefaultEqualityComparerClass");
+ CORINFO_CLASS_HANDLE result = original_ICorJitInfo->getDefaultEqualityComparerClass(cls);
+ mc->recGetDefaultEqualityComparerClass(cls, result);
+ return result;
+}
+
void interceptor_ICJI::expandRawHandleIntrinsic(
CORINFO_RESOLVED_TOKEN * pResolvedToken,
CORINFO_GENERICHANDLE_RESULT * pResult)
diff --git a/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp b/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp
index a54ead5661..17da100dac 100644
--- a/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp
+++ b/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp
@@ -163,6 +163,14 @@ CORINFO_METHOD_HANDLE interceptor_ICJI::resolveVirtualMethod(CORINFO_METHOD_HAND
return original_ICorJitInfo->resolveVirtualMethod(virtualMethod, implementingClass, ownerType);
}
+// Given T, return the type of the default EqualityComparer<T>.
+// Returns null if the type can't be determined exactly.
+CORINFO_CLASS_HANDLE interceptor_ICJI::getDefaultEqualityComparerClass(CORINFO_CLASS_HANDLE cls)
+{
+ mcs->AddCall("getDefaultEqualityComparerClass");
+ return original_ICorJitInfo->getDefaultEqualityComparerClass(cls);
+}
+
void interceptor_ICJI::expandRawHandleIntrinsic(
CORINFO_RESOLVED_TOKEN * pResolvedToken,
CORINFO_GENERICHANDLE_RESULT * pResult)
diff --git a/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp b/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp
index 7e0ded9f0f..df4cfcfbcd 100644
--- a/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp
+++ b/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp
@@ -150,6 +150,13 @@ CORINFO_METHOD_HANDLE interceptor_ICJI::resolveVirtualMethod(CORINFO_METHOD_HAND
return original_ICorJitInfo->resolveVirtualMethod(virtualMethod, implementingClass, ownerType);
}
+// Given T, return the type of the default EqualityComparer<T>.
+// Returns null if the type can't be determined exactly.
+CORINFO_CLASS_HANDLE interceptor_ICJI::getDefaultEqualityComparerClass(CORINFO_CLASS_HANDLE cls)
+{
+ return original_ICorJitInfo->getDefaultEqualityComparerClass(cls);
+}
+
void interceptor_ICJI::expandRawHandleIntrinsic(
CORINFO_RESOLVED_TOKEN * pResolvedToken,
CORINFO_GENERICHANDLE_RESULT * pResult)
diff --git a/src/ToolBox/superpmi/superpmi/icorjitinfo.cpp b/src/ToolBox/superpmi/superpmi/icorjitinfo.cpp
index 2e78113991..7c119b86dd 100644
--- a/src/ToolBox/superpmi/superpmi/icorjitinfo.cpp
+++ b/src/ToolBox/superpmi/superpmi/icorjitinfo.cpp
@@ -185,6 +185,15 @@ CORINFO_METHOD_HANDLE MyICJI::resolveVirtualMethod(CORINFO_METHOD_HANDLE virtua
return result;
}
+// Given T, return the type of the default EqualityComparer<T>.
+// Returns null if the type can't be determined exactly.
+CORINFO_CLASS_HANDLE MyICJI::getDefaultEqualityComparerClass(CORINFO_CLASS_HANDLE cls)
+{
+ jitInstance->mc->cr->AddCall("getDefaultEqualityComparerClass");
+ CORINFO_CLASS_HANDLE result = jitInstance->mc->repGetDefaultEqualityComparerClass(cls);
+ return result;
+}
+
void MyICJI::expandRawHandleIntrinsic(
CORINFO_RESOLVED_TOKEN * pResolvedToken,
CORINFO_GENERICHANDLE_RESULT * pResult)