Move all of generic virtual method resolution to the type loader (#79925)
authorMichal Strehovský <MichalStrehovsky@users.noreply.github.com>
Fri, 23 Dec 2022 17:23:38 +0000 (02:23 +0900)
committerGitHub <noreply@github.com>
Fri, 23 Dec 2022 17:23:38 +0000 (09:23 -0800)
* Move all of generic virtual method resolution to the type loader

For whatever reason, the logic that walks the inheritance hierarchy and deals with the differences between interface GVM and class GVM calls was in CoreLib.

Move it to the type loader because we'll need it for #77070.

* Oh the conversion to EEType was important

src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs
src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/Augments/TypeLoaderCallbacks.cs
src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerServices/GenericVirtualMethodSupport.cs [deleted file]
src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj
src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/TypeLoaderExports.cs
src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.GVMResolution.cs
src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.cs

index c1eb642..bdcd374 100644 (file)
@@ -632,11 +632,6 @@ namespace Internal.Runtime.Augments
             return RuntimeImports.RhResolveDispatch(instance, CreateEETypePtr(interfaceType), checked((ushort)slot));
         }
 
-        public static IntPtr GVMLookupForSlot(RuntimeTypeHandle type, RuntimeMethodHandle slot)
-        {
-            return GenericVirtualMethodSupport.GVMLookupForSlot(type, slot);
-        }
-
         public static bool IsUnmanagedPointerType(RuntimeTypeHandle typeHandle)
         {
             return typeHandle.ToEETypePtr().IsPointer;
index f3ad4c5..9a20e76 100644 (file)
@@ -23,7 +23,7 @@ namespace Internal.Runtime.Augments
         public abstract RuntimeMethodHandle GetRuntimeMethodHandleForComponents(RuntimeTypeHandle declaringTypeHandle, string methodName, RuntimeSignature methodSignature, RuntimeTypeHandle[] genericMethodArgs);
         public abstract bool CompareMethodSignatures(RuntimeSignature signature1, RuntimeSignature signature2);
         public abstract IntPtr TryGetDefaultConstructorForType(RuntimeTypeHandle runtimeTypeHandle);
-        public abstract bool TryGetGenericVirtualTargetForTypeAndSlot(RuntimeTypeHandle targetHandle, ref RuntimeTypeHandle declaringType, RuntimeTypeHandle[] genericArguments, ref string methodName, ref RuntimeSignature methodSignature, bool lookForDefaultImplementations, out IntPtr methodPointer, out IntPtr dictionaryPointer, out bool slotUpdated);
+        public abstract IntPtr ResolveGenericVirtualMethodTarget(RuntimeTypeHandle targetTypeHandle, RuntimeMethodHandle declMethod);
         public abstract bool GetRuntimeFieldHandleComponents(RuntimeFieldHandle runtimeFieldHandle, out RuntimeTypeHandle declaringTypeHandle, out string fieldName);
         public abstract RuntimeFieldHandle GetRuntimeFieldHandleForComponents(RuntimeTypeHandle declaringTypeHandle, string fieldName);
         public abstract bool TryGetPointerTypeForTargetType(RuntimeTypeHandle pointeeTypeHandle, out RuntimeTypeHandle pointerTypeHandle);
diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerServices/GenericVirtualMethodSupport.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerServices/GenericVirtualMethodSupport.cs
deleted file mode 100644 (file)
index 1db523e..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System;
-
-using Internal.Runtime.Augments;
-
-namespace Internal.Runtime.CompilerServices
-{
-    internal static class GenericVirtualMethodSupport
-    {
-        private static unsafe IntPtr GVMLookupForSlotWorker(RuntimeTypeHandle type, RuntimeTypeHandle declaringType, RuntimeTypeHandle[] genericArguments, MethodNameAndSignature methodNameAndSignature)
-        {
-            bool slotChanged = false;
-
-            IntPtr resolution = IntPtr.Zero;
-            IntPtr functionPointer;
-            IntPtr genericDictionary;
-
-            bool lookForDefaultImplementations = false;
-
-        again:
-            // Walk parent hierarchy attempting to resolve
-            EETypePtr eeType = type.ToEETypePtr();
-
-            while (!eeType.IsNull)
-            {
-                RuntimeTypeHandle handle = new RuntimeTypeHandle(eeType);
-                string methodName = methodNameAndSignature.Name;
-                RuntimeSignature methodSignature = methodNameAndSignature.Signature;
-                if (RuntimeAugments.TypeLoaderCallbacks.TryGetGenericVirtualTargetForTypeAndSlot(handle, ref declaringType, genericArguments, ref methodName, ref methodSignature, lookForDefaultImplementations, out functionPointer, out genericDictionary, out slotChanged))
-                {
-                    methodNameAndSignature = new MethodNameAndSignature(methodName, methodSignature);
-
-                    if (!slotChanged)
-                        resolution = FunctionPointerOps.GetGenericMethodFunctionPointer(functionPointer, genericDictionary);
-                    break;
-                }
-
-                eeType = eeType.BaseType;
-            }
-
-            // If the current slot to examine has changed, restart the lookup.
-            // This happens when there is an interface call.
-            if (slotChanged)
-            {
-                return GVMLookupForSlotWorker(type, declaringType, genericArguments, methodNameAndSignature);
-            }
-
-            if (resolution == IntPtr.Zero
-                && !lookForDefaultImplementations
-                && declaringType.ToEETypePtr().IsInterface)
-            {
-                lookForDefaultImplementations = true;
-                goto again;
-            }
-
-            if (resolution == IntPtr.Zero)
-            {
-                var sb = new System.Text.StringBuilder();
-                sb.AppendLine("Generic virtual method pointer lookup failure.");
-                sb.AppendLine();
-                sb.AppendLine("Declaring type: " + declaringType.LastResortToString);
-                sb.AppendLine("Target type: " + type.LastResortToString);
-                sb.AppendLine("Method name: " + methodNameAndSignature.Name);
-                sb.AppendLine("Instantiation:");
-                for (int i = 0; i < genericArguments.Length; i++)
-                {
-                    sb.AppendLine("  Argument " + i.LowLevelToString() + ": " + genericArguments[i].LastResortToString);
-                }
-
-                Environment.FailFast(sb.ToString());
-            }
-
-            return resolution;
-        }
-
-        internal static unsafe IntPtr GVMLookupForSlot(RuntimeTypeHandle type, RuntimeMethodHandle slot)
-        {
-            RuntimeTypeHandle declaringTypeHandle;
-            MethodNameAndSignature nameAndSignature;
-            RuntimeTypeHandle[] genericMethodArgs;
-            if (!RuntimeAugments.TypeLoaderCallbacks.GetRuntimeMethodHandleComponents(slot, out declaringTypeHandle, out nameAndSignature, out genericMethodArgs))
-            {
-                System.Diagnostics.Debug.Assert(false);
-                return IntPtr.Zero;
-            }
-
-            return GVMLookupForSlotWorker(type, declaringTypeHandle, genericMethodArgs, nameAndSignature);
-        }
-    }
-}
index 2c91353..a71d455 100644 (file)
     <Compile Include="Internal\Runtime\CompilerServices\FixupRuntimeTypeHandle.cs" />
     <Compile Include="Internal\Runtime\CompilerServices\FunctionPointerOps.cs" />
     <Compile Include="Internal\Runtime\CompilerServices\GenericMethodDescriptor.cs" />
-    <Compile Include="Internal\Runtime\CompilerServices\GenericVirtualMethodSupport.cs" />
     <Compile Include="Internal\Runtime\CompilerServices\RuntimeFieldHandleInfo.cs" />
     <Compile Include="Internal\Runtime\CompilerServices\RuntimeMethodHandleInfo.cs" />
     <Compile Include="Internal\Runtime\CompilerServices\RuntimeSignature.cs" />
index 576f9b5..6d71f0d 100644 (file)
@@ -114,7 +114,7 @@ namespace System.Runtime
             Entry entry = LookupInCache(s_cache, (IntPtr)obj.GetMethodTable(), *(IntPtr*)&slot);
             entry ??= CacheMiss((IntPtr)obj.GetMethodTable(), *(IntPtr*)&slot,
                     (IntPtr context, IntPtr signature, object contextObject, ref IntPtr auxResult)
-                        => Internal.Runtime.CompilerServices.GenericVirtualMethodSupport.GVMLookupForSlot(new RuntimeTypeHandle(new EETypePtr(context)), *(RuntimeMethodHandle*)&signature));
+                        => RuntimeAugments.TypeLoaderCallbacks.ResolveGenericVirtualMethodTarget(new RuntimeTypeHandle(new EETypePtr(context)), *(RuntimeMethodHandle*)&signature));
             return entry.Result;
         }
 
index f0042b7..c8fb085 100644 (file)
@@ -21,7 +21,7 @@ namespace Internal.Runtime.TypeLoader
     public sealed partial class TypeLoaderEnvironment
     {
 #if GVM_RESOLUTION_TRACE
-        private string GetTypeNameDebug(RuntimeTypeHandle rtth)
+        private static string GetTypeNameDebug(RuntimeTypeHandle rtth)
         {
             string result;
 
@@ -47,6 +47,86 @@ namespace Internal.Runtime.TypeLoader
         }
 #endif
 
+        private unsafe IntPtr GVMLookupForSlotWorker(RuntimeTypeHandle type, RuntimeTypeHandle declaringType, RuntimeTypeHandle[] genericArguments, MethodNameAndSignature methodNameAndSignature)
+        {
+            bool slotChanged = false;
+
+            IntPtr resolution = IntPtr.Zero;
+            IntPtr functionPointer;
+            IntPtr genericDictionary;
+
+            bool lookForDefaultImplementations = false;
+
+        again:
+            // Walk parent hierarchy attempting to resolve
+            RuntimeTypeHandle currentType = type;
+
+            while (!currentType.IsNull())
+            {
+                string methodName = methodNameAndSignature.Name;
+                RuntimeSignature methodSignature = methodNameAndSignature.Signature;
+                if (TryGetGenericVirtualTargetForTypeAndSlot(currentType, ref declaringType, genericArguments, ref methodName, ref methodSignature, lookForDefaultImplementations, out functionPointer, out genericDictionary, out slotChanged))
+                {
+                    methodNameAndSignature = new MethodNameAndSignature(methodName, methodSignature);
+
+                    if (!slotChanged)
+                        resolution = FunctionPointerOps.GetGenericMethodFunctionPointer(functionPointer, genericDictionary);
+                    break;
+                }
+
+                bool success = RuntimeAugments.TryGetBaseType(currentType, out currentType);
+                Debug.Assert(success);
+            }
+
+            // If the current slot to examine has changed, restart the lookup.
+            // This happens when there is an interface call.
+            if (slotChanged)
+            {
+                return GVMLookupForSlotWorker(type, declaringType, genericArguments, methodNameAndSignature);
+            }
+
+            if (resolution == IntPtr.Zero
+                && !lookForDefaultImplementations
+                && declaringType.IsInterface())
+            {
+                lookForDefaultImplementations = true;
+                goto again;
+            }
+
+            if (resolution == IntPtr.Zero)
+            {
+                var sb = new System.Text.StringBuilder();
+                sb.AppendLine("Generic virtual method pointer lookup failure.");
+                sb.AppendLine();
+                sb.AppendLine("Declaring type: " + RuntimeAugments.GetLastResortString(declaringType));
+                sb.AppendLine("Target type: " + RuntimeAugments.GetLastResortString(type));
+                sb.AppendLine("Method name: " + methodNameAndSignature.Name);
+                sb.AppendLine("Instantiation:");
+                for (int i = 0; i < genericArguments.Length; i++)
+                {
+                    sb.AppendLine("  Argument " + i.LowLevelToString() + ": " + RuntimeAugments.GetLastResortString(genericArguments[i]));
+                }
+
+                Environment.FailFast(sb.ToString());
+            }
+
+            return resolution;
+        }
+
+        internal unsafe IntPtr ResolveGenericVirtualMethodTarget(RuntimeTypeHandle type, RuntimeMethodHandle slot)
+        {
+            RuntimeTypeHandle declaringTypeHandle;
+            MethodNameAndSignature nameAndSignature;
+            RuntimeTypeHandle[] genericMethodArgs;
+            if (!TryGetRuntimeMethodHandleComponents(slot, out declaringTypeHandle, out nameAndSignature, out genericMethodArgs))
+            {
+                Debug.Assert(false);
+                return IntPtr.Zero;
+            }
+
+            return GVMLookupForSlotWorker(type, declaringTypeHandle, genericMethodArgs, nameAndSignature);
+        }
+
         public bool TryGetGenericVirtualTargetForTypeAndSlot(RuntimeTypeHandle targetHandle, ref RuntimeTypeHandle declaringType, RuntimeTypeHandle[] genericArguments, ref string methodName, ref RuntimeSignature methodSignature, bool lookForDefaultImplementation, out IntPtr methodPointer, out IntPtr dictionaryPointer, out bool slotUpdated)
         {
             MethodNameAndSignature methodNameAndSignature = new MethodNameAndSignature(methodName, methodSignature);
index ee40892..110e12f 100644 (file)
@@ -61,9 +61,9 @@ namespace Internal.Runtime.TypeLoader
             return TypeLoaderEnvironment.Instance.TryGetDefaultConstructorForType(runtimeTypeHandle);
         }
 
-        public override bool TryGetGenericVirtualTargetForTypeAndSlot(RuntimeTypeHandle targetHandle, ref RuntimeTypeHandle declaringType, RuntimeTypeHandle[] genericArguments, ref string methodName, ref RuntimeSignature methodSignature, bool lookForDefaultImplementation, out IntPtr methodPointer, out IntPtr dictionaryPointer, out bool slotUpdated)
+        public override IntPtr ResolveGenericVirtualMethodTarget(RuntimeTypeHandle targetTypeHandle, RuntimeMethodHandle declMethod)
         {
-            return TypeLoaderEnvironment.Instance.TryGetGenericVirtualTargetForTypeAndSlot(targetHandle, ref declaringType, genericArguments, ref methodName, ref methodSignature, lookForDefaultImplementation, out methodPointer, out dictionaryPointer, out slotUpdated);
+            return TypeLoaderEnvironment.Instance.ResolveGenericVirtualMethodTarget(targetTypeHandle, declMethod);
         }
 
         public override bool GetRuntimeFieldHandleComponents(RuntimeFieldHandle runtimeFieldHandle, out RuntimeTypeHandle declaringTypeHandle, out string fieldName)