Skip to content

Commit

Permalink
Move all of generic virtual method resolution to the type loader (#79925
Browse files Browse the repository at this point in the history
)

* 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
  • Loading branch information
MichalStrehovsky authored Dec 23, 2022
1 parent b631a55 commit 5b99dce
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 103 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -632,11 +632,6 @@ public static IntPtr ResolveDispatch(object instance, RuntimeTypeHandle interfac
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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public abstract class TypeLoaderCallbacks
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);
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@
<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" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ public static unsafe IntPtr GVMLookupForSlot(object obj, RuntimeMethodHandle slo
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;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -47,6 +47,86 @@ private string GetTypeNameDebug(RuntimeTypeHandle rtth)
}
#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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ public override IntPtr TryGetDefaultConstructorForType(RuntimeTypeHandle runtime
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)
Expand Down

0 comments on commit 5b99dce

Please sign in to comment.