summaryrefslogtreecommitdiff
path: root/src/vm/jitinterface.cpp
diff options
context:
space:
mode:
authorJan Kotas <jkotas@microsoft.com>2018-12-21 09:25:24 -0800
committerGitHub <noreply@github.com>2018-12-21 09:25:24 -0800
commit82e02f37564f83c3a7c90e5e28a652a39017701a (patch)
tree3df12a74b2c4667afbb17f011c03a8266fda191a /src/vm/jitinterface.cpp
parent63ab188ccae6cc1b0c65103db7f453833e2c19a8 (diff)
downloadcoreclr-82e02f37564f83c3a7c90e5e28a652a39017701a.tar.gz
coreclr-82e02f37564f83c3a7c90e5e28a652a39017701a.tar.bz2
coreclr-82e02f37564f83c3a7c90e5e28a652a39017701a.zip
Streamline default EqualityComparer and Comparer for Enums (#21604)
This borrows the implementation strategy for these from CoreRT. It makes it both simpler (fewer types and lines of code) and faster in some cases since we always use the exact right underlying type. E.g. The following micro-benchmark is 25% faster with this change: ``` enum MyEnum : byte { x, y }; var comparer = Comparer<MyEnum>.Default; for (int i = 0; i < 100000000; i++) { comparer.Compare(MyEnum.x, MyEnum.y); comparer.Compare(MyEnum.y, MyEnum.x); } ```
Diffstat (limited to 'src/vm/jitinterface.cpp')
-rw-r--r--src/vm/jitinterface.cpp61
1 files changed, 43 insertions, 18 deletions
diff --git a/src/vm/jitinterface.cpp b/src/vm/jitinterface.cpp
index 2d87c276c8..3e1765a0d7 100644
--- a/src/vm/jitinterface.cpp
+++ b/src/vm/jitinterface.cpp
@@ -6973,7 +6973,7 @@ bool getILIntrinsicImplementation(MethodDesc * ftn,
// Compare tokens to cover all generic instantiations
// The body of the first method is simply ret Arg0. The second one first casts the arg to I4.
- if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__UNSAFE_ENUM_CAST)->GetMemberDef())
+ if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__ENUM_EQUALS)->GetMemberDef())
{
// Normally we would follow the above pattern and unconditionally replace the IL,
// relying on generic type constraints to guarantee that it will only ever be instantiated
@@ -7000,19 +7000,20 @@ bool getILIntrinsicImplementation(MethodDesc * ftn,
et == ELEMENT_TYPE_I2 ||
et == ELEMENT_TYPE_U2 ||
et == ELEMENT_TYPE_I1 ||
- et == ELEMENT_TYPE_U1)
+ et == ELEMENT_TYPE_U1 ||
+ et == ELEMENT_TYPE_I8 ||
+ et == ELEMENT_TYPE_U8)
{
- // Cast to I4 and return the argument that was passed in.
- static const BYTE ilcode[] = { CEE_LDARG_0, CEE_CONV_I4, CEE_RET };
+ static const BYTE ilcode[] = { CEE_LDARG_0, CEE_LDARG_1, CEE_PREFIX1, (CEE_CEQ & 0xFF), CEE_RET };
methInfo->ILCode = const_cast<BYTE*>(ilcode);
methInfo->ILCodeSize = sizeof(ilcode);
- methInfo->maxStack = 1;
+ methInfo->maxStack = 2;
methInfo->EHcount = 0;
methInfo->options = (CorInfoOptions)0;
return true;
}
}
- else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__UNSAFE_ENUM_CAST_LONG)->GetMemberDef())
+ else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__ENUM_COMPARE_TO)->GetMemberDef())
{
// The the comment above on why this is is not an unconditional replacement. This case handles
// Enums backed by 8 byte values.
@@ -7022,14 +7023,43 @@ bool getILIntrinsicImplementation(MethodDesc * ftn,
_ASSERTE(inst.GetNumArgs() == 1);
CorElementType et = inst[0].GetVerifierCorElementType();
- if (et == ELEMENT_TYPE_I8 ||
+ if (et == ELEMENT_TYPE_I4 ||
+ et == ELEMENT_TYPE_U4 ||
+ et == ELEMENT_TYPE_I2 ||
+ et == ELEMENT_TYPE_U2 ||
+ et == ELEMENT_TYPE_I1 ||
+ et == ELEMENT_TYPE_U1 ||
+ et == ELEMENT_TYPE_I8 ||
et == ELEMENT_TYPE_U8)
{
- // Cast to I8 and return the argument that was passed in.
- static const BYTE ilcode[] = { CEE_LDARG_0, CEE_CONV_I8, CEE_RET };
- methInfo->ILCode = const_cast<BYTE*>(ilcode);
- methInfo->ILCodeSize = sizeof(ilcode);
- methInfo->maxStack = 1;
+ static BYTE ilcode[8][9];
+
+ TypeHandle thUnderlyingType = MscorlibBinder::GetElementType(et);
+
+ TypeHandle thIComparable = TypeHandle(MscorlibBinder::GetClass(CLASS__ICOMPARABLEGENERIC)).Instantiate(Instantiation(&thUnderlyingType, 1));
+
+ MethodDesc * pCompareToMD = thUnderlyingType.AsMethodTable()->GetMethodDescForInterfaceMethod(
+ thIComparable, MscorlibBinder::GetMethod(METHOD__ICOMPARABLEGENERIC__COMPARE_TO), TRUE /* throwOnConflict */);
+
+ // Call CompareTo method on the primitive type
+ int tokCompareTo = pCompareToMD->GetMemberDef();
+
+ int index = (et - ELEMENT_TYPE_I1);
+ _ASSERTE(index < _countof(ilcode));
+
+ ilcode[index][0] = CEE_LDARGA_S;
+ ilcode[index][1] = 0;
+ ilcode[index][2] = CEE_LDARG_1;
+ ilcode[index][3] = CEE_CALL;
+ ilcode[index][4] = (BYTE)(tokCompareTo);
+ ilcode[index][5] = (BYTE)(tokCompareTo >> 8);
+ ilcode[index][6] = (BYTE)(tokCompareTo >> 16);
+ ilcode[index][7] = (BYTE)(tokCompareTo >> 24);
+ ilcode[index][8] = CEE_RET;
+
+ methInfo->ILCode = const_cast<BYTE*>(ilcode[index]);
+ methInfo->ILCodeSize = sizeof(ilcode[index]);
+ methInfo->maxStack = 2;
methInfo->EHcount = 0;
methInfo->options = (CorInfoOptions)0;
return true;
@@ -9122,15 +9152,10 @@ CORINFO_CLASS_HANDLE CEEInfo::getDefaultEqualityComparerClassHelper(CORINFO_CLAS
case ELEMENT_TYPE_U2:
case ELEMENT_TYPE_I4:
case ELEMENT_TYPE_U4:
- {
- targetClass = MscorlibBinder::GetClass(CLASS__ENUM_EQUALITYCOMPARER);
- break;
- }
-
case ELEMENT_TYPE_I8:
case ELEMENT_TYPE_U8:
{
- targetClass = MscorlibBinder::GetClass(CLASS__LONG_ENUM_EQUALITYCOMPARER);
+ targetClass = MscorlibBinder::GetClass(CLASS__ENUM_EQUALITYCOMPARER);
break;
}