GVM dependency analysis performance fixes (#3872)
Refactor GVM algorithm for better performance Fix GVM resolution bug on derived types Fix bug with variance (https://github.com/dotnet/corert/issues/3454)
This commit is contained in:
Родитель
c531b93451
Коммит
962401ec63
|
@ -209,6 +209,8 @@ namespace Internal.TypeSystem
|
|||
|
||||
// Step 4, name/sig match virtual function resolve
|
||||
MethodDesc resolutionTarget = FindNameSigOverrideForVirtualMethod(group.DefiningMethod, uninstantiatedType);
|
||||
if (resolutionTarget == null)
|
||||
return null;
|
||||
|
||||
// Step 5, convert resolution target from uninstantiated form target to objecttype target,
|
||||
// and instantiate as appropriate
|
||||
|
|
|
@ -47,6 +47,22 @@ namespace Internal.TypeSystem
|
|||
return true;
|
||||
}
|
||||
|
||||
public static bool CheckValidInstantiationArguments(this Instantiation instantiation)
|
||||
{
|
||||
foreach(var arg in instantiation)
|
||||
{
|
||||
if (arg.IsPointer || arg.IsByRef || arg.IsGenericParameter || arg.IsRuntimeDeterminedSubtype || arg.IsVoid)
|
||||
return false;
|
||||
|
||||
if (arg.HasInstantiation)
|
||||
{
|
||||
if (!CheckValidInstantiationArguments(arg.Instantiation))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool CheckConstraints(this TypeDesc type)
|
||||
{
|
||||
TypeDesc uninstantiatedType = type.GetTypeDefinition();
|
||||
|
|
|
@ -29,7 +29,43 @@ namespace ILCompiler.DependencyAnalysis
|
|||
{
|
||||
get
|
||||
{
|
||||
return _type.IsDefType && _type.HasGenericVirtualMethod();
|
||||
if (_type.IsInterface)
|
||||
return _type.HasGenericVirtualMethods();
|
||||
|
||||
if (_type.IsDefType)
|
||||
{
|
||||
// First, check if this type has any GVM that overrides a GVM on a parent type. If that's the case, this makes
|
||||
// the current type interesting for GVM analysis (i.e. instantiate its overriding GVMs for existing GVMDependenciesNodes
|
||||
// of the instantiated GVM on the parent types).
|
||||
foreach (var method in _type.GetAllMethods())
|
||||
{
|
||||
if (method.HasInstantiation && method.IsVirtual)
|
||||
{
|
||||
MethodDesc slotDecl = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(method);
|
||||
if (slotDecl != method)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Second, check if this type has any GVMs that implement any GVM on any of the implemented interfaces. This would
|
||||
// make the current type interesting for dynamic dependency analysis to that we can instantiate its GVMs.
|
||||
foreach (DefType interfaceImpl in _type.RuntimeInterfaces)
|
||||
{
|
||||
foreach (var method in interfaceImpl.GetAllMethods())
|
||||
{
|
||||
if (method.HasInstantiation && method.IsVirtual)
|
||||
{
|
||||
// We found a GVM on one of the implemented interfaces. Find if the type implements this method.
|
||||
// (Note, do this comparision against the generic definition of the method, not the specific method instantiation
|
||||
MethodDesc genericDefinition = method.GetMethodDefinition();
|
||||
MethodDesc slotDecl = _type.ResolveInterfaceMethodTarget(genericDefinition);
|
||||
if (slotDecl != null)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace ILCompiler.DependencyAnalysis
|
|||
/// </summary>
|
||||
internal class GVMDependenciesNode : DependencyNodeCore<NodeFactory>
|
||||
{
|
||||
private MethodDesc _method;
|
||||
private readonly MethodDesc _method;
|
||||
|
||||
public MethodDesc Method => _method;
|
||||
|
||||
|
@ -41,14 +41,45 @@ namespace ILCompiler.DependencyAnalysis
|
|||
// TODO: https://github.com/dotnet/corert/issues/3224
|
||||
if (_method.IsAbstract)
|
||||
{
|
||||
return new DependencyListEntry[]
|
||||
{
|
||||
new DependencyListEntry(context.ReflectableMethod(_method), "Abstract reflectable method"),
|
||||
};
|
||||
yield return new DependencyListEntry(context.ReflectableMethod(_method), "Abstract reflectable method");
|
||||
}
|
||||
else
|
||||
{
|
||||
MethodDesc instantiatedMethod = _method;
|
||||
|
||||
return Array.Empty<DependencyListEntry>();
|
||||
// Universal canonical instantiations should be entirely universal canon
|
||||
if (instantiatedMethod.IsCanonicalMethod(CanonicalFormKind.Universal))
|
||||
instantiatedMethod = instantiatedMethod.GetCanonMethodTarget(CanonicalFormKind.Universal);
|
||||
|
||||
bool validInstantiation =
|
||||
instantiatedMethod.IsSharedByGenericInstantiations || ( // Non-exact methods are always valid instantiations (always pass constraints check)
|
||||
instantiatedMethod.Instantiation.CheckValidInstantiationArguments() &&
|
||||
instantiatedMethod.OwningType.Instantiation.CheckValidInstantiationArguments() &&
|
||||
instantiatedMethod.CheckConstraints());
|
||||
|
||||
if (validInstantiation)
|
||||
{
|
||||
MethodDesc canonMethodTarget = instantiatedMethod.GetCanonMethodTarget(CanonicalFormKind.Specific);
|
||||
|
||||
bool getUnboxingStub = instantiatedMethod.OwningType.IsValueType;
|
||||
yield return new DependencyListEntry(context.MethodEntrypoint(canonMethodTarget, getUnboxingStub), "GVM Dependency - Canon method");
|
||||
|
||||
if (canonMethodTarget != instantiatedMethod)
|
||||
{
|
||||
// Dependency includes the generic method dictionary of the instantiation, and all its dependencies. This is done by adding the
|
||||
// ShadowConcreteMethod to the list of dynamic dependencies. The generic dictionary will be reported as a dependency of the ShadowConcreteMethod
|
||||
// TODO: detect large recursive generics and fallback to USG templates
|
||||
Debug.Assert(!instantiatedMethod.IsCanonicalMethod(CanonicalFormKind.Any));
|
||||
yield return new DependencyListEntry(context.ShadowConcreteMethod(instantiatedMethod), "GVM Dependency - Dictionary");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: universal generics
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDependencies(NodeFactory context)
|
||||
{
|
||||
return Array.Empty<CombinedDependencyListEntry>();
|
||||
|
@ -90,20 +121,25 @@ namespace ILCompiler.DependencyAnalysis
|
|||
continue;
|
||||
|
||||
TypeDesc potentialOverrideType = entryAsEETypeNode.Type;
|
||||
if (!(potentialOverrideType is DefType))
|
||||
if (!potentialOverrideType.IsDefType)
|
||||
continue;
|
||||
|
||||
Debug.Assert(!potentialOverrideType.IsRuntimeDeterminedSubtype);
|
||||
|
||||
if (_method.OwningType.HasSameTypeDefinition(potentialOverrideType) && potentialOverrideType.IsInterface && (potentialOverrideType != _method.OwningType))
|
||||
if (potentialOverrideType.IsInterface)
|
||||
{
|
||||
if (_method.OwningType.CanCastTo(potentialOverrideType))
|
||||
if (_method.OwningType.HasSameTypeDefinition(potentialOverrideType) && (potentialOverrideType != _method.OwningType))
|
||||
{
|
||||
// Variance expansion
|
||||
MethodDesc matchingMethodOnRelatedVariantMethod = potentialOverrideType.GetMethod(_method.Name, _method.GetTypicalMethodDefinition().Signature);
|
||||
matchingMethodOnRelatedVariantMethod = _method.Context.GetInstantiatedMethod(matchingMethodOnRelatedVariantMethod, _method.Instantiation);
|
||||
dynamicDependencies.Add(new CombinedDependencyListEntry(factory.GVMDependencies(matchingMethodOnRelatedVariantMethod), null, "GVM Variant Interface dependency"));
|
||||
if (potentialOverrideType.CanCastTo(_method.OwningType))
|
||||
{
|
||||
// Variance expansion
|
||||
MethodDesc matchingMethodOnRelatedVariantMethod = potentialOverrideType.GetMethod(_method.Name, _method.GetTypicalMethodDefinition().Signature);
|
||||
matchingMethodOnRelatedVariantMethod = _method.Context.GetInstantiatedMethod(matchingMethodOnRelatedVariantMethod, _method.Instantiation);
|
||||
dynamicDependencies.Add(new CombinedDependencyListEntry(factory.GVMDependencies(matchingMethodOnRelatedVariantMethod), null, "GVM Variant Interface dependency"));
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// If this is an interface gvm, look for types that implement the interface
|
||||
|
@ -112,89 +148,59 @@ namespace ILCompiler.DependencyAnalysis
|
|||
// relationship in the vtable.
|
||||
if (_method.OwningType.IsInterface)
|
||||
{
|
||||
if (potentialOverrideType.IsInterface)
|
||||
continue;
|
||||
|
||||
foreach (DefType interfaceImpl in potentialOverrideType.RuntimeInterfaces)
|
||||
{
|
||||
if (interfaceImpl.ConvertToCanonForm(CanonicalFormKind.Specific) == _method.OwningType.ConvertToCanonForm(CanonicalFormKind.Specific))
|
||||
if (interfaceImpl == _method.OwningType)
|
||||
{
|
||||
// Find if the type implements this method. (Note, do this comparision against the generic definition of the method, not the
|
||||
// specific method instantiation that is "method"
|
||||
MethodDesc genericDefinition = interfaceImpl.GetMethod(_method.Name, _method.GetTypicalMethodDefinition().Signature);
|
||||
MethodDesc slotDecl = potentialOverrideType.ResolveInterfaceMethodTarget(genericDefinition);
|
||||
MethodDesc slotDecl = potentialOverrideType.ResolveInterfaceMethodTarget(_method.GetMethodDefinition());
|
||||
if (slotDecl != null)
|
||||
CreateDependencyForMethodSlotAndInstantiation(slotDecl, dynamicDependencies, factory);
|
||||
{
|
||||
MethodDesc implementingMethodInstantiation = _method.Context.GetInstantiatedMethod(slotDecl, _method.Instantiation);
|
||||
dynamicDependencies.Add(new CombinedDependencyListEntry(factory.GVMDependencies(implementingMethodInstantiation), null, "ImplementingMethodInstantiation"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Ensure GVM Canon Target
|
||||
|
||||
TypeDesc overrideTypeCanonCur = potentialOverrideType;
|
||||
TypeDesc methodCanonContainingType = _method.OwningType;
|
||||
while (overrideTypeCanonCur != null)
|
||||
// Quickly check if the potential overriding type is at all related to the GVM's owning type (there is no need
|
||||
// to do any processing for a type that is not at all related to the GVM's owning type. Resolving virtuals is expensive).
|
||||
TypeDesc overrideTypeCur = potentialOverrideType;
|
||||
{
|
||||
if (overrideTypeCanonCur.ConvertToCanonForm(CanonicalFormKind.Specific) == methodCanonContainingType.ConvertToCanonForm(CanonicalFormKind.Specific))
|
||||
do
|
||||
{
|
||||
MethodDesc methodDefInDerivedType = potentialOverrideType.GetMethod(_method.Name, _method.GetTypicalMethodDefinition().Signature);
|
||||
if(methodDefInDerivedType != null)
|
||||
CreateDependencyForMethodSlotAndInstantiation(methodDefInDerivedType, dynamicDependencies, factory);
|
||||
if (overrideTypeCur == _method.OwningType)
|
||||
break;
|
||||
|
||||
MethodDesc slotDecl = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(_method);
|
||||
if (slotDecl != null)
|
||||
CreateDependencyForMethodSlotAndInstantiation(slotDecl.GetMethodDefinition(), dynamicDependencies, factory);
|
||||
overrideTypeCur = overrideTypeCur.BaseType;
|
||||
}
|
||||
while (overrideTypeCur != null);
|
||||
|
||||
if (overrideTypeCur == null)
|
||||
continue;
|
||||
}
|
||||
|
||||
overrideTypeCur = potentialOverrideType;
|
||||
while (overrideTypeCur != null)
|
||||
{
|
||||
if (overrideTypeCur == _method.OwningType)
|
||||
{
|
||||
// The GVMDependencyNode already declares the entrypoint/dictionary dependencies of the current method
|
||||
// as static dependencies, therefore we can break the loop as soon we hit the current method's owning type
|
||||
// while we're traversing the hierarchy of the potential derived types.
|
||||
break;
|
||||
}
|
||||
|
||||
overrideTypeCanonCur = overrideTypeCanonCur.BaseType;
|
||||
MethodDesc instantiatedTargetMethod = overrideTypeCur.FindVirtualFunctionTargetMethodOnObjectType(_method);
|
||||
if (instantiatedTargetMethod != null)
|
||||
dynamicDependencies.Add(new CombinedDependencyListEntry(factory.GVMDependencies(instantiatedTargetMethod), null, "DerivedMethodInstantiation"));
|
||||
|
||||
overrideTypeCur = overrideTypeCur.BaseType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dynamicDependencies;
|
||||
}
|
||||
|
||||
private void CreateDependencyForMethodSlotAndInstantiation(MethodDesc methodDef, List<CombinedDependencyListEntry> dynamicDependencies, NodeFactory factory)
|
||||
{
|
||||
Debug.Assert(methodDef != null);
|
||||
Debug.Assert(!methodDef.Signature.IsStatic);
|
||||
|
||||
if (methodDef.IsAbstract)
|
||||
return;
|
||||
|
||||
MethodDesc derivedMethodInstantiation = _method.Context.GetInstantiatedMethod(methodDef, _method.Instantiation);
|
||||
|
||||
// Universal canonical instantiations should be entirely universal canon
|
||||
if (derivedMethodInstantiation.IsCanonicalMethod(CanonicalFormKind.Universal))
|
||||
{
|
||||
derivedMethodInstantiation = derivedMethodInstantiation.GetCanonMethodTarget(CanonicalFormKind.Universal);
|
||||
}
|
||||
|
||||
// TODO: verify for invalid instantiations, like List<void>?
|
||||
bool validInstantiation =
|
||||
derivedMethodInstantiation.IsSharedByGenericInstantiations || // Non-exact methods are always valid instantiations (always pass constraints check)
|
||||
derivedMethodInstantiation.CheckConstraints(); // Verify that the instantiation does not violate constraints
|
||||
|
||||
if (validInstantiation)
|
||||
{
|
||||
MethodDesc canonMethodTarget = derivedMethodInstantiation.GetCanonMethodTarget(CanonicalFormKind.Specific);
|
||||
|
||||
bool getUnboxingStub = (derivedMethodInstantiation.OwningType.IsValueType || derivedMethodInstantiation.OwningType.IsEnum);
|
||||
dynamicDependencies.Add(new CombinedDependencyListEntry(factory.MethodEntrypoint(canonMethodTarget, getUnboxingStub), null, "DerivedMethodInstantiation"));
|
||||
|
||||
if (canonMethodTarget != derivedMethodInstantiation)
|
||||
{
|
||||
// Dependency includes the generic method dictionary of the instantiation, and all its dependencies. This is done by adding the
|
||||
// ShadowConcreteMethod to the list of dynamic dependencies. The generic dictionary will be reported as a dependency of the ShadowConcreteMethod
|
||||
// TODO: detect large recursive generics and fallback to USG templates
|
||||
Debug.Assert(!derivedMethodInstantiation.IsCanonicalMethod(CanonicalFormKind.Any));
|
||||
dynamicDependencies.Add(new CombinedDependencyListEntry(factory.ShadowConcreteMethod(derivedMethodInstantiation), null, "DerivedMethodInstantiation dictionary"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: universal generics
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,7 +77,36 @@ namespace ILCompiler.DependencyAnalysis
|
|||
if(!type.IsDefType || type.IsInterface)
|
||||
return false;
|
||||
|
||||
return type.HasGenericVirtualMethod();
|
||||
// Type declares GVMs
|
||||
if (type.HasGenericVirtualMethods())
|
||||
return true;
|
||||
|
||||
//
|
||||
// Check if the type implements any interface with GVM methods, where the method implementations could be on
|
||||
// base types.
|
||||
// Example:
|
||||
// interface IFace {
|
||||
// void IFaceGVMethod<U>();
|
||||
// }
|
||||
// class BaseClass {
|
||||
// public virtual void IFaceGVMethod<U>() { ... }
|
||||
// }
|
||||
// public class DerivedClass : BaseClass, IFace { }
|
||||
//
|
||||
foreach (var iface in type.RuntimeInterfaces)
|
||||
{
|
||||
foreach (var method in iface.GetMethods())
|
||||
{
|
||||
if (!method.HasInstantiation || method.Signature.IsStatic)
|
||||
continue;
|
||||
|
||||
MethodDesc slotDecl = type.ResolveInterfaceMethodTarget(method);
|
||||
if (slotDecl != null)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public IEnumerable<TypeGVMEntryInfo> ScanForGenericVirtualMethodEntries()
|
||||
|
|
|
@ -97,7 +97,7 @@ namespace ILCompiler
|
|||
/// <summary>
|
||||
/// Gets a value indicating whether this type has any generic virtual methods.
|
||||
/// </summary>
|
||||
public static bool HasGenericVirtualMethod(this TypeDesc type)
|
||||
public static bool HasGenericVirtualMethods(this TypeDesc type)
|
||||
{
|
||||
foreach (var method in type.GetAllMethods())
|
||||
{
|
||||
|
|
|
@ -259,6 +259,27 @@ namespace TypeSystemTests
|
|||
instantiatedType = _multipleConstraintsType.MakeInstantiatedType(_classArgWithDefaultCtorType, _context.GetWellKnownType(WellKnownType.Object));
|
||||
Assert.True(instantiatedType.CheckConstraints());
|
||||
}
|
||||
|
||||
// InvalidInstantiationArgs
|
||||
{
|
||||
var pointer = _context.GetWellKnownType(WellKnownType.Int16).MakePointerType();
|
||||
var byref = _context.GetWellKnownType(WellKnownType.Int16).MakeByRefType();
|
||||
|
||||
Assert.False(_iGenType.Instantiation.CheckValidInstantiationArguments());
|
||||
|
||||
instantiatedType = _iGenType.MakeInstantiatedType(_context.GetWellKnownType(WellKnownType.Void));
|
||||
Assert.False(instantiatedType.Instantiation.CheckValidInstantiationArguments());
|
||||
|
||||
instantiatedType = _iGenType.MakeInstantiatedType(pointer);
|
||||
Assert.False(instantiatedType.Instantiation.CheckValidInstantiationArguments());
|
||||
|
||||
instantiatedType = _iGenType.MakeInstantiatedType(byref);
|
||||
Assert.False(instantiatedType.Instantiation.CheckValidInstantiationArguments());
|
||||
|
||||
instantiatedType = _iGenType.MakeInstantiatedType(byref);
|
||||
instantiatedType = _iGenType.MakeInstantiatedType(instantiatedType);
|
||||
Assert.False(instantiatedType.Instantiation.CheckValidInstantiationArguments());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,12 +21,50 @@ namespace Internal.Runtime.TypeLoader
|
|||
{
|
||||
public sealed partial class TypeLoaderEnvironment
|
||||
{
|
||||
#if GVM_RESOLUTION_TRACE
|
||||
private string GetTypeNameDebug(RuntimeTypeHandle rtth)
|
||||
{
|
||||
string result;
|
||||
|
||||
if (RuntimeAugments.IsGenericType(rtth))
|
||||
{
|
||||
RuntimeTypeHandle[] typeArgumentsHandles;
|
||||
RuntimeTypeHandle openTypeDef = RuntimeAugments.GetGenericInstantiation(rtth, out typeArgumentsHandles); ;
|
||||
result = GetTypeNameDebug(openTypeDef) + "<";
|
||||
for (int i = 0; i < typeArgumentsHandles.Length; i++)
|
||||
result += (i == 0 ? "" : ",") + GetTypeNameDebug(typeArgumentsHandles[i]);
|
||||
return result + ">";
|
||||
}
|
||||
else
|
||||
{
|
||||
System.Reflection.Runtime.General.QTypeDefinition qTypeDefinition;
|
||||
|
||||
// Check if we have metadata.
|
||||
if (Instance.TryGetMetadataForNamedType(rtth, out qTypeDefinition))
|
||||
return qTypeDefinition.NativeFormatHandle.GetFullName(qTypeDefinition.NativeFormatReader);
|
||||
}
|
||||
|
||||
result = "EEType:0x";
|
||||
ulong num = (ulong)RuntimeAugments.GetPointerFromTypeHandle(rtth);
|
||||
|
||||
int shift = IntPtr.Size * 8;
|
||||
const string HexDigits = "0123456789ABCDEF";
|
||||
while (shift > 0)
|
||||
{
|
||||
shift -= 4;
|
||||
int digit = (int)((num >> shift) & 0xF);
|
||||
result += HexDigits[digit];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
public bool TryGetGenericVirtualTargetForTypeAndSlot(RuntimeTypeHandle targetHandle, ref RuntimeTypeHandle declaringType, RuntimeTypeHandle[] genericArguments, ref string methodName, ref RuntimeSignature methodSignature, out IntPtr methodPointer, out IntPtr dictionaryPointer, out bool slotUpdated)
|
||||
{
|
||||
MethodNameAndSignature methodNameAndSignature = new MethodNameAndSignature(methodName, methodSignature);
|
||||
|
||||
#if REFLECTION_EXECUTION_TRACE
|
||||
ReflectionExecutionLogger.WriteLine("GVM resolution starting for " + GetTypeNameDebug(declaringType) + "." + methodNameAndSignature.Name + "(...) on a target of type " + GetTypeNameDebug(targetHandle) + " ...");
|
||||
#if GVM_RESOLUTION_TRACE
|
||||
Debug.WriteLine("GVM resolution starting for " + GetTypeNameDebug(declaringType) + "." + methodNameAndSignature.Name + "(...) on a target of type " + GetTypeNameDebug(targetHandle) + " ...");
|
||||
#endif
|
||||
|
||||
if (RuntimeAugments.IsInterface(declaringType))
|
||||
|
@ -83,14 +121,19 @@ namespace Internal.Runtime.TypeLoader
|
|||
{
|
||||
uint numTargetImplementations = entryParser.GetUnsigned();
|
||||
|
||||
#if GVM_RESOLUTION_TRACE
|
||||
Debug.WriteLine(" :: Declaring type = " + GetTypeNameDebug(declaringType));
|
||||
Debug.WriteLine(" :: Target type = " + GetTypeNameDebug(openTargetTypeHandle));
|
||||
#endif
|
||||
|
||||
for (uint j = 0; j < numTargetImplementations; j++)
|
||||
{
|
||||
uint nameAndSigToken = extRefs.GetExternalNativeLayoutOffset(entryParser.GetUnsigned());
|
||||
MethodNameAndSignature targetMethodNameAndSignature = GetMethodNameAndSignatureFromNativeReader(nativeLayoutReader, module.Handle, nameAndSigToken);
|
||||
RuntimeTypeHandle targetTypeHandle = extRefs.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned());
|
||||
|
||||
#if REFLECTION_EXECUTION_TRACE
|
||||
ReflectionExecutionLogger.WriteLine(" Searching for GVM implementation on targe type = " + GetTypeNameDebug(targetTypeHandle));
|
||||
#if GVM_RESOLUTION_TRACE
|
||||
Debug.WriteLine(" Searching for GVM implementation on targe type = " + GetTypeNameDebug(targetTypeHandle));
|
||||
#endif
|
||||
|
||||
uint numIfaceImpls = entryParser.GetUnsigned();
|
||||
|
@ -99,6 +142,10 @@ namespace Internal.Runtime.TypeLoader
|
|||
{
|
||||
RuntimeTypeHandle implementingTypeHandle = extRefs.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned());
|
||||
|
||||
#if GVM_RESOLUTION_TRACE
|
||||
Debug.WriteLine(" -> Current implementing type = " + GetTypeNameDebug(implementingTypeHandle));
|
||||
#endif
|
||||
|
||||
uint numIfaceSigs = entryParser.GetUnsigned();
|
||||
|
||||
if (!openTargetTypeHandle.Equals(implementingTypeHandle))
|
||||
|
@ -118,13 +165,16 @@ namespace Internal.Runtime.TypeLoader
|
|||
|
||||
if (TypeLoaderEnvironment.Instance.GetTypeFromSignatureAndContext(ref ifaceSigParser, module.Handle, targetTypeInstantiation, null, out currentIfaceTypeHandle))
|
||||
{
|
||||
#if GVM_RESOLUTION_TRACE
|
||||
Debug.WriteLine(" -> Current interface on type = " + GetTypeNameDebug(currentIfaceTypeHandle));
|
||||
#endif
|
||||
Debug.Assert(!currentIfaceTypeHandle.IsNull());
|
||||
|
||||
if ((!variantDispatch && declaringType.Equals(currentIfaceTypeHandle)) ||
|
||||
(variantDispatch && RuntimeAugments.IsAssignableFrom(declaringType, currentIfaceTypeHandle)))
|
||||
{
|
||||
#if REFLECTION_EXECUTION_TRACE
|
||||
ReflectionExecutionLogger.WriteLine(" " + (declaringType.Equals(currentIfaceTypeHandle) ? "Exact" : "Variant-compatible") + " match found on this target type!");
|
||||
#if GVM_RESOLUTION_TRACE
|
||||
Debug.WriteLine(" " + (declaringType.Equals(currentIfaceTypeHandle) ? "Exact" : "Variant-compatible") + " match found on this target type!");
|
||||
#endif
|
||||
// We found the GVM slot target for the input interface GVM call, so let's update the interface GVM slot and return success to the caller
|
||||
declaringType = targetTypeHandle;
|
||||
|
@ -197,8 +247,8 @@ namespace Internal.Runtime.TypeLoader
|
|||
RuntimeTypeHandle[] targetTypeInstantiation;
|
||||
openTargetTypeHandle = GetOpenTypeDefinition(targetTypeHandle, out targetTypeInstantiation);
|
||||
|
||||
#if REFLECTION_EXECUTION_TRACE
|
||||
ReflectionExecutionLogger.WriteLine("INTERFACE GVM call = " + GetTypeNameDebug(declaringType) + "." + methodNameAndSignature.Name);
|
||||
#if GVM_RESOLUTION_TRACE
|
||||
Debug.WriteLine("INTERFACE GVM call = " + GetTypeNameDebug(declaringType) + "." + methodNameAndSignature.Name);
|
||||
#endif
|
||||
|
||||
foreach (NativeFormatModuleInfo module in ModuleList.EnumerateModules(RuntimeAugments.GetModuleFromTypeHandle(openTargetTypeHandle)))
|
||||
|
@ -427,8 +477,8 @@ namespace Internal.Runtime.TypeLoader
|
|||
int hashCode = openCallingTypeHandle.GetHashCode();
|
||||
hashCode = ((hashCode << 13) ^ hashCode) ^ openTargetTypeHandle.GetHashCode();
|
||||
|
||||
#if REFLECTION_EXECUTION_TRACE
|
||||
ReflectionExecutionLogger.WriteLine("GVM Target Resolution = " + GetTypeNameDebug(targetTypeHandle) + "." + callingMethodNameAndSignature.Name);
|
||||
#if GVM_RESOLUTION_TRACE
|
||||
Debug.WriteLine("GVM Target Resolution = " + GetTypeNameDebug(targetTypeHandle) + "." + callingMethodNameAndSignature.Name);
|
||||
#endif
|
||||
|
||||
foreach (NativeFormatModuleInfo module in ModuleList.EnumerateModules(RuntimeAugments.GetModuleFromTypeHandle(openTargetTypeHandle)))
|
||||
|
|
|
@ -144,13 +144,6 @@
|
|||
<ExcludeList Include="$(XunitTestBinBase)\JIT\jit64\opt\cse\HugeArray1\HugeArray1.*" />
|
||||
<ExcludeList Include="$(XunitTestBinBase)\JIT\jit64\opt\cse\hugeexpr1\hugeexpr1.*" />
|
||||
|
||||
<!-- Generic virtual methods -->
|
||||
<!-- https://github.com/dotnet/corert/issues/3454 -->
|
||||
<ExcludeList Include="$(XunitTestBinBase)\JIT\Regression\CLR-x86-JIT\V1.2-Beta1\b210352\csharptester\csharptester.*" />
|
||||
<ExcludeList Include="$(XunitTestBinBase)\Loader\classloader\generics\Variance\Regressions\dev10_468712\dev10_468712\dev10_468712.*" />
|
||||
<ExcludeList Include="$(XunitTestBinBase)\Loader\classloader\methodoverriding\regressions\dev10_432038\dev10_432038\dev10_432038.*" />
|
||||
<ExcludeList Include="$(XunitTestBinBase)\Loader\classloader\regressions\dev10_398410\dev10_398410\dev10_398410.*" />
|
||||
|
||||
<!-- Reflection enabling a virtual method methodimpl'd by other virtual method -->
|
||||
<ExcludeList Include="$(XunitTestBinBase)\Loader\classloader\methodoverriding\regressions\576621\VSW576621\VSW576621.*" />
|
||||
|
||||
|
|
|
@ -1142,6 +1142,21 @@ class Program
|
|||
string IMethod1<T>(T t1, T t2);
|
||||
}
|
||||
|
||||
interface ICovariant<out T>
|
||||
{
|
||||
string ICovariantGVM<U>();
|
||||
}
|
||||
|
||||
public interface IBar<T>
|
||||
{
|
||||
U IBarGVMethod<U>(Func<T, U> arg);
|
||||
}
|
||||
|
||||
public interface IFace<T>
|
||||
{
|
||||
string IFaceGVMethod1<U>(T t, U u);
|
||||
}
|
||||
|
||||
class Base : IFoo<string>, IFoo<int>
|
||||
{
|
||||
public virtual string GMethod1<T>(T t1, T t2) { return "Base.GMethod1<" + typeof(T) + ">(" + t1 + "," + t2 + ")"; }
|
||||
|
@ -1189,6 +1204,36 @@ class Program
|
|||
public string IMethod1<T>(T t1, T t2) { return "MyStruct3.IMethod1<" + typeof(T) + ">(" + t1 + "," + t2 + ")"; }
|
||||
}
|
||||
|
||||
public class AnotherBaseClass<T>
|
||||
{
|
||||
public virtual string IFaceMethod1(T t) { return "AnotherBaseClass.IFaceMethod1"; }
|
||||
public virtual string IFaceGVMethod1<U>(T t, U u) { return "AnotherBaseClass.IFaceGVMethod1"; }
|
||||
}
|
||||
|
||||
public class AnotherDerivedClass<T> : AnotherBaseClass<T>, IFace<T>
|
||||
{
|
||||
}
|
||||
|
||||
public class BarImplementor : IBar<int>
|
||||
{
|
||||
public virtual U IBarGVMethod<U>(Func<int, U> arg) { return arg(123); }
|
||||
}
|
||||
|
||||
public class Yahoo<T>
|
||||
{
|
||||
public virtual U YahooGVM<U>(Func<T, U> arg) { return default(U); }
|
||||
}
|
||||
|
||||
public class YahooDerived : Yahoo<int>
|
||||
{
|
||||
public override U YahooGVM<U>(Func<int, U> arg) { return arg(456); }
|
||||
}
|
||||
|
||||
public class Covariant<T> : ICovariant<T>
|
||||
{
|
||||
public string ICovariantGVM<U>() { return String.Format("Covariant<{0}>.ICovariantGVM<{1}>", typeof(T).Name, typeof(U).Name); }
|
||||
}
|
||||
|
||||
static string s_GMethod1;
|
||||
static string s_IFooString;
|
||||
static string s_IFooObject;
|
||||
|
@ -1342,6 +1387,20 @@ class Program
|
|||
Console.WriteLine("====================");
|
||||
}
|
||||
|
||||
{
|
||||
string res = ((IFace<string>)new AnotherDerivedClass<string>()).IFaceGVMethod1<string>("string1", "string2");
|
||||
WriteLineWithVerification("AnotherBaseClass.IFaceGVMethod1", res);
|
||||
|
||||
res = ((IBar<int>)new BarImplementor()).IBarGVMethod<string>((i) => "BarImplementor:" + i.ToString());
|
||||
WriteLineWithVerification("BarImplementor:123", res);
|
||||
|
||||
Yahoo<int> y = new YahooDerived();
|
||||
WriteLineWithVerification("YahooDerived:456", y.YahooGVM<string>((i) => "YahooDerived:" + i.ToString()));
|
||||
|
||||
ICovariant<object> cov = new Covariant<string>();
|
||||
WriteLineWithVerification("Covariant<String>.ICovariantGVM<Exception>", cov.ICovariantGVM<Exception>());
|
||||
}
|
||||
|
||||
if (s_NumErrors != 0)
|
||||
throw new Exception();
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче