diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GVMDependenciesNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GVMDependenciesNode.cs index f7b1bd694b8a09..28b2a79c93d4d5 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GVMDependenciesNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GVMDependenciesNode.cs @@ -10,6 +10,8 @@ namespace ILCompiler.DependencyAnalysis { /// + /// Represents a use of a generic virtual method slot. This node only tracks + /// the use of the slot definition. /// This analysis node is used for computing GVM dependencies for the following cases: /// 1) Derived types where the GVM is overridden /// 2) Variant-interfaces GVMs @@ -19,17 +21,14 @@ namespace ILCompiler.DependencyAnalysis /// public class GVMDependenciesNode : DependencyNodeCore { - private const int UniversalCanonGVMDepthHeuristic_CanonDepth = 2; private readonly MethodDesc _method; public GVMDependenciesNode(MethodDesc method) { Debug.Assert(method.GetCanonMethodTarget(CanonicalFormKind.Specific) == method); Debug.Assert(method.HasInstantiation); - - // This is either a generic virtual method or a MethodImpl for a static interface method. - // We can't test for static MethodImpl so at least sanity check it's static and noninterface. - Debug.Assert(method.IsVirtual || (method.Signature.IsStatic && !method.OwningType.IsInterface)); + Debug.Assert(method.IsVirtual); + Debug.Assert(MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(method) == method); _method = method; } @@ -39,41 +38,10 @@ public GVMDependenciesNode(MethodDesc method) public override bool StaticDependenciesAreComputed => true; protected override string GetName(NodeFactory factory) => "__GVMDependenciesNode_" + factory.NameMangler.GetMangledMethodName(_method); - public override IEnumerable GetStaticDependencies(NodeFactory context) + public override IEnumerable GetStaticDependencies(NodeFactory factory) { - DependencyList dependencies = null; - - context.MetadataManager.GetDependenciesDueToVirtualMethodReflectability(ref dependencies, context, _method); - if (!_method.IsAbstract) - { - bool validInstantiation = - _method.IsSharedByGenericInstantiations || ( // Non-exact methods are always valid instantiations (always pass constraints check) - _method.Instantiation.CheckValidInstantiationArguments() && - _method.OwningType.Instantiation.CheckValidInstantiationArguments() && - _method.CheckConstraints()); - - if (validInstantiation) - { - if (context.TypeSystemContext.SupportsUniversalCanon && _method.IsGenericDepthGreaterThan(UniversalCanonGVMDepthHeuristic_CanonDepth)) - { - // fall back to using the universal generic variant of the generic method - return dependencies; - } - - bool getUnboxingStub = _method.OwningType.IsValueType && !_method.Signature.IsStatic; - dependencies ??= new DependencyList(); - dependencies.Add(context.MethodEntrypoint(_method, getUnboxingStub), "GVM Dependency - Canon method"); - - if (_method.IsSharedByGenericInstantiations) - { - dependencies.Add(context.NativeLayout.TemplateMethodEntry(_method), "GVM Dependency - Template entry"); - dependencies.Add(context.NativeLayout.TemplateMethodLayout(_method), "GVM Dependency - Template"); - } - } - } - - return dependencies; + yield return new DependencyListEntry(factory.GenericVirtualMethodImpl(_method), "Implementation of the generic virtual method"); } public override IEnumerable GetConditionalStaticDependencies(NodeFactory context) => null; @@ -89,14 +57,6 @@ public override bool HasDynamicDependencies (methodOwningType.IsSealed() || _method.IsFinal)) return false; - // We model static (non-virtual) methods that are MethodImpls for a static interface method. - // But those cannot be overriden (they're not virtual to begin with). - if (!methodOwningType.IsInterface && _method.Signature.IsStatic) - { - Debug.Assert(!_method.IsVirtual); - return false; - } - return true; } } @@ -173,7 +133,12 @@ public override IEnumerable SearchDynamicDependenci for (int instArg = 0; instArg < openInstantiation.Length; instArg++) openInstantiation[instArg] = context.GetSignatureVariable(instArg, method: true); MethodDesc implementingMethodInstantiation = slotDecl.MakeInstantiatedMethod(openInstantiation).InstantiateSignature(potentialOverrideType.Instantiation, _method.Instantiation); - dynamicDependencies.Add(new CombinedDependencyListEntry(factory.GVMDependencies(implementingMethodInstantiation.GetCanonMethodTarget(CanonicalFormKind.Specific)), null, "ImplementingMethodInstantiation")); + + // Static virtuals cannot be further overriden so this is an impl use. Otherwise it's a virtual slot use. + if (implementingMethodInstantiation.Signature.IsStatic) + dynamicDependencies.Add(new CombinedDependencyListEntry(factory.GenericVirtualMethodImpl(implementingMethodInstantiation.GetCanonMethodTarget(CanonicalFormKind.Specific)), null, "ImplementingMethodInstantiation")); + else + dynamicDependencies.Add(new CombinedDependencyListEntry(factory.GVMDependencies(implementingMethodInstantiation.GetCanonMethodTarget(CanonicalFormKind.Specific)), null, "ImplementingMethodInstantiation")); factory.MetadataManager.NoteOverridingMethod(_method, implementingMethodInstantiation); } @@ -225,7 +190,7 @@ public override IEnumerable SearchDynamicDependenci if (instantiatedTargetMethod != _method) { dynamicDependencies.Add(new CombinedDependencyListEntry( - factory.GVMDependencies(instantiatedTargetMethod), null, "DerivedMethodInstantiation")); + factory.GenericVirtualMethodImpl(instantiatedTargetMethod), null, "DerivedMethodInstantiation")); factory.MetadataManager.NoteOverridingMethod(_method, instantiatedTargetMethod); } diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GenericVirtualMethodImplNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GenericVirtualMethodImplNode.cs new file mode 100644 index 00000000000000..b7be9dd525f5c8 --- /dev/null +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GenericVirtualMethodImplNode.cs @@ -0,0 +1,78 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; +using System.Collections.Generic; + +using ILCompiler.DependencyAnalysisFramework; + +using Internal.TypeSystem; + +namespace ILCompiler.DependencyAnalysis +{ + /// + /// Represents a use of a generic virtual method body implementation. + /// + public class GenericVirtualMethodImplNode : DependencyNodeCore + { + private const int UniversalCanonGVMDepthHeuristic_CanonDepth = 2; + private readonly MethodDesc _method; + + public GenericVirtualMethodImplNode(MethodDesc method) + { + Debug.Assert(method.GetCanonMethodTarget(CanonicalFormKind.Specific) == method); + Debug.Assert(method.HasInstantiation); + + // This is either a generic virtual method or a MethodImpl for a static interface method. + // We can't test for static MethodImpl so at least sanity check it's static and noninterface. + Debug.Assert(method.IsVirtual || (method.Signature.IsStatic && !method.OwningType.IsInterface)); + + _method = method; + } + + public override bool HasConditionalStaticDependencies => false; + public override bool InterestingForDynamicDependencyAnalysis => false; + public override bool StaticDependenciesAreComputed => true; + protected override string GetName(NodeFactory factory) => "__GVMImplNode_" + factory.NameMangler.GetMangledMethodName(_method); + + public override IEnumerable GetStaticDependencies(NodeFactory factory) + { + DependencyList dependencies = null; + + factory.MetadataManager.GetDependenciesDueToVirtualMethodReflectability(ref dependencies, factory, _method); + + bool validInstantiation = + _method.IsSharedByGenericInstantiations || ( // Non-exact methods are always valid instantiations (always pass constraints check) + _method.Instantiation.CheckValidInstantiationArguments() && + _method.OwningType.Instantiation.CheckValidInstantiationArguments() && + _method.CheckConstraints()); + + if (validInstantiation) + { + if (factory.TypeSystemContext.SupportsUniversalCanon && _method.IsGenericDepthGreaterThan(UniversalCanonGVMDepthHeuristic_CanonDepth)) + { + // fall back to using the universal generic variant of the generic method + return dependencies; + } + + bool getUnboxingStub = _method.OwningType.IsValueType && !_method.Signature.IsStatic; + dependencies ??= new DependencyList(); + dependencies.Add(factory.MethodEntrypoint(_method, getUnboxingStub), "GVM Dependency - Canon method"); + + if (_method.IsSharedByGenericInstantiations) + { + dependencies.Add(factory.NativeLayout.TemplateMethodEntry(_method), "GVM Dependency - Template entry"); + dependencies.Add(factory.NativeLayout.TemplateMethodLayout(_method), "GVM Dependency - Template"); + } + } + + return dependencies; + } + + public override IEnumerable GetConditionalStaticDependencies(NodeFactory context) => null; + + public override bool HasDynamicDependencies => false; + + public override IEnumerable SearchDynamicDependencies(List> markedNodes, int firstNode, NodeFactory factory) => null; + } +} diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs index ba0f5be86ea0f6..7a22f2bbc7b7ec 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs @@ -284,6 +284,11 @@ private void CreateNodeCaches() return new GVMDependenciesNode(method); }); + _gvmImpls = new NodeCache(method => + { + return new GenericVirtualMethodImplNode(method); + }); + _gvmTableEntries = new NodeCache(type => { return new TypeGVMEntriesNode(type); @@ -931,6 +936,12 @@ public GVMDependenciesNode GVMDependencies(MethodDesc method) return _gvmDependenciesNode.GetOrAdd(method); } + private NodeCache _gvmImpls; + public GenericVirtualMethodImplNode GenericVirtualMethodImpl(MethodDesc method) + { + return _gvmImpls.GetOrAdd(method); + } + private NodeCache _gvmTableEntries; internal TypeGVMEntriesNode TypeGVMEntries(TypeDesc type) { diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ReflectedMethodNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ReflectedMethodNode.cs index 0a4a1ef59ed815..729bf520192779 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ReflectedMethodNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ReflectedMethodNode.cs @@ -64,14 +64,17 @@ public override IEnumerable GetStaticDependencies(NodeFacto { if (_method.IsVirtual) { + // Virtual method use is tracked on the slot defining method only. + MethodDesc slotDefiningMethod = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(_method); if (_method.HasInstantiation) { - dependencies.Add(factory.GVMDependencies(_method.GetCanonMethodTarget(CanonicalFormKind.Specific)), "GVM callable reflectable method"); + // FindSlotDefiningMethod might uninstantiate. We might want to fix the method not to do that. + if (slotDefiningMethod.IsMethodDefinition) + slotDefiningMethod = factory.TypeSystemContext.GetInstantiatedMethod(slotDefiningMethod, _method.Instantiation); + dependencies.Add(factory.GVMDependencies(slotDefiningMethod.GetCanonMethodTarget(CanonicalFormKind.Specific)), "GVM callable reflectable method"); } else { - // Virtual method use is tracked on the slot defining method only. - MethodDesc slotDefiningMethod = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(_method); if (!factory.VTable(slotDefiningMethod.OwningType).HasFixedSlots) dependencies.Add(factory.VirtualMethodUse(slotDefiningMethod), "Virtually callable reflectable method"); } diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj b/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj index 0cc8c90ca01446..ea72bb4d6fe76f 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj @@ -393,6 +393,7 @@ +