Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resolve generic virtual methods in managed type system #80035

Merged
merged 5 commits into from
Jan 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -634,7 +634,7 @@ internal GenericVariance* GenericVariance
{
get
{
Debug.Assert(IsGeneric);
Debug.Assert(IsGeneric || IsGenericTypeDefinition);

if (!HasGenericVariance)
return null;
Expand Down Expand Up @@ -1452,10 +1452,10 @@ public uint GetFieldOffset(EETypeField eField)

if (eField == EETypeField.ETF_GenericComposition)
{
Debug.Assert(IsGeneric);
Debug.Assert(IsGeneric || (IsGenericTypeDefinition && HasGenericVariance));
return cbOffset;
}
if (IsGeneric)
if (IsGeneric || (IsGenericTypeDefinition && HasGenericVariance))
{
cbOffset += relativeOrFullPointerOffset;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ namespace Internal.Runtime.TypeLoader
using DynamicGenericsRegistrationData = TypeLoaderEnvironment.DynamicGenericsRegistrationData;
using GenericTypeEntry = TypeLoaderEnvironment.GenericTypeEntry;
using GenericMethodEntry = TypeLoaderEnvironment.GenericMethodEntry;
using HandleBasedGenericMethodLookup = TypeLoaderEnvironment.HandleBasedGenericMethodLookup;
using MethodDescBasedGenericMethodLookup = TypeLoaderEnvironment.MethodDescBasedGenericMethodLookup;

internal static class LowLevelListExtensions
Expand Down Expand Up @@ -76,31 +75,16 @@ public MissingTemplateException()
}


private static bool CheckAllHandlesValidForMethod(MethodDesc method)
{
if (!method.OwningType.RetrieveRuntimeTypeHandleIfPossible())
return false;

for (int i = 0; i < method.Instantiation.Length; i++)
if (!method.Instantiation[i].RetrieveRuntimeTypeHandleIfPossible())
return false;

return true;
}

internal static bool RetrieveMethodDictionaryIfPossible(InstantiatedMethod method)
{
if (method.RuntimeMethodDictionary != IntPtr.Zero)
return true;

bool allHandlesValid = CheckAllHandlesValidForMethod(method);

TypeLoaderLogger.WriteLine("Looking for method dictionary for method " + method.ToString() + " ... " + (allHandlesValid ? "(All type arg handles valid)" : ""));
TypeLoaderLogger.WriteLine("Looking for method dictionary for method " + method.ToString() + " ... ");

IntPtr methodDictionary;

if ((allHandlesValid && TypeLoaderEnvironment.Instance.TryLookupGenericMethodDictionaryForComponents(new HandleBasedGenericMethodLookup(method), out methodDictionary)) ||
(!allHandlesValid && TypeLoaderEnvironment.Instance.TryLookupGenericMethodDictionaryForComponents(new MethodDescBasedGenericMethodLookup(method), out methodDictionary)))
if (TypeLoaderEnvironment.Instance.TryLookupGenericMethodDictionary(new MethodDescBasedGenericMethodLookup(method), out methodDictionary))
{
TypeLoaderLogger.WriteLine("Found DICT = " + methodDictionary.LowLevelToString() + " for method " + method.ToString());
method.AssociateWithRuntimeMethodDictionary(methodDictionary);
Expand Down Expand Up @@ -1289,22 +1273,6 @@ public static bool TryBuildByRefType(RuntimeTypeHandle pointeeTypeHandle, out Ru
return true;
}

public static bool TryBuildGenericMethod(RuntimeTypeHandle declaringTypeHandle, RuntimeTypeHandle[] genericMethodArgHandles, MethodNameAndSignature methodNameAndSignature, out IntPtr methodDictionary)
{
TypeSystemContext context = TypeSystemContextFactory.Create();

DefType declaringType = (DefType)context.ResolveRuntimeTypeHandle(declaringTypeHandle);
InstantiatedMethod methodBeingLoaded = (InstantiatedMethod)context.ResolveGenericMethodInstantiation(false, declaringType, methodNameAndSignature, context.ResolveRuntimeTypeHandles(genericMethodArgHandles), IntPtr.Zero, false);

bool success = TryBuildGenericMethod(methodBeingLoaded, out methodDictionary);

// Recycle the context only if we successfully built the method. The state may be partially initialized otherwise.
if (success)
TypeSystemContextFactory.Recycle(context);

return success;
}

internal static bool TryBuildGenericMethod(InstantiatedMethod methodBeingLoaded, out IntPtr methodDictionary)
{
try
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,118 +172,19 @@ internal override bool MatchGenericMethodEntry(GenericMethodEntry entry)
return parsedGenericMethod == _methodToLookup;
}
}
internal class HandleBasedGenericMethodLookup : MethodDescBasedGenericMethodLookup
{
private RuntimeTypeHandle _declaringType;
private MethodNameAndSignature _nameAndSignature;
private RuntimeTypeHandle[] _genericMethodArgumentHandles;

internal HandleBasedGenericMethodLookup(InstantiatedMethod methodToLookup) : base(methodToLookup)
{
Debug.Assert(methodToLookup != null);
_declaringType = _methodToLookup.OwningType.RuntimeTypeHandle;
_nameAndSignature = _methodToLookup.NameAndSignature;
// _genericMethodArgumentHandles not initialized here to avoid allocation of a new array (and it's not used if we initialize _typeToLookup).
}

internal HandleBasedGenericMethodLookup(RuntimeTypeHandle declaringType, MethodNameAndSignature nameAndSignature, RuntimeTypeHandle[] genericMethodArgumentHandles) : base(null)
{
Debug.Assert(!declaringType.IsNull() && nameAndSignature != null && genericMethodArgumentHandles != null);
_declaringType = declaringType;
_nameAndSignature = nameAndSignature;
_genericMethodArgumentHandles = genericMethodArgumentHandles;
}

internal override int LookupHashCode()
{
// Todo: Signatures in the hash code.
return _methodToLookup != null ? _methodToLookup.GetHashCode() : (_declaringType.GetHashCode() ^ TypeHashingAlgorithms.ComputeGenericInstanceHashCode(TypeHashingAlgorithms.ComputeNameHashCode(_nameAndSignature.Name), _genericMethodArgumentHandles));
}

internal override bool MatchParsedEntry(ref NativeParser entryParser, ref ExternalReferencesTable externalReferencesLookup, TypeManagerHandle moduleHandle)
{
// Compare entry with inputs as we parse it. If we get a mismatch, stop parsing and move to the next entry...
RuntimeTypeHandle parsedDeclaringTypeHandle = externalReferencesLookup.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned());
if (!parsedDeclaringTypeHandle.Equals(_declaringType))
return false;

// Hash table names / sigs are indirected through to the native layout info
MethodNameAndSignature nameAndSignature;
if (!TypeLoaderEnvironment.Instance.TryGetMethodNameAndSignatureFromNativeLayoutOffset(moduleHandle, entryParser.GetUnsigned(), out nameAndSignature))
return false;

if (!nameAndSignature.Equals(_nameAndSignature))
return false;

int parsedArity = (int)entryParser.GetSequenceCount();
int lookupArity = (_methodToLookup != null ? _methodToLookup.Instantiation.Length : _genericMethodArgumentHandles.Length);
if (parsedArity != lookupArity)
return false;

for (int i = 0; i < parsedArity; i++)
{
RuntimeTypeHandle parsedArg = externalReferencesLookup.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned());
RuntimeTypeHandle lookupArg = (_methodToLookup != null ? _methodToLookup.Instantiation[i].RuntimeTypeHandle : _genericMethodArgumentHandles[i]);
if (!parsedArg.Equals(lookupArg))
return false;
}

return true;
}

internal override bool MatchGenericMethodEntry(GenericMethodEntry entry)
{
if (!entry._declaringTypeHandle.Equals(_declaringType))
return false;

if (!entry._methodNameAndSignature.Equals(_nameAndSignature))
return false;

if (entry._genericMethodArgumentHandles == null)
return false;

if (_methodToLookup != null)
{
int expectedArity = _methodToLookup.Instantiation.Length;

if (entry._genericMethodArgumentHandles.Length != expectedArity)
return false;

for (int i = 0; i < expectedArity; i++)
if (!entry._genericMethodArgumentHandles[i].Equals(_methodToLookup.Instantiation[i].RuntimeTypeHandle))
return false;
}
else
{
if (entry._genericMethodArgumentHandles.Length != _genericMethodArgumentHandles.Length)
return false;

for (int i = 0; i < _genericMethodArgumentHandles.Length; i++)
if (!entry._genericMethodArgumentHandles[i].Equals(_genericMethodArgumentHandles[i]))
return false;
}

return true;
}
}

private DynamicGenericMethodsHashtable _dynamicGenericMethods = new DynamicGenericMethodsHashtable();
private DynamicGenericMethodComponentsHashtable _dynamicGenericMethodComponents = new DynamicGenericMethodComponentsHashtable();

internal bool TryLookupGenericMethodDictionaryForComponents(GenericMethodLookupData lookupData, out IntPtr result)
internal bool TryLookupGenericMethodDictionary(GenericMethodLookupData lookupData, out IntPtr result)
{
if (!TryGetStaticGenericMethodDictionaryForComponents(lookupData, out result))
if (!TryGetDynamicGenericMethodDictionaryForComponents(lookupData, out result))
if (!TryGetStaticGenericMethodDictionary(lookupData, out result))
if (!TryGetDynamicGenericMethodDictionary(lookupData, out result))
return false;

return true;
}

public bool TryLookupGenericMethodDictionaryForComponents(RuntimeTypeHandle declaringType, MethodNameAndSignature nameAndSignature, RuntimeTypeHandle[] genericMethodArgumentHandles, out IntPtr result)
{
return TryLookupGenericMethodDictionaryForComponents(new HandleBasedGenericMethodLookup(declaringType, nameAndSignature, genericMethodArgumentHandles), out result);
}

public bool TryGetGenericMethodComponents(IntPtr methodDictionary, out RuntimeTypeHandle declaringType, out MethodNameAndSignature nameAndSignature, out RuntimeTypeHandle[] genericMethodArgumentHandles)
{
if (!TryGetDynamicGenericMethodComponents(methodDictionary, out declaringType, out nameAndSignature, out genericMethodArgumentHandles))
Expand All @@ -293,14 +194,14 @@ public bool TryGetGenericMethodComponents(IntPtr methodDictionary, out RuntimeTy
return true;
}

public bool TryLookupExactMethodPointerForComponents(RuntimeTypeHandle declaringType, MethodNameAndSignature nameAndSignature, RuntimeTypeHandle[] genericMethodArgumentHandles, out IntPtr result)
public bool TryLookupExactMethodPointer(InstantiatedMethod method, out IntPtr result)
{
int lookupHashcode = declaringType.GetHashCode();
int lookupHashcode = method.OwningType.GetHashCode();

NativeHashtable hashtable;
ExternalReferencesTable externalReferencesLookup;

HandleBasedGenericMethodLookup lookupData = new HandleBasedGenericMethodLookup(declaringType, nameAndSignature, genericMethodArgumentHandles);
MethodDescBasedGenericMethodLookup lookupData = new MethodDescBasedGenericMethodLookup(method);

foreach (NativeFormatModuleInfo module in ModuleList.EnumerateModules())
{
Expand All @@ -327,66 +228,59 @@ public bool TryLookupExactMethodPointerForComponents(RuntimeTypeHandle declaring

// This method computes the method pointer and dictionary pointer for a GVM.
// Inputs:
// - targetTypeHanlde: target type on which the GVM is implemented
// - nameAndSignature: name and signature of the GVM method
// - genericMethodArgumentHandles: GVM instantiation arguments
// - method: the GVM whose pointer and dictionary to retrieve
// Outputs:
// - methodPointer: pointer to the GVM's implementation
// - dictionaryPointer: (if applicable) pointer to the dictionary to be used with the GVM call
public bool TryGetGenericVirtualMethodPointer(RuntimeTypeHandle targetTypeHandle, MethodNameAndSignature nameAndSignature, RuntimeTypeHandle[] genericMethodArgumentHandles, out IntPtr methodPointer, out IntPtr dictionaryPointer)
public bool TryGetGenericVirtualMethodPointer(InstantiatedMethod method, out IntPtr methodPointer, out IntPtr dictionaryPointer)
{
methodPointer = dictionaryPointer = IntPtr.Zero;

TypeSystemContext context = TypeSystemContextFactory.Create();

DefType targetType = (DefType)context.ResolveRuntimeTypeHandle(targetTypeHandle);
Instantiation methodInstantiation = context.ResolveRuntimeTypeHandles(genericMethodArgumentHandles);
InstantiatedMethod method = (InstantiatedMethod)context.ResolveGenericMethodInstantiation(false, targetType, nameAndSignature, methodInstantiation, IntPtr.Zero, false);

if (!method.CanShareNormalGenericCode())
{
// First see if we can find an exact method implementation for the GVM (avoid using USG implementations if we can,
// because USG code is much slower).
if (TryLookupExactMethodPointerForComponents(targetTypeHandle, nameAndSignature, genericMethodArgumentHandles, out methodPointer))
if (TryLookupExactMethodPointer(method, out methodPointer))
{
Debug.Assert(methodPointer != IntPtr.Zero);
TypeSystemContextFactory.Recycle(context);
dictionaryPointer = IntPtr.Zero;
return true;
}
}

// If we cannot find an exact method entry point, look for an equivalent template and compute the generic dictinoary
NativeLayoutInfo nativeLayoutInfo = new NativeLayoutInfo();
InstantiatedMethod templateMethod = TemplateLocator.TryGetGenericMethodTemplate(method, out nativeLayoutInfo.Module, out nativeLayoutInfo.Offset);
// If we cannot find an exact method entry point, look for an equivalent template and compute the generic dictionary
InstantiatedMethod templateMethod = TemplateLocator.TryGetGenericMethodTemplate(method, out _, out _);
if (templateMethod == null)
{
methodPointer = default;
dictionaryPointer = default;
return false;
}

methodPointer = templateMethod.IsCanonicalMethod(CanonicalFormKind.Universal) ?
templateMethod.UsgFunctionPointer :
templateMethod.FunctionPointer;

if (!TryLookupGenericMethodDictionaryForComponents(targetTypeHandle, nameAndSignature, genericMethodArgumentHandles, out dictionaryPointer))
if (!TryLookupGenericMethodDictionary(new MethodDescBasedGenericMethodLookup(method), out dictionaryPointer))
{
using (LockHolder.Hold(_typeLoaderLock))
{
// Now that we hold the lock, we may find that existing types can now find
// their associated RuntimeTypeHandle. Flush the type builder states as a way
// to force the reresolution of RuntimeTypeHandles which couldn't be found before.
context.FlushTypeBuilderStates();
method.Context.FlushTypeBuilderStates();

if (!TypeBuilder.TryBuildGenericMethod(method, out dictionaryPointer))
{
return false;
}
}
}

Debug.Assert(methodPointer != IntPtr.Zero && dictionaryPointer != IntPtr.Zero);

TypeSystemContextFactory.Recycle(context);
return true;
}

#region Privates
private bool TryGetDynamicGenericMethodDictionaryForComponents(GenericMethodLookupData lookupData, out IntPtr result)
private bool TryGetDynamicGenericMethodDictionary(GenericMethodLookupData lookupData, out IntPtr result)
{
result = IntPtr.Zero;

Expand All @@ -403,7 +297,7 @@ private bool TryGetDynamicGenericMethodDictionaryForComponents(GenericMethodLook
return true;
}
}
private static bool TryGetStaticGenericMethodDictionaryForComponents(GenericMethodLookupData lookupData, out IntPtr result)
private static bool TryGetStaticGenericMethodDictionary(GenericMethodLookupData lookupData, out IntPtr result)
{
// Search the hashtable for a generic instantiation match

Expand Down
Loading