Make open method resolver pay for play (#83064)
authorMichal Strehovský <MichalStrehovsky@users.noreply.github.com>
Tue, 7 Mar 2023 11:50:15 +0000 (20:50 +0900)
committerGitHub <noreply@github.com>
Tue, 7 Mar 2023 11:50:15 +0000 (03:50 -0800)
Resolver is called into from delegate thunks, so we can't get rid of it, but to construct a resolver one needs to do some reflection first. Make the resolution logic statically depend on resolver being constructed.

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

index b4fffe5..b9a5b13 100644 (file)
@@ -22,6 +22,9 @@ namespace Internal.Runtime.CompilerServices
     [ReflectionBlocked]
     public struct OpenMethodResolver : IEquatable<OpenMethodResolver>
     {
+        // Lazy initialized to point to the type loader method when the first `GVMResolve` resolver is created
+        private static unsafe delegate*<object, RuntimeMethodHandle, nint> s_lazyGvmLookupForSlot;
+
         public const short DispatchResolve = 0;
         public const short GVMResolve = 1;
         public const short OpenNonVirtualResolve = 2;
@@ -52,6 +55,9 @@ namespace Internal.Runtime.CompilerServices
             _handle = handle;
             _readerGCHandle = readerGCHandle;
             _nonVirtualOpenInvokeCodePointer = IntPtr.Zero;
+
+            if (s_lazyGvmLookupForSlot == null)
+                s_lazyGvmLookupForSlot = &TypeLoaderExports.GVMLookupForSlot;
         }
 
         public OpenMethodResolver(RuntimeTypeHandle declaringType, IntPtr codePointer, GCHandle readerGCHandle, int handle)
@@ -151,7 +157,7 @@ namespace Internal.Runtime.CompilerServices
             }
             else if (_resolveType == GVMResolve)
             {
-                return TypeLoaderExports.GVMLookupForSlot(thisObject, GVMMethodHandle);
+                return s_lazyGvmLookupForSlot(thisObject, GVMMethodHandle);
             }
             else
             {