Skip to content
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 numberDiff line numberDiff line change
Expand Up@@ -634,7 +634,7 @@ internal GenericVariance* GenericVariance
{
get
{
Debug.Assert(IsGeneric);
Debug.Assert(IsGeneric || IsGenericTypeDefinition);

if (!HasGenericVariance)
return null;
Expand DownExpand 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 numberDiff line numberDiff 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 DownExpand 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 DownExpand 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 numberDiff line numberDiff 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);
Comment thread
MichalStrehovsky marked this conversation as resolved.
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
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Resolve generic virtual methods in managed type system by MichalStrehovsky · Pull Request #80035 · dotnet/runtime · GitHub
Skip to content
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 numberDiff line numberDiff line change
Expand Up@@ -634,7 +634,7 @@ internal GenericVariance* GenericVariance
{
get
{
Debug.Assert(IsGeneric);
Debug.Assert(IsGeneric || IsGenericTypeDefinition);

if (!HasGenericVariance)
return null;
Expand DownExpand 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 numberDiff line numberDiff 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 DownExpand 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 DownExpand 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 numberDiff line numberDiff 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);
Comment thread
MichalStrehovsky marked this conversation as resolved.
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
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Resolve generic virtual methods in managed type system by MichalStrehovsky · Pull Request #80035 · dotnet/runtime · GitHub
Skip to content
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 numberDiff line numberDiff line change
Expand Up@@ -634,7 +634,7 @@ internal GenericVariance* GenericVariance
{
get
{
Debug.Assert(IsGeneric);
Debug.Assert(IsGeneric || IsGenericTypeDefinition);

if (!HasGenericVariance)
return null;
Expand DownExpand 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 numberDiff line numberDiff 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 DownExpand 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 DownExpand 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 numberDiff line numberDiff 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);
Comment thread
MichalStrehovsky marked this conversation as resolved.
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
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Resolve generic virtual methods in managed type system by MichalStrehovsky · Pull Request #80035 · dotnet/runtime · GitHub
Skip to content
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 numberDiff line numberDiff line change
Expand Up@@ -634,7 +634,7 @@ internal GenericVariance* GenericVariance
{
get
{
Debug.Assert(IsGeneric);
Debug.Assert(IsGeneric || IsGenericTypeDefinition);

if (!HasGenericVariance)
return null;
Expand DownExpand 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 numberDiff line numberDiff 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 DownExpand 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 DownExpand 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 numberDiff line numberDiff 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);
Comment thread
MichalStrehovsky marked this conversation as resolved.
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
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' Resolve generic virtual methods in managed type system by MichalStrehovsky · Pull Request #80035 · dotnet/runtime · GitHub
Skip to content
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 numberDiff line numberDiff line change
Expand Up@@ -634,7 +634,7 @@ internal GenericVariance* GenericVariance
{
get
{
Debug.Assert(IsGeneric);
Debug.Assert(IsGeneric || IsGenericTypeDefinition);

if (!HasGenericVariance)
return null;
Expand DownExpand 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 numberDiff line numberDiff 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 DownExpand 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 DownExpand 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 numberDiff line numberDiff 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);
Comment thread
MichalStrehovsky marked this conversation as resolved.
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
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Resolve generic virtual methods in managed type system by MichalStrehovsky · Pull Request #80035 · dotnet/runtime · GitHub
Skip to content
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 numberDiff line numberDiff line change
Expand Up@@ -634,7 +634,7 @@ internal GenericVariance* GenericVariance
{
get
{
Debug.Assert(IsGeneric);
Debug.Assert(IsGeneric || IsGenericTypeDefinition);

if (!HasGenericVariance)
return null;
Expand DownExpand 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 numberDiff line numberDiff 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 DownExpand 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 DownExpand 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 numberDiff line numberDiff 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);
Comment thread
MichalStrehovsky marked this conversation as resolved.
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
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Resolve generic virtual methods in managed type system by MichalStrehovsky · Pull Request #80035 · dotnet/runtime · GitHub
Skip to content
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 numberDiff line numberDiff line change
Expand Up@@ -634,7 +634,7 @@ internal GenericVariance* GenericVariance
{
get
{
Debug.Assert(IsGeneric);
Debug.Assert(IsGeneric || IsGenericTypeDefinition);

if (!HasGenericVariance)
return null;
Expand DownExpand 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 numberDiff line numberDiff 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 DownExpand 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 DownExpand 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 numberDiff line numberDiff 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);
Comment thread
MichalStrehovsky marked this conversation as resolved.
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
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); Resolve generic virtual methods in managed type system by MichalStrehovsky · Pull Request #80035 · dotnet/runtime · GitHub
Skip to content
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 numberDiff line numberDiff line change
Expand Up@@ -634,7 +634,7 @@ internal GenericVariance* GenericVariance
{
get
{
Debug.Assert(IsGeneric);
Debug.Assert(IsGeneric || IsGenericTypeDefinition);

if (!HasGenericVariance)
return null;
Expand DownExpand 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 numberDiff line numberDiff 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 DownExpand 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 DownExpand 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 numberDiff line numberDiff 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);
Comment thread
MichalStrehovsky marked this conversation as resolved.
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