Do not use RhGetCodeTarget in delegate equality (#88611)
authorSingleAccretion <62474226+SingleAccretion@users.noreply.github.com>
Wed, 12 Jul 2023 06:48:25 +0000 (09:48 +0300)
committerGitHub <noreply@github.com>
Wed, 12 Jul 2023 06:48:25 +0000 (23:48 -0700)
https://github.com/dotnet/corert/commit/08d78ae391e3eea9ad51265f867e42ee1649282d

The original motivation for this was handling import stubs:
```
Function pointer equality comparison was not handling cross-module pointers correctly when optimizations were enabled
(causes target pointers to be wrapped in jump stubs sometimes). The delegate equality comparison was hitting this bug.
```
We do not have import stubs anymore and unwrapping unboxing stubs serves no purpose here.

Microbenchmarks of delegate equality show ~3x improvement with this change:
```
Bench_DelegateEquality_Positive_OpenStatic<10000000>() took: 355 ms
Bench_DelegateEquality_Positive_ClosedStatic<10000000>() took: 367 ms
Bench_DelegateEquality_Positive_ClosedInstance<10000000>() took: 371 ms

Bench_DelegateEquality_Positive_OpenStatic<10000000>() took: 121 ms
Bench_DelegateEquality_Positive_ClosedStatic<10000000>() took: 120 ms
Bench_DelegateEquality_Positive_ClosedInstance<10000000>() took: 122 ms
```

Additionally, there is some desire to upstream changes for a portable RhGetCodeTarget implementation. Not having to
deal with it at this relatively low-level layer will make things more robust.

src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerServices/FunctionPointerOps.cs

index eba8555..eb4cb24 100644 (file)
@@ -130,25 +130,23 @@ namespace Internal.Runtime.CompilerServices
         {
             if (!IsGenericMethodPointer(functionPointerA))
             {
-                IntPtr codeTargetA = RuntimeAugments.GetCodeTarget(functionPointerA);
-                IntPtr codeTargetB = RuntimeAugments.GetCodeTarget(functionPointerB);
-                return codeTargetA == codeTargetB;
+                return functionPointerA == functionPointerB;
             }
-            else
+
+            if (!IsGenericMethodPointer(functionPointerB))
             {
-                if (!IsGenericMethodPointer(functionPointerB))
-                    return false;
+                return false;
+            }
 
-                GenericMethodDescriptor* pointerDefA = ConvertToGenericDescriptor(functionPointerA);
-                GenericMethodDescriptor* pointerDefB = ConvertToGenericDescriptor(functionPointerB);
+            GenericMethodDescriptor* pointerDefA = ConvertToGenericDescriptor(functionPointerA);
+            GenericMethodDescriptor* pointerDefB = ConvertToGenericDescriptor(functionPointerB);
 
-                if (pointerDefA->InstantiationArgument != pointerDefB->InstantiationArgument)
-                    return false;
-
-                IntPtr codeTargetA = RuntimeAugments.GetCodeTarget(pointerDefA->MethodFunctionPointer);
-                IntPtr codeTargetB = RuntimeAugments.GetCodeTarget(pointerDefB->MethodFunctionPointer);
-                return codeTargetA == codeTargetB;
+            if (pointerDefA->InstantiationArgument != pointerDefB->InstantiationArgument)
+            {
+                return false;
             }
+
+            return pointerDefA->MethodFunctionPointer == pointerDefB->MethodFunctionPointer;
         }
     }
 }