From 58cd6d194ac0ba5bda390ef9d2dd2fce9f4c7214 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Thu, 16 Jan 2025 13:54:44 +0100 Subject: [PATCH 1/2] Don't report interfaces with optimized-away MT as "never instantiated" --- .../Compiler/DevirtualizationManager.cs | 15 ++++++++++++ .../Compiler/Compilation.cs | 10 ++++++++ .../ILCompiler.Compiler/Compiler/ILScanner.cs | 23 +++++++++++++++++++ .../JitInterface/CorInfoImpl.RyuJit.cs | 13 +++++++++++ 4 files changed, 61 insertions(+) diff --git a/src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs b/src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs index 5574a9f8aa100f..7d1c3be1de42a9 100644 --- a/src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs +++ b/src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs @@ -208,6 +208,12 @@ protected virtual MethodDesc ResolveVirtualMethod(MethodDesc declMethod, DefType /// public virtual bool CanReferenceConstructedMethodTable(TypeDesc type) => true; + /// + /// Gets a value indicating whether it might be possible that the interface type is implemented by a constructed type data structure + /// in this compilation. Note that the MethodTable for the interface itself could still be optimized away. + /// + public virtual bool CanInterfaceBeImplementedByConstructedMethodTable(TypeDesc type) => true; + /// /// Gets a value indicating whether a (potentially canonically-equlivalent) constructed MethodTable could /// exist. This is similar to , but will return true @@ -215,6 +221,15 @@ protected virtual MethodDesc ResolveVirtualMethod(MethodDesc declMethod, DefType /// public virtual bool CanReferenceConstructedTypeOrCanonicalFormOfType(TypeDesc type) => true; + /// + /// Gets a value indicating whether it might be possible that the interface type is implemented by a constructed type data structure + /// in this compilation. Note that the MethodTable for the interface itself could still be optimized away. + /// Similar to but will return true for + /// IInterface<__Canon> if IInterface<String> could be implemented. + /// + public virtual bool CanInterfaceOrCanonicalFormOfItBeImplementedByConstructedMethodTable(TypeDesc type) => true; + + public virtual TypeDesc[] GetImplementingClasses(TypeDesc type) => null; #endif } diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Compilation.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Compilation.cs index 6a542d8d00a748..4673b0f7b18421 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Compilation.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Compilation.cs @@ -108,11 +108,21 @@ public bool CanReferenceConstructedMethodTable(TypeDesc type) return NodeFactory.DevirtualizationManager.CanReferenceConstructedMethodTable(type.NormalizeInstantiation()); } + public bool CanInterfaceBeImplementedByConstructedMethodTable(TypeDesc type) + { + return NodeFactory.DevirtualizationManager.CanInterfaceBeImplementedByConstructedMethodTable(type.NormalizeInstantiation()); + } + public bool CanReferenceConstructedTypeOrCanonicalFormOfType(TypeDesc type) { return NodeFactory.DevirtualizationManager.CanReferenceConstructedTypeOrCanonicalFormOfType(type.NormalizeInstantiation()); } + public bool CanInterfaceOrCanonicalFormOfItBeImplementedByConstructedMethodTable(TypeDesc type) + { + return NodeFactory.DevirtualizationManager.CanInterfaceOrCanonicalFormOfItBeImplementedByConstructedMethodTable(type.NormalizeInstantiation()); + } + public DelegateCreationInfo GetDelegateCtor(TypeDesc delegateType, MethodDesc target, TypeDesc constrainedType, bool followVirtualDispatch) { // If we're creating a delegate to a virtual method that cannot be overridden, devirtualize. diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ILScanner.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ILScanner.cs index 4d9328f1a34eef..954ae7b92b256e 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ILScanner.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ILScanner.cs @@ -438,6 +438,8 @@ private sealed class ScannedDevirtualizationManager : DevirtualizationManager private HashSet _constructedMethodTables = new HashSet(); private HashSet _canonConstructedMethodTables = new HashSet(); private HashSet _canonConstructedTypes = new HashSet(); + private HashSet _implementedInterfaces = new HashSet(); + private HashSet _canonImplementedInterfaces = new HashSet(); private HashSet _unsealedTypes = new HashSet(); private Dictionary> _implementators = new(); private HashSet _disqualifiedTypes = new(); @@ -507,6 +509,13 @@ public ScannedDevirtualizationManager(NodeFactory factory, ImmutableArray Date: Fri, 17 Jan 2025 06:40:33 +0100 Subject: [PATCH 2/2] Hmm --- .../aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs index 96169cce8aa08a..36ddc60294a684 100644 --- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs +++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs @@ -2241,6 +2241,10 @@ private bool CanNeverHaveInstanceOfSubclassOf(TypeDesc type) if (!ConstructedEETypeNode.CreationAllowed(type)) return false; + // TODO: rather conservative + if (type.HasVariance) + return false; + TypeDesc canonType = type.ConvertToCanonForm(CanonicalFormKind.Specific); // Interface optimization may be able to remove MethodTable of interfaces if they were never actually